diff --git a/clap_complete/examples/exhaustive.rs b/clap_complete/examples/exhaustive.rs index 9ebdde62c881..001b726c0e4a 100644 --- a/clap_complete/examples/exhaustive.rs +++ b/clap_complete/examples/exhaustive.rs @@ -186,6 +186,7 @@ fn cli() -> clap::Command { .long("email") .value_hint(clap::ValueHint::EmailAddress), ]), + clap::Command::new("escape-help").about("\\tab\t\"'"), ]); #[cfg(feature = "unstable-dynamic")] let cli = clap_complete::dynamic::shells::CompleteCommand::augment_subcommands(cli); diff --git a/clap_complete/src/dynamic/completer.rs b/clap_complete/src/dynamic/completer.rs index b33bee9b8da5..c838b6417920 100644 --- a/clap_complete/src/dynamic/completer.rs +++ b/clap_complete/src/dynamic/completer.rs @@ -1,33 +1,21 @@ use std::ffi::OsStr; use std::ffi::OsString; +use clap::builder::StyledStr; use clap_lex::OsStrExt as _; /// Gets all the long options, their visible aliases and flags of a [`clap::Command`]. /// Includes `help` and `version` depending on the [`clap::Command`] settings. -pub fn longs_and_visible_aliases(p: &clap::Command) -> Vec { +pub fn longs_and_visible_aliases(p: &clap::Command) -> Vec<(String, Option)> { debug!("longs: name={}", p.get_name()); p.get_arguments() .filter_map(|a| { - if !a.is_positional() { - if a.get_visible_aliases().is_some() && a.get_long().is_some() { - let mut visible_aliases: Vec<_> = a - .get_visible_aliases() - .unwrap() - .into_iter() - .map(|s| s.to_string()) - .collect(); - visible_aliases.push(a.get_long().unwrap().to_string()); - Some(visible_aliases) - } else if a.get_visible_aliases().is_none() && a.get_long().is_some() { - Some(vec![a.get_long().unwrap().to_string()]) - } else { - None - } - } else { - None - } + a.get_long_and_visible_aliases().map(|longs| { + longs + .into_iter() + .map(|s| (s.to_string(), a.get_help().cloned())) + }) }) .flatten() .collect() @@ -35,24 +23,13 @@ pub fn longs_and_visible_aliases(p: &clap::Command) -> Vec { /// Gets all the short options, their visible aliases and flags of a [`clap::Command`]. /// Includes `h` and `V` depending on the [`clap::Command`] settings. -pub fn shorts_and_visible_aliases(p: &clap::Command) -> Vec { +pub fn shorts_and_visible_aliases(p: &clap::Command) -> Vec<(char, Option)> { debug!("shorts: name={}", p.get_name()); p.get_arguments() .filter_map(|a| { - if !a.is_positional() { - if a.get_visible_short_aliases().is_some() && a.get_short().is_some() { - let mut shorts_and_visible_aliases = a.get_visible_short_aliases().unwrap(); - shorts_and_visible_aliases.push(a.get_short().unwrap()); - Some(shorts_and_visible_aliases) - } else if a.get_visible_short_aliases().is_none() && a.get_short().is_some() { - Some(vec![a.get_short().unwrap()]) - } else { - None - } - } else { - None - } + a.get_short_and_visible_aliases() + .map(|shorts| shorts.into_iter().map(|s| (s, a.get_help().cloned()))) }) .flatten() .collect() @@ -73,19 +50,13 @@ pub fn possible_values(a: &clap::Arg) -> Option Vec { +pub fn subcommands(p: &clap::Command) -> Vec<(String, Option)> { debug!("subcommands: name={}", p.get_name()); debug!("subcommands: Has subcommands...{:?}", p.has_subcommands()); - let mut subcmds = vec![]; - - for sc in p.get_subcommands() { - debug!("subcommands:iter: name={}", sc.get_name(),); - - subcmds.push(sc.get_name().to_string()); - } - - subcmds + p.get_subcommands() + .map(|sc| (sc.get_name().to_string(), sc.get_about().cloned())) + .collect() } /// Shell-specific completions @@ -116,7 +87,7 @@ pub fn complete( args: Vec, arg_index: usize, current_dir: Option<&std::path::Path>, -) -> Result, std::io::Error> { +) -> Result)>, std::io::Error> { cmd.build(); let raw_args = clap_lex::RawArgs::new(args.into_iter()); @@ -175,7 +146,7 @@ fn complete_arg( current_dir: Option<&std::path::Path>, pos_index: usize, is_escaped: bool, -) -> Result, std::io::Error> { +) -> Result)>, std::io::Error> { debug!( "complete_arg: arg={:?}, cmd={:?}, current_dir={:?}, pos_index={}, is_escaped={}", arg, @@ -194,18 +165,16 @@ fn complete_arg( completions.extend( complete_arg_value(value.to_str().ok_or(value), arg, current_dir) .into_iter() - .map(|os| { + .map(|(os, help)| { // HACK: Need better `OsStr` manipulation - format!("--{}={}", flag, os.to_string_lossy()).into() + (format!("--{}={}", flag, os.to_string_lossy()).into(), help) }), ) } } else { - completions.extend( - longs_and_visible_aliases(cmd) - .into_iter() - .filter_map(|f| f.starts_with(flag).then(|| format!("--{f}").into())), - ); + completions.extend(longs_and_visible_aliases(cmd).into_iter().filter_map( + |(f, help)| f.starts_with(flag).then(|| (format!("--{f}").into(), help)), + )); } } } else if arg.is_escape() || arg.is_stdio() || arg.is_empty() { @@ -213,7 +182,7 @@ fn complete_arg( completions.extend( longs_and_visible_aliases(cmd) .into_iter() - .map(|f| format!("--{f}").into()), + .map(|(f, help)| (format!("--{f}").into(), help)), ); } @@ -228,7 +197,7 @@ fn complete_arg( shorts_and_visible_aliases(cmd) .into_iter() // HACK: Need better `OsStr` manipulation - .map(|f| format!("{}{}", dash_or_arg, f).into()), + .map(|(f, help)| (format!("{}{}", dash_or_arg, f).into(), help)), ); } } @@ -251,7 +220,7 @@ fn complete_arg_value( value: Result<&str, &OsStr>, arg: &clap::Arg, current_dir: Option<&std::path::Path>, -) -> Vec { +) -> Vec<(OsString, Option)> { let mut values = Vec::new(); debug!("complete_arg_value: arg={arg:?}, value={value:?}"); @@ -259,7 +228,8 @@ fn complete_arg_value( if let Ok(value) = value { values.extend(possible_values.into_iter().filter_map(|p| { let name = p.get_name(); - name.starts_with(value).then(|| name.into()) + name.starts_with(value) + .then(|| (name.into(), p.get_help().cloned())) })); } } else { @@ -308,7 +278,7 @@ fn complete_path( value_os: &OsStr, current_dir: Option<&std::path::Path>, is_wanted: impl Fn(&std::path::Path) -> bool, -) -> Vec { +) -> Vec<(OsString, Option)> { let mut completions = Vec::new(); let current_dir = match current_dir { @@ -340,12 +310,12 @@ fn complete_path( let path = entry.path(); let mut suggestion = pathdiff::diff_paths(&path, current_dir).unwrap_or(path); suggestion.push(""); // Ensure trailing `/` - completions.push(suggestion.as_os_str().to_owned()); + completions.push((suggestion.as_os_str().to_owned(), None)); } else { let path = entry.path(); if is_wanted(&path) { let suggestion = pathdiff::diff_paths(&path, current_dir).unwrap_or(path); - completions.push(suggestion.as_os_str().to_owned()); + completions.push((suggestion.as_os_str().to_owned(), None)); } } } @@ -353,7 +323,7 @@ fn complete_path( completions } -fn complete_subcommand(value: &str, cmd: &clap::Command) -> Vec { +fn complete_subcommand(value: &str, cmd: &clap::Command) -> Vec<(OsString, Option)> { debug!( "complete_subcommand: cmd={:?}, value={:?}", cmd.get_name(), @@ -362,8 +332,8 @@ fn complete_subcommand(value: &str, cmd: &clap::Command) -> Vec { let mut scs = subcommands(cmd) .into_iter() - .filter(|x| x.starts_with(value)) - .map(OsString::from) + .filter(|x| x.0.starts_with(value)) + .map(|x| (OsString::from(&x.0), x.1)) .collect::>(); scs.sort(); scs.dedup(); diff --git a/clap_complete/src/dynamic/shells/bash.rs b/clap_complete/src/dynamic/shells/bash.rs index ebc43c6910fe..43c128e5b4ec 100644 --- a/clap_complete/src/dynamic/shells/bash.rs +++ b/clap_complete/src/dynamic/shells/bash.rs @@ -73,7 +73,7 @@ complete -o nospace -o bashdefault -F _clap_complete_NAME BIN let ifs: Option = std::env::var("IFS").ok().and_then(|i| i.parse().ok()); let completions = crate::dynamic::complete(cmd, args, index, current_dir)?; - for (i, completion) in completions.iter().enumerate() { + for (i, (completion, _)) in completions.iter().enumerate() { if i != 0 { write!(buf, "{}", ifs.as_deref().unwrap_or("\n"))?; } diff --git a/clap_complete/src/dynamic/shells/fish.rs b/clap_complete/src/dynamic/shells/fish.rs index 79b8bda543d4..a73259f01257 100644 --- a/clap_complete/src/dynamic/shells/fish.rs +++ b/clap_complete/src/dynamic/shells/fish.rs @@ -30,8 +30,12 @@ impl crate::dynamic::Completer for Fish { let index = args.len() - 1; let completions = crate::dynamic::complete(cmd, args, index, current_dir)?; - for completion in completions { - writeln!(buf, "{}", completion.to_string_lossy())?; + for (completion, help) in completions { + write!(buf, "{}", completion.to_string_lossy())?; + if let Some(help) = help { + write!(buf, "\t{help}")?; + } + writeln!(buf)?; } Ok(()) } diff --git a/clap_complete/tests/snapshots/home/static/exhaustive/bash/.bashrc b/clap_complete/tests/snapshots/home/static/exhaustive/bash/.bashrc index 9ef12ac7edbc..a9b9221b55b7 100644 --- a/clap_complete/tests/snapshots/home/static/exhaustive/bash/.bashrc +++ b/clap_complete/tests/snapshots/home/static/exhaustive/bash/.bashrc @@ -23,6 +23,9 @@ _exhaustive() { exhaustive,complete) cmd="exhaustive__complete" ;; + exhaustive,escape-help) + cmd="exhaustive__escape__help" + ;; exhaustive,help) cmd="exhaustive__help" ;; @@ -50,6 +53,9 @@ _exhaustive() { exhaustive__help,complete) cmd="exhaustive__help__complete" ;; + exhaustive__help,escape-help) + cmd="exhaustive__help__escape__help" + ;; exhaustive__help,help) cmd="exhaustive__help__help" ;; @@ -159,7 +165,7 @@ _exhaustive() { case "${cmd}" in exhaustive) - opts="-h -V --global --generate --help --version action quote value pacman last alias hint complete help" + opts="-h -V --global --generate --help --version action quote value pacman last alias hint escape-help complete help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -250,8 +256,22 @@ _exhaustive() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + exhaustive__escape__help) + opts="-h -V --global --help --version" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; exhaustive__help) - opts="action quote value pacman last alias hint complete help" + opts="action quote value pacman last alias hint escape-help complete help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -306,6 +326,20 @@ _exhaustive() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + exhaustive__help__escape__help) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; exhaustive__help__help) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then diff --git a/clap_complete/tests/snapshots/home/static/exhaustive/elvish/elvish/rc.elv b/clap_complete/tests/snapshots/home/static/exhaustive/elvish/elvish/rc.elv index 8c0a4d62f71a..abeb9104e8a3 100644 --- a/clap_complete/tests/snapshots/home/static/exhaustive/elvish/elvish/rc.elv +++ b/clap_complete/tests/snapshots/home/static/exhaustive/elvish/elvish/rc.elv @@ -33,6 +33,7 @@ set edit:completion:arg-completer[exhaustive] = {|@words| cand last 'last' cand alias 'alias' cand hint 'hint' + cand escape-help '\tab "''' cand complete 'Register shell completions for this program' cand help 'Print this message or the help of the given subcommand(s)' } @@ -226,6 +227,13 @@ set edit:completion:arg-completer[exhaustive] = {|@words| cand -V 'Print version' cand --version 'Print version' } + &'exhaustive;escape-help'= { + cand --global 'everywhere' + cand -h 'Print help' + cand --help 'Print help' + cand -V 'Print version' + cand --version 'Print version' + } &'exhaustive;complete'= { cand --shell 'Specify shell to complete for' cand --register 'Path to write completion-registration to' @@ -243,6 +251,7 @@ set edit:completion:arg-completer[exhaustive] = {|@words| cand last 'last' cand alias 'alias' cand hint 'hint' + cand escape-help '\tab "''' cand complete 'Register shell completions for this program' cand help 'Print this message or the help of the given subcommand(s)' } @@ -284,6 +293,8 @@ set edit:completion:arg-completer[exhaustive] = {|@words| } &'exhaustive;help;hint'= { } + &'exhaustive;help;escape-help'= { + } &'exhaustive;help;complete'= { } &'exhaustive;help;help'= { diff --git a/clap_complete/tests/snapshots/home/static/exhaustive/fish/fish/completions/exhaustive.fish b/clap_complete/tests/snapshots/home/static/exhaustive/fish/fish/completions/exhaustive.fish index 77cfddd8e0c3..db2ccb73f250 100644 --- a/clap_complete/tests/snapshots/home/static/exhaustive/fish/fish/completions/exhaustive.fish +++ b/clap_complete/tests/snapshots/home/static/exhaustive/fish/fish/completions/exhaustive.fish @@ -9,6 +9,7 @@ complete -c exhaustive -n "__fish_use_subcommand" -f -a "pacman" complete -c exhaustive -n "__fish_use_subcommand" -f -a "last" complete -c exhaustive -n "__fish_use_subcommand" -f -a "alias" complete -c exhaustive -n "__fish_use_subcommand" -f -a "hint" +complete -c exhaustive -n "__fish_use_subcommand" -f -a "escape-help" -d '\\tab "\'' complete -c exhaustive -n "__fish_use_subcommand" -f -a "complete" -d 'Register shell completions for this program' complete -c exhaustive -n "__fish_use_subcommand" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c exhaustive -n "__fish_seen_subcommand_from action" -l set -d 'value' -r @@ -104,20 +105,24 @@ complete -c exhaustive -n "__fish_seen_subcommand_from hint" -l email -r -f complete -c exhaustive -n "__fish_seen_subcommand_from hint" -l global -d 'everywhere' complete -c exhaustive -n "__fish_seen_subcommand_from hint" -s h -l help -d 'Print help' complete -c exhaustive -n "__fish_seen_subcommand_from hint" -s V -l version -d 'Print version' +complete -c exhaustive -n "__fish_seen_subcommand_from escape-help" -l global -d 'everywhere' +complete -c exhaustive -n "__fish_seen_subcommand_from escape-help" -s h -l help -d 'Print help' +complete -c exhaustive -n "__fish_seen_subcommand_from escape-help" -s V -l version -d 'Print version' complete -c exhaustive -n "__fish_seen_subcommand_from complete" -l shell -d 'Specify shell to complete for' -r -f -a "{bash ,fish }" complete -c exhaustive -n "__fish_seen_subcommand_from complete" -l register -d 'Path to write completion-registration to' -r -F complete -c exhaustive -n "__fish_seen_subcommand_from complete" -l global -d 'everywhere' complete -c exhaustive -n "__fish_seen_subcommand_from complete" -s h -l help -d 'Print help (see more with \'--help\')' complete -c exhaustive -n "__fish_seen_subcommand_from complete" -s V -l version -d 'Print version' -complete -c exhaustive -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from action; and not __fish_seen_subcommand_from quote; and not __fish_seen_subcommand_from value; and not __fish_seen_subcommand_from pacman; and not __fish_seen_subcommand_from last; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from hint; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from help" -f -a "action" -complete -c exhaustive -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from action; and not __fish_seen_subcommand_from quote; and not __fish_seen_subcommand_from value; and not __fish_seen_subcommand_from pacman; and not __fish_seen_subcommand_from last; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from hint; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from help" -f -a "quote" -complete -c exhaustive -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from action; and not __fish_seen_subcommand_from quote; and not __fish_seen_subcommand_from value; and not __fish_seen_subcommand_from pacman; and not __fish_seen_subcommand_from last; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from hint; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from help" -f -a "value" -complete -c exhaustive -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from action; and not __fish_seen_subcommand_from quote; and not __fish_seen_subcommand_from value; and not __fish_seen_subcommand_from pacman; and not __fish_seen_subcommand_from last; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from hint; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from help" -f -a "pacman" -complete -c exhaustive -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from action; and not __fish_seen_subcommand_from quote; and not __fish_seen_subcommand_from value; and not __fish_seen_subcommand_from pacman; and not __fish_seen_subcommand_from last; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from hint; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from help" -f -a "last" -complete -c exhaustive -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from action; and not __fish_seen_subcommand_from quote; and not __fish_seen_subcommand_from value; and not __fish_seen_subcommand_from pacman; and not __fish_seen_subcommand_from last; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from hint; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from help" -f -a "alias" -complete -c exhaustive -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from action; and not __fish_seen_subcommand_from quote; and not __fish_seen_subcommand_from value; and not __fish_seen_subcommand_from pacman; and not __fish_seen_subcommand_from last; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from hint; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from help" -f -a "hint" -complete -c exhaustive -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from action; and not __fish_seen_subcommand_from quote; and not __fish_seen_subcommand_from value; and not __fish_seen_subcommand_from pacman; and not __fish_seen_subcommand_from last; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from hint; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from help" -f -a "complete" -d 'Register shell completions for this program' -complete -c exhaustive -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from action; and not __fish_seen_subcommand_from quote; and not __fish_seen_subcommand_from value; and not __fish_seen_subcommand_from pacman; and not __fish_seen_subcommand_from last; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from hint; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c exhaustive -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from action; and not __fish_seen_subcommand_from quote; and not __fish_seen_subcommand_from value; and not __fish_seen_subcommand_from pacman; and not __fish_seen_subcommand_from last; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from hint; and not __fish_seen_subcommand_from escape-help; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from help" -f -a "action" +complete -c exhaustive -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from action; and not __fish_seen_subcommand_from quote; and not __fish_seen_subcommand_from value; and not __fish_seen_subcommand_from pacman; and not __fish_seen_subcommand_from last; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from hint; and not __fish_seen_subcommand_from escape-help; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from help" -f -a "quote" +complete -c exhaustive -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from action; and not __fish_seen_subcommand_from quote; and not __fish_seen_subcommand_from value; and not __fish_seen_subcommand_from pacman; and not __fish_seen_subcommand_from last; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from hint; and not __fish_seen_subcommand_from escape-help; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from help" -f -a "value" +complete -c exhaustive -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from action; and not __fish_seen_subcommand_from quote; and not __fish_seen_subcommand_from value; and not __fish_seen_subcommand_from pacman; and not __fish_seen_subcommand_from last; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from hint; and not __fish_seen_subcommand_from escape-help; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from help" -f -a "pacman" +complete -c exhaustive -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from action; and not __fish_seen_subcommand_from quote; and not __fish_seen_subcommand_from value; and not __fish_seen_subcommand_from pacman; and not __fish_seen_subcommand_from last; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from hint; and not __fish_seen_subcommand_from escape-help; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from help" -f -a "last" +complete -c exhaustive -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from action; and not __fish_seen_subcommand_from quote; and not __fish_seen_subcommand_from value; and not __fish_seen_subcommand_from pacman; and not __fish_seen_subcommand_from last; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from hint; and not __fish_seen_subcommand_from escape-help; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from help" -f -a "alias" +complete -c exhaustive -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from action; and not __fish_seen_subcommand_from quote; and not __fish_seen_subcommand_from value; and not __fish_seen_subcommand_from pacman; and not __fish_seen_subcommand_from last; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from hint; and not __fish_seen_subcommand_from escape-help; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from help" -f -a "hint" +complete -c exhaustive -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from action; and not __fish_seen_subcommand_from quote; and not __fish_seen_subcommand_from value; and not __fish_seen_subcommand_from pacman; and not __fish_seen_subcommand_from last; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from hint; and not __fish_seen_subcommand_from escape-help; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from help" -f -a "escape-help" -d '\\tab "\'' +complete -c exhaustive -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from action; and not __fish_seen_subcommand_from quote; and not __fish_seen_subcommand_from value; and not __fish_seen_subcommand_from pacman; and not __fish_seen_subcommand_from last; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from hint; and not __fish_seen_subcommand_from escape-help; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from help" -f -a "complete" -d 'Register shell completions for this program' +complete -c exhaustive -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from action; and not __fish_seen_subcommand_from quote; and not __fish_seen_subcommand_from value; and not __fish_seen_subcommand_from pacman; and not __fish_seen_subcommand_from last; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from hint; and not __fish_seen_subcommand_from escape-help; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c exhaustive -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from quote; and not __fish_seen_subcommand_from cmd-single-quotes; and not __fish_seen_subcommand_from cmd-double-quotes; and not __fish_seen_subcommand_from cmd-backticks; and not __fish_seen_subcommand_from cmd-backslash; and not __fish_seen_subcommand_from cmd-brackets; and not __fish_seen_subcommand_from cmd-expansions" -f -a "cmd-single-quotes" -d 'Can be \'always\', \'auto\', or \'never\'' complete -c exhaustive -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from quote; and not __fish_seen_subcommand_from cmd-single-quotes; and not __fish_seen_subcommand_from cmd-double-quotes; and not __fish_seen_subcommand_from cmd-backticks; and not __fish_seen_subcommand_from cmd-backslash; and not __fish_seen_subcommand_from cmd-brackets; and not __fish_seen_subcommand_from cmd-expansions" -f -a "cmd-double-quotes" -d 'Can be "always", "auto", or "never"' complete -c exhaustive -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from quote; and not __fish_seen_subcommand_from cmd-single-quotes; and not __fish_seen_subcommand_from cmd-double-quotes; and not __fish_seen_subcommand_from cmd-backticks; and not __fish_seen_subcommand_from cmd-backslash; and not __fish_seen_subcommand_from cmd-brackets; and not __fish_seen_subcommand_from cmd-expansions" -f -a "cmd-backticks" -d 'For more information see `echo test`' diff --git a/clap_complete/tests/snapshots/home/static/exhaustive/zsh/zsh/_exhaustive b/clap_complete/tests/snapshots/home/static/exhaustive/zsh/zsh/_exhaustive index 6548aa0e6bc7..cc431862c4bd 100644 --- a/clap_complete/tests/snapshots/home/static/exhaustive/zsh/zsh/_exhaustive +++ b/clap_complete/tests/snapshots/home/static/exhaustive/zsh/zsh/_exhaustive @@ -307,6 +307,15 @@ _arguments "${_arguments_options[@]}" \ '*::command_with_args:_cmdambivalent' \ && ret=0 ;; +(escape-help) +_arguments "${_arguments_options[@]}" \ +'--global[everywhere]' \ +'-h[Print help]' \ +'--help[Print help]' \ +'-V[Print version]' \ +'--version[Print version]' \ +&& ret=0 +;; (complete) _arguments "${_arguments_options[@]}" \ '--shell=[Specify shell to complete for]:SHELL:(bash fish)' \ @@ -415,6 +424,10 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ && ret=0 ;; +(escape-help) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; (complete) _arguments "${_arguments_options[@]}" \ && ret=0 @@ -442,6 +455,7 @@ _exhaustive_commands() { 'last:' \ 'alias:' \ 'hint:' \ +'escape-help:\\tab "'\''' \ 'complete:Register shell completions for this program' \ 'help:Print this message or the help of the given subcommand(s)' \ ) @@ -567,6 +581,16 @@ _exhaustive__help__complete_commands() { local commands; commands=() _describe -t commands 'exhaustive help complete commands' commands "$@" } +(( $+functions[_exhaustive__escape-help_commands] )) || +_exhaustive__escape-help_commands() { + local commands; commands=() + _describe -t commands 'exhaustive escape-help commands' commands "$@" +} +(( $+functions[_exhaustive__help__escape-help_commands] )) || +_exhaustive__help__escape-help_commands() { + local commands; commands=() + _describe -t commands 'exhaustive help escape-help commands' commands "$@" +} (( $+functions[_exhaustive__help_commands] )) || _exhaustive__help_commands() { local commands; commands=( @@ -577,6 +601,7 @@ _exhaustive__help_commands() { 'last:' \ 'alias:' \ 'hint:' \ +'escape-help:\\tab "'\''' \ 'complete:Register shell completions for this program' \ 'help:Print this message or the help of the given subcommand(s)' \ ) diff --git a/clap_complete/tests/testsuite/bash.rs b/clap_complete/tests/testsuite/bash.rs index b9692a421c99..d40b9dc2a5a9 100644 --- a/clap_complete/tests/testsuite/bash.rs +++ b/clap_complete/tests/testsuite/bash.rs @@ -156,8 +156,8 @@ fn complete() { let input = "exhaustive \t\t"; let expected = r#"% --h --global --help action value last hint help --V --generate --version quote pacman alias complete"#; +-h --global --help action value last hint complete +-V --generate --version quote pacman alias escape-help help"#; let actual = runtime.complete(input, &term).unwrap(); snapbox::assert_eq(expected, actual); } diff --git a/clap_complete/tests/testsuite/dynamic.rs b/clap_complete/tests/testsuite/dynamic.rs index 8ab7461d033d..8a2d9e466b43 100644 --- a/clap_complete/tests/testsuite/dynamic.rs +++ b/clap_complete/tests/testsuite/dynamic.rs @@ -19,7 +19,7 @@ fn suggest_subcommand_subset() { clap_complete::dynamic::complete(&mut cmd, args, arg_index, current_dir).unwrap(); let completions = completions .into_iter() - .map(|s| s.to_string_lossy().into_owned()) + .map(|s| s.0.to_string_lossy().into_owned()) .collect::>(); assert_eq!(completions, ["hello-moon", "hello-world", "help"]); @@ -56,7 +56,7 @@ fn suggest_long_flag_subset() { clap_complete::dynamic::complete(&mut cmd, args, arg_index, current_dir).unwrap(); let completions = completions .into_iter() - .map(|s| s.to_string_lossy().into_owned()) + .map(|s| s.0.to_string_lossy().into_owned()) .collect::>(); assert_eq!(completions, ["--hello-world", "--hello-moon", "--help"]); @@ -82,7 +82,7 @@ fn suggest_possible_value_subset() { clap_complete::dynamic::complete(&mut cmd, args, arg_index, current_dir).unwrap(); let completions = completions .into_iter() - .map(|s| s.to_string_lossy().into_owned()) + .map(|s| s.0.to_string_lossy().into_owned()) .collect::>(); assert_eq!(completions, ["hello-world", "hello-moon"]); @@ -119,7 +119,7 @@ fn suggest_additional_short_flags() { clap_complete::dynamic::complete(&mut cmd, args, arg_index, current_dir).unwrap(); let completions = completions .into_iter() - .map(|s| s.to_string_lossy().into_owned()) + .map(|s| s.0.to_string_lossy().into_owned()) .collect::>(); assert_eq!(completions, ["-aa", "-ab", "-ac", "-ah"]); diff --git a/clap_complete/tests/testsuite/fish.rs b/clap_complete/tests/testsuite/fish.rs index 6e2bbeb46fe4..eecc3303f992 100644 --- a/clap_complete/tests/testsuite/fish.rs +++ b/clap_complete/tests/testsuite/fish.rs @@ -138,8 +138,11 @@ fn complete() { let input = "exhaustive \t"; let expected = r#"% exhaustive -action complete (Register shell completions for this program) hint pacman value -alias help (Print this message or the help of the given subcommand(s)) last quote"#; +action hint +alias last +complete (Register shell completions for this program) pacman +escape-help (\tab "') quote +help (Print this message or the help of the given subcommand(s)) value"#; let actual = runtime.complete(input, &term).unwrap(); snapbox::assert_eq(expected, actual); } @@ -162,9 +165,12 @@ fn complete_dynamic() { let input = "exhaustive \t"; let expected = r#"% exhaustive -action help pacman -h --global -alias hint quote -V --help -complete last value --generate --version"#; +action last --generate (generate) +alias pacman --global (everywhere) +complete (Register shell completions for this program) quote --help (Print help) +escape-help (\tab "') value --version (Print version) +help (Print this message or the help of the given subcommand(s)) -h (Print help) +hint -V (Print version)"#; let actual = runtime.complete(input, &term).unwrap(); snapbox::assert_eq(expected, actual); } diff --git a/clap_complete/tests/testsuite/zsh.rs b/clap_complete/tests/testsuite/zsh.rs index d6b51ab00e75..e1036d79d7a8 100644 --- a/clap_complete/tests/testsuite/zsh.rs +++ b/clap_complete/tests/testsuite/zsh.rs @@ -138,9 +138,10 @@ fn complete() { let input = "exhaustive \t"; let expected = r#"% exhaustive -complete -- Register shell completions for this program -help -- Print this message or the help of the given subcommand(s) -pacman action alias value quote hint last --"#; +complete -- Register shell completions for this program +escape-help -- \tab\t"' +help -- Print this message or the help of the given subcommand(s) +pacman action alias value quote hint last --"#; let actual = runtime.complete(input, &term).unwrap(); snapbox::assert_eq(expected, actual); }