| 
									
										
										
										
											2010-12-02 16:46:23 +00:00
										 |  |  | #!/usr/bin/env python | 
					
						
							| 
									
										
										
										
											2012-05-07 06:50:40 +00:00
										 |  |  | # -*- coding: utf-8 -*- | 
					
						
							| 
									
										
										
										
											2012-05-07 06:19:19 +00:00
										 |  |  | """ | 
					
						
							|  |  |  |   Copyright © 2008-2012 Joel Schaerer | 
					
						
							| 
									
										
										
										
											2013-07-07 02:17:54 +00:00
										 |  |  |   Copyright © 2012-2013 William Ting | 
					
						
							| 
									
										
										
										
											2012-05-07 06:19:19 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   *  This program is free software; you can redistribute it and/or modify | 
					
						
							|  |  |  |   it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  |   the Free Software Foundation; either version 3, or (at your option) | 
					
						
							|  |  |  |   any later version. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   *  This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |   but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |   GNU General Public License for more details. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   *  You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |   along with this program; if not, write to the Free Software | 
					
						
							|  |  |  |   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 
					
						
							|  |  |  | """ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-10-24 09:30:01 +00:00
										 |  |  | from __future__ import division, print_function | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-17 02:28:54 +00:00
										 |  |  | from collections import namedtuple | 
					
						
							|  |  |  | from functools import partial | 
					
						
							|  |  |  | from itertools import ifilter | 
					
						
							|  |  |  | from itertools import imap | 
					
						
							|  |  |  | from math import sqrt | 
					
						
							|  |  |  | from operator import attrgetter | 
					
						
							|  |  |  | from operator import itemgetter | 
					
						
							| 
									
										
										
										
											2013-05-14 22:34:19 +00:00
										 |  |  | import os | 
					
						
							| 
									
										
										
										
											2013-12-17 02:28:54 +00:00
										 |  |  | import platform | 
					
						
							| 
									
										
										
										
											2013-05-14 22:34:19 +00:00
										 |  |  | import sys | 
					
						
							| 
									
										
										
										
											2011-09-06 14:21:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-17 02:28:54 +00:00
										 |  |  | from argparse import ArgumentParser | 
					
						
							| 
									
										
										
										
											2013-09-26 20:40:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-17 02:28:54 +00:00
										 |  |  | from data import load | 
					
						
							|  |  |  | from data import save | 
					
						
							|  |  |  | from utils import decode | 
					
						
							|  |  |  | from utils import encode_local | 
					
						
							|  |  |  | from utils import first | 
					
						
							|  |  |  | from utils import is_osx | 
					
						
							|  |  |  | from utils import print_entry | 
					
						
							| 
									
										
										
										
											2013-05-21 14:28:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-17 02:28:54 +00:00
										 |  |  | VERSION = 'release-v21.8.0' | 
					
						
							|  |  |  | Entry = namedtuple('Entry', ['path', 'weight']) | 
					
						
							| 
									
										
										
										
											2013-09-26 20:40:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-07 01:23:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-14 22:34:19 +00:00
										 |  |  | def set_defaults(): | 
					
						
							|  |  |  |     config = {} | 
					
						
							| 
									
										
										
										
											2013-12-17 02:28:54 +00:00
										 |  |  |     config['tab_menu_separator'] = '__' | 
					
						
							| 
									
										
										
										
											2012-05-06 23:12:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-17 02:28:54 +00:00
										 |  |  |     if is_osx(): | 
					
						
							|  |  |  |         data_home = os.path.join( | 
					
						
							|  |  |  |                         os.path.expanduser('~'), | 
					
						
							|  |  |  |                         'Library', | 
					
						
							|  |  |  |                         'autojump') | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         data_home = os.getenv( | 
					
						
							|  |  |  |                 'XDG_DATA_HOME', | 
					
						
							|  |  |  |                 os.path.join( | 
					
						
							|  |  |  |                         os.path.expanduser('~'), | 
					
						
							|  |  |  |                         '.local', | 
					
						
							|  |  |  |                         'share', | 
					
						
							|  |  |  |                         'autojump')) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     config['data_path'] = os.path.join(data_home, 'autojump.txt') | 
					
						
							|  |  |  |     config['backup_path'] = os.path.join(data_home, 'autojump.txt.bak') | 
					
						
							|  |  |  |     config['tmp_path'] = os.path.join(data_home, 'data.tmp') | 
					
						
							| 
									
										
										
										
											2013-05-14 22:34:19 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return config | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-17 02:28:54 +00:00
										 |  |  | def parse_env(config): | 
					
						
							|  |  |  |     # TODO(ting|2013-12-16): add autojump_data_dir support | 
					
						
							|  |  |  |     # TODO(ting|2013-12-15): add ignore case / smartcase support | 
					
						
							|  |  |  |     # TODO(ting|2013-12-15): add symlink support | 
					
						
							| 
									
										
										
										
											2013-05-14 22:34:19 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return config | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-17 02:28:54 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def parse_args(config): | 
					
						
							|  |  |  |     parser = ArgumentParser( | 
					
						
							| 
									
										
										
										
											2013-05-15 01:58:24 +00:00
										 |  |  |             description='Automatically jump to directory passed as an argument.', | 
					
						
							| 
									
										
										
										
											2012-05-06 23:41:00 +00:00
										 |  |  |             epilog="Please see autojump(1) man pages for full documentation.") | 
					
						
							| 
									
										
										
										
											2013-02-25 05:49:45 +00:00
										 |  |  |     parser.add_argument( | 
					
						
							| 
									
										
										
										
											2013-02-25 05:55:29 +00:00
										 |  |  |             'directory', metavar='DIRECTORY', nargs='*', default='', | 
					
						
							| 
									
										
										
										
											2012-05-06 23:41:00 +00:00
										 |  |  |             help='directory to jump to') | 
					
						
							| 
									
										
										
										
											2013-02-25 05:49:45 +00:00
										 |  |  |     parser.add_argument( | 
					
						
							| 
									
										
										
										
											2013-05-15 00:03:08 +00:00
										 |  |  |             '-a', '--add', metavar='DIRECTORY', | 
					
						
							| 
									
										
										
										
											2013-12-17 02:28:54 +00:00
										 |  |  |             help='add path') | 
					
						
							| 
									
										
										
										
											2013-05-15 00:03:08 +00:00
										 |  |  |     parser.add_argument( | 
					
						
							|  |  |  |             '-i', '--increase', metavar='WEIGHT', nargs='?', type=int, | 
					
						
							|  |  |  |             const=20, default=False, | 
					
						
							| 
									
										
										
										
											2013-12-17 02:28:54 +00:00
										 |  |  |             help='increase current directory weight') | 
					
						
							| 
									
										
										
										
											2013-02-25 05:49:45 +00:00
										 |  |  |     parser.add_argument( | 
					
						
							| 
									
										
										
										
											2013-02-25 05:55:29 +00:00
										 |  |  |             '-d', '--decrease', metavar='WEIGHT', nargs='?', type=int, | 
					
						
							|  |  |  |             const=15, default=False, | 
					
						
							| 
									
										
										
										
											2013-12-17 02:28:54 +00:00
										 |  |  |             help='decrease current directory weight') | 
					
						
							|  |  |  |     # parser.add_argument( | 
					
						
							|  |  |  |             # '-b', '--bash', action="store_true", default=False, | 
					
						
							|  |  |  |             # help='enclose directory quotes to prevent errors') | 
					
						
							|  |  |  |     # parser.add_argument( | 
					
						
							|  |  |  |             # '--complete', action="store_true", default=False, | 
					
						
							|  |  |  |             # help='used for tab completion') | 
					
						
							| 
									
										
										
										
											2013-02-25 05:49:45 +00:00
										 |  |  |     parser.add_argument( | 
					
						
							|  |  |  |             '--purge', action="store_true", default=False, | 
					
						
							| 
									
										
										
										
											2013-12-17 02:28:54 +00:00
										 |  |  |             help='remove non-existent paths from database') | 
					
						
							| 
									
										
										
										
											2013-02-25 05:49:45 +00:00
										 |  |  |     parser.add_argument( | 
					
						
							|  |  |  |             '-s', '--stat', action="store_true", default=False, | 
					
						
							| 
									
										
										
										
											2012-05-06 23:41:00 +00:00
										 |  |  |             help='show database entries and their key weights') | 
					
						
							| 
									
										
										
										
											2013-02-25 05:49:45 +00:00
										 |  |  |     parser.add_argument( | 
					
						
							| 
									
										
										
										
											2013-05-14 22:34:19 +00:00
										 |  |  |             '-v', '--version', action="version", version="%(prog)s " + | 
					
						
							| 
									
										
										
										
											2013-12-17 02:28:54 +00:00
										 |  |  |             VERSION, help='show version information') | 
					
						
							| 
									
										
										
										
											2013-05-14 22:34:19 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     args = parser.parse_args() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-15 00:03:08 +00:00
										 |  |  |     if args.add: | 
					
						
							| 
									
										
										
										
											2013-12-17 02:28:54 +00:00
										 |  |  |         add_path(config, args.add) | 
					
						
							| 
									
										
										
										
											2013-05-14 22:34:19 +00:00
										 |  |  |         sys.exit(0) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-15 00:03:08 +00:00
										 |  |  |     if args.increase: | 
					
						
							| 
									
										
										
										
											2013-12-17 02:28:54 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             print_entry(add_path(config, os.getcwdu(), args.increase)) | 
					
						
							|  |  |  |             sys.exit(0) | 
					
						
							|  |  |  |         except OSError: | 
					
						
							|  |  |  |             print("Current directory no longer exists.", file=sys.stderr) | 
					
						
							|  |  |  |             sys.exit(1) | 
					
						
							| 
									
										
										
										
											2013-05-14 22:34:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-15 00:03:08 +00:00
										 |  |  |     if args.decrease: | 
					
						
							| 
									
										
										
										
											2013-12-17 02:28:54 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             print_entry(decrease_path(config, os.getcwdu(), args.decrease)) | 
					
						
							|  |  |  |             sys.exit(0) | 
					
						
							|  |  |  |         except OSError: | 
					
						
							|  |  |  |             print("Current directory no longer exists.", file=sys.stderr) | 
					
						
							|  |  |  |             sys.exit(1) | 
					
						
							| 
									
										
										
										
											2013-05-14 22:34:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-15 00:03:08 +00:00
										 |  |  |     if args.purge: | 
					
						
							| 
									
										
										
										
											2013-12-17 02:28:54 +00:00
										 |  |  |         print("Purged %d entries." % purge_missing_paths(config)) | 
					
						
							| 
									
										
										
										
											2013-05-14 22:34:19 +00:00
										 |  |  |         sys.exit(0) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-15 00:03:08 +00:00
										 |  |  |     if args.stat: | 
					
						
							| 
									
										
										
										
											2013-12-17 02:28:54 +00:00
										 |  |  |         print_stats(config) | 
					
						
							| 
									
										
										
										
											2013-05-14 22:34:19 +00:00
										 |  |  |         sys.exit(0) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-17 02:28:54 +00:00
										 |  |  |     print(encode_local(find_matches(config, args.directory))) | 
					
						
							|  |  |  |     sys.exit(0) | 
					
						
							| 
									
										
										
										
											2013-05-15 02:58:00 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-17 02:28:54 +00:00
										 |  |  |     # if args.complete: | 
					
						
							|  |  |  |         # config['match_cnt'] = 9 | 
					
						
							|  |  |  |         # config['ignore_case'] = True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # config['args'] = args | 
					
						
							| 
									
										
										
										
											2013-05-14 22:34:19 +00:00
										 |  |  |     return config | 
					
						
							| 
									
										
										
										
											2012-05-06 23:41:00 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-07 01:09:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-17 02:28:54 +00:00
										 |  |  | def add_path(config, path, increment=10): | 
					
						
							|  |  |  |     """Add a new path or increment an existing one.""" | 
					
						
							|  |  |  |     path = decode(path).rstrip(os.sep) | 
					
						
							|  |  |  |     if path == os.path.expanduser('~'): | 
					
						
							|  |  |  |         return path, 0 | 
					
						
							| 
									
										
										
										
											2012-05-07 01:09:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-17 02:28:54 +00:00
										 |  |  |     data = load(config) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if path in data: | 
					
						
							|  |  |  |         data[path] = sqrt((data[path]**2) + (increment**2)) | 
					
						
							| 
									
										
										
										
											2010-07-21 14:44:43 +00:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2013-12-17 02:28:54 +00:00
										 |  |  |         data[path] = increment | 
					
						
							| 
									
										
										
										
											2010-07-21 14:44:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-17 02:28:54 +00:00
										 |  |  |     save(config, data) | 
					
						
							|  |  |  |     return path, data[path] | 
					
						
							| 
									
										
										
										
											2012-05-07 00:34:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-07 14:14:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-17 02:28:54 +00:00
										 |  |  | def decrease_path(config, path, increment=15): | 
					
						
							|  |  |  |     """Decrease weight of existing path.""" | 
					
						
							|  |  |  |     path = decode(path).rstrip(os.sep) | 
					
						
							|  |  |  |     data = load(config) | 
					
						
							| 
									
										
										
										
											2012-04-07 14:14:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-17 02:28:54 +00:00
										 |  |  |     data[path] = max(0, data[path]-increment) | 
					
						
							| 
									
										
										
										
											2013-05-15 02:58:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-17 02:28:54 +00:00
										 |  |  |     save(config, data) | 
					
						
							|  |  |  |     return path, data[path] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def find_matches(config, needles, count=1): | 
					
						
							|  |  |  |     """Return [count] paths matching needles.""" | 
					
						
							|  |  |  |     entriefy = lambda tup: Entry(*tup) | 
					
						
							|  |  |  |     exists = lambda entry: os.path.exists(entry.path) | 
					
						
							|  |  |  |     data = sorted( | 
					
						
							|  |  |  |             ifilter(exists, imap(entriefy, load(config).iteritems())), | 
					
						
							|  |  |  |             key=attrgetter('weight'), | 
					
						
							|  |  |  |             reverse=True) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     print(data[:3]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # if no arguments, return first path | 
					
						
							|  |  |  |     if not needles: | 
					
						
							|  |  |  |         return first(data).path | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sanitize = lambda x: decode(x).rstrip(os.sep) | 
					
						
							|  |  |  |     needle = first(imap(sanitize, needles)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     exact_matches = match_exact(needle, data) | 
					
						
							| 
									
										
										
										
											2012-05-06 23:41:00 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-17 02:28:54 +00:00
										 |  |  |     return first(exact_matches).path | 
					
						
							| 
									
										
										
										
											2012-05-06 23:41:00 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-17 02:28:54 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def match_exact(needle, haystack): | 
					
						
							|  |  |  |     find = lambda haystack: needle in haystack.path | 
					
						
							|  |  |  |     return ifilter(find, haystack) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def purge_missing_paths(config): | 
					
						
							|  |  |  |     """Remove non-existent paths.""" | 
					
						
							|  |  |  |     exists = lambda x: os.path.exists(x[0]) | 
					
						
							|  |  |  |     old_data = load(config) | 
					
						
							|  |  |  |     new_data = dict(ifilter(exists, old_data.iteritems())) | 
					
						
							|  |  |  |     save(config, new_data) | 
					
						
							|  |  |  |     return len(old_data) - len(new_data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def print_stats(config): | 
					
						
							|  |  |  |     data = load(config) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for path, weight in sorted(data.iteritems(), key=itemgetter(1)): | 
					
						
							|  |  |  |         print_entry(path, weight) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     print("________________________________________\n") | 
					
						
							|  |  |  |     print("%d:\t total weight" % sum(data.itervalues())) | 
					
						
							|  |  |  |     print("%d:\t number of entries" % len(data)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         print("%.2f:\t current directory weight" % data.get(os.getcwdu(), 0)) | 
					
						
							|  |  |  |     except OSError: | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     print("\ndata:\t %s" % config['data_path']) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def main(): | 
					
						
							|  |  |  |     parse_args(parse_env(set_defaults())) | 
					
						
							| 
									
										
										
										
											2013-05-14 22:34:19 +00:00
										 |  |  |     return 0 | 
					
						
							| 
									
										
										
										
											2012-04-07 14:14:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-04 20:00:59 +00:00
										 |  |  | if __name__ == "__main__": | 
					
						
							| 
									
										
										
										
											2013-05-14 22:34:19 +00:00
										 |  |  |     sys.exit(main()) |