From ccecab394b45bc4dd251d00b7d69737ed93d18f8 Mon Sep 17 00:00:00 2001 From: shannmu Date: Fri, 26 Jul 2024 00:22:32 +0800 Subject: [PATCH 1/2] test(clap_complete): Add test cases for delimiter_values support --- clap_complete/tests/testsuite/dynamic.rs | 108 +++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/clap_complete/tests/testsuite/dynamic.rs b/clap_complete/tests/testsuite/dynamic.rs index 6d8138f1352..4b3c20c8947 100644 --- a/clap_complete/tests/testsuite/dynamic.rs +++ b/clap_complete/tests/testsuite/dynamic.rs @@ -615,6 +615,114 @@ pos_c ); } +#[test] +fn suggest_delimiter_values() { + let mut cmd = Command::new("delimiter") + .arg( + clap::Arg::new("delimiter") + .long("delimiter") + .short('D') + .value_parser([ + PossibleValue::new("comma"), + PossibleValue::new("space"), + PossibleValue::new("tab"), + ]) + .value_delimiter(','), + ) + .arg( + clap::Arg::new("pos") + .index(1) + .value_parser(["a_pos", "b_pos", "c_pos"]) + .value_delimiter(','), + ); + + assert_data_eq!( + complete!(cmd, "--delimiter [TAB]"), + snapbox::str![ + "comma +space +tab" + ] + ); + + assert_data_eq!( + complete!(cmd, "--delimiter=[TAB]"), + snapbox::str![ + "--delimiter=comma +--delimiter=space +--delimiter=tab" + ] + ); + + assert_data_eq!(complete!(cmd, "--delimiter c[TAB]"), snapbox::str!["comma"]); + + assert_data_eq!( + complete!(cmd, "--delimiter=c[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![""]); + + assert_data_eq!( + complete!(cmd, "--delimiter comma,s[TAB]"), + snapbox::str![""] + ); + + assert_data_eq!( + complete!(cmd, "--delimiter=comma,s[TAB]"), + snapbox::str![""] + ); + + assert_data_eq!( + complete!(cmd, "-D [TAB]"), + snapbox::str![ + "comma +space +tab" + ] + ); + + assert_data_eq!( + complete!(cmd, "-D=[TAB]"), + snapbox::str![ + "-D=comma +-D=space +-D=tab" + ] + ); + + assert_data_eq!(complete!(cmd, "-D c[TAB]"), snapbox::str!["comma"]); + + 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![""]); + + assert_data_eq!(complete!(cmd, "-D comma,s[TAB]"), snapbox::str![""]); + + assert_data_eq!(complete!(cmd, "-D=comma,s[TAB]"), snapbox::str![""]); + + assert_data_eq!( + complete!(cmd, "-- [TAB]"), + snapbox::str![ + "--delimiter +--help\tPrint help +-D +-h\tPrint help +a_pos +b_pos +c_pos" + ] + ); + + assert_data_eq!(complete!(cmd, " -- a_pos,[TAB]"), snapbox::str![""]); + + assert_data_eq!(complete!(cmd, "-- a_pos,b[TAB]"), snapbox::str![""]); +} + fn complete(cmd: &mut Command, args: impl AsRef, current_dir: Option<&Path>) -> String { let input = args.as_ref(); let mut args = vec![std::ffi::OsString::from(cmd.get_name())]; From 59bf26dd56032a7a4e6d923cd37de6e72c33078e Mon Sep 17 00:00:00 2001 From: shanmu Date: Tue, 6 Aug 2024 00:17:11 +0800 Subject: [PATCH 2/2] feat(clap_complete): Support delimiter values in native completions --- clap_complete/src/dynamic/complete.rs | 22 ++++++++ clap_complete/tests/testsuite/dynamic.rs | 70 ++++++++++++++++++++---- 2 files changed, 82 insertions(+), 10 deletions(-) diff --git a/clap_complete/src/dynamic/complete.rs b/clap_complete/src/dynamic/complete.rs index dc2339317fb..4f1fea45ce1 100644 --- a/clap_complete/src/dynamic/complete.rs +++ b/clap_complete/src/dynamic/complete.rs @@ -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, @@ -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, +) -> 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>, diff --git a/clap_complete/tests/testsuite/dynamic.rs b/clap_complete/tests/testsuite/dynamic.rs index 4b3c20c8947..bbde81688e1 100644 --- a/clap_complete/tests/testsuite/dynamic.rs +++ b/clap_complete/tests/testsuite/dynamic.rs @@ -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!( @@ -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]"), @@ -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, current_dir: Option<&Path>) -> String {