remove typo completion, add subsequence completion

This commit is contained in:
adam j hartz 2016-06-08 01:29:15 -04:00
parent cf3105e1ab
commit d027432e3b
3 changed files with 70 additions and 12 deletions

View file

@ -13,6 +13,8 @@ Current Developments
attempted to load. attempted to load.
* Only show the prompt for the wizard if we did not attempt to load any run * Only show the prompt for the wizard if we did not attempt to load any run
control files (as opposed to if none were successfully loaded). control files (as opposed to if none were successfully loaded).
* Tab completion of paths now includes zsh-style path expansion (subsequence
matching)
**Deprecated:** None **Deprecated:** None

View file

@ -151,9 +151,57 @@ def _quote_paths(paths, start, end):
return out return out
def fuzzy_match(ref, typed): def joinpath(path):
thresh = builtins.__xonsh_env__['SUGGEST_THRESHOLD'] if path is None:
return levenshtein(ref, typed, thresh) <= thresh return ''
if len(path) == 0:
return ''
if path == ('',):
return get_sep()
elif path[0] == '':
return get_sep() + _normpath(os.path.join(*path))
else:
return _normpath(os.path.join(*path))
def splitpath(path):
path = _normpath(path)
if path.startswith(get_sep()):
pre = ('', )
else:
pre = ()
return pre + _splitpath(path, ())
def _splitpath(path, sofar=()):
folder, path = os.path.split(path)
if path == "":
return sofar[::-1]
elif folder == "":
return (sofar + (path, ))[::-1]
else:
return _splitpath(folder, sofar + (path, ))
def expanded_match(ref, typed):
if len(typed) == 0:
return True
elif len(ref) == 0:
return False
elif ref[0] == typed[0]:
return expanded_match(ref[1:], typed[1:])
else:
return expanded_match(ref[1:], typed)
def _expand_one(sofar, nextone):
out = set()
for i in sofar:
for j in iglobpath(os.path.join(joinpath(i), '*') if i is not None else '*'):
j = os.path.basename(j)
if expanded_match(j, nextone):
out.add((i or ()) + (j, ))
return out
def complete_path(prefix, line, start, end, ctx, cdpath=True): def complete_path(prefix, line, start, end, ctx, cdpath=True):
@ -174,15 +222,18 @@ def complete_path(prefix, line, start, end, ctx, cdpath=True):
csc = env.get('CASE_SENSITIVE_COMPLETIONS') csc = env.get('CASE_SENSITIVE_COMPLETIONS')
for s in iglobpath(prefix + '*', ignore_case=(not csc)): for s in iglobpath(prefix + '*', ignore_case=(not csc)):
paths.add(s) paths.add(s)
if len(paths) == 0: if env.get('FUZZY_PATH_COMPLETION'):
for s in iglobpath(os.path.join(os.path.dirname(prefix), '*'), p = splitpath(prefix)
ignore_case=(not csc)): if len(p) != 0:
bname = os.path.basename(prefix) if p[0] == '':
lenb = len(bname) basedir = ('', )
if csc and fuzzy_match(s, bname): p = p[1:]
paths.add(os.path.join(os.path.dirname(prefix), s)) else:
if (not csc) and fuzzy_match(s.lower(), prefix.lower()): basedir = None
paths.add(os.path.join(os.path.dirname(prefix), s)) matches_so_far = {basedir}
for i in p:
matches_so_far = _expand_one(matches_so_far, i)
paths |= {joinpath(i) for i in matches_so_far}
if tilde in prefix: if tilde in prefix:
home = os.path.expanduser(tilde) home = os.path.expanduser(tilde)
paths = {s.replace(home, tilde) for s in paths} paths = {s.replace(home, tilde) for s in paths}

View file

@ -92,6 +92,7 @@ DEFAULT_ENSURERS = {
'DYNAMIC_CWD_WIDTH': (is_dynamic_cwd_width, to_dynamic_cwd_tuple, 'DYNAMIC_CWD_WIDTH': (is_dynamic_cwd_width, to_dynamic_cwd_tuple,
dynamic_cwd_tuple_to_str), dynamic_cwd_tuple_to_str),
'FORCE_POSIX_PATHS': (is_bool, to_bool, bool_to_str), 'FORCE_POSIX_PATHS': (is_bool, to_bool, bool_to_str),
'FUZZY_PATH_COMPLETION': (is_bool, to_bool, bool_to_str),
'HISTCONTROL': (is_string_set, csv_to_set, set_to_csv), 'HISTCONTROL': (is_string_set, csv_to_set, set_to_csv),
'IGNOREEOF': (is_bool, to_bool, bool_to_str), 'IGNOREEOF': (is_bool, to_bool, bool_to_str),
'INTENSIFY_COLORS_ON_WIN':(always_false, intensify_colors_on_win_setter, 'INTENSIFY_COLORS_ON_WIN':(always_false, intensify_colors_on_win_setter,
@ -202,6 +203,7 @@ DEFAULT_VALUES = {
'DYNAMIC_CWD_WIDTH': (float('inf'), 'c'), 'DYNAMIC_CWD_WIDTH': (float('inf'), 'c'),
'EXPAND_ENV_VARS': True, 'EXPAND_ENV_VARS': True,
'FORCE_POSIX_PATHS': False, 'FORCE_POSIX_PATHS': False,
'FUZZY_PATH_COMPLETION': True,
'HISTCONTROL': set(), 'HISTCONTROL': set(),
'IGNOREEOF': False, 'IGNOREEOF': False,
'INDENT': ' ', 'INDENT': ' ',
@ -350,6 +352,9 @@ DEFAULT_DOCS = {
"and $TITLE. See 'Customizing the Prompt' " "and $TITLE. See 'Customizing the Prompt' "
'http://xon.sh/tutorial.html#customizing-the-prompt', 'http://xon.sh/tutorial.html#customizing-the-prompt',
configurable=False, default='xonsh.environ.FORMATTER_DICT'), configurable=False, default='xonsh.environ.FORMATTER_DICT'),
'FUZZY_PATH_COMPLETION': VarDocs(
"Causes path completion to use subsequence matching rather than "
"substring matching."),
'HISTCONTROL': VarDocs( 'HISTCONTROL': VarDocs(
'A set of strings (comma-separated list in string form) of options ' 'A set of strings (comma-separated list in string form) of options '
'that determine what commands are saved to the history list. By ' 'that determine what commands are saved to the history list. By '