@@ -53,9 +53,10 @@ pub fn complete(
53
53
let mut current_cmd = & * cmd;
54
54
let mut pos_index = 1 ;
55
55
let mut is_escaped = false ;
56
+ let mut state = ParseState :: ValueDone ;
56
57
while let Some ( arg) = raw_args. next ( & mut cursor) {
57
58
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 ) ;
59
60
}
60
61
61
62
debug ! ( "complete::next: Begin parsing '{:?}'" , arg. to_value_os( ) , ) ;
@@ -64,18 +65,22 @@ pub fn complete(
64
65
if let Some ( next_cmd) = current_cmd. find_subcommand ( value) {
65
66
current_cmd = next_cmd;
66
67
pos_index = 1 ;
68
+ state = ParseState :: ValueDone ;
67
69
continue ;
68
70
}
69
71
}
70
72
71
73
if is_escaped {
72
74
pos_index += 1 ;
75
+ state = ParseState :: Pos ( pos_index) ;
73
76
} else if arg. is_escape ( ) {
74
77
is_escaped = true ;
78
+ state = ParseState :: ValueDone ;
75
79
} else if let Some ( _long) = arg. to_long ( ) {
76
80
} else if let Some ( _short) = arg. to_short ( ) {
77
81
} else {
78
82
pos_index += 1 ;
83
+ state = ParseState :: ValueDone ;
79
84
}
80
85
}
81
86
@@ -85,96 +90,117 @@ pub fn complete(
85
90
) )
86
91
}
87
92
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
+
88
102
fn complete_arg (
89
103
arg : & clap_lex:: ParsedArg < ' _ > ,
90
104
cmd : & clap:: Command ,
91
105
current_dir : Option < & std:: path:: Path > ,
92
106
pos_index : usize ,
93
- is_escaped : bool ,
107
+ state : ParseState ,
94
108
) -> Result < Vec < CompletionCandidate > , std:: io:: Error > {
95
109
debug ! (
96
- "complete_arg: arg={:?}, cmd={:?}, current_dir={:?}, pos_index={}, is_escaped={ }" ,
110
+ "complete_arg: arg={:?}, cmd={:?}, current_dir={:?}, pos_index={:? }, state={:? }" ,
97
111
arg,
98
112
cmd. get_name( ) ,
99
113
current_dir,
100
114
pos_index,
101
- is_escaped
115
+ state
102
116
) ;
103
117
let mut completions = Vec :: < CompletionCandidate > :: new ( ) ;
104
118
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
+ } ) )
123
152
}
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
- } ) )
134
153
}
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) ) ;
139
157
140
- completions. extend ( hidden_longs_aliases ( cmd) ) ;
141
- }
158
+ completions. extend ( hidden_longs_aliases ( cmd) ) ;
159
+ }
142
160
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
+ }
166
183
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
+ }
173
190
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
+ }
176
203
}
177
-
178
204
if completions. iter ( ) . any ( |a| a. is_visible ( ) ) {
179
205
completions. retain ( |a| a. is_visible ( ) )
180
206
}
0 commit comments