1
0
mirror of https://github.com/wting/autojump synced 2024-10-27 20:34:07 +00:00

implement basic fuzzy search

This commit is contained in:
William Ting 2012-05-06 18:10:06 -10:00
parent f98b13641f
commit d7cea40619

View File

@ -2,7 +2,6 @@
from __future__ import division, print_function from __future__ import division, print_function
import argparse import argparse
import math
from operator import itemgetter from operator import itemgetter
import os import os
import re import re
@ -10,7 +9,7 @@ import shutil
import sys import sys
from tempfile import NamedTemporaryFile from tempfile import NamedTemporaryFile
VERSION = 'release-v20' VERSION = 'release-v20-3'
MAX_KEYWEIGHT = 1000 MAX_KEYWEIGHT = 1000
MAX_STORED_PATHS = 1000 MAX_STORED_PATHS = 1000
COMPLETION_SEPARATOR = '__' COMPLETION_SEPARATOR = '__'
@ -40,6 +39,7 @@ class Database:
if path not in self.data: if path not in self.data:
self.data[path] = 10 self.data[path] = 10
else: else:
import math
self.data[path] = math.sqrt((self.data[path]**2)+100) self.data[path] = math.sqrt((self.data[path]**2)+100)
def decay(self): def decay(self):
@ -234,17 +234,17 @@ def match(path, pattern, only_end=False, ignore_case=False):
match_path = path match_path = path
if ignore_case: if ignore_case:
find_idx = match_path.lower().find(pattern.lower()) match_path = match_path.lower()
else: pattern = pattern.lower()
find_idx = match_path.find(pattern)
find_idx = match_path.find(pattern)
# truncate path to avoid matching a pattern multiple times # truncate path to avoid matching a pattern multiple times
if find_idx != -1: if find_idx != -1:
return (True, path) return (True, path)
else: else:
return (False, path[find_idx+len(pattern):]) return (False, path[find_idx+len(pattern):])
def find_matches(db, patterns, max_matches=1, ignore_case=False): def find_matches(db, patterns, max_matches=1, ignore_case=False, fuzzy=False):
""" Find max_matches paths that match the pattern, and add them to the result_list. """ """ Find max_matches paths that match the pattern, and add them to the result_list. """
try: try:
current_dir = decode(os.path.realpath(os.curdir)) current_dir = decode(os.path.realpath(os.curdir))
@ -254,6 +254,30 @@ def find_matches(db, patterns, max_matches=1, ignore_case=False):
dirs = list(db.data.items()) dirs = list(db.data.items())
dirs.sort(key=itemgetter(1), reverse=True) dirs.sort(key=itemgetter(1), reverse=True)
results = [] results = []
if fuzzy:
from difflib import get_close_matches
# create dictionary of end paths to compare against
end_dirs = {}
for d in dirs:
if ignore_case:
end = d[0].split('/')[-1].lower()
else:
end = d[0].split('/')[-1]
# collisions: ignore lower weight paths
if end not in end_dirs and os.path.exists(d[0]):
end_dirs[end] = d[0]
# find the first match (heighest weight)
found = get_close_matches(patterns[-1], end_dirs, 1, .6)
if found:
found = found[0]
results.append(end_dirs[found])
return results
else:
return []
for path, _ in dirs: for path, _ in dirs:
# avoid jumping to current directory # avoid jumping to current directory
if current_dir == path : if current_dir == path :
@ -312,6 +336,10 @@ def shell_utility():
if ARGS.complete or not results: if ARGS.complete or not results:
results = find_matches(db, patterns, max_matches, True) results = find_matches(db, patterns, max_matches, True)
# if no results, try approximate matching
if not results:
results = find_matches(db, patterns, max_matches, True, True)
quotes = "" quotes = ""
if ARGS.complete and ARGS.bash: quotes = "'" if ARGS.complete and ARGS.bash: quotes = "'"