Skip to content

Commit 82e599e

Browse files
authored
Merge pull request #5602 from shannmu/delimiter_values
Support delimited values in native completions
2 parents a3a4764 + 59bf26d commit 82e599e

File tree

2 files changed

+180
-0
lines changed

2 files changed

+180
-0
lines changed

clap_complete/src/dynamic/complete.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,9 @@ fn complete_arg_value(
262262
let mut values = Vec::new();
263263
debug!("complete_arg_value: arg={arg:?}, value={value:?}");
264264

265+
let (prefix, value) =
266+
rsplit_delimiter(value, arg.get_value_delimiter()).unwrap_or((None, value));
267+
265268
let value_os = match value {
266269
Ok(value) => OsStr::new(value),
267270
Err(value_os) => value_os,
@@ -316,9 +319,28 @@ fn complete_arg_value(
316319
values.sort();
317320
}
318321

322+
if let Some(prefix) = prefix {
323+
values = values
324+
.into_iter()
325+
.map(|comp| comp.add_prefix(prefix))
326+
.collect();
327+
}
319328
values
320329
}
321330

331+
fn rsplit_delimiter<'s, 'o>(
332+
value: Result<&'s str, &'o OsStr>,
333+
delimiter: Option<char>,
334+
) -> Option<(Option<&'s str>, Result<&'s str, &'o OsStr>)> {
335+
let delimiter = delimiter?;
336+
let value = value.ok()?;
337+
let pos = value.rfind(delimiter)?;
338+
let (prefix, value) = value
339+
.split_at_checked(pos + delimiter.len_utf8())
340+
.expect("since delimiter was found, it is within bounds");
341+
Some((Some(prefix), Ok(value)))
342+
}
343+
322344
fn complete_path(
323345
value_os: &OsStr,
324346
current_dir: Option<&std::path::Path>,

clap_complete/tests/testsuite/dynamic.rs

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,164 @@ pos_c
615615
);
616616
}
617617

618+
#[test]
619+
fn suggest_delimiter_values() {
620+
let mut cmd = Command::new("delimiter")
621+
.arg(
622+
clap::Arg::new("delimiter")
623+
.long("delimiter")
624+
.short('D')
625+
.value_parser([
626+
PossibleValue::new("comma"),
627+
PossibleValue::new("space"),
628+
PossibleValue::new("tab"),
629+
])
630+
.value_delimiter(','),
631+
)
632+
.arg(
633+
clap::Arg::new("pos")
634+
.index(1)
635+
.value_parser(["a_pos", "b_pos", "c_pos"])
636+
.value_delimiter(','),
637+
);
638+
639+
assert_data_eq!(
640+
complete!(cmd, "--delimiter [TAB]"),
641+
snapbox::str![
642+
"comma
643+
space
644+
tab"
645+
]
646+
);
647+
648+
assert_data_eq!(
649+
complete!(cmd, "--delimiter=[TAB]"),
650+
snapbox::str![
651+
"--delimiter=comma
652+
--delimiter=space
653+
--delimiter=tab"
654+
]
655+
);
656+
657+
assert_data_eq!(complete!(cmd, "--delimiter c[TAB]"), snapbox::str!["comma"]);
658+
659+
assert_data_eq!(
660+
complete!(cmd, "--delimiter=c[TAB]"),
661+
snapbox::str!["--delimiter=comma"]
662+
);
663+
664+
assert_data_eq!(
665+
complete!(cmd, "--delimiter comma,[TAB]"),
666+
snapbox::str![
667+
"comma,comma
668+
comma,space
669+
comma,tab"
670+
]
671+
);
672+
673+
assert_data_eq!(
674+
complete!(cmd, "--delimiter=comma,[TAB]"),
675+
snapbox::str![
676+
"--delimiter=comma,comma
677+
--delimiter=comma,space
678+
--delimiter=comma,tab
679+
--delimiter=comma,a_pos
680+
--delimiter=comma,b_pos
681+
--delimiter=comma,c_pos"
682+
]
683+
);
684+
685+
assert_data_eq!(
686+
complete!(cmd, "--delimiter comma,s[TAB]"),
687+
snapbox::str!["comma,space"]
688+
);
689+
690+
assert_data_eq!(
691+
complete!(cmd, "--delimiter=comma,s[TAB]"),
692+
snapbox::str!["--delimiter=comma,space"]
693+
);
694+
695+
assert_data_eq!(
696+
complete!(cmd, "-D [TAB]"),
697+
snapbox::str![
698+
"comma
699+
space
700+
tab"
701+
]
702+
);
703+
704+
assert_data_eq!(
705+
complete!(cmd, "-D=[TAB]"),
706+
snapbox::str![
707+
"-D=comma
708+
-D=space
709+
-D=tab"
710+
]
711+
);
712+
713+
assert_data_eq!(complete!(cmd, "-D c[TAB]"), snapbox::str!["comma"]);
714+
715+
assert_data_eq!(complete!(cmd, "-D=c[TAB]"), snapbox::str!["-D=comma"]);
716+
717+
assert_data_eq!(
718+
complete!(cmd, "-D comma,[TAB]"),
719+
snapbox::str![
720+
"comma,comma
721+
comma,space
722+
comma,tab"
723+
]
724+
);
725+
726+
assert_data_eq!(
727+
complete!(cmd, "-D=comma,[TAB]"),
728+
snapbox::str![
729+
"-D=comma,comma
730+
-D=comma,space
731+
-D=comma,tab
732+
-D=comma,a_pos
733+
-D=comma,b_pos
734+
-D=comma,c_pos"
735+
]
736+
);
737+
738+
assert_data_eq!(
739+
complete!(cmd, "-D comma,s[TAB]"),
740+
snapbox::str!["comma,space"]
741+
);
742+
743+
assert_data_eq!(
744+
complete!(cmd, "-D=comma,s[TAB]"),
745+
snapbox::str!["-D=comma,space"]
746+
);
747+
748+
assert_data_eq!(
749+
complete!(cmd, "-- [TAB]"),
750+
snapbox::str![
751+
"--delimiter
752+
--help\tPrint help
753+
-D
754+
-h\tPrint help
755+
a_pos
756+
b_pos
757+
c_pos"
758+
]
759+
);
760+
761+
assert_data_eq!(
762+
complete!(cmd, " -- a_pos,[TAB]"),
763+
snapbox::str![
764+
"a_pos,a_pos
765+
a_pos,b_pos
766+
a_pos,c_pos"
767+
]
768+
);
769+
770+
assert_data_eq!(
771+
complete!(cmd, "-- a_pos,b[TAB]"),
772+
snapbox::str!["a_pos,b_pos"]
773+
);
774+
}
775+
618776
fn complete(cmd: &mut Command, args: impl AsRef<str>, current_dir: Option<&Path>) -> String {
619777
let input = args.as_ref();
620778
let mut args = vec![std::ffi::OsString::from(cmd.get_name())];

0 commit comments

Comments
 (0)