@@ -46,140 +46,55 @@ def _BashScript(name, commands, default_options=None):
4646 A string which is the Bash script. Source the bash script to enable tab
4747 completion in Bash.
4848 """
49-
5049 default_options = default_options or set ()
51- global_options , options_map , subcommands_map = _GetMaps (
52- name , commands , default_options
53- )
50+ options_map = collections .defaultdict (lambda : copy .copy (default_options ))
51+ for command in commands :
52+ start = (name + ' ' + ' ' .join (command [:- 1 ])).strip ()
53+ completion = _FormatForCommand (command [- 1 ])
54+ options_map [start ].add (completion )
55+ options_map [start .replace ('_' , '-' )].add (completion )
5456
5557 bash_completion_template = """# bash completion support for {name}
5658# DO NOT EDIT.
5759# This script is autogenerated by fire/completion.py.
5860
5961_complete-{identifier}()
6062{{
61- local cur prev opts lastcommand
63+ local start cur opts
6264 COMPREPLY=()
63- prev ="${{COMP_WORDS[COMP_CWORD-1] }}"
65+ start ="${{COMP_WORDS[@]:0:COMP_CWORD }}"
6466 cur="${{COMP_WORDS[COMP_CWORD]}}"
65- lastcommand=$(get_lastcommand)
6667
6768 opts="{default_options}"
68- GLOBAL_OPTIONS="{global_options}"
6969
70- {checks }
70+ {start_checks }
7171
7272 COMPREPLY=( $(compgen -W "${{opts}}" -- ${{cur}}) )
7373 return 0
7474}}
7575
76- get_lastcommand()
77- {{
78- local lastcommand i
79-
80- lastcommand=
81- for ((i=0; i < ${{#COMP_WORDS[@]}}; ++i)); do
82- if [[ ${{COMP_WORDS[i]}} != -* ]] && [[ -n ${{COMP_WORDS[i]}} ]] && [[
83- ${{COMP_WORDS[i]}} != $cur ]]; then
84- lastcommand=${{COMP_WORDS[i]}}
85- fi
86- done
87-
88- echo $lastcommand
89- }}
90-
91- filter_options()
92- {{
93- local opts
94- opts=""
95- for opt in "$@"
96- do
97- if ! option_already_entered $opt; then
98- opts="$opts $opt"
99- fi
100- done
101-
102- echo $opts
103- }}
104-
105- option_already_entered()
106- {{
107- local opt
108- for opt in ${{COMP_WORDS[@]:0:COMP_CWORD}}
109- do
110- if [ $1 == $opt ]; then
111- return 0
112- fi
113- done
114- return 1
115- }}
116-
117- is_prev_global()
118- {{
119- local opt
120- for opt in $GLOBAL_OPTIONS
121- do
122- if [ $opt == $prev ]; then
123- return 0
124- fi
125- done
126- return 1
127- }}
128-
12976complete -F _complete-{identifier} {command}
13077"""
131-
132- check_wrapper = """
133- case "${{lastcommand}}" in
134- {lastcommand_checks}
135- esac"""
136-
137- lastcommand_check_template = """
138- {command})
139- {opts_assignment}
140- opts=$(filter_options $opts)
141- ;;"""
142-
143- opts_assignment_subcommand_template = """
144- if is_prev_global; then
145- opts="${{GLOBAL_OPTIONS}}"
146- else
147- opts="{options} ${{GLOBAL_OPTIONS}}"
148- fi"""
149-
150- opts_assignment_main_command_template = """
151- opts="{options} ${{GLOBAL_OPTIONS}}" """
152-
153- def _GetOptsAssignmentTemplate (command ):
154- if command == name :
155- return opts_assignment_main_command_template
156- else :
157- return opts_assignment_subcommand_template
158-
159- lastcommand_checks = '\n ' .join (
160- lastcommand_check_template .format (
161- command = command ,
162- opts_assignment = _GetOptsAssignmentTemplate (command ).format (
163- options = ' ' .join (sorted (
164- options_map [command ].union (subcommands_map [command ])
165- )),
166- ),
78+ start_check_template = """
79+ if [[ "$start" == "{start}" ]] ; then
80+ opts="{completions}"
81+ fi"""
82+
83+ start_checks = '\n ' .join (
84+ start_check_template .format (
85+ start = start ,
86+ completions = ' ' .join (sorted (options_map [start ]))
16787 )
168- for command in set (subcommands_map .keys ()).union (set (options_map .keys ()))
169- )
170-
171- checks = check_wrapper .format (
172- lastcommand_checks = lastcommand_checks ,
88+ for start in options_map
17389 )
17490
17591 return (
17692 bash_completion_template .format (
17793 name = name ,
17894 command = name ,
179- checks = checks ,
95+ start_checks = start_checks ,
18096 default_options = ' ' .join (default_options ),
181- identifier = name .replace ('/' , '' ).replace ('.' , '' ).replace (',' , '' ),
182- global_options = ' ' .join (global_options ),
97+ identifier = name .replace ('/' , '' ).replace ('.' , '' ).replace (',' , '' )
18398 )
18499 )
185100
@@ -199,85 +114,44 @@ def _FishScript(name, commands, default_options=None):
199114 completion in Fish.
200115 """
201116 default_options = default_options or set ()
202- global_options , options_map , subcommands_map = _GetMaps (
203- name , commands , default_options
204- )
205-
117+ options_map = collections .defaultdict (lambda : copy .copy (default_options ))
118+ for command in commands :
119+ start = (name + ' ' + ' ' .join (command [:- 1 ])).strip ()
120+ completion = _FormatForCommand (command [- 1 ])
121+ options_map [start ].add (completion )
122+ options_map [start .replace ('_' , '-' )].add (completion )
206123 fish_source = """function __fish_using_command
207124 set cmd (commandline -opc)
208- for i in (seq (count $cmd) 1)
209- switch $cmd[$i]
210- case "-*"
211- case "*"
212- if [ $cmd[$i] = $argv[1] ]
213- return 0
214- else
125+ if [ (count $cmd) -eq (count $argv) ]
126+ for i in (seq (count $argv))
127+ if [ $cmd[$i] != $argv[$i] ]
215128 return 1
216129 end
217130 end
131+ return 0
218132 end
219133 return 1
220134end
221-
222- function __option_entered_check
223- set cmd (commandline -opc)
224- for i in (seq (count $cmd))
225- switch $cmd[$i]
226- case "-*"
227- if [ $cmd[$i] = $argv[1] ]
228- return 1
229- end
230- end
231- end
232- return 0
233- end
234-
235- function __is_prev_global
236- set cmd (commandline -opc)
237- set global_options {global_options}
238- set prev (count $cmd)
239-
240- for opt in $global_options
241- if [ "--$opt" = $cmd[$prev] ]
242- echo $prev
243- return 0
244- end
245- end
246- return 1
247- end
248-
249135"""
250-
251- subcommand_template = ("complete -c {name} -n '__fish_using_command "
252- "{command}' -f -a {subcommand}\n " )
136+ subcommand_template = ("complete -c {name} -n '__fish_using_command {start}' "
137+ "-f -a {subcommand}\n " )
253138 flag_template = ("complete -c {name} -n "
254- "'__fish_using_command {command};{prev_global_check} and "
255- "__option_entered_check --{option}' -l {option}\n " )
256-
257- prev_global_check = " and __is_prev_global;"
258- for command in set (subcommands_map .keys ()).union (set (options_map .keys ())):
259- for subcommand in subcommands_map [command ]:
260- fish_source += subcommand_template .format (
261- name = name ,
262- command = command ,
263- subcommand = subcommand ,
264- )
265-
266- for option in options_map [command ].union (global_options ):
267- check_needed = command != name
268- fish_source += flag_template .format (
269- name = name ,
270- command = command ,
271- prev_global_check = prev_global_check if check_needed else "" ,
272- option = option .lstrip ("--" ),
273- )
274-
275- return fish_source .format (
276- global_options = ' ' .join (
277- '"{option}"' .format (option = option )
278- for option in global_options
279- )
280- )
139+ "'__fish_using_command {start}' -l {option}\n " )
140+ for start in options_map :
141+ for option in sorted (options_map [start ]):
142+ if option .startswith ('--' ):
143+ fish_source += flag_template .format (
144+ name = name ,
145+ start = start ,
146+ option = option [2 :]
147+ )
148+ else :
149+ fish_source += subcommand_template .format (
150+ name = name ,
151+ start = start ,
152+ subcommand = option
153+ )
154+ return fish_source
281155
282156
283157def _IncludeMember (name , verbose ):
@@ -428,51 +302,3 @@ def _Commands(component, depth=3):
428302
429303 for command in _Commands (member , depth - 1 ):
430304 yield (member_name ,) + command
431-
432-
433- def _IsOption (arg ):
434- return arg .startswith ('-' )
435-
436- def _GetMaps (name , commands , default_options ):
437- """Returns sets of subcommands and options for each command.
438-
439- Args:
440- name: The first token in the commands, also the name of the command.
441- commands: A list of all possible commands that tab completion can complete
442- to. Each command is a list or tuple of the string tokens that make up
443- that command.
444- default_options: A dict of options that can be used with any command. Use
445- this if there are flags that can always be appended to a command.
446- Returns:
447- global_options: A set of all options of the first token of the command.
448- subcommands_map: A dict storing set of subcommands for each
449- command/subcommand.
450- options_map: A dict storing set of options for each subcommand.
451- """
452-
453- global_options = copy .copy (default_options )
454- options_map = collections .defaultdict (lambda : copy .copy (default_options ))
455- subcommands_map = collections .defaultdict (set )
456-
457- for command in commands :
458- if len (command ) == 1 :
459-
460- if _IsOption (command [0 ]):
461- global_options .add (command [0 ])
462- else :
463- subcommands_map [name ].add (command [0 ])
464-
465- elif command :
466-
467- subcommand = command [- 2 ]
468- arg = _FormatForCommand (command [- 1 ])
469-
470- if _IsOption (arg ):
471- args_map = options_map
472- else :
473- args_map = subcommands_map
474-
475- args_map [subcommand ].add (arg )
476- args_map [subcommand .replace ('_' , '-' )].add (arg )
477-
478- return global_options , options_map , subcommands_map
0 commit comments