suggestions for unknown commands in subprocess mode

This commit is contained in:
adam j hartz 2015-03-16 08:37:12 -04:00
parent 4177c6bc06
commit 90adbaf070
2 changed files with 61 additions and 3 deletions

View file

@ -11,9 +11,9 @@ from io import TextIOWrapper, StringIO
from glob import glob, iglob
from subprocess import Popen, PIPE
from contextlib import contextmanager
from collections import Sequence, MutableMapping, Iterable, namedtuple
from collections import Sequence, MutableMapping, Iterable, namedtuple, OrderedDict
from xonsh.tools import string_types, redirect_stdout, redirect_stderr
from xonsh.tools import string_types, redirect_stdout, redirect_stderr, levenshtein, levenshtein_sort_helper
from xonsh.inspectors import Inspector
from xonsh.environ import default_env
from xonsh.aliases import DEFAULT_ALIASES
@ -355,7 +355,34 @@ def run_subproc(cmds, captured=True):
proc = Popen(aliased_cmd, universal_newlines=uninew, env=ENV.detype(),
stdin=stdin, stdout=stdout)
except FileNotFoundError:
print('xonsh: subprocess mode: command not found: {0}'.format(aliased_cmd[0]))
cmd = aliased_cmd[0]
print('xonsh: subprocess mode: command not found: {0}'.format(cmd))
if(ENV.get('SUGGEST_COMMANDS', True)):
threshold = ENV.get('SUGGEST_ERROR_THRESHOLD', 3)
max_sugg = ENV.get('SUGGEST_MAX_NUM', 5)
if max_sugg < 0:
max_sugg = float('inf')
suggested = {}
path = ENV.get('PATH',[])
for a in builtins.aliases:
if a not in suggested and levenshtein(a, cmd) < threshold:
suggested[a] = 'Alias'
for d in path:
if os.path.isdir(d):
for f in os.listdir(d):
if f not in suggested and levenshtein(f, cmd) < threshold:
fname = os.path.join(d,f)
suggested[f] = 'Command ({0})'.format(fname)
suggested = OrderedDict(sorted(suggested.items(),
key=lambda x: levenshtein_sort_helper(x[0], cmd)))
num = min(len(suggested), max_sugg)
if num>1:
print('Did you mean one of the following?')
elif num>0:
print('Did you mean the following?')
for i in range(num):
k,v = suggested.popitem(False)
print(' {0}: {1}'.format(k,v))
return
if prev_is_proxy:
proc.communicate(input=prev_proc.stdout)

View file

@ -210,3 +210,34 @@ class redirect_stdout(_RedirectStream):
class redirect_stderr(_RedirectStream):
"""Context manager for temporarily redirecting stderr to another file."""
_stream = "stderr"
# Public Domain code, by Magnus Lie Hetland
# from http://hetland.org/coding/python/levenshtein.py
def levenshtein(a,b):
"Calculates the Levenshtein distance between a and b."
n, m = len(a), len(b)
if n > m:
# Make sure n <= m, to use O(min(n,m)) space
a,b = b,a
n,m = m,n
current = range(n+1)
for i in range(1,m+1):
previous, current = current, [i]+[0]*n
for j in range(1,n+1):
add, delete = previous[j]+1, current[j-1]+1
change = previous[j-1]
if a[j-1] != b[i-1]:
change = change + 1
current[j] = min(add, delete, change)
return current[n]
def levenshtein_sort_helper(x, y):
x = x.lower()
y = y.lower()
lendiff = len(x)+len(y)
inx = len([i for i in x if i not in y])
iny = len([i for i in y if i not in x])
return lendiff + inx + iny