@@ -17,69 +17,67 @@ extension [ParsableCommand.Type] {
1717 // - first is guaranteed non-empty in the one place where this computed var is used.
1818 let commandName = first!. _commandName
1919 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]
2226 \( commandCases)
23- case '*'
24- set commands $positionals[1]
25- set -e positionals[1]
2627 end
27- end
2828
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 " \\ )
4030 end
4131
4232 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
4434 commandline --tokens-raw $argv
4535 else
4636 commandline -o $argv
4737 end
4838 end
4939
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..]
5644
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
6159 end
6260
6361 function \( completeDirectoriesFunctionName)
64- set token (commandline -t)
62+ set -f token (commandline -t)
6563 string match -- '*/' $token
66- set subdirs $token*/
64+ set -f subdirs $token*/
6765 printf '%s \\ n' $subdirs
6866 end
6967
7068 function \( customCompletionFunctionName)
7169 set -x \( CompletionShell . shellEnvironmentVariableName) fish
7270 set -x \( CompletionShell . shellVersionEnvironmentVariableName) $FISH_VERSION
7371
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)..]
7876 end
7977 command $tokens[1] $argv $tokens
8078 end
8179
82- complete -c \( commandName) -f
80+ complete -c ' \( commandName) ' -f
8381 \( completions. joined ( separator: " \n " ) )
8482 """
8583 }
@@ -90,9 +88,7 @@ extension [ParsableCommand.Type] {
9088 // Precondition: last is guaranteed to be non-empty
9189 return """
9290 case ' \( last!. _commandName) '
93- \( commandsAndPositionalsFunctionName) _helper ' \(
94- subcommands. isEmpty ? " " : " -s "
95- ) ' \(
91+ \( parseSubcommandFunctionName) \( positionalArgumentCountArguments) \(
9692 completableArguments
9793 . compactMap ( \. optionSpec)
9894 . map { " ' \( $0. fishEscapeForSingleQuotedString ( ) ) ' " }
@@ -102,7 +98,7 @@ extension [ParsableCommand.Type] {
10298 ? " "
10399 : """
104100
105- switch $positionals [1]
101+ switch $unparsed_tokens [1]
106102 \( subcommands. map { ( self + [ $0] ) . commandCases } . joined ( separator: " \n " ) )
107103 end
108104 """
@@ -114,64 +110,48 @@ extension [ParsableCommand.Type] {
114110 private var completions : [ String ] {
115111 // swift-format-ignore: NeverForceUnwrap
116112 // Precondition: first is guaranteed to be non-empty
117- let commandName = first!. _commandName
118113 let prefix = """
119- complete -c \( commandName ) \
120- -n ' \( usingCommandFunctionName ) \
114+ complete -c ' \( first! . _commandName ) ' \
115+ -n ' \( shouldOfferCompletionsForFunctionName ) \
121116 " \( map { $0. _commandName } . joined ( separator: separator) ) "
122117 """
123118
124119 let subcommands = subcommands
125120
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-
137121 var positionalIndex = 0
138122
139123 let argumentCompletions =
140124 completableArguments
141125 . 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+ """
156137 }
157138
158- let completionsFromSubcommands = subcommands. flatMap { subcommand in
159- ( self + [ subcommand] ) . completions
160- }
139+ positionalIndex += 1
161140
162141 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+ }
164149 }
165150
166151 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
175155 . filter { $0. configuration. shouldDisplay }
176156 if count == 1 {
177157 subcommands. addHelpSubcommandIfMissing ( )
@@ -205,19 +185,24 @@ extension [ParsableCommand.Type] {
205185 }
206186 }
207187
188+ let r = arg. isPositional ? " " : " r "
189+
208190 switch arg. completion. kind {
209191 case . default:
192+ if case . unary = arg. update {
193+ results += [ " - \( r) fka '' " ]
194+ }
210195 break
211196 case . list( let list) :
212- results += [ " -rfka ' \( list. joined ( separator: separator) ) ' " ]
197+ results += [ " - \( r ) fka '\( list. joined ( separator: separator) ) ' " ]
213198 case . file( let extensions) :
214199 switch extensions. count {
215200 case 0 :
216- results += [ " -rF " ]
201+ results += [ " - \( r ) F " ]
217202 case 1 :
218203 results += [
219204 """
220- -rfa '( \
205+ - \( r ) fa '(\
221206 for p in (string match -e -- \\ '*/ \\ ' (commandline -t);or printf \\ n)*. \\ ' \( extensions. map { $0. fishEscapeForSingleQuotedString ( iterationCount: 2 ) } . joined ( ) ) \\ ';printf %s \\ n $p;end; \
222207 __fish_complete_directories (commandline -t) \\ ' \\ ' \
223208 )'
@@ -226,51 +211,52 @@ extension [ParsableCommand.Type] {
226211 default :
227212 results += [
228213 """
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) ) ; \
231216 for p in (string match -e -- \\ '*/ \\ ' (commandline -t);or printf \\ n)*.{$exts};printf %s \\ n $p;end; \
232217 __fish_complete_directories (commandline -t) \\ ' \\ ' \
233218 )'
234219 """
235220 ]
236221 }
237222 case . directory:
238- results += [ " -rfa '( \( completeDirectoriesFunctionName) )' " ]
223+ results += [ " - \( r ) fa '(\( completeDirectoriesFunctionName) )' " ]
239224 case . shellCommand( let shellCommand) :
240- results += [ " -rfka '( \( shellCommand) )' " ]
225+ results += [ " - \( r ) fka '(\( shellCommand) )' " ]
241226 case . custom:
242227 results += [
243228 """
244- -rfka '( \( customCompletionFunctionName) \( arg. customCompletionCall ( self ) ) )'
229+ - \( r ) fka '(\( customCompletionFunctionName) \( arg. customCompletionCall ( self ) ) )'
245230 """
246231 ]
247232 }
248233
249234 return results
250235 }
251236
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+ """
256242 }
257243
258- private var tokensFunctionName : String {
244+ private var shouldOfferCompletionsForFunctionName : String {
259245 // swift-format-ignore: NeverForceUnwrap
260246 // Precondition: first is guaranteed to be non-empty
261- " _swift_ \( first!. _commandName) _tokens "
247+ " _swift_ \( first!. _commandName) _should_offer_completions_for "
262248 }
263249
264- private var usingCommandFunctionName : String {
250+ private var tokensFunctionName : String {
265251 // swift-format-ignore: NeverForceUnwrap
266252 // Precondition: first is guaranteed to be non-empty
267- " _swift_ \( first!. _commandName) _using_command "
253+ " _swift_ \( first!. _commandName) _tokens "
268254 }
269255
270- private var positionalIndexFunctionName : String {
256+ private var parseSubcommandFunctionName : String {
271257 // swift-format-ignore: NeverForceUnwrap
272258 // Precondition: first is guaranteed to be non-empty
273- " _swift_ \( first!. _commandName) _positional_index "
259+ " _swift_ \( first!. _commandName) _parse_subcommand "
274260 }
275261
276262 private var completeDirectoriesFunctionName : String {
0 commit comments