@@ -53,9 +53,10 @@ pub fn complete(
5353 let mut current_cmd = & * cmd;
5454 let mut pos_index = 1 ;
5555 let mut is_escaped = false ;
56+ let mut state = ParseState :: ValueDone ;
5657 while let Some ( arg) = raw_args. next ( & mut cursor) {
5758 if cursor == target_cursor {
58- return complete_arg ( & arg, current_cmd, current_dir, pos_index, is_escaped ) ;
59+ return complete_arg ( & arg, current_cmd, current_dir, pos_index, state ) ;
5960 }
6061
6162 debug ! ( "complete::next: Begin parsing '{:?}'" , arg. to_value_os( ) , ) ;
@@ -64,18 +65,22 @@ pub fn complete(
6465 if let Some ( next_cmd) = current_cmd. find_subcommand ( value) {
6566 current_cmd = next_cmd;
6667 pos_index = 1 ;
68+ state = ParseState :: ValueDone ;
6769 continue ;
6870 }
6971 }
7072
7173 if is_escaped {
7274 pos_index += 1 ;
75+ state = ParseState :: Pos ( pos_index) ;
7376 } else if arg. is_escape ( ) {
7477 is_escaped = true ;
78+ state = ParseState :: ValueDone ;
7579 } else if let Some ( _long) = arg. to_long ( ) {
7680 } else if let Some ( _short) = arg. to_short ( ) {
7781 } else {
7882 pos_index += 1 ;
83+ state = ParseState :: ValueDone ;
7984 }
8085 }
8186
@@ -85,96 +90,117 @@ pub fn complete(
8590 ) )
8691}
8792
93+ #[ derive( Debug , PartialEq , Eq , Clone ) ]
94+ enum ParseState {
95+ /// Parsing a value done, there is no state to record.
96+ ValueDone ,
97+
98+ /// Parsing a positional argument after `--`
99+ Pos ( usize ) ,
100+ }
101+
88102fn complete_arg (
89103 arg : & clap_lex:: ParsedArg < ' _ > ,
90104 cmd : & clap:: Command ,
91105 current_dir : Option < & std:: path:: Path > ,
92106 pos_index : usize ,
93- is_escaped : bool ,
107+ state : ParseState ,
94108) -> Result < Vec < CompletionCandidate > , std:: io:: Error > {
95109 debug ! (
96- "complete_arg: arg={:?}, cmd={:?}, current_dir={:?}, pos_index={}, is_escaped={ }" ,
110+ "complete_arg: arg={:?}, cmd={:?}, current_dir={:?}, pos_index={:? }, state={:? }" ,
97111 arg,
98112 cmd. get_name( ) ,
99113 current_dir,
100114 pos_index,
101- is_escaped
115+ state
102116 ) ;
103117 let mut completions = Vec :: < CompletionCandidate > :: new ( ) ;
104118
105- if !is_escaped {
106- if let Some ( ( flag, value) ) = arg. to_long ( ) {
107- if let Ok ( flag) = flag {
108- if let Some ( value) = value {
109- if let Some ( arg) = cmd. get_arguments ( ) . find ( |a| a. get_long ( ) == Some ( flag) ) {
110- completions. extend (
111- complete_arg_value ( value. to_str ( ) . ok_or ( value) , arg, current_dir)
112- . into_iter ( )
113- . map ( |comp| {
114- CompletionCandidate :: new ( format ! (
115- "--{}={}" ,
116- flag,
117- comp. get_content( ) . to_string_lossy( )
118- ) )
119- . help ( comp. get_help ( ) . cloned ( ) )
120- . visible ( comp. is_visible ( ) )
121- } ) ,
122- ) ;
119+ match state {
120+ ParseState :: ValueDone => {
121+ if let Some ( ( flag, value) ) = arg. to_long ( ) {
122+ if let Ok ( flag) = flag {
123+ if let Some ( value) = value {
124+ if let Some ( arg) = cmd. get_arguments ( ) . find ( |a| a. get_long ( ) == Some ( flag) )
125+ {
126+ completions. extend (
127+ complete_arg_value ( value. to_str ( ) . ok_or ( value) , arg, current_dir)
128+ . into_iter ( )
129+ . map ( |comp| {
130+ CompletionCandidate :: new ( format ! (
131+ "--{}={}" ,
132+ flag,
133+ comp. get_content( ) . to_string_lossy( )
134+ ) )
135+ . help ( comp. get_help ( ) . cloned ( ) )
136+ . visible ( comp. is_visible ( ) )
137+ } ) ,
138+ ) ;
139+ }
140+ } else {
141+ completions. extend ( longs_and_visible_aliases ( cmd) . into_iter ( ) . filter (
142+ |comp| {
143+ comp. get_content ( )
144+ . starts_with ( format ! ( "--{}" , flag) . as_str ( ) )
145+ } ,
146+ ) ) ;
147+
148+ completions. extend ( hidden_longs_aliases ( cmd) . into_iter ( ) . filter ( |comp| {
149+ comp. get_content ( )
150+ . starts_with ( format ! ( "--{}" , flag) . as_str ( ) )
151+ } ) )
123152 }
124- } else {
125- completions. extend ( longs_and_visible_aliases ( cmd) . into_iter ( ) . filter ( |comp| {
126- comp. get_content ( )
127- . starts_with ( format ! ( "--{}" , flag) . as_str ( ) )
128- } ) ) ;
129-
130- completions. extend ( hidden_longs_aliases ( cmd) . into_iter ( ) . filter ( |comp| {
131- comp. get_content ( )
132- . starts_with ( format ! ( "--{}" , flag) . as_str ( ) )
133- } ) )
134153 }
135- }
136- } else if arg. is_escape ( ) || arg. is_stdio ( ) || arg. is_empty ( ) {
137- // HACK: Assuming knowledge of is_escape / is_stdio
138- completions. extend ( longs_and_visible_aliases ( cmd) ) ;
154+ } else if arg. is_escape ( ) || arg. is_stdio ( ) || arg. is_empty ( ) {
155+ // HACK: Assuming knowledge of is_escape / is_stdio
156+ completions. extend ( longs_and_visible_aliases ( cmd) ) ;
139157
140- completions. extend ( hidden_longs_aliases ( cmd) ) ;
141- }
158+ completions. extend ( hidden_longs_aliases ( cmd) ) ;
159+ }
142160
143- if arg. is_empty ( ) || arg. is_stdio ( ) || arg. is_short ( ) {
144- let dash_or_arg = if arg. is_empty ( ) {
145- "-" . into ( )
146- } else {
147- arg. to_value_os ( ) . to_string_lossy ( )
148- } ;
149- // HACK: Assuming knowledge of is_stdio
150- completions. extend (
151- shorts_and_visible_aliases ( cmd)
152- . into_iter ( )
153- // HACK: Need better `OsStr` manipulation
154- . map ( |comp| {
155- CompletionCandidate :: new ( format ! (
156- "{}{}" ,
157- dash_or_arg,
158- comp. get_content( ) . to_string_lossy( )
159- ) )
160- . help ( comp. get_help ( ) . cloned ( ) )
161- . visible ( true )
162- } ) ,
163- ) ;
164- }
165- }
161+ if arg. is_empty ( ) || arg. is_stdio ( ) || arg. is_short ( ) {
162+ let dash_or_arg = if arg. is_empty ( ) {
163+ "-" . into ( )
164+ } else {
165+ arg. to_value_os ( ) . to_string_lossy ( )
166+ } ;
167+ // HACK: Assuming knowledge of is_stdio
168+ completions. extend (
169+ shorts_and_visible_aliases ( cmd)
170+ . into_iter ( )
171+ // HACK: Need better `OsStr` manipulation
172+ . map ( |comp| {
173+ CompletionCandidate :: new ( format ! (
174+ "{}{}" ,
175+ dash_or_arg,
176+ comp. get_content( ) . to_string_lossy( )
177+ ) )
178+ . help ( comp. get_help ( ) . cloned ( ) )
179+ . visible ( true )
180+ } ) ,
181+ ) ;
182+ }
166183
167- if let Some ( positional) = cmd
168- . get_positionals ( )
169- . find ( |p| p. get_index ( ) == Some ( pos_index) )
170- {
171- completions. extend ( complete_arg_value ( arg. to_value ( ) , positional, current_dir) . into_iter ( ) ) ;
172- }
184+ if let Some ( positional) = cmd
185+ . get_positionals ( )
186+ . find ( |p| p. get_index ( ) == Some ( pos_index) )
187+ {
188+ completions. extend ( complete_arg_value ( arg. to_value ( ) , positional, current_dir) ) ;
189+ }
173190
174- if let Ok ( value) = arg. to_value ( ) {
175- completions. extend ( complete_subcommand ( value, cmd) ) ;
191+ if let Ok ( value) = arg. to_value ( ) {
192+ completions. extend ( complete_subcommand ( value, cmd) ) ;
193+ }
194+ }
195+ ParseState :: Pos ( _) => {
196+ if let Some ( positional) = cmd
197+ . get_positionals ( )
198+ . find ( |p| p. get_index ( ) == Some ( pos_index) )
199+ {
200+ completions. extend ( complete_arg_value ( arg. to_value ( ) , positional, current_dir) ) ;
201+ }
202+ }
176203 }
177-
178204 if completions. iter ( ) . any ( |a| a. is_visible ( ) ) {
179205 completions. retain ( |a| a. is_visible ( ) )
180206 }
0 commit comments