51
50
# Compatibility - Option used to be in commands.
52
51
from .option import Option
53
52
from .plugin import disable_plugins, load_plugins, plugin_name
54
from . import registry
53
from . import errors, registry
55
54
from .sixish import (
59
class BzrOptionError(errors.BzrCommandError):
61
_fmt = "Error in command line options"
60
64
class CommandInfo(object):
61
65
"""Information about a command."""
218
222
return plugin_cmds.keys()
225
# Overrides for common mispellings that heuristics get wrong
227
'ic': {'ci': 0}, # heuristic finds nick
231
def guess_command(cmd_name):
232
"""Guess what command a user typoed.
234
:param cmd_name: Command to search for
235
:return: None if no command was found, name of a command otherwise
238
for name in all_command_names():
240
cmd = get_cmd_object(name)
241
names.update(cmd.aliases)
242
# candidate: modified levenshtein distance against cmd_name.
244
from . import patiencediff
245
for name in sorted(names):
246
matcher = patiencediff.PatienceSequenceMatcher(None, cmd_name, name)
248
opcodes = matcher.get_opcodes()
249
for opcode, l1, l2, r1, r2 in opcodes:
250
if opcode == 'delete':
252
elif opcode == 'replace':
253
distance += max(l2-l1, r2-l1)
254
elif opcode == 'insert':
256
elif opcode == 'equal':
257
# Score equal ranges lower, making similar commands of equal
258
# length closer than arbitrary same length commands.
259
distance -= 0.1 * (l2-l1)
260
costs[name] = distance
261
costs.update(_GUESS_OVERRIDES.get(cmd_name, {}))
262
costs = sorted((value, key) for key, value in costs.iteritems())
267
candidate = costs[0][1]
221
271
def get_cmd_object(cmd_name, plugins_override=True):
222
272
"""Return the command object for a command.
228
278
return _get_cmd_object(cmd_name, plugins_override)
230
raise errors.BzrCommandError(gettext('unknown command "%s"') % cmd_name)
280
# No command found, see if this was a typo
281
candidate = guess_command(cmd_name)
282
if candidate is not None:
283
raise errors.BzrCommandError(
284
gettext('unknown command "%s". Perhaps you meant "%s"')
285
% (cmd_name, candidate))
286
raise errors.BzrCommandError(gettext('unknown command "%s"')
233
290
def _get_cmd_object(cmd_name, plugins_override=True, check_missing=True):