1
0
mirror of https://github.com/wting/autojump synced 2024-09-28 14:00:46 +00:00

Merge branch 'master' into change_install_path

Conflicts:
	install.py
This commit is contained in:
Felix Laurie von Massenbach 2014-06-29 22:08:06 +01:00
commit 3c2189fcbf
17 changed files with 215 additions and 212 deletions

1
.gitignore vendored
View File

@ -3,4 +3,5 @@
*~ *~
*.tar.gz *.tar.gz
*.patch *.patch
.tox
tags tags

View File

@ -1,11 +1,17 @@
language: python language: python
python: python: 2.7
- 2.6
- 2.7 env:
- TOX_ENV=py26
- TOX_ENV=py27
- TOX_ENV=py32
- TOX_ENV=py33
- TOX_ENV=py34
- TOX_ENV=flake8
install: install:
- pip install --use-mirrors testify - pip install tox
script: script:
- make test - tox -e $TOX_ENV

View File

@ -14,7 +14,7 @@ docs:
pandoc -s -w markdown docs/header.md docs/install.md docs/body.md -o README.md pandoc -s -w markdown docs/header.md docs/install.md docs/body.md -o README.md
lint: lint:
@flake8 ./ --config=setup.cfg @flake8 ./ --config=tox.ini
release: docs release: docs
# Check for tag existence # Check for tag existence
@ -38,6 +38,6 @@ tar:
git archive --format=tar --prefix autojump_v$(VERSION)/ $(TAGNAME) | gzip > autojump_v$(VERSION).tar.gz git archive --format=tar --prefix autojump_v$(VERSION)/ $(TAGNAME) | gzip > autojump_v$(VERSION).tar.gz
sha1sum autojump_v$(VERSION).tar.gz sha1sum autojump_v$(VERSION).tar.gz
test: test: lint
@find . -type f -iname "*.pyc" -delete @find . -type f -iname "*.pyc" -delete
testify -v tests -x disabled tox

View File

@ -38,7 +38,7 @@ can be used with `autojump` can be used with `j` and vice versa.
jo music jo music
- Opening a file manager to a child directory is also supported: Opening a file manager to a child directory is also supported:
jco images jco images
@ -54,7 +54,7 @@ can be used with `autojump` can be used with `j` and vice versa.
a different entry. In the above example, `j w in` would then change a different entry. In the above example, `j w in` would then change
directory to /home/user/work/inbox. directory to /home/user/work/inbox.
For more options refer to the help: For more options refer to help:
autojump --help autojump --help
@ -64,7 +64,12 @@ INSTALLATION
### REQUIREMENTS ### REQUIREMENTS
- Python v2.6+ - Python v2.6+
- Bash v4.0+, zsh, fish, or clink (Windows) - Supported shells:
- bash v4.0+
- zsh
- fish
- tcsh (experimental)
- clink on Windows (experimental)
### AUTOMATIC ### AUTOMATIC
@ -98,7 +103,7 @@ MacPorts also available:
Windows Windows
------- -------
Windows support is enabled by [clink](https://code.google.com/p/clink/), Windows support is enabled by [clink](https://code.google.com/p/clink/)
which should be installed prior to installing autojump. which should be installed prior to installing autojump.
### MANUAL ### MANUAL
@ -107,7 +112,7 @@ Grab a copy of autojump:
git clone git://github.com/joelthelion/autojump.git git clone git://github.com/joelthelion/autojump.git
Run the installation script and follow the on screen instructions. Run the installation script and follow on screen instructions.
cd autojump cd autojump
./install.py or ./uninstall.py ./install.py or ./uninstall.py

View File

@ -193,9 +193,6 @@ def find_matches(entries, needles, check_entries=True):
def handle_tab_completion(needle, entries): def handle_tab_completion(needle, entries):
if not needle:
sys.exit(0)
tab_needle, tab_index, tab_path = get_tab_entry_info(needle, TAB_SEPARATOR) tab_needle, tab_index, tab_path = get_tab_entry_info(needle, TAB_SEPARATOR)
if tab_path: if tab_path:
@ -285,7 +282,7 @@ def match_consecutive(needles, haystack, ignore_case=False):
regex_no_sep_end = regex_no_sep + '$' regex_no_sep_end = regex_no_sep + '$'
regex_one_sep = regex_no_sep + sep + regex_no_sep regex_one_sep = regex_no_sep + sep + regex_no_sep
# can't use compiled regex because of flags # can't use compiled regex because of flags
regex_needle = regex_one_sep.join(needles).replace('\\', '\\\\') + regex_no_sep_end regex_needle = regex_one_sep.join(needles).replace('\\', '\\\\') + regex_no_sep_end # noqa
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 entry: re.search( found = lambda entry: re.search(
regex_needle, regex_needle,
@ -364,7 +361,7 @@ def main(args): # noqa
save(config, first(add_path(load(config), args.add))) save(config, first(add_path(load(config), args.add)))
elif args.complete: elif args.complete:
handle_tab_completion( handle_tab_completion(
needle=first(sanitize(args.directory)), needle=first(chain(sanitize(args.directory), [''])),
entries=entriefy(load(config))) entries=entriefy(load(config)))
elif args.decrease: elif args.decrease:
data, entry = decrease_path(load(config), get_pwd(), args.decrease) data, entry = decrease_path(load(config), get_pwd(), args.decrease)
@ -382,8 +379,12 @@ def main(args): # noqa
elif args.stat: elif args.stat:
print_stats(load(config), config['data_path']) print_stats(load(config), config['data_path'])
elif not args.directory: elif not args.directory:
# Return best match.
entries = entriefy(load(config))
print_local(first(chain(
imap(attrgetter('path'), find_matches(entries, [''])),
# always return a path to calling shell functions # always return a path to calling shell functions
print_local('.') ['.'])))
else: else:
entries = entriefy(load(config)) entries = entriefy(load(config))
needles = sanitize(args.directory) needles = sanitize(args.directory)

12
bin/autojump.tcsh Normal file
View File

@ -0,0 +1,12 @@
# set user installation paths
if (-d ~/.autojump/bin) then
set path = (~/.autojump/bin path)
endif
# prepend autojump to cwdcmd (run after every change of working directory)
if (`alias cwdcmd` !~ *autojump*) then
alias cwdcmd 'autojump --add $cwd >/dev/null;' `alias cwdcmd`
endif
#default autojump command
alias j 'cd `autojump -- \!:1`'

View File

@ -137,5 +137,5 @@ def save(config, data):
# create backup file if it doesn't exist or is older than BACKUP_THRESHOLD # create backup file if it doesn't exist or is older than BACKUP_THRESHOLD
if not os.path.exists(config['backup_path']) or \ if not os.path.exists(config['backup_path']) or \
(time() - os.path.getmtime(config['backup_path']) > BACKUP_THRESHOLD): #noqa (time() - os.path.getmtime(config['backup_path']) > BACKUP_THRESHOLD): # noqa
shutil.copy(config['data_path'], config['backup_path']) shutil.copy(config['data_path'], config['backup_path'])

View File

@ -30,6 +30,8 @@ def create_dir(path):
def encode_local(string): def encode_local(string):
"""Converts string into user's preferred encoding.""" """Converts string into user's preferred encoding."""
if is_python3():
return string
return string.encode(sys.getfilesystemencoding() or 'utf-8') return string.encode(sys.getfilesystemencoding() or 'utf-8')
@ -170,8 +172,12 @@ def sanitize(directories):
def second(xs): def second(xs):
it = iter(xs) it = iter(xs)
try: try:
if is_python2():
it.next() it.next()
return it.next() return it.next()
elif is_python3():
next(it)
return next(it)
except StopIteration: except StopIteration:
return None return None

View File

@ -1,2 +1,4 @@
flake8>=2.0.0 flake8
testify mock
pytest
tox

View File

@ -25,7 +25,7 @@ j\ foo
.fi .fi
.RE .RE
.IP \[bu] 2 .IP \[bu] 2
Jump To A Child Directory Jump To A Child Directory:
.RS 2 .RS 2
.PP .PP
Sometimes it\[aq]s convenient to jump to a child directory Sometimes it\[aq]s convenient to jump to a child directory
@ -52,7 +52,7 @@ jo\ music
\f[] \f[]
.fi .fi
.PP .PP
Opening a file manager to a child directory is also supported. Opening a file manager to a child directory is also supported:
.IP .IP
.nf .nf
\f[C] \f[C]

View File

@ -21,7 +21,7 @@ be used with `autojump` can be used with `j` and vice versa.
j foo j foo
- Jump To A Child Directory - Jump To A Child Directory:
Sometimes it's convenient to jump to a child directory (sub-directory of Sometimes it's convenient to jump to a child directory (sub-directory of
current directory) rather than typing out the full name. current directory) rather than typing out the full name.
@ -35,7 +35,7 @@ be used with `autojump` can be used with `j` and vice versa.
jo music jo music
Opening a file manager to a child directory is also supported. Opening a file manager to a child directory is also supported:
jco images jco images

View File

@ -3,7 +3,12 @@
### REQUIREMENTS ### REQUIREMENTS
- Python v2.6+ - Python v2.6+
- Bash v4.0+, zsh, fish, or clink (Windows) - Supported shells:
- bash v4.0+
- zsh
- fish
- tcsh (experimental)
- clink (Windows, experimental)
### AUTOMATIC ### AUTOMATIC
@ -47,4 +52,4 @@ Grab a copy of autojump:
Run the installation script and follow on screen instructions. Run the installation script and follow on screen instructions.
cd autojump cd autojump
./install.py or ./uinstall.py ./install.py or ./uninstall.py

View File

@ -10,7 +10,7 @@ import sys
sys.path.append('bin') sys.path.append('bin')
from autojump_argparse import ArgumentParser from autojump_argparse import ArgumentParser
SUPPORTED_SHELLS = ('bash', 'zsh', 'fish') SUPPORTED_SHELLS = ('bash', 'zsh', 'fish', 'tcsh')
def cp(src, dest, dryrun=False): def cp(src, dest, dryrun=False):
@ -157,6 +157,7 @@ def print_post_installation_message(share_dir, bin_dir):
print('\n\t' + source_msg) print('\n\t' + source_msg)
if get_shell() == 'zsh': if get_shell() == 'zsh':
print("\n\tautoload -U compinit && compinit -u") print("\n\tautoload -U compinit && compinit -u")
print("\nPlease restart terminal(s) before running autojump.\n") print("\nPlease restart terminal(s) before running autojump.\n")

View File

@ -1,5 +0,0 @@
[flake8]
filename = *.py,autojump
ignore = E126,E128
max-line-length = 79
max-complexity = 10

View File

@ -1,39 +1,20 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from random import randrange
from shutil import rmtree
from tempfile import gettempdir
from tempfile import mkdtemp
import os import os
import sys import sys
import mock import mock
from testify import TestCase import pytest
from testify import assert_equal
from testify import assert_false
from testify import assert_raises
from testify import assert_true
from testify import class_setup
from testify import class_teardown
from testify import run
from testify import setup
from testify import suite
from testify import teardown
if sys.version_info[0] == 3:
os.getcwdu = os.getcwd
sys.path.append(os.path.join(os.getcwd(), 'bin')) sys.path.append(os.path.join(os.getcwd(), 'bin'))
import autojump_utils import autojump_utils
from autojump_utils import create_dir
from autojump_utils import encode_local from autojump_utils import encode_local
from autojump_utils import first from autojump_utils import first
from autojump_utils import get_pwd
from autojump_utils import get_tab_entry_info from autojump_utils import get_tab_entry_info
from autojump_utils import has_uppercase from autojump_utils import has_uppercase
from autojump_utils import in_bash from autojump_utils import in_bash
from autojump_utils import is_python3
from autojump_utils import last from autojump_utils import last
from autojump_utils import move_file
from autojump_utils import sanitize from autojump_utils import sanitize
from autojump_utils import second from autojump_utils import second
from autojump_utils import surround_quotes from autojump_utils import surround_quotes
@ -41,170 +22,124 @@ from autojump_utils import take
from autojump_utils import unico from autojump_utils import unico
class StringUnitTests(TestCase): if is_python3():
@mock.patch.object(sys, 'getfilesystemencoding', return_value='ascii') os.getcwdu = os.getcwd
def test_encode_local_ascii(self, _): xrange = range
assert_equal(encode_local(u'foo'), b'foo')
@suite('disabled', reason='#246')
def test_encode_local_ascii_fails(self):
with assert_raises(UnicodeDecodeError):
with mock.patch.object(
sys,
'getfilesystemencoding',
return_value='ascii'):
encode_local(u'日本語')
@mock.patch.object(sys, 'getfilesystemencoding', return_value=None)
def test_encode_local_empty(self, _):
assert_equal(encode_local(b'foo'), u'foo')
@mock.patch.object(sys, 'getfilesystemencoding', return_value='utf-8')
def test_encode_local_unicode(self, _):
assert_equal(encode_local(b'foo'), u'foo')
assert_equal(encode_local(u'foo'), u'foo')
def test_has_uppercase(self):
assert_true(has_uppercase('Foo'))
assert_true(has_uppercase('foO'))
assert_false(has_uppercase('foo'))
assert_false(has_uppercase(''))
@mock.patch.object(autojump_utils, 'in_bash', return_value=True)
def test_surround_quotes_in_bash(self, _):
assert_equal(surround_quotes('foo'), '"foo"')
@mock.patch.object(autojump_utils, 'in_bash', return_value=False)
def test_dont_surround_quotes_not_in_bash(self, _):
assert_equal(surround_quotes('foo'), 'foo')
def test_sanitize(self):
assert_equal(sanitize([]), [])
assert_equal(sanitize([r'/foo/bar/', r'/']), [u'/foo/bar', u'/'])
def test_unico(self):
assert_equal(unico(b'blah'), u'blah')
assert_equal(unico(b'日本語'), u'日本語')
assert_equal(unico(u'でもおれは中国人だ。'), u'でもおれは中国人だ。')
class IterationUnitTests(TestCase): def u(string):
def test_first(self): """
assert_equal(first(xrange(5)), 0) This is a unicode() wrapper since u'string' is a Python3 compiler error.
assert_equal(first([]), None) """
if is_python3():
def test_second(self): return string
assert_equal(second(xrange(5)), 1) return unicode(string, encoding='utf-8', errors='strict')
assert_equal(second([]), None)
def test_last(self):
assert_equal(last(xrange(4)), 3)
assert_equal(last([]), None)
def test_take(self):
assert_equal(list(take(1, xrange(3))), [0])
assert_equal(list(take(2, xrange(3))), [0, 1])
assert_equal(list(take(4, xrange(3))), [0, 1, 2])
assert_equal(list(take(10, [])), [])
class EnvironmentalVariableIntegrationTests(TestCase): # strings
@setup @pytest.mark.skipif(is_python3(), reason="Unicode sucks.")
def create_tmp_dir(self): @mock.patch.object(sys, 'getfilesystemencoding', return_value='ascii')
self.tmp_dir = mkdtemp() def test_encode_local_ascii(_):
assert encode_local(u('foo')) == b'foo'
@teardown
def delete_tmp_dir(self):
try:
rmtree(self.tmp_dir)
except OSError:
pass
def test_in_bash(self): @pytest.mark.skipif(is_python3(), reason="Unicode sucks.")
os.environ['SHELL'] = '/bin/bash' @pytest.mark.xfail(reason="disabled due to pytest bug: https://bitbucket.org/hpk42/pytest/issue/534/pytest-fails-to-catch-unicodedecodeerrors") # noqa
assert_true(in_bash()) @mock.patch.object(sys, 'getfilesystemencoding', return_value='ascii')
def test_encode_local_ascii_fails(_):
with pytest.raises(UnicodeDecodeError):
encode_local(u('日本語'))
@pytest.mark.skipif(is_python3(), reason="Unicode sucks.")
@mock.patch.object(sys, 'getfilesystemencoding', return_value=None)
def test_encode_local_empty(_):
assert encode_local(b'foo') == u('foo')
@pytest.mark.skipif(is_python3(), reason="Unicode sucks.")
@mock.patch.object(sys, 'getfilesystemencoding', return_value='utf-8')
def test_encode_local_unicode(_):
assert encode_local(b'foo') == u('foo')
assert encode_local(u('foo')) == u('foo')
def test_has_uppercase():
assert has_uppercase('Foo')
assert has_uppercase('foO')
assert not has_uppercase('foo')
assert not has_uppercase('')
@mock.patch.object(autojump_utils, 'in_bash', return_value=True)
def test_surround_quotes_in_bash(_):
assert surround_quotes('foo') == '"foo"'
@mock.patch.object(autojump_utils, 'in_bash', return_value=False)
def test_dont_surround_quotes_not_in_bash(_):
assert surround_quotes('foo') == 'foo'
def test_sanitize():
assert sanitize([]) == []
assert sanitize([r'/foo/bar/', r'/']) == [u('/foo/bar'), u('/')]
@pytest.mark.skipif(is_python3(), reason="Unicode sucks.")
def test_unico():
assert unico(str('blah')) == u('blah')
assert unico(str('日本語')) == u('日本語')
assert unico(u('でもおれは中国人だ。')) == u('でもおれは中国人だ。')
# iteration
def test_first():
assert first(xrange(5)) == 0
assert first([]) is None
def test_second():
assert second(xrange(5)) == 1
assert second([]) is None
def test_last():
assert last(xrange(4)) == 3
assert last([]) is None
def test_take():
assert list(take(1, xrange(3))) == [0]
assert list(take(2, xrange(3))) == [0, 1]
assert list(take(4, xrange(3))) == [0, 1, 2]
assert list(take(10, [])) == []
# environment variables
def test_in_bash():
for path in ['/bin/bash', '/usr/bin/bash']:
os.environ['SHELL'] = path
assert in_bash()
for path in ['/bin/zsh', '/usr/bin/zsh']:
os.environ['SHELL'] = '/usr/bin/zsh' os.environ['SHELL'] = '/usr/bin/zsh'
assert_false(in_bash()) assert not in_bash()
def test_good_get_pwd(self):
os.chdir(self.tmp_dir)
assert_equal(get_pwd(), self.tmp_dir)
def test_bad_get_pwd(self):
os.chdir(self.tmp_dir)
rmtree(self.tmp_dir)
assert_raises(OSError, get_pwd)
class FileSystemIntegrationTests(TestCase): # helper functions
@class_setup def test_get_needle():
def init(self): assert get_tab_entry_info('foo__', '__') == ('foo', None, None)
self.tmp_dir = os.path.join(gettempdir(), 'autojump')
os.makedirs(self.tmp_dir)
@class_teardown
def cleanup(self):
try:
rmtree(self.tmp_dir)
except OSError:
pass
def get_random_path(self):
path = gettempdir()
while os.path.exists(path):
random_string = '%30x' % randrange(16 ** 30)
path = os.path.join(self.tmp_dir, random_string)
return path
def get_random_file(self):
path = self.get_random_path()
with open(path, 'w+') as f:
f.write('filler\n')
return path
def test_create_dir(self):
path = self.get_random_path()
create_dir(path)
assert_true(os.path.exists(path))
# should not raise OSError if directory already exists
create_dir(path)
assert_true(os.path.exists(path))
def test_move_file(self):
src = self.get_random_file()
dst = self.get_random_path()
assert_true(os.path.exists(src))
assert_false(os.path.exists(dst))
move_file(src, dst)
assert_false(os.path.exists(src))
assert_true(os.path.exists(dst))
class HelperFunctionsUnitTests(TestCase): def test_get_index():
def test_get_needle(self): assert get_tab_entry_info('foo__2', '__') == ('foo', 2, None)
assert_equal(
get_tab_entry_info('foo__', '__'),
('foo', None, None))
def test_get_index(self):
assert_equal(
get_tab_entry_info('foo__2', '__'),
('foo', 2, None))
def test_get_path(self):
assert_equal(
get_tab_entry_info('foo__3__/foo/bar', '__'),
('foo', 3, '/foo/bar'))
def test_get_none(self):
assert_equal(
get_tab_entry_info('gibberish content', '__'),
(None, None, None))
if __name__ == "__main__": def test_get_path():
run() assert get_tab_entry_info('foo__3__/foo/bar', '__') \
== ('foo', 3, '/foo/bar')
def test_get_none():
assert get_tab_entry_info('gibberish content', '__') == (None, None, None)

32
tox.ini Normal file
View File

@ -0,0 +1,32 @@
[tox]
envlist =
py26,
py27,
py32,
py33,
py34
# ignore missing setup.py
skipsdist = True
[testenv]
deps = -rdev-requirements.txt
commands = py.test -rsxX -q
[testenv:flake8]
deps = flake8
commands = flake8 .
[flake8]
filename =
*.py,
autojump
ignore =
E126,
E128
max-line-length = 79
max-complexity = 10
show-pep8 = True
[pytest]
addopts = -rsxX -q
norecursedirs = .git .tox docs

View File

@ -78,6 +78,7 @@ def remove_custom_installation(args, dryrun=False):
rm(os.path.join(etc_dir, 'autojump.sh'), dryrun) rm(os.path.join(etc_dir, 'autojump.sh'), dryrun)
rm(os.path.join(etc_dir, 'autojump.bash'), dryrun) rm(os.path.join(etc_dir, 'autojump.bash'), dryrun)
rm(os.path.join(etc_dir, 'autojump.fish'), dryrun) rm(os.path.join(etc_dir, 'autojump.fish'), dryrun)
rm(os.path.join(etc_dir, 'autojump.tcsh'), dryrun)
rm(os.path.join(etc_dir, 'autojump.zsh'), dryrun) rm(os.path.join(etc_dir, 'autojump.zsh'), dryrun)
rm(os.path.join(zshshare_dir, '_j'), dryrun) rm(os.path.join(zshshare_dir, '_j'), dryrun)
rmdir(icon_dir, dryrun) rmdir(icon_dir, dryrun)
@ -114,6 +115,7 @@ def remove_system_installation(dryrun=False):
rm(os.path.join(etc_dir, 'autojump.sh'), dryrun) rm(os.path.join(etc_dir, 'autojump.sh'), dryrun)
rm(os.path.join(etc_dir, 'autojump.bash'), dryrun) rm(os.path.join(etc_dir, 'autojump.bash'), dryrun)
rm(os.path.join(etc_dir, 'autojump.fish'), dryrun) rm(os.path.join(etc_dir, 'autojump.fish'), dryrun)
rm(os.path.join(etc_dir, 'autojump.tcsh'), dryrun)
rm(os.path.join(etc_dir, 'autojump.zsh'), dryrun) rm(os.path.join(etc_dir, 'autojump.zsh'), dryrun)
rm(os.path.join(zshshare_dir, '_j'), dryrun) rm(os.path.join(zshshare_dir, '_j'), dryrun)
rmdir(icon_dir, dryrun) rmdir(icon_dir, dryrun)