11#![ cfg( feature = "unstable-dynamic" ) ]
22
3+ use std:: path:: Path ;
4+
5+ use clap:: Command ;
6+
7+ macro_rules! complete {
8+ ( $cmd: expr, $input: expr$( , current_dir = $current_dir: expr) ? $( , ) ?) => {
9+ {
10+ #[ allow( unused) ]
11+ let current_dir = None ;
12+ $( let current_dir = $current_dir; ) ?
13+ complete( & mut $cmd, $input, current_dir)
14+ }
15+ }
16+ }
17+
318#[ test]
419fn suggest_subcommand_subset ( ) {
5- let name = "exhaustive" ;
6- let mut cmd = clap:: Command :: new ( name)
7- . subcommand ( clap:: Command :: new ( "hello-world" ) )
8- . subcommand ( clap:: Command :: new ( "hello-moon" ) )
9- . subcommand ( clap:: Command :: new ( "goodbye-world" ) ) ;
10-
11- let args = [ name, "he" ] ;
12- let arg_index = 1 ;
13- let args = IntoIterator :: into_iter ( args)
14- . map ( std:: ffi:: OsString :: from)
15- . collect :: < Vec < _ > > ( ) ;
16- let current_dir = None ;
17-
18- let completions =
19- clap_complete:: dynamic:: complete ( & mut cmd, args, arg_index, current_dir) . unwrap ( ) ;
20- let completions = completions
21- . into_iter ( )
22- . map ( |s| s. 0 . to_string_lossy ( ) . into_owned ( ) )
23- . collect :: < Vec < _ > > ( ) ;
24-
25- assert_eq ! ( completions, [ "hello-moon" , "hello-world" , "help" ] ) ;
20+ let mut cmd = Command :: new ( "exhaustive" )
21+ . subcommand ( Command :: new ( "hello-world" ) )
22+ . subcommand ( Command :: new ( "hello-moon" ) )
23+ . subcommand ( Command :: new ( "goodbye-world" ) ) ;
24+
25+ snapbox:: assert_eq (
26+ "hello-moon
27+ hello-world
28+ help\t Print this message or the help of the given subcommand(s)" ,
29+ complete ! ( cmd, "he" ) ,
30+ ) ;
2631}
2732
2833#[ test]
2934fn suggest_long_flag_subset ( ) {
30- let name = "exhaustive" ;
31- let mut cmd = clap:: Command :: new ( name)
35+ let mut cmd = Command :: new ( "exhaustive" )
3236 . arg (
3337 clap:: Arg :: new ( "hello-world" )
3438 . long ( "hello-world" )
@@ -45,53 +49,33 @@ fn suggest_long_flag_subset() {
4549 . action ( clap:: ArgAction :: Count ) ,
4650 ) ;
4751
48- let args = [ name, "--he" ] ;
49- let arg_index = 1 ;
50- let args = IntoIterator :: into_iter ( args)
51- . map ( std:: ffi:: OsString :: from)
52- . collect :: < Vec < _ > > ( ) ;
53- let current_dir = None ;
54-
55- let completions =
56- clap_complete:: dynamic:: complete ( & mut cmd, args, arg_index, current_dir) . unwrap ( ) ;
57- let completions = completions
58- . into_iter ( )
59- . map ( |s| s. 0 . to_string_lossy ( ) . into_owned ( ) )
60- . collect :: < Vec < _ > > ( ) ;
61-
62- assert_eq ! ( completions, [ "--hello-world" , "--hello-moon" , "--help" ] ) ;
52+ snapbox:: assert_eq (
53+ "--hello-world
54+ --hello-moon
55+ --help\t Print help" ,
56+ complete ! ( cmd, "--he" ) ,
57+ ) ;
6358}
6459
6560#[ test]
6661fn suggest_possible_value_subset ( ) {
6762 let name = "exhaustive" ;
68- let mut cmd = clap :: Command :: new ( name) . arg ( clap:: Arg :: new ( "hello-world" ) . value_parser ( [
63+ let mut cmd = Command :: new ( name) . arg ( clap:: Arg :: new ( "hello-world" ) . value_parser ( [
6964 "hello-world" ,
7065 "hello-moon" ,
7166 "goodbye-world" ,
7267 ] ) ) ;
7368
74- let args = [ name, "hello" ] ;
75- let arg_index = 1 ;
76- let args = IntoIterator :: into_iter ( args)
77- . map ( std:: ffi:: OsString :: from)
78- . collect :: < Vec < _ > > ( ) ;
79- let current_dir = None ;
80-
81- let completions =
82- clap_complete:: dynamic:: complete ( & mut cmd, args, arg_index, current_dir) . unwrap ( ) ;
83- let completions = completions
84- . into_iter ( )
85- . map ( |s| s. 0 . to_string_lossy ( ) . into_owned ( ) )
86- . collect :: < Vec < _ > > ( ) ;
87-
88- assert_eq ! ( completions, [ "hello-world" , "hello-moon" ] ) ;
69+ snapbox:: assert_eq (
70+ "hello-world
71+ hello-moon" ,
72+ complete ! ( cmd, "hello" ) ,
73+ ) ;
8974}
9075
9176#[ test]
9277fn suggest_additional_short_flags ( ) {
93- let name = "exhaustive" ;
94- let mut cmd = clap:: Command :: new ( name)
78+ let mut cmd = Command :: new ( "exhaustive" )
9579 . arg (
9680 clap:: Arg :: new ( "a" )
9781 . short ( 'a' )
@@ -108,19 +92,47 @@ fn suggest_additional_short_flags() {
10892 . action ( clap:: ArgAction :: Count ) ,
10993 ) ;
11094
111- let args = [ name, "-a" ] ;
112- let arg_index = 1 ;
113- let args = IntoIterator :: into_iter ( args)
114- . map ( std:: ffi:: OsString :: from)
115- . collect :: < Vec < _ > > ( ) ;
116- let current_dir = None ;
95+ snapbox:: assert_eq (
96+ "-aa
97+ -ab
98+ -ac
99+ -ah\t Print help" ,
100+ complete ! ( cmd, "-a" ) ,
101+ ) ;
102+ }
117103
118- let completions =
119- clap_complete:: dynamic:: complete ( & mut cmd, args, arg_index, current_dir) . unwrap ( ) ;
120- let completions = completions
104+ fn complete ( cmd : & mut Command , args : impl AsRef < str > , current_dir : Option < & Path > ) -> String {
105+ let input = args. as_ref ( ) ;
106+ let mut args = vec ! [ std:: ffi:: OsString :: from( cmd. get_name( ) ) ] ;
107+ let arg_index;
108+
109+ if let Some ( ( prior, after) ) = input. split_once ( "[TAB]" ) {
110+ args. extend ( prior. split_whitespace ( ) . map ( From :: from) ) ;
111+ if prior. ends_with ( char:: is_whitespace) {
112+ args. push ( std:: ffi:: OsString :: default ( ) )
113+ }
114+ arg_index = args. len ( ) - 1 ;
115+ // HACK: this cannot handle in-word '[TAB]'
116+ args. extend ( after. split_whitespace ( ) . map ( From :: from) ) ;
117+ } else {
118+ args. extend ( input. split_whitespace ( ) . map ( From :: from) ) ;
119+ if input. ends_with ( char:: is_whitespace) {
120+ args. push ( std:: ffi:: OsString :: default ( ) )
121+ }
122+ arg_index = args. len ( ) - 1 ;
123+ }
124+
125+ clap_complete:: dynamic:: complete ( cmd, args, arg_index, current_dir)
126+ . unwrap ( )
121127 . into_iter ( )
122- . map ( |s| s. 0 . to_string_lossy ( ) . into_owned ( ) )
123- . collect :: < Vec < _ > > ( ) ;
124-
125- assert_eq ! ( completions, [ "-aa" , "-ab" , "-ac" , "-ah" ] ) ;
128+ . map ( |( compl, help) | {
129+ let compl = compl. to_str ( ) . unwrap ( ) ;
130+ if let Some ( help) = help {
131+ format ! ( "{compl}\t {help}" )
132+ } else {
133+ compl. to_owned ( )
134+ }
135+ } )
136+ . collect :: < Vec < _ > > ( )
137+ . join ( "\n " )
126138}
0 commit comments