4 from stgit
import argparse
8 def actions(self
, var
):
14 def command(self
, var
):
16 for act
in self
.actions(var
):
18 words
= self
.words(var
)
20 cmd
+= ['-W', '"%s"' % ' '.join(words
)]
21 cmd
+= ['--', '"%s"' % var
]
25 class CompgenJoin(CompgenBase
):
26 def __init__(self
, a
, b
):
27 assert isinstance(a
, CompgenBase
)
28 assert isinstance(b
, CompgenBase
)
33 union_words
= self
.__a
.words(var
)
34 for b_word
in self
.__b
.words(var
):
35 if b_word
not in union_words
:
36 union_words
.append(b_word
)
39 def actions(self
, var
):
40 union_actions
= self
.__a
.actions(var
)
41 for b_action
in self
.__b
.actions(var
):
42 if b_action
not in union_actions
:
43 union_actions
.append(b_action
)
47 class Compgen(CompgenBase
):
48 def __init__(self
, words
=(), actions
=()):
49 self
.__words
= list(words
)
50 self
.__actions
= list(actions
)
52 def actions(self
, var
):
59 class patch_range(CompgenBase
):
60 def __init__(self
, *endpoints
):
61 self
.__endpoints
= endpoints
65 for e
in self
.__endpoints
:
66 assert not e
.actions(var
)
67 for e_word
in e
.words(var
):
68 if e_word
not in words
:
70 return ['$(_patch_range "%s" "%s")' % (' '.join(words
), var
)]
73 def compjoin(compgens
):
76 comp
= CompgenJoin(comp
, c
)
80 _arg_to_compgen
= dict(
81 all_branches
=Compgen(['$(_all_branches)']),
82 stg_branches
=Compgen(['$(_stg_branches)']),
83 applied_patches
=Compgen(['$(_applied_patches)']),
84 other_applied_patches
=Compgen(['$(_other_applied_patches)']),
85 unapplied_patches
=Compgen(['$(_unapplied_patches)']),
86 hidden_patches
=Compgen(['$(_hidden_patches)']),
87 commit
=Compgen(['$(_all_branches) $(_tags) $(_remotes)']),
88 conflicting_files
=Compgen(['$(_conflicting_files)']),
89 dirty_files
=Compgen(['$(_dirty_files)']),
90 unknown_files
=Compgen(['$(_unknown_files)']),
91 known_files
=Compgen(['$(_known_files)']),
92 repo
=Compgen(actions
=['directory']),
93 dir=Compgen(actions
=['directory']),
94 files
=Compgen(actions
=['file']),
95 mail_aliases
=Compgen(['$(_mail_aliases)']),
99 def arg_to_compgen(arg
):
100 if isinstance(arg
, argparse
.patch_range
):
102 for range_arg
in arg
:
103 range_args
.append(_arg_to_compgen
[range_arg
])
104 return patch_range(*range_args
)
105 elif isinstance(arg
, argparse
.strings
):
108 return _arg_to_compgen
[arg
]
111 def fun(name
, *body
):
112 return ['%s ()' % name
, '{', list(body
), '}']
115 def fun_desc(name
, desc
, *body
):
116 return ['# %s' % desc
] + fun(name
, *body
)
119 def flatten(stuff
, sep
):
127 def write(f
, stuff
, indent
=0):
129 if isinstance(s
, str):
130 f
.write((' ' * 4 * indent
+ s
).rstrip() + '\n')
132 write(f
, s
, indent
+ 1)
135 def patch_list_fun(type):
137 '_%s_patches' % type, 'stg series --no-description --noprefix --%s' % type
141 def file_list_fun(name
, cmd
):
142 return fun('_%s_files' % name
, 'local g', 'g=$(_gitdir)', 'test "$g" && %s' % cmd
)
145 def ref_list_fun(name
, prefix
):
153 " | grep ' %s/' | sed 's,.* %s/,,'" % (prefix
, prefix
)
162 "The path to .git, or empty if we're not in a repository.",
163 'git rev-parse --git-dir 2>/dev/null',
167 "Name of the current branch, or empty if there isn't one.",
169 'b=$(git symbolic-ref HEAD 2>/dev/null)',
170 'echo "${b#refs/heads/}"',
173 '_other_applied_patches',
174 'List of all applied patches except the current patch.',
175 'stg series --no-description --noprefix --applied | grep -v "^$(stg top)$"',
179 'local patches="$1"',
185 'local pfx="${cur%..*}.."',
187 'compgen -P "$pfx" -W "$patches" -- "$cur"',
191 ['compgen -W "$patches" -- "$cur"', ';;'],
197 ('stg branch --list 2>/dev/null' ' | grep ". s" | cut -f2 | cut -d" " -f1'),
199 fun('_all_branches', 'stg branch --list 2>/dev/null | cut -f2 | cut -d" " -f1'),
203 'git config --name-only --get-regexp "^mail\\.alias\\." '
207 ref_list_fun('_tags', 'refs/tags'),
208 ref_list_fun('_remotes', 'refs/remotes'),
210 for type in ['applied', 'unapplied', 'hidden']:
211 r
.append(patch_list_fun(type))
213 ('conflicting', r
"git ls-files --unmerged | sed 's/.*\t//g' | sort -u"),
214 ('dirty', 'git diff-index --name-only HEAD'),
215 ('unknown', 'git ls-files --others --exclude-standard'),
216 ('known', 'git ls-files'),
218 r
.append(file_list_fun(name
, cmd
))
219 return flatten(r
, '')
222 def command_list(commands
):
223 return ['_stg_commands="%s"\n' % ' '.join(cmd
for cmd
, _
, _
, _
in commands
)]
226 def command_fun(cmd
, modname
):
227 mod
= stgit
.commands
.get_command(modname
)
231 [arg_to_compgen(arg
) for arg
in args
] + [Compgen(flags
)]
243 for opt
in mod
.options
244 for flag
in opt
.flags
245 if flag
.startswith('--')
250 'local prev="${COMP_WORDS[COMP_CWORD-1]}"',
251 'local cur="${COMP_WORDS[COMP_CWORD]}"',
254 '%s) COMPREPLY=($(%s)) ;;' % ('|'.join(opt
.flags
), cg(opt
.args
, []))
255 for opt
in mod
.options
258 + ['*) COMPREPLY=($(%s)) ;;' % cg(mod
.args
, ['$flags'])],
263 def main_switch(commands
):
269 'while test $c -lt $COMP_CWORD; do',
270 ['if test $c == 1; then', ['command="${COMP_WORDS[c]}"'], 'fi', 'c=$((++c))'],
274 '# Complete name of subcommand if the user has not finished'
277 'if test $c -eq $COMP_CWORD -a -z "$command"; then',
280 'COMPREPLY=($(compgen -W "help version copyright $_stg_commands" '
281 '-- "${COMP_WORDS[COMP_CWORD]}"))'
287 '# Complete arguments to subcommands.',
288 'case "$command" in',
293 'COMPREPLY=($(compgen -W "$_stg_commands" --'
294 ' "${COMP_WORDS[COMP_CWORD]}"))'
298 'version) return ;;',
299 'copyright) return ;;',
301 ['%s) _stg_%s ;;' % (cmd
, cmd
) for cmd
, _
, _
, _
in commands
],
308 'complete -o bashdefault -o default -F _stg stg 2>/dev/null \\',
309 ['|| complete -o default -F _stg stg'],
313 def write_bash_completion(f
):
314 commands
= stgit
.commands
.get_commands(allow_cached
=False)
317 """# -*- shell-script -*-
318 # bash completion script for StGit (automatically generated)
320 # To use these routines:
322 # 1. Copy this file to somewhere (e.g. ~/.stgit-completion.bash).
324 # 2. Add the following line to your .bashrc:
325 # . ~/.stgit-completion.bash"""
328 r
+= [util(), command_list(commands
)]
329 for cmd
, modname
, _
, _
in commands
:
330 r
.append(command_fun(cmd
, modname
))
331 r
+= [main_switch(commands
), install()]
332 write(f
, flatten(r
, ''))
335 if __name__
== '__main__':
338 write_bash_completion(sys
.stdout
)