summaryrefslogtreecommitdiffstats
path: root/vendor/clap_complete/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
commit9835e2ae736235810b4ea1c162ca5e65c547e770 (patch)
tree3fcebf40ed70e581d776a8a4c65923e8ec20e026 /vendor/clap_complete/src
parentReleasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff)
downloadrustc-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.rs44
-rw-r--r--vendor/clap_complete/src/generator/mod.rs31
-rw-r--r--vendor/clap_complete/src/lib.rs2
-rw-r--r--vendor/clap_complete/src/shells/bash.rs21
-rw-r--r--vendor/clap_complete/src/shells/elvish.rs14
-rw-r--r--vendor/clap_complete/src/shells/fish.rs14
-rw-r--r--vendor/clap_complete/src/shells/powershell.rs92
-rw-r--r--vendor/clap_complete/src/shells/shell.rs2
-rw-r--r--vendor/clap_complete/src/shells/zsh.rs153
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"
+ )
+ }
+}