summaryrefslogtreecommitdiffstats
path: root/vendor/clap_complete/src/shells/zsh.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/clap_complete/src/shells/zsh.rs')
-rw-r--r--vendor/clap_complete/src/shells/zsh.rs153
1 files changed, 92 insertions, 61 deletions
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"
+ )
+ }
+}