Merge pull request #5740 from epage/complete-id

fix(complete): De-duplicate built-in candidates
This commit is contained in:
Ed Page 2024-09-20 14:27:41 -04:00 committed by GitHub
commit 3af629a141
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 68 additions and 100 deletions

View file

@ -8,6 +8,7 @@ use clap::builder::StyledStr;
pub struct CompletionCandidate {
value: OsString,
help: Option<StyledStr>,
id: Option<String>,
hidden: bool,
}
@ -27,6 +28,14 @@ impl CompletionCandidate {
self
}
/// Only first for a given Id is shown
///
/// To reduce the risk of conflicts, this should likely contain a namespace.
pub fn id(mut self, id: Option<String>) -> Self {
self.id = id;
self
}
/// Set the visibility of the completion candidate
///
/// Only shown when there is no visible candidate for completing the current argument.
@ -60,6 +69,11 @@ impl CompletionCandidate {
self.help.as_ref()
}
/// Get the id used for de-duplicating
pub fn get_id(&self) -> Option<&String> {
self.id.as_ref()
}
/// Get the visibility of the completion candidate
pub fn is_hide_set(&self) -> bool {
self.hidden

View file

@ -257,6 +257,14 @@ fn complete_arg(
if completions.iter().any(|a| !a.is_hide_set()) {
completions.retain(|a| !a.is_hide_set());
}
let mut seen_ids = std::collections::HashSet::new();
completions.retain(move |a| {
if let Some(id) = a.get_id().cloned() {
seen_ids.insert(id)
} else {
true
}
});
Ok(completions)
}
@ -388,6 +396,7 @@ fn longs_and_visible_aliases(p: &clap::Command) -> Vec<CompletionCandidate> {
longs.into_iter().map(|s| {
CompletionCandidate::new(format!("--{}", s))
.help(a.get_help().cloned())
.id(Some(format!("arg::{}", a.get_id())))
.hide(a.is_hide_set())
})
})
@ -406,6 +415,7 @@ fn hidden_longs_aliases(p: &clap::Command) -> Vec<CompletionCandidate> {
longs.into_iter().map(|s| {
CompletionCandidate::new(format!("--{}", s))
.help(a.get_help().cloned())
.id(Some(format!("arg::{}", a.get_id())))
.hide(true)
})
})
@ -425,6 +435,7 @@ fn shorts_and_visible_aliases(p: &clap::Command) -> Vec<CompletionCandidate> {
shorts.into_iter().map(|s| {
CompletionCandidate::new(s.to_string())
.help(a.get_help().cloned())
.id(Some(format!("arg::{}", a.get_id())))
.hide(a.is_hide_set())
})
})
@ -458,11 +469,13 @@ fn subcommands(p: &clap::Command) -> Vec<CompletionCandidate> {
.map(|s| {
CompletionCandidate::new(s.to_string())
.help(sc.get_about().cloned())
.id(Some(format!("command::{}", sc.get_name())))
.hide(sc.is_hide_set())
})
.chain(sc.get_aliases().map(|s| {
CompletionCandidate::new(s.to_string())
.help(sc.get_about().cloned())
.id(Some(format!("command::{}", sc.get_name())))
.hide(true)
}))
})

View file

@ -255,8 +255,8 @@ fn complete_dynamic_env_toplevel() {
let input = "exhaustive \t\t";
let expected = snapbox::str![[r#"
%
action help last quote --global --help -h
alias hint pacman value --generate --version -V
action help last quote --global --help
alias hint pacman value --generate --version
"#]];
let actual = runtime.complete(input, &term).unwrap();
assert_data_eq!(actual, expected);
@ -275,10 +275,9 @@ fn complete_dynamic_env_quoted_help() {
let input = "exhaustive quote \t\t";
let expected = snapbox::str![[r#"
%
cmd-backslash cmd-expansions --single-quotes --brackets --help
cmd-backticks cmd-single-quotes --double-quotes --expansions --version
cmd-brackets escape-help --backticks --choice -h
cmd-double-quotes help --backslash --global -V
cmd-backslash cmd-double-quotes escape-help --double-quotes --brackets --global
cmd-backticks cmd-expansions help --backticks --expansions --help
cmd-brackets cmd-single-quotes --single-quotes --backslash --choice --version
"#]];
let actual = runtime.complete(input, &term).unwrap();
assert_data_eq!(actual, expected);

View file

@ -198,8 +198,8 @@ fn complete_dynamic_env_toplevel() {
let expected = snapbox::str![[r#"
% exhaustive --generate
COMPLETING argument
--generate --help -V action help last quote
--global --version -h alias hint pacman value
--generate --help action help last quote
--global --version alias hint pacman value
"#]];
let actual = runtime.complete(input, &term).unwrap();
assert_data_eq!(actual, expected);
@ -219,10 +219,9 @@ fn complete_dynamic_env_quoted_help() {
let expected = snapbox::str![[r#"
% exhaustive quote --backslash
COMPLETING argument
--backslash --double-quotes --single-quotes cmd-backslash cmd-expansions
--backticks --expansions --version cmd-backticks cmd-single-quotes
--brackets --global -V cmd-brackets escape-help
--choice --help -h cmd-double-quotes help
--backslash --choice --global --version cmd-brackets cmd-single-quotes
--backticks --double-quotes --help cmd-backslash cmd-double-quotes escape-help
--brackets --expansions --single-quotes cmd-backticks cmd-expansions help
"#]];
let actual = runtime.complete(input, &term).unwrap();
assert_data_eq!(actual, expected);

View file

@ -75,19 +75,12 @@ fn suggest_hidden_subcommand_and_aliases() {
assert_data_eq!(
complete!(cmd, "test"),
snapbox::str![[r#"
test_visible
test_visible-alias_visible
"#]]
snapbox::str!["test_visible"]
);
assert_data_eq!(
complete!(cmd, "test_h"),
snapbox::str![[r#"
test_hidden
test_hidden-alias_hidden
test_hidden-alias_visible
"#]]
snapbox::str!["test_hidden"]
);
assert_data_eq!(
@ -119,9 +112,7 @@ fn suggest_subcommand_aliases() {
complete!(cmd, "hello"),
snapbox::str![[r#"
hello-moon
hello-moon-foo
hello-world
hello-world-foo
"#]],
);
}
@ -167,19 +158,12 @@ fn suggest_hidden_long_flag_aliases() {
assert_data_eq!(
complete!(cmd, "--test"),
snapbox::str![[r#"
--test_visible
--test_visible-alias_visible
"#]]
snapbox::str!["--test_visible"]
);
assert_data_eq!(
complete!(cmd, "--test_h"),
snapbox::str![[r#"
--test_hidden
--test_hidden-alias_visible
--test_hidden-alias_hidden
"#]]
snapbox::str!["--test_hidden"]
);
assert_data_eq!(
@ -287,7 +271,6 @@ hello-world Say hello to the world
hello-moon
goodbye-world
--help Print help (see more with '--help')
-h Print help (see more with '--help')
"#]],
);
}
@ -361,10 +344,6 @@ pos_c
--stream
--count
--help Print help
-F
-S
-c
-h Print help
"#]]
);
@ -433,9 +412,6 @@ val3
--certain-num
--uncertain-num
--help Print help
-Y
-N
-h Print help
"#]]
);
@ -457,9 +433,6 @@ val3
--certain-num
--uncertain-num
--help Print help
-Y
-N
-h Print help
"#]]
);
@ -469,9 +442,6 @@ val3
--certain-num
--uncertain-num
--help Print help
-Y
-N
-h Print help
"#]]
);
@ -499,9 +469,6 @@ val3
--certain-num
--uncertain-num
--help Print help
-Y
-N
-h Print help
"#]]
);
@ -523,9 +490,6 @@ val3
--certain-num
--uncertain-num
--help Print help
-Y
-N
-h Print help
"#]]
);
@ -535,9 +499,6 @@ val3
--certain-num
--uncertain-num
--help Print help
-Y
-N
-h Print help
"#]]
);
}
@ -775,8 +736,6 @@ pos_b
pos_c
--format
--help Print help
-F
-h Print help
"#]]
);
@ -794,8 +753,6 @@ pos_c
snapbox::str![[r#"
--format
--help Print help
-F
-h Print help
"#]]
);
@ -935,8 +892,6 @@ b_pos
c_pos
--delimiter
--help Print help
-D
-h Print help
"#]]);
assert_data_eq!(complete!(cmd, " -- a_pos,[TAB]"), snapbox::str![[r#"
@ -1028,16 +983,12 @@ fn suggest_positional_long_allow_hyphen() {
pos_b
--format
--help Print help
-F
-h Print help
"#]]
);
assert_data_eq!(complete!(cmd, "-F --json --pos_a [TAB]"), snapbox::str![[r#"
pos_b
--format
--help Print help
-F
-h Print help
"#]]);
assert_data_eq!(
@ -1076,15 +1027,11 @@ fn suggest_positional_short_allow_hyphen() {
pos_b
--format
--help Print help
-F
-h Print help
"#]]);
assert_data_eq!(complete!(cmd, "-F --json -a [TAB]"), snapbox::str![[r#"
pos_b
--format
--help Print help
-F
-h Print help
"#]]);
assert_data_eq!(
@ -1125,30 +1072,20 @@ pos-a
pos-b
pos-c
--required-flag
--required-flag2
--optional-flag
--2optional-flag
--long-flag
--help Print help
-r
-o
-s
-h Print help
"#]]
);
assert_data_eq!(
complete!(cmd, "-[TAB]"),
snapbox::str![[r#"
--required-flag
--required-flag2
--optional-flag
--2optional-flag
--long-flag
--help Print help
-r
-o
-s
-h Print help
"#]]
);
}

View file

@ -192,11 +192,10 @@ fn complete_dynamic_env_toplevel() {
let input = "exhaustive \t\t";
let expected = snapbox::str![[r#"
% exhaustive action
action pacman --help (Print help)
alias quote --version (Print version)
help (Print this message or the help of the given subcommand(s)) value -h (Print help)
hint --global (everywhere) -V (Print version)
last --generate (generate)
action last --global (everywhere)
alias pacman --generate (generate)
help (Print this message or the help of the given subcommand(s)) quote --help (Print help)
hint value --version (Print version)
"#]];
let actual = runtime.complete(input, &term).unwrap();
assert_data_eq!(actual, expected);
@ -215,16 +214,24 @@ fn complete_dynamic_env_quoted_help() {
let input = "exhaustive quote \t\t";
let expected = snapbox::str![[r#"
% exhaustive quote
cmd-backslash (Avoid '/n') --backticks (For more information see `echo test`)
cmd-backticks (For more information see `echo test`) --backslash (Avoid '/n')
cmd-brackets (List packages [filter]) --brackets (List packages [filter])
cmd-double-quotes (Can be "always", "auto", or "never") --expansions (Execute the shell command with $SHELL)
cmd-expansions (Execute the shell command with $SHELL) --choice
cmd-single-quotes (Can be 'always', 'auto', or 'never') --global (everywhere)
escape-help (/tab "') --help (Print help (see more with '--help'))
help (Print this message or the help of the given subcommand(s)) --version (Print version)
--single-quotes (Can be 'always', 'auto', or 'never') -h (Print help (see more with '--help'))
--double-quotes (Can be "always", "auto", or "never") -V (Print version)
cmd-backslash (Avoid '/n')
cmd-backticks (For more information see `echo test`)
cmd-brackets (List packages [filter])
cmd-double-quotes (Can be "always", "auto", or "never")
cmd-expansions (Execute the shell command with $SHELL)
cmd-single-quotes (Can be 'always', 'auto', or 'never')
escape-help (/tab "')
help (Print this message or the help of the given subcommand(s))
--single-quotes (Can be 'always', 'auto', or 'never')
--double-quotes (Can be "always", "auto", or "never")
--backticks (For more information see `echo test`)
--backslash (Avoid '/n')
--brackets (List packages [filter])
--expansions (Execute the shell command with $SHELL)
--choice
--global (everywhere)
--help (Print help (see more with '--help'))
--version (Print version)
"#]];
let actual = runtime.complete(input, &term).unwrap();
assert_data_eq!(actual, expected);

View file

@ -185,8 +185,8 @@ fn complete_dynamic_env_toplevel() {
let input = "exhaustive \t\t";
let expected = snapbox::str![[r#"
% exhaustive
--generate --help -V action help last quote
--global --version -h alias hint pacman value
--generate --help action help last quote
--global --version alias hint pacman value
"#]];
let actual = runtime.complete(input, &term).unwrap();
assert_data_eq!(actual, expected);
@ -205,10 +205,9 @@ fn complete_dynamic_env_quoted_help() {
let input = "exhaustive quote \t\t";
let expected = snapbox::str![[r#"
% exhaustive quote
--backslash --double-quotes --single-quotes cmd-backslash cmd-expansions
--backticks --expansions --version cmd-backticks cmd-single-quotes
--brackets --global -V cmd-brackets escape-help
--choice --help -h cmd-double-quotes help
--backslash --choice --global --version cmd-brackets cmd-single-quotes
--backticks --double-quotes --help cmd-backslash cmd-double-quotes escape-help
--brackets --expansions --single-quotes cmd-backticks cmd-expansions help
"#]];
let actual = runtime.complete(input, &term).unwrap();
assert_data_eq!(actual, expected);