diff --git a/bin/autojump b/bin/autojump index edc1ec7..92b6d83 100755 --- a/bin/autojump +++ b/bin/autojump @@ -45,12 +45,16 @@ from data import save from utils import decode from utils import encode_local from utils import first +from utils import get_needle_and_index from utils import get_pwd from utils import has_uppercase from utils import is_osx +from utils import is_tab_entry +from utils import is_tab_partial_match from utils import last from utils import print_entry -from utils import print_tab_completion_menu +from utils import print_tab_menu +from utils import sanitize from utils import second from utils import surround_quotes from utils import take @@ -58,11 +62,11 @@ from utils import take VERSION = 'release-v21.8.0' FUZZY_MATCH_THRESHOLD = 0.6 TAB_COMPLETION_COUNT = 9 +TAB_SEPARATOR = '__' def set_defaults(): config = {} - config['tab_menu_separator'] = '__' if is_osx(): data_home = os.path.join( @@ -170,8 +174,6 @@ def find_matches(entries, needles): if not needles: return first(data).path - sanitize = lambda x: decode(x).rstrip(os.sep) - needles = map(sanitize, needles) ignore_case = detect_smartcase(needles) exists = lambda entry: os.path.exists(entry.path) @@ -318,11 +320,11 @@ def main(): if args.add: save(config, first(add_path(load(config), args.add))) elif args.complete: - print_tab_completion_menu( - separator=config['tab_menu_separator'], - entries=take( - TAB_COMPLETION_COUNT, - find_matches(entriefy(load(config)), args.directory))) + needle = first(sanitize(args.directory)) + tab_entries = take( + TAB_COMPLETION_COUNT, + find_matches(entriefy(load(config)), needle)) + print_tab_menu(needle, tab_entries, TAB_SEPARATOR) elif args.decrease: data, entry = decrease_path(load(config), get_pwd(), args.decrease) save(config, data) @@ -340,14 +342,31 @@ def main(): print_stats(load(config), config['data_path']) else: # default behavior, no optional arguments - result = first(find_matches(entriefy(load(config)), args.directory)) + entries = entriefy(load(config)) + needles = sanitize(args.directory) + needle = first(needles) - if result: - print(encode_local(surround_quotes(result.path))) + if is_tab_entry(needle, TAB_SEPARATOR): + # the needle is actually a tab entry here + needle, tab_index = get_needle_and_index(needle, TAB_SEPARATOR) + tab_entries = take( + TAB_COMPLETION_COUNT, + find_matches(entries, needle)) + + get_ith_path = lambda i, iterable: last(take(i, iterable)).path + print(encode_local(surround_quotes( + get_ith_path(tab_index, tab_entries)))) + elif is_tab_partial_match(needle, TAB_SEPARATOR): + print("tab_partial_match") else: - # always return something so the calling shell function has an - # argument to `cd` to - print(encode_local('.')) + result = first(find_matches(entries, needles)) + + if result: + print(encode_local(surround_quotes(result.path))) + else: + # always return something so the calling shell function has an + # argument to `cd` to + print(encode_local('.')) return 0 diff --git a/bin/utils.py b/bin/utils.py index 166e44b..5fce158 100644 --- a/bin/utils.py +++ b/bin/utils.py @@ -8,6 +8,7 @@ import errno from itertools import islice import os import platform +import re import shutil import sys import unicodedata @@ -51,6 +52,21 @@ def first(xs): return None +def get_needle_and_index(tab_entry, separator): + """ + Given a tab entry in the following format return the needle and index: + + [needle]__[index]__[possible_match] + """ + matches = re.search( + r'(.*)' + \ + separator + \ + r'([0-9]{1})' + \ + separator, tab_entry) + return matches.group(1), int(matches.group(2)) + + + def get_pwd(): try: return os.getcwdu() @@ -79,6 +95,24 @@ def is_osx(): return platform.system() == 'Darwin' +def is_tab_entry(needle, separator): + """ + Valid tab entry: + + [needle]__[index]__[possible_match] + """ + pattern = re.compile( + '.*' + \ + separator + \ + '[0-9]{1}' + \ + separator) + return re.search(pattern, needle) + + +def is_tab_partial_match(needle, separator): + return re.match(r'(.*)'+separator, needle) + + def is_windows(): return platform.system() == 'Windows' @@ -110,16 +144,30 @@ def print_entry(entry): print(encode_local("%.1f:\t%s" % (entry.weight, entry.path))) -def print_tab_completion_menu(separator, entries): - for i, entry in enumerate(entries): +def print_tab_menu(needle, tab_entries, separator): + """ + Prints the tab completion menu according to the following format: + + [needle]__[index]__[possible_match] + + The needle (search pattern) and index are necessary to recreate the results + on subsequent calls. + """ + for i, entry in enumerate(tab_entries): print(encode_local(surround_quotes( - '%s%d%s%s' % ( + '%s%s%d%s%s' % ( + needle, separator, - i, + i+1, separator, entry.path)))) +def sanitize(directories): + clean = lambda x: decode(x).rstrip(os.sep) + return map(clean, directories) + + def second(xs): it = iter(xs) try: