~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/plugins/bash_completion/bashcomp.py

  • Committer: Martin Pool
  • Date: 2005-09-01 06:32:52 UTC
  • Revision ID: mbp@sourcefrog.net-20050901063252-00fc761bf1076759
- make target to build emacs TAGS file

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/usr/bin/env python
2
 
 
3
 
# Copyright (C) 2009, 2010 Canonical Ltd
4
 
#
5
 
# This file is part of bzr-bash-completion
6
 
#
7
 
# bzr-bash-completion free software: you can redistribute it and/or
8
 
# modify it under the terms of the GNU General Public License as
9
 
# published by the Free Software Foundation, either version 2 of the
10
 
# License, or (at your option) any later version.
11
 
#
12
 
# bzr-bash-completion is distributed in the hope that it will be
13
 
# useful, but WITHOUT ANY WARRANTY; without even the implied warranty
14
 
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 
# General Public License for more details.
16
 
#
17
 
# You should have received a copy of the GNU General Public License
18
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
 
 
20
 
from meta import __version__
21
 
from bzrlib import (
22
 
    commands,
23
 
    config,
24
 
    help_topics,
25
 
    option,
26
 
    plugin,
27
 
)
28
 
import bzrlib
29
 
import re
30
 
 
31
 
head="""\
32
 
# Programmable completion for the Bazaar-NG bzr command under bash.
33
 
# Known to work with bash 2.05a as well as bash 4.1.2, and probably
34
 
# all versions in between as well.
35
 
 
36
 
# Based originally on the svn bash completition script.
37
 
# Customized by Sven Wilhelm/Icecrash.com
38
 
# Adjusted for automatic generation by Martin von Gagern
39
 
 
40
 
# Generated using the bzr-bash-completion plugin version %(version)s.
41
 
# See https://launchpad.net/bzr-bash-completion for details.
42
 
 
43
 
# Commands and options of bzr %(bzr_version)s
44
 
 
45
 
shopt -s progcomp
46
 
"""
47
 
fun="""\
48
 
%(function_name)s ()
49
 
{
50
 
        local cur cmds cmdIdx cmd cmdOpts fixedWords i globalOpts
51
 
        local curOpt optEnums
52
 
 
53
 
        COMPREPLY=()
54
 
        cur=${COMP_WORDS[COMP_CWORD]}
55
 
 
56
 
        cmds='%(cmds)s'
57
 
        globalOpts='%(global_options)s'
58
 
 
59
 
        # do ordinary expansion if we are anywhere after a -- argument
60
 
        for ((i = 1; i < COMP_CWORD; ++i)); do
61
 
                [[ ${COMP_WORDS[i]} == "--" ]] && return 0
62
 
        done
63
 
 
64
 
        # find the command; it's the first word not starting in -
65
 
        cmd=
66
 
        for ((cmdIdx = 1; cmdIdx < ${#COMP_WORDS[@]}; ++cmdIdx)); do
67
 
                if [[ ${COMP_WORDS[cmdIdx]} != -* ]]; then
68
 
                        cmd=${COMP_WORDS[cmdIdx]}
69
 
                        break
70
 
                fi
71
 
        done
72
 
 
73
 
        # complete command name if we are not already past the command
74
 
        if [[ $COMP_CWORD -le cmdIdx ]]; then
75
 
                COMPREPLY=( $( compgen -W "$cmds $globalOpts" -- $cur ) )
76
 
                return 0
77
 
        fi
78
 
 
79
 
        # find the option for which we want to complete a value
80
 
        curOpt=
81
 
        if [[ $cur != -* ]] && [[ $COMP_CWORD -gt 1 ]]; then
82
 
                curOpt=${COMP_WORDS[COMP_CWORD - 1]}
83
 
                if [[ $curOpt == = ]]; then
84
 
                        curOpt=${COMP_WORDS[COMP_CWORD - 2]}
85
 
                fi
86
 
        fi
87
 
%(debug)s
88
 
        cmdOpts=
89
 
        optEnums=
90
 
        fixedWords=
91
 
        case $cmd in
92
 
%(cases)s\
93
 
        *)
94
 
                cmdOpts='--help -h'
95
 
                ;;
96
 
        esac
97
 
 
98
 
        # if not typing an option, and if we don't know all the
99
 
        # possible non-option arguments for the current command,
100
 
        # then fallback on ordinary filename expansion
101
 
        if [[ -z $fixedWords ]] && [[ -z $optEnums ]] && [[ $cur != -* ]]; then
102
 
                return 0
103
 
        fi
104
 
 
105
 
        if [[ $cur == = ]] && [[ -n $optEnums ]]; then
106
 
                # complete directly after "--option=", list all enum values
107
 
                COMPREPLY=( $optEnums )
108
 
        else
109
 
                fixedWords="$cmdOpts $globalOpts $optEnums $fixedWords"
110
 
                COMPREPLY=( $( compgen -W "$fixedWords" -- $cur ) )
111
 
        fi
112
 
 
113
 
        return 0
114
 
}
115
 
"""
116
 
tail="""\
117
 
complete -F %(function_name)s -o default bzr
118
 
"""
119
 
debug_output=r"""
120
 
        # Debugging code enabled using the --debug command line switch.
121
 
        # Will dump some variables to the top portion of the terminal.
122
 
        echo -ne '\e[s\e[H'
123
 
        for (( i=0; i < ${#COMP_WORDS[@]}; ++i)); do
124
 
                echo "\$COMP_WORDS[$i]='${COMP_WORDS[i]}'"$'\e[K'
125
 
        done
126
 
        for i in COMP_CWORD COMP_LINE COMP_POINT COMP_TYPE COMP_KEY cur curOpt; do
127
 
                echo "\$${i}=\"${!i}\""$'\e[K'
128
 
        done
129
 
        echo -ne '---\e[K\e[u'
130
 
"""
131
 
 
132
 
def wrap_container(list, parser):
133
 
    def tweaked_add_option(*opts, **attrs):
134
 
        list.extend(opts)
135
 
    parser.add_option = tweaked_add_option
136
 
    return parser
137
 
 
138
 
def wrap_parser(list, parser):
139
 
    orig_add_option_group = parser.add_option_group
140
 
    def tweaked_add_option_group(*opts, **attrs):
141
 
        return wrap_container(list, orig_add_option_group(*opts, **attrs))
142
 
    parser.add_option_group = tweaked_add_option_group
143
 
    return wrap_container(list, parser)
144
 
 
145
 
def bash_completion_function(out, function_name="_bzr", function_only=False,
146
 
                             debug=False,
147
 
                             no_plugins=False, selected_plugins=None):
148
 
    cmds = []
149
 
    cases = ""
150
 
    reqarg = {}
151
 
    plugins = set()
152
 
    if selected_plugins:
153
 
        selected_plugins = set([x.replace('-', '_') for x in selected_plugins])
154
 
    else:
155
 
        selected_plugins = None
156
 
 
157
 
    re_switch = re.compile(r'\n(--[A-Za-z0-9-_]+)(?:, (-\S))?\s')
158
 
    help_text = help_topics.topic_registry.get_detail('global-options')
159
 
    global_options = set()
160
 
    for long, short in re_switch.findall(help_text):
161
 
        global_options.add(long)
162
 
        if short:
163
 
            global_options.add(short)
164
 
    global_options = " ".join(sorted(global_options))
165
 
 
166
 
    user_aliases = {} # dict from cmd name to set of user-defined alias names
167
 
    for alias, expansion in config.GlobalConfig().get_aliases().iteritems():
168
 
        for token in commands.shlex_split_unicode(expansion):
169
 
            if not token.startswith("-"):
170
 
                user_aliases.setdefault(token, set()).add(alias)
171
 
                break
172
 
 
173
 
    all_cmds = sorted(commands.all_command_names())
174
 
    for cmdname in all_cmds:
175
 
        cmd = commands.get_cmd_object(cmdname)
176
 
 
177
 
        # Find all aliases to the command; both cmd-defined and user-defined.
178
 
        # We assume a user won't override one command with a different one,
179
 
        # but will choose completely new names or add options to existing
180
 
        # ones while maintaining the actual command name unchanged.
181
 
        aliases = [cmdname]
182
 
        aliases.extend(cmd.aliases)
183
 
        aliases.extend(sorted([alias
184
 
                               for name in aliases
185
 
                               if name in user_aliases
186
 
                               for alias in user_aliases[name]
187
 
                               if alias not in aliases]))
188
 
        cases += "\t%s)\n" % "|".join(aliases)
189
 
        cmds.extend(aliases)
190
 
        plugin = cmd.plugin_name()
191
 
        if plugin is not None:
192
 
            if selected_plugins is not None and plugin not in selected_plugins:
193
 
                continue
194
 
            plugins.add(plugin)
195
 
            cases += "\t\t# plugin \"%s\"\n" % plugin
196
 
        opts = cmd.options()
197
 
        switches = []
198
 
        enums = []
199
 
        fixedWords = None
200
 
        for optname in sorted(cmd.options()):
201
 
            opt = opts[optname]
202
 
            optswitches = []
203
 
            parser = option.get_optparser({optname: opt})
204
 
            parser = wrap_parser(optswitches, parser)
205
 
            optswitches[:] = []
206
 
            opt.add_option(parser, opt.short_name())
207
 
            if isinstance(opt, option.RegistryOption) and opt.enum_switch:
208
 
                enum_switch = '--%s' % optname
209
 
                keys = opt.registry.keys()
210
 
                if enum_switch in optswitches and keys:
211
 
                    optswitches.remove(enum_switch)
212
 
                    for key in keys:
213
 
                        optswitches.append('%s=%s' % (enum_switch, key))
214
 
                    enums.append("%s) optEnums='%s' ;;"
215
 
                                 % (enum_switch, ' '.join(keys)))
216
 
            switches.extend(optswitches)
217
 
        if 'help' == cmdname or 'help' in cmd.aliases:
218
 
            fixedWords = " ".join(sorted(help_topics.topic_registry.keys()))
219
 
            fixedWords = '"$cmds %s"' % fixedWords
220
 
 
221
 
        cases += "\t\tcmdOpts='" + " ".join(switches) + "'\n"
222
 
        if fixedWords:
223
 
            if isinstance(fixedWords, list):
224
 
                fixedWords = "'" + join(fixedWords) + "'"
225
 
            cases += "\t\tfixedWords=" + fixedWords + "\n"
226
 
        if enums:
227
 
            cases += "\t\tcase $curOpt in\n\t\t\t"
228
 
            cases += "\n\t\t\t".join(enums)
229
 
            cases += "\n\t\tesac\n"
230
 
        cases += "\t\t;;\n"
231
 
 
232
 
    bzr_version = bzrlib.version_string
233
 
    if not plugins:
234
 
        bzr_version += "."
235
 
    else:
236
 
        bzr_version += " and the following plugins:"
237
 
        for plugin in sorted(plugins):
238
 
            pv = bzrlib.plugin.plugins()[plugin].__version__
239
 
            if pv == 'unknown':
240
 
                pv = ''
241
 
            else:
242
 
                pv = ' ' + pv
243
 
                bzr_version += "\n# %s%s" % (plugin, pv)
244
 
 
245
 
    if function_only:
246
 
        template = fun
247
 
    else:
248
 
        template = head + fun + tail
249
 
    out.write(template % {"cmds": " ".join(cmds),
250
 
                          "cases": cases,
251
 
                          "function_name": function_name,
252
 
                          "version": __version__,
253
 
                          "global_options": global_options,
254
 
                          "debug": debug_output if debug else "",
255
 
                          "bzr_version": bzr_version,
256
 
                          })
257
 
 
258
 
if __name__ == '__main__':
259
 
 
260
 
    import sys
261
 
    import locale
262
 
    import optparse
263
 
    from meta import __version__
264
 
 
265
 
    def plugin_callback(option, opt, value, parser):
266
 
        values = parser.values.selected_plugins
267
 
        if value == '-':
268
 
            del values[:]
269
 
        else:
270
 
            values.append(value)
271
 
 
272
 
    parser = optparse.OptionParser(usage="%prog [-f NAME] [-o]",
273
 
                                   version="%%prog %s" % __version__)
274
 
    parser.add_option("--function-name", "-f", metavar="NAME",
275
 
                      help="Name of the generated function (default: _bzr)")
276
 
    parser.add_option("--function-only", "-o", action="store_true",
277
 
                      help="Generate only the shell function, don't enable it")
278
 
    parser.add_option("--debug", action="store_true",
279
 
                      help=optparse.SUPPRESS_HELP)
280
 
    parser.add_option("--no-plugins", action="store_true",
281
 
                      help="Don't load any bzr plugins")
282
 
    parser.add_option("--plugin", metavar="NAME", type="string",
283
 
                      dest="selected_plugins", default=[],
284
 
                      action="callback", callback=plugin_callback,
285
 
                      help="Enable completions for the selected plugin"
286
 
                      + " (default: all plugins)")
287
 
    (opts, args) = parser.parse_args()
288
 
    if args:
289
 
        parser.error("script does not take positional arguments")
290
 
    kwargs = dict()
291
 
    for name, value in opts.__dict__.iteritems():
292
 
        if value is not None:
293
 
            kwargs[name] = value
294
 
 
295
 
    locale.setlocale(locale.LC_ALL, '')
296
 
    if not kwargs.get('no_plugins', False):
297
 
        plugin.load_plugins()
298
 
    commands.install_bzr_command_hooks()
299
 
    bash_completion_function(sys.stdout, **kwargs)