@@ -144,9 +144,10 @@ def self.format_description(description, fish: false)
144
144
description . gsub ( /[<>]/ , "" ) . tr ( "\n " , " " ) . chomp ( "." )
145
145
end
146
146
147
- sig { params ( command : String ) . returns ( T ::Hash [ String , String ] ) }
148
- def self . command_options ( command )
147
+ sig { params ( command : String , subcommand : T . nilable ( String ) ) . returns ( T ::Hash [ String , String ] ) }
148
+ def self . command_options ( command , subcommand = nil )
149
149
options = { }
150
+
150
151
Commands . command_options ( command ) &.each do |option |
151
152
next if option . blank?
152
153
@@ -159,6 +160,19 @@ def self.command_options(command)
159
160
options [ name ] = desc
160
161
end
161
162
end
163
+
164
+ if subcommand . present?
165
+ subcommand_options = Commands . subcommand_options ( command , subcommand )
166
+ subcommand_options . each do |name , desc |
167
+ if name . start_with? "--[no-]"
168
+ options [ name . gsub ( "[no-]" , "" ) ] = desc
169
+ options [ name . sub ( "[no-]" , "no-" ) ] = desc
170
+ else
171
+ options [ name ] = desc
172
+ end
173
+ end
174
+ end
175
+
162
176
options
163
177
end
164
178
@@ -176,7 +190,67 @@ def self.generate_bash_subcommand_completion(command)
176
190
named_completion_string += "\n #{ BASH_NAMED_ARGS_COMPLETION_FUNCTION_MAPPING [ type ] } "
177
191
end
178
192
179
- named_completion_string += "\n __brewcomp \" #{ named_args_strings . join ( " " ) } \" " if named_args_strings . any?
193
+ if named_args_strings . any?
194
+ named_completion_string += "\n __brewcomp \" #{ named_args_strings . join ( " " ) } \" "
195
+ subcommand_functions = [ ]
196
+ named_args_strings . each do |subcommand |
197
+ subcommand_options = command_options ( command , subcommand )
198
+ next if subcommand_options . empty?
199
+ subcommand_functions << <<~SUBCOMPLETION
200
+ _brew_#{ Commands . method_name command } _#{ subcommand . tr ( "-" , "_" ) } () {
201
+ local cur="${COMP_WORDS[COMP_CWORD]}"
202
+ case "${cur}" in
203
+ -*)
204
+ __brewcomp "
205
+ #{ subcommand_options . keys . sort . join ( "\n " ) }
206
+ "
207
+ return
208
+ ;;
209
+ *) ;;
210
+ esac
211
+ }
212
+ SUBCOMPLETION
213
+ end
214
+
215
+ if subcommand_functions . any?
216
+ named_completion_string += "\n \n # Handle subcommands"
217
+ named_completion_string += "\n local subcmd_idx=1"
218
+ named_completion_string += "\n for ((; subcmd_idx < COMP_CWORD; subcmd_idx++))"
219
+ named_completion_string += "\n do"
220
+ named_completion_string += "\n local subcmd=\" ${COMP_WORDS[subcmd_idx]}\" "
221
+ named_completion_string += "\n case \" ${subcmd}\" in"
222
+
223
+ named_args_strings . each do |subcommand |
224
+ next if command_options ( command , subcommand ) . empty?
225
+
226
+ named_completion_string += "\n #{ subcommand } )"
227
+ named_completion_string += "\n _brew_#{ Commands . method_name command } _#{ subcommand . tr ( "-" , "_" ) } "
228
+ named_completion_string += "\n return"
229
+ named_completion_string += "\n ;;"
230
+ end
231
+
232
+ named_completion_string += "\n *) ;; # Default case"
233
+ named_completion_string += "\n esac"
234
+ named_completion_string += "\n done"
235
+
236
+ return <<~COMPLETION
237
+ #{ subcommand_functions . join ( "\n " ) }
238
+
239
+ _brew_#{ Commands . method_name command } () {
240
+ local cur="${COMP_WORDS[COMP_CWORD]}"
241
+ case "${cur}" in
242
+ -*)
243
+ __brewcomp "
244
+ #{ command_options ( command ) . keys . sort . join ( "\n " ) }
245
+ "
246
+ return
247
+ ;;
248
+ *) ;;
249
+ esac#{ named_completion_string }
250
+ }
251
+ COMPLETION
252
+ end
253
+ end
180
254
end
181
255
182
256
<<~COMPLETION
@@ -218,6 +292,8 @@ def self.generate_zsh_subcommand_completion(command)
218
292
options = command_options ( command )
219
293
220
294
args_options = [ ]
295
+ subcommand_completions = [ ]
296
+
221
297
if ( types = Commands . named_args_type ( command ) )
222
298
named_args_strings , named_args_types = types . partition { |type | type . is_a? String }
223
299
@@ -244,6 +320,25 @@ def self.generate_zsh_subcommand_completion(command)
244
320
if named_args_strings . any?
245
321
args_options << "- subcommand"
246
322
args_options << "*::subcommand:(#{ named_args_strings . join ( " " ) } )"
323
+ named_args_strings . each do |subcommand |
324
+ subcommand_opts = command_options ( command , subcommand )
325
+ next if subcommand_opts . empty?
326
+
327
+ formatted_opts = subcommand_opts . sort . map do |opt , desc |
328
+ next opt if desc . blank?
329
+
330
+ conflicts = generate_zsh_option_exclusions ( command , opt )
331
+ "#{ conflicts } #{ opt } [#{ format_description desc } ]"
332
+ end
333
+
334
+ subcommand_completions << <<~SUBCOMPLETION
335
+ # brew #{ command } #{ subcommand }
336
+ _brew_#{ Commands . method_name command } _#{ subcommand . tr ( "-" , "_" ) } () {
337
+ _arguments \\
338
+ #{ formatted_opts . map { |opt | "'#{ opt } '" } . join ( " \\ \n " ) }
339
+ }
340
+ SUBCOMPLETION
341
+ end
247
342
end
248
343
end
249
344
@@ -255,11 +350,33 @@ def self.generate_zsh_subcommand_completion(command)
255
350
end
256
351
options += args_options
257
352
353
+ return <<~COMPLETION if subcommand_completions . any?
354
+
355
+ #{ subcommand_completions . join ( "\n \n " ) }
356
+
357
+ # brew #{ command }
358
+ _brew_#{ Commands . method_name command } () {
359
+ if (( CURRENT > 2 )); then
360
+ local subcmd=${words[2]}
361
+ case "$subcmd" in
362
+ #{ named_args_strings . reject { |s | command_options ( command , s ) . empty? }
363
+ . map { |s | "#{ s } ) _brew_#{ Commands . method_name command } _#{ s . tr ( "-" , "_" ) } ;;" }
364
+ . join ( "\n " ) }
365
+ *) _arguments \\
366
+ #{ options . map { |opt | opt . start_with? ( "- " ) ? opt : "'#{ opt } '" } . join ( " \\ \n " ) } ;;
367
+ esac
368
+ else
369
+ _arguments \\
370
+ #{ options . map { |opt | opt . start_with? ( "- " ) ? opt : "'#{ opt } '" } . join ( " \\ \n " ) }
371
+ fi
372
+ }
373
+ COMPLETION
374
+
258
375
<<~COMPLETION
259
376
# brew #{ command }
260
377
_brew_#{ Commands . method_name command } () {
261
378
_arguments \\
262
- #{ options . map! { |opt | opt . start_with? ( "- " ) ? opt : "'#{ opt } '" } . join ( " \\ \n " ) }
379
+ #{ options . map { |opt | opt . start_with? ( "- " ) ? opt : "'#{ opt } '" } . join ( " \\ \n " ) }
263
380
}
264
381
COMPLETION
265
382
end
@@ -318,6 +435,8 @@ def self.generate_fish_subcommand_completion(command)
318
435
319
436
subcommands = [ ]
320
437
named_args = [ ]
438
+ subcommand_options = [ ]
439
+
321
440
if ( types = Commands . named_args_type ( command ) )
322
441
named_args_strings , named_args_types = types . partition { |type | type . is_a? String }
323
442
@@ -341,10 +460,22 @@ def self.generate_fish_subcommand_completion(command)
341
460
342
461
named_args_strings . each do |subcommand |
343
462
subcommands << "__fish_brew_complete_sub_cmd '#{ command } ' '#{ subcommand } '"
463
+
464
+ subcmd_options = command_options ( command , subcommand )
465
+ next if subcmd_options . empty?
466
+
467
+ subcmd_options . sort . each do |opt , desc |
468
+ arg_line = "# #{ subcommand } subcommand options"
469
+ subcommand_options << arg_line unless subcommand_options . include? ( arg_line )
470
+
471
+ arg_line = "__fish_brew_complete_sub_arg '#{ command } ' '#{ subcommand } ' -l #{ opt . sub ( /^-+/ , "" ) } "
472
+ arg_line += " -d '#{ format_description desc , fish : true } '" if desc . present?
473
+ subcommand_options << arg_line
474
+ end
344
475
end
345
476
end
346
477
347
- lines += subcommands + options + named_args
478
+ lines += subcommands + options + named_args + subcommand_options
348
479
<<~COMPLETION
349
480
#{ lines . join ( "\n " ) . chomp }
350
481
COMPLETION
0 commit comments