diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:50 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:50 +0000 |
commit | 9835e2ae736235810b4ea1c162ca5e65c547e770 (patch) | |
tree | 3fcebf40ed70e581d776a8a4c65923e8ec20e026 /vendor/clap_complete/src | |
parent | Releasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff) | |
download | rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip |
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/clap_complete/src')
-rw-r--r-- | vendor/clap_complete/src/dynamic.rs | 44 | ||||
-rw-r--r-- | vendor/clap_complete/src/generator/mod.rs | 31 | ||||
-rw-r--r-- | vendor/clap_complete/src/lib.rs | 2 | ||||
-rw-r--r-- | vendor/clap_complete/src/shells/bash.rs | 21 | ||||
-rw-r--r-- | vendor/clap_complete/src/shells/elvish.rs | 14 | ||||
-rw-r--r-- | vendor/clap_complete/src/shells/fish.rs | 14 | ||||
-rw-r--r-- | vendor/clap_complete/src/shells/powershell.rs | 92 | ||||
-rw-r--r-- | vendor/clap_complete/src/shells/shell.rs | 2 | ||||
-rw-r--r-- | vendor/clap_complete/src/shells/zsh.rs | 153 |
9 files changed, 180 insertions, 193 deletions
diff --git a/vendor/clap_complete/src/dynamic.rs b/vendor/clap_complete/src/dynamic.rs index 929841ec8..f25b4a48d 100644 --- a/vendor/clap_complete/src/dynamic.rs +++ b/vendor/clap_complete/src/dynamic.rs @@ -2,9 +2,11 @@ /// Complete commands within bash pub mod bash { + use std::ffi::OsStr; use std::ffi::OsString; use std::io::Write; + use clap_lex::OsStrExt as _; use unicode_xid::UnicodeXID; #[derive(clap::Subcommand)] @@ -69,7 +71,7 @@ pub mod bash { /// Process the completion request pub fn try_complete(&self, cmd: &mut clap::Command) -> clap::error::Result<()> { - debug!("CompleteCommand::try_complete: {:?}", self); + debug!("CompleteCommand::try_complete: {self:?}"); let CompleteCommand::Complete(args) = self; if let Some(out_path) = args.register.as_deref() { let mut buf = Vec::new(); @@ -122,7 +124,7 @@ pub mod bash { /// The recommended file name for the registration code pub fn file_name(name: &str) -> String { - format!("{}.bash", name) + format!("{name}.bash") } /// Define the completion behavior @@ -152,8 +154,7 @@ pub mod bash { let escaped_name = name.replace('-', "_"); debug_assert!( escaped_name.chars().all(|c| c.is_xid_continue()), - "`name` must be an identifier, got `{}`", - escaped_name + "`name` must be an identifier, got `{escaped_name}`" ); let mut upper_name = escaped_name.clone(); upper_name.make_ascii_uppercase(); @@ -199,7 +200,7 @@ complete OPTIONS -F _clap_complete_NAME EXECUTABLES .replace("COMPLETER", &completer) .replace("UPPER", &upper_name); - writeln!(buf, "{}", script)?; + writeln!(buf, "{script}")?; Ok(()) } @@ -320,11 +321,7 @@ complete OPTIONS -F _clap_complete_NAME EXECUTABLES return complete_arg(&arg, current_cmd, current_dir, pos_index, is_escaped); } - debug!( - "complete::next: Begin parsing '{:?}' ({:?})", - arg.to_value_os(), - arg.to_value_os().as_raw_bytes() - ); + debug!("complete::next: Begin parsing '{:?}'", arg.to_value_os(),); if let Ok(value) = arg.to_value() { if let Some(next_cmd) = current_cmd.find_subcommand(value) { @@ -388,7 +385,7 @@ complete OPTIONS -F _clap_complete_NAME EXECUTABLES crate::generator::utils::longs_and_visible_aliases(cmd) .into_iter() .filter_map(|f| { - f.starts_with(flag).then(|| format!("--{}", f).into()) + f.starts_with(flag).then(|| format!("--{f}").into()) }), ); } @@ -398,7 +395,7 @@ complete OPTIONS -F _clap_complete_NAME EXECUTABLES completions.extend( crate::generator::utils::longs_and_visible_aliases(cmd) .into_iter() - .map(|f| format!("--{}", f).into()), + .map(|f| format!("--{f}").into()), ); } @@ -408,7 +405,7 @@ complete OPTIONS -F _clap_complete_NAME EXECUTABLES crate::generator::utils::shorts_and_visible_aliases(cmd) .into_iter() // HACK: Need better `OsStr` manipulation - .map(|f| format!("{}{}", arg.to_value_os().to_str_lossy(), f).into()), + .map(|f| format!("{}{}", arg.to_value_os().to_string_lossy(), f).into()), ); } } @@ -428,12 +425,12 @@ complete OPTIONS -F _clap_complete_NAME EXECUTABLES } fn complete_arg_value( - value: Result<&str, &clap_lex::RawOsStr>, + value: Result<&str, &OsStr>, arg: &clap::Arg, current_dir: Option<&std::path::Path>, ) -> Vec<OsString> { let mut values = Vec::new(); - debug!("complete_arg_value: arg={:?}, value={:?}", arg, value); + debug!("complete_arg_value: arg={arg:?}, value={value:?}"); if let Some(possible_values) = crate::generator::utils::possible_values(arg) { if let Ok(value) = value { @@ -444,7 +441,7 @@ complete OPTIONS -F _clap_complete_NAME EXECUTABLES } } else { let value_os = match value { - Ok(value) => clap_lex::RawOsStr::from_str(value), + Ok(value) => OsStr::new(value), Err(value_os) => value_os, }; match arg.get_value_hint() { @@ -485,7 +482,7 @@ complete OPTIONS -F _clap_complete_NAME EXECUTABLES } fn complete_path( - value_os: &clap_lex::RawOsStr, + value_os: &OsStr, current_dir: Option<&std::path::Path>, is_wanted: impl Fn(&std::path::Path) -> bool, ) -> Vec<OsString> { @@ -499,10 +496,11 @@ complete OPTIONS -F _clap_complete_NAME EXECUTABLES } }; let (existing, prefix) = value_os - .split_once('\\') - .unwrap_or((clap_lex::RawOsStr::from_str(""), value_os)); - let root = current_dir.join(existing.to_os_str()); - debug!("complete_path: root={:?}, prefix={:?}", root, prefix); + .split_once("\\") + .unwrap_or((OsStr::new(""), value_os)); + let root = current_dir.join(existing); + debug!("complete_path: root={root:?}, prefix={prefix:?}"); + let prefix = prefix.to_string_lossy(); for entry in std::fs::read_dir(&root) .ok() @@ -510,8 +508,8 @@ complete OPTIONS -F _clap_complete_NAME EXECUTABLES .flatten() .filter_map(Result::ok) { - let raw_file_name = clap_lex::RawOsString::new(entry.file_name()); - if !raw_file_name.starts_with_os(prefix) { + let raw_file_name = OsString::from(entry.file_name()); + if !raw_file_name.starts_with(&prefix) { continue; } diff --git a/vendor/clap_complete/src/generator/mod.rs b/vendor/clap_complete/src/generator/mod.rs index c025697ed..c6e5c5ec8 100644 --- a/vendor/clap_complete/src/generator/mod.rs +++ b/vendor/clap_complete/src/generator/mod.rs @@ -28,10 +28,10 @@ pub trait Generator { /// pub struct Fish; /// /// impl Generator for Fish { - /// # fn generate(&self, cmd: &Command, buf: &mut dyn Write) {} /// fn file_name(&self, name: &str) -> String { - /// format!("{}.fish", name) + /// format!("{name}.fish") /// } + /// # fn generate(&self, cmd: &Command, buf: &mut dyn Write) {} /// } /// ``` fn file_name(&self, name: &str) -> String; @@ -55,12 +55,12 @@ pub trait Generator { /// pub struct ClapDebug; /// /// impl Generator for ClapDebug { - /// fn generate(&self, cmd: &Command, buf: &mut dyn Write) { - /// write!(buf, "{}", cmd).unwrap(); - /// } /// # fn file_name(&self, name: &str) -> String { - /// # name.into() + /// # name.into() /// # } + /// fn generate(&self, cmd: &Command, buf: &mut dyn Write) { + /// write!(buf, "{cmd}").unwrap(); + /// } /// } /// ``` fn generate(&self, cmd: &Command, buf: &mut dyn Write); @@ -150,7 +150,7 @@ pub trait Generator { /// outdir, // We need to specify where to write to /// )?; /// -/// println!("cargo:warning=completion file is generated: {:?}", path); +/// println!("cargo:warning=completion file is generated: {path:?}"); /// /// Ok(()) /// } @@ -164,7 +164,7 @@ pub trait Generator { /// to see the name of the files generated. pub fn generate_to<G, S, T>( gen: G, - cmd: &mut clap::Command, + cmd: &mut Command, bin_name: S, out_dir: T, ) -> Result<PathBuf, Error> @@ -181,7 +181,7 @@ where let path = out_dir.join(file_name); let mut file = File::create(&path)?; - _generate::<G, S>(gen, cmd, &mut file); + _generate::<G>(gen, cmd, &mut file); Ok(path) } @@ -217,24 +217,19 @@ where /// /// Usage: /// -/// ```shell +/// ```console /// $ myapp generate-bash-completions > /usr/share/bash-completion/completions/myapp.bash /// ``` -pub fn generate<G, S>(gen: G, cmd: &mut clap::Command, bin_name: S, buf: &mut dyn Write) +pub fn generate<G, S>(gen: G, cmd: &mut Command, bin_name: S, buf: &mut dyn Write) where G: Generator, S: Into<String>, { cmd.set_bin_name(bin_name); - _generate::<G, S>(gen, cmd, buf) + _generate::<G>(gen, cmd, buf) } -fn _generate<G, S>(gen: G, cmd: &mut clap::Command, buf: &mut dyn Write) -where - G: Generator, - S: Into<String>, -{ +fn _generate<G: Generator>(gen: G, cmd: &mut Command, buf: &mut dyn Write) { cmd.build(); - gen.generate(cmd, buf) } diff --git a/vendor/clap_complete/src/lib.rs b/vendor/clap_complete/src/lib.rs index 80fead4a5..a44288220 100644 --- a/vendor/clap_complete/src/lib.rs +++ b/vendor/clap_complete/src/lib.rs @@ -49,7 +49,7 @@ //! //! if let Some(generator) = matches.get_one::<Shell>("generator").copied() { //! let mut cmd = build_cli(); -//! eprintln!("Generating completion file for {}...", generator); +//! eprintln!("Generating completion file for {generator}..."); //! print_completions(generator, &mut cmd); //! } //! } diff --git a/vendor/clap_complete/src/shells/bash.rs b/vendor/clap_complete/src/shells/bash.rs index e110537e5..60e6b346c 100644 --- a/vendor/clap_complete/src/shells/bash.rs +++ b/vendor/clap_complete/src/shells/bash.rs @@ -10,7 +10,7 @@ pub struct Bash; impl Generator for Bash { fn file_name(&self, name: &str) -> String { - format!("{}.bash", name) + format!("{name}.bash") } fn generate(&self, cmd: &Command, buf: &mut dyn Write) { @@ -22,7 +22,7 @@ impl Generator for Bash { buf, format!( "_{name}() {{ - local i cur prev opts cmds + local i cur prev opts cmd COMPREPLY=() cur=\"${{COMP_WORDS[COMP_CWORD]}}\" prev=\"${{COMP_WORDS[COMP_CWORD-1]}}\" @@ -114,9 +114,6 @@ fn all_subcommands(cmd: &Command) -> String { "{parent_fn_name},{name}) cmd=\"{fn_name}\" ;;", - parent_fn_name = parent_fn_name, - name = name, - fn_name = fn_name, )); } @@ -161,7 +158,7 @@ fn subcommand_details(cmd: &Command) -> String { } fn option_details_for_path(cmd: &Command, path: &str) -> String { - debug!("option_details_for_path: path={}", path); + debug!("option_details_for_path: path={path}"); let p = utils::find_subcommand_with_path(cmd, path.split("__").skip(1).collect()); let mut opts = vec![String::new()]; @@ -209,22 +206,24 @@ fn vals_for(o: &Arg) -> String { .collect::<Vec<_>>() .join(" ") ) + } else if o.get_value_hint() == ValueHint::Other { + String::from("\"${cur}\"") } else { String::from("$(compgen -f \"${cur}\")") } } fn all_options_for_path(cmd: &Command, path: &str) -> String { - debug!("all_options_for_path: path={}", path); + debug!("all_options_for_path: path={path}"); let p = utils::find_subcommand_with_path(cmd, path.split("__").skip(1).collect()); let mut opts = String::new(); for short in utils::shorts_and_visible_aliases(p) { - write!(&mut opts, "-{} ", short).unwrap(); + write!(&mut opts, "-{short} ").unwrap(); } for long in utils::longs_and_visible_aliases(p) { - write!(&mut opts, "--{} ", long).unwrap(); + write!(&mut opts, "--{long} ").unwrap(); } for pos in p.get_positionals() { if let Some(vals) = utils::possible_values(pos) { @@ -232,11 +231,11 @@ fn all_options_for_path(cmd: &Command, path: &str) -> String { write!(&mut opts, "{} ", value.get_name()).unwrap(); } } else { - write!(&mut opts, "{} ", pos).unwrap(); + write!(&mut opts, "{pos} ").unwrap(); } } for (sc, _) in utils::subcommands(p) { - write!(&mut opts, "{} ", sc).unwrap(); + write!(&mut opts, "{sc} ").unwrap(); } opts.pop(); diff --git a/vendor/clap_complete/src/shells/elvish.rs b/vendor/clap_complete/src/shells/elvish.rs index 07da28348..48a0f852b 100644 --- a/vendor/clap_complete/src/shells/elvish.rs +++ b/vendor/clap_complete/src/shells/elvish.rs @@ -12,7 +12,7 @@ pub struct Elvish; impl Generator for Elvish { fn file_name(&self, name: &str) -> String { - format!("{}.elv", name) + format!("{name}.elv") } fn generate(&self, cmd: &Command, buf: &mut dyn Write) { @@ -46,8 +46,6 @@ set edit:completion:arg-completer[{bin_name}] = {{|@words| $completions[$command] }} "#, - bin_name = bin_name, - subcommands_cases = subcommands_cases ); w!(buf, result.as_bytes()); @@ -83,7 +81,7 @@ fn generate_inner(p: &Command, previous_command_name: &str) -> String { let tooltip = get_tooltip(option.get_help(), shorts[0]); for short in shorts { completions.push_str(&preamble); - completions.push_str(format!("-{} '{}'", short, tooltip).as_str()); + completions.push_str(format!("-{short} '{tooltip}'").as_str()); } } @@ -91,7 +89,7 @@ fn generate_inner(p: &Command, previous_command_name: &str) -> String { let tooltip = get_tooltip(option.get_help(), longs[0]); for long in longs { completions.push_str(&preamble); - completions.push_str(format!("--{} '{}'", long, tooltip).as_str()); + completions.push_str(format!("--{long} '{tooltip}'").as_str()); } } } @@ -101,7 +99,7 @@ fn generate_inner(p: &Command, previous_command_name: &str) -> String { let tooltip = get_tooltip(flag.get_help(), shorts[0]); for short in shorts { completions.push_str(&preamble); - completions.push_str(format!("-{} '{}'", short, tooltip).as_str()); + completions.push_str(format!("-{short} '{tooltip}'").as_str()); } } @@ -109,7 +107,7 @@ fn generate_inner(p: &Command, previous_command_name: &str) -> String { let tooltip = get_tooltip(flag.get_help(), longs[0]); for long in longs { completions.push_str(&preamble); - completions.push_str(format!("--{} '{}'", long, tooltip).as_str()); + completions.push_str(format!("--{long} '{tooltip}'").as_str()); } } } @@ -119,7 +117,7 @@ fn generate_inner(p: &Command, previous_command_name: &str) -> String { let tooltip = get_tooltip(subcommand.get_about(), data); completions.push_str(&preamble); - completions.push_str(format!("{} '{}'", data, tooltip).as_str()); + completions.push_str(format!("{data} '{tooltip}'").as_str()); } let mut subcommands_cases = format!( diff --git a/vendor/clap_complete/src/shells/fish.rs b/vendor/clap_complete/src/shells/fish.rs index fd2f3a4f8..5a069d35b 100644 --- a/vendor/clap_complete/src/shells/fish.rs +++ b/vendor/clap_complete/src/shells/fish.rs @@ -12,7 +12,7 @@ pub struct Fish; impl Generator for Fish { fn file_name(&self, name: &str) -> String { - format!("{}.fish", name) + format!("{name}.fish") } fn generate(&self, cmd: &Command, buf: &mut dyn Write) { @@ -56,7 +56,7 @@ fn gen_fish_inner( // -n "__fish_use_subcommand" # complete for command "myprog" // -n "__fish_seen_subcommand_from subcmd1" # complete for command "myprog subcmd1" - let mut basic_template = format!("complete -c {}", root_command); + let mut basic_template = format!("complete -c {root_command}"); if parent_commands.is_empty() { if cmd.has_subcommands() { @@ -68,10 +68,10 @@ fn gen_fish_inner( " -n \"{}\"", parent_commands .iter() - .map(|command| format!("__fish_seen_subcommand_from {}", command)) + .map(|command| format!("__fish_seen_subcommand_from {command}")) .chain( cmd.get_subcommands() - .map(|command| format!("not __fish_seen_subcommand_from {}", command)) + .map(|command| format!("not __fish_seen_subcommand_from {command}")) ) .collect::<Vec<_>>() .join("; and ") @@ -80,14 +80,14 @@ fn gen_fish_inner( ); } - debug!("gen_fish_inner: parent_commands={:?}", parent_commands); + debug!("gen_fish_inner: parent_commands={parent_commands:?}"); for option in cmd.get_opts() { let mut template = basic_template.clone(); if let Some(shorts) = option.get_short_and_visible_aliases() { for short in shorts { - template.push_str(format!(" -s {}", short).as_str()); + template.push_str(format!(" -s {short}").as_str()); } } @@ -113,7 +113,7 @@ fn gen_fish_inner( if let Some(shorts) = flag.get_short_and_visible_aliases() { for short in shorts { - template.push_str(format!(" -s {}", short).as_str()); + template.push_str(format!(" -s {short}").as_str()); } } diff --git a/vendor/clap_complete/src/shells/powershell.rs b/vendor/clap_complete/src/shells/powershell.rs index 0d3a2a55f..417facf70 100644 --- a/vendor/clap_complete/src/shells/powershell.rs +++ b/vendor/clap_complete/src/shells/powershell.rs @@ -12,7 +12,7 @@ pub struct PowerShell; impl Generator for PowerShell { fn file_name(&self, name: &str) -> String { - format!("_{}.ps1", name) + format!("_{name}.ps1") } fn generate(&self, cmd: &Command, buf: &mut dyn Write) { @@ -50,9 +50,7 @@ Register-ArgumentCompleter -Native -CommandName '{bin_name}' -ScriptBlock {{ $completions.Where{{ $_.CompletionText -like "$wordToComplete*" }} | Sort-Object -Property ListItemText }} -"#, - bin_name = bin_name, - subcommands_cases = subcommands_cases +"# ); w!(buf, result.as_bytes()); @@ -84,63 +82,11 @@ fn generate_inner(p: &Command, previous_command_name: &str) -> String { let preamble = String::from("\n [CompletionResult]::new("); for option in p.get_opts() { - if let Some(shorts) = option.get_short_and_visible_aliases() { - let tooltip = get_tooltip(option.get_help(), shorts[0]); - for short in shorts { - completions.push_str(&preamble); - completions.push_str( - format!( - "'-{}', '{}', {}, '{}')", - short, short, "[CompletionResultType]::ParameterName", tooltip - ) - .as_str(), - ); - } - } - - if let Some(longs) = option.get_long_and_visible_aliases() { - let tooltip = get_tooltip(option.get_help(), longs[0]); - for long in longs { - completions.push_str(&preamble); - completions.push_str( - format!( - "'--{}', '{}', {}, '{}')", - long, long, "[CompletionResultType]::ParameterName", tooltip - ) - .as_str(), - ); - } - } + generate_aliases(&mut completions, &preamble, option); } for flag in utils::flags(p) { - if let Some(shorts) = flag.get_short_and_visible_aliases() { - let tooltip = get_tooltip(flag.get_help(), shorts[0]); - for short in shorts { - completions.push_str(&preamble); - completions.push_str( - format!( - "'-{}', '{}', {}, '{}')", - short, short, "[CompletionResultType]::ParameterName", tooltip - ) - .as_str(), - ); - } - } - - if let Some(longs) = flag.get_long_and_visible_aliases() { - let tooltip = get_tooltip(flag.get_help(), longs[0]); - for long in longs { - completions.push_str(&preamble); - completions.push_str( - format!( - "'--{}', '{}', {}, '{}')", - long, long, "[CompletionResultType]::ParameterName", tooltip - ) - .as_str(), - ); - } - } + generate_aliases(&mut completions, &preamble, &flag); } for subcommand in p.get_subcommands() { @@ -149,11 +95,8 @@ fn generate_inner(p: &Command, previous_command_name: &str) -> String { completions.push_str(&preamble); completions.push_str( - format!( - "'{}', '{}', {}, '{}')", - data, data, "[CompletionResultType]::ParameterValue", tooltip - ) - .as_str(), + format!("'{data}', '{data}', [CompletionResultType]::ParameterValue, '{tooltip}')") + .as_str(), ); } @@ -172,3 +115,26 @@ fn generate_inner(p: &Command, previous_command_name: &str) -> String { subcommands_cases } + +fn generate_aliases(completions: &mut String, preamble: &String, arg: &Arg) { + use std::fmt::Write as _; + + if let Some(aliases) = arg.get_short_and_visible_aliases() { + let tooltip = get_tooltip(arg.get_help(), aliases[0]); + for alias in aliases { + let _ = write!( + completions, + "{preamble}'-{alias}', '{alias}', [CompletionResultType]::ParameterName, '{tooltip}')" + ); + } + } + if let Some(aliases) = arg.get_long_and_visible_aliases() { + let tooltip = get_tooltip(arg.get_help(), aliases[0]); + for alias in aliases { + let _ = write!( + completions, + "{preamble}'--{alias}', '{alias}', [CompletionResultType]::ParameterName, '{tooltip}')" + ); + } + } +} diff --git a/vendor/clap_complete/src/shells/shell.rs b/vendor/clap_complete/src/shells/shell.rs index f6e70f575..52cb2e9b7 100644 --- a/vendor/clap_complete/src/shells/shell.rs +++ b/vendor/clap_complete/src/shells/shell.rs @@ -42,7 +42,7 @@ impl FromStr for Shell { return Ok(*variant); } } - Err(format!("Invalid variant: {}", s)) + Err(format!("invalid variant: {s}")) } } diff --git a/vendor/clap_complete/src/shells/zsh.rs b/vendor/clap_complete/src/shells/zsh.rs index 580de77a2..71c586d8e 100644 --- a/vendor/clap_complete/src/shells/zsh.rs +++ b/vendor/clap_complete/src/shells/zsh.rs @@ -11,7 +11,7 @@ pub struct Zsh; impl Generator for Zsh { fn file_name(&self, name: &str) -> String { - format!("_{}", name) + format!("_{name}") } fn generate(&self, cmd: &Command, buf: &mut dyn Write) { @@ -43,7 +43,11 @@ _{name}() {{ {subcommand_details} -_{name} \"$@\" +if [ \"$funcstack[1]\" = \"_{name}\" ]; then + _{name} \"$@\" +else + compdef _{name} {name} +fi ", name = bin_name, initial_args = get_args_of(cmd, None), @@ -111,8 +115,8 @@ _{bin_name_underscore}_commands() {{ all_subcommands.sort(); all_subcommands.dedup(); - for &(_, ref bin_name) in &all_subcommands { - debug!("subcommand_details:iter: bin_name={}", bin_name); + for (_, ref bin_name) in &all_subcommands { + debug!("subcommand_details:iter: bin_name={bin_name}"); ret.push(format!( "\ @@ -223,14 +227,12 @@ fn get_subcommands_of(parent: &Command) -> String { let subcommand_names = utils::subcommands(parent); let mut all_subcommands = vec![]; - for &(ref name, ref bin_name) in &subcommand_names { + for (ref name, ref bin_name) in &subcommand_names { debug!( - "get_subcommands_of:iter: parent={}, name={}, bin_name={}", + "get_subcommands_of:iter: parent={}, name={name}, bin_name={bin_name}", parent.get_name(), - name, - bin_name, ); - let mut segments = vec![format!("({})", name)]; + let mut segments = vec![format!("({name})")]; let subcommand_args = get_args_of( parser_of(parent, bin_name).expect(INTERNAL_ERROR_MSG), Some(parent), @@ -424,6 +426,9 @@ fn escape_help(string: &str) -> String { .replace('\'', "'\\''") .replace('[', "\\[") .replace(']', "\\]") + .replace(':', "\\:") + .replace('$', "\\$") + .replace('`', "\\`") } /// Escape value string inside single quotes and parentheses @@ -431,6 +436,11 @@ fn escape_value(string: &str) -> String { string .replace('\\', "\\\\") .replace('\'', "'\\''") + .replace('[', "\\[") + .replace(']', "\\]") + .replace(':', "\\:") + .replace('$', "\\$") + .replace('`', "\\`") .replace('(', "\\(") .replace(')', "\\)") .replace(' ', "\\ ") @@ -458,21 +468,14 @@ fn write_opts_of(p: &Command, p_global: Option<&Command>) -> String { Some(val) => val[0].to_string(), }; let vc = match value_completion(o) { - Some(val) => format!(":{}:{}", vn, val), - None => format!(":{}: ", vn), + Some(val) => format!(":{vn}:{val}"), + None => format!(":{vn}: "), }; let vc = vc.repeat(o.get_num_args().expect("built").min_values()); if let Some(shorts) = o.get_short_and_visible_aliases() { for short in shorts { - let s = format!( - "'{conflicts}{multiple}-{arg}+[{help}]{value_completion}' \\", - conflicts = conflicts, - multiple = multiple, - arg = short, - value_completion = vc, - help = help - ); + let s = format!("'{conflicts}{multiple}-{short}+[{help}]{vc}' \\"); debug!("write_opts_of:iter: Wrote...{}", &*s); ret.push(s); @@ -480,14 +483,7 @@ fn write_opts_of(p: &Command, p_global: Option<&Command>) -> String { } if let Some(longs) = o.get_long_and_visible_aliases() { for long in longs { - let l = format!( - "'{conflicts}{multiple}--{arg}=[{help}]{value_completion}' \\", - conflicts = conflicts, - multiple = multiple, - arg = long, - value_completion = vc, - help = help - ); + let l = format!("'{conflicts}{multiple}--{long}=[{help}]{vc}' \\"); debug!("write_opts_of:iter: Wrote...{}", &*l); ret.push(l); @@ -502,11 +498,11 @@ fn arg_conflicts(cmd: &Command, arg: &Arg, app_global: Option<&Command>) -> Stri fn push_conflicts(conflicts: &[&Arg], res: &mut Vec<String>) { for conflict in conflicts { if let Some(s) = conflict.get_short() { - res.push(format!("-{}", s)); + res.push(format!("-{s}")); } if let Some(l) = conflict.get_long() { - res.push(format!("--{}", l)); + res.push(format!("--{l}")); } } } @@ -554,13 +550,7 @@ fn write_flags_of(p: &Command, p_global: Option<&Command>) -> String { }; if let Some(short) = f.get_short() { - let s = format!( - "'{conflicts}{multiple}-{arg}[{help}]' \\", - multiple = multiple, - conflicts = conflicts, - arg = short, - help = help - ); + let s = format!("'{conflicts}{multiple}-{short}[{help}]' \\"); debug!("write_flags_of:iter: Wrote...{}", &*s); @@ -568,13 +558,7 @@ fn write_flags_of(p: &Command, p_global: Option<&Command>) -> String { if let Some(short_aliases) = f.get_visible_short_aliases() { for alias in short_aliases { - let s = format!( - "'{conflicts}{multiple}-{arg}[{help}]' \\", - multiple = multiple, - conflicts = conflicts, - arg = alias, - help = help - ); + let s = format!("'{conflicts}{multiple}-{alias}[{help}]' \\",); debug!("write_flags_of:iter: Wrote...{}", &*s); @@ -584,13 +568,7 @@ fn write_flags_of(p: &Command, p_global: Option<&Command>) -> String { } if let Some(long) = f.get_long() { - let l = format!( - "'{conflicts}{multiple}--{arg}[{help}]' \\", - conflicts = conflicts, - multiple = multiple, - arg = long, - help = help - ); + let l = format!("'{conflicts}{multiple}--{long}[{help}]' \\"); debug!("write_flags_of:iter: Wrote...{}", &*l); @@ -598,13 +576,7 @@ fn write_flags_of(p: &Command, p_global: Option<&Command>) -> String { if let Some(aliases) = f.get_visible_aliases() { for alias in aliases { - let l = format!( - "'{conflicts}{multiple}--{arg}[{help}]' \\", - conflicts = conflicts, - multiple = multiple, - arg = alias, - help = help - ); + let l = format!("'{conflicts}{multiple}--{alias}[{help}]' \\"); debug!("write_flags_of:iter: Wrote...{}", &*l); @@ -622,12 +594,47 @@ fn write_positionals_of(p: &Command) -> String { let mut ret = vec![]; + // Completions for commands that end with two Vec arguments require special care. + // - You can have two Vec args separated with a custom value terminator. + // - You can have two Vec args with the second one set to last (raw sets last) + // which will require a '--' separator to be used before the second argument + // on the command-line. + // + // We use the '-S' _arguments option to disable completion after '--'. Thus, the + // completion for the second argument in scenario (B) does not need to be emitted + // because it is implicitly handled by the '-S' option. + // We only need to emit the first catch-all. + // + // Have we already emitted a catch-all multi-valued positional argument + // without a custom value terminator? + let mut catch_all_emitted = false; + for arg in p.get_positionals() { debug!("write_positionals_of:iter: arg={}", arg.get_id()); let num_args = arg.get_num_args().expect("built"); - let cardinality = if num_args.max_values() > 1 { - "*:" + let is_multi_valued = num_args.max_values() > 1; + + if catch_all_emitted && (arg.is_last_set() || is_multi_valued) { + // This is the final argument and it also takes multiple arguments. + // We've already emitted a catch-all positional argument so we don't need + // to emit anything for this argument because it is implicitly handled by + // the use of the '-S' _arguments option. + continue; + } + + let cardinality_value; + let cardinality = if is_multi_valued { + match arg.get_value_terminator() { + Some(terminator) => { + cardinality_value = format!("*{}:", escape_value(terminator)); + cardinality_value.as_str() + } + None => { + catch_all_emitted = true; + "*:" + } + } } else if !arg.is_required_set() { ":" } else { @@ -641,7 +648,8 @@ fn write_positionals_of(p: &Command) -> String { help = arg .get_help() .map(|s| s.to_string()) - .map_or("".to_owned(), |v| " -- ".to_owned() + &v) + .map(|v| " -- ".to_owned() + &v) + .unwrap_or_else(|| "".to_owned()) .replace('[', "\\[") .replace(']', "\\]") .replace('\'', "'\\''") @@ -649,10 +657,33 @@ fn write_positionals_of(p: &Command) -> String { value_completion = value_completion(arg).unwrap_or_default() ); - debug!("write_positionals_of:iter: Wrote...{}", a); + debug!("write_positionals_of:iter: Wrote...{a}"); ret.push(a); } ret.join("\n") } + +#[cfg(test)] +mod tests { + use crate::shells::zsh::{escape_help, escape_value}; + + #[test] + fn test_escape_value() { + let raw_string = "\\ [foo]() `bar https://$PATH"; + assert_eq!( + escape_value(raw_string), + "\\\\\\ \\[foo\\]\\(\\)\\ \\`bar\\ https\\://\\$PATH" + ) + } + + #[test] + fn test_escape_help() { + let raw_string = "\\ [foo]() `bar https://$PATH"; + assert_eq!( + escape_help(raw_string), + "\\\\ \\[foo\\]() \\`bar https\\://\\$PATH" + ) + } +} |