diff --git a/clap_builder/src/builder/command.rs b/clap_builder/src/builder/command.rs index f67eb9c623f..0430323a53e 100644 --- a/clap_builder/src/builder/command.rs +++ b/clap_builder/src/builder/command.rs @@ -631,7 +631,7 @@ impl Command { /// [`env::args_os`]: std::env::args_os() /// [`Command::get_matches`]: Command::get_matches() pub fn get_matches_mut(&mut self) -> ArgMatches { - self.try_get_matches_from_mut(&mut env::args_os()) + self.try_get_matches_from_mut(env::args_os()) .unwrap_or_else(|e| e.exit()) } diff --git a/clap_builder/src/builder/debug_asserts.rs b/clap_builder/src/builder/debug_asserts.rs index ce890104f21..9e6154ab66a 100644 --- a/clap_builder/src/builder/debug_asserts.rs +++ b/clap_builder/src/builder/debug_asserts.rs @@ -370,7 +370,7 @@ pub(crate) fn assert_app(cmd: &Command) { "Command {}: {}", cmd.get_name(), "`{bin}` template variable was removed in clap5, use `{name}` instead" - ) + ); } cmd._panic_on_missing_help(cmd.is_help_expected_set()); diff --git a/clap_complete/src/dynamic/completer.rs b/clap_complete/src/dynamic/completer.rs index fd614cb9760..617d73d269f 100644 --- a/clap_complete/src/dynamic/completer.rs +++ b/clap_complete/src/dynamic/completer.rs @@ -92,7 +92,7 @@ pub fn complete( if value.is_some() { ParseState::ValueDone } else { - ParseState::Opt(opt.unwrap().clone()) + ParseState::Opt(opt.unwrap()) } } Some(clap::ArgAction::SetTrue) | Some(clap::ArgAction::SetFalse) => { @@ -115,7 +115,7 @@ pub fn complete( Some(opt) => { state = match short.next_value_os() { Some(_) => ParseState::ValueDone, - None => ParseState::Opt(opt.clone()), + None => ParseState::Opt(opt), }; } None => { @@ -142,7 +142,7 @@ pub fn complete( } #[derive(Debug, PartialEq, Eq, Clone)] -enum ParseState { +enum ParseState<'a> { /// Parsing a value done, there is no state to record. ValueDone, @@ -150,7 +150,7 @@ enum ParseState { Pos(usize), /// Parsing a optional flag argument - Opt(clap::Arg), + Opt(&'a clap::Arg), } fn complete_arg( @@ -158,7 +158,7 @@ fn complete_arg( cmd: &clap::Command, current_dir: Option<&std::path::Path>, pos_index: usize, - state: ParseState, + state: ParseState<'_>, ) -> Result, std::io::Error> { debug!( "complete_arg: arg={:?}, cmd={:?}, current_dir={:?}, pos_index={:?}, state={:?}", @@ -202,7 +202,7 @@ fn complete_arg( completions.extend(hidden_longs_aliases(cmd).into_iter().filter(|comp| { comp.get_content() .starts_with(format!("--{}", flag).as_str()) - })) + })); } } } else if arg.is_escape() || arg.is_stdio() || arg.is_empty() { @@ -236,7 +236,7 @@ fn complete_arg( } else if let Some(short) = arg.to_short() { if !short.is_negative_number() { // Find the first takes_value option. - let (leading_flags, takes_value_opt, mut short) = parse_shortflags(&cmd, short); + let (leading_flags, takes_value_opt, mut short) = parse_shortflags(cmd, short); // Clone `short` to `peek_short` to peek whether the next flag is a `=`. if let Some(opt) = takes_value_opt { @@ -250,7 +250,7 @@ fn complete_arg( let value = short.next_value_os().unwrap_or(OsStr::new("")); completions.extend( - complete_arg_value(value.to_str().ok_or(value), &opt, current_dir) + complete_arg_value(value.to_str().ok_or(value), opt, current_dir) .into_iter() .map(|comp| { CompletionCandidate::new(format!( @@ -299,11 +299,11 @@ fn complete_arg( } } ParseState::Opt(opt) => { - completions.extend(complete_arg_value(arg.to_value(), &opt, current_dir)); + completions.extend(complete_arg_value(arg.to_value(), opt, current_dir)); } } if completions.iter().any(|a| a.is_visible()) { - completions.retain(|a| a.is_visible()) + completions.retain(|a| a.is_visible()); } Ok(completions) @@ -452,7 +452,7 @@ fn longs_and_visible_aliases(p: &clap::Command) -> Vec { .filter_map(|a| { a.get_long_and_visible_aliases().map(|longs| { longs.into_iter().map(|s| { - CompletionCandidate::new(format!("--{}", s.to_string())) + CompletionCandidate::new(format!("--{}", s)) .help(a.get_help().cloned()) .visible(!a.is_hide_set()) }) @@ -470,7 +470,7 @@ fn hidden_longs_aliases(p: &clap::Command) -> Vec { .filter_map(|a| { a.get_aliases().map(|longs| { longs.into_iter().map(|s| { - CompletionCandidate::new(format!("--{}", s.to_string())) + CompletionCandidate::new(format!("--{}", s)) .help(a.get_help().cloned()) .visible(false) }) @@ -526,7 +526,7 @@ fn subcommands(p: &clap::Command) -> Vec { .help(sc.get_about().cloned()) .visible(!sc.is_hide_set()) }) - .chain(sc.get_aliases().into_iter().map(|s| { + .chain(sc.get_aliases().map(|s| { CompletionCandidate::new(s.to_string()) .help(sc.get_about().cloned()) .visible(false) @@ -535,11 +535,11 @@ fn subcommands(p: &clap::Command) -> Vec { .collect() } -/// Parse the short flags and find the first takes_value option. -fn parse_shortflags<'s>( - cmd: &clap::Command, +/// Parse the short flags and find the first `takes_value` option. +fn parse_shortflags<'c, 's>( + cmd: &'c clap::Command, mut short: clap_lex::ShortFlags<'s>, -) -> (OsString, Option, clap_lex::ShortFlags<'s>) { +) -> (OsString, Option<&'c clap::Arg>, clap_lex::ShortFlags<'s>) { let takes_value_opt; let mut leading_flags = OsString::new(); // Find the first takes_value option. @@ -579,7 +579,7 @@ fn parse_shortflags<'s>( } } - (leading_flags, takes_value_opt.cloned(), short) + (leading_flags, takes_value_opt, short) } /// A completion candidate definition diff --git a/clap_complete/src/dynamic/shells/bash.rs b/clap_complete/src/dynamic/shells/bash.rs index d01a932b080..ca6d791f514 100644 --- a/clap_complete/src/dynamic/shells/bash.rs +++ b/clap_complete/src/dynamic/shells/bash.rs @@ -23,7 +23,8 @@ impl crate::dynamic::Completer for Bash { let mut upper_name = escaped_name.clone(); upper_name.make_ascii_uppercase(); - let completer = shlex::quote(completer); + let completer = + shlex::try_quote(completer).unwrap_or(std::borrow::Cow::Borrowed(completer)); let script = r#" _clap_complete_NAME() { diff --git a/clap_complete/src/dynamic/shells/elvish.rs b/clap_complete/src/dynamic/shells/elvish.rs index 323226c672d..52767a65666 100644 --- a/clap_complete/src/dynamic/shells/elvish.rs +++ b/clap_complete/src/dynamic/shells/elvish.rs @@ -8,13 +8,14 @@ impl crate::dynamic::Completer for Elvish { } fn write_registration( &self, - name: &str, + _name: &str, bin: &str, completer: &str, buf: &mut dyn std::io::Write, ) -> Result<(), std::io::Error> { - let bin = shlex::quote(bin); - let completer = shlex::quote(completer); + let bin = shlex::try_quote(bin).unwrap_or(std::borrow::Cow::Borrowed(bin)); + let completer = + shlex::try_quote(completer).unwrap_or(std::borrow::Cow::Borrowed(completer)); let script = r#" set edit:completion:arg-completer[BIN] = { |@words| diff --git a/clap_complete/src/dynamic/shells/fish.rs b/clap_complete/src/dynamic/shells/fish.rs index 269539e0e03..c3ae1dba395 100644 --- a/clap_complete/src/dynamic/shells/fish.rs +++ b/clap_complete/src/dynamic/shells/fish.rs @@ -13,8 +13,10 @@ impl crate::dynamic::Completer for Fish { completer: &str, buf: &mut dyn std::io::Write, ) -> Result<(), std::io::Error> { - let bin = shlex::quote(bin); - let completer = shlex::quote(completer); + let bin = shlex::try_quote(bin).unwrap_or(std::borrow::Cow::Borrowed(bin)); + let completer = + shlex::try_quote(completer).unwrap_or(std::borrow::Cow::Borrowed(completer)); + writeln!( buf, r#"complete -x -c {bin} -a "("'{completer}'" complete --shell fish -- (commandline --current-process --tokenize --cut-at-cursor) (commandline --current-token))""# diff --git a/clap_complete/src/dynamic/shells/mod.rs b/clap_complete/src/dynamic/shells/mod.rs index 405d2abba97..1d6fc3c00fd 100644 --- a/clap_complete/src/dynamic/shells/mod.rs +++ b/clap_complete/src/dynamic/shells/mod.rs @@ -39,8 +39,8 @@ use crate::dynamic::Completer as _; /// #[derive(Parser, Debug)] /// #[clap(name = "dynamic", about = "A dynamic command line tool")] /// struct Cli { -/// /// The subcommand to run complete -/// #[command(subcommand)] +/// /// The subcommand to run complete +/// #[command(subcommand)] /// complete: Option, /// /// Input file path /// #[clap(short, long, value_hint = clap::ValueHint::FilePath)] @@ -54,9 +54,9 @@ use crate::dynamic::Completer as _; /// let cli = Cli::parse(); /// if let Some(completions) = cli.complete { /// completions.complete(&mut Cli::command()); -/// } +/// } /// -/// // normal logic continues... +/// // normal logic continues... /// } ///``` /// @@ -68,29 +68,29 @@ use crate::dynamic::Completer as _; /// please remember to modify the redirection output file in the following command. /// /// - Bash -/// ```bash -/// echo "source <(your_program complete --shell bash --register -)" >> ~/.bashrc -/// ``` +/// ```bash +/// echo "source <(your_program complete --shell bash --register -)" >> ~/.bashrc +/// ``` /// /// - Fish -/// ```fish -/// echo "source (your_program complete --shell fish --register - | psub)" >> ~/.config/fish/config.fish -/// ``` +/// ```fish +/// echo "source (your_program complete --shell fish --register - | psub)" >> ~/.config/fish/config.fish +/// ``` /// /// - Zsh -/// ```zsh -/// echo "source <(your_program complete --shell zsh --register -)" >> ~/.zshrc -/// ``` +/// ```zsh +/// echo "source <(your_program complete --shell zsh --register -)" >> ~/.zshrc +/// ``` /// /// - Elvish -/// ```elvish -/// echo "eval (your_program complete --shell elvish --register -)" >> ~/.elvish/rc.elv -/// ``` +/// ```elvish +/// echo "eval (your_program complete --shell elvish --register -)" >> ~/.elvish/rc.elv +/// ``` /// /// - Powershell -/// ```powershell -/// echo "your_program complete --shell powershell --register - | Invoke-Expression" >> $PROFILE -/// ``` +/// ```powershell +/// echo "your_program complete --shell powershell --register - | Invoke-Expression" >> $PROFILE +/// ``` /// #[derive(clap::Subcommand)] #[allow(missing_docs)] diff --git a/clap_complete/src/dynamic/shells/zsh.rs b/clap_complete/src/dynamic/shells/zsh.rs index 4326cd16dc7..326d29ce670 100644 --- a/clap_complete/src/dynamic/shells/zsh.rs +++ b/clap_complete/src/dynamic/shells/zsh.rs @@ -13,8 +13,10 @@ impl crate::dynamic::Completer for Zsh { completer: &str, buf: &mut dyn std::io::Write, ) -> Result<(), std::io::Error> { - let bin = shlex::quote(bin); - let completer = shlex::quote(completer); + let bin = shlex::try_quote(bin).unwrap_or(std::borrow::Cow::Borrowed(bin)); + let completer = + shlex::try_quote(completer).unwrap_or(std::borrow::Cow::Borrowed(completer)); + let script = r#"#compdef BIN function _clap_dynamic_completer() { export _CLAP_COMPLETE_INDEX=$(expr $CURRENT - 1) diff --git a/clap_complete/tests/testsuite/dynamic.rs b/clap_complete/tests/testsuite/dynamic.rs index 81057cd55d3..0264aea38ab 100644 --- a/clap_complete/tests/testsuite/dynamic.rs +++ b/clap_complete/tests/testsuite/dynamic.rs @@ -52,7 +52,7 @@ fn suggest_hidden_long_flags() { assert_data_eq!( complete!(cmd, "--hello-world-h"), snapbox::str!["--hello-world-hidden"] - ) + ); } #[test] @@ -90,7 +90,7 @@ test_hidden-alias_visible" assert_data_eq!( complete!(cmd, "test_hidden-alias_h"), snapbox::str!["test_hidden-alias_hidden"] - ) + ); } #[test] @@ -142,7 +142,7 @@ fn suggest_hidden_possible_value() { assert_data_eq!( complete!(cmd, "--test=test-h"), snapbox::str!["--test=test-hidden\tSay hello to the moon"] - ) + ); } #[test] @@ -436,7 +436,7 @@ pos_c" assert_data_eq!( complete!(cmd, "-ciF=[TAB]", current_dir = Some(testdir_path)), snapbox::str![""] - ) + ); } fn complete(cmd: &mut Command, args: impl AsRef, current_dir: Option<&Path>) -> String {