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

reformat doc strings, move config into own function, add global variable for testing purposes

This commit is contained in:
William Ting 2012-05-12 16:31:37 -10:00
parent 79e644bd63
commit 13e385a0ef

View File

@ -35,49 +35,78 @@ MAX_STORED_PATHS = 1000
COMPLETION_SEPARATOR = '__' COMPLETION_SEPARATOR = '__'
ARGS = None ARGS = None
# load config from environmental variables CONFIG_DIR = None
if 'AUTOJUMP_DATA_DIR' in os.environ: DB_FILE = None
CONFIG_DIR = os.environ.get('AUTOJUMP_DATA_DIR')
else:
xdg_data_dir = os.environ.get('XDG_DATA_HOME') or os.path.join(os.environ['HOME'], '.local', 'share')
CONFIG_DIR = os.path.join(xdg_data_dir, 'autojump')
TESTING = False
KEEP_ALL_ENTRIES = False KEEP_ALL_ENTRIES = False
if 'AUTOJUMP_KEEP_ALL_ENTRIES' in os.environ and os.environ.get('AUTOJUMP_KEEP_ALL_ENTRIES') == '1': IGNORE_CASE = False
KEEP_ALL_ENTRIES = True
ALWAYS_IGNORE_CASE = False def config(testing=False):
if 'AUTOJUMP_IGNORE_CASE' in os.environ and os.environ.get('AUTOJUMP_IGNORE_CASE') == '1': global TESTING, CONFIG_DIR, KEEP_ALL_ENTRIES, DB_FILE
ALWAYS_IGNORE_CASE = True TESTING = testing
if CONFIG_DIR == os.path.expanduser('~'): # load config from environmental variables
DB_FILE = CONFIG_DIR + '/.autojump.txt' if 'AUTOJUMP_DATA_DIR' in os.environ:
else: CONFIG_DIR = os.environ.get('AUTOJUMP_DATA_DIR')
DB_FILE = CONFIG_DIR + '/autojump.txt' else:
xdg_data_dir = os.environ.get('XDG_DATA_HOME') or os.path.join(os.environ['HOME'], '.local', 'share')
CONFIG_DIR = os.path.join(xdg_data_dir, 'autojump')
if 'AUTOJUMP_KEEP_ALL_ENTRIES' in os.environ and os.environ.get('AUTOJUMP_KEEP_ALL_ENTRIES') == '1':
KEEP_ALL_ENTRIES = True
if 'AUTOJUMP_IGNORE_CASE' in os.environ and os.environ.get('AUTOJUMP_IGNORE_CASE') == '1':
ALWAYS_IGNORE_CASE = True
if CONFIG_DIR == os.path.expanduser('~'):
DB_FILE = CONFIG_DIR + '/.autojump.txt'
else:
DB_FILE = CONFIG_DIR + '/autojump.txt'
class Database: class Database:
""" Object for interfacing with autojump database. """ """
Object for interfacing with autojump database.
"""
def __init__(self, filename): def __init__(self, filename):
self.filename = filename self.filename = filename
self.data = {} self.data = {}
self.load() self.load()
def add(self, path, increment=1): def __len__(self):
""" Increment existing paths or initialize new ones to 0. """ return len(self.data)
def add(self, path, increment = 10):
"""
Increment existing paths or initialize new ones to 0.
"""
if path not in self.data: if path not in self.data:
self.data[path] = 10 self.data[path] = increment
else: else:
import math import math
self.data[path] = math.sqrt((self.data[path]**2)+100) self.data[path] = math.sqrt((self.data[path]**2)+(increment**2))
def decay(self): def decay(self):
""" Decay database entries. """ """
Decay database entries.
"""
for k in self.data.keys(): for k in self.data.keys():
self.data[k] *= 0.9 self.data[k] *= 0.9
def get_weight(self, path):
"""
Return path weight.
"""
if path in self.data:
return self.data[path]
else:
return 0
def load(self, error_recovery = False): def load(self, error_recovery = False):
""" Try to open the database file, recovering from backup if needed. """ """
Try to open the database file, recovering from backup if needed.
"""
try: try:
with open(self.filename, 'r') as aj_file: with open(self.filename, 'r') as aj_file:
for line in aj_file.readlines(): for line in aj_file.readlines():
@ -116,7 +145,9 @@ class Database:
return {} # if everything fails, return an empty dictionary return {} # if everything fails, return an empty dictionary
def maintenance(self): def maintenance(self):
""" Trims and decays database entries when exceeding settings. """ """
Trims and decays database entries when exceeding settings.
"""
if sum(self.data.values()) > MAX_KEYWEIGHT: if sum(self.data.values()) > MAX_KEYWEIGHT:
self.decay() self.decay()
if len(self.data) > MAX_STORED_PATHS: if len(self.data) > MAX_STORED_PATHS:
@ -124,7 +155,9 @@ class Database:
self.save() self.save()
def purge(self): def purge(self):
""" Deletes all entries that no longer exist on system. """ """
Deletes all entries that no longer exist on system.
"""
removed = [] removed = []
for path in self.data.keys(): for path in self.data.keys():
if not os.path.exists(path): if not os.path.exists(path):
@ -134,7 +167,9 @@ class Database:
return removed return removed
def save(self): def save(self):
""" Save database atomically and preserve backup. """ """
Save database atomically and preserve backup.
"""
# check file existence and permissions # check file existence and permissions
if ((not os.path.exists(self.filename)) or if ((not os.path.exists(self.filename)) or
os.name == 'nt' or os.name == 'nt' or
@ -166,17 +201,21 @@ class Database:
print("Error while creating backup autojump file. (%s)" % print("Error while creating backup autojump file. (%s)" %
ex, file=sys.stderr) ex, file=sys.stderr)
def trim(self): def trim(self, percent=0.1):
""" If database has exceeded MAX_STORED_PATHS, removes bottom 10%. """ """
If database has exceeded MAX_STORED_PATHS, removes bottom 10%.
"""
dirs = list(self.data.items()) dirs = list(self.data.items())
dirs.sort(key=itemgetter(1)) dirs.sort(key=itemgetter(1))
remove_cnt = .1 * MAX_STORED_PATHS remove_cnt = int(percent * len(dirs))
for path, _ in dirs[:remove_cnt]: for path, _ in dirs[:remove_cnt]:
del self.data[path] del self.data[path]
def get_db_file(filename = "autojump.txt"): def get_db_file(filename = "autojump.txt"):
""" Retrieve full database path. """ """
Retrieve full database path.
"""
# TODO: Remove when migration code is removed. # TODO: Remove when migration code is removed.
if CONFIG_DIR == os.path.expanduser("~"): if CONFIG_DIR == os.path.expanduser("~"):
return CONFIG_DIR + "/." + filename return CONFIG_DIR + "/." + filename
@ -184,9 +223,9 @@ def get_db_file(filename = "autojump.txt"):
return CONFIG_DIR + "/" + filename return CONFIG_DIR + "/" + filename
def options(): def options():
""" Parse command line options. """ """
global ARGS Parse command line options.
"""
parser = argparse.ArgumentParser(description='Automatically jump to directory passed as an argument.', parser = argparse.ArgumentParser(description='Automatically jump to directory passed as an argument.',
epilog="Please see autojump(1) man pages for full documentation.") epilog="Please see autojump(1) man pages for full documentation.")
parser.add_argument('directory', metavar='DIR', nargs='*', default='', parser.add_argument('directory', metavar='DIR', nargs='*', default='',
@ -235,7 +274,9 @@ def options():
return False return False
def decode(text, encoding=None, errors="strict"): def decode(text, encoding=None, errors="strict"):
""" Decoding step for Python 2 which does not default to unicode. """ """
Decoding step for Python 2 which does not default to unicode.
"""
if sys.version_info[0] > 2: if sys.version_info[0] > 2:
return text return text
else: else:
@ -244,8 +285,10 @@ def decode(text, encoding=None, errors="strict"):
return text.decode(encoding, errors) return text.decode(encoding, errors)
def output(unicode_text, encoding=None): def output(unicode_text, encoding=None):
""" Wrapper for the print function, using the filesystem encoding by default """
to minimize encoding mismatch problems in directory names. """ Wrapper for the print function, using the filesystem encoding by default
to minimize encoding mismatch problems in directory names.
"""
if sys.version_info[0] > 2: if sys.version_info[0] > 2:
print(unicode_text) print(unicode_text)
else: else:
@ -254,16 +297,20 @@ def output(unicode_text, encoding=None):
print(unicode_text.encode(encoding)) print(unicode_text.encode(encoding))
def unico(text): def unico(text):
""" If Python 2, convert to a unicode object. """ """
If Python 2, convert to a unicode object.
"""
if sys.version_info[0] > 2: if sys.version_info[0] > 2:
return text return text
else: else:
return unicode(text) return unicode(text)
def match_last(pattern): def match_last(pattern):
""" If the last pattern contains a full path, jump there. """
If the last pattern contains a full path, jump there.
The regexp is because we need to support stuff like The regexp is because we need to support stuff like
"j wo jo__3__/home/joel/workspace/joel" for zsh. """ "j wo jo__3__/home/joel/workspace/joel" for zsh.
"""
last_pattern_path = re.sub("(.*)"+COMPLETION_SEPARATOR, "", pattern[-1]) last_pattern_path = re.sub("(.*)"+COMPLETION_SEPARATOR, "", pattern[-1])
if (len(last_pattern_path) > 0 and if (len(last_pattern_path) > 0 and
last_pattern_path[0] == "/" and last_pattern_path[0] == "/" and
@ -274,8 +321,10 @@ def match_last(pattern):
return False return False
def match(path, pattern, only_end=False, ignore_case=False): def match(path, pattern, only_end=False, ignore_case=False):
""" Check whether a path matches a particular pattern, and return """
the remaining part of the string. """ Check whether a path matches a particular pattern, and return
the remaining part of the string.
"""
if only_end: if only_end:
match_path = "/".join(path.split('/')[-1-pattern.count('/'):]) match_path = "/".join(path.split('/')[-1-pattern.count('/'):])
else: else:
@ -293,7 +342,9 @@ def match(path, pattern, only_end=False, ignore_case=False):
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, fuzzy=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))
except OSError: except OSError:
@ -314,7 +365,7 @@ def find_matches(db, patterns, max_matches=1, ignore_case=False, fuzzy=False):
end = d[0].split('/')[-1] end = d[0].split('/')[-1]
# collisions: ignore lower weight paths # collisions: ignore lower weight paths
if end not in end_dirs and os.path.exists(d[0]): if end not in end_dirs and (os.path.exists(d[0]) or TESTING):
end_dirs[end] = d[0] end_dirs[end] = d[0]
# find the first match (heighest weight) # find the first match (heighest weight)
@ -340,7 +391,7 @@ def find_matches(db, patterns, max_matches=1, ignore_case=False, fuzzy=False):
found, tmp = match(tmp, p, False, ignore_case) found, tmp = match(tmp, p, False, ignore_case)
if not found: break if not found: break
if found and os.path.exists(path): if found and (os.path.exists(path) or TESTING):
if path not in results: if path not in results:
results.append(path) results.append(path)
if len(results) >= max_matches: if len(results) >= max_matches:
@ -348,8 +399,14 @@ def find_matches(db, patterns, max_matches=1, ignore_case=False, fuzzy=False):
return results return results
def shell_utility(): def shell_utility():
""" Run this when autojump is called as a shell utility. """ """
Run this when autojump is called as a shell utility.
"""
if options(): return True if options(): return True
config()
global ARGS, COMPLETION_SEPARATOR, DB_FILE, \
ALWAYS_IGNORE_CASE, KEEP_ALL_ENTRIES
db = Database(DB_FILE) db = Database(DB_FILE)
# if no directories, add empty string # if no directories, add empty string