mirror of
https://github.com/wting/autojump
synced 2024-10-27 20:34:07 +00:00
add fuzzy matching
This commit is contained in:
parent
551b2f3853
commit
3125c65378
56
bin/autojump
56
bin/autojump
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
|
from difflib import SequenceMatcher
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
# FIXME(ting|2013-12-17): fix imports for Python 3 compatability
|
# FIXME(ting|2013-12-17): fix imports for Python 3 compatability
|
||||||
@ -47,11 +48,13 @@ from utils import first
|
|||||||
from utils import get_pwd
|
from utils import get_pwd
|
||||||
from utils import has_uppercase
|
from utils import has_uppercase
|
||||||
from utils import is_osx
|
from utils import is_osx
|
||||||
|
from utils import last
|
||||||
from utils import print_entry
|
from utils import print_entry
|
||||||
from utils import second
|
from utils import second
|
||||||
from utils import take
|
from utils import take
|
||||||
|
|
||||||
VERSION = 'release-v21.8.0'
|
VERSION = 'release-v21.8.0'
|
||||||
|
FUZZY_MATCH_THRESHOLD = 0.6
|
||||||
|
|
||||||
|
|
||||||
def set_defaults():
|
def set_defaults():
|
||||||
@ -180,10 +183,13 @@ def find_matches(entries, needles):
|
|||||||
ignore_case = detect_smartcase(needles)
|
ignore_case = detect_smartcase(needles)
|
||||||
|
|
||||||
consecutive_matches = match_consecutive(needles, data, ignore_case)
|
consecutive_matches = match_consecutive(needles, data, ignore_case)
|
||||||
|
quicksilver_matches = match_quicksilver(needles, data, ignore_case)
|
||||||
fuzzy_matches = match_fuzzy(needles, data, ignore_case)
|
fuzzy_matches = match_fuzzy(needles, data, ignore_case)
|
||||||
|
|
||||||
exists = lambda entry: os.path.exists(entry.path)
|
exists = lambda entry: os.path.exists(entry.path)
|
||||||
return ifilter(exists, chain(consecutive_matches, fuzzy_matches))
|
return ifilter(
|
||||||
|
exists,
|
||||||
|
chain(consecutive_matches, quicksilver_matches, fuzzy_matches))
|
||||||
|
|
||||||
|
|
||||||
def match_consecutive(needles, haystack, ignore_case=False):
|
def match_consecutive(needles, haystack, ignore_case=False):
|
||||||
@ -193,10 +199,10 @@ def match_consecutive(needles, haystack, ignore_case=False):
|
|||||||
For example:
|
For example:
|
||||||
needles = ['foo', 'baz']
|
needles = ['foo', 'baz']
|
||||||
haystack = [
|
haystack = [
|
||||||
(path="/foo/bar/baz", 10),
|
(path="/foo/bar/baz", weight=10),
|
||||||
(path="/foo/baz/moo", 10),
|
(path="/foo/baz/moo", weight=10),
|
||||||
(path="/moo/foo/baz", 10),
|
(path="/moo/foo/baz", weight=10),
|
||||||
(path="/foo/baz", 10)]
|
(path="/foo/baz", weight=10)]
|
||||||
|
|
||||||
regex_needle = re.compile(r'''
|
regex_needle = re.compile(r'''
|
||||||
foo # needle #1
|
foo # needle #1
|
||||||
@ -209,8 +215,8 @@ def match_consecutive(needles, haystack, ignore_case=False):
|
|||||||
''')
|
''')
|
||||||
|
|
||||||
result = [
|
result = [
|
||||||
(path="/moo/foo/baz", 10),
|
(path="/moo/foo/baz", weight=10),
|
||||||
(path="/foo/baz", 10)]
|
(path="/foo/baz", weight=10)]
|
||||||
"""
|
"""
|
||||||
regex_no_sep = '[^' + os.sep + ']*'
|
regex_no_sep = '[^' + os.sep + ']*'
|
||||||
regex_one_sep = regex_no_sep + os.sep + regex_no_sep
|
regex_one_sep = regex_no_sep + os.sep + regex_no_sep
|
||||||
@ -219,14 +225,46 @@ def match_consecutive(needles, haystack, ignore_case=False):
|
|||||||
regex_needle = regex_one_sep.join(needles) + regex_no_sep_end
|
regex_needle = regex_one_sep.join(needles) + regex_no_sep_end
|
||||||
regex_flags = re.IGNORECASE | re.UNICODE if ignore_case else re.UNICODE
|
regex_flags = re.IGNORECASE | re.UNICODE if ignore_case else re.UNICODE
|
||||||
|
|
||||||
found = lambda haystack: re.search(
|
found = lambda entry: re.search(
|
||||||
regex_needle,
|
regex_needle,
|
||||||
haystack.path,
|
entry.path,
|
||||||
flags=regex_flags)
|
flags=regex_flags)
|
||||||
return ifilter(found, haystack)
|
return ifilter(found, haystack)
|
||||||
|
|
||||||
|
|
||||||
def match_fuzzy(needles, haystack, ignore_case=False):
|
def match_fuzzy(needles, haystack, ignore_case=False):
|
||||||
|
"""
|
||||||
|
Performs an approximate match with the last needle against the end of
|
||||||
|
every path past an acceptable threshold (FUZZY_MATCH_THRESHOLD).
|
||||||
|
|
||||||
|
For example:
|
||||||
|
needles = ['foo', 'bar']
|
||||||
|
haystack = [
|
||||||
|
(path="/foo/bar/baz", weight=11),
|
||||||
|
(path="/foo/baz/moo", weight=10),
|
||||||
|
(path="/moo/foo/baz", weight=10),
|
||||||
|
(path="/foo/baz", weight=10),
|
||||||
|
(path="/foo/bar", weight=10)]
|
||||||
|
|
||||||
|
result = [
|
||||||
|
(path="/foo/bar/baz", weight=11),
|
||||||
|
(path="/moo/foo/baz", weight=10),
|
||||||
|
(path="/foo/baz", weight=10),
|
||||||
|
(path="/foo/bar", weight=10)]
|
||||||
|
|
||||||
|
This is a weak heuristic and be used as a last resort to find matches.
|
||||||
|
"""
|
||||||
|
needle = last(needles)
|
||||||
|
end_dir = lambda path: last(os.path.split(path))
|
||||||
|
match_percent = lambda entry: SequenceMatcher(
|
||||||
|
a=needle,
|
||||||
|
b=end_dir(entry.path)).ratio()
|
||||||
|
meets_threshold = lambda entry: match_percent(entry) \
|
||||||
|
>= FUZZY_MATCH_THRESHOLD
|
||||||
|
return ifilter(meets_threshold, haystack)
|
||||||
|
|
||||||
|
|
||||||
|
def match_quicksilver(needles, haystack, ignore_case=False):
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
return []
|
return []
|
||||||
|
10
bin/utils.py
10
bin/utils.py
@ -79,6 +79,16 @@ def is_windows():
|
|||||||
return platform.system() == 'Windows'
|
return platform.system() == 'Windows'
|
||||||
|
|
||||||
|
|
||||||
|
def last(xs):
|
||||||
|
it = iter(xs)
|
||||||
|
tmp = None
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
tmp = it.next()
|
||||||
|
except StopIteration:
|
||||||
|
return tmp
|
||||||
|
|
||||||
|
|
||||||
def move_file(src, dst):
|
def move_file(src, dst):
|
||||||
"""
|
"""
|
||||||
Atomically move file.
|
Atomically move file.
|
||||||
|
Loading…
Reference in New Issue
Block a user