stgit.el: Use 'git diff-stat' to show files in a patch
[stgit] / stgit / completion.py
CommitLineData
6c8a90e1
KH
1import textwrap
2import stgit.commands
3from stgit import argparse
4
5def fun(name, *body):
6 return ['%s ()' % name, '{', list(body), '}']
7
8def fun_desc(name, desc, *body):
9 return ['# %s' % desc] + fun(name, *body)
10
11def flatten(stuff, sep):
12 r = stuff[0]
13 for s in stuff[1:]:
14 r.append(sep)
15 r.extend(s)
16 return r
17
18def write(f, stuff, indent = 0):
19 for s in stuff:
20 if isinstance(s, str):
21 f.write((' '*4*indent + s).rstrip() + '\n')
22 else:
23 write(f, s, indent + 1)
24
25def patch_list_fun(type):
26 return fun('_%s_patches' % type, 'local g=$(_gitdir)',
27 'test "$g" && cat "$g/patches/$(_current_branch)/%s"' % type)
28
29def file_list_fun(name, cmd):
30 return fun('_%s_files' % name, 'local g=$(_gitdir)',
31 'test "$g" && %s' % cmd)
32
33def ref_list_fun(name, prefix):
34 return fun(name, 'local g=$(_gitdir)',
35 ("test \"$g\" && git show-ref | grep ' %s/' | sed 's,.* %s/,,'"
36 % (prefix, prefix)))
37
38def util():
39 r = [fun_desc('_gitdir',
40 "The path to .git, or empty if we're not in a repository.",
41 'echo "$(git rev-parse --git-dir 2>/dev/null)"'),
42 fun_desc('_current_branch',
43 "Name of the current branch, or empty if there isn't one.",
44 'local b=$(git symbolic-ref HEAD 2>/dev/null)',
45 'echo ${b#refs/heads/}'),
46 fun_desc('_other_applied_patches',
47 'List of all applied patches except the current patch.',
48 'local b=$(_current_branch)',
49 'local g=$(_gitdir)',
50 ('test "$g" && cat "$g/patches/$b/applied" | grep -v'
51 ' "^$(tail -n 1 $g/patches/$b/applied 2> /dev/null)$"')),
52 fun('_patch_range', 'local patches="$1"', 'local cur="$2"',
53 'case "$cur" in', [
54 '*..*)', ['local pfx="${cur%..*}.."', 'cur="${cur#*..}"',
55 'compgen -P "$pfx" -W "$patches" -- "$cur"', ';;'],
56 '*)', ['compgen -W "$patches" -- "$cur"', ';;']],
57 'esac'),
58 fun('_stg_branches',
59 'local g=$(_gitdir)', 'test "$g" && (cd $g/patches/ && echo *)'),
60 ref_list_fun('_all_branches', 'refs/heads'),
61 ref_list_fun('_tags', 'refs/tags'),
62 ref_list_fun('_remotes', 'refs/remotes')]
63 for type in ['applied', 'unapplied', 'hidden']:
64 r.append(patch_list_fun(type))
65 for name, cmd in [('conflicting',
66 r"git ls-files --unmerged | sed 's/.*\t//g' | sort -u"),
67 ('dirty', 'git diff-index --name-only HEAD'),
68 ('unknown', 'git ls-files --others --exclude-standard'),
69 ('known', 'git ls-files')]:
70 r.append(file_list_fun(name, cmd))
71 return flatten(r, '')
72
73def command_list(commands):
74 return ['_stg_commands="%s"\n' % ' '.join(sorted(commands.iterkeys()))]
75
76def command_fun(cmd, modname):
77 mod = stgit.commands.get_command(modname)
78 def cg(args, flags):
79 return argparse.compjoin(list(args) + [argparse.strings(*flags)]
80 ).command('$cur')
81 return fun(
82 '_stg_%s' % cmd,
83 'local flags="%s"' % ' '.join(sorted(
84 flag for opt in mod.options
85 for flag in opt.flags if flag.startswith('--'))),
86 'local prev="${COMP_WORDS[COMP_CWORD-1]}"',
87 'local cur="${COMP_WORDS[COMP_CWORD]}"',
88 'case "$prev" in', [
89 '%s) COMPREPLY=($(%s)) ;;' % ('|'.join(opt.flags), cg(opt.args, []))
90 for opt in mod.options if opt.args] + [
91 '*) COMPREPLY=($(%s)) ;;' % cg(mod.args, ['$flags'])],
92 'esac')
93
94def main_switch(commands):
95 return fun(
96 '_stg',
97 'local i',
98 'local c=1',
99 'local command',
100 '',
101 'while test $c -lt $COMP_CWORD; do', [
102 'if test $c == 1; then', [
103 'command="${COMP_WORDS[c]}"'],
104 'fi',
105 'c=$((++c))'],
106 'done',
107 '',
108 ('# Complete name of subcommand if the user has not finished'
109 ' typing it yet.'),
110 'if test $c -eq $COMP_CWORD -a -z "$command"; then', [
111 ('COMPREPLY=($(compgen -W "$_stg_commands" --'
112 ' "${COMP_WORDS[COMP_CWORD]}"))'),
113 'return'],
114 'fi',
115 '',
116 '# Complete arguments to subcommands.',
117 'case "$command" in', [
118 '%s) _stg_%s ;;' % (cmd, cmd)
119 for cmd in sorted(commands.iterkeys())],
120 'esac')
121
122def install():
123 return ['complete -o default -F _stg stg']
124
125def write_completion(f):
126 commands = stgit.commands.get_commands(allow_cached = False)
127 r = [["""# -*- shell-script -*-
128# bash completion script for StGit (automatically generated)
129#
130# To use these routines:
131#
132# 1. Copy this file to somewhere (e.g. ~/.stgit-completion.bash).
133#
134# 2. Add the following line to your .bashrc:
135# . ~/.stgit-completion.bash"""]]
136 r += [util(), command_list(commands)]
137 for cmd, (modname, _, _) in sorted(commands.iteritems()):
138 r.append(command_fun(cmd, modname))
139 r += [main_switch(commands), install()]
140 write(f, flatten(r, ''))