1
0
mirror of https://github.com/wting/autojump synced 2026-03-02 03:49:26 +00:00

restructure files, working make doc and make release

This commit is contained in:
William Ting
2012-04-17 13:09:39 -10:00
parent 2ebcdba5bd
commit acfc5c13ef
16 changed files with 28 additions and 90 deletions

23
bin/_j Normal file
View File

@@ -0,0 +1,23 @@
#compdef j
#Copyright Joel Schaerer 2008, 2009
#This file is part of autojump
#autojump 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 of the License, or
#(at your option) any later version.
#
#autojump 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 autojump. If not, see <http://www.gnu.org/licenses/>.
cur=${words[2, -1]}
autojump --completion ${=cur[*]} | while read i; do
compadd -U "$i";
done

330
bin/autojump Executable file
View File

@@ -0,0 +1,330 @@
#!/usr/bin/env python
"""Copyright Joel Schaerer 2008-2012
This file is part of autojump
autojump 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 of the License, or
(at your option) any later version.
autojump 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 autojump. If not, see <http://www.gnu.org/licenses/>.
Autojump is a small tool that maintains a database of your most
used directories, and finds the best match to help you jump to
frequently used places."""
from __future__ import division, print_function
import argparse
from sys import argv, stderr, version_info, exit, getfilesystemencoding
from tempfile import NamedTemporaryFile
from operator import itemgetter
import os
import shutil
AUTOJUMP_VERSION = "release-v20"
MAX_KEYWEIGHT = 1000
MAX_STORED_PATHS = 600
COMPLETION_SEPARATOR = '__'
if "AUTOJUMP_DATA_DIR" in os.environ:
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')
def uniqadd(collection, key):
"""Adds a key to a list only if it is not already present"""
if key not in collection:
collection.append(key)
def dicadd(dic, key, increment=1):
"""Increment a value in a dic, set it to 0
if is is not already present"""
dic[key] = dic.get(key, 0.)+increment
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"""
if version_info[0] > 2:
print(unicode_text)
else:
if encoding is None:
encoding = getfilesystemencoding()
print(unicode_text.encode(encoding))
def decode(text,encoding=None,errors="strict"):
"""Decoding step for python2.x which does not default to unicode"""
if version_info[0] > 2:
return text
else:
if encoding is None:
encoding = getfilesystemencoding()
return text.decode(encoding,errors)
def unico(text):
"""if python2, convert to a unicode object"""
if version_info[0] > 2:
return text
else:
return unicode(text)
def save(path_dict, dic_file):
"""Save the database in an atomic way, and preserve
a backup file."""
# If the dic_file exists and os supports permissions, check that dic_file belongs to us
# Otherwise, fail quietly
if (not os.path.exists(dic_file)) or os.name == 'nt' or os.getuid() == os.stat(dic_file)[4]:
temp = NamedTemporaryFile(dir=CONFIG_DIR, delete=False)
for path,weight in sorted(path_dict.items(),key=itemgetter(1),reverse=True):
# the db is stored in utf-8
temp.write((unico("%s\t%s\n")%(weight,path)).encode("utf-8"))
# Catching disk errors and skipping save since file handle can't be closed.
try:
#cf. http://thunk.org/tytso/blog/2009/03/15/dont-fear-the-fsync/
temp.flush()
os.fsync(temp)
temp.close()
except IOError as ex:
print("Error while saving autojump database (disk full?)" %
ex, file=stderr)
return
# Use shutil.move instead of os.rename because windows doesn't support
# using rename to overwrite files
shutil.move(temp.name, dic_file)
try: #backup file
import time
if (not os.path.exists(dic_file+".bak") or
time.time()-os.path.getmtime(dic_file+".bak")>86400):
shutil.copy(dic_file, dic_file+".bak")
except OSError as ex:
print("Error while creating backup autojump file. (%s)" %
ex, file=stderr)
def open_dic(dic_file, error_recovery=False):
"""Try hard to open the database file, recovering
from backup if needed. """
try:
path_dict = {}
with open(dic_file, 'r') as aj_file:
for l in aj_file.readlines():
weight,path = l[:-1].split("\t",1)
# the db is stored in utf-8
path = decode(path,"utf-8")
path_dict[path] = float(weight)
return path_dict
except (IOError, EOFError):
if not error_recovery and os.path.exists(dic_file+".bak"):
print('Problem with autojump database,\
trying to recover from backup...', file=stderr)
shutil.copy(dic_file+".bak", dic_file)
return open_dic(dic_file, True)
else:
# Temporary migration code
old_dic_file = get_dic_file("autojump_py")
if os.path.exists(old_dic_file):
try: # fix to get optimised pickle in python < 3
import cPickle as pickle
except ImportError:
import pickle
try:
with open(old_dic_file, 'rb') as aj_file:
if version_info[0] > 2:
#encoding is only specified for python2.x compatibility
path_dict = pickle.load(aj_file, encoding="utf-8")
else:
path_dict = pickle.load(aj_file)
unicode_dict = {} #we now use unicode internally
for k,v in path_dict.items():
print(k)
unicode_dict[decode(k,errors="replace")] = v
return unicode_dict
except (IOError, EOFError, pickle.UnpicklingError):
pass
return {} #if everything fails, return an empty file
def forget(path_dict, dic_file):
"""Gradually forget about directories. Only call
from the actual jump since it can take time"""
keyweight = sum(path_dict.values())
if keyweight > MAX_KEYWEIGHT:
for k in path_dict.keys():
path_dict[k] *= 0.9 * MAX_KEYWEIGHT / keyweight
save(path_dict, dic_file)
def clean_dict(sorted_dirs, path_dict):
"""Limits the sized of the path_dict to MAX_STORED_PATHS.
Returns True if keys were deleted"""
if len(sorted_dirs) > MAX_STORED_PATHS:
#remove 25 more than needed, to avoid doing it every time
for path, dummy in sorted_dirs[MAX_STORED_PATHS-25:]:
del path_dict[path]
return True
else: return False
def match(path, pattern, ignore_case=False, only_end=False):
"""Check whether a path matches a particular pattern, and return
the remaning part of the string"""
if only_end:
match_string = "/".join(path.split('/')[-1-pattern.count('/'):])
else:
match_string = path
if ignore_case:
find_idx = match_string.lower().find(pattern.lower())
else:
find_idx = match_string.find(pattern)
does_match = (find_idx != -1)
# Eat the path to avoid two patterns matching the same part of the string
if does_match:
eaten_path = path[find_idx+len(pattern):]
else:
eaten_path = path
return (does_match, eaten_path)
def find_matches(dirs, patterns, result_list, ignore_case, max_matches, current_dir):
"""Find max_matches paths that match the pattern,
and add them to the result_list"""
for path, count in dirs:
# Don't jump to where we alread are
if current_dir == path :
continue
does_match, eaten_path = True, path
for n,p in enumerate(patterns):
#For the last pattern, only match the end of the pattern
does_match, eaten_path = match(eaten_path, p, ignore_case, only_end=(n == len(patterns)-1))
if not does_match: break
#If a path doesn't exist, don't jump there
#We still keep it in db in case it's from a removable drive
if does_match and os.path.exists(path):
uniqadd(result_list, path)
if len(result_list) >= max_matches :
break
def get_dic_file(filename="autojump.txt"):
if CONFIG_DIR == os.path.expanduser("~"):
dic_file = CONFIG_DIR+"/." + filename
else:
dic_file = CONFIG_DIR+"/" + filename
return dic_file
def shell_utility():
"""Run this when autojump is called as a shell utility"""
parser = argparse.ArgumentParser(description='Automatically jump to directory passed as an argument.',
epilog="Please see autojump(1) man pages for full documentation.")
parser.add_argument('directory', metavar='DIR', nargs='*', default='',
help='directory to jump to')
parser.add_argument('-a', '--add', metavar='DIR',
help='manually add path to database')
parser.add_argument('-b', '--bash', action="store_true", default=False,
help='enclose directory quotes to prevent errors')
parser.add_argument('--completion', action="store_true", default=False,
help='prevent key weight decay over time')
parser.add_argument('--stat', action="store_true", default=False,
help='show database entries and their key weights')
parser.add_argument('--version', action="version", version="%(prog)s " + AUTOJUMP_VERSION,
help='show version information and exit')
args = parser.parse_args()
dic_file = get_dic_file()
path_dict = open_dic(dic_file)
# The home dir can be reached quickly by "cd" and may interfere with other directories
if (args.add):
if(args.add != os.path.expanduser("~")):
dicadd(path_dict, decode(args.add))
save(path_dict, dic_file)
return True
if (args.stat):
paths = list(path_dict.items())
paths.sort(key=itemgetter(1))
for path, count in paths[-100:]:
output(unico("%.1f:\t%s") % (count, path))
print("Total key weight: %d. Number of stored paths: %d" %
(sum(path_dict.values()), len(paths)))
return True
import re
#userchoice is i if the pattern is __pattern__i, otherwise -1
userchoice = -1
results = []
#default: gradually forget about old directories
if (not args.completion): forget(path_dict, dic_file)
if (args.directory == ''):
patterns = [unico("")]
else:
patterns = [decode(a) for a in args.directory]
# If the last pattern contains a full path, jump there
# The regexp is because we need to support stuff like
# "j wo jo__3__/home/joel/workspace/joel" for zsh
last_pattern_path = re.sub("(.*)"+COMPLETION_SEPARATOR, "", patterns[-1])
if (len(last_pattern_path)>0 and
last_pattern_path[0] == "/" and
os.path.exists(last_pattern_path)):
if not args.completion: output(last_pattern_path)
else:
#check for ongoing completion, and act accordingly
endmatch = re.search(COMPLETION_SEPARATOR+"([0-9]+)", patterns[-1])
if endmatch: #user has selected a completion
userchoice = int(endmatch.group(1))
patterns[-1] = re.sub(COMPLETION_SEPARATOR+"[0-9]+.*",
"", patterns[-1])
else: #user hasn't selected a completion, display the same choices again
endmatch = re.match("(.*)"+COMPLETION_SEPARATOR, patterns[-1])
if endmatch: patterns[-1] = endmatch.group(1)
dirs = list(path_dict.items())
dirs.sort(key=itemgetter(1), reverse=True)
if args.completion or userchoice != -1:
max_matches = 9
else:
max_matches = 1
# Don't jump to the current directory
try:
current_dir = decode(os.path.realpath(os.curdir))
#Sometimes the current path doesn't exist anymore.
#In that case, jump if possible.
except OSError:
current_dir = None
find_matches(dirs, patterns, results, False, max_matches, current_dir)
# If not found, try ignoring case.
# On completion always show all results
if args.completion or not results:
find_matches(dirs, patterns, results,
ignore_case=True,
max_matches=max_matches, current_dir=current_dir)
# Keep the database to a reasonable size
if not args.completion and clean_dict(dirs, path_dict):
save(path_dict, dic_file)
if args.completion and args.bash: quotes = "'"
else: quotes = ""
if userchoice != -1:
if len(results) > userchoice-1 :
output(unico("%s%s%s") % (quotes,results[userchoice-1],quotes))
elif len(results) > 1 and args.completion:
output("\n".join(("%s%s%d%s%s" % (patterns[-1],
COMPLETION_SEPARATOR, n+1, COMPLETION_SEPARATOR, r)
for n, r in enumerate(results[:8]))))
elif results: output(unico("%s%s%s")%(quotes,results[0],quotes))
else:
return False
return True
if __name__ == "__main__":
success=shell_utility()
if not success: exit(1)

95
bin/autojump.bash Normal file
View File

@@ -0,0 +1,95 @@
#Copyright Joel Schaerer 2008, 2009
#This file is part of autojump
#autojump 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 of the License, or
#(at your option) any later version.
#
#autojump 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 autojump. If not, see <http://www.gnu.org/licenses/>.
#This shell snippet sets the prompt command and the necessary aliases
_autojump()
{
local cur
cur=${COMP_WORDS[*]:1}
comps=$(autojump --bash --completion $cur)
while read i
do
COMPREPLY=("${COMPREPLY[@]}" "${i}")
done <<EOF
$comps
EOF
}
complete -F _autojump j
_autojump_files()
{
if [[ ${COMP_WORDS[COMP_CWORD]} == *__* ]]; then
local cur
#cur=${COMP_WORDS[*]:1}
cur=${COMP_WORDS[COMP_CWORD]}
comps=$(autojump --bash --completion $cur)
while read i
do
COMPREPLY=("${COMPREPLY[@]}" "${i}")
done <<EOF
$comps
EOF
fi
}
complete -o default -o bashdefault -F _autojump_files cp mv meld diff kdiff3 vim emacs
#determine the data directory according to the XDG Base Directory Specification
if [[ -n ${XDG_DATA_HOME} ]] && [[ ${XDG_DATA_HOME} =~ ${USER} ]]; then
export AUTOJUMP_DATA_DIR="${XDG_DATA_HOME}/autojump"
else
export AUTOJUMP_DATA_DIR=~/.local/share/autojump
fi
if [ ! -e "${AUTOJUMP_DATA_DIR}" ]; then
mkdir -p "${AUTOJUMP_DATA_DIR}"
mv ~/.autojump_py "${AUTOJUMP_DATA_DIR}/autojump_py" 2>>/dev/null #migration
mv ~/.autojump_py.bak "${AUTOJUMP_DATA_DIR}/autojump_py.bak" 2>>/dev/null
mv ~/.autojump_errors "${AUTOJUMP_DATA_DIR}/autojump_errors" 2>>/dev/null
fi
# set paths if necessary for local installations
if [ -d ~/.autojump/ ]; then
export PATH=~/.autojump/bin:"${PATH}"
fi
export AUTOJUMP_HOME=${HOME}
if [ "${AUTOJUMP_KEEP_SYMLINKS}" == "1" ]
then
_PWD_ARGS=""
else
_PWD_ARGS="-P"
fi
AUTOJUMP='{ [[ "$AUTOJUMP_HOME" == "$HOME" ]] && (autojump -a "$(pwd ${_PWD_ARGS})"&)>/dev/null 2>>"${AUTOJUMP_DATA_DIR}/.autojump_errors";} 2>/dev/null'
case $PROMPT_COMMAND in
*autojump*) ;;
*) export PROMPT_COMMAND="$AUTOJUMP ; ${PROMPT_COMMAND:-:}";;
esac
alias jumpstat="autojump --stat"
function j {
new_path="$(autojump $@)"
if [ -d "${new_path}" ]; then
echo -e "\\033[31m${new_path}\\033[0m"
cd "${new_path}"
else
echo "autojump: directory '${@}' not found"
echo "Try \`autojump --help\` for more information."
false
fi
}

29
bin/autojump.sh Normal file
View File

@@ -0,0 +1,29 @@
# Source autojump on BASH or ZSH depending on the shell
#Copyright Joel Schaerer 2008, 2009
#This file is part of autojump
#autojump 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 of the License, or
#(at your option) any later version.
#
#autojump 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 autojump. If not, see <http://www.gnu.org/licenses/>.
if [ "$BASH_VERSION" ] && [ -n "$PS1" ] && echo $SHELLOPTS | grep -v posix >>/dev/null; then
if [ -f ~/.autojump/etc/profile.d/autojump.bash ]; then
source ~/.autojump/etc/profile.d/autojump.bash
elif [ -f /etc/profile.d/autojump.bash ]; then
source /etc/profile.d/autojump.bash
fi
elif [ "$ZSH_VERSION" ] && [ -n "$PS1" ]; then
if [ -f ~/.autojump/etc/profile.d/autojump.zsh ]; then
source ~/.autojump/etc/profile.d/autojump.zsh
elif [ -f /etc/profile.d/autojump.zsh ]; then
source /etc/profile.d/autojump.zsh
fi
fi

66
bin/autojump.zsh Normal file
View File

@@ -0,0 +1,66 @@
#Copyright Joel Schaerer 2008, 2009
#This file is part of autojump
#autojump 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 of the License, or
#(at your option) any later version.
#
#autojump 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 autojump. If not, see <http://www.gnu.org/licenses/>.
# determine the data directory according to the XDG Base Directory Specification
if [[ -n ${XDG_DATA_HOME} ]] && [[ ${XDG_DATA_HOME} =~ ${USER} ]]; then
export AUTOJUMP_DATA_DIR="${XDG_DATA_HOME}/autojump"
else
export AUTOJUMP_DATA_DIR=${HOME}/.local/share/autojump
fi
if [[ ! -e ${AUTOJUMP_DATA_DIR} ]]; then
mkdir -p "${AUTOJUMP_DATA_DIR}"
mv ${HOME}/.autojump_py "${AUTOJUMP_DATA_DIR}/autojump_py" 2>>/dev/null #migration
mv ${HOME}/.autojump_py.bak "${AUTOJUMP_DATA_DIR}/autojump_py.bak" 2>>/dev/null
mv ${HOME}/.autojump_errors "${AUTOJUMP_DATA_DIR}/autojump_errors" 2>>/dev/null
fi
# set paths if necessary for local installations
if [[ -d ${HOME}/.autojump ]]; then
path=(${HOME}/.autojump/bin ${path})
fpath=(${HOME}/.autojump/functions/ ${fpath})
fi
# set fpath if necessary for homebrew installation
if [[ -d "`brew --prefix 2>/dev/null`/share/zsh/functions" ]]; then
fpath=(`brew --prefix`/share/zsh/functions ${fpath})
fi
function autojump_preexec() {
if [[ "${AUTOJUMP_KEEP_SYMLINKS}" == "1" ]]; then
_PWD_ARGS=""
else
_PWD_ARGS="-P"
fi
{ (autojump -a "$(pwd ${_PWD_ARGS})"&)>/dev/null 2>>|${AUTOJUMP_DATA_DIR}/.autojump_errors ; } 2>/dev/null
}
typeset -ga preexec_functions
preexec_functions+=autojump_preexec
alias jumpstat="autojump --stat"
function j {
local new_path="$(autojump $@)"
if [ -d "${new_path}" ]; then
echo -e "\\033[31m${new_path}\\033[0m"
cd "${new_path}"
else
echo "autojump: directory '${@}' not found"
echo "Try \`autojump --help\` for more information."
false
fi
}

BIN
bin/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 594 B

306
bin/jumpapplet Executable file
View File

@@ -0,0 +1,306 @@
#!/usr/bin/env python2
#Copyright Joel Schaerer and Pierre Gueth 2008, 2009
#This file is part of autojump
#autojump 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 of the License, or
#(at your option) any later version.
#
#autojump 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 autojump. If not, see <http://www.gnu.org/licenses/>.
import subprocess
import cPickle
import os.path
import os
import sys
import pygtk
pygtk.require('2.0')
import gtk
from autojump import open_dic,get_dic_file
defaults={}
actions={}
#directory finding helpers, conforming to the XDG Base Directory Specification
def data_dir():
xdg_data_dir = os.environ.get('XDG_DATA_HOME') or os.path.join(os.environ['HOME'], '.local', 'share')
return os.path.join(xdg_data_dir, 'autojump')
def config_dir():
xdg_config_dir = os.environ.get('XDG_CONFIG_HOME') or os.path.join(os.environ['HOME'], '.config')
return os.path.join(xdg_config_dir, 'autojump')
#decorator truff
def action(validator,name=None):
if name is None:
def wrapper(action):
actions[action.__name__]=(action,validator)
else:
def wrapper(action):
actions[name]=(action,validator)
return wrapper
#validator helper
def has_child_dir(dirname,recursion=0):
def wrapper(path):
k=recursion
ii=""
while k>=0:
if os.path.isdir(os.path.join(path,ii,dirname)): return True
k-=1
ii=os.path.join("..",ii)
return False
return wrapper
def has_child_file(filename):
def wrapper(path):
return os.path.isfile(os.path.join(path,filename))
return wrapper
def load_paths(maxpath=10):
path_dict=open_dic(get_dic_file())
path_dict=path_dict.items()
path_dict.sort(key=lambda x: x[1],reverse=True)
return [path for path,score in path_dict[:maxpath]]
def load_settings_file():
filename = os.path.join(config_dir(), 'jumpapplet_py')
#migration from old location
old_filename = os.path.join(os.environ['HOME'], '.jumpapplet_py')
if not os.path.exists(filename) and os.path.exists(old_filename):
os.rename(old_filename, filename)
print "loading settings"
global defaults
dic_file = filename
try:
aj_file=open(dic_file,'r')
defaults=cPickle.load(aj_file)
aj_file.close()
except IOError:
print "no config file"
pass
if not "terminal" in defaults: defaults["terminal"]="gnome-terminal"
if not "navigator" in defaults: defaults["navigator"]="nautilus"
if not "maxpath" in defaults: defaults["maxpath"]=15
if not "invert" in defaults: defaults["invert"]=False
if not "collapse" in defaults: defaults["collapse"]=True
create_actions()
def save_settings_file(filename=None):
directory = config_dir()
if not filename:
filename = os.path.join(directory, 'jumpapplet_py')
if not os.path.exists(directory):
os.makedirs(directory)
print "saving settings"
dic_file= filename
aj_file=open(dic_file,'w')
cPickle.dump(defaults,aj_file)
aj_file.close()
def get_actions(path):
return [(name,action) for name,(action,validator) in actions.items() if validator(path)]
def popup(sender,button,activation):
paths=load_paths(maxpath=defaults["maxpath"])
if defaults["collapse"]:
def collapse_home(path):
return path.replace(os.path.expanduser('~'),"~")
else:
def collapse_home(path):
return path
menu=gtk.Menu()
if defaults["invert"]:
item=gtk.ImageMenuItem(stock_id=gtk.STOCK_QUIT)
item.connect("activate",quit)
menu.append(item)
item=gtk.ImageMenuItem(stock_id=gtk.STOCK_PREFERENCES)
item.connect("activate",settings)
menu.append(item)
menu.append(gtk.SeparatorMenuItem())
for path in reversed(paths):
actions=get_actions(path)
if not actions: continue
item=gtk.MenuItem(collapse_home(path),use_underline=False)
submenu=gtk.Menu()
item.set_submenu(submenu)
for name,action in actions:
subitem=gtk.MenuItem(name)
subitem.connect("activate",action,path)
submenu.append(subitem)
menu.append(item)
else:
for path in paths:
actions=get_actions(path)
if not actions: continue
item=gtk.MenuItem(collapse_home(path),use_underline=False)
submenu=gtk.Menu()
item.set_submenu(submenu)
for name,action in actions:
subitem=gtk.MenuItem(name)
subitem.connect("activate",action,path)
submenu.append(subitem)
menu.append(item)
menu.append(gtk.SeparatorMenuItem())
item=gtk.ImageMenuItem(stock_id=gtk.STOCK_PREFERENCES)
item.connect("activate",settings)
menu.append(item)
item=gtk.ImageMenuItem(stock_id=gtk.STOCK_QUIT)
item.connect("activate",quit)
menu.append(item)
menu.show_all()
menu.popup(None,None,gtk.status_icon_position_menu,button,activation,sender)
def settings(sender):
window=gtk.Dialog("jump applet preferences",None,gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,(gtk.STOCK_SAVE,gtk.RESPONSE_OK,gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL))
window.set_border_width(3)
window.set_resizable(False)
if os.path.isfile("icon.png"): window.set_icon_from_file("icon.png")
elif os.path.isfile("/usr/share/autojump/icon.png"): window.set_icon_from_file("/usr/share/autojump/icon.png")
vbox=gtk.Table(5,2)
vbox.set_row_spacings(3)
window.get_child().add(vbox)
def add_string_setting(name,label,nsettings):
label=gtk.Label(label+' ')
label.set_alignment(1.,.5)
entry=gtk.Entry()
if name in defaults: entry.set_text(defaults[name])
vbox.attach(label,0,1,nsettings,nsettings+1)
vbox.attach(entry,1,2,nsettings,nsettings+1)
return (name,entry)
def add_integer_setting(name,label,nsettings):
label=gtk.Label(label+' ')
label.set_alignment(1.,.5)
entry=gtk.SpinButton()
entry.set_range(5,35)
entry.set_numeric(True)
entry.set_increments(1,5)
entry.set_snap_to_ticks(True)
if name in defaults: entry.set_value(defaults[name])
vbox.attach(label,0,1,nsettings,nsettings+1)
vbox.attach(entry,1,2,nsettings,nsettings+1)
return (name,entry)
def add_bool_setting(name,label,nsettings):
entry=gtk.CheckButton(label=label,use_underline=False)
if name in defaults: entry.set_active(defaults[name])
vbox.attach(entry,0,2,nsettings,nsettings+1)
return (name,entry)
entries=[]
entries.append(add_string_setting("terminal","Terminal program",0))
entries.append(add_string_setting("navigator","Navigator program",1))
entries.append(add_integer_setting("maxpath","Number of directories",2))
entries.append(add_bool_setting("invert","List directories in reverse order",3))
entries.append(add_bool_setting("collapse","Collapse home directory to ~",4))
window.connect("response",save_settings,entries,window)
window.show_all();
def save_settings(sender,response,entries,window):
window.hide_all()
if response!=gtk.RESPONSE_OK: return
global defaults
for name,entry in entries:
try:
defaults[name]=int(entry.get_text())
except (ValueError,AttributeError):
try:
defaults[name]=entry.get_active()
except AttributeError:
defaults[name]=entry.get_text()
save_settings_file()
create_actions()
def init():
load_settings_file()
if os.path.isfile("icon.png"): icon=gtk.status_icon_new_from_file("icon.png")
elif os.path.isfile("/usr/share/autojump/icon.png"): icon=gtk.status_icon_new_from_file("/usr/share/autojump/icon.png")
else: icon=gtk.status_icon_new_from_icon_name("help")
icon.set_visible(True)
icon.connect("popup-menu",popup)
def quit(sender):
gtk.main_quit()
######################################################
#insert other actions here using the action decorator#
######################################################
def create_actions():
global actions
actions={}
@action(has_child_dir(".git",recursion=3))
def gitk(sender,path):
if not os.fork():
os.chdir(path)
subprocess.Popen(['gitk']).wait()
sys.exit()
@action(has_child_file("CMakeCache.txt"),"configure")
def cmake(sender,path):
if not os.fork():
os.chdir(path)
subprocess.Popen(['cmake-gui','.']).wait()
sys.exit()
@action(os.path.isdir)
def terminal(sender,path):
print "launch terminal '%s'" % defaults["terminal"]
if not os.fork():
try:
if defaults["terminal"]=="konsole":
subprocess.Popen([defaults["terminal"],"--workdir=%s"%path]).wait()
else:
os.chdir(path)
subprocess.Popen([defaults["terminal"]]).wait()
except OSError:
pass
sys.exit()
@action(os.path.isdir)
def navigator(sender,path):
print "launch navigator '%s'" % defaults["navigator"]
if not os.fork():
try:
subprocess.Popen([defaults["navigator"],path]).wait()
except OSError:
pass
sys.exit()
if __name__=='__main__':
init()
gtk.main()