@@ -17,69 +17,67 @@ extension [ParsableCommand.Type] {
17
17
// - first is guaranteed non-empty in the one place where this computed var is used.
18
18
let commandName = first!. _commandName
19
19
return """
20
- function \( commandsAndPositionalsFunctionName) -S
21
- switch $positionals[1]
20
+ function \( shouldOfferCompletionsForFunctionName) -a expected_commands -a expected_positional_index
21
+ set -f unparsed_tokens ( \( tokensFunctionName) -pc)
22
+ set -f positional_index 0
23
+ set -f commands
24
+
25
+ switch $unparsed_tokens[1]
22
26
\( commandCases)
23
- case '*'
24
- set commands $positionals[1]
25
- set -e positionals[1]
26
27
end
27
- end
28
28
29
- function \( commandsAndPositionalsFunctionName) _helper -S -a argparse_options
30
- set -l option_specs $argv[2..]
31
- set -a commands $positionals[1]
32
- set -e positionals[1]
33
- if test -z $argparse_options
34
- argparse -n " $commands " $option_specs -- $positionals 2> /dev/null
35
- set positionals $argv
36
- else
37
- argparse (string split -- ' \( separator) ' $argparse_options) -n " $commands " $option_specs -- $positionals 2> /dev/null
38
- set positionals $argv
39
- end
29
+ test " $commands " = " $expected_commands " -a \\ ( -z " $expected_positional_index " -o " $expected_positional_index " -eq " $positional_index " \\ )
40
30
end
41
31
42
32
function \( tokensFunctionName)
43
- if test (string split -m 1 -f 1 -- . $FISH_VERSION) -gt 3
33
+ if test " $ (string split -m 1 -f 1 -- . " $FISH_VERSION " ) " -gt 3
44
34
commandline --tokens-raw $argv
45
35
else
46
36
commandline -o $argv
47
37
end
48
38
end
49
39
50
- function \( usingCommandFunctionName) -a expected_commands
51
- set commands
52
- set positionals ( \( tokensFunctionName) -pc)
53
- \( commandsAndPositionalsFunctionName)
54
- test " $commands " = $expected_commands
55
- end
40
+ function \( parseSubcommandFunctionName) -S
41
+ argparse -s r -- $argv
42
+ set -f positional_count $argv[1]
43
+ set -f option_specs $argv[2..]
56
44
57
- function \( positionalIndexFunctionName)
58
- set positionals ( \( tokensFunctionName) -pc)
59
- \( commandsAndPositionalsFunctionName)
60
- math (count $positionals) + 1
45
+ set -a commands $unparsed_tokens[1]
46
+ set -e unparsed_tokens[1]
47
+
48
+ set positional_index 0
49
+
50
+ while true
51
+ argparse -sn " $commands " $option_specs -- $unparsed_tokens 2> /dev/null
52
+ set unparsed_tokens $argv
53
+ set positional_index (math $positional_index + 1)
54
+ if test (count $unparsed_tokens) -eq 0 -o \\ ( -z " $_flag_r " -a " $positional_index " -gt " $positional_count " \\ )
55
+ return 0
56
+ end
57
+ set -e unparsed_tokens[1]
58
+ end
61
59
end
62
60
63
61
function \( completeDirectoriesFunctionName)
64
- set token (commandline -t)
62
+ set -f token (commandline -t)
65
63
string match -- '*/' $token
66
- set subdirs $token*/
64
+ set -f subdirs $token*/
67
65
printf '%s \\ n' $subdirs
68
66
end
69
67
70
68
function \( customCompletionFunctionName)
71
69
set -x \( CompletionShell . shellEnvironmentVariableName) fish
72
70
set -x \( CompletionShell . shellVersionEnvironmentVariableName) $FISH_VERSION
73
71
74
- set tokens ( \( tokensFunctionName) -p)
75
- if test -z ( \( tokensFunctionName) -t)
76
- set index (count ( \( tokensFunctionName) -pc))
77
- set tokens $tokens[..$index] \\ ' \\ ' $tokens[$(math $index + 1)..]
72
+ set -f tokens ( \( tokensFunctionName) -p)
73
+ if test -z " $ (\( tokensFunctionName) -t) "
74
+ set -f index (count ( \( tokensFunctionName) -pc))
75
+ set -f tokens $tokens[..$index] \\ ' \\ ' $tokens[$(math $index + 1)..]
78
76
end
79
77
command $tokens[1] $argv $tokens
80
78
end
81
79
82
- complete -c \( commandName) -f
80
+ complete -c ' \( commandName) ' -f
83
81
\( completions. joined ( separator: " \n " ) )
84
82
"""
85
83
}
@@ -90,9 +88,7 @@ extension [ParsableCommand.Type] {
90
88
// Precondition: last is guaranteed to be non-empty
91
89
return """
92
90
case ' \( last!. _commandName) '
93
- \( commandsAndPositionalsFunctionName) _helper ' \(
94
- subcommands. isEmpty ? " " : " -s "
95
- ) ' \(
91
+ \( parseSubcommandFunctionName) \( positionalArgumentCountArguments) \(
96
92
completableArguments
97
93
. compactMap ( \. optionSpec)
98
94
. map { " ' \( $0. fishEscapeForSingleQuotedString ( ) ) ' " }
@@ -102,7 +98,7 @@ extension [ParsableCommand.Type] {
102
98
? " "
103
99
: """
104
100
105
- switch $positionals [1]
101
+ switch $unparsed_tokens [1]
106
102
\( subcommands. map { ( self + [ $0] ) . commandCases } . joined ( separator: " \n " ) )
107
103
end
108
104
"""
@@ -114,64 +110,48 @@ extension [ParsableCommand.Type] {
114
110
private var completions : [ String ] {
115
111
// swift-format-ignore: NeverForceUnwrap
116
112
// Precondition: first is guaranteed to be non-empty
117
- let commandName = first!. _commandName
118
113
let prefix = """
119
- complete -c \( commandName ) \
120
- -n ' \( usingCommandFunctionName ) \
114
+ complete -c ' \( first! . _commandName ) ' \
115
+ -n ' \( shouldOfferCompletionsForFunctionName ) \
121
116
" \( map { $0. _commandName } . joined ( separator: separator) ) "
122
117
"""
123
118
124
119
let subcommands = subcommands
125
120
126
- func complete( suggestion: String , extraTests: [ String ] = [ ] ) -> String {
127
- " \( prefix) \( extraTests. map { " ; \( $0) " } . joined ( ) ) ' \( suggestion) "
128
- }
129
-
130
- let subcommandCompletions : [ String ] = subcommands. map { subcommand in
131
- complete (
132
- suggestion:
133
- " -fa ' \( subcommand. _commandName) ' -d ' \( subcommand. configuration. abstract. fishEscapeForSingleQuotedString ( ) ) ' "
134
- )
135
- }
136
-
137
121
var positionalIndex = 0
138
122
139
123
let argumentCompletions =
140
124
completableArguments
141
125
. map { ( arg: ArgumentDefinition ) in
142
- complete (
143
- suggestion: argumentSegments ( arg) . joined ( separator: separator) ,
144
- extraTests: arg. isPositional
145
- ? [
146
- """
147
- and test ( \( positionalIndexFunctionName) ) \
148
- -eq \( {
149
- positionalIndex += 1
150
- return positionalIndex
151
- } ( ) )
152
- """
153
- ]
154
- : [ ]
155
- )
126
+ """
127
+ \( prefix) \( arg. isPositional
128
+ ? """
129
+ \( {
130
+ positionalIndex += 1
131
+ return " \( positionalIndex) "
132
+ } ( ) )
133
+ """
134
+ : " "
135
+ ) ' \( argumentSegments ( arg) . joined ( separator: separator) )
136
+ """
156
137
}
157
138
158
- let completionsFromSubcommands = subcommands. flatMap { subcommand in
159
- ( self + [ subcommand] ) . completions
160
- }
139
+ positionalIndex += 1
161
140
162
141
return
163
- completionsFromSubcommands + argumentCompletions + subcommandCompletions
142
+ argumentCompletions
143
+ + subcommands. map { subcommand in
144
+ " \( prefix) \( positionalIndex) ' -fa ' \( subcommand. _commandName) ' -d ' \( subcommand. configuration. abstract. fishEscapeForSingleQuotedString ( ) ) ' "
145
+ }
146
+ + subcommands. flatMap { subcommand in
147
+ ( self + [ subcommand] ) . completions
148
+ }
164
149
}
165
150
166
151
private var subcommands : Self {
167
- guard
168
- let command = last,
169
- ArgumentSet ( command, visibility: . default, parent: nil )
170
- . filter ( \. isPositional) . isEmpty
171
- else {
172
- return [ ]
173
- }
174
- var subcommands = command. configuration. subcommands
152
+ // swift-format-ignore: NeverForceUnwrap
153
+ // Precondition: last is guaranteed to be non-empty
154
+ var subcommands = last!. configuration. subcommands
175
155
. filter { $0. configuration. shouldDisplay }
176
156
if count == 1 {
177
157
subcommands. addHelpSubcommandIfMissing ( )
@@ -205,19 +185,24 @@ extension [ParsableCommand.Type] {
205
185
}
206
186
}
207
187
188
+ let r = arg. isPositional ? " " : " r "
189
+
208
190
switch arg. completion. kind {
209
191
case . default:
192
+ if case . unary = arg. update {
193
+ results += [ " - \( r) fka '' " ]
194
+ }
210
195
break
211
196
case . list( let list) :
212
- results += [ " -rfka ' \( list. joined ( separator: separator) ) ' " ]
197
+ results += [ " - \( r ) fka '\( list. joined ( separator: separator) ) ' " ]
213
198
case . file( let extensions) :
214
199
switch extensions. count {
215
200
case 0 :
216
- results += [ " -rF " ]
201
+ results += [ " - \( r ) F " ]
217
202
case 1 :
218
203
results += [
219
204
"""
220
- -rfa '( \
205
+ - \( r ) fa '(\
221
206
for p in (string match -e -- \\ '*/ \\ ' (commandline -t);or printf \\ n)*. \\ ' \( extensions. map { $0. fishEscapeForSingleQuotedString ( iterationCount: 2 ) } . joined ( ) ) \\ ';printf %s \\ n $p;end; \
222
207
__fish_complete_directories (commandline -t) \\ ' \\ ' \
223
208
)'
@@ -226,51 +211,52 @@ extension [ParsableCommand.Type] {
226
211
default :
227
212
results += [
228
213
"""
229
- -rfa '( \
230
- set exts \( extensions. map { " \\ ' \( $0. fishEscapeForSingleQuotedString ( iterationCount: 2 ) ) \\ ' " } . joined ( separator: separator) ) ; \
214
+ - \( r ) fa '(\
215
+ set -l exts \( extensions. map { " \\ ' \( $0. fishEscapeForSingleQuotedString ( iterationCount: 2 ) ) \\ ' " } . joined ( separator: separator) ) ; \
231
216
for p in (string match -e -- \\ '*/ \\ ' (commandline -t);or printf \\ n)*.{$exts};printf %s \\ n $p;end; \
232
217
__fish_complete_directories (commandline -t) \\ ' \\ ' \
233
218
)'
234
219
"""
235
220
]
236
221
}
237
222
case . directory:
238
- results += [ " -rfa '( \( completeDirectoriesFunctionName) )' " ]
223
+ results += [ " - \( r ) fa '(\( completeDirectoriesFunctionName) )' " ]
239
224
case . shellCommand( let shellCommand) :
240
- results += [ " -rfka '( \( shellCommand) )' " ]
225
+ results += [ " - \( r ) fka '(\( shellCommand) )' " ]
241
226
case . custom:
242
227
results += [
243
228
"""
244
- -rfka '( \( customCompletionFunctionName) \( arg. customCompletionCall ( self ) ) )'
229
+ - \( r ) fka '(\( customCompletionFunctionName) \( arg. customCompletionCall ( self ) ) )'
245
230
"""
246
231
]
247
232
}
248
233
249
234
return results
250
235
}
251
236
252
- private var commandsAndPositionalsFunctionName : String {
253
- // swift-format-ignore: NeverForceUnwrap
254
- // Precondition: first is guaranteed to be non-empty
255
- " _swift_ \( first!. _commandName) _commands_and_positionals "
237
+ var positionalArgumentCountArguments : String {
238
+ let positionalArguments = positionalArguments
239
+ return """
240
+ \( positionalArguments. contains ( where: { $0. isRepeatingPositional } ) ? " -r " : " " ) \( positionalArguments. count)
241
+ """
256
242
}
257
243
258
- private var tokensFunctionName : String {
244
+ private var shouldOfferCompletionsForFunctionName : String {
259
245
// swift-format-ignore: NeverForceUnwrap
260
246
// Precondition: first is guaranteed to be non-empty
261
- " _swift_ \( first!. _commandName) _tokens "
247
+ " _swift_ \( first!. _commandName) _should_offer_completions_for "
262
248
}
263
249
264
- private var usingCommandFunctionName : String {
250
+ private var tokensFunctionName : String {
265
251
// swift-format-ignore: NeverForceUnwrap
266
252
// Precondition: first is guaranteed to be non-empty
267
- " _swift_ \( first!. _commandName) _using_command "
253
+ " _swift_ \( first!. _commandName) _tokens "
268
254
}
269
255
270
- private var positionalIndexFunctionName : String {
256
+ private var parseSubcommandFunctionName : String {
271
257
// swift-format-ignore: NeverForceUnwrap
272
258
// Precondition: first is guaranteed to be non-empty
273
- " _swift_ \( first!. _commandName) _positional_index "
259
+ " _swift_ \( first!. _commandName) _parse_subcommand "
274
260
}
275
261
276
262
private var completeDirectoriesFunctionName : String {
0 commit comments