Skip to content

Commit

Permalink
feat(clap_complete): Support delimiter values in native completions
Browse files Browse the repository at this point in the history
  • Loading branch information
shannmu authored and epage committed Aug 16, 2024
1 parent ccecab3 commit 59bf26d
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 10 deletions.
22 changes: 22 additions & 0 deletions clap_complete/src/dynamic/complete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,9 @@ fn complete_arg_value(
let mut values = Vec::new();
debug!("complete_arg_value: arg={arg:?}, value={value:?}");

let (prefix, value) =
rsplit_delimiter(value, arg.get_value_delimiter()).unwrap_or((None, value));

let value_os = match value {
Ok(value) => OsStr::new(value),
Err(value_os) => value_os,
Expand Down Expand Up @@ -316,9 +319,28 @@ fn complete_arg_value(
values.sort();
}

if let Some(prefix) = prefix {
values = values
.into_iter()
.map(|comp| comp.add_prefix(prefix))
.collect();
}
values
}

fn rsplit_delimiter<'s, 'o>(
value: Result<&'s str, &'o OsStr>,
delimiter: Option<char>,
) -> Option<(Option<&'s str>, Result<&'s str, &'o OsStr>)> {
let delimiter = delimiter?;
let value = value.ok()?;
let pos = value.rfind(delimiter)?;
let (prefix, value) = value
.split_at_checked(pos + delimiter.len_utf8())
.expect("since delimiter was found, it is within bounds");
Some((Some(prefix), Ok(value)))
}

fn complete_path(
value_os: &OsStr,
current_dir: Option<&std::path::Path>,
Expand Down
70 changes: 60 additions & 10 deletions clap_complete/tests/testsuite/dynamic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -661,18 +661,35 @@ tab"
snapbox::str!["--delimiter=comma"]
);

assert_data_eq!(complete!(cmd, "--delimiter comma,[TAB]"), snapbox::str![""]);
assert_data_eq!(
complete!(cmd, "--delimiter comma,[TAB]"),
snapbox::str![
"comma,comma
comma,space
comma,tab"
]
);

assert_data_eq!(complete!(cmd, "--delimiter=comma,[TAB]"), snapbox::str![""]);
assert_data_eq!(
complete!(cmd, "--delimiter=comma,[TAB]"),
snapbox::str![
"--delimiter=comma,comma
--delimiter=comma,space
--delimiter=comma,tab
--delimiter=comma,a_pos
--delimiter=comma,b_pos
--delimiter=comma,c_pos"
]
);

assert_data_eq!(
complete!(cmd, "--delimiter comma,s[TAB]"),
snapbox::str![""]
snapbox::str!["comma,space"]
);

assert_data_eq!(
complete!(cmd, "--delimiter=comma,s[TAB]"),
snapbox::str![""]
snapbox::str!["--delimiter=comma,space"]
);

assert_data_eq!(
Expand All @@ -697,13 +714,36 @@ tab"

assert_data_eq!(complete!(cmd, "-D=c[TAB]"), snapbox::str!["-D=comma"]);

assert_data_eq!(complete!(cmd, "-D comma,[TAB]"), snapbox::str![""]);
assert_data_eq!(
complete!(cmd, "-D comma,[TAB]"),
snapbox::str![
"comma,comma
comma,space
comma,tab"
]
);

assert_data_eq!(complete!(cmd, "-D=comma,[TAB]"), snapbox::str![""]);
assert_data_eq!(
complete!(cmd, "-D=comma,[TAB]"),
snapbox::str![
"-D=comma,comma
-D=comma,space
-D=comma,tab
-D=comma,a_pos
-D=comma,b_pos
-D=comma,c_pos"
]
);

assert_data_eq!(complete!(cmd, "-D comma,s[TAB]"), snapbox::str![""]);
assert_data_eq!(
complete!(cmd, "-D comma,s[TAB]"),
snapbox::str!["comma,space"]
);

assert_data_eq!(complete!(cmd, "-D=comma,s[TAB]"), snapbox::str![""]);
assert_data_eq!(
complete!(cmd, "-D=comma,s[TAB]"),
snapbox::str!["-D=comma,space"]
);

assert_data_eq!(
complete!(cmd, "-- [TAB]"),
Expand All @@ -718,9 +758,19 @@ c_pos"
]
);

assert_data_eq!(complete!(cmd, " -- a_pos,[TAB]"), snapbox::str![""]);
assert_data_eq!(
complete!(cmd, " -- a_pos,[TAB]"),
snapbox::str![
"a_pos,a_pos
a_pos,b_pos
a_pos,c_pos"
]
);

assert_data_eq!(complete!(cmd, "-- a_pos,b[TAB]"), snapbox::str![""]);
assert_data_eq!(
complete!(cmd, "-- a_pos,b[TAB]"),
snapbox::str!["a_pos,b_pos"]
);
}

fn complete(cmd: &mut Command, args: impl AsRef<str>, current_dir: Option<&Path>) -> String {
Expand Down

0 comments on commit 59bf26d

Please sign in to comment.