changeset 24221:4e240d6ab898

dispatch: offer near-edit-distance suggestions for {file,rev}set functions Before this patch, when I have a brain fart and type `hg log -r 'add(foo)'`, hg exits and just says add isn't a function, leading me to the help page for revset to figure out how to spell the function. With this patch, it suggests 'adds' as a function I might have meant.
author Augie Fackler <augie@google.com>
date Mon, 26 Jan 2015 15:43:13 -0500
parents fe195d41f7d2
children 02d7b5cd373b
files mercurial/dispatch.py tests/test-revset.t
diffstat 2 files changed, 20 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/dispatch.py	Mon Jan 26 15:52:46 2015 -0500
+++ b/mercurial/dispatch.py	Mon Jan 26 15:43:13 2015 -0500
@@ -7,6 +7,7 @@
 
 from i18n import _
 import os, sys, atexit, signal, pdb, socket, errno, shlex, time, traceback, re
+import difflib
 import util, commands, hg, fancyopts, extensions, hook, error
 import cmdutil, encoding
 import ui as uimod
@@ -27,7 +28,17 @@
     "run the command in sys.argv"
     sys.exit((dispatch(request(sys.argv[1:])) or 0) & 255)
 
+def _getsimilar(symbols, value):
+    sim = lambda x: difflib.SequenceMatcher(None, value, x).ratio()
+    # The cutoff for similarity here is pretty arbitrary. It should
+    # probably be investigated and tweaked.
+    return [s for s in symbols if sim(s) > 0.6]
+
 def _formatparse(write, inst):
+    similar = []
+    if isinstance(inst, error.UnknownIdentifier):
+        # make sure to check fileset first, as revset can invoke fileset
+        similar = _getsimilar(inst.symbols, inst.function)
     if len(inst.args) > 1:
         write(_("hg: parse error at %s: %s\n") %
                          (inst.args[1], inst.args[0]))
@@ -35,6 +46,12 @@
             write(_("unexpected leading whitespace\n"))
     else:
         write(_("hg: parse error: %s\n") % inst.args[0])
+        if similar:
+            if len(similar) == 1:
+                write(_("(did you mean %r?)\n") % similar[0])
+            else:
+                ss = ", ".join(sorted(similar))
+                write(_("(did you mean one of %s?)\n") % ss)
 
 def dispatch(req):
     "run the command specified in req.args"
--- a/tests/test-revset.t	Mon Jan 26 15:52:46 2015 -0500
+++ b/tests/test-revset.t	Mon Jan 26 15:43:13 2015 -0500
@@ -891,12 +891,15 @@
 Bogus function gets suggestions
   $ log 'add()'
   hg: parse error: not a function: add
+  (did you mean 'adds'?)
   [255]
   $ log 'added()'
   hg: parse error: not a function: added
+  (did you mean 'adds'?)
   [255]
   $ log 'remo()'
   hg: parse error: not a function: remo
+  (did you mean one of remote, removes?)
   [255]
   $ log 'babar()'
   hg: parse error: not a function: babar