mirror of
https://github.com/wting/autojump
synced 2024-10-27 20:34:07 +00:00
Compare commits
No commits in common. "master" and "release-v21.7.1" have entirely different histories.
master
...
release-v2
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -1,2 +0,0 @@
|
|||||||
# Ensure batch files are crlf
|
|
||||||
*.bat text eol=crlf
|
|
8
.gitignore
vendored
8
.gitignore
vendored
@ -1,10 +1,6 @@
|
|||||||
.cache
|
tags
|
||||||
.coverage
|
bin/autojump.py
|
||||||
*.pyc
|
*.pyc
|
||||||
__pycache__
|
|
||||||
*~
|
*~
|
||||||
*.tar.gz
|
*.tar.gz
|
||||||
*.patch
|
*.patch
|
||||||
.pytest_cache
|
|
||||||
.tox
|
|
||||||
tags
|
|
||||||
|
@ -1,51 +0,0 @@
|
|||||||
repos:
|
|
||||||
- repo: git@github.com:pre-commit/pre-commit-hooks.git
|
|
||||||
rev: v1.4.0
|
|
||||||
hooks:
|
|
||||||
- id: autopep8-wrapper
|
|
||||||
language_version: python2
|
|
||||||
args:
|
|
||||||
- --in-place
|
|
||||||
- --aggressive
|
|
||||||
- --aggressive
|
|
||||||
- --ignore=E731
|
|
||||||
- --max-line-length=131
|
|
||||||
- id: check-added-large-files
|
|
||||||
language_version: python2
|
|
||||||
- id: check-ast
|
|
||||||
language_version: python2
|
|
||||||
- id: check-case-conflict
|
|
||||||
language_version: python2
|
|
||||||
- id: check-docstring-first
|
|
||||||
language_version: python2
|
|
||||||
- id: debug-statements
|
|
||||||
language_version: python2
|
|
||||||
- id: double-quote-string-fixer
|
|
||||||
language_version: python2
|
|
||||||
- id: end-of-file-fixer
|
|
||||||
language_version: python2
|
|
||||||
exclude_types: [batch, lua]
|
|
||||||
- id: fix-encoding-pragma
|
|
||||||
language_version: python2
|
|
||||||
- id: flake8
|
|
||||||
language_version: python2
|
|
||||||
args:
|
|
||||||
- --max-complexity=10
|
|
||||||
- --max-line-length=131
|
|
||||||
- --ignore=E402,E731
|
|
||||||
- --exclude=bin/autojump_argparse.py
|
|
||||||
- id: name-tests-test
|
|
||||||
language_version: python2
|
|
||||||
- id: requirements-txt-fixer
|
|
||||||
language_version: python2
|
|
||||||
- id: trailing-whitespace
|
|
||||||
language_version: python2
|
|
||||||
- repo: git@github.com:asottile/reorder_python_imports.git
|
|
||||||
rev: v1.1.1
|
|
||||||
hooks:
|
|
||||||
- id: reorder-python-imports
|
|
||||||
language_version: python2
|
|
||||||
- repo: git@github.com:asottile/add-trailing-comma
|
|
||||||
rev: v0.7.0
|
|
||||||
hooks:
|
|
||||||
- id: add-trailing-comma
|
|
17
.travis.yml
17
.travis.yml
@ -1,17 +0,0 @@
|
|||||||
language: python
|
|
||||||
|
|
||||||
python: 2.7
|
|
||||||
|
|
||||||
env:
|
|
||||||
- TOX_ENV=py26
|
|
||||||
- TOX_ENV=py27
|
|
||||||
- TOX_ENV=py32
|
|
||||||
- TOX_ENV=py33
|
|
||||||
- TOX_ENV=py34
|
|
||||||
- TOX_ENV=flake8
|
|
||||||
|
|
||||||
install:
|
|
||||||
- pip install tox
|
|
||||||
|
|
||||||
script:
|
|
||||||
- tox -e $TOX_ENV
|
|
194
CHANGES.md
194
CHANGES.md
@ -1,194 +0,0 @@
|
|||||||
## Summary of release changes, see commit history for more details:
|
|
||||||
## https://github.com/wting/autojump/commits/master/
|
|
||||||
|
|
||||||
### Release v22.4.0:
|
|
||||||
- minor zsh performance improvement
|
|
||||||
|
|
||||||
### Release v22.3.0:
|
|
||||||
- use colors only if stdout is a terminal
|
|
||||||
- updated RedHat docs
|
|
||||||
- misc bug fixes for fish and Clink versions
|
|
||||||
|
|
||||||
### Release v22.2.2:
|
|
||||||
|
|
||||||
#### Backwards Incompatible
|
|
||||||
|
|
||||||
- install.sh -> install.py
|
|
||||||
- `--auto` option removed
|
|
||||||
- `--local` option removed, defaults to local user install
|
|
||||||
- `--global` option renamed to `--system`
|
|
||||||
- install.py modifies autojump.sh accordingly for custom installations
|
|
||||||
- it is recommended that maintainers use install.py with `--destdir` and
|
|
||||||
`--prefix` accordingly. Two stage installations requires manually updating
|
|
||||||
autojump.sh.
|
|
||||||
- uninstall.sh -> uninstall.py
|
|
||||||
- automatically removes user and system installations
|
|
||||||
- now removes custom installations cleanly when passed appropriate
|
|
||||||
`--destdir` and/or `--prefix` options.
|
|
||||||
- new `--userdata` option to remove autojump database
|
|
||||||
- all user environmental options removed:
|
|
||||||
- AUTOJUMP_DATA_DIR
|
|
||||||
- AUTOJUMP_IGNORE_CASE
|
|
||||||
- AUTOJUMP_KEEP_SYMLINKS
|
|
||||||
- misc bug fixes
|
|
||||||
|
|
||||||
#### Features and Bug Fixes
|
|
||||||
|
|
||||||
- fish shell support added
|
|
||||||
- defaults to smartcasing
|
|
||||||
- If any uppercase characters are detected, then search is case sensitive.
|
|
||||||
Otherwise searches default to case insensitive.
|
|
||||||
- defaults to symlinks
|
|
||||||
- symlinks are not resolved to real path and thus results in duplicate
|
|
||||||
database entries but ensuring that short paths will be used
|
|
||||||
- autojump now uses ~/Library/autojump for storing data on OS X instead of
|
|
||||||
incorrectly using Linux's $XDG_DATA_HOME. Existing data should automatically
|
|
||||||
be migrated to the new location.
|
|
||||||
- Past behavior jumped to the highest weight database entry when not passed any
|
|
||||||
arguments. The new behavior is to stay in the current directory.
|
|
||||||
|
|
||||||
|
|
||||||
### Release v21.6.8:
|
|
||||||
|
|
||||||
- fix --increase and --decrease options
|
|
||||||
- heavy refactoring
|
|
||||||
- remove unused unit tests
|
|
||||||
|
|
||||||
### Release v21.5.8:
|
|
||||||
|
|
||||||
- fix security bug: http://www.openwall.com/lists/oss-security/2013/04/25/14
|
|
||||||
- minor documentation updates, optimization performances, bug fixes
|
|
||||||
|
|
||||||
### Release v21.5.1:
|
|
||||||
|
|
||||||
- add options to manually increase or decrease weight of the current directory
|
|
||||||
with --increase or --decrease
|
|
||||||
- add `_j` back, necessary for zsh tab completion
|
|
||||||
|
|
||||||
### Release v21.4.2:
|
|
||||||
|
|
||||||
- add options to open file explorer windows with `jo`, `jco` which maps to jump
|
|
||||||
open, jump child open.
|
|
||||||
- remove `_j`
|
|
||||||
|
|
||||||
### Release v21.3.0:
|
|
||||||
|
|
||||||
- `jumpapplet` removed.
|
|
||||||
- performance improvements when using network mounts (e.g. sshfs)
|
|
||||||
|
|
||||||
### Release v21.2.0:
|
|
||||||
|
|
||||||
- Add `jc` command (jump child). Jumps to a subdirectory of the current working
|
|
||||||
directory.
|
|
||||||
|
|
||||||
### Release v21.1.0:
|
|
||||||
|
|
||||||
- install.sh is rewritten to add support for --path and --destdir options,
|
|
||||||
making it easier for package maintainers to install autojump specifically into
|
|
||||||
certain locations. Thanks to jjk-jacky for his contributions.
|
|
||||||
|
|
||||||
### Release v21.0.0:
|
|
||||||
|
|
||||||
- Switch to semantic versioning (http://semver.org/): major.minor.micro
|
|
||||||
- Migration code for v17 or older users has been removed.
|
|
||||||
|
|
||||||
During testing, it was apparent that the migration code wasn't working to
|
|
||||||
begin with. The major distros (Debian, RedHat) have already moved to v18+
|
|
||||||
for LTS. Rolling release distros and Homebrew / Macports are regularly kept
|
|
||||||
up to date.
|
|
||||||
|
|
||||||
Users upgrading from v17 or older will start with a new database.
|
|
||||||
|
|
||||||
- Approximate matching introduced. Matching priority is now:
|
|
||||||
|
|
||||||
1. exact match
|
|
||||||
2. case insensitive match
|
|
||||||
3. approximate match
|
|
||||||
|
|
||||||
- The `j` function now accepts autojump arguments (e.g. --help, --stat).
|
|
||||||
|
|
||||||
As a result, the `jumpstat` alias is now removed. The preferred method is `j
|
|
||||||
--stat` or `j -s`. Consequently, autojump cannot jump to directories
|
|
||||||
beginning with a hyphen '-'.
|
|
||||||
|
|
||||||
- Always use case insensitive search with AUTOJUMP_IGNORE_CASE=1
|
|
||||||
|
|
||||||
As mentioned earlier, normal priority is to prefer exact match and then
|
|
||||||
check for case insensitive match. For users who prefer case insensitivity
|
|
||||||
can now modify the program behavior.
|
|
||||||
|
|
||||||
- Prevent database decay with AUTOJUMP_KEEP_ALL_ENTRIES=1
|
|
||||||
|
|
||||||
The database is regularly trimmed for performance reasons. However users can
|
|
||||||
prevent database maintenance with the above environmental variable.
|
|
||||||
|
|
||||||
- ZSH tab completion fixed.
|
|
||||||
|
|
||||||
ZSH behavior now matches Bash behavior. However it requires the `compinit`
|
|
||||||
module to be loaded. Add the following line to ~/.zshrc:
|
|
||||||
|
|
||||||
autoload -U compinit; compinit
|
|
||||||
|
|
||||||
To use type:
|
|
||||||
|
|
||||||
j<space><tab><tab>
|
|
||||||
|
|
||||||
A menu showing the top database entries will be displayed. Type in any
|
|
||||||
number followed by <tab> to complete the entry.
|
|
||||||
|
|
||||||
- Database entry weight growth changed form linear to logarithmic scale.
|
|
||||||
|
|
||||||
A combination of low total weight ceiling and linear growth resulted in a
|
|
||||||
few, commonly used directories to be responsible for 50%+ of the total
|
|
||||||
database weight. This caused unnecessary trimming of long tail entries.
|
|
||||||
|
|
||||||
Switching to logarithmic growth combined with regular decay meant that
|
|
||||||
commonly used directories still climbed database ranking appropriately with
|
|
||||||
a more even weight distribution.
|
|
||||||
|
|
||||||
- Vendorize argparse so now Python v2.6+ is supported (from v2.7).
|
|
||||||
- Unit testing suite added.
|
|
||||||
- Miscellaneous refactoring, bug fixes, documentation updates.
|
|
||||||
|
|
||||||
### Release v20.0.0:
|
|
||||||
|
|
||||||
- Python versions supported is now v2.7+ and v3.2+ due to rewrite using
|
|
||||||
argparse.
|
|
||||||
|
|
||||||
- Man page and --help has been overhauled to provide better documentation and
|
|
||||||
usage scenarios.
|
|
||||||
|
|
||||||
- Installation scripts now act dependent on current environmental settings.
|
|
||||||
|
|
||||||
If run as root, will do a global install. Installation script also detects
|
|
||||||
which version to install (bash or zsh) dependent on $SHELL. Both of these
|
|
||||||
behaviors can be overrode using --local/--global or --bash/--zsh arguments.
|
|
||||||
|
|
||||||
- Uninstallation script added, will remove both global and local installations
|
|
||||||
but ignores database.
|
|
||||||
|
|
||||||
- Allow symlink database entries with AUTOJUMP_KEEP_SYMLINKS=1
|
|
||||||
|
|
||||||
Normally symlinks are resolved to full path to prevent duplicate database
|
|
||||||
entries. However users who prefer symlink paths can modify behavior with the
|
|
||||||
above environmental variable.
|
|
||||||
|
|
||||||
- This ChangeLog added to better help package maintainers keep track of changes
|
|
||||||
between releases.
|
|
||||||
|
|
||||||
- Miscellaneous bug fixes.
|
|
||||||
|
|
||||||
### Release v19.0.0:
|
|
||||||
|
|
||||||
- prototype `cp` and `mv` directory tab completion
|
|
||||||
- Debian post-installation instructions
|
|
||||||
- minor Mac OS X fixes
|
|
||||||
|
|
||||||
### Release v18.0.0:
|
|
||||||
|
|
||||||
- add automated version numbering
|
|
||||||
- performance tweaks to reduce filesystem checks
|
|
||||||
- add local installation option
|
|
||||||
- unicode fixes
|
|
||||||
- ugly fixes for Python 3
|
|
||||||
- migrate to new database format
|
|
162
ChangeLog
Normal file
162
ChangeLog
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
|
||||||
|
# Summary of release changes, see commit history for more details:
|
||||||
|
# https://github.com/joelthelion/autojump/commits/master/
|
||||||
|
|
||||||
|
* Release v21.6.8:
|
||||||
|
|
||||||
|
- fix --increase and --decrease options
|
||||||
|
- heavy refactoring
|
||||||
|
- remove unused unit tests
|
||||||
|
|
||||||
|
* Release v21.5.8:
|
||||||
|
|
||||||
|
- fix security bug:
|
||||||
|
http://www.openwall.com/lists/oss-security/2013/04/25/14
|
||||||
|
- minor documentation updates, optimization performances, bug fixes
|
||||||
|
|
||||||
|
* Release v21.5.1:
|
||||||
|
|
||||||
|
- add options to manually increase or decrease weight of the current
|
||||||
|
directory with --increase or --decrease
|
||||||
|
- add `_j` back, necessary for zsh tab completion
|
||||||
|
|
||||||
|
* Release v21.4.2:
|
||||||
|
|
||||||
|
- add options to open file explorer windows with `jo`, `jco` which
|
||||||
|
maps to jump open, jump child open.
|
||||||
|
- remove `_j`
|
||||||
|
|
||||||
|
* Release v21.3.0:
|
||||||
|
|
||||||
|
- `jumpapplet` removed.
|
||||||
|
- performance improvements when using network mounts (e.g. sshfs)
|
||||||
|
|
||||||
|
* Release v21.2.0:
|
||||||
|
|
||||||
|
- Add `jc` command (jump child). Jumps to a subdirectory of the current
|
||||||
|
working directory.
|
||||||
|
|
||||||
|
* Release v21.1.0:
|
||||||
|
|
||||||
|
- install.sh is rewritten to add support for --path and --destdir options,
|
||||||
|
making it easier for package maintainers to install autojump specifically into
|
||||||
|
certain locations. Thanks to jjk-jacky for his contributions.
|
||||||
|
|
||||||
|
* Release v21.0.0:
|
||||||
|
|
||||||
|
- New mailing list for developer discussion and announcements:
|
||||||
|
|
||||||
|
https://groups.google.com/forum/?fromgroups%5C#!forum/autojump
|
||||||
|
|
||||||
|
- Switch to semantic versioning (http://semver.org/): major.minor.micro
|
||||||
|
|
||||||
|
major = breaks backwards compatibility
|
||||||
|
minor = new features with backwards compatibility
|
||||||
|
micro = bug fixes with backwards compatibility
|
||||||
|
|
||||||
|
- Migration code for v17 or older users has been removed.
|
||||||
|
|
||||||
|
During testing, it was apparent that the migration code wasn't working to
|
||||||
|
begin with. The major distros (Debian, RedHat) have already moved to v18+ for
|
||||||
|
LTS. Rolling release distros and Homebrew / Macports are regularly kept up to
|
||||||
|
date.
|
||||||
|
|
||||||
|
Users upgrading from v17 or older will start with a new database.
|
||||||
|
|
||||||
|
- Approximate matching introduced.
|
||||||
|
|
||||||
|
Matching priority is now:
|
||||||
|
1. exact match
|
||||||
|
2. case insensitive match
|
||||||
|
3. approximate match
|
||||||
|
|
||||||
|
- The `j` function now accepts autojump arguments (e.g. --help, --stat).
|
||||||
|
|
||||||
|
As a result, the `jumpstat` alias is now removed. The preferred method is `j
|
||||||
|
--stat` or `j -s`. Consequently, autojump cannot jump to directories
|
||||||
|
beginning with a hyphen '-'.
|
||||||
|
|
||||||
|
- Always use case insensitive search with AUTOJUMP_IGNORE_CASE=1
|
||||||
|
|
||||||
|
As mentioned earlier, normal priority is to prefer exact match and then check
|
||||||
|
for case insensitive match. For users who prefer case insensitivity can now
|
||||||
|
modify the program behavior.
|
||||||
|
|
||||||
|
- Prevent database decay with AUTOJUMP_KEEP_ALL_ENTRIES=1
|
||||||
|
|
||||||
|
The database is regularly trimmed for performance reasons. However users can
|
||||||
|
prevent database maintenance with the above environmental variable.
|
||||||
|
|
||||||
|
- ZSH tab completion fixed.
|
||||||
|
|
||||||
|
ZSH behavior now matches Bash behavior. However it requires the `compinit`
|
||||||
|
module to be loaded. Add the following line to ~/.zshrc:
|
||||||
|
|
||||||
|
autoload -U compinit; compinit
|
||||||
|
|
||||||
|
To use type:
|
||||||
|
|
||||||
|
j<space><tab><tab>
|
||||||
|
|
||||||
|
A menu showing the top database entries will be displayed. Type in any number
|
||||||
|
followed by <tab> to complete the entry.
|
||||||
|
|
||||||
|
- Database entry weight growth changed form linear to logarithmic scale.
|
||||||
|
|
||||||
|
A combination of low total weight ceiling and linear growth resulted in
|
||||||
|
a few, commonly used directories to be responsible for 50%+ of the total
|
||||||
|
database weight. This caused unnecessary trimming of long tail entries.
|
||||||
|
|
||||||
|
Switching to logarithmic growth combined with regular decay meant that
|
||||||
|
commonly used directories still climbed database ranking appropriately with a
|
||||||
|
more even weight distribution.
|
||||||
|
|
||||||
|
- Vendorize argparse so now Python v2.6+ is supported (from v2.7).
|
||||||
|
|
||||||
|
- Unit testing suite added.
|
||||||
|
|
||||||
|
- Miscellaneous refactoring, bug fixes, documentation updates.
|
||||||
|
|
||||||
|
* Release v20.0.0:
|
||||||
|
|
||||||
|
- Python versions supported is now v2.7+ and v3.2+ due to rewrite using
|
||||||
|
argparse.
|
||||||
|
|
||||||
|
- Man page and --help has been overhauled to provide better documentation and
|
||||||
|
usage scenarios.
|
||||||
|
|
||||||
|
- Installation scripts now act dependent on current environmental settings.
|
||||||
|
|
||||||
|
If run as root, will do a global install. Installation script also detects
|
||||||
|
which version to install (bash or zsh) dependent on $SHELL. Both of these
|
||||||
|
behaviors can be overrode using --local/--global or --bash/--zsh arguments.
|
||||||
|
|
||||||
|
- Uninstallation script added, will remove both global and local installations
|
||||||
|
but ignores database.
|
||||||
|
|
||||||
|
- Allow symlink database entries with AUTOJUMP_KEEP_SYMLINKS=1
|
||||||
|
|
||||||
|
Normally symlinks are resolved to full path to prevent duplicate database
|
||||||
|
entries. However users who prefer symlink paths can modify behavior with the
|
||||||
|
above environmental variable.
|
||||||
|
|
||||||
|
- This ChangeLog added to better help package maintainers keep track of
|
||||||
|
changes
|
||||||
|
between releases.
|
||||||
|
|
||||||
|
- Miscellaneous bug fixes.
|
||||||
|
|
||||||
|
* Release v19.0.0:
|
||||||
|
|
||||||
|
- prototype `cp` and `mv` directory tab completion
|
||||||
|
- Debian post-installation instructions
|
||||||
|
- minor Mac OS X fixes
|
||||||
|
|
||||||
|
* Release v18.0.0:
|
||||||
|
|
||||||
|
- add automated version numbering
|
||||||
|
- performance tweaks to reduce filesystem checks
|
||||||
|
- add local installation option
|
||||||
|
- unicode fixes
|
||||||
|
- ugly fixes for Python 3
|
||||||
|
- migrate to new database format
|
42
Makefile
42
Makefile
@ -1,31 +1,18 @@
|
|||||||
VERSION = $(shell grep -oE "[0-9]+\.[0-9]+\.[0-9]+" bin/autojump)
|
VERSION = $(shell grep -oE "[0-9]+\.[0-9]+\.[0-9]+" bin/autojump)
|
||||||
TAGNAME = release-v$(VERSION)
|
TAGNAME = release-v$(VERSION)
|
||||||
|
|
||||||
.PHONY: install
|
.PHONY: docs install uninstall tar
|
||||||
|
|
||||||
install:
|
install:
|
||||||
./install.py
|
install.sh
|
||||||
|
|
||||||
.PHONY: uninstall
|
|
||||||
uninstall:
|
uninstall:
|
||||||
./uninstall.py
|
uninstall.sh
|
||||||
|
|
||||||
.PHONY: docs
|
|
||||||
docs:
|
docs:
|
||||||
@echo "% autojump(1) ${TAGNAME}" >docs/manpage_header.md
|
|
||||||
@echo "%" >>docs/manpage_header.md
|
|
||||||
@echo "% $(shell \date +%Y-%m-%d)" >>docs/manpage_header.md
|
|
||||||
pandoc -s -w man docs/manpage_header.md docs/header.md docs/body.md -o docs/autojump.1
|
pandoc -s -w man docs/manpage_header.md docs/header.md docs/body.md -o docs/autojump.1
|
||||||
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/development.md docs/body.md -o README.md
|
||||||
|
|
||||||
.PHONY: lint
|
|
||||||
lint: pre-commit
|
|
||||||
@tox -e pre-commit -- run --all-files
|
|
||||||
|
|
||||||
.PHONY: pre-commit
|
|
||||||
pre-commit:
|
|
||||||
@tox -e pre-commit -- install -f --install-hooks
|
|
||||||
|
|
||||||
.PHONY: release
|
|
||||||
release: docs
|
release: docs
|
||||||
# Check for tag existence
|
# Check for tag existence
|
||||||
# git describe release-$(VERSION) 2>&1 >/dev/null || exit 1
|
# git describe release-$(VERSION) 2>&1 >/dev/null || exit 1
|
||||||
@ -43,26 +30,7 @@ release: docs
|
|||||||
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
|
||||||
|
|
||||||
.PHONY: tar
|
|
||||||
tar:
|
tar:
|
||||||
# Create tagged archive
|
# Create tagged archive
|
||||||
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
|
||||||
|
|
||||||
.PHONY: test
|
|
||||||
test: pre-commit
|
|
||||||
@tox
|
|
||||||
|
|
||||||
.PHONY: test-xfail
|
|
||||||
test-xfail: pre-commit
|
|
||||||
@tox -- --runxfail
|
|
||||||
|
|
||||||
.PHONY: test-fast
|
|
||||||
test-fast: pre-commit
|
|
||||||
@tox -e py27
|
|
||||||
|
|
||||||
.PHONY: clean
|
|
||||||
clean:
|
|
||||||
@find . -type f -iname '*.py[co]' -delete
|
|
||||||
@find . -type d -iname '__pycache__' -delete
|
|
||||||
@rm -fr .tox
|
|
||||||
|
318
README.md
318
README.md
@ -3,173 +3,271 @@ NAME
|
|||||||
|
|
||||||
autojump - a faster way to navigate your filesystem
|
autojump - a faster way to navigate your filesystem
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
--------
|
||||||
|
|
||||||
|
Jump to a previously visited directory that contains 'foo':
|
||||||
|
|
||||||
|
j foo
|
||||||
|
|
||||||
|
Jump to a previously visited subdirectory of the current directory:
|
||||||
|
|
||||||
|
jc bar
|
||||||
|
|
||||||
|
Show database entries and their respective key weights:
|
||||||
|
|
||||||
|
j --stat
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
autojump is a faster way to navigate your filesystem. It works by
|
autojump is a faster way to navigate your filesystem. It works by
|
||||||
maintaining a database of the directories you use the most from the
|
maintaining a database of the directories you use the most from the
|
||||||
command line.
|
command line. Directories must be visited first before they can be
|
||||||
|
jumped to.
|
||||||
*Directories must be visited first before they can be jumped to.*
|
|
||||||
|
|
||||||
USAGE
|
|
||||||
-----
|
|
||||||
|
|
||||||
`j` is a convenience wrapper function around `autojump`. Any option that
|
|
||||||
can be used with `autojump` can be used with `j` and vice versa.
|
|
||||||
|
|
||||||
- Jump To A Directory That Contains `foo`:
|
|
||||||
|
|
||||||
j foo
|
|
||||||
|
|
||||||
- Jump To A Child Directory:
|
|
||||||
|
|
||||||
Sometimes it's convenient to jump to a child directory
|
|
||||||
(sub-directory of current directory) rather than typing out the
|
|
||||||
full name.
|
|
||||||
|
|
||||||
jc bar
|
|
||||||
|
|
||||||
- Open File Manager To Directories (instead of jumping):
|
|
||||||
|
|
||||||
Instead of jumping to a directory, you can open a file explorer
|
|
||||||
window (Mac Finder, Windows Explorer, GNOME Nautilus, etc.) to the
|
|
||||||
directory instead.
|
|
||||||
|
|
||||||
jo music
|
|
||||||
|
|
||||||
Opening a file manager to a child directory is also supported:
|
|
||||||
|
|
||||||
jco images
|
|
||||||
|
|
||||||
- Using Multiple Arguments:
|
|
||||||
|
|
||||||
Let's assume the following database:
|
|
||||||
|
|
||||||
30 /home/user/mail/inbox
|
|
||||||
10 /home/user/work/inbox
|
|
||||||
|
|
||||||
`j in` would jump into /home/user/mail/inbox as the higher
|
|
||||||
weighted entry. However you can pass multiple arguments to autojump
|
|
||||||
to prefer a different entry. In the above example, `j w in` would
|
|
||||||
then change directory to /home/user/work/inbox.
|
|
||||||
|
|
||||||
For more options refer to help:
|
|
||||||
|
|
||||||
autojump --help
|
|
||||||
|
|
||||||
INSTALLATION
|
INSTALLATION
|
||||||
------------
|
------------
|
||||||
|
|
||||||
### REQUIREMENTS
|
### REQUIREMENTS
|
||||||
|
|
||||||
- Python v2.6+ or Python v3.3+
|
- Python v2.6+
|
||||||
- Supported shells
|
- Bash v4.0 for tab completion (or zsh)
|
||||||
- bash - first class support
|
|
||||||
- zsh - first class support
|
|
||||||
- fish - community supported
|
|
||||||
- tcsh - community supported
|
|
||||||
- clink - community supported
|
|
||||||
- Supported platforms
|
|
||||||
- Linux - first class support
|
|
||||||
- OS X - first class support
|
|
||||||
- Windows - community supported
|
|
||||||
- BSD - community supported
|
|
||||||
- Supported installation methods
|
|
||||||
- source code - first class support
|
|
||||||
- Debian and derivatives - first class support
|
|
||||||
- ArchLinux / Gentoo / openSUSE / RedHat and derivatives -
|
|
||||||
community supported
|
|
||||||
- Homebrew / MacPorts - community supported
|
|
||||||
|
|
||||||
Due to limited time and resources, only "first class support" items will
|
If you are unable to update Python to a supported version, older
|
||||||
be maintained by the primary committers. All "community supported" items
|
versions of autojump can be [downloaded][dl] and installed manually.
|
||||||
will be updated based on pull requests submitted by the general public.
|
|
||||||
|
|
||||||
Please continue opening issues and providing feedback for community
|
- Python v2.4 is supported by [release v12][v12].
|
||||||
supported items since consolidating information helps other users
|
|
||||||
troubleshoot and submit enhancements and fixes.
|
|
||||||
|
|
||||||
### MANUAL
|
### AUTOMATIC INSTALLATION
|
||||||
|
|
||||||
Grab a copy of autojump:
|
**Linux**
|
||||||
|
|
||||||
git clone git://github.com/wting/autojump.git
|
|
||||||
|
|
||||||
Run the installation script and follow on screen instructions.
|
|
||||||
|
|
||||||
cd autojump
|
|
||||||
./install.py or ./uninstall.py
|
|
||||||
|
|
||||||
### AUTOMATIC
|
|
||||||
|
|
||||||
#### Linux
|
|
||||||
|
|
||||||
autojump is included in the following distro repositories, please use
|
autojump is included in the following distro repositories, please use
|
||||||
relevant package management utilities to install (e.g. apt-get, yum,
|
relevant package management utilities to install (e.g. yum, apt-get,
|
||||||
pacman, etc):
|
etc):
|
||||||
|
|
||||||
- Debian, Ubuntu, Linux Mint
|
|
||||||
|
|
||||||
All Debian-derived distros require manual activation for policy
|
|
||||||
reasons, please see `/usr/share/doc/autojump/README.Debian`.
|
|
||||||
|
|
||||||
|
- Debian\* testing/unstable, Ubuntu, Linux Mint
|
||||||
- RedHat, Fedora, CentOS
|
- RedHat, Fedora, CentOS
|
||||||
|
|
||||||
Install `autojump-zsh` for zsh, `autojump-fish` for fish, etc.
|
|
||||||
|
|
||||||
- ArchLinux
|
- ArchLinux
|
||||||
- Gentoo
|
- Gentoo
|
||||||
- Frugalware
|
- Frugalware
|
||||||
- Slackware
|
- Slackware
|
||||||
|
|
||||||
#### OS X
|
\* Requires manual activation for policy reasons, please see
|
||||||
|
`/usr/share/doc/autojump/README.Debian`.
|
||||||
|
|
||||||
|
**Mac**
|
||||||
|
|
||||||
Homebrew is the recommended installation method for Mac OS X:
|
Homebrew is the recommended installation method for Mac OS X:
|
||||||
|
|
||||||
brew install autojump
|
brew install autojump
|
||||||
|
|
||||||
MacPorts is also available:
|
MacPorts also available:
|
||||||
|
|
||||||
port install autojump
|
port install autojump
|
||||||
|
|
||||||
Windows
|
**Other**
|
||||||
|
|
||||||
|
Please check the [Wiki][wiki] for an up to date listing of installation methods.
|
||||||
|
|
||||||
|
### MANUAL INSTALLATION
|
||||||
|
|
||||||
|
Grab a copy of autojump:
|
||||||
|
|
||||||
|
git clone git://github.com/joelthelion/autojump.git
|
||||||
|
|
||||||
|
Run the installation script:
|
||||||
|
|
||||||
|
cd autojump
|
||||||
|
./install.sh [ --local ]
|
||||||
|
|
||||||
|
and follow on screen instructions.
|
||||||
|
|
||||||
|
### MANUAL UNINSTALLATION
|
||||||
|
|
||||||
|
It is recommended to use your distribution's relevant package management
|
||||||
|
utilities, unless you installed manually or ran into uninstallation
|
||||||
|
issues.
|
||||||
|
|
||||||
|
Grab a copy of autojump:
|
||||||
|
|
||||||
|
git clone git://github.com/joelthelion/autojump.git
|
||||||
|
|
||||||
|
Run the uninstallation script:
|
||||||
|
|
||||||
|
cd autojump
|
||||||
|
./uninstall.sh
|
||||||
|
|
||||||
|
and follow on screen instructions.
|
||||||
|
|
||||||
|
If you keep getting `autojump: command not found` at the prompt,
|
||||||
|
do:`unset PROMPT_COMMAND`. You can also restart your shell.
|
||||||
|
|
||||||
|
DEVELOPMENT
|
||||||
|
-----------
|
||||||
|
|
||||||
|
The source code is primarily in `./bin/autojump`. Various shell wrapper
|
||||||
|
scripts are also available in `./bin/`.
|
||||||
|
|
||||||
|
Documentation is in various files under `./docs/`. Build documentation
|
||||||
|
with the command:
|
||||||
|
|
||||||
|
make docs
|
||||||
|
|
||||||
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
|
|
||||||
Windows support is enabled by [clink](https://mridgers.github.io/clink/)
|
Options must be passed to 'autojump' and not the 'j' wrapper function.
|
||||||
which should be installed prior to installing autojump.
|
|
||||||
|
-i, --increase manually increase current directory weight
|
||||||
|
|
||||||
|
-d, --decrease manually decrease current directory weight
|
||||||
|
|
||||||
|
--purge deletes database entries that no longer exist on system
|
||||||
|
|
||||||
|
-s, --stat show general stats and top 100 database entries
|
||||||
|
|
||||||
|
--version show version information and exit
|
||||||
|
|
||||||
|
ADVANCED USAGE
|
||||||
|
--------------
|
||||||
|
|
||||||
|
- Using Multiple Arguments
|
||||||
|
|
||||||
|
Let's assume the following database:
|
||||||
|
|
||||||
|
30 /home/user/mail/inbox
|
||||||
|
10 /home/user/work/inbox
|
||||||
|
|
||||||
|
`j in` would jump into /home/user/mail/inbox as the higher weighted
|
||||||
|
entry. However you can pass multiple arguments to autojump to prefer
|
||||||
|
a different entry. In the above example, `j w in` would then jump
|
||||||
|
you into /home/user/work/inbox.
|
||||||
|
|
||||||
|
- Jump To A Child Directory.
|
||||||
|
|
||||||
|
Sometimes it's convenient to jump to a child directory
|
||||||
|
(sub-directory of current directory) rather than typing out the full
|
||||||
|
name.
|
||||||
|
|
||||||
|
jc images
|
||||||
|
|
||||||
|
- Open File Manager To Directories (instead of jumping)
|
||||||
|
|
||||||
|
Instead of jumping to a directory, you can open a file explorer
|
||||||
|
window (Mac Finder, Windows Explorer, GNOME Nautilus, etc) to the
|
||||||
|
directory instead.
|
||||||
|
|
||||||
|
jo music
|
||||||
|
|
||||||
|
Opening a file manager to a child directory is also supported.
|
||||||
|
|
||||||
|
jco images
|
||||||
|
|
||||||
|
ADDITIONAL CONFIGURATION
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
- Enable ZSH Tab Completion
|
||||||
|
|
||||||
|
ZSH tab completion requires the `compinit` module to be loaded.
|
||||||
|
Please add the following line to your \~/.zshrc *after* loading
|
||||||
|
autojump:
|
||||||
|
|
||||||
|
autoload -U compinit && compinit
|
||||||
|
|
||||||
|
For security compinit checks completion system if files will be
|
||||||
|
owned by root or the current user. This check can be ignored by
|
||||||
|
using the -u flag:
|
||||||
|
|
||||||
|
autoload -U compinit && compinit -u
|
||||||
|
|
||||||
|
Tab completion requires two tabs before autojump will display the
|
||||||
|
completion menu. However if `setopt nolistambiguous` is enabled,
|
||||||
|
then only one tab is required.
|
||||||
|
|
||||||
|
- Always Ignore Case
|
||||||
|
|
||||||
|
Default behavior is to prioritize exact matches over all else. For
|
||||||
|
example, `j foo` will prefer /foobar over /FooBar even if the latter
|
||||||
|
has a higher weight. To change this behavior and ignore case, add
|
||||||
|
the following environmental variable in your \~/.bashrc:
|
||||||
|
|
||||||
|
export AUTOJUMP_IGNORE_CASE=1
|
||||||
|
|
||||||
|
- Prefer Symbolic Links
|
||||||
|
|
||||||
|
Default behavior is to evaluate symbolic links into full paths as to
|
||||||
|
reduce duplicate entries in the database. However, some users prefer
|
||||||
|
a shorter working directory path in their shell prompt. To switch
|
||||||
|
behavior to prefer symbolic links, add the following environmental
|
||||||
|
variable in your \~/.bashrc:
|
||||||
|
|
||||||
|
export AUTOJUMP_KEEP_SYMLINKS=1
|
||||||
|
|
||||||
|
- Autocomplete Additional Commands (Bash only)
|
||||||
|
|
||||||
|
Autojump can be used to autocomplete other commands (e.g. cp or
|
||||||
|
vim). To use this feature, add the following environmental variable
|
||||||
|
in your \~/.bashrc:
|
||||||
|
|
||||||
|
export AUTOJUMP_AUTOCOMPLETE_CMDS='cp vim'
|
||||||
|
|
||||||
|
Changes require reloading autojump to take into effect.
|
||||||
|
|
||||||
KNOWN ISSUES
|
KNOWN ISSUES
|
||||||
------------
|
------------
|
||||||
|
|
||||||
- autojump does not support directories that begin with `-`.
|
- For bash users, autojump keeps track of directories as a pre-command
|
||||||
|
hook by modifying \$PROMPT\_COMMAND. If you overwrite
|
||||||
- For bash users, autojump keeps track of directories by modifying
|
\$PROMPT\_COMMAND in \~/.bashrc you can cause problems. Don't do
|
||||||
`$PROMPT_COMMAND`. Do not overwrite `$PROMPT_COMMAND`:
|
this:
|
||||||
|
|
||||||
export PROMPT_COMMAND="history -a"
|
export PROMPT_COMMAND="history -a"
|
||||||
|
|
||||||
Instead append to the end of the existing \$PROMPT\_COMMAND:
|
Do this:
|
||||||
|
|
||||||
export PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND ;} history -a"
|
export PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND ;} history -a"
|
||||||
|
|
||||||
|
- The jump function `j` does not support directories that begin with
|
||||||
|
`-`. If you want to jump a directory called `--music`, try using
|
||||||
|
`j music` instead of `j --music`.
|
||||||
|
|
||||||
|
FILES
|
||||||
|
-----
|
||||||
|
|
||||||
|
If installed locally, autojump is self-contained in *\~/.autojump/*.
|
||||||
|
|
||||||
|
The database is stored in *\$XDG\_DATA\_HOME/autojump/autojump.txt*.
|
||||||
|
|
||||||
REPORTING BUGS
|
REPORTING BUGS
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
For any questions or issues please visit:
|
For any usage related issues or feature requests please visit:
|
||||||
|
|
||||||
https://github.com/wting/autojump/issues
|
*https://github.com/joelthelion/autojump/issues*
|
||||||
|
|
||||||
|
THANKS
|
||||||
|
------
|
||||||
|
|
||||||
|
Special thanks goes out to: Pierre Gueth, Simon Marache-Francisco,
|
||||||
|
Daniel Jackoway, and many others.
|
||||||
|
|
||||||
AUTHORS
|
AUTHORS
|
||||||
-------
|
-------
|
||||||
|
|
||||||
autojump was originally written by Joël Schaerer, and currently
|
autojump was originally written by Joël Schaerer, and currently
|
||||||
maintained by William Ting. More contributors can be found in `AUTHORS`.
|
maintained by William Ting.
|
||||||
|
|
||||||
COPYRIGHT
|
COPYRIGHT
|
||||||
---------
|
---------
|
||||||
|
|
||||||
Copyright © 2016 Free Software Foundation, Inc. License GPLv3+: GNU GPL
|
Copyright © 2013 Free Software Foundation, Inc. License GPLv3+: GNU GPL
|
||||||
version 3 or later <http://gnu.org/licenses/gpl.html>. This is free
|
version 3 or later <http://gnu.org/licenses/gpl.html>. This is free
|
||||||
software: you are free to change and redistribute it. There is NO
|
software: you are free to change and redistribute it. There is NO
|
||||||
WARRANTY, to the extent permitted by law.
|
WARRANTY, to the extent permitted by law.
|
||||||
|
|
||||||
|
[dl]: https://github.com/joelthelion/autojump/downloads
|
||||||
|
[mock]: https://pypi.python.org/pypi/mock
|
||||||
|
[v12]: https://github.com/downloads/joelthelion/autojump/autojump_v12.tar.gz
|
||||||
|
[wiki]: https://github.com/joelthelion/autojump/wiki
|
||||||
|
759
bin/autojump
759
bin/autojump
@ -1,342 +1,525 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Copyright © 2008-2012 Joel Schaerer
|
Copyright © 2008-2012 Joel Schaerer
|
||||||
Copyright © 2012-2016 William Ting
|
Copyright © 2012-2013 William Ting
|
||||||
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
it under the terms of the GNU General Public License as published by
|
||||||
the Free Software Foundation; either version 3, or (at your option)
|
the Free Software Foundation; either version 3, or (at your option)
|
||||||
any later version.
|
any later version.
|
||||||
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
* You should have received a copy of the GNU General Public License
|
* 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.,
|
along with this program; if not, write to the Free Software
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
"""
|
"""
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
|
from __future__ import division, print_function
|
||||||
|
|
||||||
|
import collections
|
||||||
|
import difflib
|
||||||
|
import errno
|
||||||
|
import math
|
||||||
|
import operator
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
from itertools import chain
|
import tempfile
|
||||||
from math import sqrt
|
|
||||||
from operator import attrgetter
|
|
||||||
from operator import itemgetter
|
|
||||||
|
|
||||||
if sys.version_info[0] == 3:
|
|
||||||
ifilter = filter
|
|
||||||
imap = map
|
|
||||||
os.getcwdu = os.getcwd
|
|
||||||
else:
|
|
||||||
from itertools import ifilter
|
|
||||||
from itertools import imap
|
|
||||||
|
|
||||||
# Vendorized argparse for Python 2.6 support
|
try:
|
||||||
from autojump_argparse import ArgumentParser
|
import argparse
|
||||||
|
except ImportError:
|
||||||
|
# Python 2.6 support
|
||||||
|
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
|
||||||
|
import autojump_argparse as argparse
|
||||||
|
sys.path.pop()
|
||||||
|
|
||||||
# autojump is not a standard python package but rather installed as a mixed
|
|
||||||
# shell + Python app with no outside dependencies (except Python). As a
|
|
||||||
# consequence we use relative imports and depend on file prefixes to prevent
|
|
||||||
# module conflicts.
|
|
||||||
from autojump_data import dictify
|
|
||||||
from autojump_data import entriefy
|
|
||||||
from autojump_data import Entry
|
|
||||||
from autojump_data import load
|
|
||||||
from autojump_data import save
|
|
||||||
from autojump_match import match_anywhere
|
|
||||||
from autojump_match import match_consecutive
|
|
||||||
from autojump_match import match_fuzzy
|
|
||||||
from autojump_utils import first
|
|
||||||
from autojump_utils import get_pwd
|
|
||||||
from autojump_utils import get_tab_entry_info
|
|
||||||
from autojump_utils import has_uppercase
|
|
||||||
from autojump_utils import is_autojump_sourced
|
|
||||||
from autojump_utils import is_osx
|
|
||||||
from autojump_utils import is_windows
|
|
||||||
from autojump_utils import last
|
|
||||||
from autojump_utils import print_entry
|
|
||||||
from autojump_utils import print_local
|
|
||||||
from autojump_utils import print_tab_menu
|
|
||||||
from autojump_utils import sanitize
|
|
||||||
from autojump_utils import take
|
|
||||||
from autojump_utils import unico
|
|
||||||
|
|
||||||
VERSION = '22.5.3'
|
def create_dir_atomically(path):
|
||||||
FUZZY_MATCH_THRESHOLD = 0.6
|
try:
|
||||||
TAB_ENTRIES_COUNT = 9
|
os.makedirs(path)
|
||||||
TAB_SEPARATOR = '__'
|
except OSError as exception:
|
||||||
|
if exception.errno != errno.EEXIST:
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
class Database:
|
||||||
|
"""
|
||||||
|
Abstraction for interfacing with with autojump database file.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, config):
|
||||||
|
self.config = config
|
||||||
|
self.filename = config['db']
|
||||||
|
self.data = collections.defaultdict(int)
|
||||||
|
self.load()
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self.data)
|
||||||
|
|
||||||
|
def load(self, error_recovery = False):
|
||||||
|
"""
|
||||||
|
Open database file, recovering from backup if needed.
|
||||||
|
"""
|
||||||
|
if os.path.exists(self.filename):
|
||||||
|
try:
|
||||||
|
if sys.version_info >= (3, 0):
|
||||||
|
with open(self.filename, 'r', encoding='utf-8') as f:
|
||||||
|
for line in f.readlines():
|
||||||
|
weight, path = line[:-1].split("\t", 1)
|
||||||
|
path = decode(path, 'utf-8')
|
||||||
|
self.data[path] = float(weight)
|
||||||
|
else:
|
||||||
|
with open(self.filename, 'r') as f:
|
||||||
|
for line in f.readlines():
|
||||||
|
weight, path = line[:-1].split("\t", 1)
|
||||||
|
path = decode(path, 'utf-8')
|
||||||
|
self.data[path] = float(weight)
|
||||||
|
except (IOError, EOFError):
|
||||||
|
self.load_backup(error_recovery)
|
||||||
|
else:
|
||||||
|
self.load_backup(error_recovery)
|
||||||
|
|
||||||
|
def load_backup(self, error_recovery = False):
|
||||||
|
"""
|
||||||
|
Loads database from backup file.
|
||||||
|
"""
|
||||||
|
if os.path.exists(self.filename + '.bak'):
|
||||||
|
if not error_recovery:
|
||||||
|
print('Problem with autojump database,\
|
||||||
|
trying to recover from backup...', file=sys.stderr)
|
||||||
|
shutil.copy(self.filename + '.bak', self.filename)
|
||||||
|
return self.load(True)
|
||||||
|
|
||||||
|
def save(self):
|
||||||
|
"""
|
||||||
|
Save database atomically and preserve backup, creating new database if
|
||||||
|
needed.
|
||||||
|
"""
|
||||||
|
# check file existence and permissions
|
||||||
|
if ((not os.path.exists(self.filename)) or
|
||||||
|
os.name == 'nt' or
|
||||||
|
os.getuid() == os.stat(self.filename)[4]):
|
||||||
|
|
||||||
|
create_dir_atomically(self.config['data'])
|
||||||
|
|
||||||
|
temp = tempfile.NamedTemporaryFile(
|
||||||
|
dir=self.config['data'],
|
||||||
|
delete=False)
|
||||||
|
|
||||||
|
for path, weight in sorted(self.data.items(),
|
||||||
|
key=operator.itemgetter(1),
|
||||||
|
reverse=True):
|
||||||
|
temp.write((unico("%s\t%s\n" % (weight, path)).encode("utf-8")))
|
||||||
|
|
||||||
|
# catching disk errors and skipping save when file handle can't
|
||||||
|
# be closed.
|
||||||
|
try:
|
||||||
|
# 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 saving autojump database (disk full?)" %
|
||||||
|
ex, file=sys.stderr)
|
||||||
|
return
|
||||||
|
|
||||||
|
shutil.move(temp.name, self.filename)
|
||||||
|
try: # backup file
|
||||||
|
import time
|
||||||
|
if (not os.path.exists(self.filename+".bak") or
|
||||||
|
time.time()-os.path.getmtime(self.filename+".bak") \
|
||||||
|
> 86400):
|
||||||
|
shutil.copy(self.filename, self.filename+".bak")
|
||||||
|
except OSError as ex:
|
||||||
|
print("Error while creating backup autojump file. (%s)" %
|
||||||
|
ex, file=sys.stderr)
|
||||||
|
|
||||||
|
def add(self, path, increment=10):
|
||||||
|
"""
|
||||||
|
Increase weight of existing paths or initialize new ones to 10.
|
||||||
|
"""
|
||||||
|
if path == self.config['home']:
|
||||||
|
return
|
||||||
|
|
||||||
|
path = path.rstrip(os.sep)
|
||||||
|
|
||||||
|
if self.data[path]:
|
||||||
|
self.data[path] = math.sqrt((self.data[path]**2) + (increment**2))
|
||||||
|
else:
|
||||||
|
self.data[path] = increment
|
||||||
|
|
||||||
|
self.save()
|
||||||
|
|
||||||
|
def decrease(self, path, increment=15):
|
||||||
|
"""
|
||||||
|
Decrease weight of existing path. Unknown paths are ignored.
|
||||||
|
"""
|
||||||
|
if path == self.config['home']:
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.data[path] < increment:
|
||||||
|
self.data[path] = 0
|
||||||
|
else:
|
||||||
|
self.data[path] -= increment
|
||||||
|
|
||||||
|
self.save()
|
||||||
|
|
||||||
|
def get_weight(self, path):
|
||||||
|
return self.data[path]
|
||||||
|
|
||||||
|
def maintenance(self):
|
||||||
|
"""
|
||||||
|
Decay weights by 10%, periodically remove bottom 10% entries.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
items = self.data.iteritems()
|
||||||
|
except AttributeError:
|
||||||
|
items = self.data.items()
|
||||||
|
|
||||||
|
for path, _ in items:
|
||||||
|
self.data[path] *= 0.9
|
||||||
|
|
||||||
|
if len(self.data) > self.config['max_paths']:
|
||||||
|
remove_cnt = int(0.1 * len(self.data))
|
||||||
|
for path in sorted(self.data, key=self.data.get)[:remove_cnt]:
|
||||||
|
del self.data[path]
|
||||||
|
|
||||||
|
self.save()
|
||||||
|
|
||||||
|
def purge(self):
|
||||||
|
"""
|
||||||
|
Remove non-existent paths.
|
||||||
|
"""
|
||||||
|
removed = []
|
||||||
|
|
||||||
|
for path in list(self.data.keys()):
|
||||||
|
if not os.path.exists(path):
|
||||||
|
removed.append(path)
|
||||||
|
del self.data[path]
|
||||||
|
|
||||||
|
self.save()
|
||||||
|
return removed
|
||||||
|
|
||||||
def set_defaults():
|
def set_defaults():
|
||||||
config = {}
|
config = {}
|
||||||
|
|
||||||
if is_osx():
|
config['version'] = 'release-v21.7.1'
|
||||||
data_home = os.path.join(os.path.expanduser('~'), 'Library')
|
config['max_paths'] = 1000
|
||||||
elif is_windows():
|
config['separator'] = '__'
|
||||||
data_home = os.getenv('APPDATA')
|
config['home'] = os.path.expanduser('~')
|
||||||
else:
|
|
||||||
data_home = os.getenv(
|
config['ignore_case'] = False
|
||||||
'XDG_DATA_HOME',
|
config['keep_symlinks'] = False
|
||||||
os.path.join(
|
config['debug'] = False
|
||||||
os.path.expanduser('~'),
|
config['match_cnt'] = 1
|
||||||
'.local',
|
|
||||||
'share',
|
xdg_data = os.environ.get('XDG_DATA_HOME') or \
|
||||||
),
|
os.path.join(config['home'], '.local', 'share')
|
||||||
)
|
config['data'] = os.path.join(xdg_data, 'autojump')
|
||||||
config['data_path'] = os.path.join(data_home, 'autojump', 'autojump.txt')
|
config['db'] = config['data'] + '/autojump.txt'
|
||||||
config['backup_path'] = os.path.join(data_home, 'autojump', 'autojump.txt.bak')
|
|
||||||
|
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
def parse_env(config):
|
||||||
|
if 'AUTOJUMP_DATA_DIR' in os.environ:
|
||||||
|
config['data'] = os.environ.get('AUTOJUMP_DATA_DIR')
|
||||||
|
config['db'] = config['data'] + '/autojump.txt'
|
||||||
|
|
||||||
def parse_arguments():
|
if config['data'] == config['home']:
|
||||||
parser = ArgumentParser(
|
config['db'] = config['data'] + '/.autojump.txt'
|
||||||
description='Automatically jump to directory passed as an argument.',
|
|
||||||
epilog='Please see autojump(1) man pages for full documentation.',
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'directory', metavar='DIRECTORY', nargs='*', default='',
|
|
||||||
help='directory to jump to',
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-a', '--add', metavar='DIRECTORY',
|
|
||||||
help='add path',
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-i', '--increase', metavar='WEIGHT', nargs='?', type=int,
|
|
||||||
const=10, default=False,
|
|
||||||
help='increase current directory weight',
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-d', '--decrease', metavar='WEIGHT', nargs='?', type=int,
|
|
||||||
const=15, default=False,
|
|
||||||
help='decrease current directory weight',
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'--complete', action='store_true', default=False,
|
|
||||||
help='used for tab completion',
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'--purge', action='store_true', default=False,
|
|
||||||
help='remove non-existent paths from database',
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-s', '--stat', action='store_true', default=False,
|
|
||||||
help='show database entries and their key weights',
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-v', '--version', action='version', version='%(prog)s v' +
|
|
||||||
VERSION, help='show version information',
|
|
||||||
)
|
|
||||||
|
|
||||||
return parser.parse_args()
|
if 'AUTOJUMP_IGNORE_CASE' in os.environ and \
|
||||||
|
os.environ.get('AUTOJUMP_IGNORE_CASE') == '1':
|
||||||
|
config['ignore_case'] = True
|
||||||
|
|
||||||
|
if 'AUTOJUMP_KEEP_SYMLINKS' in os.environ and \
|
||||||
|
os.environ.get('AUTOJUMP_KEEP_SYMLINKS') == '1':
|
||||||
|
config['keep_symlinks'] = True
|
||||||
|
|
||||||
def add_path(data, path, weight=10):
|
return config
|
||||||
|
|
||||||
|
def parse_arg(config):
|
||||||
|
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='DIRECTORY', nargs='*', default='',
|
||||||
|
help='directory to jump to')
|
||||||
|
parser.add_argument(
|
||||||
|
'-a', '--add', metavar='DIRECTORY',
|
||||||
|
help='manually add path to database')
|
||||||
|
parser.add_argument(
|
||||||
|
'-i', '--increase', metavar='WEIGHT', nargs='?', type=int,
|
||||||
|
const=20, default=False,
|
||||||
|
help='manually increase path weight in database')
|
||||||
|
parser.add_argument(
|
||||||
|
'-d', '--decrease', metavar='WEIGHT', nargs='?', type=int,
|
||||||
|
const=15, default=False,
|
||||||
|
help='manually decrease path weight in database')
|
||||||
|
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')
|
||||||
|
parser.add_argument(
|
||||||
|
'--purge', action="store_true", default=False,
|
||||||
|
help='delete all database entries that no longer exist on system')
|
||||||
|
parser.add_argument(
|
||||||
|
'-s', '--stat', action="store_true", default=False,
|
||||||
|
help='show database entries and their key weights')
|
||||||
|
parser.add_argument(
|
||||||
|
'-v', '--version', action="version", version="%(prog)s " +
|
||||||
|
config['version'], help='show version information and exit')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
db = Database(config)
|
||||||
|
|
||||||
|
if args.add:
|
||||||
|
db.add(decode(args.add))
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
if args.increase:
|
||||||
|
print("%.2f:\t old directory weight" % db.get_weight(os.getcwd()))
|
||||||
|
db.add(os.getcwd(), args.increase)
|
||||||
|
print("%.2f:\t new directory weight" % db.get_weight(os.getcwd()))
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
if args.decrease:
|
||||||
|
print("%.2f:\t old directory weight" % db.get_weight(os.getcwd()))
|
||||||
|
db.decrease(os.getcwd(), args.decrease)
|
||||||
|
print("%.2f:\t new directory weight" % db.get_weight(os.getcwd()))
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
if args.purge:
|
||||||
|
removed = db.purge()
|
||||||
|
|
||||||
|
if len(removed):
|
||||||
|
for dir in removed:
|
||||||
|
output(dir)
|
||||||
|
|
||||||
|
print("Number of database entries removed: %d" % len(removed))
|
||||||
|
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
if args.stat:
|
||||||
|
for path, weight in sorted(db.data.items(),
|
||||||
|
key=operator.itemgetter(1))[-100:]:
|
||||||
|
output("%.1f:\t%s" % (weight, path))
|
||||||
|
|
||||||
|
print("________________________________________\n")
|
||||||
|
print("%d:\t total key weight" % sum(db.data.values()))
|
||||||
|
print("%d:\t stored directories" % len(db.data))
|
||||||
|
print("%.2f:\t current directory weight" % db.get_weight(os.getcwd()))
|
||||||
|
|
||||||
|
print("\ndb file: %s" % config['db'])
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
if args.complete:
|
||||||
|
config['match_cnt'] = 9
|
||||||
|
config['ignore_case'] = True
|
||||||
|
|
||||||
|
config['args'] = args
|
||||||
|
return config
|
||||||
|
|
||||||
|
def decode(text, encoding=None, errors="strict"):
|
||||||
"""
|
"""
|
||||||
Add a new path or increment an existing one.
|
Decoding step for Python 2 which does not default to unicode.
|
||||||
|
|
||||||
os.path.realpath() is not used because it's preferable to use symlinks
|
|
||||||
with resulting duplicate entries in the database than a single canonical
|
|
||||||
path.
|
|
||||||
"""
|
"""
|
||||||
path = unico(path).rstrip(os.sep)
|
if sys.version_info[0] > 2:
|
||||||
if path == os.path.expanduser('~'):
|
return text
|
||||||
return data, Entry(path, 0)
|
|
||||||
|
|
||||||
data[path] = sqrt((data.get(path, 0) ** 2) + (weight ** 2))
|
|
||||||
|
|
||||||
return data, Entry(path, data[path])
|
|
||||||
|
|
||||||
|
|
||||||
def decrease_path(data, path, weight=15):
|
|
||||||
"""Decrease or zero out a path."""
|
|
||||||
path = unico(path).rstrip(os.sep)
|
|
||||||
data[path] = max(0, data.get(path, 0) - weight)
|
|
||||||
return data, Entry(path, data[path])
|
|
||||||
|
|
||||||
|
|
||||||
def detect_smartcase(needles):
|
|
||||||
"""
|
|
||||||
If any needles contain an uppercase letter then use case sensitive
|
|
||||||
searching. Otherwise use case insensitive searching.
|
|
||||||
"""
|
|
||||||
return not any(imap(has_uppercase, needles))
|
|
||||||
|
|
||||||
|
|
||||||
def find_matches(entries, needles, check_entries=True):
|
|
||||||
"""Return an iterator to matching entries."""
|
|
||||||
# TODO(wting|2014-02-24): replace assertion with unit test
|
|
||||||
assert isinstance(needles, list), 'Needles must be a list.'
|
|
||||||
ignore_case = detect_smartcase(needles)
|
|
||||||
|
|
||||||
try:
|
|
||||||
pwd = os.getcwdu()
|
|
||||||
except OSError:
|
|
||||||
pwd = None
|
|
||||||
|
|
||||||
# using closure to prevent constantly hitting hdd
|
|
||||||
def is_cwd(entry):
|
|
||||||
return os.path.realpath(entry.path) == pwd
|
|
||||||
|
|
||||||
if check_entries:
|
|
||||||
path_exists = lambda entry: os.path.exists(entry.path)
|
|
||||||
else:
|
else:
|
||||||
path_exists = lambda _: True
|
if encoding is None:
|
||||||
|
encoding = sys.getfilesystemencoding()
|
||||||
|
return text.decode(encoding, errors)
|
||||||
|
|
||||||
data = sorted(
|
def output_quotes(config, text):
|
||||||
entries,
|
quotes = ""
|
||||||
key=attrgetter('weight', 'path'),
|
if config['args'].complete and config['args'].bash:
|
||||||
reverse=True,
|
quotes = "'"
|
||||||
)
|
|
||||||
|
|
||||||
return ifilter(
|
output("%s%s%s" % (quotes, text, quotes))
|
||||||
lambda entry: not is_cwd(entry) and path_exists(entry),
|
|
||||||
chain(
|
|
||||||
match_consecutive(needles, data, ignore_case),
|
|
||||||
match_fuzzy(needles, data, ignore_case),
|
|
||||||
match_anywhere(needles, data, ignore_case),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
def output(text, encoding=None):
|
||||||
def handle_tab_completion(needle, entries):
|
"""
|
||||||
tab_needle, tab_index, tab_path = get_tab_entry_info(needle, TAB_SEPARATOR)
|
Wrapper for the print function, using the filesystem encoding by default
|
||||||
|
to minimize encoding mismatch problems in directory names.
|
||||||
if tab_path:
|
"""
|
||||||
print_local(tab_path)
|
if sys.version_info[0] > 2:
|
||||||
elif tab_index:
|
print(text)
|
||||||
get_ith_path = lambda i, iterable: last(take(i, iterable)).path
|
|
||||||
print_local(get_ith_path(
|
|
||||||
tab_index,
|
|
||||||
find_matches(entries, [tab_needle], check_entries=False),
|
|
||||||
))
|
|
||||||
elif tab_needle:
|
|
||||||
# found partial tab completion entry
|
|
||||||
print_tab_menu(
|
|
||||||
tab_needle,
|
|
||||||
take(
|
|
||||||
TAB_ENTRIES_COUNT, find_matches(
|
|
||||||
entries,
|
|
||||||
[tab_needle],
|
|
||||||
check_entries=False,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
TAB_SEPARATOR,
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
print_tab_menu(
|
if encoding is None:
|
||||||
needle,
|
encoding = sys.getfilesystemencoding()
|
||||||
take(
|
print(unicode(text).encode(encoding))
|
||||||
TAB_ENTRIES_COUNT, find_matches(
|
|
||||||
entries,
|
|
||||||
[needle],
|
|
||||||
check_entries=False,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
TAB_SEPARATOR,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
def unico(text):
|
||||||
|
"""
|
||||||
|
If Python 2, convert to a unicode object.
|
||||||
|
"""
|
||||||
|
if sys.version_info[0] > 2:
|
||||||
|
return text
|
||||||
|
else:
|
||||||
|
return unicode(text)
|
||||||
|
|
||||||
def purge_missing_paths(entries):
|
def match(path, pattern, only_end=False, ignore_case=False):
|
||||||
"""Remove non-existent paths from a list of entries."""
|
"""
|
||||||
exists = lambda entry: os.path.exists(entry.path)
|
Check whether a path matches a particular pattern, and return
|
||||||
return ifilter(exists, entries)
|
the remaining part of the string.
|
||||||
|
"""
|
||||||
|
if only_end:
|
||||||
|
match_path = "/".join(path.split('/')[-1-pattern.count('/'):])
|
||||||
|
else:
|
||||||
|
match_path = path
|
||||||
|
|
||||||
|
if ignore_case:
|
||||||
|
match_path = match_path.lower()
|
||||||
|
pattern = pattern.lower()
|
||||||
|
|
||||||
def print_stats(data, data_path):
|
find_idx = match_path.find(pattern)
|
||||||
for path, weight in sorted(data.items(), key=itemgetter(1)):
|
# truncate path to avoid matching a pattern multiple times
|
||||||
print_entry(Entry(path, weight))
|
if find_idx != -1:
|
||||||
|
return (True, path)
|
||||||
print('________________________________________\n')
|
else:
|
||||||
print('%d:\t total weight' % sum(data.values()))
|
return (False, path[find_idx+len(pattern):])
|
||||||
print('%d:\t number of entries' % len(data))
|
|
||||||
|
|
||||||
|
def find_matches(config, db, patterns, ignore_case=False, fuzzy=False):
|
||||||
|
"""
|
||||||
|
Find paths matching patterns up to max_matches.
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
print_local(
|
current_dir = decode(os.path.realpath(os.curdir))
|
||||||
'%.2f:\t current directory weight' % data.get(os.getcwdu(), 0),
|
|
||||||
)
|
|
||||||
except OSError:
|
except OSError:
|
||||||
# current directory no longer exists
|
current_dir = None
|
||||||
pass
|
|
||||||
|
|
||||||
print('\ndata:\t %s' % data_path)
|
dirs = sorted(db.data.items(), key=operator.itemgetter(1), reverse=True)
|
||||||
|
results = []
|
||||||
|
|
||||||
|
if ignore_case:
|
||||||
|
patterns = [p.lower() for p in patterns]
|
||||||
|
|
||||||
def main(args): # noqa
|
if fuzzy:
|
||||||
if not is_autojump_sourced() and not is_windows():
|
# create dictionary of end paths to compare against
|
||||||
print("Please source the correct autojump file in your shell's")
|
end_dirs = {}
|
||||||
print('startup file. For more information, please reinstall autojump')
|
for d in dirs:
|
||||||
print('and read the post installation instructions.')
|
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:
|
||||||
|
end_dirs[end] = d[0]
|
||||||
|
|
||||||
|
# find the first match (heighest weight)
|
||||||
|
while True:
|
||||||
|
found = difflib.get_close_matches(patterns[-1], end_dirs, n=1, cutoff=.6)
|
||||||
|
if not found:
|
||||||
|
break
|
||||||
|
# avoid jumping to current directory
|
||||||
|
if (os.path.exists(found[0]) or config['debug']) and \
|
||||||
|
current_dir != os.path.realpath(found[0]):
|
||||||
|
break
|
||||||
|
# continue with the last found directory removed
|
||||||
|
del end_dirs[found[0]]
|
||||||
|
|
||||||
|
if found:
|
||||||
|
found = found[0]
|
||||||
|
results.append(end_dirs[found])
|
||||||
|
return results
|
||||||
|
else:
|
||||||
|
return []
|
||||||
|
|
||||||
|
current_dir_match = False
|
||||||
|
for path, _ in dirs:
|
||||||
|
found, tmp = True, path
|
||||||
|
for n, p in enumerate(patterns):
|
||||||
|
# for single/last pattern, only check end of path
|
||||||
|
if n == len(patterns)-1:
|
||||||
|
found, tmp = match(tmp, p, True, ignore_case)
|
||||||
|
else:
|
||||||
|
found, tmp = match(tmp, p, False, ignore_case)
|
||||||
|
if not found: break
|
||||||
|
|
||||||
|
if found and (os.path.exists(path) or config['debug']):
|
||||||
|
# avoid jumping to current directory
|
||||||
|
# (call out to realpath this late to not stat all dirs)
|
||||||
|
if current_dir == os.path.realpath(path):
|
||||||
|
current_dir_match = True
|
||||||
|
continue
|
||||||
|
|
||||||
|
if path not in results:
|
||||||
|
results.append(path)
|
||||||
|
|
||||||
|
if len(results) >= config['match_cnt']:
|
||||||
|
break
|
||||||
|
|
||||||
|
# if current directory is the only match, add it to results
|
||||||
|
if len(results) == 0 and current_dir_match:
|
||||||
|
results.append(current_dir)
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
def main():
|
||||||
|
config = parse_arg(parse_env(set_defaults()))
|
||||||
|
sep = config['separator']
|
||||||
|
db = Database(config)
|
||||||
|
|
||||||
|
# checking command line directory arguments
|
||||||
|
if config['args'].directory:
|
||||||
|
patterns = [decode(d) for d in config['args'].directory]
|
||||||
|
else:
|
||||||
|
patterns = [unico('')]
|
||||||
|
|
||||||
|
# check for tab completion
|
||||||
|
tab_choice = None
|
||||||
|
tab_match = re.search(sep+r'([0-9]+)', patterns[-1])
|
||||||
|
|
||||||
|
# user has selected a tab completion entry
|
||||||
|
if tab_match:
|
||||||
|
config['match_cnt'] = 9
|
||||||
|
tab_choice = int(tab_match.group(1))
|
||||||
|
patterns[-1] = re.sub(sep+r'[0-9]+.*', '', patterns[-1])
|
||||||
|
else:
|
||||||
|
tab_match = re.match(r'(.*)'+sep, patterns[-1])
|
||||||
|
# partial tab match, display choices again
|
||||||
|
if tab_match:
|
||||||
|
config['match_cnt'] = 9
|
||||||
|
patterns[-1] = tab_match.group(1)
|
||||||
|
|
||||||
|
results = find_matches(config, db, patterns,
|
||||||
|
ignore_case=config['ignore_case'])
|
||||||
|
|
||||||
|
# if no results, try ignoring case
|
||||||
|
if not results and not config['ignore_case']:
|
||||||
|
results = find_matches(config, db, patterns, ignore_case=True)
|
||||||
|
|
||||||
|
# if no results, try approximate matching
|
||||||
|
if not results:
|
||||||
|
results = find_matches(config, db, patterns, ignore_case=True,
|
||||||
|
fuzzy=True)
|
||||||
|
|
||||||
|
if tab_choice and len(results) > (tab_choice-1):
|
||||||
|
output_quotes(config, results[tab_choice-1])
|
||||||
|
elif len(results) > 1 and config['args'].complete:
|
||||||
|
for n, r in enumerate(results[:9]):
|
||||||
|
output_quotes(config, '%s%s%d%s%s' %
|
||||||
|
(patterns[-1], sep, n+1, sep, r))
|
||||||
|
elif results:
|
||||||
|
output_quotes(config, results[0])
|
||||||
|
else:
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
config = set_defaults()
|
db.maintenance()
|
||||||
|
|
||||||
# all arguments are mutually exclusive
|
|
||||||
if args.add:
|
|
||||||
save(config, first(add_path(load(config), args.add)))
|
|
||||||
elif args.complete:
|
|
||||||
handle_tab_completion(
|
|
||||||
needle=first(chain(sanitize(args.directory), [''])),
|
|
||||||
entries=entriefy(load(config)),
|
|
||||||
)
|
|
||||||
elif args.decrease:
|
|
||||||
data, entry = decrease_path(load(config), get_pwd(), args.decrease)
|
|
||||||
save(config, data)
|
|
||||||
print_entry(entry)
|
|
||||||
elif args.increase:
|
|
||||||
data, entry = add_path(load(config), get_pwd(), args.increase)
|
|
||||||
save(config, data)
|
|
||||||
print_entry(entry)
|
|
||||||
elif args.purge:
|
|
||||||
old_data = load(config)
|
|
||||||
new_data = dictify(purge_missing_paths(entriefy(old_data)))
|
|
||||||
save(config, new_data)
|
|
||||||
print('Purged %d entries.' % (len(old_data) - len(new_data)))
|
|
||||||
elif args.stat:
|
|
||||||
print_stats(load(config), config['data_path'])
|
|
||||||
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
|
|
||||||
['.'],
|
|
||||||
)))
|
|
||||||
else:
|
|
||||||
entries = entriefy(load(config))
|
|
||||||
needles = sanitize(args.directory)
|
|
||||||
tab_needle, tab_index, tab_path = \
|
|
||||||
get_tab_entry_info(first(needles), TAB_SEPARATOR)
|
|
||||||
|
|
||||||
# Handle `j foo__`, assuming first index.
|
|
||||||
if not tab_path and not tab_index \
|
|
||||||
and tab_needle and needles[0] == tab_needle + TAB_SEPARATOR:
|
|
||||||
tab_index = 1
|
|
||||||
|
|
||||||
if tab_path:
|
|
||||||
print_local(tab_path)
|
|
||||||
elif tab_index:
|
|
||||||
get_ith_path = lambda i, iterable: last(take(i, iterable)).path
|
|
||||||
print_local(
|
|
||||||
get_ith_path(
|
|
||||||
tab_index,
|
|
||||||
find_matches(entries, [tab_needle]),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
print_local(first(chain(
|
|
||||||
imap(attrgetter('path'), find_matches(entries, needles)),
|
|
||||||
# always return a path to calling shell functions
|
|
||||||
['.'],
|
|
||||||
)))
|
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
if __name__ == '__main__':
|
sys.exit(main())
|
||||||
sys.exit(main(parse_arguments()))
|
|
||||||
|
@ -1,31 +1,10 @@
|
|||||||
export AUTOJUMP_SOURCED=1
|
_autojump()
|
||||||
|
{
|
||||||
# set user installation paths
|
|
||||||
if [[ -d ~/.autojump/ ]]; then
|
|
||||||
export PATH=~/.autojump/bin:"${PATH}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
# set error file location
|
|
||||||
if [[ "$(uname)" == "Darwin" ]]; then
|
|
||||||
export AUTOJUMP_ERROR_PATH=~/Library/autojump/errors.log
|
|
||||||
elif [[ -n "${XDG_DATA_HOME}" ]]; then
|
|
||||||
export AUTOJUMP_ERROR_PATH="${XDG_DATA_HOME}/autojump/errors.log"
|
|
||||||
else
|
|
||||||
export AUTOJUMP_ERROR_PATH=~/.local/share/autojump/errors.log
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! -d "$(dirname ${AUTOJUMP_ERROR_PATH})" ]]; then
|
|
||||||
mkdir -p "$(dirname ${AUTOJUMP_ERROR_PATH})"
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
# enable tab completion
|
|
||||||
_autojump() {
|
|
||||||
local cur
|
local cur
|
||||||
cur=${COMP_WORDS[*]:1}
|
cur=${COMP_WORDS[*]:1}
|
||||||
comps=$(autojump --complete $cur)
|
comps=$(autojump --bash --complete $cur)
|
||||||
while read i; do
|
while read i
|
||||||
|
do
|
||||||
COMPREPLY=("${COMPREPLY[@]}" "${i}")
|
COMPREPLY=("${COMPREPLY[@]}" "${i}")
|
||||||
done <<EOF
|
done <<EOF
|
||||||
$comps
|
$comps
|
||||||
@ -33,13 +12,52 @@ EOF
|
|||||||
}
|
}
|
||||||
complete -F _autojump j
|
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 --complete $cur)
|
||||||
|
while read i
|
||||||
|
do
|
||||||
|
COMPREPLY=("${COMPREPLY[@]}" "${i}")
|
||||||
|
done <<EOF
|
||||||
|
$comps
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ -n ${AUTOJUMP_AUTOCOMPLETE_CMDS} ]]; then
|
||||||
|
complete -o default -o bashdefault -F _autojump_files ${AUTOJUMP_AUTOCOMPLETE_CMDS}
|
||||||
|
fi
|
||||||
|
|
||||||
|
#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}"
|
||||||
|
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
|
||||||
|
|
||||||
# change pwd hook
|
|
||||||
autojump_add_to_database() {
|
autojump_add_to_database() {
|
||||||
if [[ -f "${AUTOJUMP_ERROR_PATH}" ]]; then
|
if [[ "${AUTOJUMP_HOME}" == "${HOME}" ]]; then
|
||||||
(autojump --add "$(pwd)" >/dev/null 2>>${AUTOJUMP_ERROR_PATH} &) &>/dev/null
|
autojump -a "$(pwd ${_PWD_ARGS})" 1>/dev/null 2>>"${AUTOJUMP_DATA_DIR}/autojump_errors"
|
||||||
else
|
|
||||||
(autojump --add "$(pwd)" >/dev/null &) &>/dev/null
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,79 +69,57 @@ case $PROMPT_COMMAND in
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
function j {
|
||||||
# default autojump command
|
if [[ ${@} =~ ^-{1,2}.* ]]; then
|
||||||
j() {
|
|
||||||
if [[ ${1} == -* ]] && [[ ${1} != "--" ]]; then
|
|
||||||
autojump ${@}
|
autojump ${@}
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
output="$(autojump ${@})"
|
new_path="$(autojump ${@})"
|
||||||
if [[ -d "${output}" ]]; then
|
if [ -d "${new_path}" ]; then
|
||||||
if [ -t 1 ]; then # if stdout is a terminal, use colors
|
echo -e "\\033[31m${new_path}\\033[0m"
|
||||||
echo -e "\\033[31m${output}\\033[0m"
|
cd "${new_path}"
|
||||||
else
|
|
||||||
echo -e "${output}"
|
|
||||||
fi
|
|
||||||
cd "${output}"
|
|
||||||
else
|
else
|
||||||
echo "autojump: directory '${@}' not found"
|
echo "autojump: directory '${@}' not found"
|
||||||
echo "\n${output}\n"
|
|
||||||
echo "Try \`autojump --help\` for more information."
|
echo "Try \`autojump --help\` for more information."
|
||||||
false
|
false
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function jc {
|
||||||
# jump to child directory (subdirectory of current path)
|
if [[ ${@} == -* ]]; then
|
||||||
jc() {
|
j ${@}
|
||||||
if [[ ${1} == -* ]] && [[ ${1} != "--" ]]; then
|
|
||||||
autojump ${@}
|
|
||||||
return
|
|
||||||
else
|
else
|
||||||
j $(pwd) ${@}
|
j $(pwd)/ ${@}
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function jo {
|
||||||
# open autojump results in file browser
|
if [ -z $(autojump $@) ]; then
|
||||||
jo() {
|
echo "autojump: directory '${@}' not found"
|
||||||
if [[ ${1} == -* ]] && [[ ${1} != "--" ]]; then
|
echo "Try \`autojump --help\` for more information."
|
||||||
autojump ${@}
|
false
|
||||||
return
|
else
|
||||||
fi
|
|
||||||
|
|
||||||
output="$(autojump ${@})"
|
|
||||||
if [[ -d "${output}" ]]; then
|
|
||||||
case ${OSTYPE} in
|
case ${OSTYPE} in
|
||||||
linux*)
|
linux-gnu)
|
||||||
xdg-open "${output}"
|
xdg-open "$(autojump $@)"
|
||||||
;;
|
;;
|
||||||
darwin*)
|
darwin*)
|
||||||
open "${output}"
|
open "$(autojump $@)"
|
||||||
;;
|
;;
|
||||||
cygwin)
|
cygwin)
|
||||||
cygstart "" $(cygpath -w -a ${output})
|
cygstart "" $(cygpath -w -a $(pwd))
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Unknown operating system: ${OSTYPE}." 1>&2
|
echo "Unknown operating system." 1>&2
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
else
|
|
||||||
echo "autojump: directory '${@}' not found"
|
|
||||||
echo "\n${output}\n"
|
|
||||||
echo "Try \`autojump --help\` for more information."
|
|
||||||
false
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function jco {
|
||||||
# open autojump results (child directory) in file browser
|
if [[ ${@} == -* ]]; then
|
||||||
jco() {
|
j ${@}
|
||||||
if [[ ${1} == -* ]] && [[ ${1} != "--" ]]; then
|
|
||||||
autojump ${@}
|
|
||||||
return
|
|
||||||
else
|
else
|
||||||
jo $(pwd) ${@}
|
jo $(pwd) ${@}
|
||||||
fi
|
fi
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
@echo off
|
|
||||||
python "%~dp0\autojump" %*
|
|
@ -1,74 +1,54 @@
|
|||||||
set -gx AUTOJUMP_SOURCED 1
|
complete -x -c j -a '(autojump --bash --complete (commandline -t))'
|
||||||
|
|
||||||
# set user installation path
|
switch "$XDG_DATA_HOME"
|
||||||
|
case "*$USER*"
|
||||||
|
set -x AUTOJUMP_DATA_DIR "$XDG_DATA_HOME/autojump"
|
||||||
|
case '*'
|
||||||
|
set -x AUTOJUMP_DATA_DIR ~/.local/share/autojump
|
||||||
|
end
|
||||||
|
|
||||||
|
if not test -d $AUTOJUMP_DATA_DIR
|
||||||
|
mkdir $AUTOJUMP_DATA_DIR
|
||||||
|
end
|
||||||
|
|
||||||
|
# local installation
|
||||||
if test -d ~/.autojump
|
if test -d ~/.autojump
|
||||||
set -x PATH ~/.autojump/bin $PATH
|
set -x PATH ~/.autojump/bin $PATH
|
||||||
end
|
end
|
||||||
|
|
||||||
# Set ostype, if not set
|
set -x AUTOJUMP_HOME $HOME
|
||||||
if not set -q OSTYPE
|
|
||||||
set -gx OSTYPE (bash -c 'echo ${OSTYPE}')
|
function __aj_err
|
||||||
|
echo $argv 1>&2; false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function __aj_not_found
|
||||||
# enable tab completion
|
__aj_err "autojump: directory '"$argv"' not found"
|
||||||
complete -x -c j -a '(autojump --complete (commandline -t))'
|
__aj_err "Try `autojump --help` for more information."
|
||||||
|
|
||||||
|
|
||||||
# set error file location
|
|
||||||
if test (uname) = "Darwin"
|
|
||||||
set -gx AUTOJUMP_ERROR_PATH ~/Library/autojump/errors.log
|
|
||||||
else if test -d "$XDG_DATA_HOME"
|
|
||||||
set -gx AUTOJUMP_ERROR_PATH $XDG_DATA_HOME/autojump/errors.log
|
|
||||||
else
|
|
||||||
set -gx AUTOJUMP_ERROR_PATH ~/.local/share/autojump/errors.log
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if test ! -d (dirname $AUTOJUMP_ERROR_PATH)
|
|
||||||
mkdir -p (dirname $AUTOJUMP_ERROR_PATH)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# change pwd hook
|
|
||||||
function __aj_add --on-variable PWD
|
function __aj_add --on-variable PWD
|
||||||
status --is-command-substitution; and return
|
status --is-command-substitution; and return
|
||||||
autojump --add (pwd) >/dev/null 2>>$AUTOJUMP_ERROR_PATH &
|
autojump -a (pwd) >/dev/null ^$AUTOJUMP_DATA_DIR/autojump_errors
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
# misc helper functions
|
|
||||||
function __aj_err
|
|
||||||
# TODO(ting|#247): set error file location
|
|
||||||
echo -e $argv 1>&2; false
|
|
||||||
end
|
|
||||||
|
|
||||||
# default autojump command
|
|
||||||
function j
|
function j
|
||||||
switch "$argv"
|
switch "$argv"
|
||||||
case '-*' '--*'
|
case '-*' '--*'
|
||||||
autojump $argv
|
autojump $argv
|
||||||
case '*'
|
case '*'
|
||||||
set -l output (autojump $argv)
|
set -l new_path (autojump $argv)
|
||||||
# Check for . and attempt a regular cd
|
if test -d "$new_path"
|
||||||
if [ $output = "." ]
|
set_color red
|
||||||
cd $argv
|
echo $new_path
|
||||||
|
set_color normal
|
||||||
|
cd $new_path
|
||||||
else
|
else
|
||||||
if test -d "$output"
|
__aj_not_found $argv
|
||||||
set_color red
|
|
||||||
echo $output
|
|
||||||
set_color normal
|
|
||||||
cd $output
|
|
||||||
else
|
|
||||||
__aj_err "autojump: directory '"$argv"' not found"
|
|
||||||
__aj_err "\n$output\n"
|
|
||||||
__aj_err "Try `autojump --help` for more information."
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
# jump to child directory (subdirectory of current path)
|
|
||||||
function jc
|
function jc
|
||||||
switch "$argv"
|
switch "$argv"
|
||||||
case '-*'
|
case '-*'
|
||||||
@ -78,30 +58,24 @@ function jc
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
# open autojump results in file browser
|
|
||||||
function jo
|
function jo
|
||||||
set -l output (autojump $argv)
|
if test -z (autojump $argv)
|
||||||
if test -d "$output"
|
__aj_not_found $argv
|
||||||
switch $OSTYPE
|
else
|
||||||
case 'linux*'
|
switch (sh -c 'echo ${OSTYPE}')
|
||||||
|
case linux-gnu
|
||||||
xdg-open (autojump $argv)
|
xdg-open (autojump $argv)
|
||||||
case 'darwin*'
|
case 'darwin*'
|
||||||
open (autojump $argv)
|
open (autojump $argv)
|
||||||
case cygwin
|
case cygwin
|
||||||
cygstart "" (cygpath -w -a (pwd))
|
cygstart "" (cygpath -w -a (pwd))
|
||||||
case '*'
|
case '*'
|
||||||
__aj_err "Unknown operating system: \"$OSTYPE\""
|
__aj_error "Unknown operating system."
|
||||||
end
|
end
|
||||||
else
|
echo end
|
||||||
__aj_err "autojump: directory '"$argv"' not found"
|
|
||||||
__aj_err "\n$output\n"
|
|
||||||
__aj_err "Try `autojump --help` for more information."
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
# open autojump results (child directory) in file browser
|
|
||||||
function jco
|
function jco
|
||||||
switch "$argv"
|
switch "$argv"
|
||||||
case '-*'
|
case '-*'
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
local AUTOJUMP_DIR = debug.getinfo(1, "S").source:match[[^@?(.*[\/])[^\/]-$]] .. "..\\AutoJump"
|
|
||||||
local AUTOJUMP_BIN_DIR = AUTOJUMP_DIR .. "\\bin"
|
|
||||||
local AUTOJUMP_BIN = (AUTOJUMP_BIN_DIR or clink.get_env("LOCALAPPDATA") .. "\\autojump\\bin") .. "\\autojump"
|
|
||||||
|
|
||||||
function autojump_add_to_database()
|
|
||||||
os.execute("python " .. "\"" .. AUTOJUMP_BIN .. "\"" .. " --add " .. "\"" .. clink.get_cwd() .. "\"" .. " 2> " .. clink.get_env("TEMP") .. "\\autojump_error.txt")
|
|
||||||
end
|
|
||||||
|
|
||||||
clink.prompt.register_filter(autojump_add_to_database, 99)
|
|
||||||
|
|
||||||
function autojump_completion(word)
|
|
||||||
for line in io.popen("python " .. "\"" .. AUTOJUMP_BIN .. "\"" .. " --complete " .. word):lines() do
|
|
||||||
clink.add_match(line)
|
|
||||||
end
|
|
||||||
return {}
|
|
||||||
end
|
|
||||||
|
|
||||||
local autojump_parser = clink.arg.new_parser()
|
|
||||||
autojump_parser:set_arguments({ autojump_completion })
|
|
||||||
|
|
||||||
clink.arg.register_parser("j", autojump_parser)
|
|
@ -1,26 +1,21 @@
|
|||||||
# the login $SHELL isn't always the one used
|
# source autojump on BASH or ZSH depending on the shell
|
||||||
# NOTE: problems might occur if /bin/sh is symlinked to /bin/bash
|
|
||||||
if [ -n "${BASH}" ]; then
|
shell=`echo ${SHELL} | awk -F/ '{ print $NF }'`
|
||||||
shell="bash"
|
|
||||||
elif [ -n "${ZSH_NAME}" ]; then
|
|
||||||
shell="zsh"
|
|
||||||
elif [ -n "${__fish_datadir}" ]; then
|
|
||||||
shell="fish"
|
|
||||||
elif [ -n "${version}" ]; then
|
|
||||||
shell="tcsh"
|
|
||||||
else
|
|
||||||
shell=$(echo ${SHELL} | awk -F/ '{ print $NF }')
|
|
||||||
fi
|
|
||||||
|
|
||||||
# prevent circular loop for sh shells
|
# prevent circular loop for sh shells
|
||||||
if [ "${shell}" = "sh" ]; then
|
if [ "${shell}" = "sh" ]; then
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
# check local install
|
# check local install
|
||||||
elif [ -s ~/.autojump/share/autojump/autojump.${shell} ]; then
|
elif [ -s ~/.autojump/etc/profile.d/autojump.${shell} ]; then
|
||||||
source ~/.autojump/share/autojump/autojump.${shell}
|
source ~/.autojump/etc/profile.d/autojump.${shell}
|
||||||
|
|
||||||
# check global install
|
# check global install
|
||||||
elif [ -s /usr/local/share/autojump/autojump.${shell} ]; then
|
elif [ -s /etc/profile.d/autojump.${shell} ]; then
|
||||||
source /usr/local/share/autojump/autojump.${shell}
|
source /etc/profile.d/autojump.${shell}
|
||||||
|
|
||||||
|
# check custom install locations (modified by Homebrew or using --destdir option)
|
||||||
|
#custom# elif [ -s destdir_install/autojump.${shell} ]; then
|
||||||
|
#custom# source destdir_install/autojump.${shell}
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
# 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`'
|
|
126
bin/autojump.zsh
126
bin/autojump.zsh
@ -1,124 +1,94 @@
|
|||||||
export AUTOJUMP_SOURCED=1
|
# determine the data directory according to the XDG Base Directory Specification
|
||||||
|
if [[ -n ${XDG_DATA_HOME} ]] && [[ ${XDG_DATA_HOME} == *${USER}* ]]; then
|
||||||
# set user installation paths
|
export AUTOJUMP_DATA_DIR="${XDG_DATA_HOME}/autojump"
|
||||||
if [[ -d ~/.autojump/bin ]]; then
|
|
||||||
path=(~/.autojump/bin ${path})
|
|
||||||
fi
|
|
||||||
if [[ -d ~/.autojump/functions ]]; then
|
|
||||||
fpath=(~/.autojump/functions ${fpath})
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
# set homebrew installation paths
|
|
||||||
if command -v brew &>/dev/null; then
|
|
||||||
local brew_prefix=${BREW_PREFIX:-$(brew --prefix)}
|
|
||||||
if [[ -d "${brew_prefix}/share/zsh/site-functions" ]]; then
|
|
||||||
fpath=("${brew_prefix}/share/zsh/site-functions" ${fpath})
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
# set error file location
|
|
||||||
if [[ "$(uname)" == "Darwin" ]]; then
|
|
||||||
export AUTOJUMP_ERROR_PATH=~/Library/autojump/errors.log
|
|
||||||
elif [[ -n "${XDG_DATA_HOME}" ]]; then
|
|
||||||
export AUTOJUMP_ERROR_PATH="${XDG_DATA_HOME}/autojump/errors.log"
|
|
||||||
else
|
else
|
||||||
export AUTOJUMP_ERROR_PATH=~/.local/share/autojump/errors.log
|
export AUTOJUMP_DATA_DIR=${HOME}/.local/share/autojump
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ! -d ${AUTOJUMP_ERROR_PATH:h} ]]; then
|
if [[ ! -e ${AUTOJUMP_DATA_DIR} ]]; then
|
||||||
mkdir -p ${AUTOJUMP_ERROR_PATH:h}
|
mkdir -p "${AUTOJUMP_DATA_DIR}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# set paths if necessary for local installations
|
||||||
|
if [[ -d ${HOME}/.autojump ]]; then
|
||||||
|
path=(${HOME}/.autojump/bin ${path})
|
||||||
|
fpath=(${HOME}/.autojump/functions/ ${fpath})
|
||||||
|
fi
|
||||||
|
|
||||||
# change pwd hook
|
# set fpath if necessary for homebrew installation
|
||||||
autojump_chpwd() {
|
command -v brew &>/dev/null \
|
||||||
if [[ -f "${AUTOJUMP_ERROR_PATH}" ]]; then
|
&& [[ -d "`brew --prefix`/share/zsh/site-functions" ]] \
|
||||||
autojump --add "$(pwd)" >/dev/null 2>>${AUTOJUMP_ERROR_PATH} &!
|
&& fpath=(`brew --prefix`/share/zsh/site-functions ${fpath})
|
||||||
|
|
||||||
|
function autojump_chpwd() {
|
||||||
|
if [[ "${AUTOJUMP_KEEP_SYMLINKS}" == "1" ]]; then
|
||||||
|
_PWD_ARGS=""
|
||||||
else
|
else
|
||||||
autojump --add "$(pwd)" >/dev/null &!
|
_PWD_ARGS="-P"
|
||||||
fi
|
fi
|
||||||
|
{ (autojump -a "$(pwd ${_PWD_ARGS})"&)>/dev/null 2>>|${AUTOJUMP_DATA_DIR}/autojump_errors ; } 2>/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
typeset -gaU chpwd_functions
|
typeset -gaU chpwd_functions
|
||||||
chpwd_functions+=autojump_chpwd
|
chpwd_functions+=autojump_chpwd
|
||||||
|
|
||||||
|
function j {
|
||||||
# default autojump command
|
# Cannot use =~ due to MacPorts zsh v4.2, see issue #125.
|
||||||
j() {
|
if [[ ${@} == -* ]]; then
|
||||||
if [[ ${1} == -* ]] && [[ ${1} != "--" ]]; then
|
|
||||||
autojump ${@}
|
autojump ${@}
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
setopt localoptions noautonamedirs
|
local new_path="$(autojump ${@})"
|
||||||
local output="$(autojump ${@})"
|
if [ -d "${new_path}" ]; then
|
||||||
if [[ -d "${output}" ]]; then
|
echo -e "\\033[31m${new_path}\\033[0m"
|
||||||
if [ -t 1 ]; then # if stdout is a terminal, use colors
|
cd "${new_path}"
|
||||||
echo -e "\\033[31m${output}\\033[0m"
|
|
||||||
else
|
|
||||||
echo -e "${output}"
|
|
||||||
fi
|
|
||||||
cd "${output}"
|
|
||||||
else
|
else
|
||||||
echo "autojump: directory '${@}' not found"
|
echo "autojump: directory '${@}' not found"
|
||||||
echo "\n${output}\n"
|
|
||||||
echo "Try \`autojump --help\` for more information."
|
echo "Try \`autojump --help\` for more information."
|
||||||
false
|
false
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function jc {
|
||||||
# jump to child directory (subdirectory of current path)
|
if [[ ${@} == -* ]]; then
|
||||||
jc() {
|
j ${@}
|
||||||
if [[ ${1} == -* ]] && [[ ${1} != "--" ]]; then
|
|
||||||
autojump ${@}
|
|
||||||
return
|
|
||||||
else
|
else
|
||||||
j $(pwd) ${@}
|
j $(pwd)/ ${@}
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function jo {
|
||||||
# open autojump results in file browser
|
if [[ ${@} == -* ]]; then
|
||||||
jo() {
|
j ${@}
|
||||||
if [[ ${1} == -* ]] && [[ ${1} != "--" ]]; then
|
|
||||||
autojump ${@}
|
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
setopt localoptions noautonamedirs
|
if [ -z $(autojump $@) ]; then
|
||||||
local output="$(autojump ${@})"
|
echo "autojump: directory '${@}' not found"
|
||||||
if [[ -d "${output}" ]]; then
|
echo "Try \`autojump --help\` for more information."
|
||||||
|
false
|
||||||
|
else
|
||||||
case ${OSTYPE} in
|
case ${OSTYPE} in
|
||||||
linux*)
|
linux-gnu)
|
||||||
xdg-open "${output}"
|
xdg-open "$(autojump $@)"
|
||||||
;;
|
;;
|
||||||
darwin*)
|
darwin*)
|
||||||
open "${output}"
|
open "$(autojump $@)"
|
||||||
;;
|
;;
|
||||||
cygwin)
|
cygwin)
|
||||||
cygstart "" $(cygpath -w -a ${output})
|
cygstart "" $(cygpath -w -a $(pwd))
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Unknown operating system: ${OSTYPE}" 1>&2
|
echo "Unknown operating system." 1>&2
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
else
|
|
||||||
echo "autojump: directory '${@}' not found"
|
|
||||||
echo "\n${output}\n"
|
|
||||||
echo "Try \`autojump --help\` for more information."
|
|
||||||
false
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function jco {
|
||||||
# open autojump results (child directory) in file browser
|
if [[ ${@} == -* ]]; then
|
||||||
jco() {
|
j ${@}
|
||||||
if [[ ${1} == -* ]] && [[ ${1} != "--" ]]; then
|
|
||||||
autojump ${@}
|
|
||||||
return
|
|
||||||
else
|
else
|
||||||
jo $(pwd) ${@}
|
jo $(pwd) ${@}
|
||||||
fi
|
fi
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Author: Steven J. Bethard <steven.bethard@gmail.com>.
|
# Author: Steven J. Bethard <steven.bethard@gmail.com>.
|
||||||
# flake8: noqa
|
|
||||||
"""Command-line parsing library
|
"""Command-line parsing library
|
||||||
|
|
||||||
This module is an optparse-inspired command-line parsing library that:
|
This module is an optparse-inspired command-line parsing library that:
|
||||||
@ -62,7 +61,7 @@ considered public as object names -- the API of the formatter objects is
|
|||||||
still considered an implementation detail.)
|
still considered an implementation detail.)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__version__ = '1.2.1'
|
__version__ = '1.2'
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'ArgumentParser',
|
'ArgumentParser',
|
||||||
'ArgumentError',
|
'ArgumentError',
|
||||||
@ -107,7 +106,8 @@ try:
|
|||||||
except NameError:
|
except NameError:
|
||||||
# for python < 2.4 compatibility:
|
# for python < 2.4 compatibility:
|
||||||
def sorted(iterable, reverse=False):
|
def sorted(iterable, reverse=False):
|
||||||
result = sorted(iterable)
|
result = list(iterable)
|
||||||
|
result.sort()
|
||||||
if reverse:
|
if reverse:
|
||||||
result.reverse()
|
result.reverse()
|
||||||
return result
|
return result
|
||||||
@ -130,9 +130,7 @@ _UNRECOGNIZED_ARGS_ATTR = '_unrecognized_args'
|
|||||||
# Utility functions and classes
|
# Utility functions and classes
|
||||||
# =============================
|
# =============================
|
||||||
|
|
||||||
|
|
||||||
class _AttributeHolder(object):
|
class _AttributeHolder(object):
|
||||||
|
|
||||||
"""Abstract base class that provides __repr__.
|
"""Abstract base class that provides __repr__.
|
||||||
|
|
||||||
The __repr__ method returns a string in the format::
|
The __repr__ method returns a string in the format::
|
||||||
@ -168,20 +166,17 @@ def _ensure_value(namespace, name, value):
|
|||||||
# ===============
|
# ===============
|
||||||
|
|
||||||
class HelpFormatter(object):
|
class HelpFormatter(object):
|
||||||
|
|
||||||
"""Formatter for generating usage messages and argument help strings.
|
"""Formatter for generating usage messages and argument help strings.
|
||||||
|
|
||||||
Only the name of this class is considered a public API. All the methods
|
Only the name of this class is considered a public API. All the methods
|
||||||
provided by the class are considered an implementation detail.
|
provided by the class are considered an implementation detail.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(self,
|
||||||
self,
|
prog,
|
||||||
prog,
|
indent_increment=2,
|
||||||
indent_increment=2,
|
max_help_position=24,
|
||||||
max_help_position=24,
|
width=None):
|
||||||
width=None,
|
|
||||||
):
|
|
||||||
|
|
||||||
# default setting for width
|
# default setting for width
|
||||||
if width is None:
|
if width is None:
|
||||||
@ -288,10 +283,8 @@ class HelpFormatter(object):
|
|||||||
# update the maximum item length
|
# update the maximum item length
|
||||||
invocation_length = max([len(s) for s in invocations])
|
invocation_length = max([len(s) for s in invocations])
|
||||||
action_length = invocation_length + self._current_indent
|
action_length = invocation_length + self._current_indent
|
||||||
self._action_max_length = max(
|
self._action_max_length = max(self._action_max_length,
|
||||||
self._action_max_length,
|
action_length)
|
||||||
action_length,
|
|
||||||
)
|
|
||||||
|
|
||||||
# add the item to the list
|
# add the item to the list
|
||||||
self._add_item(self._format_action, [action])
|
self._add_item(self._format_action, [action])
|
||||||
@ -311,11 +304,9 @@ class HelpFormatter(object):
|
|||||||
return help
|
return help
|
||||||
|
|
||||||
def _join_parts(self, part_strings):
|
def _join_parts(self, part_strings):
|
||||||
return ''.join([
|
return ''.join([part
|
||||||
part
|
for part in part_strings
|
||||||
for part in part_strings
|
if part and part is not SUPPRESS])
|
||||||
if part and part is not SUPPRESS
|
|
||||||
])
|
|
||||||
|
|
||||||
def _format_usage(self, usage, actions, groups, prefix):
|
def _format_usage(self, usage, actions, groups, prefix):
|
||||||
if prefix is None:
|
if prefix is None:
|
||||||
@ -514,10 +505,8 @@ class HelpFormatter(object):
|
|||||||
|
|
||||||
def _format_action(self, action):
|
def _format_action(self, action):
|
||||||
# determine the required width and the entry label
|
# determine the required width and the entry label
|
||||||
help_position = min(
|
help_position = min(self._action_max_length + 2,
|
||||||
self._action_max_length + 2,
|
self._max_help_position)
|
||||||
self._max_help_position,
|
|
||||||
)
|
|
||||||
help_width = self._width - help_position
|
help_width = self._width - help_position
|
||||||
action_width = help_position - self._current_indent - 2
|
action_width = help_position - self._current_indent - 2
|
||||||
action_header = self._format_action_invocation(action)
|
action_header = self._format_action_invocation(action)
|
||||||
@ -649,17 +638,14 @@ class HelpFormatter(object):
|
|||||||
|
|
||||||
def _fill_text(self, text, width, indent):
|
def _fill_text(self, text, width, indent):
|
||||||
text = self._whitespace_matcher.sub(' ', text).strip()
|
text = self._whitespace_matcher.sub(' ', text).strip()
|
||||||
return _textwrap.fill(
|
return _textwrap.fill(text, width, initial_indent=indent,
|
||||||
text, width, initial_indent=indent,
|
subsequent_indent=indent)
|
||||||
subsequent_indent=indent,
|
|
||||||
)
|
|
||||||
|
|
||||||
def _get_help_string(self, action):
|
def _get_help_string(self, action):
|
||||||
return action.help
|
return action.help
|
||||||
|
|
||||||
|
|
||||||
class RawDescriptionHelpFormatter(HelpFormatter):
|
class RawDescriptionHelpFormatter(HelpFormatter):
|
||||||
|
|
||||||
"""Help message formatter which retains any formatting in descriptions.
|
"""Help message formatter which retains any formatting in descriptions.
|
||||||
|
|
||||||
Only the name of this class is considered a public API. All the methods
|
Only the name of this class is considered a public API. All the methods
|
||||||
@ -671,7 +657,6 @@ class RawDescriptionHelpFormatter(HelpFormatter):
|
|||||||
|
|
||||||
|
|
||||||
class RawTextHelpFormatter(RawDescriptionHelpFormatter):
|
class RawTextHelpFormatter(RawDescriptionHelpFormatter):
|
||||||
|
|
||||||
"""Help message formatter which retains formatting of all help text.
|
"""Help message formatter which retains formatting of all help text.
|
||||||
|
|
||||||
Only the name of this class is considered a public API. All the methods
|
Only the name of this class is considered a public API. All the methods
|
||||||
@ -683,7 +668,6 @@ class RawTextHelpFormatter(RawDescriptionHelpFormatter):
|
|||||||
|
|
||||||
|
|
||||||
class ArgumentDefaultsHelpFormatter(HelpFormatter):
|
class ArgumentDefaultsHelpFormatter(HelpFormatter):
|
||||||
|
|
||||||
"""Help message formatter which adds default values to argument help.
|
"""Help message formatter which adds default values to argument help.
|
||||||
|
|
||||||
Only the name of this class is considered a public API. All the methods
|
Only the name of this class is considered a public API. All the methods
|
||||||
@ -708,7 +692,7 @@ def _get_action_name(argument):
|
|||||||
if argument is None:
|
if argument is None:
|
||||||
return None
|
return None
|
||||||
elif argument.option_strings:
|
elif argument.option_strings:
|
||||||
return '/'.join(argument.option_strings)
|
return '/'.join(argument.option_strings)
|
||||||
elif argument.metavar not in (None, SUPPRESS):
|
elif argument.metavar not in (None, SUPPRESS):
|
||||||
return argument.metavar
|
return argument.metavar
|
||||||
elif argument.dest not in (None, SUPPRESS):
|
elif argument.dest not in (None, SUPPRESS):
|
||||||
@ -718,7 +702,6 @@ def _get_action_name(argument):
|
|||||||
|
|
||||||
|
|
||||||
class ArgumentError(Exception):
|
class ArgumentError(Exception):
|
||||||
|
|
||||||
"""An error from creating or using an argument (optional or positional).
|
"""An error from creating or using an argument (optional or positional).
|
||||||
|
|
||||||
The string value of this exception is the message, augmented with
|
The string value of this exception is the message, augmented with
|
||||||
@ -734,14 +717,11 @@ class ArgumentError(Exception):
|
|||||||
format = '%(message)s'
|
format = '%(message)s'
|
||||||
else:
|
else:
|
||||||
format = 'argument %(argument_name)s: %(message)s'
|
format = 'argument %(argument_name)s: %(message)s'
|
||||||
return format % dict(
|
return format % dict(message=self.message,
|
||||||
message=self.message,
|
argument_name=self.argument_name)
|
||||||
argument_name=self.argument_name,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class ArgumentTypeError(Exception):
|
class ArgumentTypeError(Exception):
|
||||||
|
|
||||||
"""An error from trying to convert a command line string to a type."""
|
"""An error from trying to convert a command line string to a type."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -751,7 +731,6 @@ class ArgumentTypeError(Exception):
|
|||||||
# ==============
|
# ==============
|
||||||
|
|
||||||
class Action(_AttributeHolder):
|
class Action(_AttributeHolder):
|
||||||
|
|
||||||
"""Information about how to convert command line strings to Python objects.
|
"""Information about how to convert command line strings to Python objects.
|
||||||
|
|
||||||
Action objects are used by an ArgumentParser to represent the information
|
Action objects are used by an ArgumentParser to represent the information
|
||||||
@ -802,19 +781,17 @@ class Action(_AttributeHolder):
|
|||||||
help string. If None, the 'dest' value will be used as the name.
|
help string. If None, the 'dest' value will be used as the name.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(self,
|
||||||
self,
|
option_strings,
|
||||||
option_strings,
|
dest,
|
||||||
dest,
|
nargs=None,
|
||||||
nargs=None,
|
const=None,
|
||||||
const=None,
|
default=None,
|
||||||
default=None,
|
type=None,
|
||||||
type=None,
|
choices=None,
|
||||||
choices=None,
|
required=False,
|
||||||
required=False,
|
help=None,
|
||||||
help=None,
|
metavar=None):
|
||||||
metavar=None,
|
|
||||||
):
|
|
||||||
self.option_strings = option_strings
|
self.option_strings = option_strings
|
||||||
self.dest = dest
|
self.dest = dest
|
||||||
self.nargs = nargs
|
self.nargs = nargs
|
||||||
@ -846,25 +823,21 @@ class Action(_AttributeHolder):
|
|||||||
|
|
||||||
class _StoreAction(Action):
|
class _StoreAction(Action):
|
||||||
|
|
||||||
def __init__(
|
def __init__(self,
|
||||||
self,
|
option_strings,
|
||||||
option_strings,
|
dest,
|
||||||
dest,
|
nargs=None,
|
||||||
nargs=None,
|
const=None,
|
||||||
const=None,
|
default=None,
|
||||||
default=None,
|
type=None,
|
||||||
type=None,
|
choices=None,
|
||||||
choices=None,
|
required=False,
|
||||||
required=False,
|
help=None,
|
||||||
help=None,
|
metavar=None):
|
||||||
metavar=None,
|
|
||||||
):
|
|
||||||
if nargs == 0:
|
if nargs == 0:
|
||||||
raise ValueError(
|
raise ValueError('nargs for store actions must be > 0; if you '
|
||||||
'nargs for store actions must be > 0; if you '
|
'have nothing to store, actions such as store '
|
||||||
'have nothing to store, actions such as store '
|
'true or store const may be more appropriate')
|
||||||
'true or store const may be more appropriate',
|
|
||||||
)
|
|
||||||
if const is not None and nargs != OPTIONAL:
|
if const is not None and nargs != OPTIONAL:
|
||||||
raise ValueError('nargs must be %r to supply const' % OPTIONAL)
|
raise ValueError('nargs must be %r to supply const' % OPTIONAL)
|
||||||
super(_StoreAction, self).__init__(
|
super(_StoreAction, self).__init__(
|
||||||
@ -877,8 +850,7 @@ class _StoreAction(Action):
|
|||||||
choices=choices,
|
choices=choices,
|
||||||
required=required,
|
required=required,
|
||||||
help=help,
|
help=help,
|
||||||
metavar=metavar,
|
metavar=metavar)
|
||||||
)
|
|
||||||
|
|
||||||
def __call__(self, parser, namespace, values, option_string=None):
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
setattr(namespace, self.dest, values)
|
setattr(namespace, self.dest, values)
|
||||||
@ -886,16 +858,14 @@ class _StoreAction(Action):
|
|||||||
|
|
||||||
class _StoreConstAction(Action):
|
class _StoreConstAction(Action):
|
||||||
|
|
||||||
def __init__(
|
def __init__(self,
|
||||||
self,
|
option_strings,
|
||||||
option_strings,
|
dest,
|
||||||
dest,
|
const,
|
||||||
const,
|
default=None,
|
||||||
default=None,
|
required=False,
|
||||||
required=False,
|
help=None,
|
||||||
help=None,
|
metavar=None):
|
||||||
metavar=None,
|
|
||||||
):
|
|
||||||
super(_StoreConstAction, self).__init__(
|
super(_StoreConstAction, self).__init__(
|
||||||
option_strings=option_strings,
|
option_strings=option_strings,
|
||||||
dest=dest,
|
dest=dest,
|
||||||
@ -903,8 +873,7 @@ class _StoreConstAction(Action):
|
|||||||
const=const,
|
const=const,
|
||||||
default=default,
|
default=default,
|
||||||
required=required,
|
required=required,
|
||||||
help=help,
|
help=help)
|
||||||
)
|
|
||||||
|
|
||||||
def __call__(self, parser, namespace, values, option_string=None):
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
setattr(namespace, self.dest, self.const)
|
setattr(namespace, self.dest, self.const)
|
||||||
@ -912,65 +881,55 @@ class _StoreConstAction(Action):
|
|||||||
|
|
||||||
class _StoreTrueAction(_StoreConstAction):
|
class _StoreTrueAction(_StoreConstAction):
|
||||||
|
|
||||||
def __init__(
|
def __init__(self,
|
||||||
self,
|
option_strings,
|
||||||
option_strings,
|
dest,
|
||||||
dest,
|
default=False,
|
||||||
default=False,
|
required=False,
|
||||||
required=False,
|
help=None):
|
||||||
help=None,
|
|
||||||
):
|
|
||||||
super(_StoreTrueAction, self).__init__(
|
super(_StoreTrueAction, self).__init__(
|
||||||
option_strings=option_strings,
|
option_strings=option_strings,
|
||||||
dest=dest,
|
dest=dest,
|
||||||
const=True,
|
const=True,
|
||||||
default=default,
|
default=default,
|
||||||
required=required,
|
required=required,
|
||||||
help=help,
|
help=help)
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class _StoreFalseAction(_StoreConstAction):
|
class _StoreFalseAction(_StoreConstAction):
|
||||||
|
|
||||||
def __init__(
|
def __init__(self,
|
||||||
self,
|
option_strings,
|
||||||
option_strings,
|
dest,
|
||||||
dest,
|
default=True,
|
||||||
default=True,
|
required=False,
|
||||||
required=False,
|
help=None):
|
||||||
help=None,
|
|
||||||
):
|
|
||||||
super(_StoreFalseAction, self).__init__(
|
super(_StoreFalseAction, self).__init__(
|
||||||
option_strings=option_strings,
|
option_strings=option_strings,
|
||||||
dest=dest,
|
dest=dest,
|
||||||
const=False,
|
const=False,
|
||||||
default=default,
|
default=default,
|
||||||
required=required,
|
required=required,
|
||||||
help=help,
|
help=help)
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class _AppendAction(Action):
|
class _AppendAction(Action):
|
||||||
|
|
||||||
def __init__(
|
def __init__(self,
|
||||||
self,
|
option_strings,
|
||||||
option_strings,
|
dest,
|
||||||
dest,
|
nargs=None,
|
||||||
nargs=None,
|
const=None,
|
||||||
const=None,
|
default=None,
|
||||||
default=None,
|
type=None,
|
||||||
type=None,
|
choices=None,
|
||||||
choices=None,
|
required=False,
|
||||||
required=False,
|
help=None,
|
||||||
help=None,
|
metavar=None):
|
||||||
metavar=None,
|
|
||||||
):
|
|
||||||
if nargs == 0:
|
if nargs == 0:
|
||||||
raise ValueError(
|
raise ValueError('nargs for append actions must be > 0; if arg '
|
||||||
'nargs for append actions must be > 0; if arg '
|
'strings are not supplying the value to append, '
|
||||||
'strings are not supplying the value to append, '
|
'the append const action may be more appropriate')
|
||||||
'the append const action may be more appropriate',
|
|
||||||
)
|
|
||||||
if const is not None and nargs != OPTIONAL:
|
if const is not None and nargs != OPTIONAL:
|
||||||
raise ValueError('nargs must be %r to supply const' % OPTIONAL)
|
raise ValueError('nargs must be %r to supply const' % OPTIONAL)
|
||||||
super(_AppendAction, self).__init__(
|
super(_AppendAction, self).__init__(
|
||||||
@ -983,8 +942,7 @@ class _AppendAction(Action):
|
|||||||
choices=choices,
|
choices=choices,
|
||||||
required=required,
|
required=required,
|
||||||
help=help,
|
help=help,
|
||||||
metavar=metavar,
|
metavar=metavar)
|
||||||
)
|
|
||||||
|
|
||||||
def __call__(self, parser, namespace, values, option_string=None):
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
items = _copy.copy(_ensure_value(namespace, self.dest, []))
|
items = _copy.copy(_ensure_value(namespace, self.dest, []))
|
||||||
@ -994,16 +952,14 @@ class _AppendAction(Action):
|
|||||||
|
|
||||||
class _AppendConstAction(Action):
|
class _AppendConstAction(Action):
|
||||||
|
|
||||||
def __init__(
|
def __init__(self,
|
||||||
self,
|
option_strings,
|
||||||
option_strings,
|
dest,
|
||||||
dest,
|
const,
|
||||||
const,
|
default=None,
|
||||||
default=None,
|
required=False,
|
||||||
required=False,
|
help=None,
|
||||||
help=None,
|
metavar=None):
|
||||||
metavar=None,
|
|
||||||
):
|
|
||||||
super(_AppendConstAction, self).__init__(
|
super(_AppendConstAction, self).__init__(
|
||||||
option_strings=option_strings,
|
option_strings=option_strings,
|
||||||
dest=dest,
|
dest=dest,
|
||||||
@ -1012,8 +968,7 @@ class _AppendConstAction(Action):
|
|||||||
default=default,
|
default=default,
|
||||||
required=required,
|
required=required,
|
||||||
help=help,
|
help=help,
|
||||||
metavar=metavar,
|
metavar=metavar)
|
||||||
)
|
|
||||||
|
|
||||||
def __call__(self, parser, namespace, values, option_string=None):
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
items = _copy.copy(_ensure_value(namespace, self.dest, []))
|
items = _copy.copy(_ensure_value(namespace, self.dest, []))
|
||||||
@ -1023,22 +978,19 @@ class _AppendConstAction(Action):
|
|||||||
|
|
||||||
class _CountAction(Action):
|
class _CountAction(Action):
|
||||||
|
|
||||||
def __init__(
|
def __init__(self,
|
||||||
self,
|
option_strings,
|
||||||
option_strings,
|
dest,
|
||||||
dest,
|
default=None,
|
||||||
default=None,
|
required=False,
|
||||||
required=False,
|
help=None):
|
||||||
help=None,
|
|
||||||
):
|
|
||||||
super(_CountAction, self).__init__(
|
super(_CountAction, self).__init__(
|
||||||
option_strings=option_strings,
|
option_strings=option_strings,
|
||||||
dest=dest,
|
dest=dest,
|
||||||
nargs=0,
|
nargs=0,
|
||||||
default=default,
|
default=default,
|
||||||
required=required,
|
required=required,
|
||||||
help=help,
|
help=help)
|
||||||
)
|
|
||||||
|
|
||||||
def __call__(self, parser, namespace, values, option_string=None):
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
new_count = _ensure_value(namespace, self.dest, 0) + 1
|
new_count = _ensure_value(namespace, self.dest, 0) + 1
|
||||||
@ -1047,20 +999,17 @@ class _CountAction(Action):
|
|||||||
|
|
||||||
class _HelpAction(Action):
|
class _HelpAction(Action):
|
||||||
|
|
||||||
def __init__(
|
def __init__(self,
|
||||||
self,
|
option_strings,
|
||||||
option_strings,
|
dest=SUPPRESS,
|
||||||
dest=SUPPRESS,
|
default=SUPPRESS,
|
||||||
default=SUPPRESS,
|
help=None):
|
||||||
help=None,
|
|
||||||
):
|
|
||||||
super(_HelpAction, self).__init__(
|
super(_HelpAction, self).__init__(
|
||||||
option_strings=option_strings,
|
option_strings=option_strings,
|
||||||
dest=dest,
|
dest=dest,
|
||||||
default=default,
|
default=default,
|
||||||
nargs=0,
|
nargs=0,
|
||||||
help=help,
|
help=help)
|
||||||
)
|
|
||||||
|
|
||||||
def __call__(self, parser, namespace, values, option_string=None):
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
parser.print_help()
|
parser.print_help()
|
||||||
@ -1069,21 +1018,18 @@ class _HelpAction(Action):
|
|||||||
|
|
||||||
class _VersionAction(Action):
|
class _VersionAction(Action):
|
||||||
|
|
||||||
def __init__(
|
def __init__(self,
|
||||||
self,
|
option_strings,
|
||||||
option_strings,
|
version=None,
|
||||||
version=None,
|
dest=SUPPRESS,
|
||||||
dest=SUPPRESS,
|
default=SUPPRESS,
|
||||||
default=SUPPRESS,
|
help="show program's version number and exit"):
|
||||||
help="show program's version number and exit",
|
|
||||||
):
|
|
||||||
super(_VersionAction, self).__init__(
|
super(_VersionAction, self).__init__(
|
||||||
option_strings=option_strings,
|
option_strings=option_strings,
|
||||||
dest=dest,
|
dest=dest,
|
||||||
default=default,
|
default=default,
|
||||||
nargs=0,
|
nargs=0,
|
||||||
help=help,
|
help=help)
|
||||||
)
|
|
||||||
self.version = version
|
self.version = version
|
||||||
|
|
||||||
def __call__(self, parser, namespace, values, option_string=None):
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
@ -1103,15 +1049,13 @@ class _SubParsersAction(Action):
|
|||||||
sup = super(_SubParsersAction._ChoicesPseudoAction, self)
|
sup = super(_SubParsersAction._ChoicesPseudoAction, self)
|
||||||
sup.__init__(option_strings=[], dest=name, help=help)
|
sup.__init__(option_strings=[], dest=name, help=help)
|
||||||
|
|
||||||
def __init__(
|
def __init__(self,
|
||||||
self,
|
option_strings,
|
||||||
option_strings,
|
prog,
|
||||||
prog,
|
parser_class,
|
||||||
parser_class,
|
dest=SUPPRESS,
|
||||||
dest=SUPPRESS,
|
help=None,
|
||||||
help=None,
|
metavar=None):
|
||||||
metavar=None,
|
|
||||||
):
|
|
||||||
|
|
||||||
self._prog_prefix = prog
|
self._prog_prefix = prog
|
||||||
self._parser_class = parser_class
|
self._parser_class = parser_class
|
||||||
@ -1124,8 +1068,7 @@ class _SubParsersAction(Action):
|
|||||||
nargs=PARSER,
|
nargs=PARSER,
|
||||||
choices=self._name_parser_map,
|
choices=self._name_parser_map,
|
||||||
help=help,
|
help=help,
|
||||||
metavar=metavar,
|
metavar=metavar)
|
||||||
)
|
|
||||||
|
|
||||||
def add_parser(self, name, **kwargs):
|
def add_parser(self, name, **kwargs):
|
||||||
# set prog from the existing prefix
|
# set prog from the existing prefix
|
||||||
@ -1165,9 +1108,7 @@ class _SubParsersAction(Action):
|
|||||||
# parse all the remaining options into the namespace
|
# parse all the remaining options into the namespace
|
||||||
# store any unrecognized options on the object, so that the top
|
# store any unrecognized options on the object, so that the top
|
||||||
# level parser can decide what to do with them
|
# level parser can decide what to do with them
|
||||||
namespace, arg_strings = parser.parse_known_args(
|
namespace, arg_strings = parser.parse_known_args(arg_strings, namespace)
|
||||||
arg_strings, namespace,
|
|
||||||
)
|
|
||||||
if arg_strings:
|
if arg_strings:
|
||||||
vars(namespace).setdefault(_UNRECOGNIZED_ARGS_ATTR, [])
|
vars(namespace).setdefault(_UNRECOGNIZED_ARGS_ATTR, [])
|
||||||
getattr(namespace, _UNRECOGNIZED_ARGS_ATTR).extend(arg_strings)
|
getattr(namespace, _UNRECOGNIZED_ARGS_ATTR).extend(arg_strings)
|
||||||
@ -1178,7 +1119,6 @@ class _SubParsersAction(Action):
|
|||||||
# ==============
|
# ==============
|
||||||
|
|
||||||
class FileType(object):
|
class FileType(object):
|
||||||
|
|
||||||
"""Factory for creating file object types
|
"""Factory for creating file object types
|
||||||
|
|
||||||
Instances of FileType are typically passed as type= arguments to the
|
Instances of FileType are typically passed as type= arguments to the
|
||||||
@ -1221,9 +1161,7 @@ class FileType(object):
|
|||||||
# Optional and Positional Parsing
|
# Optional and Positional Parsing
|
||||||
# ===========================
|
# ===========================
|
||||||
|
|
||||||
|
|
||||||
class Namespace(_AttributeHolder):
|
class Namespace(_AttributeHolder):
|
||||||
|
|
||||||
"""Simple object for storing attributes.
|
"""Simple object for storing attributes.
|
||||||
|
|
||||||
Implements equality by attribute names and values, and provides a simple
|
Implements equality by attribute names and values, and provides a simple
|
||||||
@ -1248,13 +1186,11 @@ class Namespace(_AttributeHolder):
|
|||||||
|
|
||||||
class _ActionsContainer(object):
|
class _ActionsContainer(object):
|
||||||
|
|
||||||
def __init__(
|
def __init__(self,
|
||||||
self,
|
description,
|
||||||
description,
|
prefix_chars,
|
||||||
prefix_chars,
|
argument_default,
|
||||||
argument_default,
|
conflict_handler):
|
||||||
conflict_handler,
|
|
||||||
):
|
|
||||||
super(_ActionsContainer, self).__init__()
|
super(_ActionsContainer, self).__init__()
|
||||||
|
|
||||||
self.description = description
|
self.description = description
|
||||||
@ -1327,6 +1263,7 @@ class _ActionsContainer(object):
|
|||||||
return action.default
|
return action.default
|
||||||
return self._defaults.get(dest, None)
|
return self._defaults.get(dest, None)
|
||||||
|
|
||||||
|
|
||||||
# =======================
|
# =======================
|
||||||
# Adding argument actions
|
# Adding argument actions
|
||||||
# =======================
|
# =======================
|
||||||
@ -1423,8 +1360,7 @@ class _ActionsContainer(object):
|
|||||||
title_group_map[group.title] = self.add_argument_group(
|
title_group_map[group.title] = self.add_argument_group(
|
||||||
title=group.title,
|
title=group.title,
|
||||||
description=group.description,
|
description=group.description,
|
||||||
conflict_handler=group.conflict_handler,
|
conflict_handler=group.conflict_handler)
|
||||||
)
|
|
||||||
|
|
||||||
# map the actions to their new group
|
# map the actions to their new group
|
||||||
for action in group._group_actions:
|
for action in group._group_actions:
|
||||||
@ -1435,8 +1371,7 @@ class _ActionsContainer(object):
|
|||||||
# description= then this code will need to be expanded as above
|
# description= then this code will need to be expanded as above
|
||||||
for group in container._mutually_exclusive_groups:
|
for group in container._mutually_exclusive_groups:
|
||||||
mutex_group = self.add_mutually_exclusive_group(
|
mutex_group = self.add_mutually_exclusive_group(
|
||||||
required=group.required,
|
required=group.required)
|
||||||
)
|
|
||||||
|
|
||||||
# map the actions to their new mutex group
|
# map the actions to their new mutex group
|
||||||
for action in group._group_actions:
|
for action in group._group_actions:
|
||||||
@ -1469,10 +1404,8 @@ class _ActionsContainer(object):
|
|||||||
for option_string in args:
|
for option_string in args:
|
||||||
# error on strings that don't start with an appropriate prefix
|
# error on strings that don't start with an appropriate prefix
|
||||||
if not option_string[0] in self.prefix_chars:
|
if not option_string[0] in self.prefix_chars:
|
||||||
msg = _(
|
msg = _('invalid option string %r: '
|
||||||
'invalid option string %r: '
|
'must start with a character %r')
|
||||||
'must start with a character %r',
|
|
||||||
)
|
|
||||||
tup = option_string, self.prefix_chars
|
tup = option_string, self.prefix_chars
|
||||||
raise ValueError(msg % tup)
|
raise ValueError(msg % tup)
|
||||||
|
|
||||||
@ -1528,11 +1461,9 @@ class _ActionsContainer(object):
|
|||||||
|
|
||||||
def _handle_conflict_error(self, action, conflicting_actions):
|
def _handle_conflict_error(self, action, conflicting_actions):
|
||||||
message = _('conflicting option string(s): %s')
|
message = _('conflicting option string(s): %s')
|
||||||
conflict_string = ', '.join([
|
conflict_string = ', '.join([option_string
|
||||||
option_string
|
for option_string, action
|
||||||
for option_string, action
|
in conflicting_actions])
|
||||||
in conflicting_actions
|
|
||||||
])
|
|
||||||
raise ArgumentError(action, message % conflict_string)
|
raise ArgumentError(action, message % conflict_string)
|
||||||
|
|
||||||
def _handle_conflict_resolve(self, action, conflicting_actions):
|
def _handle_conflict_resolve(self, action, conflicting_actions):
|
||||||
@ -1604,7 +1535,6 @@ class _MutuallyExclusiveGroup(_ArgumentGroup):
|
|||||||
|
|
||||||
|
|
||||||
class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
||||||
|
|
||||||
"""Object for parsing command line strings into Python objects.
|
"""Object for parsing command line strings into Python objects.
|
||||||
|
|
||||||
Keyword Arguments:
|
Keyword Arguments:
|
||||||
@ -1622,21 +1552,19 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
|||||||
- add_help -- Add a -h/-help option
|
- add_help -- Add a -h/-help option
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(self,
|
||||||
self,
|
prog=None,
|
||||||
prog=None,
|
usage=None,
|
||||||
usage=None,
|
description=None,
|
||||||
description=None,
|
epilog=None,
|
||||||
epilog=None,
|
version=None,
|
||||||
version=None,
|
parents=[],
|
||||||
parents=[],
|
formatter_class=HelpFormatter,
|
||||||
formatter_class=HelpFormatter,
|
prefix_chars='-',
|
||||||
prefix_chars='-',
|
fromfile_prefix_chars=None,
|
||||||
fromfile_prefix_chars=None,
|
argument_default=None,
|
||||||
argument_default=None,
|
conflict_handler='error',
|
||||||
conflict_handler='error',
|
add_help=True):
|
||||||
add_help=True,
|
|
||||||
):
|
|
||||||
|
|
||||||
if version is not None:
|
if version is not None:
|
||||||
import warnings
|
import warnings
|
||||||
@ -1644,16 +1572,13 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
|||||||
"""The "version" argument to ArgumentParser is deprecated. """
|
"""The "version" argument to ArgumentParser is deprecated. """
|
||||||
"""Please use """
|
"""Please use """
|
||||||
""""add_argument(..., action='version', version="N", ...)" """
|
""""add_argument(..., action='version', version="N", ...)" """
|
||||||
"""instead""", DeprecationWarning,
|
"""instead""", DeprecationWarning)
|
||||||
)
|
|
||||||
|
|
||||||
superinit = super(ArgumentParser, self).__init__
|
superinit = super(ArgumentParser, self).__init__
|
||||||
superinit(
|
superinit(description=description,
|
||||||
description=description,
|
prefix_chars=prefix_chars,
|
||||||
prefix_chars=prefix_chars,
|
argument_default=argument_default,
|
||||||
argument_default=argument_default,
|
conflict_handler=conflict_handler)
|
||||||
conflict_handler=conflict_handler,
|
|
||||||
)
|
|
||||||
|
|
||||||
# default setting for prog
|
# default setting for prog
|
||||||
if prog is None:
|
if prog is None:
|
||||||
@ -1685,17 +1610,15 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
|||||||
default_prefix = prefix_chars[0]
|
default_prefix = prefix_chars[0]
|
||||||
if self.add_help:
|
if self.add_help:
|
||||||
self.add_argument(
|
self.add_argument(
|
||||||
default_prefix + 'h', default_prefix * 2 + 'help',
|
default_prefix+'h', default_prefix*2+'help',
|
||||||
action='help', default=SUPPRESS,
|
action='help', default=SUPPRESS,
|
||||||
help=_('show this help message and exit'),
|
help=_('show this help message and exit'))
|
||||||
)
|
|
||||||
if self.version:
|
if self.version:
|
||||||
self.add_argument(
|
self.add_argument(
|
||||||
default_prefix + 'v', default_prefix * 2 + 'version',
|
default_prefix+'v', default_prefix*2+'version',
|
||||||
action='version', default=SUPPRESS,
|
action='version', default=SUPPRESS,
|
||||||
version=self.version,
|
version=self.version,
|
||||||
help=_("show program's version number and exit"),
|
help=_("show program's version number and exit"))
|
||||||
)
|
|
||||||
|
|
||||||
# add parent arguments and defaults
|
# add parent arguments and defaults
|
||||||
for parent in parents:
|
for parent in parents:
|
||||||
@ -1764,18 +1687,14 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
|||||||
return action
|
return action
|
||||||
|
|
||||||
def _get_optional_actions(self):
|
def _get_optional_actions(self):
|
||||||
return [
|
return [action
|
||||||
action
|
for action in self._actions
|
||||||
for action in self._actions
|
if action.option_strings]
|
||||||
if action.option_strings
|
|
||||||
]
|
|
||||||
|
|
||||||
def _get_positional_actions(self):
|
def _get_positional_actions(self):
|
||||||
return [
|
return [action
|
||||||
action
|
for action in self._actions
|
||||||
for action in self._actions
|
if not action.option_strings]
|
||||||
if not action.option_strings
|
|
||||||
]
|
|
||||||
|
|
||||||
# =====================================
|
# =====================================
|
||||||
# Command line argument parsing methods
|
# Command line argument parsing methods
|
||||||
@ -1999,8 +1918,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
|||||||
next_option_string_index = min([
|
next_option_string_index = min([
|
||||||
index
|
index
|
||||||
for index in option_string_indices
|
for index in option_string_indices
|
||||||
if index >= start_index
|
if index >= start_index])
|
||||||
])
|
|
||||||
if start_index != next_option_string_index:
|
if start_index != next_option_string_index:
|
||||||
positionals_end_index = consume_positionals(start_index)
|
positionals_end_index = consume_positionals(start_index)
|
||||||
|
|
||||||
@ -2049,11 +1967,9 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
|||||||
|
|
||||||
# if no actions were used, report the error
|
# if no actions were used, report the error
|
||||||
else:
|
else:
|
||||||
names = [
|
names = [_get_action_name(action)
|
||||||
_get_action_name(action)
|
for action in group._group_actions
|
||||||
for action in group._group_actions
|
if action.help is not SUPPRESS]
|
||||||
if action.help is not SUPPRESS
|
|
||||||
]
|
|
||||||
msg = _('one of the arguments %s is required')
|
msg = _('one of the arguments %s is required')
|
||||||
self.error(msg % ' '.join(names))
|
self.error(msg % ' '.join(names))
|
||||||
|
|
||||||
@ -2117,10 +2033,8 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
|||||||
result = []
|
result = []
|
||||||
for i in range(len(actions), 0, -1):
|
for i in range(len(actions), 0, -1):
|
||||||
actions_slice = actions[:i]
|
actions_slice = actions[:i]
|
||||||
pattern = ''.join([
|
pattern = ''.join([self._get_nargs_pattern(action)
|
||||||
self._get_nargs_pattern(action)
|
for action in actions_slice])
|
||||||
for action in actions_slice
|
|
||||||
])
|
|
||||||
match = _re.match(pattern, arg_strings_pattern)
|
match = _re.match(pattern, arg_strings_pattern)
|
||||||
if match is not None:
|
if match is not None:
|
||||||
result.extend([len(string) for string in match.groups()])
|
result.extend([len(string) for string in match.groups()])
|
||||||
@ -2160,9 +2074,8 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
|||||||
|
|
||||||
# if multiple actions match, the option string was ambiguous
|
# if multiple actions match, the option string was ambiguous
|
||||||
if len(option_tuples) > 1:
|
if len(option_tuples) > 1:
|
||||||
options = ', '.join(
|
options = ', '.join([option_string
|
||||||
[option_string for action, option_string, explicit_arg in option_tuples],
|
for action, option_string, explicit_arg in option_tuples])
|
||||||
)
|
|
||||||
tup = arg_string, options
|
tup = arg_string, options
|
||||||
self.error(_('ambiguous option: %s could match %s') % tup)
|
self.error(_('ambiguous option: %s could match %s') % tup)
|
||||||
|
|
||||||
@ -2292,10 +2205,8 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
|||||||
|
|
||||||
# when nargs='*' on a positional, if there were no command-line
|
# when nargs='*' on a positional, if there were no command-line
|
||||||
# args, use the default if it is anything other than None
|
# args, use the default if it is anything other than None
|
||||||
elif (
|
elif (not arg_strings and action.nargs == ZERO_OR_MORE and
|
||||||
not arg_strings and action.nargs == ZERO_OR_MORE and
|
not action.option_strings):
|
||||||
not action.option_strings
|
|
||||||
):
|
|
||||||
if action.default is not None:
|
if action.default is not None:
|
||||||
value = action.default
|
value = action.default
|
||||||
else:
|
else:
|
||||||
@ -2363,20 +2274,16 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
|||||||
# =======================
|
# =======================
|
||||||
def format_usage(self):
|
def format_usage(self):
|
||||||
formatter = self._get_formatter()
|
formatter = self._get_formatter()
|
||||||
formatter.add_usage(
|
formatter.add_usage(self.usage, self._actions,
|
||||||
self.usage, self._actions,
|
self._mutually_exclusive_groups)
|
||||||
self._mutually_exclusive_groups,
|
|
||||||
)
|
|
||||||
return formatter.format_help()
|
return formatter.format_help()
|
||||||
|
|
||||||
def format_help(self):
|
def format_help(self):
|
||||||
formatter = self._get_formatter()
|
formatter = self._get_formatter()
|
||||||
|
|
||||||
# usage
|
# usage
|
||||||
formatter.add_usage(
|
formatter.add_usage(self.usage, self._actions,
|
||||||
self.usage, self._actions,
|
self._mutually_exclusive_groups)
|
||||||
self._mutually_exclusive_groups,
|
|
||||||
)
|
|
||||||
|
|
||||||
# description
|
# description
|
||||||
formatter.add_text(self.description)
|
formatter.add_text(self.description)
|
||||||
@ -2399,8 +2306,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
|||||||
warnings.warn(
|
warnings.warn(
|
||||||
'The format_version method is deprecated -- the "version" '
|
'The format_version method is deprecated -- the "version" '
|
||||||
'argument to ArgumentParser is no longer supported.',
|
'argument to ArgumentParser is no longer supported.',
|
||||||
DeprecationWarning,
|
DeprecationWarning)
|
||||||
)
|
|
||||||
formatter = self._get_formatter()
|
formatter = self._get_formatter()
|
||||||
formatter.add_text(self.version)
|
formatter.add_text(self.version)
|
||||||
return formatter.format_help()
|
return formatter.format_help()
|
||||||
@ -2426,8 +2332,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
|||||||
warnings.warn(
|
warnings.warn(
|
||||||
'The print_version method is deprecated -- the "version" '
|
'The print_version method is deprecated -- the "version" '
|
||||||
'argument to ArgumentParser is no longer supported.',
|
'argument to ArgumentParser is no longer supported.',
|
||||||
DeprecationWarning,
|
DeprecationWarning)
|
||||||
)
|
|
||||||
self._print_message(self.format_version(), file)
|
self._print_message(self.format_version(), file)
|
||||||
|
|
||||||
def _print_message(self, message, file=None):
|
def _print_message(self, message, file=None):
|
||||||
|
@ -1,148 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import os
|
|
||||||
import shutil
|
|
||||||
import sys
|
|
||||||
from codecs import open
|
|
||||||
from collections import namedtuple
|
|
||||||
from tempfile import NamedTemporaryFile
|
|
||||||
from time import time
|
|
||||||
|
|
||||||
from autojump_utils import create_dir
|
|
||||||
from autojump_utils import is_osx
|
|
||||||
from autojump_utils import is_python3
|
|
||||||
from autojump_utils import move_file
|
|
||||||
from autojump_utils import unico
|
|
||||||
|
|
||||||
|
|
||||||
if sys.version_info[0] == 3:
|
|
||||||
ifilter = filter
|
|
||||||
imap = map
|
|
||||||
else:
|
|
||||||
from itertools import ifilter # noqa
|
|
||||||
from itertools import imap # noqa
|
|
||||||
|
|
||||||
|
|
||||||
BACKUP_THRESHOLD = 24 * 60 * 60
|
|
||||||
Entry = namedtuple('Entry', ['path', 'weight'])
|
|
||||||
|
|
||||||
|
|
||||||
def dictify(entries):
|
|
||||||
"""
|
|
||||||
Converts a list of entries into a dictionary where
|
|
||||||
key = path
|
|
||||||
value = weight
|
|
||||||
"""
|
|
||||||
result = {}
|
|
||||||
for entry in entries:
|
|
||||||
result[entry.path] = entry.weight
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def entriefy(data):
|
|
||||||
"""Converts a dictionary into an iterator of entries."""
|
|
||||||
convert = lambda tup: Entry(*tup)
|
|
||||||
if is_python3():
|
|
||||||
return map(convert, data.items())
|
|
||||||
return imap(convert, data.iteritems())
|
|
||||||
|
|
||||||
|
|
||||||
def load(config):
|
|
||||||
"""Returns a dictonary (key=path, value=weight) loaded from data file."""
|
|
||||||
xdg_aj_home = os.path.join(
|
|
||||||
os.path.expanduser('~'),
|
|
||||||
'.local',
|
|
||||||
'share',
|
|
||||||
'autojump',
|
|
||||||
)
|
|
||||||
|
|
||||||
if is_osx() and os.path.exists(xdg_aj_home):
|
|
||||||
migrate_osx_xdg_data(config)
|
|
||||||
|
|
||||||
if not os.path.exists(config['data_path']):
|
|
||||||
return {}
|
|
||||||
|
|
||||||
# example: u'10.0\t/home/user\n' -> ['10.0', u'/home/user']
|
|
||||||
parse = lambda line: line.strip().split('\t')
|
|
||||||
|
|
||||||
correct_length = lambda x: len(x) == 2
|
|
||||||
|
|
||||||
# example: ['10.0', u'/home/user'] -> (u'/home/user', 10.0)
|
|
||||||
tupleize = lambda x: (x[1], float(x[0]))
|
|
||||||
|
|
||||||
try:
|
|
||||||
with open(
|
|
||||||
config['data_path'],
|
|
||||||
'r', encoding='utf-8',
|
|
||||||
errors='replace',
|
|
||||||
) as f:
|
|
||||||
return dict(
|
|
||||||
imap(
|
|
||||||
tupleize,
|
|
||||||
ifilter(correct_length, imap(parse, f)),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
except (IOError, EOFError):
|
|
||||||
return load_backup(config)
|
|
||||||
|
|
||||||
|
|
||||||
def load_backup(config):
|
|
||||||
if os.path.exists(config['backup_path']):
|
|
||||||
move_file(config['backup_path'], config['data_path'])
|
|
||||||
return load(config)
|
|
||||||
return {}
|
|
||||||
|
|
||||||
|
|
||||||
def migrate_osx_xdg_data(config):
|
|
||||||
"""
|
|
||||||
Older versions incorrectly used Linux XDG_DATA_HOME paths on OS X. This
|
|
||||||
migrates autojump files from ~/.local/share/autojump to ~/Library/autojump
|
|
||||||
"""
|
|
||||||
assert is_osx(), 'This function should only be run on OS X.'
|
|
||||||
|
|
||||||
xdg_data_home = os.path.join(os.path.expanduser('~'), '.local', 'share')
|
|
||||||
xdg_aj_home = os.path.join(xdg_data_home, 'autojump')
|
|
||||||
data_path = os.path.join(xdg_aj_home, 'autojump.txt')
|
|
||||||
backup_path = os.path.join(xdg_aj_home, 'autojump.txt.bak')
|
|
||||||
|
|
||||||
if os.path.exists(data_path):
|
|
||||||
move_file(data_path, config['data_path'])
|
|
||||||
if os.path.exists(backup_path):
|
|
||||||
move_file(backup_path, config['backup_path'])
|
|
||||||
|
|
||||||
# cleanup
|
|
||||||
shutil.rmtree(xdg_aj_home)
|
|
||||||
if len(os.listdir(xdg_data_home)) == 0:
|
|
||||||
shutil.rmtree(xdg_data_home)
|
|
||||||
|
|
||||||
|
|
||||||
def save(config, data):
|
|
||||||
"""Save data and create backup, creating a new data file if necessary."""
|
|
||||||
data_dir = os.path.dirname(config['data_path'])
|
|
||||||
create_dir(data_dir)
|
|
||||||
|
|
||||||
# atomically save by writing to temporary file and moving to destination
|
|
||||||
try:
|
|
||||||
temp = NamedTemporaryFile(delete=False, dir=data_dir)
|
|
||||||
# Windows cannot reuse the same open file name
|
|
||||||
temp.close()
|
|
||||||
|
|
||||||
with open(temp.name, 'w', encoding='utf-8', errors='replace') as f:
|
|
||||||
for path, weight in data.items():
|
|
||||||
f.write(unico('%s\t%s\n' % (weight, path)))
|
|
||||||
|
|
||||||
f.flush()
|
|
||||||
os.fsync(f)
|
|
||||||
except IOError as ex:
|
|
||||||
print('Error saving autojump data (disk full?)' % ex, file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# move temp_file -> autojump.txt
|
|
||||||
move_file(temp.name, config['data_path'])
|
|
||||||
|
|
||||||
# create backup file if it doesn't exist or is older than BACKUP_THRESHOLD
|
|
||||||
if not os.path.exists(config['backup_path']) or \
|
|
||||||
(time() - os.path.getmtime(config['backup_path']) > BACKUP_THRESHOLD): # noqa
|
|
||||||
shutil.copy(config['data_path'], config['backup_path'])
|
|
@ -1,129 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
from difflib import SequenceMatcher
|
|
||||||
|
|
||||||
from autojump_utils import is_python3
|
|
||||||
from autojump_utils import last
|
|
||||||
|
|
||||||
|
|
||||||
if is_python3(): # pragma: no cover
|
|
||||||
ifilter = filter
|
|
||||||
imap = map
|
|
||||||
os.getcwdu = os.getcwd
|
|
||||||
else:
|
|
||||||
from itertools import ifilter
|
|
||||||
from itertools import imap
|
|
||||||
|
|
||||||
|
|
||||||
def match_anywhere(needles, haystack, ignore_case=False):
|
|
||||||
"""
|
|
||||||
Matches needles anywhere in the path as long as they're in the same (but
|
|
||||||
not necessary consecutive) order.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
needles = ['foo', 'baz']
|
|
||||||
regex needle = r'.*foo.*baz.*'
|
|
||||||
haystack = [
|
|
||||||
(path='/foo/bar/baz', weight=10),
|
|
||||||
(path='/baz/foo/bar', weight=10),
|
|
||||||
(path='/foo/baz', weight=10),
|
|
||||||
]
|
|
||||||
|
|
||||||
result = [
|
|
||||||
(path='/moo/foo/baz', weight=10),
|
|
||||||
(path='/foo/baz', weight=10),
|
|
||||||
]
|
|
||||||
"""
|
|
||||||
regex_needle = '.*' + '.*'.join(imap(re.escape, needles)) + '.*'
|
|
||||||
regex_flags = re.IGNORECASE | re.UNICODE if ignore_case else re.UNICODE
|
|
||||||
found = lambda haystack: re.search(
|
|
||||||
regex_needle,
|
|
||||||
haystack.path,
|
|
||||||
flags=regex_flags,
|
|
||||||
)
|
|
||||||
return ifilter(found, haystack)
|
|
||||||
|
|
||||||
|
|
||||||
def match_consecutive(needles, haystack, ignore_case=False):
|
|
||||||
"""
|
|
||||||
Matches consecutive needles at the end of a path.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
needles = ['foo', 'baz']
|
|
||||||
haystack = [
|
|
||||||
(path='/foo/bar/baz', weight=10),
|
|
||||||
(path='/foo/baz/moo', weight=10),
|
|
||||||
(path='/moo/foo/baz', weight=10),
|
|
||||||
(path='/foo/baz', weight=10),
|
|
||||||
]
|
|
||||||
|
|
||||||
# We can't actually use re.compile because of re.UNICODE
|
|
||||||
regex_needle = re.compile(r'''
|
|
||||||
foo # needle #1
|
|
||||||
[^/]* # all characters except os.sep zero or more times
|
|
||||||
/ # os.sep
|
|
||||||
[^/]* # all characters except os.sep zero or more times
|
|
||||||
baz # needle #2
|
|
||||||
[^/]* # all characters except os.sep zero or more times
|
|
||||||
$ # end of string
|
|
||||||
''')
|
|
||||||
|
|
||||||
result = [
|
|
||||||
(path='/moo/foo/baz', weight=10),
|
|
||||||
(path='/foo/baz', weight=10),
|
|
||||||
]
|
|
||||||
"""
|
|
||||||
regex_no_sep = '[^' + os.sep + ']*'
|
|
||||||
regex_no_sep_end = regex_no_sep + '$'
|
|
||||||
regex_one_sep = regex_no_sep + os.sep + regex_no_sep
|
|
||||||
regex_needle = regex_one_sep.join(imap(re.escape, needles)) + regex_no_sep_end
|
|
||||||
regex_flags = re.IGNORECASE | re.UNICODE if ignore_case else re.UNICODE
|
|
||||||
found = lambda entry: re.search(
|
|
||||||
regex_needle,
|
|
||||||
entry.path,
|
|
||||||
flags=regex_flags,
|
|
||||||
)
|
|
||||||
return ifilter(found, haystack)
|
|
||||||
|
|
||||||
|
|
||||||
def match_fuzzy(needles, haystack, ignore_case=False, threshold=0.6):
|
|
||||||
"""
|
|
||||||
Performs an approximate match with the last needle against the end of
|
|
||||||
every path past an acceptable threshold.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
needles = ['foo', 'bar']
|
|
||||||
haystack = [
|
|
||||||
(path='/foo/bar/baz', weight=11),
|
|
||||||
(path='/foo/baz/moo', weight=10),
|
|
||||||
(path='/moo/foo/baz', weight=10),
|
|
||||||
(path='/foo/baz', weight=10),
|
|
||||||
(path='/foo/bar', weight=10),
|
|
||||||
]
|
|
||||||
|
|
||||||
result = [
|
|
||||||
(path='/foo/bar/baz', weight=11),
|
|
||||||
(path='/moo/foo/baz', weight=10),
|
|
||||||
(path='/foo/baz', weight=10),
|
|
||||||
(path='/foo/bar', weight=10),
|
|
||||||
]
|
|
||||||
|
|
||||||
This is a weak heuristic and used as a last resort to find matches.
|
|
||||||
"""
|
|
||||||
end_dir = lambda path: last(os.path.split(path))
|
|
||||||
if ignore_case:
|
|
||||||
needle = last(needles).lower()
|
|
||||||
match_percent = lambda entry: SequenceMatcher(
|
|
||||||
a=needle,
|
|
||||||
b=end_dir(entry.path.lower()),
|
|
||||||
).ratio()
|
|
||||||
else:
|
|
||||||
needle = last(needles)
|
|
||||||
match_percent = lambda entry: SequenceMatcher(
|
|
||||||
a=needle,
|
|
||||||
b=end_dir(entry.path),
|
|
||||||
).ratio()
|
|
||||||
meets_threshold = lambda entry: match_percent(entry) >= threshold
|
|
||||||
return ifilter(meets_threshold, haystack)
|
|
@ -1,211 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import errno
|
|
||||||
import os
|
|
||||||
import platform
|
|
||||||
import re
|
|
||||||
import shutil
|
|
||||||
import sys
|
|
||||||
import unicodedata
|
|
||||||
from itertools import islice
|
|
||||||
|
|
||||||
if sys.version_info[0] == 3:
|
|
||||||
imap = map
|
|
||||||
os.getcwdu = os.getcwd
|
|
||||||
else:
|
|
||||||
from itertools import imap
|
|
||||||
|
|
||||||
|
|
||||||
def create_dir(path):
|
|
||||||
"""Creates a directory atomically."""
|
|
||||||
try:
|
|
||||||
os.makedirs(path)
|
|
||||||
except OSError as exception:
|
|
||||||
if exception.errno != errno.EEXIST:
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
|
||||||
def encode_local(string):
|
|
||||||
"""Converts string into user's preferred encoding."""
|
|
||||||
if is_python3():
|
|
||||||
return string
|
|
||||||
return string.encode(sys.getfilesystemencoding() or 'utf-8')
|
|
||||||
|
|
||||||
|
|
||||||
def first(xs):
|
|
||||||
it = iter(xs)
|
|
||||||
try:
|
|
||||||
if is_python3():
|
|
||||||
return it.__next__()
|
|
||||||
return it.next()
|
|
||||||
except StopIteration:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def get_tab_entry_info(entry, separator):
|
|
||||||
"""
|
|
||||||
Given a tab entry in the following format return needle, index, and path:
|
|
||||||
|
|
||||||
[needle]__[index]__[path]
|
|
||||||
"""
|
|
||||||
needle, index, path = None, None, None
|
|
||||||
|
|
||||||
match_needle = re.search(r'(.*?)' + separator, entry)
|
|
||||||
match_index = re.search(separator + r'([0-9]{1})', entry)
|
|
||||||
match_path = re.search(
|
|
||||||
separator + r'[0-9]{1}' + separator + r'(.*)',
|
|
||||||
entry,
|
|
||||||
)
|
|
||||||
|
|
||||||
if match_needle:
|
|
||||||
needle = match_needle.group(1)
|
|
||||||
|
|
||||||
if match_index:
|
|
||||||
index = int(match_index.group(1))
|
|
||||||
|
|
||||||
if match_path:
|
|
||||||
path = match_path.group(1)
|
|
||||||
|
|
||||||
return needle, index, path
|
|
||||||
|
|
||||||
|
|
||||||
def get_pwd():
|
|
||||||
try:
|
|
||||||
return os.getcwdu()
|
|
||||||
except OSError:
|
|
||||||
print('Current directory no longer exists.', file=sys.stderr)
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
|
||||||
def has_uppercase(string):
|
|
||||||
if is_python3():
|
|
||||||
return any(ch.isupper() for ch in string)
|
|
||||||
return any(unicodedata.category(c) == 'Lu' for c in unicode(string))
|
|
||||||
|
|
||||||
|
|
||||||
def in_bash():
|
|
||||||
return 'bash' in os.getenv('SHELL')
|
|
||||||
|
|
||||||
|
|
||||||
def is_autojump_sourced():
|
|
||||||
return '1' == os.getenv('AUTOJUMP_SOURCED')
|
|
||||||
|
|
||||||
|
|
||||||
def is_python2():
|
|
||||||
return sys.version_info[0] == 2
|
|
||||||
|
|
||||||
|
|
||||||
def is_python3():
|
|
||||||
return sys.version_info[0] == 3
|
|
||||||
|
|
||||||
|
|
||||||
def is_linux():
|
|
||||||
return platform.system() == 'Linux'
|
|
||||||
|
|
||||||
|
|
||||||
def is_osx():
|
|
||||||
return platform.system() == 'Darwin'
|
|
||||||
|
|
||||||
|
|
||||||
def is_windows():
|
|
||||||
return platform.system() == 'Windows'
|
|
||||||
|
|
||||||
|
|
||||||
def last(xs):
|
|
||||||
it = iter(xs)
|
|
||||||
tmp = None
|
|
||||||
try:
|
|
||||||
if is_python3():
|
|
||||||
while True:
|
|
||||||
tmp = it.__next__()
|
|
||||||
else:
|
|
||||||
while True:
|
|
||||||
tmp = it.next()
|
|
||||||
except StopIteration:
|
|
||||||
return tmp
|
|
||||||
|
|
||||||
|
|
||||||
def move_file(src, dst):
|
|
||||||
"""
|
|
||||||
Atomically move file.
|
|
||||||
|
|
||||||
Windows does not allow for atomic file renaming (which is used by
|
|
||||||
os.rename / shutil.move) so destination paths must first be deleted.
|
|
||||||
"""
|
|
||||||
if is_windows() and os.path.exists(dst):
|
|
||||||
# raises exception if file is in use on Windows
|
|
||||||
os.remove(dst)
|
|
||||||
shutil.move(src, dst)
|
|
||||||
|
|
||||||
|
|
||||||
def print_entry(entry):
|
|
||||||
print_local('%.1f:\t%s' % (entry.weight, entry.path))
|
|
||||||
|
|
||||||
|
|
||||||
def print_local(string):
|
|
||||||
print(encode_local(string))
|
|
||||||
|
|
||||||
|
|
||||||
def print_tab_menu(needle, tab_entries, separator):
|
|
||||||
"""
|
|
||||||
Prints the tab completion menu according to the following format:
|
|
||||||
|
|
||||||
[needle]__[index]__[possible_match]
|
|
||||||
|
|
||||||
The needle (search pattern) and index are necessary to recreate the results
|
|
||||||
on subsequent calls.
|
|
||||||
"""
|
|
||||||
for i, entry in enumerate(tab_entries):
|
|
||||||
print_local(
|
|
||||||
'%s%s%d%s%s' % (
|
|
||||||
needle,
|
|
||||||
separator,
|
|
||||||
i + 1,
|
|
||||||
separator,
|
|
||||||
entry.path,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def sanitize(directories):
|
|
||||||
# edge case to allow '/' as a valid path
|
|
||||||
clean = lambda x: unico(x) if x == os.sep else unico(x).rstrip(os.sep)
|
|
||||||
return list(imap(clean, directories))
|
|
||||||
|
|
||||||
|
|
||||||
def second(xs):
|
|
||||||
it = iter(xs)
|
|
||||||
try:
|
|
||||||
if is_python2():
|
|
||||||
it.next()
|
|
||||||
return it.next()
|
|
||||||
elif is_python3():
|
|
||||||
next(it)
|
|
||||||
return next(it)
|
|
||||||
except StopIteration:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def surround_quotes(string):
|
|
||||||
"""
|
|
||||||
Bash has problems dealing with certain paths so we're surrounding all
|
|
||||||
path outputs with quotes.
|
|
||||||
"""
|
|
||||||
if in_bash() and string:
|
|
||||||
# Python 2.6 requres field numbers
|
|
||||||
return '"{0}"'.format(string)
|
|
||||||
return string
|
|
||||||
|
|
||||||
|
|
||||||
def take(n, iterable):
|
|
||||||
"""Return first n items of an iterable."""
|
|
||||||
return islice(iterable, n)
|
|
||||||
|
|
||||||
|
|
||||||
def unico(string):
|
|
||||||
"""Converts into Unicode string."""
|
|
||||||
if is_python2() and not isinstance(string, unicode):
|
|
||||||
return unicode(string, encoding='utf-8', errors='replace')
|
|
||||||
return string
|
|
21
bin/j.bat
21
bin/j.bat
@ -1,21 +0,0 @@
|
|||||||
@echo off
|
|
||||||
setlocal EnableDelayedExpansion
|
|
||||||
|
|
||||||
echo %*|>nul findstr /rx \-.*
|
|
||||||
if ERRORLEVEL 1 (
|
|
||||||
for /f "delims=" %%i in ('python "%~dp0\autojump" %*') do set new_path=%%i
|
|
||||||
if exist !new_path!\nul (
|
|
||||||
echo !new_path!
|
|
||||||
pushd !new_path!
|
|
||||||
REM endlocal is necessary so that we can change directory for outside of this script
|
|
||||||
REM but will automatically popd. We mush pushd twice to work around this.
|
|
||||||
pushd !new_path!
|
|
||||||
endlocal
|
|
||||||
popd
|
|
||||||
) else (
|
|
||||||
echo autojump: directory %* not found
|
|
||||||
echo try `autojump --help` for more information
|
|
||||||
)
|
|
||||||
) else (
|
|
||||||
python "%~dp0\autojump" %*
|
|
||||||
)
|
|
@ -1,8 +0,0 @@
|
|||||||
@echo off
|
|
||||||
|
|
||||||
echo %*|>nul findstr /rx \-.*
|
|
||||||
if ERRORLEVEL 1 (
|
|
||||||
"%~dp0\j.bat" "%cd%" %*
|
|
||||||
) else (
|
|
||||||
python "%~dp0\autojump" %*
|
|
||||||
)
|
|
@ -1,8 +0,0 @@
|
|||||||
@echo off
|
|
||||||
|
|
||||||
echo %*|>nul findstr /rx \-.*
|
|
||||||
if ERRORLEVEL 1 (
|
|
||||||
"%~dp0\jc.bat" "%cd%" %*
|
|
||||||
) else (
|
|
||||||
python "%~dp0\autojump" %*
|
|
||||||
)
|
|
15
bin/jo.bat
15
bin/jo.bat
@ -1,15 +0,0 @@
|
|||||||
@echo off
|
|
||||||
setlocal EnableDelayedExpansion
|
|
||||||
|
|
||||||
echo %*|>nul findstr /rx \-.*
|
|
||||||
if ERRORLEVEL 1 (
|
|
||||||
for /f "delims=" %%i in ('python "%~dp0\autojump" %*') do set new_path=%%i
|
|
||||||
if exist !new_path!\nul (
|
|
||||||
start "" "explorer" !new_path!
|
|
||||||
) else (
|
|
||||||
echo autojump: directory %* not found
|
|
||||||
echo try `autojump --help` for more information
|
|
||||||
)
|
|
||||||
) else (
|
|
||||||
python "%~dp0\autojump" %*
|
|
||||||
)
|
|
216
docs/autojump.1
216
docs/autojump.1
@ -1,70 +1,59 @@
|
|||||||
.\" Automatically generated by Pandoc 1.16.0.2
|
.TH autojump 1 "10 April 2012" "release\-v20"
|
||||||
.\"
|
|
||||||
.TH "autojump" "1" "2018\-09\-09" "release\-v22.5.3" ""
|
|
||||||
.hy
|
|
||||||
.SS NAME
|
.SS NAME
|
||||||
.PP
|
.PP
|
||||||
autojump \- a faster way to navigate your filesystem
|
autojump \- a faster way to navigate your filesystem
|
||||||
.SS DESCRIPTION
|
.SS SYNOPSIS
|
||||||
.PP
|
.PP
|
||||||
autojump is a faster way to navigate your filesystem.
|
Jump to a previously visited directory that contains \[aq]foo\[aq]:
|
||||||
It works by maintaining a database of the directories you use the most
|
|
||||||
from the command line.
|
|
||||||
.PP
|
|
||||||
\f[I]Directories must be visited first before they can be jumped to.\f[]
|
|
||||||
.SS USAGE
|
|
||||||
.PP
|
|
||||||
\f[C]j\f[] is a convenience wrapper function around \f[C]autojump\f[].
|
|
||||||
Any option that can be used with \f[C]autojump\f[] can be used with
|
|
||||||
\f[C]j\f[] and vice versa.
|
|
||||||
.IP \[bu] 2
|
|
||||||
Jump To A Directory That Contains \f[C]foo\f[]:
|
|
||||||
.RS 2
|
|
||||||
.IP
|
.IP
|
||||||
.nf
|
.nf
|
||||||
\f[C]
|
\f[C]
|
||||||
j\ foo
|
j\ foo
|
||||||
\f[]
|
\f[]
|
||||||
.fi
|
.fi
|
||||||
.RE
|
|
||||||
.IP \[bu] 2
|
|
||||||
Jump To A Child Directory:
|
|
||||||
.RS 2
|
|
||||||
.PP
|
.PP
|
||||||
Sometimes it\[aq]s convenient to jump to a child directory
|
Jump to a previously visited subdirectory of the current directory:
|
||||||
(sub\-directory of current directory) rather than typing out the full
|
|
||||||
name.
|
|
||||||
.IP
|
.IP
|
||||||
.nf
|
.nf
|
||||||
\f[C]
|
\f[C]
|
||||||
jc\ bar
|
jc\ bar
|
||||||
\f[]
|
\f[]
|
||||||
.fi
|
.fi
|
||||||
.RE
|
|
||||||
.IP \[bu] 2
|
|
||||||
Open File Manager To Directories (instead of jumping):
|
|
||||||
.RS 2
|
|
||||||
.PP
|
.PP
|
||||||
Instead of jumping to a directory, you can open a file explorer window
|
Show database entries and their respective key weights:
|
||||||
(Mac Finder, Windows Explorer, GNOME Nautilus, etc.) to the directory
|
|
||||||
instead.
|
|
||||||
.IP
|
.IP
|
||||||
.nf
|
.nf
|
||||||
\f[C]
|
\f[C]
|
||||||
jo\ music
|
j\ \-\-stat
|
||||||
\f[]
|
\f[]
|
||||||
.fi
|
.fi
|
||||||
|
.SS DESCRIPTION
|
||||||
.PP
|
.PP
|
||||||
Opening a file manager to a child directory is also supported:
|
autojump is a faster way to navigate your filesystem.
|
||||||
|
It works by maintaining a database of the directories you use the most
|
||||||
|
from the command line.
|
||||||
|
Directories must be visited first before they can be jumped to.
|
||||||
|
.SS OPTIONS
|
||||||
|
.PP
|
||||||
|
Options must be passed to \[aq]autojump\[aq] and not the \[aq]j\[aq]
|
||||||
|
wrapper function.
|
||||||
.IP
|
.IP
|
||||||
.nf
|
.nf
|
||||||
\f[C]
|
\f[C]
|
||||||
jco\ images
|
\-i,\ \-\-increase\ \ \ \ \ \ manually\ increase\ current\ directory\ weight
|
||||||
|
|
||||||
|
\-d,\ \-\-decrease\ \ \ \ \ \ manually\ decrease\ current\ directory\ weight
|
||||||
|
|
||||||
|
\-\-purge\ \ \ \ \ \ \ \ \ \ \ \ \ deletes\ database\ entries\ that\ no\ longer\ exist\ on\ system
|
||||||
|
|
||||||
|
\-s,\ \-\-stat\ \ \ \ \ \ \ \ \ \ show\ general\ stats\ and\ top\ 100\ database\ entries
|
||||||
|
|
||||||
|
\-\-version\ \ \ \ \ \ \ \ \ \ \ show\ version\ information\ and\ exit
|
||||||
\f[]
|
\f[]
|
||||||
.fi
|
.fi
|
||||||
.RE
|
.SS ADVANCED USAGE
|
||||||
.IP \[bu] 2
|
.IP \[bu] 2
|
||||||
Using Multiple Arguments:
|
Using Multiple Arguments
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
.PP
|
||||||
Let\[aq]s assume the following database:
|
Let\[aq]s assume the following database:
|
||||||
@ -80,24 +69,131 @@ Let\[aq]s assume the following database:
|
|||||||
weighted entry.
|
weighted entry.
|
||||||
However you can pass multiple arguments to autojump to prefer a
|
However you can pass multiple arguments to autojump to prefer a
|
||||||
different entry.
|
different entry.
|
||||||
In the above example, \f[C]j\ w\ in\f[] would then change directory to
|
In the above example, \f[C]j\ w\ in\f[] would then jump you into
|
||||||
/home/user/work/inbox.
|
/home/user/work/inbox.
|
||||||
.RE
|
.RE
|
||||||
|
.IP \[bu] 2
|
||||||
|
Jump To A Child Directory.
|
||||||
|
.RS 2
|
||||||
.PP
|
.PP
|
||||||
For more options refer to help:
|
Sometimes it\[aq]s convenient to jump to a child directory
|
||||||
|
(sub\-directory of current directory) rather than typing out the full
|
||||||
|
name.
|
||||||
.IP
|
.IP
|
||||||
.nf
|
.nf
|
||||||
\f[C]
|
\f[C]
|
||||||
autojump\ \-\-help
|
jc\ images
|
||||||
\f[]
|
\f[]
|
||||||
.fi
|
.fi
|
||||||
|
.RE
|
||||||
|
.IP \[bu] 2
|
||||||
|
Open File Manager To Directories (instead of jumping)
|
||||||
|
.RS 2
|
||||||
|
.PP
|
||||||
|
Instead of jumping to a directory, you can open a file explorer window
|
||||||
|
(Mac Finder, Windows Explorer, GNOME Nautilus, etc) to the directory
|
||||||
|
instead.
|
||||||
|
.IP
|
||||||
|
.nf
|
||||||
|
\f[C]
|
||||||
|
jo\ music
|
||||||
|
\f[]
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
Opening a file manager to a child directory is also supported.
|
||||||
|
.IP
|
||||||
|
.nf
|
||||||
|
\f[C]
|
||||||
|
jco\ images
|
||||||
|
\f[]
|
||||||
|
.fi
|
||||||
|
.RE
|
||||||
|
.SS ADDITIONAL CONFIGURATION
|
||||||
|
.IP \[bu] 2
|
||||||
|
Enable ZSH Tab Completion
|
||||||
|
.RS 2
|
||||||
|
.PP
|
||||||
|
ZSH tab completion requires the \f[C]compinit\f[] module to be loaded.
|
||||||
|
Please add the following line to your ~/.zshrc \f[I]after\f[] loading
|
||||||
|
autojump:
|
||||||
|
.IP
|
||||||
|
.nf
|
||||||
|
\f[C]
|
||||||
|
autoload\ \-U\ compinit\ &&\ compinit
|
||||||
|
\f[]
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
For security compinit checks completion system if files will be owned by
|
||||||
|
root or the current user.
|
||||||
|
This check can be ignored by using the \-u flag:
|
||||||
|
.IP
|
||||||
|
.nf
|
||||||
|
\f[C]
|
||||||
|
autoload\ \-U\ compinit\ &&\ compinit\ \-u
|
||||||
|
\f[]
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
Tab completion requires two tabs before autojump will display the
|
||||||
|
completion menu.
|
||||||
|
However if \f[C]setopt\ nolistambiguous\f[] is enabled, then only one
|
||||||
|
tab is required.
|
||||||
|
.RE
|
||||||
|
.IP \[bu] 2
|
||||||
|
Always Ignore Case
|
||||||
|
.RS 2
|
||||||
|
.PP
|
||||||
|
Default behavior is to prioritize exact matches over all else.
|
||||||
|
For example, \f[C]j\ foo\f[] will prefer /foobar over /FooBar even if
|
||||||
|
the latter has a higher weight.
|
||||||
|
To change this behavior and ignore case, add the following environmental
|
||||||
|
variable in your ~/.bashrc:
|
||||||
|
.IP
|
||||||
|
.nf
|
||||||
|
\f[C]
|
||||||
|
export\ AUTOJUMP_IGNORE_CASE=1
|
||||||
|
\f[]
|
||||||
|
.fi
|
||||||
|
.RE
|
||||||
|
.IP \[bu] 2
|
||||||
|
Prefer Symbolic Links
|
||||||
|
.RS 2
|
||||||
|
.PP
|
||||||
|
Default behavior is to evaluate symbolic links into full paths as to
|
||||||
|
reduce duplicate entries in the database.
|
||||||
|
However, some users prefer a shorter working directory path in their
|
||||||
|
shell prompt.
|
||||||
|
To switch behavior to prefer symbolic links, add the following
|
||||||
|
environmental variable in your ~/.bashrc:
|
||||||
|
.IP
|
||||||
|
.nf
|
||||||
|
\f[C]
|
||||||
|
export\ AUTOJUMP_KEEP_SYMLINKS=1
|
||||||
|
\f[]
|
||||||
|
.fi
|
||||||
|
.RE
|
||||||
|
.IP \[bu] 2
|
||||||
|
Autocomplete Additional Commands (Bash only)
|
||||||
|
.RS 2
|
||||||
|
.PP
|
||||||
|
Autojump can be used to autocomplete other commands (e.g.
|
||||||
|
cp or vim).
|
||||||
|
To use this feature, add the following environmental variable in your
|
||||||
|
~/.bashrc:
|
||||||
|
.IP
|
||||||
|
.nf
|
||||||
|
\f[C]
|
||||||
|
export\ AUTOJUMP_AUTOCOMPLETE_CMDS=\[aq]cp\ vim\[aq]
|
||||||
|
\f[]
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
Changes require reloading autojump to take into effect.
|
||||||
|
.RE
|
||||||
.SS KNOWN ISSUES
|
.SS KNOWN ISSUES
|
||||||
.IP \[bu] 2
|
.IP \[bu] 2
|
||||||
autojump does not support directories that begin with \f[C]\-\f[].
|
For bash users, autojump keeps track of directories as a pre\-command
|
||||||
.IP \[bu] 2
|
hook by modifying $PROMPT_COMMAND.
|
||||||
For bash users, autojump keeps track of directories by modifying
|
If you overwrite $PROMPT_COMMAND in ~/.bashrc you can cause problems.
|
||||||
\f[C]$PROMPT_COMMAND\f[].
|
Don\[aq]t do this:
|
||||||
Do not overwrite \f[C]$PROMPT_COMMAND\f[]:
|
|
||||||
.RS 2
|
.RS 2
|
||||||
.IP
|
.IP
|
||||||
.nf
|
.nf
|
||||||
@ -106,7 +202,7 @@ export\ PROMPT_COMMAND="history\ \-a"
|
|||||||
\f[]
|
\f[]
|
||||||
.fi
|
.fi
|
||||||
.PP
|
.PP
|
||||||
Instead append to the end of the existing $PROMPT_COMMAND:
|
Do this:
|
||||||
.IP
|
.IP
|
||||||
.nf
|
.nf
|
||||||
\f[C]
|
\f[C]
|
||||||
@ -114,23 +210,33 @@ export\ PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND\ ;}\ history\ \-a"
|
|||||||
\f[]
|
\f[]
|
||||||
.fi
|
.fi
|
||||||
.RE
|
.RE
|
||||||
|
.IP \[bu] 2
|
||||||
|
The jump function \f[C]j\f[] does not support directories that begin
|
||||||
|
with \f[C]\-\f[].
|
||||||
|
If you want to jump a directory called \f[C]\-\-music\f[], try using
|
||||||
|
\f[C]j\ music\f[] instead of \f[C]j\ \ \ \-\-music\f[].
|
||||||
|
.SS FILES
|
||||||
|
.PP
|
||||||
|
If installed locally, autojump is self\-contained in
|
||||||
|
\f[I]~/.autojump/\f[].
|
||||||
|
.PP
|
||||||
|
The database is stored in \f[I]$XDG_DATA_HOME/autojump/autojump.txt\f[].
|
||||||
.SS REPORTING BUGS
|
.SS REPORTING BUGS
|
||||||
.PP
|
.PP
|
||||||
For any questions or issues please visit:
|
For any usage related issues or feature requests please visit:
|
||||||
.IP
|
.PP
|
||||||
.nf
|
\f[I]https://github.com/joelthelion/autojump/issues\f[]
|
||||||
\f[C]
|
.SS THANKS
|
||||||
https://github.com/wting/autojump/issues
|
.PP
|
||||||
\f[]
|
Special thanks goes out to: Pierre Gueth, Simon Marache\-Francisco,
|
||||||
.fi
|
Daniel Jackoway, and many others.
|
||||||
.SS AUTHORS
|
.SS AUTHORS
|
||||||
.PP
|
.PP
|
||||||
autojump was originally written by Joël Schaerer, and currently
|
autojump was originally written by Joël Schaerer, and currently
|
||||||
maintained by William Ting.
|
maintained by William Ting.
|
||||||
More contributors can be found in \f[C]AUTHORS\f[].
|
|
||||||
.SS COPYRIGHT
|
.SS COPYRIGHT
|
||||||
.PP
|
.PP
|
||||||
Copyright © 2016 Free Software Foundation, Inc.
|
Copyright © 2012 Free Software Foundation, Inc.
|
||||||
License GPLv3+: GNU GPL version 3 or later
|
License GPLv3+: GNU GPL version 3 or later
|
||||||
<http://gnu.org/licenses/gpl.html>.
|
<http://gnu.org/licenses/gpl.html>.
|
||||||
This is free software: you are free to change and redistribute it.
|
This is free software: you are free to change and redistribute it.
|
||||||
|
137
docs/body.md
137
docs/body.md
@ -1,34 +1,139 @@
|
|||||||
KNOWN ISSUES
|
## OPTIONS
|
||||||
------------
|
|
||||||
|
|
||||||
- autojump does not support directories that begin with `-`.
|
Options must be passed to 'autojump' and not the 'j' wrapper function.
|
||||||
|
|
||||||
- For bash users, autojump keeps track of directories by modifying
|
-i, --increase manually increase current directory weight
|
||||||
`$PROMPT_COMMAND`. Do not overwrite `$PROMPT_COMMAND`:
|
|
||||||
|
-d, --decrease manually decrease current directory weight
|
||||||
|
|
||||||
|
--purge deletes database entries that no longer exist on system
|
||||||
|
|
||||||
|
-s, --stat show general stats and top 100 database entries
|
||||||
|
|
||||||
|
--version show version information and exit
|
||||||
|
|
||||||
|
ADVANCED USAGE
|
||||||
|
--------------
|
||||||
|
|
||||||
|
- Using Multiple Arguments
|
||||||
|
|
||||||
|
Let's assume the following database:
|
||||||
|
|
||||||
|
30 /home/user/mail/inbox
|
||||||
|
10 /home/user/work/inbox
|
||||||
|
|
||||||
|
`j in` would jump into /home/user/mail/inbox as the higher weighted
|
||||||
|
entry. However you can pass multiple arguments to autojump to prefer
|
||||||
|
a different entry. In the above example, `j w in` would then jump
|
||||||
|
you into /home/user/work/inbox.
|
||||||
|
|
||||||
|
- Jump To A Child Directory.
|
||||||
|
|
||||||
|
Sometimes it's convenient to jump to a child directory (sub-directory of
|
||||||
|
current directory) rather than typing out the full name.
|
||||||
|
|
||||||
|
jc images
|
||||||
|
|
||||||
|
- Open File Manager To Directories (instead of jumping)
|
||||||
|
|
||||||
|
Instead of jumping to a directory, you can open a file explorer window (Mac
|
||||||
|
Finder, Windows Explorer, GNOME Nautilus, etc) to the directory instead.
|
||||||
|
|
||||||
|
jo music
|
||||||
|
|
||||||
|
Opening a file manager to a child directory is also supported.
|
||||||
|
|
||||||
|
jco images
|
||||||
|
|
||||||
|
ADDITIONAL CONFIGURATION
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
- Enable ZSH Tab Completion
|
||||||
|
|
||||||
|
ZSH tab completion requires the `compinit` module to be loaded.
|
||||||
|
Please add the following line to your \~/.zshrc *after* loading autojump:
|
||||||
|
|
||||||
|
autoload -U compinit && compinit
|
||||||
|
|
||||||
|
For security compinit checks completion system if files will be owned by
|
||||||
|
root or the current user. This check can be ignored by using the -u flag:
|
||||||
|
|
||||||
|
autoload -U compinit && compinit -u
|
||||||
|
|
||||||
|
Tab completion requires two tabs before autojump will display the
|
||||||
|
completion menu. However if `setopt nolistambiguous` is enabled,
|
||||||
|
then only one tab is required.
|
||||||
|
|
||||||
|
- Always Ignore Case
|
||||||
|
|
||||||
|
Default behavior is to prioritize exact matches over all else. For
|
||||||
|
example, `j foo` will prefer /foobar over /FooBar even if the latter
|
||||||
|
has a higher weight. To change this behavior and ignore case, add
|
||||||
|
the following environmental variable in your \~/.bashrc:
|
||||||
|
|
||||||
|
export AUTOJUMP_IGNORE_CASE=1
|
||||||
|
|
||||||
|
- Prefer Symbolic Links
|
||||||
|
|
||||||
|
Default behavior is to evaluate symbolic links into full paths as to
|
||||||
|
reduce duplicate entries in the database. However, some users prefer
|
||||||
|
a shorter working directory path in their shell prompt. To switch
|
||||||
|
behavior to prefer symbolic links, add the following environmental
|
||||||
|
variable in your \~/.bashrc:
|
||||||
|
|
||||||
|
export AUTOJUMP_KEEP_SYMLINKS=1
|
||||||
|
|
||||||
|
- Autocomplete Additional Commands (Bash only)
|
||||||
|
|
||||||
|
Autojump can be used to autocomplete other commands (e.g. cp or
|
||||||
|
vim). To use this feature, add the following environmental variable
|
||||||
|
in your \~/.bashrc:
|
||||||
|
|
||||||
|
export AUTOJUMP_AUTOCOMPLETE_CMDS='cp vim'
|
||||||
|
|
||||||
|
Changes require reloading autojump to take into effect.
|
||||||
|
|
||||||
|
## KNOWN ISSUES
|
||||||
|
|
||||||
|
- For bash users, autojump keeps track of directories as a pre-command hook by
|
||||||
|
modifying \$PROMPT\_COMMAND. If you overwrite \$PROMPT\_COMMAND in ~/.bashrc you
|
||||||
|
can cause problems. Don't do this:
|
||||||
|
|
||||||
export PROMPT_COMMAND="history -a"
|
export PROMPT_COMMAND="history -a"
|
||||||
|
|
||||||
Instead append to the end of the existing \$PROMPT\_COMMAND:
|
Do this:
|
||||||
|
|
||||||
export PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND ;} history -a"
|
export PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND ;} history -a"
|
||||||
|
|
||||||
REPORTING BUGS
|
- The jump function `j` does not support directories that begin with `-`. If you
|
||||||
--------------
|
want to jump a directory called `--music`, try using `j music` instead of `j
|
||||||
|
--music`.
|
||||||
|
|
||||||
For any questions or issues please visit:
|
## FILES
|
||||||
|
|
||||||
https://github.com/wting/autojump/issues
|
If installed locally, autojump is self-contained in _~/.autojump/_.
|
||||||
|
|
||||||
AUTHORS
|
The database is stored in _$XDG\_DATA\_HOME/autojump/autojump.txt_.
|
||||||
-------
|
|
||||||
|
## REPORTING BUGS
|
||||||
|
|
||||||
|
For any usage related issues or feature requests please visit:
|
||||||
|
|
||||||
|
_https://github.com/joelthelion/autojump/issues_
|
||||||
|
|
||||||
|
## THANKS
|
||||||
|
|
||||||
|
Special thanks goes out to: Pierre Gueth, Simon Marache-Francisco, Daniel
|
||||||
|
Jackoway, and many others.
|
||||||
|
|
||||||
|
## AUTHORS
|
||||||
|
|
||||||
autojump was originally written by Joël Schaerer, and currently maintained by
|
autojump was originally written by Joël Schaerer, and currently maintained by
|
||||||
William Ting. More contributors can be found in `AUTHORS`.
|
William Ting.
|
||||||
|
|
||||||
COPYRIGHT
|
## COPYRIGHT
|
||||||
---------
|
|
||||||
|
|
||||||
Copyright © 2016 Free Software Foundation, Inc. License GPLv3+: GNU GPL version
|
Copyright © 2012 Free Software Foundation, Inc. License GPLv3+: GNU GPL version
|
||||||
3 or later <http://gnu.org/licenses/gpl.html>. This is free software: you are
|
3 or later <http://gnu.org/licenses/gpl.html>. This is free software: you are
|
||||||
free to change and redistribute it. There is NO WARRANTY, to the extent
|
free to change and redistribute it. There is NO WARRANTY, to the extent
|
||||||
permitted by law.
|
permitted by law.
|
||||||
|
9
docs/development.md
Normal file
9
docs/development.md
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
## DEVELOPMENT
|
||||||
|
|
||||||
|
The source code is primarily in `./bin/autojump`. Various shell wrapper scripts
|
||||||
|
are also available in `./bin/`.
|
||||||
|
|
||||||
|
Documentation is in various files under `./docs/`. Build documentation with the
|
||||||
|
command:
|
||||||
|
|
||||||
|
make docs
|
@ -1,56 +1,23 @@
|
|||||||
NAME
|
## NAME
|
||||||
----
|
|
||||||
|
|
||||||
autojump - a faster way to navigate your filesystem
|
autojump - a faster way to navigate your filesystem
|
||||||
|
|
||||||
DESCRIPTION
|
## SYNOPSIS
|
||||||
-----------
|
|
||||||
|
Jump to a previously visited directory that contains 'foo':
|
||||||
|
|
||||||
|
j foo
|
||||||
|
|
||||||
|
Jump to a previously visited subdirectory of the current directory:
|
||||||
|
|
||||||
|
jc bar
|
||||||
|
|
||||||
|
Show database entries and their respective key weights:
|
||||||
|
|
||||||
|
j --stat
|
||||||
|
|
||||||
|
## DESCRIPTION
|
||||||
|
|
||||||
autojump is a faster way to navigate your filesystem. It works by maintaining a
|
autojump is a faster way to navigate your filesystem. It works by maintaining a
|
||||||
database of the directories you use the most from the command line.
|
database of the directories you use the most from the command line. Directories
|
||||||
|
must be visited first before they can be jumped to.
|
||||||
*Directories must be visited first before they can be jumped to.*
|
|
||||||
|
|
||||||
USAGE
|
|
||||||
-----
|
|
||||||
|
|
||||||
`j` is a convenience wrapper function around `autojump`. Any option that can
|
|
||||||
be used with `autojump` can be used with `j` and vice versa.
|
|
||||||
|
|
||||||
- Jump To A Directory That Contains `foo`:
|
|
||||||
|
|
||||||
j foo
|
|
||||||
|
|
||||||
- Jump To A Child Directory:
|
|
||||||
|
|
||||||
Sometimes it's convenient to jump to a child directory (sub-directory of
|
|
||||||
current directory) rather than typing out the full name.
|
|
||||||
|
|
||||||
jc bar
|
|
||||||
|
|
||||||
- Open File Manager To Directories (instead of jumping):
|
|
||||||
|
|
||||||
Instead of jumping to a directory, you can open a file explorer window (Mac
|
|
||||||
Finder, Windows Explorer, GNOME Nautilus, etc.) to the directory instead.
|
|
||||||
|
|
||||||
jo music
|
|
||||||
|
|
||||||
Opening a file manager to a child directory is also supported:
|
|
||||||
|
|
||||||
jco images
|
|
||||||
|
|
||||||
- Using Multiple Arguments:
|
|
||||||
|
|
||||||
Let's assume the following database:
|
|
||||||
|
|
||||||
30 /home/user/mail/inbox
|
|
||||||
10 /home/user/work/inbox
|
|
||||||
|
|
||||||
`j in` would jump into /home/user/mail/inbox as the higher weighted
|
|
||||||
entry. However you can pass multiple arguments to autojump to prefer
|
|
||||||
a different entry. In the above example, `j w in` would then change
|
|
||||||
directory to /home/user/work/inbox.
|
|
||||||
|
|
||||||
For more options refer to help:
|
|
||||||
|
|
||||||
autojump --help
|
|
||||||
|
102
docs/install.md
102
docs/install.md
@ -2,75 +2,77 @@
|
|||||||
|
|
||||||
### REQUIREMENTS
|
### REQUIREMENTS
|
||||||
|
|
||||||
- Python v2.6+ or Python v3.3+
|
- Python v2.6+
|
||||||
- Supported shells
|
- Bash v4.0 for tab completion (or zsh)
|
||||||
- bash - first class support
|
|
||||||
- zsh - first class support
|
|
||||||
- fish - community supported
|
|
||||||
- tcsh - community supported
|
|
||||||
- clink - community supported
|
|
||||||
- Supported platforms
|
|
||||||
- Linux - first class support
|
|
||||||
- OS X - first class support
|
|
||||||
- Windows - community supported
|
|
||||||
- BSD - community supported
|
|
||||||
- Supported installation methods
|
|
||||||
- source code - first class support
|
|
||||||
- Debian and derivatives - first class support
|
|
||||||
- ArchLinux / Gentoo / openSUSE / RedHat and derivatives - community supported
|
|
||||||
- Homebrew / MacPorts - community supported
|
|
||||||
|
|
||||||
Due to limited time and resources, only "first class support" items will be
|
If you are unable to update Python to a supported version, older versions of
|
||||||
maintained by the primary committers. All "community supported" items will be
|
autojump can be [downloaded][dl] and installed manually.
|
||||||
updated based on pull requests submitted by the general public.
|
|
||||||
|
|
||||||
Please continue opening issues and providing feedback for community supported
|
- Python v2.4 is supported by [release v12][v12].
|
||||||
items since consolidating information helps other users troubleshoot and submit
|
|
||||||
enhancements and fixes.
|
|
||||||
|
|
||||||
### MANUAL
|
### AUTOMATIC INSTALLATION
|
||||||
|
|
||||||
Grab a copy of autojump:
|
**Linux**
|
||||||
|
|
||||||
git clone git://github.com/wting/autojump.git
|
|
||||||
|
|
||||||
Run the installation script and follow on screen instructions.
|
|
||||||
|
|
||||||
cd autojump
|
|
||||||
./install.py or ./uninstall.py
|
|
||||||
|
|
||||||
### AUTOMATIC
|
|
||||||
|
|
||||||
#### Linux
|
|
||||||
|
|
||||||
autojump is included in the following distro repositories, please use relevant
|
autojump is included in the following distro repositories, please use relevant
|
||||||
package management utilities to install (e.g. apt-get, yum, pacman, etc):
|
package management utilities to install (e.g. yum, apt-get, etc):
|
||||||
|
|
||||||
- Debian, Ubuntu, Linux Mint
|
|
||||||
|
|
||||||
All Debian-derived distros require manual activation for policy reasons,
|
|
||||||
please see `/usr/share/doc/autojump/README.Debian`.
|
|
||||||
|
|
||||||
|
- Debian\* testing/unstable, Ubuntu, Linux Mint
|
||||||
- RedHat, Fedora, CentOS
|
- RedHat, Fedora, CentOS
|
||||||
|
|
||||||
Install `autojump-zsh` for zsh, `autojump-fish` for fish, etc.
|
|
||||||
|
|
||||||
- ArchLinux
|
- ArchLinux
|
||||||
- Gentoo
|
- Gentoo
|
||||||
- Frugalware
|
- Frugalware
|
||||||
- Slackware
|
- Slackware
|
||||||
|
|
||||||
#### OS X
|
\* Requires manual activation for policy reasons, please see
|
||||||
|
``/usr/share/doc/autojump/README.Debian``.
|
||||||
|
|
||||||
|
**Mac**
|
||||||
|
|
||||||
Homebrew is the recommended installation method for Mac OS X:
|
Homebrew is the recommended installation method for Mac OS X:
|
||||||
|
|
||||||
brew install autojump
|
brew install autojump
|
||||||
|
|
||||||
MacPorts is also available:
|
MacPorts also available:
|
||||||
|
|
||||||
port install autojump
|
port install autojump
|
||||||
|
|
||||||
## Windows
|
**Other**
|
||||||
|
|
||||||
Windows support is enabled by [clink](https://mridgers.github.io/clink/) which
|
Please check the [Wiki][wiki] for an up to date listing of installation methods.
|
||||||
should be installed prior to installing autojump.
|
|
||||||
|
### MANUAL INSTALLATION
|
||||||
|
|
||||||
|
Grab a copy of autojump:
|
||||||
|
|
||||||
|
git clone git://github.com/joelthelion/autojump.git
|
||||||
|
|
||||||
|
Run the installation script:
|
||||||
|
|
||||||
|
cd autojump
|
||||||
|
./install.sh [ --local ]
|
||||||
|
|
||||||
|
and follow on screen instructions.
|
||||||
|
|
||||||
|
### MANUAL UNINSTALLATION
|
||||||
|
|
||||||
|
It is recommended to use your distribution's relevant package management
|
||||||
|
utilities, unless you installed manually or ran into uninstallation issues.
|
||||||
|
|
||||||
|
Grab a copy of autojump:
|
||||||
|
|
||||||
|
git clone git://github.com/joelthelion/autojump.git
|
||||||
|
|
||||||
|
Run the uninstallation script:
|
||||||
|
|
||||||
|
cd autojump
|
||||||
|
./uninstall.sh
|
||||||
|
|
||||||
|
and follow on screen instructions.
|
||||||
|
|
||||||
|
If you keep getting `autojump: command not found` at the prompt, do:`unset
|
||||||
|
PROMPT_COMMAND`. You can also restart your shell.
|
||||||
|
|
||||||
|
[dl]: https://github.com/joelthelion/autojump/downloads
|
||||||
|
[v12]: https://github.com/downloads/joelthelion/autojump/autojump_v12.tar.gz
|
||||||
|
[wiki]: https://github.com/joelthelion/autojump/wiki
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
% autojump(1) release-v22.5.3
|
% autojump(1) release-v20
|
||||||
%
|
%
|
||||||
% 2018-09-09
|
% 10 April 2012
|
||||||
|
236
install.py
236
install.py
@ -1,236 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import os
|
|
||||||
import platform
|
|
||||||
import shutil
|
|
||||||
import sys
|
|
||||||
|
|
||||||
sys.path.append('bin')
|
|
||||||
from autojump_argparse import ArgumentParser # noqa
|
|
||||||
|
|
||||||
SUPPORTED_SHELLS = ('bash', 'zsh', 'fish', 'tcsh')
|
|
||||||
|
|
||||||
|
|
||||||
def cp(src, dest, dryrun=False):
|
|
||||||
print('copying file: %s -> %s' % (src, dest))
|
|
||||||
if not dryrun:
|
|
||||||
shutil.copy(src, dest)
|
|
||||||
|
|
||||||
|
|
||||||
def get_shell():
|
|
||||||
return os.path.basename(os.getenv('SHELL', ''))
|
|
||||||
|
|
||||||
|
|
||||||
def mkdir(path, dryrun=False):
|
|
||||||
print('creating directory:', path)
|
|
||||||
if not dryrun and not os.path.exists(path):
|
|
||||||
os.makedirs(path)
|
|
||||||
|
|
||||||
|
|
||||||
def modify_autojump_sh(etc_dir, share_dir, dryrun=False):
|
|
||||||
"""Append custom installation path to autojump.sh"""
|
|
||||||
custom_install = '\
|
|
||||||
\n# check custom install \
|
|
||||||
\nif [ -s %s/autojump.${shell} ]; then \
|
|
||||||
\n source %s/autojump.${shell} \
|
|
||||||
\nfi\n' % (share_dir, share_dir)
|
|
||||||
|
|
||||||
with open(os.path.join(etc_dir, 'autojump.sh'), 'a') as f:
|
|
||||||
f.write(custom_install)
|
|
||||||
|
|
||||||
|
|
||||||
def modify_autojump_lua(clink_dir, bin_dir, dryrun=False):
|
|
||||||
"""Prepend custom AUTOJUMP_BIN_DIR definition to autojump.lua"""
|
|
||||||
custom_install = "local AUTOJUMP_BIN_DIR = \"%s\"\n" % bin_dir.replace(
|
|
||||||
'\\',
|
|
||||||
'\\\\',
|
|
||||||
)
|
|
||||||
clink_file = os.path.join(clink_dir, 'autojump.lua')
|
|
||||||
with open(clink_file, 'r') as f:
|
|
||||||
original = f.read()
|
|
||||||
with open(clink_file, 'w') as f:
|
|
||||||
f.write(custom_install + original)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_arguments(): # noqa
|
|
||||||
if platform.system() == 'Windows':
|
|
||||||
default_user_destdir = os.path.join(
|
|
||||||
os.getenv('LOCALAPPDATA', ''),
|
|
||||||
'autojump',
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
default_user_destdir = os.path.join(
|
|
||||||
os.path.expanduser('~'),
|
|
||||||
'.autojump',
|
|
||||||
)
|
|
||||||
default_user_prefix = ''
|
|
||||||
default_user_zshshare = 'functions'
|
|
||||||
default_system_destdir = '/'
|
|
||||||
default_system_prefix = '/usr/local'
|
|
||||||
default_system_zshshare = '/usr/share/zsh/site-functions'
|
|
||||||
default_clink_dir = os.path.join(os.getenv('LOCALAPPDATA', ''), 'clink')
|
|
||||||
|
|
||||||
parser = ArgumentParser(
|
|
||||||
description='Installs autojump globally for root users, otherwise \
|
|
||||||
installs in current user\'s home directory.'
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-n', '--dryrun', action='store_true', default=False,
|
|
||||||
help='simulate installation',
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-f', '--force', action='store_true', default=False,
|
|
||||||
help='skip root user, shell type, Python version checks',
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-d', '--destdir', metavar='DIR', default=default_user_destdir,
|
|
||||||
help='set destination to DIR',
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-p', '--prefix', metavar='DIR', default=default_user_prefix,
|
|
||||||
help='set prefix to DIR',
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-z', '--zshshare', metavar='DIR', default=default_user_zshshare,
|
|
||||||
help='set zsh share destination to DIR',
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-c', '--clinkdir', metavar='DIR', default=default_clink_dir,
|
|
||||||
help='set clink directory location to DIR (Windows only)',
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-s', '--system', action='store_true', default=False,
|
|
||||||
help='install system wide for all users',
|
|
||||||
)
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
if not args.force:
|
|
||||||
if sys.version_info[0] == 2 and sys.version_info[1] < 6:
|
|
||||||
print('Python v2.6+ or v3.0+ required.', file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
if args.system:
|
|
||||||
if platform.system() == 'Windows':
|
|
||||||
print(
|
|
||||||
'System-wide installation is not supported on Windows.',
|
|
||||||
file=sys.stderr,
|
|
||||||
)
|
|
||||||
sys.exit(1)
|
|
||||||
elif os.geteuid() != 0:
|
|
||||||
print(
|
|
||||||
'Please rerun as root for system-wide installation.',
|
|
||||||
file=sys.stderr,
|
|
||||||
)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
if platform.system() != 'Windows' \
|
|
||||||
and get_shell() not in SUPPORTED_SHELLS:
|
|
||||||
print(
|
|
||||||
'Unsupported shell: %s' % os.getenv('SHELL'),
|
|
||||||
file=sys.stderr,
|
|
||||||
)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
if args.destdir != default_user_destdir \
|
|
||||||
or args.prefix != default_user_prefix \
|
|
||||||
or args.zshshare != default_user_zshshare:
|
|
||||||
args.custom_install = True
|
|
||||||
else:
|
|
||||||
args.custom_install = False
|
|
||||||
|
|
||||||
if args.system:
|
|
||||||
if args.custom_install:
|
|
||||||
print(
|
|
||||||
'Custom paths incompatible with --system option.',
|
|
||||||
file=sys.stderr,
|
|
||||||
)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
args.destdir = default_system_destdir
|
|
||||||
args.prefix = default_system_prefix
|
|
||||||
args.zshshare = default_system_zshshare
|
|
||||||
|
|
||||||
return args
|
|
||||||
|
|
||||||
|
|
||||||
def show_post_installation_message(etc_dir, share_dir, bin_dir):
|
|
||||||
if platform.system() == 'Windows':
|
|
||||||
print('\nPlease manually add %s to your user path' % bin_dir)
|
|
||||||
else:
|
|
||||||
if get_shell() == 'fish':
|
|
||||||
aj_shell = '%s/autojump.fish' % share_dir
|
|
||||||
source_msg = 'if test -f %s; . %s; end' % (aj_shell, aj_shell)
|
|
||||||
rcfile = '~/.config/fish/config.fish'
|
|
||||||
else:
|
|
||||||
aj_shell = '%s/autojump.sh' % etc_dir
|
|
||||||
source_msg = '[[ -s %s ]] && source %s' % (aj_shell, aj_shell)
|
|
||||||
|
|
||||||
if platform.system() == 'Darwin' and get_shell() == 'bash':
|
|
||||||
rcfile = '~/.profile'
|
|
||||||
else:
|
|
||||||
rcfile = '~/.%src' % get_shell()
|
|
||||||
|
|
||||||
print('\nPlease manually add the following line(s) to %s:' % rcfile)
|
|
||||||
print('\n\t' + source_msg)
|
|
||||||
if get_shell() == 'zsh':
|
|
||||||
print('\n\tautoload -U compinit && compinit -u')
|
|
||||||
|
|
||||||
print('\nPlease restart terminal(s) before running autojump.\n')
|
|
||||||
|
|
||||||
|
|
||||||
def main(args):
|
|
||||||
if args.dryrun:
|
|
||||||
print('Installing autojump to %s (DRYRUN)...' % args.destdir)
|
|
||||||
else:
|
|
||||||
print('Installing autojump to %s ...' % args.destdir)
|
|
||||||
|
|
||||||
bin_dir = os.path.join(args.destdir, args.prefix, 'bin')
|
|
||||||
etc_dir = os.path.join(args.destdir, 'etc', 'profile.d')
|
|
||||||
doc_dir = os.path.join(args.destdir, args.prefix, 'share', 'man', 'man1')
|
|
||||||
share_dir = os.path.join(args.destdir, args.prefix, 'share', 'autojump')
|
|
||||||
zshshare_dir = os.path.join(args.destdir, args.zshshare)
|
|
||||||
|
|
||||||
mkdir(bin_dir, args.dryrun)
|
|
||||||
mkdir(doc_dir, args.dryrun)
|
|
||||||
mkdir(etc_dir, args.dryrun)
|
|
||||||
mkdir(share_dir, args.dryrun)
|
|
||||||
|
|
||||||
cp('./bin/autojump', bin_dir, args.dryrun)
|
|
||||||
cp('./bin/autojump_argparse.py', bin_dir, args.dryrun)
|
|
||||||
cp('./bin/autojump_data.py', bin_dir, args.dryrun)
|
|
||||||
cp('./bin/autojump_match.py', bin_dir, args.dryrun)
|
|
||||||
cp('./bin/autojump_utils.py', bin_dir, args.dryrun)
|
|
||||||
cp('./bin/icon.png', share_dir, args.dryrun)
|
|
||||||
cp('./docs/autojump.1', doc_dir, args.dryrun)
|
|
||||||
|
|
||||||
if platform.system() == 'Windows':
|
|
||||||
cp('./bin/autojump.lua', args.clinkdir, args.dryrun)
|
|
||||||
cp('./bin/autojump.bat', bin_dir, args.dryrun)
|
|
||||||
cp('./bin/j.bat', bin_dir, args.dryrun)
|
|
||||||
cp('./bin/jc.bat', bin_dir, args.dryrun)
|
|
||||||
cp('./bin/jo.bat', bin_dir, args.dryrun)
|
|
||||||
cp('./bin/jco.bat', bin_dir, args.dryrun)
|
|
||||||
|
|
||||||
if args.custom_install:
|
|
||||||
modify_autojump_lua(args.clinkdir, bin_dir, args.dryrun)
|
|
||||||
else:
|
|
||||||
mkdir(etc_dir, args.dryrun)
|
|
||||||
mkdir(share_dir, args.dryrun)
|
|
||||||
mkdir(zshshare_dir, args.dryrun)
|
|
||||||
|
|
||||||
cp('./bin/autojump.sh', etc_dir, args.dryrun)
|
|
||||||
cp('./bin/autojump.bash', share_dir, args.dryrun)
|
|
||||||
cp('./bin/autojump.fish', share_dir, args.dryrun)
|
|
||||||
cp('./bin/autojump.zsh', share_dir, args.dryrun)
|
|
||||||
cp('./bin/_j', zshshare_dir, args.dryrun)
|
|
||||||
|
|
||||||
if args.custom_install:
|
|
||||||
modify_autojump_sh(etc_dir, share_dir, args.dryrun)
|
|
||||||
|
|
||||||
show_post_installation_message(etc_dir, share_dir, bin_dir)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
sys.exit(main(parse_arguments()))
|
|
248
install.sh
Executable file
248
install.sh
Executable file
@ -0,0 +1,248 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
function help_msg {
|
||||||
|
echo "./install.sh [OPTION..]"
|
||||||
|
echo
|
||||||
|
echo " -a, --auto Try to determine destdir, prefix (and zshshare if applicable)"
|
||||||
|
echo " -g, --global Use default global settings (destdir=/; prefix=usr)"
|
||||||
|
echo " -l, --local Use default local settings (destdir=~/.autojump)"
|
||||||
|
echo
|
||||||
|
echo " -d, --destdir PATH Set install destination to PATH"
|
||||||
|
echo " -p, --prefix PATH Use PATH as prefix"
|
||||||
|
echo " -Z, --zshshare PATH Use PATH as zsh share destination"
|
||||||
|
echo
|
||||||
|
echo " -f, --force Ignore Python version check"
|
||||||
|
echo " -n, --dry_run Only show installation paths, don't install anything"
|
||||||
|
echo
|
||||||
|
echo "Will install autojump into:"
|
||||||
|
echo
|
||||||
|
echo ' Binaries: $destdir$prefix/bin'
|
||||||
|
echo ' Documentation: $destdir$prefix/share/man/man1'
|
||||||
|
echo ' Icon: $destdir$prefix/share/autojump'
|
||||||
|
echo ' Shell scripts: $destdir/etc/profile.d'
|
||||||
|
echo ' zsh functions: $destdir$zshsharedir'
|
||||||
|
echo
|
||||||
|
echo 'Unless specified, $zshshare will be :'
|
||||||
|
echo ' - $destdir$prefix/functions for local installations'
|
||||||
|
echo ' - $destdir$prefix/share/zsh/site-functions for all other installations'
|
||||||
|
}
|
||||||
|
|
||||||
|
dry_run=
|
||||||
|
local=
|
||||||
|
global=
|
||||||
|
force=
|
||||||
|
shell=`echo ${SHELL} | awk -F/ '{ print $NF }'`
|
||||||
|
destdir=
|
||||||
|
prefix="usr/local"
|
||||||
|
zshsharedir=
|
||||||
|
|
||||||
|
# If no arguments passed, default to --auto.
|
||||||
|
if [[ ${#} == 0 ]]; then
|
||||||
|
set -- "--auto"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Only dry-run should also default to --auto
|
||||||
|
if [[ ${#} == 1 ]] && ([[ $1 = "-n" ]] || [[ $1 = "--dry-run" ]]); then
|
||||||
|
set -- "-n" "--auto"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Command line parsing
|
||||||
|
while true; do
|
||||||
|
case "$1" in
|
||||||
|
-a|--auto)
|
||||||
|
if [[ ${UID} -eq 0 ]]; then
|
||||||
|
set -- "--global" "${@:2}"
|
||||||
|
else
|
||||||
|
set -- "--local" "${@:2}"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
-d|--destdir)
|
||||||
|
if [ $# -gt 1 ]; then
|
||||||
|
destdir=$2; shift 2
|
||||||
|
else
|
||||||
|
echo "--destdir or -d requires an argument" 1>&2
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
-f|--force)
|
||||||
|
force=true
|
||||||
|
shift
|
||||||
|
if [[ ${#} == 0 ]]; then
|
||||||
|
set -- "--auto"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
-g|--global)
|
||||||
|
global=true
|
||||||
|
destdir=
|
||||||
|
prefix=usr
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-h|--help|-\?)
|
||||||
|
help_msg;
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
-l|--local)
|
||||||
|
local=true
|
||||||
|
destdir=~/.autojump
|
||||||
|
prefix=
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-n|--dry_run)
|
||||||
|
dry_run=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-p|--prefix)
|
||||||
|
if [ $# -gt 1 ]; then
|
||||||
|
prefix=$2; shift 2
|
||||||
|
else
|
||||||
|
echo "--prefix or -p requires an argument" 1>&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
-Z|--zshshare)
|
||||||
|
if [ $# -gt 1 ]; then
|
||||||
|
zshsharedir=$2; shift 2
|
||||||
|
else
|
||||||
|
echo "--zshshare or -Z requires an argument" 1>&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
--)
|
||||||
|
shift
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
-*)
|
||||||
|
echo "invalid option: $1" 1>&2;
|
||||||
|
help_msg;
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# destdir must be a full path, and end with a slash
|
||||||
|
if [[ -n ${destdir} ]]; then
|
||||||
|
if [[ ${destdir:0:1} != "/" ]]; then
|
||||||
|
echo "Error: destdir must be a full path" 1>&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
len=${#destdir}
|
||||||
|
if [[ ${destdir:len - 1} != "/" ]]; then
|
||||||
|
destdir="$destdir/"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
destdir="/"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# prefix should not start with, and end with, a slash
|
||||||
|
if [[ -n ${prefix} ]]; then
|
||||||
|
if [[ ${prefix:0:1} == "/" ]]; then
|
||||||
|
prefix=${prefix:1}
|
||||||
|
fi
|
||||||
|
len=${#prefix}
|
||||||
|
if [[ ${prefix:len - 1} != "/" ]]; then
|
||||||
|
prefix="$prefix/"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# check shell support
|
||||||
|
if [[ ${shell} != "bash" ]] && [[ ${shell} != "zsh" ]] \
|
||||||
|
&& [[ ${shell} != "fish" ]]; then
|
||||||
|
echo "Unsupported shell (${shell}). Only Bash and Zsh shells are supported."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# zsh functions
|
||||||
|
if [[ $shell == "zsh" ]]; then
|
||||||
|
if [[ -z $zshsharedir ]]; then
|
||||||
|
# if not set, use a default
|
||||||
|
if [[ $local ]]; then
|
||||||
|
zshsharedir="${prefix}functions"
|
||||||
|
else
|
||||||
|
zshsharedir="${prefix}share/zsh/site-functions"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# check Python version
|
||||||
|
if [ ! ${force} ]; then
|
||||||
|
python_version=`python -c 'import sys; print(sys.version_info[:])'`
|
||||||
|
|
||||||
|
if [[ ${python_version:1:1} -eq 2 && ${python_version:4:1} -lt 6 ]]; then
|
||||||
|
echo
|
||||||
|
echo "Incompatible Python version, please upgrade to v2.6+."
|
||||||
|
if [[ ${python_version:4:1} -ge 4 ]]; then
|
||||||
|
echo
|
||||||
|
echo "Alternatively, you can download v12 that supports Python v2.4+ from:"
|
||||||
|
echo
|
||||||
|
echo -e "\thttps://github.com/joelthelion/autojump/downloads"
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "Installating autojump..."
|
||||||
|
echo
|
||||||
|
echo "Destination: $destdir"
|
||||||
|
if [[ -n $prefix ]]; then
|
||||||
|
echo "Prefix: /$prefix"
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
echo "Binary: ${destdir}${prefix}bin/"
|
||||||
|
echo "Documentation: ${destdir}${prefix}share/man/man1/"
|
||||||
|
echo "Icon: ${destdir}${prefix}share/autojump/"
|
||||||
|
echo "Shell scripts: ${destdir}etc/profile.d/"
|
||||||
|
if [[ -z $shell ]] || [[ $shell == "zsh" ]]; then
|
||||||
|
echo "zsh functions: ${destdir}${zshsharedir}"
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
|
||||||
|
if [[ $dry_run ]]; then
|
||||||
|
echo "--dry_run (-n) used, stopping"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
# INSTALL AUTOJUMP
|
||||||
|
mkdir -p ${destdir}${prefix}share/autojump/ || exit 1
|
||||||
|
mkdir -p ${destdir}${prefix}bin/ || exit 1
|
||||||
|
mkdir -p ${destdir}${prefix}share/man/man1/ || exit 1
|
||||||
|
cp -v ./bin/icon.png ${destdir}${prefix}share/autojump/ || exit 1
|
||||||
|
cp -v ./bin/autojump ${destdir}${prefix}bin/ || exit 1
|
||||||
|
cp -v ./bin/autojump_argparse.py ${destdir}${prefix}bin/ || exit 1
|
||||||
|
cp -v ./docs/autojump.1 ${destdir}${prefix}share/man/man1/ || exit 1
|
||||||
|
mkdir -p ${destdir}etc/profile.d/ || exit 1
|
||||||
|
cp -v ./bin/autojump.sh ${destdir}etc/profile.d/ || exit 1
|
||||||
|
cp -v ./bin/autojump.bash ${destdir}etc/profile.d/ || exit 1
|
||||||
|
cp -v ./bin/autojump.zsh ${destdir}etc/profile.d/ || exit 1
|
||||||
|
cp -v ./bin/autojump.fish ${destdir}etc/profile.d/ || exit 1
|
||||||
|
mkdir -p ${destdir}${zshsharedir} || exit 1
|
||||||
|
# TODO: remove unused _j function (2013.02.01_1348, ting)
|
||||||
|
install -v -m 0755 ./bin/_j ${destdir}${zshsharedir} || exit 1
|
||||||
|
|
||||||
|
# MODIFY AUTOJUMP.SH FOR CUSTOM INSTALLS
|
||||||
|
if [[ -z ${local} ]] && [[ -z ${global} ]]; then
|
||||||
|
sed -i "s:#custom#\t::g" ${destdir}etc/profile.d/autojump.sh
|
||||||
|
sed -i "s:destdir_install\t:${destdir}etc/profile.d:g" ${destdir}etc/profile.d/autojump.sh
|
||||||
|
fi
|
||||||
|
|
||||||
|
# DISPLAY ADD MESSAGE
|
||||||
|
rc_file="~/.${shell}rc"
|
||||||
|
if [[ `uname` == "Darwin" ]] && [[ ${shell} == "bash" ]]; then
|
||||||
|
rc_file="~/.bash_profile"
|
||||||
|
fi
|
||||||
|
|
||||||
|
aj_shell_file="${destdir}etc/profile.d/autojump.${shell}"
|
||||||
|
if [[ ${local} ]]; then
|
||||||
|
aj_shell_file="~/.autojump/etc/profile.d/autojump.${shell}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "Please add the line to ${rc_file} :"
|
||||||
|
echo
|
||||||
|
echo -e "[[ -s ${aj_shell_file} ]] && . ${aj_shell_file}"
|
||||||
|
echo
|
||||||
|
echo "You need to run 'source ${rc_file}' before you can start using autojump. To remove autojump, run './uninstall.sh'"
|
||||||
|
echo
|
@ -1,131 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
sys.path.append(os.path.join(os.getcwd(), 'bin')) # noqa
|
|
||||||
from autojump_data import Entry
|
|
||||||
from autojump_match import match_anywhere
|
|
||||||
from autojump_match import match_consecutive
|
|
||||||
|
|
||||||
|
|
||||||
class TestMatchAnywhere(object):
|
|
||||||
|
|
||||||
entry1 = Entry('/foo/bar/baz', 10)
|
|
||||||
entry2 = Entry('/baz/foo/bar', 10)
|
|
||||||
entry3 = Entry('/foo/baz', 10)
|
|
||||||
entry4 = Entry('/中/zhong/国/guo', 10)
|
|
||||||
entry5 = Entry('/is\'t/this/a/b*tchin/edge/case?', 10)
|
|
||||||
win_entry1 = Entry('C:\\foo\\bar\\baz', 10)
|
|
||||||
win_entry2 = Entry('D:\Program Files (x86)\GIMP', 10)
|
|
||||||
win_entry3 = Entry('C:\Windows\System32', 10)
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def haystack(self):
|
|
||||||
return [
|
|
||||||
self.entry1,
|
|
||||||
self.entry2,
|
|
||||||
self.entry3,
|
|
||||||
self.entry4,
|
|
||||||
self.entry5,
|
|
||||||
]
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def windows_haystack(self):
|
|
||||||
return [self.win_entry1, self.win_entry2, self.win_entry3]
|
|
||||||
|
|
||||||
def test_single_needle(self, haystack):
|
|
||||||
assert list(match_anywhere(['bar'], haystack)) == [self.entry1, self.entry2]
|
|
||||||
|
|
||||||
def test_consecutive(self, haystack):
|
|
||||||
assert list(match_anywhere(['foo', 'bar'], haystack)) \
|
|
||||||
== [self.entry1, self.entry2]
|
|
||||||
assert list(match_anywhere(['bar', 'foo'], haystack)) == []
|
|
||||||
|
|
||||||
def test_skip(self, haystack):
|
|
||||||
assert list(match_anywhere(['baz', 'bar'], haystack)) == [self.entry2]
|
|
||||||
assert list(match_anywhere(['中', '国'], haystack)) == [self.entry4]
|
|
||||||
|
|
||||||
def test_ignore_case(self, haystack):
|
|
||||||
assert list(match_anywhere(['bAz', 'bAR'], haystack, ignore_case=True)) \
|
|
||||||
== [self.entry2]
|
|
||||||
|
|
||||||
def test_backslashes_for_windows_paths(self, windows_haystack):
|
|
||||||
# https://github.com/wting/autojump/issues/281
|
|
||||||
assert list(match_anywhere(['foo', 'baz'], windows_haystack)) \
|
|
||||||
== [self.win_entry1]
|
|
||||||
assert list(match_anywhere(['program', 'gimp'], windows_haystack, True)) \
|
|
||||||
== [self.win_entry2]
|
|
||||||
assert list(match_anywhere(['win', '32'], windows_haystack, True)) \
|
|
||||||
== [self.win_entry3]
|
|
||||||
|
|
||||||
def test_wildcard_in_needle(self, haystack):
|
|
||||||
# https://github.com/wting/autojump/issues/402
|
|
||||||
assert list(match_anywhere(['*', 'this'], haystack)) == []
|
|
||||||
assert list(match_anywhere(['this', '*'], haystack)) == [self.entry5]
|
|
||||||
|
|
||||||
|
|
||||||
class TestMatchConsecutive(object):
|
|
||||||
|
|
||||||
entry1 = Entry('/foo/bar/baz', 10)
|
|
||||||
entry2 = Entry('/baz/foo/bar', 10)
|
|
||||||
entry3 = Entry('/foo/baz', 10)
|
|
||||||
entry4 = Entry('/中/zhong/国/guo', 10)
|
|
||||||
entry5 = Entry('/日/本', 10)
|
|
||||||
entry6 = Entry('/is\'t/this/a/b*tchin/edge/case?', 10)
|
|
||||||
win_entry1 = Entry('C:\Foo\Bar\Baz', 10)
|
|
||||||
win_entry2 = Entry('D:\Program Files (x86)\GIMP', 10)
|
|
||||||
win_entry3 = Entry('C:\Windows\System32', 10)
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def haystack(self):
|
|
||||||
return [
|
|
||||||
self.entry1,
|
|
||||||
self.entry2,
|
|
||||||
self.entry3,
|
|
||||||
self.entry4,
|
|
||||||
self.entry5,
|
|
||||||
]
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def windows_haystack(self):
|
|
||||||
return [self.win_entry1, self.win_entry2, self.win_entry3]
|
|
||||||
|
|
||||||
def test_single_needle(self, haystack):
|
|
||||||
assert list(match_consecutive(['baz'], haystack)) == [self.entry1, self.entry3]
|
|
||||||
assert list(match_consecutive(['本'], haystack)) == [self.entry5]
|
|
||||||
|
|
||||||
def test_consecutive(self, haystack):
|
|
||||||
assert list(match_consecutive(['bar', 'baz'], haystack)) == [self.entry1]
|
|
||||||
assert list(match_consecutive(['foo', 'bar'], haystack)) == [self.entry2]
|
|
||||||
assert list(match_consecutive(['国', 'guo'], haystack)) == [self.entry4]
|
|
||||||
assert list(match_consecutive(['bar', 'foo'], haystack)) == []
|
|
||||||
|
|
||||||
def test_ignore_case(self, haystack):
|
|
||||||
assert list(match_consecutive(['FoO', 'bAR'], haystack, ignore_case=True)) \
|
|
||||||
== [self.entry2]
|
|
||||||
|
|
||||||
def test_windows_ignore_case(self, windows_haystack):
|
|
||||||
assert list(match_consecutive(['gimp'], windows_haystack, True)) == [self.win_entry2]
|
|
||||||
|
|
||||||
@pytest.mark.xfail(reason='https://github.com/wting/autojump/issues/418')
|
|
||||||
def test_backslashes_for_windows_paths(self, windows_haystack):
|
|
||||||
assert list(match_consecutive(['program', 'gimp'], windows_haystack, True)) \
|
|
||||||
== [self.win_entry2]
|
|
||||||
|
|
||||||
@pytest.mark.xfail(reason='https://github.com/wting/autojump/issues/418')
|
|
||||||
def test_foo_bar_baz(self, windows_haystack):
|
|
||||||
assert list(match_consecutive(['bar', 'baz'], windows_haystack, ignore_case=True)) \
|
|
||||||
== [self.win_entry1]
|
|
||||||
|
|
||||||
@pytest.mark.xfail(reason='https://github.com/wting/autojump/issues/402')
|
|
||||||
def test_thing(self, windows_haystack):
|
|
||||||
assert list(match_consecutive(['win', '32'], windows_haystack, True)) \
|
|
||||||
== [self.win_entry3]
|
|
||||||
|
|
||||||
@pytest.mark.xfail(reason='https://github.com/wting/autojump/issues/402')
|
|
||||||
def test_wildcard_in_needle(self, haystack):
|
|
||||||
assert list(match_consecutive(['*', 'this'], haystack)) == []
|
|
||||||
assert list(match_consecutive(['*', 'edge', 'case'], haystack)) == [self.entry6]
|
|
@ -1,145 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
import mock
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
sys.path.append(os.path.join(os.getcwd(), 'bin')) # noqa
|
|
||||||
import autojump_utils
|
|
||||||
from autojump_utils import encode_local
|
|
||||||
from autojump_utils import first
|
|
||||||
from autojump_utils import get_tab_entry_info
|
|
||||||
from autojump_utils import has_uppercase
|
|
||||||
from autojump_utils import in_bash
|
|
||||||
from autojump_utils import is_python3
|
|
||||||
from autojump_utils import last
|
|
||||||
from autojump_utils import sanitize
|
|
||||||
from autojump_utils import second
|
|
||||||
from autojump_utils import surround_quotes
|
|
||||||
from autojump_utils import take
|
|
||||||
from autojump_utils import unico
|
|
||||||
|
|
||||||
|
|
||||||
if is_python3():
|
|
||||||
os.getcwdu = os.getcwd
|
|
||||||
xrange = range
|
|
||||||
|
|
||||||
|
|
||||||
def u(string):
|
|
||||||
"""
|
|
||||||
This is a unicode() wrapper since u'string' is a Python3 compiler error.
|
|
||||||
"""
|
|
||||||
if is_python3():
|
|
||||||
return string
|
|
||||||
return unicode(string, encoding='utf-8', errors='strict')
|
|
||||||
|
|
||||||
|
|
||||||
# strings
|
|
||||||
@pytest.mark.skipif(is_python3(), reason='Unicode sucks.')
|
|
||||||
@mock.patch.object(sys, 'getfilesystemencoding', return_value='ascii')
|
|
||||||
def test_encode_local_ascii(_):
|
|
||||||
assert encode_local(u('foo')) == b'foo'
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(is_python3(), reason='Unicode sucks.')
|
|
||||||
@pytest.mark.xfail(reason='disabled due to pytest bug: https://bitbucket.org/hpk42/pytest/issue/534/pytest-fails-to-catch-unicodedecodeerrors') # noqa
|
|
||||||
@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'
|
|
||||||
assert not in_bash()
|
|
||||||
|
|
||||||
|
|
||||||
# helper functions
|
|
||||||
def test_get_needle():
|
|
||||||
assert get_tab_entry_info('foo__', '__') == ('foo', None, None)
|
|
||||||
|
|
||||||
|
|
||||||
def test_get_index():
|
|
||||||
assert get_tab_entry_info('foo__2', '__') == ('foo', 2, None)
|
|
||||||
|
|
||||||
|
|
||||||
def test_get_path():
|
|
||||||
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)
|
|
@ -1,39 +1,32 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
"""
|
||||||
IPython autojump magic
|
IPython autojump magic
|
||||||
|
|
||||||
Written by keith hughitt <keith.hughitt@gmail.com>, based on an earlier
|
Written by keith hughitt <keith.hughitt@gmail.com>, based on an earlier
|
||||||
version by Mario Pastorelli <pastorelli.mario@gmail.com>.
|
version by Mario Pastorelli <pastorelli.mario@gmail.com>.
|
||||||
|
|
||||||
To install, create a new IPython user profile by running:
|
To install, `create a new IPython user profile <http://ipython.org/ipython-doc/stable/config/ipython.html#configuring-ipython>`_
|
||||||
|
if you have not already done so by running:
|
||||||
|
|
||||||
ipython profile create
|
ipython profile create
|
||||||
|
|
||||||
And copy this file into the "startup" folder of your new profile (e.g.
|
And copy this file into the "startup" folder of your new profile (e.g.
|
||||||
"$HOME/.config/ipython/profile_default/startup/").
|
"$HOME/.config/ipython/profile_default/startup/").
|
||||||
|
|
||||||
@TODO: extend %cd to call "autojump -a"
|
@TODO: extend %cd to call "autojump -a"
|
||||||
"""
|
"""
|
||||||
from subprocess import PIPE
|
import os
|
||||||
from subprocess import Popen
|
import subprocess as sub
|
||||||
|
from IPython.core.magic import (register_line_magic, register_cell_magic,
|
||||||
from IPython.core.magic import register_line_magic
|
register_line_cell_magic)
|
||||||
|
|
||||||
ip = get_ipython() # noqa
|
|
||||||
|
|
||||||
|
ip = get_ipython()
|
||||||
|
|
||||||
@register_line_magic
|
@register_line_magic
|
||||||
def j(path):
|
def j(path):
|
||||||
cmd = ['autojump'] + path.split()
|
cmd = ['autojump'] + path.split()
|
||||||
newpath = Popen(
|
newpath = sub.Popen(cmd, stdout=sub.PIPE, shell=False).communicate()[0].strip()
|
||||||
cmd,
|
|
||||||
stdout=PIPE,
|
|
||||||
shell=False,
|
|
||||||
).communicate()[0].strip()
|
|
||||||
|
|
||||||
if newpath:
|
if newpath:
|
||||||
ip.magic('cd %s' % newpath.decode('utf-8'))
|
ip.magic('cd %s' % newpath.decode('utf-8'))
|
||||||
|
|
||||||
|
|
||||||
# remove from namespace
|
# remove from namespace
|
||||||
del j
|
del j
|
||||||
|
33
tox.ini
33
tox.ini
@ -1,33 +0,0 @@
|
|||||||
[tox]
|
|
||||||
envlist =
|
|
||||||
py26,
|
|
||||||
py27,
|
|
||||||
py33,
|
|
||||||
py34,
|
|
||||||
py35
|
|
||||||
# ignore missing setup.py
|
|
||||||
skipsdist = True
|
|
||||||
|
|
||||||
[testenv]
|
|
||||||
setenv =
|
|
||||||
PYTHONDONTWRITEBYTECODE = 1
|
|
||||||
deps =
|
|
||||||
mock
|
|
||||||
coverage
|
|
||||||
ipdb
|
|
||||||
ipython
|
|
||||||
pytest >= 2.9
|
|
||||||
commands =
|
|
||||||
coverage run --source=bin/ --omit=bin/autojump_argparse.py -m \
|
|
||||||
py.test -vv -rxs --tb native -s --strict {posargs:tests}
|
|
||||||
coverage report -m
|
|
||||||
|
|
||||||
|
|
||||||
[testenv:pre-commit]
|
|
||||||
deps =
|
|
||||||
pre-commit>=0.7.0
|
|
||||||
commands =
|
|
||||||
pre-commit {posargs}
|
|
||||||
|
|
||||||
[pytest]
|
|
||||||
norecursedirs = .git .tox docs
|
|
217
uninstall.py
217
uninstall.py
@ -1,217 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import os
|
|
||||||
import platform
|
|
||||||
import shutil
|
|
||||||
import sys
|
|
||||||
|
|
||||||
sys.path.append('bin')
|
|
||||||
from autojump_argparse import ArgumentParser # noqa
|
|
||||||
|
|
||||||
|
|
||||||
def is_empty_dir(path):
|
|
||||||
"""
|
|
||||||
Checks if any files are present within a directory and all sub-directories.
|
|
||||||
"""
|
|
||||||
for _, _, files in os.walk(path):
|
|
||||||
if files:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def parse_arguments():
|
|
||||||
default_clink_dir = os.path.join(os.getenv('LOCALAPPDATA', ''), 'clink')
|
|
||||||
|
|
||||||
parser = ArgumentParser(
|
|
||||||
description='Uninstalls autojump.',
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-n', '--dryrun', action='store_true', default=False,
|
|
||||||
help='simulate installation',
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-u', '--userdata', action='store_true', default=False,
|
|
||||||
help='delete user data',
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-d', '--destdir', metavar='DIR',
|
|
||||||
help='custom destdir',
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-p', '--prefix', metavar='DIR', default='',
|
|
||||||
help='custom prefix',
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-z', '--zshshare', metavar='DIR', default='functions',
|
|
||||||
help='custom zshshare',
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-c', '--clinkdir', metavar='DIR', default=default_clink_dir,
|
|
||||||
)
|
|
||||||
|
|
||||||
return parser.parse_args()
|
|
||||||
|
|
||||||
|
|
||||||
def remove_custom_installation(args, dryrun=False):
|
|
||||||
if not args.destdir:
|
|
||||||
return
|
|
||||||
|
|
||||||
bin_dir = os.path.join(args.destdir, args.prefix, 'bin')
|
|
||||||
doc_dir = os.path.join(args.destdir, args.prefix, 'share', 'man', 'man1')
|
|
||||||
etc_dir = os.path.join(args.destdir, 'etc', 'profile.d')
|
|
||||||
share_dir = os.path.join(args.destdir, args.prefix, 'share', 'autojump')
|
|
||||||
zshshare_dir = os.path.join(args.destdir, args.zshshare)
|
|
||||||
|
|
||||||
if not os.path.exists(share_dir):
|
|
||||||
return
|
|
||||||
|
|
||||||
print('\nFound custom installation...')
|
|
||||||
rm(os.path.join(bin_dir, 'autojump'), dryrun)
|
|
||||||
rm(os.path.join(bin_dir, 'autojump_data.py'), dryrun)
|
|
||||||
rm(os.path.join(bin_dir, 'autojump_utils.py'), dryrun)
|
|
||||||
rm(os.path.join(bin_dir, 'autojump_argparse.py'), dryrun)
|
|
||||||
if platform.system() == 'Windows':
|
|
||||||
if os.path.exists(args.clinkdir):
|
|
||||||
rm(os.path.join(args.clinkdir, 'autojump.lua'), dryrun)
|
|
||||||
rm(os.path.join(bin_dir, 'autojump.bat'), dryrun)
|
|
||||||
rm(os.path.join(bin_dir, 'j.bat'), dryrun)
|
|
||||||
rm(os.path.join(bin_dir, 'jc.bat'), dryrun)
|
|
||||||
rm(os.path.join(bin_dir, 'jco.bat'), dryrun)
|
|
||||||
rm(os.path.join(bin_dir, 'jo.bat'), dryrun)
|
|
||||||
else:
|
|
||||||
rm(os.path.join(etc_dir, 'autojump.sh'), dryrun)
|
|
||||||
rm(os.path.join(share_dir, 'autojump.bash'), dryrun)
|
|
||||||
rm(os.path.join(share_dir, 'autojump.fish'), dryrun)
|
|
||||||
rm(os.path.join(share_dir, 'autojump.tcsh'), dryrun)
|
|
||||||
rm(os.path.join(share_dir, 'autojump.zsh'), dryrun)
|
|
||||||
rm(os.path.join(zshshare_dir, '_j'), dryrun)
|
|
||||||
rmdir(share_dir, dryrun)
|
|
||||||
rm(os.path.join(doc_dir, 'autojump.1'), dryrun)
|
|
||||||
|
|
||||||
if is_empty_dir(args.destdir):
|
|
||||||
rmdir(args.destdir, dryrun)
|
|
||||||
|
|
||||||
|
|
||||||
def remove_system_installation(dryrun=False):
|
|
||||||
default_destdir = '/'
|
|
||||||
default_prefix = '/usr/local'
|
|
||||||
default_zshshare = '/usr/share/zsh/site-functions'
|
|
||||||
|
|
||||||
bin_dir = os.path.join(default_destdir, default_prefix, 'bin')
|
|
||||||
doc_dir = os.path.join(
|
|
||||||
default_destdir,
|
|
||||||
default_prefix,
|
|
||||||
'share',
|
|
||||||
'man',
|
|
||||||
'man1',
|
|
||||||
)
|
|
||||||
etc_dir = os.path.join(default_destdir, 'etc', 'profile.d')
|
|
||||||
share_dir = os.path.join(
|
|
||||||
default_destdir,
|
|
||||||
default_prefix,
|
|
||||||
'share',
|
|
||||||
'autojump',
|
|
||||||
)
|
|
||||||
zshshare_dir = os.path.join(default_destdir, default_zshshare)
|
|
||||||
|
|
||||||
if not os.path.exists(share_dir):
|
|
||||||
return
|
|
||||||
|
|
||||||
print('\nFound system installation...')
|
|
||||||
|
|
||||||
if os.geteuid() != 0:
|
|
||||||
print(
|
|
||||||
'Please rerun as root for system-wide uninstall, skipping...',
|
|
||||||
file=sys.stderr,
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
rm(os.path.join(bin_dir, 'autojump'), dryrun)
|
|
||||||
rm(os.path.join(bin_dir, 'autojump_data.py'), dryrun)
|
|
||||||
rm(os.path.join(bin_dir, 'autojump_utils.py'), dryrun)
|
|
||||||
rm(os.path.join(etc_dir, 'autojump.sh'), dryrun)
|
|
||||||
rm(os.path.join(share_dir, 'autojump.bash'), dryrun)
|
|
||||||
rm(os.path.join(share_dir, 'autojump.fish'), dryrun)
|
|
||||||
rm(os.path.join(share_dir, 'autojump.tcsh'), dryrun)
|
|
||||||
rm(os.path.join(share_dir, 'autojump.zsh'), dryrun)
|
|
||||||
rm(os.path.join(zshshare_dir, '_j'), dryrun)
|
|
||||||
rmdir(share_dir, dryrun)
|
|
||||||
rm(os.path.join(doc_dir, 'autojump.1'), dryrun)
|
|
||||||
|
|
||||||
|
|
||||||
def remove_user_data(dryrun=False):
|
|
||||||
if platform.system() == 'Darwin':
|
|
||||||
data_home = os.path.join(
|
|
||||||
os.path.expanduser('~'),
|
|
||||||
'Library',
|
|
||||||
'autojump',
|
|
||||||
)
|
|
||||||
elif platform.system() == 'Windows':
|
|
||||||
data_home = os.path.join(
|
|
||||||
os.getenv('APPDATA'),
|
|
||||||
'autojump',
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
data_home = os.getenv(
|
|
||||||
'XDG_DATA_HOME',
|
|
||||||
os.path.join(
|
|
||||||
os.path.expanduser('~'),
|
|
||||||
'.local',
|
|
||||||
'share',
|
|
||||||
'autojump',
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
if os.path.exists(data_home):
|
|
||||||
print('\nFound user data...')
|
|
||||||
rmdir(data_home, dryrun)
|
|
||||||
|
|
||||||
|
|
||||||
def remove_user_installation(dryrun=False):
|
|
||||||
if platform.system() == 'Windows':
|
|
||||||
default_destdir = os.path.join(
|
|
||||||
os.getenv('LOCALAPPDATA', ''),
|
|
||||||
'autojump',
|
|
||||||
)
|
|
||||||
clink_dir = os.path.join(os.getenv('LOCALAPPDATA', ''), 'clink')
|
|
||||||
else:
|
|
||||||
default_destdir = os.path.join(os.path.expanduser('~'), '.autojump')
|
|
||||||
|
|
||||||
if os.path.exists(default_destdir):
|
|
||||||
print('\nFound user installation...')
|
|
||||||
rmdir(default_destdir, dryrun)
|
|
||||||
if platform.system() == 'Windows' and os.path.exists(clink_dir):
|
|
||||||
rm(os.path.join(clink_dir, 'autojump.lua'), dryrun)
|
|
||||||
|
|
||||||
|
|
||||||
def rm(path, dryrun):
|
|
||||||
if os.path.exists(path):
|
|
||||||
print('deleting file:', path)
|
|
||||||
if not dryrun:
|
|
||||||
os.remove(path)
|
|
||||||
|
|
||||||
|
|
||||||
def rmdir(path, dryrun):
|
|
||||||
if os.path.exists(path):
|
|
||||||
print('deleting directory:', path)
|
|
||||||
if not dryrun:
|
|
||||||
shutil.rmtree(path)
|
|
||||||
|
|
||||||
|
|
||||||
def main(args):
|
|
||||||
if args.dryrun:
|
|
||||||
print('Uninstalling autojump (DRYRUN)...')
|
|
||||||
else:
|
|
||||||
print('Uninstalling autojump...')
|
|
||||||
|
|
||||||
remove_user_installation(args.dryrun)
|
|
||||||
remove_system_installation(args.dryrun)
|
|
||||||
remove_custom_installation(args, args.dryrun)
|
|
||||||
if args.userdata:
|
|
||||||
remove_user_data(args.dryrun)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
sys.exit(main(parse_arguments()))
|
|
94
uninstall.sh
Executable file
94
uninstall.sh
Executable file
@ -0,0 +1,94 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
function help_msg {
|
||||||
|
echo "sudo ./uninstall.sh [--prefix /usr/local]"
|
||||||
|
}
|
||||||
|
|
||||||
|
function remove_msg {
|
||||||
|
echo
|
||||||
|
echo "Please remove the line from .${2}rc :"
|
||||||
|
echo
|
||||||
|
if [ "${1}" == "global" ]; then
|
||||||
|
echo -e "\t[[ -s /etc/profile.d/autojump.${2} ]] && source /etc/profile.d/autojump.${2}"
|
||||||
|
elif [ "${1}" == "local" ]; then
|
||||||
|
echo -e "\t[[ -s ~/.autojump/etc/profile.d/autojump.${2} ]] && source ~/.autojump/etc/profile.d/autojump.${2}"
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
# Default install directory.
|
||||||
|
prefix=/usr
|
||||||
|
|
||||||
|
user=${SUDO_USER:-${USER}}
|
||||||
|
OS=`uname`
|
||||||
|
|
||||||
|
if [ $OS == 'Darwin' ]; then
|
||||||
|
user_home=$(dscl . -search /Users UniqueID ${user} | cut -d: -f6)
|
||||||
|
else
|
||||||
|
user_home=$(getent passwd ${user} | cut -d: -f6)
|
||||||
|
fi
|
||||||
|
bashrc_file=${user_home}/.bashrc
|
||||||
|
|
||||||
|
# Command line parsing
|
||||||
|
while true; do
|
||||||
|
case "$1" in
|
||||||
|
-h|--help|-\?) help_msg; exit 0;;
|
||||||
|
-p|--prefix)
|
||||||
|
if [ $# -gt 1 ]; then
|
||||||
|
prefix=$2; shift 2
|
||||||
|
else
|
||||||
|
echo "--prefix or -p require an argument" 1>&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
--) shift; break;;
|
||||||
|
-*) echo "invalid option: $1" 1>&2; help_msg; exit 1;;
|
||||||
|
*) break;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# UNINSTALL AUTOJUMP
|
||||||
|
# global / custom location installations
|
||||||
|
if [ -d "${prefix}/share/autojump/" ]; then
|
||||||
|
echo
|
||||||
|
echo "Uninstalling from ${prefix} ..."
|
||||||
|
echo
|
||||||
|
sudo rm -rv ${prefix}/share/autojump/
|
||||||
|
sudo rm -v ${prefix}/bin/autojump
|
||||||
|
sudo rm -v ${prefix}/share/man/man1/autojump.1
|
||||||
|
sudo rm -v /etc/profile.d/autojump.sh
|
||||||
|
|
||||||
|
if [ -f /etc/profile.d/autojump.bash ]; then
|
||||||
|
sudo rm -v /etc/profile.d/autojump.bash
|
||||||
|
remove_msg "global" "bash"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f /etc/profile.d/autojump.zsh ]; then
|
||||||
|
sudo rm -v /etc/profile.d/autojump.zsh
|
||||||
|
|
||||||
|
fpath=`/usr/bin/env zsh -c 'echo $fpath'`
|
||||||
|
for f in ${fpath}; do
|
||||||
|
if [[ -f ${f}/_j ]]; then
|
||||||
|
sudo rm -v ${f}/_j
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
remove_msg "global" "zsh"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# local installations
|
||||||
|
if [ -d ~/.autojump/ ]; then
|
||||||
|
echo
|
||||||
|
echo "Uninstalling from ~/.autojump/ ..."
|
||||||
|
echo
|
||||||
|
|
||||||
|
if [ -f ~/.autojump/etc/profile.d/autojump.bash ]; then
|
||||||
|
rm -rv ~/.autojump/
|
||||||
|
remove_msg "local" "bash"
|
||||||
|
fi
|
||||||
|
if [ -f ~/.autojump/etc/profile.d/autojump.zsh ]; then
|
||||||
|
rm -rv ~/.autojump/
|
||||||
|
remove_msg "local" "zsh"
|
||||||
|
fi
|
||||||
|
fi
|
Loading…
Reference in New Issue
Block a user