135
165
echo "\$${i}=\"${!i}\""$'\e[K'
137
167
echo -ne '---\e[K\e[u'
140
def wrap_container(list, parser):
141
def tweaked_add_option(*opts, **attrs):
143
parser.add_option = tweaked_add_option
146
def wrap_parser(list, parser):
147
orig_add_option_group = parser.add_option_group
148
def tweaked_add_option_group(*opts, **attrs):
149
return wrap_container(list, orig_add_option_group(*opts, **attrs))
150
parser.add_option_group = tweaked_add_option_group
151
return wrap_container(list, parser)
153
def bash_completion_function(out, function_name="_bzr", function_only=False,
155
no_plugins=False, selected_plugins=None):
161
selected_plugins = set([x.replace('-', '_') for x in selected_plugins])
163
selected_plugins = None
165
re_switch = re.compile(r'\n(--[A-Za-z0-9-_]+)(?:, (-\S))?\s')
166
help_text = help_topics.topic_registry.get_detail('global-options')
167
global_options = set()
168
for long, short in re_switch.findall(help_text):
169
global_options.add(long)
171
global_options.add(short)
172
global_options = " ".join(sorted(global_options))
174
user_aliases = {} # dict from cmd name to set of user-defined alias names
175
for alias, expansion in config.GlobalConfig().get_aliases().iteritems():
176
for token in commands.shlex_split_unicode(expansion):
177
if not token.startswith("-"):
178
user_aliases.setdefault(token, set()).add(alias)
181
all_cmds = sorted(commands.all_command_names())
182
for cmdname in all_cmds:
183
cmd = commands.get_cmd_object(cmdname)
170
def bzr_version(self):
171
bzr_version = bzrlib.version_string
172
if not self.data.plugins:
175
bzr_version += " and the following plugins:"
176
for name, plugin in sorted(self.data.plugins.iteritems()):
177
bzr_version += "\n# %s" % plugin
179
def global_options(self):
180
return " ".join(sorted(self.data.global_options))
182
def command_cases(self):
184
for command in self.data.commands:
185
cases += self.command_case(command)
188
def command_case(self, command):
189
case = "\t%s)\n" % "|".join(command.aliases)
191
case += "\t\t# plugin \"%s\"\n" % command.plugin
194
for option in command.options:
195
for message in option.error_messages:
196
case += "\t\t# %s\n" % message
197
if option.registry_keys:
198
for key in option.registry_keys:
199
options.append("%s=%s" % (option, key))
200
enums.append("%s) optEnums='%s' ;;" %
201
(option, ' '.join(option.registry_keys)))
203
options.append(str(option))
204
case += "\t\tcmdOpts='%s'\n" % " ".join(options)
205
if command.fixed_words:
206
fixed_words = command.fixed_words
207
if isinstance(fixed_words, list):
208
fixed_words = "'%s'" + ' '.join(fixed_words)
209
case += "\t\tfixedWords=%s\n" % fixed_words
211
case += "\t\tcase $curOpt in\n\t\t\t"
212
case += "\n\t\t\t".join(enums)
213
case += "\n\t\tesac\n"
218
class CompletionData(object):
222
self.global_options = set()
225
def all_command_aliases(self):
226
for c in self.commands:
231
class CommandData(object):
233
def __init__(self, name):
235
self.aliases = [name]
238
self.fixed_words = None
241
class PluginData(object):
243
def __init__(self, name, version=None):
245
version = bzrlib.plugin.plugins()[name].__version__
247
self.version = version
250
if self.version == 'unknown':
252
return '%s %s' % (self.name, self.version)
255
class OptionData(object):
257
def __init__(self, name):
259
self.registry_keys = None
260
self.error_messages = []
265
def __cmp__(self, other):
266
return cmp(self.name, other.name)
269
class DataCollector(object):
271
def __init__(self, no_plugins=False, selected_plugins=None):
272
self.data = CompletionData()
273
self.user_aliases = {}
275
self.selected_plugins = set()
276
elif selected_plugins is None:
277
self.selected_plugins = None
279
self.selected_plugins = set([x.replace('-', '_')
280
for x in selected_plugins])
283
self.global_options()
288
def global_options(self):
289
re_switch = re.compile(r'\n(--[A-Za-z0-9-_]+)(?:, (-\S))?\s')
290
help_text = help_topics.topic_registry.get_detail('global-options')
291
for long, short in re_switch.findall(help_text):
292
self.data.global_options.add(long)
294
self.data.global_options.add(short)
297
for alias, expansion in config.GlobalConfig().get_aliases().iteritems():
298
for token in commands.shlex_split_unicode(expansion):
299
if not token.startswith("-"):
300
self.user_aliases.setdefault(token, set()).add(alias)
304
for name in sorted(commands.all_command_names()):
307
def command(self, name):
308
cmd = commands.get_cmd_object(name)
309
cmd_data = CommandData(name)
311
plugin_name = cmd.plugin_name()
312
if plugin_name is not None:
313
if (self.selected_plugins is not None and
314
plugin not in self.selected_plugins):
316
plugin_data = self.data.plugins.get(plugin_name)
317
if plugin_data is None:
318
plugin_data = PluginData(plugin_name)
319
self.data.plugins[plugin_name] = plugin_data
320
cmd_data.plugin = plugin_data
321
self.data.commands.append(cmd_data)
185
323
# Find all aliases to the command; both cmd-defined and user-defined.
186
324
# We assume a user won't override one command with a different one,
187
325
# but will choose completely new names or add options to existing
188
326
# ones while maintaining the actual command name unchanged.
190
aliases.extend(cmd.aliases)
191
aliases.extend(sorted([alias
193
if name in user_aliases
194
for alias in user_aliases[name]
195
if alias not in aliases]))
196
cases += "\t%s)\n" % "|".join(aliases)
198
plugin = cmd.plugin_name()
199
if plugin is not None:
200
if selected_plugins is not None and plugin not in selected_plugins:
203
cases += "\t\t# plugin \"%s\"\n" % plugin
327
cmd_data.aliases.extend(cmd.aliases)
328
cmd_data.aliases.extend(sorted([useralias
329
for cmdalias in cmd_data.aliases
330
if cmdalias in self.user_aliases
331
for useralias in self.user_aliases[cmdalias]
332
if useralias not in cmd_data.aliases]))
204
334
opts = cmd.options()
208
for optname in sorted(cmd.options()):
211
parser = option.get_optparser({optname: opt})
212
parser = wrap_parser(optswitches, parser)
214
opt.add_option(parser, opt.short_name())
215
if isinstance(opt, option.RegistryOption) and opt.enum_switch:
216
enum_switch = '--%s' % optname
335
for optname, opt in sorted(opts.iteritems()):
336
cmd_data.options.extend(self.option(opt))
338
if 'help' == name or 'help' in cmd.aliases:
339
cmd_data.fixed_words = ('"$cmds %s"' %
340
" ".join(sorted(help_topics.topic_registry.keys())))
342
def option(self, opt):
344
parser = option.get_optparser({opt.name: opt})
345
parser = self.wrap_parser(optswitches, parser)
347
opt.add_option(parser, opt.short_name())
348
if isinstance(opt, option.RegistryOption) and opt.enum_switch:
349
enum_switch = '--%s' % opt.name
350
enum_data = optswitches.get(enum_switch)
218
keys = opt.registry.keys()
353
enum_data.registry_keys = opt.registry.keys()
219
354
except ImportError, e:
220
cases += ("\t\t# ERROR getting registry keys for '--%s':"
221
+ " %s\n") % (optname, str(e).split('\n')[0])
223
if enum_switch in optswitches and keys:
224
optswitches.remove(enum_switch)
226
optswitches.append('%s=%s' % (enum_switch, key))
227
enums.append("%s) optEnums='%s' ;;"
228
% (enum_switch, ' '.join(keys)))
229
switches.extend(optswitches)
230
if 'help' == cmdname or 'help' in cmd.aliases:
231
fixedWords = " ".join(sorted(help_topics.topic_registry.keys()))
232
fixedWords = '"$cmds %s"' % fixedWords
234
cases += "\t\tcmdOpts='" + " ".join(switches) + "'\n"
236
if isinstance(fixedWords, list):
237
fixedWords = "'" + join(fixedWords) + "'"
238
cases += "\t\tfixedWords=" + fixedWords + "\n"
240
cases += "\t\tcase $curOpt in\n\t\t\t"
241
cases += "\n\t\t\t".join(enums)
242
cases += "\n\t\tesac\n"
245
bzr_version = bzrlib.version_string
249
bzr_version += " and the following plugins:"
250
for plugin in sorted(plugins):
251
pv = bzrlib.plugin.plugins()[plugin].__version__
256
bzr_version += "\n# %s%s" % (plugin, pv)
355
enum_data.error_messages.append(
356
"ERROR getting registry keys for '--%s': %s"
357
% (opt.name, str(e).split('\n')[0]))
358
return sorted(optswitches.values())
360
def wrap_container(self, optswitches, parser):
361
def tweaked_add_option(*opts, **attrs):
363
optswitches[name] = OptionData(name)
364
parser.add_option = tweaked_add_option
367
def wrap_parser(self, optswitches, parser):
368
orig_add_option_group = parser.add_option_group
369
def tweaked_add_option_group(*opts, **attrs):
370
return self.wrap_container(optswitches,
371
orig_add_option_group(*opts, **attrs))
372
parser.add_option_group = tweaked_add_option_group
373
return self.wrap_container(optswitches, parser)
376
def bash_completion_function(out, function_name="_bzr", function_only=False,
378
no_plugins=False, selected_plugins=None):
379
dc = DataCollector(no_plugins=no_plugins, selected_plugins=selected_plugins)
381
cg = BashCodeGen(data, function_name=function_name, debug=debug)
258
382
if function_only:
261
template = head + fun + tail
263
perhaps_debug_output = debug_output
265
perhaps_debug_output = ''
266
out.write(template % {"cmds": " ".join(cmds),
268
"function_name": function_name,
269
"version": __version__,
270
"global_options": global_options,
271
"debug": perhaps_debug_output,
272
"bzr_version": bzr_version,
275
389
if __name__ == '__main__':