mirror of
https://github.com/wting/autojump
synced 2024-10-27 20:34:07 +00:00
Compare commits
313 Commits
release-v2
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
ff75f542ae | ||
|
96ae111824 | ||
|
06e082c918 | ||
|
af23852374 | ||
|
8fffbad95a | ||
|
daa496bc39 | ||
|
cf358d8fd3 | ||
|
bc4ea61546 | ||
|
8eace445a7 | ||
|
26c81fc39f | ||
|
900ce8e092 | ||
|
89eb573306 | ||
|
0cbfd764f5 | ||
|
a876bc1f39 | ||
|
fc43204ca1 | ||
|
965296f6b2 | ||
|
5ab005ea86 | ||
|
7494d142d5 | ||
|
4f84e755f5 | ||
|
b4e8474769 | ||
|
5e6bb82835 | ||
|
6a529f4f92 | ||
|
b06d686bfe | ||
|
a0719f488e | ||
|
0e4d15ace6 | ||
|
e7aebe69bf | ||
|
9ff654d41d | ||
|
46329ac744 | ||
|
37b336bf98 | ||
|
e8f3cbd874 | ||
|
d5a4fd270d | ||
|
f59e398c48 | ||
|
13a63fbf3a | ||
|
0bf1ad5ba9 | ||
|
3f0eae1be7 | ||
|
b0bc534838 | ||
|
865476ed56 | ||
|
3e089a3b32 | ||
|
2e2ffcfadb | ||
|
4f238bdd46 | ||
|
b2f243ee17 | ||
|
8eb094220b | ||
|
df935c664c | ||
|
cacbb68591 | ||
|
39990fff58 | ||
|
332698fdc5 | ||
|
c4d82b1888 | ||
|
7874719e4a | ||
|
9a26c1f17b | ||
|
851f3e3b2d | ||
|
242936f258 | ||
|
215cee3a93 | ||
|
b9e70a0eea | ||
|
7c7865ea7e | ||
|
5e550267c7 | ||
|
dc9e11e7d5 | ||
|
3cb4e8a28c | ||
|
cf013c6875 | ||
|
eafd6ac451 | ||
|
737563570e | ||
|
218d779b4d | ||
|
7922a9013d | ||
|
797d97c9bf | ||
|
2e60fa2892 | ||
|
180c5d8402 | ||
|
e75d4d4d11 | ||
|
be5b703996 | ||
|
94dae01b49 | ||
|
d1822bc11a | ||
|
a24d199161 | ||
|
9241b4b20f | ||
|
a32f237043 | ||
|
9622659099 | ||
|
61af2bf4c5 | ||
|
6df88c33d2 | ||
|
68e10ae402 | ||
|
3090963beb | ||
|
ecd272e979 | ||
|
0bce510c7e | ||
|
9a6e2869b1 | ||
|
9cf647bc6d | ||
|
25ef9c6a3c | ||
|
d529790278 | ||
|
e57956cc1c | ||
|
a9c892f713 | ||
|
db1c32ff6e | ||
|
377eadbad3 | ||
|
ed7ec4dbdd | ||
|
0b184f3bf0 | ||
|
5985ce604a | ||
|
a5e4b83e82 | ||
|
4230bbe2d1 | ||
|
aa366c3a4f | ||
|
14ea9513fd | ||
|
7ee214c9c2 | ||
|
8fa8b06349 | ||
|
f26a38e0f9 | ||
|
f6876ef3f0 | ||
|
3e5cec67b9 | ||
|
b71612eea4 | ||
|
d3dd3f34e6 | ||
|
113a84f9f0 | ||
|
f59eaf9bb1 | ||
|
d188d7e675 | ||
|
ffe22e1838 | ||
|
55f4eacc8a | ||
|
f09d23e30d | ||
|
8b525c1b55 | ||
|
59335b4109 | ||
|
fa3ff58d92 | ||
|
53683525d2 | ||
|
491b4fd27b | ||
|
c5f0473837 | ||
|
d177aaa12c | ||
|
7de39a2f9d | ||
|
d71a354abb | ||
|
ec7f788276 | ||
|
f75d01299d | ||
|
d6453dffef | ||
|
b4cbcc2fd2 | ||
|
c0c9398794 | ||
|
e621603e46 | ||
|
819c5c76cc | ||
|
fe5f78fe43 | ||
|
531a7321d3 | ||
|
4f90d5b755 | ||
|
e3f3257a8c | ||
|
77d9d6ebc2 | ||
|
86f663fa6e | ||
|
f480bd1315 | ||
|
0d80d91805 | ||
|
2095b2b129 | ||
|
896b1c8562 | ||
|
3c658dc64f | ||
|
b60932616b | ||
|
5538cf70f3 | ||
|
23be6ab233 | ||
|
c889aa013e | ||
|
581b8d9617 | ||
|
f23727ed0f | ||
|
62c0877479 | ||
|
921b52e9d5 | ||
|
567ae121ab | ||
|
349326c82c | ||
|
e30d7d392e | ||
|
969fb4e6ed | ||
|
3465bb1f84 | ||
|
2100f993b3 | ||
|
1e15497706 | ||
|
17565a907d | ||
|
68b457184d | ||
|
015deece87 | ||
|
fbf932c4f2 | ||
|
196d5233a0 | ||
|
95472620c7 | ||
|
27a01662a5 | ||
|
2f26642e7a | ||
|
c16a816d37 | ||
|
8c7f0bf994 | ||
|
225cdb2a8b | ||
|
903f79333a | ||
|
09289c59a5 | ||
|
6360876933 | ||
|
bc91905a29 | ||
|
72313dbc51 | ||
|
4826a0ef6b | ||
|
4bd62e2293 | ||
|
1d317dcd1a | ||
|
d0578b2c10 | ||
|
559ead890c | ||
|
615bb0cafb | ||
|
042428c41f | ||
|
9f3d7ab5f9 | ||
|
12a4667824 | ||
|
06ea178332 | ||
|
9db8c4feb3 | ||
|
255f548b4a | ||
|
5ba2774ff3 | ||
|
0d3aa06686 | ||
|
59d1e1fd9d | ||
|
681068a2bc | ||
|
1f045c2658 | ||
|
5f9ac19afd | ||
|
6e0e3741a5 | ||
|
ff9376cb93 | ||
|
d0d906f3cb | ||
|
7a756aaa4e | ||
|
de939863be | ||
|
19f09e5cb0 | ||
|
1d13c0d4ae | ||
|
53eeed8a99 | ||
|
09d8992289 | ||
|
4a1de9d599 | ||
|
3ef1195077 | ||
|
573c1ea418 | ||
|
3d6bf541cf | ||
|
b80c630ef8 | ||
|
f5d13da96c | ||
|
35bc63c66e | ||
|
d4f824d79f | ||
|
4716493681 | ||
|
de85828b79 | ||
|
1a0003d852 | ||
|
3f460fb3e9 | ||
|
4bb6dfe1ca | ||
|
dcb97e0d0c | ||
|
6f5e4dd2d1 | ||
|
c4ec07784a | ||
|
85824098c1 | ||
|
b3162c917b | ||
|
80d7ab660f | ||
|
795bdcc9a7 | ||
|
59e494a066 | ||
|
cc9b7c28cf | ||
|
fb1f397fee | ||
|
737ccf85c1 | ||
|
77eddd3c0b | ||
|
c15996db19 | ||
|
8ab23c01c4 | ||
|
2c999dca83 | ||
|
b0957e50eb | ||
|
3709536698 | ||
|
4c28a998b4 | ||
|
c0301c7cee | ||
|
c4feb1a2b2 | ||
|
5f8be97861 | ||
|
e5a97294ac | ||
|
9811922a77 | ||
|
6293af5b7a | ||
|
bec6314eab | ||
|
0caa91030f | ||
|
77b12e6dc5 | ||
|
78c6884895 | ||
|
0c50e8b94c | ||
|
bab752bf09 | ||
|
8ad3c5aefd | ||
|
c7c8bceac9 | ||
|
661f17791c | ||
|
a59d671fb0 | ||
|
23779d65a7 | ||
|
7b1c436ec6 | ||
|
172a74a5e4 | ||
|
d7992caeeb | ||
|
616596c0dc | ||
|
24d8ccb48e | ||
|
a9bf6dc608 | ||
|
a8057ed1db | ||
|
16d6e0cbcc | ||
|
895b9281f0 | ||
|
80a3f0da4d | ||
|
1c8a4c13cd | ||
|
d20ec4afb4 | ||
|
4aafd023c3 | ||
|
2a53341feb | ||
|
30b9708654 | ||
|
9139092847 | ||
|
99d92733ea | ||
|
0422d23a86 | ||
|
71861c4402 | ||
|
751ec6a7f2 | ||
|
13377acbbd | ||
|
c259978585 | ||
|
1e4ca4d67e | ||
|
3125c65378 | ||
|
551b2f3853 | ||
|
6ea43c4267 | ||
|
39e5b0b4cc | ||
|
d115075295 | ||
|
1472b417c3 | ||
|
b695cc3f7d | ||
|
067f653b50 | ||
|
30d1b6d6f2 | ||
|
c2189efb7b | ||
|
1a2a5a86f6 | ||
|
e51f595018 | ||
|
d9b205c935 | ||
|
bb04405cd6 | ||
|
bd091b8766 | ||
|
f84dffb7c7 | ||
|
fdeedb4f70 | ||
|
4c432fc5f1 | ||
|
9112dc97d9 | ||
|
92b6047962 | ||
|
95c81b7665 | ||
|
bde9ac1d9f | ||
|
35a0991385 | ||
|
694d150882 | ||
|
8cbd19cc79 | ||
|
7671fcbd06 | ||
|
39b5e3030d | ||
|
5fd2859f19 | ||
|
b4dcdffa9c | ||
|
dabc177bbd | ||
|
4d70c24b16 | ||
|
b980ce795e | ||
|
605deee8c6 | ||
|
d1fe6fead9 | ||
|
a312764d69 | ||
|
26db68a8e8 | ||
|
0b25bef134 | ||
|
986f02124e | ||
|
adde814ed3 | ||
|
195312acad | ||
|
72b8c0a660 | ||
|
d692bc644a | ||
|
07c0313430 | ||
|
fca26f3ef4 | ||
|
2a7b9835eb | ||
|
e22a346b56 | ||
|
e72369c1a9 | ||
|
6a639d59b2 | ||
|
e491a63175 | ||
|
701e454dd6 |
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# Ensure batch files are crlf
|
||||
*.bat text eol=crlf
|
8
.gitignore
vendored
8
.gitignore
vendored
@ -1,6 +1,10 @@
|
||||
tags
|
||||
bin/autojump.py
|
||||
.cache
|
||||
.coverage
|
||||
*.pyc
|
||||
__pycache__
|
||||
*~
|
||||
*.tar.gz
|
||||
*.patch
|
||||
.pytest_cache
|
||||
.tox
|
||||
tags
|
||||
|
51
.pre-commit-config.yaml
Normal file
51
.pre-commit-config.yaml
Normal file
@ -0,0 +1,51 @@
|
||||
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
Normal file
17
.travis.yml
Normal file
@ -0,0 +1,17 @@
|
||||
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
Normal file
194
CHANGES.md
Normal file
@ -0,0 +1,194 @@
|
||||
## 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
162
ChangeLog
@ -1,162 +0,0 @@
|
||||
|
||||
# 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
|
45
Makefile
45
Makefile
@ -1,19 +1,32 @@
|
||||
VERSION = $(shell grep -oE "[0-9]+\.[0-9]+\.[0-9]+" bin/autojump)
|
||||
TAGNAME = release-v$(VERSION)
|
||||
|
||||
.PHONY: docs install uninstall tar test
|
||||
|
||||
.PHONY: install
|
||||
install:
|
||||
install.sh
|
||||
./install.py
|
||||
|
||||
.PHONY: uninstall
|
||||
uninstall:
|
||||
uninstall.sh
|
||||
./uninstall.py
|
||||
|
||||
.PHONY: 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 markdown docs/header.md docs/install.md docs/development.md docs/body.md -o README.md
|
||||
pandoc -s -w markdown docs/header.md docs/install.md docs/body.md -o README.md
|
||||
|
||||
release: docs test
|
||||
.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
|
||||
# Check for tag existence
|
||||
# git describe release-$(VERSION) 2>&1 >/dev/null || exit 1
|
||||
|
||||
@ -30,10 +43,26 @@ release: docs test
|
||||
git archive --format=tar --prefix autojump_v$(VERSION)/ $(TAGNAME) | gzip > autojump_v$(VERSION).tar.gz
|
||||
sha1sum autojump_v$(VERSION).tar.gz
|
||||
|
||||
.PHONY: tar
|
||||
tar:
|
||||
# Create tagged archive
|
||||
git archive --format=tar --prefix autojump_v$(VERSION)/ $(TAGNAME) | gzip > autojump_v$(VERSION).tar.gz
|
||||
sha1sum autojump_v$(VERSION).tar.gz
|
||||
|
||||
test:
|
||||
@tests/runtests.py
|
||||
.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
|
||||
|
288
README.md
288
README.md
@ -3,273 +3,173 @@ NAME
|
||||
|
||||
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
|
||||
-----------
|
||||
|
||||
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.
|
||||
command line.
|
||||
|
||||
INSTALLATION
|
||||
------------
|
||||
*Directories must be visited first before they can be jumped to.*
|
||||
|
||||
### REQUIREMENTS
|
||||
USAGE
|
||||
-----
|
||||
|
||||
- Python v2.6+
|
||||
- Bash v4.0 for tab completion (or zsh)
|
||||
`j` is a convenience wrapper function around `autojump`. Any option that
|
||||
can be used with `autojump` can be used with `j` and vice versa.
|
||||
|
||||
If you are unable to update Python to a supported version, older
|
||||
versions of autojump can be
|
||||
[downloaded](https://github.com/joelthelion/autojump/downloads) and
|
||||
installed manually.
|
||||
- Jump To A Directory That Contains `foo`:
|
||||
|
||||
- Python v2.4 is supported by [release
|
||||
v12](https://github.com/downloads/joelthelion/autojump/autojump_v12.tar.gz).
|
||||
j foo
|
||||
|
||||
### AUTOMATIC INSTALLATION
|
||||
- Jump To A Child Directory:
|
||||
|
||||
**Linux**
|
||||
Sometimes it's convenient to jump to a child directory
|
||||
(sub-directory of current directory) rather than typing out the
|
||||
full name.
|
||||
|
||||
autojump is included in the following distro repositories, please use
|
||||
relevant package management utilities to install (e.g. yum, apt-get,
|
||||
etc):
|
||||
jc bar
|
||||
|
||||
- Debian\* testing/unstable, Ubuntu, Linux Mint
|
||||
- RedHat, Fedora, CentOS
|
||||
- ArchLinux
|
||||
- Gentoo
|
||||
- Frugalware
|
||||
- Slackware
|
||||
- Open File Manager To Directories (instead of jumping):
|
||||
|
||||
\* Requires manual activation for policy reasons, please see
|
||||
`/usr/share/doc/autojump/README.Debian`.
|
||||
Instead of jumping to a directory, you can open a file explorer
|
||||
window (Mac Finder, Windows Explorer, GNOME Nautilus, etc.) to the
|
||||
directory instead.
|
||||
|
||||
**Mac**
|
||||
jo music
|
||||
|
||||
Homebrew is the recommended installation method for Mac OS X:
|
||||
Opening a file manager to a child directory is also supported:
|
||||
|
||||
brew install autojump
|
||||
jco images
|
||||
|
||||
MacPorts also available:
|
||||
|
||||
port install autojump
|
||||
|
||||
**Other**
|
||||
|
||||
Please check the [Wiki](https://github.com/joelthelion/autojump/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
|
||||
|
||||
Unit tests are available in `./tests/`. Run unit tests with the command:
|
||||
|
||||
make test
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
|
||||
Options must be passed to 'autojump' and not the 'j' wrapper function.
|
||||
|
||||
-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
|
||||
- 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.
|
||||
`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.
|
||||
|
||||
- Jump To A Child Directory.
|
||||
For more options refer to help:
|
||||
|
||||
Sometimes it's convenient to jump to a child directory
|
||||
(sub-directory of current directory) rather than typing out the full
|
||||
name.
|
||||
autojump --help
|
||||
|
||||
jc images
|
||||
INSTALLATION
|
||||
------------
|
||||
|
||||
- Open File Manager To Directories (instead of jumping)
|
||||
### REQUIREMENTS
|
||||
|
||||
Instead of jumping to a directory, you can open a file explorer
|
||||
window (Mac Finder, Windows Explorer, GNOME Nautilus, etc) to the
|
||||
directory instead.
|
||||
- Python v2.6+ or Python v3.3+
|
||||
- Supported shells
|
||||
- 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
|
||||
|
||||
jo music
|
||||
Due to limited time and resources, only "first class support" items will
|
||||
be maintained by the primary committers. All "community supported" items
|
||||
will be updated based on pull requests submitted by the general public.
|
||||
|
||||
Opening a file manager to a child directory is also supported.
|
||||
Please continue opening issues and providing feedback for community
|
||||
supported items since consolidating information helps other users
|
||||
troubleshoot and submit enhancements and fixes.
|
||||
|
||||
jco images
|
||||
### MANUAL
|
||||
|
||||
ADDITIONAL CONFIGURATION
|
||||
------------------------
|
||||
Grab a copy of autojump:
|
||||
|
||||
- Enable ZSH Tab Completion
|
||||
git clone git://github.com/wting/autojump.git
|
||||
|
||||
ZSH tab completion requires the `compinit` module to be loaded.
|
||||
Please add the following line to your \~/.zshrc *after* loading
|
||||
autojump:
|
||||
Run the installation script and follow on screen instructions.
|
||||
|
||||
autoload -U compinit && compinit
|
||||
cd autojump
|
||||
./install.py or ./uninstall.py
|
||||
|
||||
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:
|
||||
### AUTOMATIC
|
||||
|
||||
autoload -U compinit && compinit -u
|
||||
#### Linux
|
||||
|
||||
Tab completion requires two tabs before autojump will display the
|
||||
completion menu. However if `setopt nolistambiguous` is enabled,
|
||||
then only one tab is required.
|
||||
autojump is included in the following distro repositories, please use
|
||||
relevant package management utilities to install (e.g. apt-get, yum,
|
||||
pacman, etc):
|
||||
|
||||
- Always Ignore Case
|
||||
- Debian, Ubuntu, Linux Mint
|
||||
|
||||
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:
|
||||
All Debian-derived distros require manual activation for policy
|
||||
reasons, please see `/usr/share/doc/autojump/README.Debian`.
|
||||
|
||||
export AUTOJUMP_IGNORE_CASE=1
|
||||
- RedHat, Fedora, CentOS
|
||||
|
||||
- Prefer Symbolic Links
|
||||
Install `autojump-zsh` for zsh, `autojump-fish` for fish, etc.
|
||||
|
||||
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:
|
||||
- ArchLinux
|
||||
- Gentoo
|
||||
- Frugalware
|
||||
- Slackware
|
||||
|
||||
export AUTOJUMP_KEEP_SYMLINKS=1
|
||||
#### OS X
|
||||
|
||||
- Autocomplete Additional Commands (Bash only)
|
||||
Homebrew is the recommended installation method for Mac OS X:
|
||||
|
||||
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:
|
||||
brew install autojump
|
||||
|
||||
export AUTOJUMP_AUTOCOMPLETE_CMDS='cp vim'
|
||||
MacPorts is also available:
|
||||
|
||||
Changes require reloading autojump to take into effect.
|
||||
port install autojump
|
||||
|
||||
Windows
|
||||
-------
|
||||
|
||||
Windows support is enabled by [clink](https://mridgers.github.io/clink/)
|
||||
which should be installed prior to installing autojump.
|
||||
|
||||
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:
|
||||
- autojump does not support directories that begin with `-`.
|
||||
|
||||
- For bash users, autojump keeps track of directories by modifying
|
||||
`$PROMPT_COMMAND`. Do not overwrite `$PROMPT_COMMAND`:
|
||||
|
||||
export PROMPT_COMMAND="history -a"
|
||||
|
||||
Do this:
|
||||
Instead append to the end of the existing \$PROMPT\_COMMAND:
|
||||
|
||||
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
|
||||
--------------
|
||||
|
||||
For any usage related issues or feature requests please visit:
|
||||
For any questions or issues please visit:
|
||||
|
||||
*https://github.com/joelthelion/autojump/issues*
|
||||
|
||||
THANKS
|
||||
------
|
||||
|
||||
Special thanks goes out to: Pierre Gueth, Simon Marache-Francisco,
|
||||
Daniel Jackoway, and many others.
|
||||
https://github.com/wting/autojump/issues
|
||||
|
||||
AUTHORS
|
||||
-------
|
||||
|
||||
autojump was originally written by Joël Schaerer, and currently
|
||||
maintained by William Ting.
|
||||
maintained by William Ting. More contributors can be found in `AUTHORS`.
|
||||
|
||||
COPYRIGHT
|
||||
---------
|
||||
|
||||
Copyright © 2012 Free Software Foundation, Inc. License GPLv3+: GNU GPL
|
||||
Copyright © 2016 Free Software Foundation, Inc. License GPLv3+: GNU GPL
|
||||
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
|
||||
WARRANTY, to the extent permitted by law.
|
||||
|
723
bin/autojump
723
bin/autojump
@ -1,513 +1,342 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright © 2008-2012 Joel Schaerer
|
||||
Copyright © 2012 William Ting
|
||||
Copyright © 2012-2016 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
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
from __future__ import division, print_function
|
||||
|
||||
import collections
|
||||
import difflib
|
||||
import math
|
||||
import operator
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
from itertools import chain
|
||||
from math import sqrt
|
||||
from operator import attrgetter
|
||||
from operator import itemgetter
|
||||
|
||||
try:
|
||||
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()
|
||||
if sys.version_info[0] == 3:
|
||||
ifilter = filter
|
||||
imap = map
|
||||
os.getcwdu = os.getcwd
|
||||
else:
|
||||
from itertools import ifilter
|
||||
from itertools import imap
|
||||
|
||||
class Database:
|
||||
"""
|
||||
Object for interfacing with autojump database file.
|
||||
"""
|
||||
# Vendorized argparse for Python 2.6 support
|
||||
from autojump_argparse import ArgumentParser
|
||||
|
||||
def __init__(self, config):
|
||||
self.config = config
|
||||
self.filename = config['db']
|
||||
self.data = collections.defaultdict(int)
|
||||
self.load()
|
||||
# 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
|
||||
|
||||
def __len__(self):
|
||||
return len(self.data)
|
||||
VERSION = '22.5.3'
|
||||
FUZZY_MATCH_THRESHOLD = 0.6
|
||||
TAB_ENTRIES_COUNT = 9
|
||||
TAB_SEPARATOR = '__'
|
||||
|
||||
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 ones 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 path weight.
|
||||
"""
|
||||
return self.data[path]
|
||||
|
||||
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 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):
|
||||
"""
|
||||
Deletes all entries that no longer exist on system.
|
||||
"""
|
||||
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 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]):
|
||||
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 set_defaults():
|
||||
config = {}
|
||||
|
||||
config['version'] = 'release-v21.6.9'
|
||||
config['max_paths'] = 1000
|
||||
config['separator'] = '__'
|
||||
config['home'] = os.path.expanduser('~')
|
||||
|
||||
config['ignore_case'] = False
|
||||
config['keep_symlinks'] = False
|
||||
config['debug'] = False
|
||||
config['match_cnt'] = 1
|
||||
|
||||
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['db'] = config['data'] + '/autojump.txt'
|
||||
if is_osx():
|
||||
data_home = os.path.join(os.path.expanduser('~'), 'Library')
|
||||
elif is_windows():
|
||||
data_home = os.getenv('APPDATA')
|
||||
else:
|
||||
data_home = os.getenv(
|
||||
'XDG_DATA_HOME',
|
||||
os.path.join(
|
||||
os.path.expanduser('~'),
|
||||
'.local',
|
||||
'share',
|
||||
),
|
||||
)
|
||||
config['data_path'] = os.path.join(data_home, 'autojump', 'autojump.txt')
|
||||
config['backup_path'] = os.path.join(data_home, 'autojump', 'autojump.txt.bak')
|
||||
|
||||
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'
|
||||
|
||||
if config['data'] == config['home']:
|
||||
config['db'] = config['data'] + '/.autojump.txt'
|
||||
|
||||
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
|
||||
|
||||
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.")
|
||||
def parse_arguments():
|
||||
parser = 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')
|
||||
'directory', metavar='DIRECTORY', nargs='*', default='',
|
||||
help='directory to jump to',
|
||||
)
|
||||
parser.add_argument(
|
||||
'-a', '--add', metavar='DIRECTORY',
|
||||
help='manually add path to database')
|
||||
'-a', '--add', metavar='DIRECTORY',
|
||||
help='add path',
|
||||
)
|
||||
parser.add_argument(
|
||||
'-i', '--increase', metavar='WEIGHT', nargs='?', type=int,
|
||||
const=20, default=False,
|
||||
help='manually increase path weight in database')
|
||||
'-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='manually decrease path weight in database')
|
||||
'-d', '--decrease', metavar='WEIGHT', nargs='?', type=int,
|
||||
const=15, default=False,
|
||||
help='decrease current directory weight',
|
||||
)
|
||||
parser.add_argument(
|
||||
'-b', '--bash', action="store_true", default=False,
|
||||
help='enclose directory quotes to prevent errors')
|
||||
'--complete', action='store_true', default=False,
|
||||
help='used for tab completion',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--complete', action="store_true", default=False,
|
||||
help='used for tab completion')
|
||||
'--purge', action='store_true', default=False,
|
||||
help='remove non-existent paths from database',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--purge', action="store_true", default=False,
|
||||
help='delete all database entries that no longer exist on system')
|
||||
'-s', '--stat', action='store_true', default=False,
|
||||
help='show database entries and their key weights',
|
||||
)
|
||||
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')
|
||||
'-v', '--version', action='version', version='%(prog)s v' +
|
||||
VERSION, help='show version information',
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
db = Database(config)
|
||||
return parser.parse_args()
|
||||
|
||||
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"):
|
||||
def add_path(data, path, weight=10):
|
||||
"""
|
||||
Decoding step for Python 2 which does not default to unicode.
|
||||
"""
|
||||
if sys.version_info[0] > 2:
|
||||
return text
|
||||
else:
|
||||
if encoding is None:
|
||||
encoding = sys.getfilesystemencoding()
|
||||
return text.decode(encoding, errors)
|
||||
Add a new path or increment an existing one.
|
||||
|
||||
def output_quotes(config, text):
|
||||
quotes = ""
|
||||
if config['args'].complete and config['args'].bash:
|
||||
quotes = "'"
|
||||
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 path == os.path.expanduser('~'):
|
||||
return data, Entry(path, 0)
|
||||
|
||||
output("%s%s%s" % (quotes, text, quotes))
|
||||
data[path] = sqrt((data.get(path, 0) ** 2) + (weight ** 2))
|
||||
|
||||
def output(text, encoding=None):
|
||||
"""
|
||||
Wrapper for the print function, using the filesystem encoding by default
|
||||
to minimize encoding mismatch problems in directory names.
|
||||
"""
|
||||
if sys.version_info[0] > 2:
|
||||
print(text)
|
||||
else:
|
||||
if encoding is None:
|
||||
encoding = sys.getfilesystemencoding()
|
||||
print(unicode(text).encode(encoding))
|
||||
return data, Entry(path, data[path])
|
||||
|
||||
def unico(text):
|
||||
"""
|
||||
If Python 2, convert to a unicode object.
|
||||
"""
|
||||
if sys.version_info[0] > 2:
|
||||
return text
|
||||
else:
|
||||
return unicode(text)
|
||||
|
||||
def match(path, pattern, only_end=False, ignore_case=False):
|
||||
"""
|
||||
Check whether a path matches a particular pattern, and return
|
||||
the remaining part of the string.
|
||||
"""
|
||||
if only_end:
|
||||
match_path = "/".join(path.split('/')[-1-pattern.count('/'):])
|
||||
else:
|
||||
match_path = 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])
|
||||
|
||||
if ignore_case:
|
||||
match_path = match_path.lower()
|
||||
pattern = pattern.lower()
|
||||
|
||||
find_idx = match_path.find(pattern)
|
||||
# truncate path to avoid matching a pattern multiple times
|
||||
if find_idx != -1:
|
||||
return (True, path)
|
||||
else:
|
||||
return (False, path[find_idx+len(pattern):])
|
||||
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)
|
||||
|
||||
def find_matches(config, db, patterns, ignore_case=False, fuzzy=False):
|
||||
"""
|
||||
Find paths matching patterns up to max_matches.
|
||||
"""
|
||||
try:
|
||||
current_dir = decode(os.path.realpath(os.curdir))
|
||||
pwd = os.getcwdu()
|
||||
except OSError:
|
||||
current_dir = None
|
||||
pwd = None
|
||||
|
||||
dirs = sorted(db.data.items(), key=operator.itemgetter(1), reverse=True)
|
||||
results = []
|
||||
# using closure to prevent constantly hitting hdd
|
||||
def is_cwd(entry):
|
||||
return os.path.realpath(entry.path) == pwd
|
||||
|
||||
if ignore_case:
|
||||
patterns = [p.lower() for p in patterns]
|
||||
|
||||
if fuzzy:
|
||||
# create dictionary of end paths to compare against
|
||||
end_dirs = {}
|
||||
for d in dirs:
|
||||
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]
|
||||
if check_entries:
|
||||
path_exists = lambda entry: os.path.exists(entry.path)
|
||||
else:
|
||||
patterns = [unico('')]
|
||||
path_exists = lambda _: True
|
||||
|
||||
# check for tab completion
|
||||
tab_choice = None
|
||||
tab_match = re.search(sep+r'([0-9]+)', patterns[-1])
|
||||
data = sorted(
|
||||
entries,
|
||||
key=attrgetter('weight', 'path'),
|
||||
reverse=True,
|
||||
)
|
||||
|
||||
# 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])
|
||||
return ifilter(
|
||||
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 handle_tab_completion(needle, entries):
|
||||
tab_needle, tab_index, tab_path = get_tab_entry_info(needle, TAB_SEPARATOR)
|
||||
|
||||
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], 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:
|
||||
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)
|
||||
print_tab_menu(
|
||||
needle,
|
||||
take(
|
||||
TAB_ENTRIES_COUNT, find_matches(
|
||||
entries,
|
||||
[needle],
|
||||
check_entries=False,
|
||||
),
|
||||
),
|
||||
TAB_SEPARATOR,
|
||||
)
|
||||
|
||||
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)
|
||||
def purge_missing_paths(entries):
|
||||
"""Remove non-existent paths from a list of entries."""
|
||||
exists = lambda entry: os.path.exists(entry.path)
|
||||
return ifilter(exists, entries)
|
||||
|
||||
# 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:
|
||||
def print_stats(data, data_path):
|
||||
for path, weight in sorted(data.items(), key=itemgetter(1)):
|
||||
print_entry(Entry(path, weight))
|
||||
|
||||
print('________________________________________\n')
|
||||
print('%d:\t total weight' % sum(data.values()))
|
||||
print('%d:\t number of entries' % len(data))
|
||||
|
||||
try:
|
||||
print_local(
|
||||
'%.2f:\t current directory weight' % data.get(os.getcwdu(), 0),
|
||||
)
|
||||
except OSError:
|
||||
# current directory no longer exists
|
||||
pass
|
||||
|
||||
print('\ndata:\t %s' % data_path)
|
||||
|
||||
|
||||
def main(args): # noqa
|
||||
if not is_autojump_sourced() and not is_windows():
|
||||
print("Please source the correct autojump file in your shell's")
|
||||
print('startup file. For more information, please reinstall autojump')
|
||||
print('and read the post installation instructions.')
|
||||
return 1
|
||||
|
||||
db.maintenance()
|
||||
config = set_defaults()
|
||||
|
||||
# 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
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main(parse_arguments()))
|
||||
|
@ -1,10 +1,31 @@
|
||||
_autojump()
|
||||
{
|
||||
export AUTOJUMP_SOURCED=1
|
||||
|
||||
# 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
|
||||
cur=${COMP_WORDS[*]:1}
|
||||
comps=$(autojump --bash --complete $cur)
|
||||
while read i
|
||||
do
|
||||
comps=$(autojump --complete $cur)
|
||||
while read i; do
|
||||
COMPREPLY=("${COMPREPLY[@]}" "${i}")
|
||||
done <<EOF
|
||||
$comps
|
||||
@ -12,52 +33,13 @@ EOF
|
||||
}
|
||||
complete -F _autojump j
|
||||
|
||||
_autojump_files()
|
||||
{
|
||||
if [[ ${COMP_WORDS[COMP_CWORD]} == *__* ]]; then
|
||||
local cur
|
||||
#cur=${COMP_WORDS[*]:1}
|
||||
cur=${COMP_WORDS[COMP_CWORD]}
|
||||
comps=$(autojump --bash --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() {
|
||||
if [[ "${AUTOJUMP_HOME}" == "${HOME}" ]]; then
|
||||
autojump -a "$(pwd ${_PWD_ARGS})" 1>/dev/null 2>>"${AUTOJUMP_DATA_DIR}/autojump_errors"
|
||||
if [[ -f "${AUTOJUMP_ERROR_PATH}" ]]; then
|
||||
(autojump --add "$(pwd)" >/dev/null 2>>${AUTOJUMP_ERROR_PATH} &) &>/dev/null
|
||||
else
|
||||
(autojump --add "$(pwd)" >/dev/null &) &>/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
@ -69,57 +51,79 @@ case $PROMPT_COMMAND in
|
||||
;;
|
||||
esac
|
||||
|
||||
function j {
|
||||
if [[ ${@} =~ ^-{1,2}.* ]]; then
|
||||
|
||||
# default autojump command
|
||||
j() {
|
||||
if [[ ${1} == -* ]] && [[ ${1} != "--" ]]; then
|
||||
autojump ${@}
|
||||
return
|
||||
fi
|
||||
|
||||
new_path="$(autojump ${@})"
|
||||
if [ -d "${new_path}" ]; then
|
||||
echo -e "\\033[31m${new_path}\\033[0m"
|
||||
cd "${new_path}"
|
||||
output="$(autojump ${@})"
|
||||
if [[ -d "${output}" ]]; then
|
||||
if [ -t 1 ]; then # if stdout is a terminal, use colors
|
||||
echo -e "\\033[31m${output}\\033[0m"
|
||||
else
|
||||
echo -e "${output}"
|
||||
fi
|
||||
cd "${output}"
|
||||
else
|
||||
echo "autojump: directory '${@}' not found"
|
||||
echo "\n${output}\n"
|
||||
echo "Try \`autojump --help\` for more information."
|
||||
false
|
||||
fi
|
||||
}
|
||||
|
||||
function jc {
|
||||
if [[ ${@} == -* ]]; then
|
||||
j ${@}
|
||||
|
||||
# jump to child directory (subdirectory of current path)
|
||||
jc() {
|
||||
if [[ ${1} == -* ]] && [[ ${1} != "--" ]]; then
|
||||
autojump ${@}
|
||||
return
|
||||
else
|
||||
j $(pwd)/ ${@}
|
||||
j $(pwd) ${@}
|
||||
fi
|
||||
}
|
||||
|
||||
function jo {
|
||||
if [ -z $(autojump $@) ]; then
|
||||
echo "autojump: directory '${@}' not found"
|
||||
echo "Try \`autojump --help\` for more information."
|
||||
false
|
||||
else
|
||||
|
||||
# open autojump results in file browser
|
||||
jo() {
|
||||
if [[ ${1} == -* ]] && [[ ${1} != "--" ]]; then
|
||||
autojump ${@}
|
||||
return
|
||||
fi
|
||||
|
||||
output="$(autojump ${@})"
|
||||
if [[ -d "${output}" ]]; then
|
||||
case ${OSTYPE} in
|
||||
linux-gnu)
|
||||
xdg-open "$(autojump $@)"
|
||||
linux*)
|
||||
xdg-open "${output}"
|
||||
;;
|
||||
darwin*)
|
||||
open "$(autojump $@)"
|
||||
open "${output}"
|
||||
;;
|
||||
cygwin)
|
||||
cygstart "" $(cygpath -w -a $(pwd))
|
||||
cygstart "" $(cygpath -w -a ${output})
|
||||
;;
|
||||
*)
|
||||
echo "Unknown operating system." 1>&2
|
||||
echo "Unknown operating system: ${OSTYPE}." 1>&2
|
||||
;;
|
||||
esac
|
||||
else
|
||||
echo "autojump: directory '${@}' not found"
|
||||
echo "\n${output}\n"
|
||||
echo "Try \`autojump --help\` for more information."
|
||||
false
|
||||
fi
|
||||
}
|
||||
|
||||
function jco {
|
||||
if [[ ${@} == -* ]]; then
|
||||
j ${@}
|
||||
|
||||
# open autojump results (child directory) in file browser
|
||||
jco() {
|
||||
if [[ ${1} == -* ]] && [[ ${1} != "--" ]]; then
|
||||
autojump ${@}
|
||||
return
|
||||
else
|
||||
jo $(pwd) ${@}
|
||||
fi
|
||||
|
2
bin/autojump.bat
Normal file
2
bin/autojump.bat
Normal file
@ -0,0 +1,2 @@
|
||||
@echo off
|
||||
python "%~dp0\autojump" %*
|
112
bin/autojump.fish
Normal file
112
bin/autojump.fish
Normal file
@ -0,0 +1,112 @@
|
||||
set -gx AUTOJUMP_SOURCED 1
|
||||
|
||||
# set user installation path
|
||||
if test -d ~/.autojump
|
||||
set -x PATH ~/.autojump/bin $PATH
|
||||
end
|
||||
|
||||
# Set ostype, if not set
|
||||
if not set -q OSTYPE
|
||||
set -gx OSTYPE (bash -c 'echo ${OSTYPE}')
|
||||
end
|
||||
|
||||
|
||||
# enable tab completion
|
||||
complete -x -c j -a '(autojump --complete (commandline -t))'
|
||||
|
||||
|
||||
# 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
|
||||
|
||||
if test ! -d (dirname $AUTOJUMP_ERROR_PATH)
|
||||
mkdir -p (dirname $AUTOJUMP_ERROR_PATH)
|
||||
end
|
||||
|
||||
|
||||
# change pwd hook
|
||||
function __aj_add --on-variable PWD
|
||||
status --is-command-substitution; and return
|
||||
autojump --add (pwd) >/dev/null 2>>$AUTOJUMP_ERROR_PATH &
|
||||
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
|
||||
switch "$argv"
|
||||
case '-*' '--*'
|
||||
autojump $argv
|
||||
case '*'
|
||||
set -l output (autojump $argv)
|
||||
# Check for . and attempt a regular cd
|
||||
if [ $output = "." ]
|
||||
cd $argv
|
||||
else
|
||||
if test -d "$output"
|
||||
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
|
||||
|
||||
|
||||
# jump to child directory (subdirectory of current path)
|
||||
function jc
|
||||
switch "$argv"
|
||||
case '-*'
|
||||
j $argv
|
||||
case '*'
|
||||
j (pwd) $argv
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# open autojump results in file browser
|
||||
function jo
|
||||
set -l output (autojump $argv)
|
||||
if test -d "$output"
|
||||
switch $OSTYPE
|
||||
case 'linux*'
|
||||
xdg-open (autojump $argv)
|
||||
case 'darwin*'
|
||||
open (autojump $argv)
|
||||
case cygwin
|
||||
cygstart "" (cygpath -w -a (pwd))
|
||||
case '*'
|
||||
__aj_err "Unknown operating system: \"$OSTYPE\""
|
||||
end
|
||||
else
|
||||
__aj_err "autojump: directory '"$argv"' not found"
|
||||
__aj_err "\n$output\n"
|
||||
__aj_err "Try `autojump --help` for more information."
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# open autojump results (child directory) in file browser
|
||||
function jco
|
||||
switch "$argv"
|
||||
case '-*'
|
||||
j $argv
|
||||
case '*'
|
||||
jo (pwd) $argv
|
||||
end
|
||||
end
|
21
bin/autojump.lua
Normal file
21
bin/autojump.lua
Normal file
@ -0,0 +1,21 @@
|
||||
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,21 +1,26 @@
|
||||
# source autojump on BASH or ZSH depending on the shell
|
||||
|
||||
shell=`echo ${SHELL} | awk -F/ '{ print $NF }'`
|
||||
# the login $SHELL isn't always the one used
|
||||
# NOTE: problems might occur if /bin/sh is symlinked to /bin/bash
|
||||
if [ -n "${BASH}" ]; then
|
||||
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
|
||||
if [ "${shell}" = "sh" ]; then
|
||||
return 0
|
||||
return 0
|
||||
|
||||
# check local install
|
||||
elif [ -s ~/.autojump/etc/profile.d/autojump.${shell} ]; then
|
||||
source ~/.autojump/etc/profile.d/autojump.${shell}
|
||||
elif [ -s ~/.autojump/share/autojump/autojump.${shell} ]; then
|
||||
source ~/.autojump/share/autojump/autojump.${shell}
|
||||
|
||||
# check global install
|
||||
elif [ -s /etc/profile.d/autojump.${shell} ]; then
|
||||
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}
|
||||
|
||||
elif [ -s /usr/local/share/autojump/autojump.${shell} ]; then
|
||||
source /usr/local/share/autojump/autojump.${shell}
|
||||
fi
|
||||
|
12
bin/autojump.tcsh
Normal file
12
bin/autojump.tcsh
Normal file
@ -0,0 +1,12 @@
|
||||
# set user installation paths
|
||||
if (-d ~/.autojump/bin) then
|
||||
set path = (~/.autojump/bin path)
|
||||
endif
|
||||
|
||||
# prepend autojump to cwdcmd (run after every change of working directory)
|
||||
if (`alias cwdcmd` !~ *autojump*) then
|
||||
alias cwdcmd 'autojump --add $cwd >/dev/null;' `alias cwdcmd`
|
||||
endif
|
||||
|
||||
#default autojump command
|
||||
alias j 'cd `autojump -- \!:1`'
|
129
bin/autojump.zsh
129
bin/autojump.zsh
@ -1,89 +1,124 @@
|
||||
# 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"
|
||||
export AUTOJUMP_SOURCED=1
|
||||
|
||||
# set user installation paths
|
||||
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
|
||||
export AUTOJUMP_DATA_DIR=${HOME}/.local/share/autojump
|
||||
export AUTOJUMP_ERROR_PATH=~/.local/share/autojump/errors.log
|
||||
fi
|
||||
|
||||
if [[ ! -e ${AUTOJUMP_DATA_DIR} ]]; then
|
||||
mkdir -p "${AUTOJUMP_DATA_DIR}"
|
||||
if [[ ! -d ${AUTOJUMP_ERROR_PATH:h} ]]; then
|
||||
mkdir -p ${AUTOJUMP_ERROR_PATH:h}
|
||||
fi
|
||||
|
||||
# set paths if necessary for local installations
|
||||
if [[ -d ${HOME}/.autojump ]]; then
|
||||
path=(${HOME}/.autojump/bin ${path})
|
||||
fpath=(${HOME}/.autojump/functions/ ${fpath})
|
||||
fi
|
||||
|
||||
# set fpath if necessary for homebrew installation
|
||||
command -v brew &>/dev/null \
|
||||
&& [[ -d "`brew --prefix`/share/zsh/site-functions" ]] \
|
||||
&& fpath=(`brew --prefix`/share/zsh/site-functions ${fpath})
|
||||
|
||||
function autojump_chpwd() {
|
||||
if [[ "${AUTOJUMP_KEEP_SYMLINKS}" == "1" ]]; then
|
||||
_PWD_ARGS=""
|
||||
# change pwd hook
|
||||
autojump_chpwd() {
|
||||
if [[ -f "${AUTOJUMP_ERROR_PATH}" ]]; then
|
||||
autojump --add "$(pwd)" >/dev/null 2>>${AUTOJUMP_ERROR_PATH} &!
|
||||
else
|
||||
_PWD_ARGS="-P"
|
||||
autojump --add "$(pwd)" >/dev/null &!
|
||||
fi
|
||||
{ (autojump -a "$(pwd ${_PWD_ARGS})"&)>/dev/null 2>>|${AUTOJUMP_DATA_DIR}/autojump_errors ; } 2>/dev/null
|
||||
}
|
||||
|
||||
typeset -ga chpwd_functions
|
||||
typeset -gaU chpwd_functions
|
||||
chpwd_functions+=autojump_chpwd
|
||||
|
||||
function j {
|
||||
# Cannot use =~ due to MacPorts zsh v4.2, see issue #125.
|
||||
if [[ ${@} == -* ]]; then
|
||||
|
||||
# default autojump command
|
||||
j() {
|
||||
if [[ ${1} == -* ]] && [[ ${1} != "--" ]]; then
|
||||
autojump ${@}
|
||||
return
|
||||
fi
|
||||
|
||||
local new_path="$(autojump ${@})"
|
||||
if [ -d "${new_path}" ]; then
|
||||
echo -e "\\033[31m${new_path}\\033[0m"
|
||||
cd "${new_path}"
|
||||
setopt localoptions noautonamedirs
|
||||
local output="$(autojump ${@})"
|
||||
if [[ -d "${output}" ]]; then
|
||||
if [ -t 1 ]; then # if stdout is a terminal, use colors
|
||||
echo -e "\\033[31m${output}\\033[0m"
|
||||
else
|
||||
echo -e "${output}"
|
||||
fi
|
||||
cd "${output}"
|
||||
else
|
||||
echo "autojump: directory '${@}' not found"
|
||||
echo "\n${output}\n"
|
||||
echo "Try \`autojump --help\` for more information."
|
||||
false
|
||||
fi
|
||||
}
|
||||
|
||||
function jc {
|
||||
if [[ ${@} == -* ]]; then
|
||||
j ${@}
|
||||
|
||||
# jump to child directory (subdirectory of current path)
|
||||
jc() {
|
||||
if [[ ${1} == -* ]] && [[ ${1} != "--" ]]; then
|
||||
autojump ${@}
|
||||
return
|
||||
else
|
||||
j $(pwd)/ ${@}
|
||||
j $(pwd) ${@}
|
||||
fi
|
||||
}
|
||||
|
||||
function jo {
|
||||
if [ -z $(autojump $@) ]; then
|
||||
echo "autojump: directory '${@}' not found"
|
||||
echo "Try \`autojump --help\` for more information."
|
||||
false
|
||||
else
|
||||
|
||||
# open autojump results in file browser
|
||||
jo() {
|
||||
if [[ ${1} == -* ]] && [[ ${1} != "--" ]]; then
|
||||
autojump ${@}
|
||||
return
|
||||
fi
|
||||
|
||||
setopt localoptions noautonamedirs
|
||||
local output="$(autojump ${@})"
|
||||
if [[ -d "${output}" ]]; then
|
||||
case ${OSTYPE} in
|
||||
linux-gnu)
|
||||
xdg-open "$(autojump $@)"
|
||||
linux*)
|
||||
xdg-open "${output}"
|
||||
;;
|
||||
darwin*)
|
||||
open "$(autojump $@)"
|
||||
open "${output}"
|
||||
;;
|
||||
cygwin)
|
||||
cygstart "" $(cygpath -w -a $(pwd))
|
||||
cygstart "" $(cygpath -w -a ${output})
|
||||
;;
|
||||
*)
|
||||
echo "Unknown operating system." 1>&2
|
||||
echo "Unknown operating system: ${OSTYPE}" 1>&2
|
||||
;;
|
||||
esac
|
||||
else
|
||||
echo "autojump: directory '${@}' not found"
|
||||
echo "\n${output}\n"
|
||||
echo "Try \`autojump --help\` for more information."
|
||||
false
|
||||
fi
|
||||
}
|
||||
|
||||
function jco {
|
||||
if [[ ${@} == -* ]]; then
|
||||
j ${@}
|
||||
|
||||
# open autojump results (child directory) in file browser
|
||||
jco() {
|
||||
if [[ ${1} == -* ]] && [[ ${1} != "--" ]]; then
|
||||
autojump ${@}
|
||||
return
|
||||
else
|
||||
jo $(pwd) ${@}
|
||||
fi
|
||||
|
@ -1,5 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Author: Steven J. Bethard <steven.bethard@gmail.com>.
|
||||
|
||||
# flake8: noqa
|
||||
"""Command-line parsing library
|
||||
|
||||
This module is an optparse-inspired command-line parsing library that:
|
||||
@ -61,7 +62,7 @@ considered public as object names -- the API of the formatter objects is
|
||||
still considered an implementation detail.)
|
||||
"""
|
||||
|
||||
__version__ = '1.2'
|
||||
__version__ = '1.2.1'
|
||||
__all__ = [
|
||||
'ArgumentParser',
|
||||
'ArgumentError',
|
||||
@ -106,8 +107,7 @@ try:
|
||||
except NameError:
|
||||
# for python < 2.4 compatibility:
|
||||
def sorted(iterable, reverse=False):
|
||||
result = list(iterable)
|
||||
result.sort()
|
||||
result = sorted(iterable)
|
||||
if reverse:
|
||||
result.reverse()
|
||||
return result
|
||||
@ -130,7 +130,9 @@ _UNRECOGNIZED_ARGS_ATTR = '_unrecognized_args'
|
||||
# Utility functions and classes
|
||||
# =============================
|
||||
|
||||
|
||||
class _AttributeHolder(object):
|
||||
|
||||
"""Abstract base class that provides __repr__.
|
||||
|
||||
The __repr__ method returns a string in the format::
|
||||
@ -166,17 +168,20 @@ def _ensure_value(namespace, name, value):
|
||||
# ===============
|
||||
|
||||
class HelpFormatter(object):
|
||||
|
||||
"""Formatter for generating usage messages and argument help strings.
|
||||
|
||||
Only the name of this class is considered a public API. All the methods
|
||||
provided by the class are considered an implementation detail.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
prog,
|
||||
indent_increment=2,
|
||||
max_help_position=24,
|
||||
width=None):
|
||||
def __init__(
|
||||
self,
|
||||
prog,
|
||||
indent_increment=2,
|
||||
max_help_position=24,
|
||||
width=None,
|
||||
):
|
||||
|
||||
# default setting for width
|
||||
if width is None:
|
||||
@ -283,8 +288,10 @@ class HelpFormatter(object):
|
||||
# update the maximum item length
|
||||
invocation_length = max([len(s) for s in invocations])
|
||||
action_length = invocation_length + self._current_indent
|
||||
self._action_max_length = max(self._action_max_length,
|
||||
action_length)
|
||||
self._action_max_length = max(
|
||||
self._action_max_length,
|
||||
action_length,
|
||||
)
|
||||
|
||||
# add the item to the list
|
||||
self._add_item(self._format_action, [action])
|
||||
@ -304,9 +311,11 @@ class HelpFormatter(object):
|
||||
return help
|
||||
|
||||
def _join_parts(self, part_strings):
|
||||
return ''.join([part
|
||||
for part in part_strings
|
||||
if part and part is not SUPPRESS])
|
||||
return ''.join([
|
||||
part
|
||||
for part in part_strings
|
||||
if part and part is not SUPPRESS
|
||||
])
|
||||
|
||||
def _format_usage(self, usage, actions, groups, prefix):
|
||||
if prefix is None:
|
||||
@ -505,8 +514,10 @@ class HelpFormatter(object):
|
||||
|
||||
def _format_action(self, action):
|
||||
# determine the required width and the entry label
|
||||
help_position = min(self._action_max_length + 2,
|
||||
self._max_help_position)
|
||||
help_position = min(
|
||||
self._action_max_length + 2,
|
||||
self._max_help_position,
|
||||
)
|
||||
help_width = self._width - help_position
|
||||
action_width = help_position - self._current_indent - 2
|
||||
action_header = self._format_action_invocation(action)
|
||||
@ -638,14 +649,17 @@ class HelpFormatter(object):
|
||||
|
||||
def _fill_text(self, text, width, indent):
|
||||
text = self._whitespace_matcher.sub(' ', text).strip()
|
||||
return _textwrap.fill(text, width, initial_indent=indent,
|
||||
subsequent_indent=indent)
|
||||
return _textwrap.fill(
|
||||
text, width, initial_indent=indent,
|
||||
subsequent_indent=indent,
|
||||
)
|
||||
|
||||
def _get_help_string(self, action):
|
||||
return action.help
|
||||
|
||||
|
||||
class RawDescriptionHelpFormatter(HelpFormatter):
|
||||
|
||||
"""Help message formatter which retains any formatting in descriptions.
|
||||
|
||||
Only the name of this class is considered a public API. All the methods
|
||||
@ -657,6 +671,7 @@ class RawDescriptionHelpFormatter(HelpFormatter):
|
||||
|
||||
|
||||
class RawTextHelpFormatter(RawDescriptionHelpFormatter):
|
||||
|
||||
"""Help message formatter which retains formatting of all help text.
|
||||
|
||||
Only the name of this class is considered a public API. All the methods
|
||||
@ -668,6 +683,7 @@ class RawTextHelpFormatter(RawDescriptionHelpFormatter):
|
||||
|
||||
|
||||
class ArgumentDefaultsHelpFormatter(HelpFormatter):
|
||||
|
||||
"""Help message formatter which adds default values to argument help.
|
||||
|
||||
Only the name of this class is considered a public API. All the methods
|
||||
@ -692,7 +708,7 @@ def _get_action_name(argument):
|
||||
if argument is None:
|
||||
return None
|
||||
elif argument.option_strings:
|
||||
return '/'.join(argument.option_strings)
|
||||
return '/'.join(argument.option_strings)
|
||||
elif argument.metavar not in (None, SUPPRESS):
|
||||
return argument.metavar
|
||||
elif argument.dest not in (None, SUPPRESS):
|
||||
@ -702,6 +718,7 @@ def _get_action_name(argument):
|
||||
|
||||
|
||||
class ArgumentError(Exception):
|
||||
|
||||
"""An error from creating or using an argument (optional or positional).
|
||||
|
||||
The string value of this exception is the message, augmented with
|
||||
@ -717,11 +734,14 @@ class ArgumentError(Exception):
|
||||
format = '%(message)s'
|
||||
else:
|
||||
format = 'argument %(argument_name)s: %(message)s'
|
||||
return format % dict(message=self.message,
|
||||
argument_name=self.argument_name)
|
||||
return format % dict(
|
||||
message=self.message,
|
||||
argument_name=self.argument_name,
|
||||
)
|
||||
|
||||
|
||||
class ArgumentTypeError(Exception):
|
||||
|
||||
"""An error from trying to convert a command line string to a type."""
|
||||
pass
|
||||
|
||||
@ -731,6 +751,7 @@ class ArgumentTypeError(Exception):
|
||||
# ==============
|
||||
|
||||
class Action(_AttributeHolder):
|
||||
|
||||
"""Information about how to convert command line strings to Python objects.
|
||||
|
||||
Action objects are used by an ArgumentParser to represent the information
|
||||
@ -781,17 +802,19 @@ class Action(_AttributeHolder):
|
||||
help string. If None, the 'dest' value will be used as the name.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
option_strings,
|
||||
dest,
|
||||
nargs=None,
|
||||
const=None,
|
||||
default=None,
|
||||
type=None,
|
||||
choices=None,
|
||||
required=False,
|
||||
help=None,
|
||||
metavar=None):
|
||||
def __init__(
|
||||
self,
|
||||
option_strings,
|
||||
dest,
|
||||
nargs=None,
|
||||
const=None,
|
||||
default=None,
|
||||
type=None,
|
||||
choices=None,
|
||||
required=False,
|
||||
help=None,
|
||||
metavar=None,
|
||||
):
|
||||
self.option_strings = option_strings
|
||||
self.dest = dest
|
||||
self.nargs = nargs
|
||||
@ -823,21 +846,25 @@ class Action(_AttributeHolder):
|
||||
|
||||
class _StoreAction(Action):
|
||||
|
||||
def __init__(self,
|
||||
option_strings,
|
||||
dest,
|
||||
nargs=None,
|
||||
const=None,
|
||||
default=None,
|
||||
type=None,
|
||||
choices=None,
|
||||
required=False,
|
||||
help=None,
|
||||
metavar=None):
|
||||
def __init__(
|
||||
self,
|
||||
option_strings,
|
||||
dest,
|
||||
nargs=None,
|
||||
const=None,
|
||||
default=None,
|
||||
type=None,
|
||||
choices=None,
|
||||
required=False,
|
||||
help=None,
|
||||
metavar=None,
|
||||
):
|
||||
if nargs == 0:
|
||||
raise ValueError('nargs for store actions must be > 0; if you '
|
||||
'have nothing to store, actions such as store '
|
||||
'true or store const may be more appropriate')
|
||||
raise ValueError(
|
||||
'nargs for store actions must be > 0; if you '
|
||||
'have nothing to store, actions such as store '
|
||||
'true or store const may be more appropriate',
|
||||
)
|
||||
if const is not None and nargs != OPTIONAL:
|
||||
raise ValueError('nargs must be %r to supply const' % OPTIONAL)
|
||||
super(_StoreAction, self).__init__(
|
||||
@ -850,7 +877,8 @@ class _StoreAction(Action):
|
||||
choices=choices,
|
||||
required=required,
|
||||
help=help,
|
||||
metavar=metavar)
|
||||
metavar=metavar,
|
||||
)
|
||||
|
||||
def __call__(self, parser, namespace, values, option_string=None):
|
||||
setattr(namespace, self.dest, values)
|
||||
@ -858,14 +886,16 @@ class _StoreAction(Action):
|
||||
|
||||
class _StoreConstAction(Action):
|
||||
|
||||
def __init__(self,
|
||||
option_strings,
|
||||
dest,
|
||||
const,
|
||||
default=None,
|
||||
required=False,
|
||||
help=None,
|
||||
metavar=None):
|
||||
def __init__(
|
||||
self,
|
||||
option_strings,
|
||||
dest,
|
||||
const,
|
||||
default=None,
|
||||
required=False,
|
||||
help=None,
|
||||
metavar=None,
|
||||
):
|
||||
super(_StoreConstAction, self).__init__(
|
||||
option_strings=option_strings,
|
||||
dest=dest,
|
||||
@ -873,7 +903,8 @@ class _StoreConstAction(Action):
|
||||
const=const,
|
||||
default=default,
|
||||
required=required,
|
||||
help=help)
|
||||
help=help,
|
||||
)
|
||||
|
||||
def __call__(self, parser, namespace, values, option_string=None):
|
||||
setattr(namespace, self.dest, self.const)
|
||||
@ -881,55 +912,65 @@ class _StoreConstAction(Action):
|
||||
|
||||
class _StoreTrueAction(_StoreConstAction):
|
||||
|
||||
def __init__(self,
|
||||
option_strings,
|
||||
dest,
|
||||
default=False,
|
||||
required=False,
|
||||
help=None):
|
||||
def __init__(
|
||||
self,
|
||||
option_strings,
|
||||
dest,
|
||||
default=False,
|
||||
required=False,
|
||||
help=None,
|
||||
):
|
||||
super(_StoreTrueAction, self).__init__(
|
||||
option_strings=option_strings,
|
||||
dest=dest,
|
||||
const=True,
|
||||
default=default,
|
||||
required=required,
|
||||
help=help)
|
||||
help=help,
|
||||
)
|
||||
|
||||
|
||||
class _StoreFalseAction(_StoreConstAction):
|
||||
|
||||
def __init__(self,
|
||||
option_strings,
|
||||
dest,
|
||||
default=True,
|
||||
required=False,
|
||||
help=None):
|
||||
def __init__(
|
||||
self,
|
||||
option_strings,
|
||||
dest,
|
||||
default=True,
|
||||
required=False,
|
||||
help=None,
|
||||
):
|
||||
super(_StoreFalseAction, self).__init__(
|
||||
option_strings=option_strings,
|
||||
dest=dest,
|
||||
const=False,
|
||||
default=default,
|
||||
required=required,
|
||||
help=help)
|
||||
help=help,
|
||||
)
|
||||
|
||||
|
||||
class _AppendAction(Action):
|
||||
|
||||
def __init__(self,
|
||||
option_strings,
|
||||
dest,
|
||||
nargs=None,
|
||||
const=None,
|
||||
default=None,
|
||||
type=None,
|
||||
choices=None,
|
||||
required=False,
|
||||
help=None,
|
||||
metavar=None):
|
||||
def __init__(
|
||||
self,
|
||||
option_strings,
|
||||
dest,
|
||||
nargs=None,
|
||||
const=None,
|
||||
default=None,
|
||||
type=None,
|
||||
choices=None,
|
||||
required=False,
|
||||
help=None,
|
||||
metavar=None,
|
||||
):
|
||||
if nargs == 0:
|
||||
raise ValueError('nargs for append actions must be > 0; if arg '
|
||||
'strings are not supplying the value to append, '
|
||||
'the append const action may be more appropriate')
|
||||
raise ValueError(
|
||||
'nargs for append actions must be > 0; if arg '
|
||||
'strings are not supplying the value to append, '
|
||||
'the append const action may be more appropriate',
|
||||
)
|
||||
if const is not None and nargs != OPTIONAL:
|
||||
raise ValueError('nargs must be %r to supply const' % OPTIONAL)
|
||||
super(_AppendAction, self).__init__(
|
||||
@ -942,7 +983,8 @@ class _AppendAction(Action):
|
||||
choices=choices,
|
||||
required=required,
|
||||
help=help,
|
||||
metavar=metavar)
|
||||
metavar=metavar,
|
||||
)
|
||||
|
||||
def __call__(self, parser, namespace, values, option_string=None):
|
||||
items = _copy.copy(_ensure_value(namespace, self.dest, []))
|
||||
@ -952,14 +994,16 @@ class _AppendAction(Action):
|
||||
|
||||
class _AppendConstAction(Action):
|
||||
|
||||
def __init__(self,
|
||||
option_strings,
|
||||
dest,
|
||||
const,
|
||||
default=None,
|
||||
required=False,
|
||||
help=None,
|
||||
metavar=None):
|
||||
def __init__(
|
||||
self,
|
||||
option_strings,
|
||||
dest,
|
||||
const,
|
||||
default=None,
|
||||
required=False,
|
||||
help=None,
|
||||
metavar=None,
|
||||
):
|
||||
super(_AppendConstAction, self).__init__(
|
||||
option_strings=option_strings,
|
||||
dest=dest,
|
||||
@ -968,7 +1012,8 @@ class _AppendConstAction(Action):
|
||||
default=default,
|
||||
required=required,
|
||||
help=help,
|
||||
metavar=metavar)
|
||||
metavar=metavar,
|
||||
)
|
||||
|
||||
def __call__(self, parser, namespace, values, option_string=None):
|
||||
items = _copy.copy(_ensure_value(namespace, self.dest, []))
|
||||
@ -978,19 +1023,22 @@ class _AppendConstAction(Action):
|
||||
|
||||
class _CountAction(Action):
|
||||
|
||||
def __init__(self,
|
||||
option_strings,
|
||||
dest,
|
||||
default=None,
|
||||
required=False,
|
||||
help=None):
|
||||
def __init__(
|
||||
self,
|
||||
option_strings,
|
||||
dest,
|
||||
default=None,
|
||||
required=False,
|
||||
help=None,
|
||||
):
|
||||
super(_CountAction, self).__init__(
|
||||
option_strings=option_strings,
|
||||
dest=dest,
|
||||
nargs=0,
|
||||
default=default,
|
||||
required=required,
|
||||
help=help)
|
||||
help=help,
|
||||
)
|
||||
|
||||
def __call__(self, parser, namespace, values, option_string=None):
|
||||
new_count = _ensure_value(namespace, self.dest, 0) + 1
|
||||
@ -999,17 +1047,20 @@ class _CountAction(Action):
|
||||
|
||||
class _HelpAction(Action):
|
||||
|
||||
def __init__(self,
|
||||
option_strings,
|
||||
dest=SUPPRESS,
|
||||
default=SUPPRESS,
|
||||
help=None):
|
||||
def __init__(
|
||||
self,
|
||||
option_strings,
|
||||
dest=SUPPRESS,
|
||||
default=SUPPRESS,
|
||||
help=None,
|
||||
):
|
||||
super(_HelpAction, self).__init__(
|
||||
option_strings=option_strings,
|
||||
dest=dest,
|
||||
default=default,
|
||||
nargs=0,
|
||||
help=help)
|
||||
help=help,
|
||||
)
|
||||
|
||||
def __call__(self, parser, namespace, values, option_string=None):
|
||||
parser.print_help()
|
||||
@ -1018,18 +1069,21 @@ class _HelpAction(Action):
|
||||
|
||||
class _VersionAction(Action):
|
||||
|
||||
def __init__(self,
|
||||
option_strings,
|
||||
version=None,
|
||||
dest=SUPPRESS,
|
||||
default=SUPPRESS,
|
||||
help="show program's version number and exit"):
|
||||
def __init__(
|
||||
self,
|
||||
option_strings,
|
||||
version=None,
|
||||
dest=SUPPRESS,
|
||||
default=SUPPRESS,
|
||||
help="show program's version number and exit",
|
||||
):
|
||||
super(_VersionAction, self).__init__(
|
||||
option_strings=option_strings,
|
||||
dest=dest,
|
||||
default=default,
|
||||
nargs=0,
|
||||
help=help)
|
||||
help=help,
|
||||
)
|
||||
self.version = version
|
||||
|
||||
def __call__(self, parser, namespace, values, option_string=None):
|
||||
@ -1049,13 +1103,15 @@ class _SubParsersAction(Action):
|
||||
sup = super(_SubParsersAction._ChoicesPseudoAction, self)
|
||||
sup.__init__(option_strings=[], dest=name, help=help)
|
||||
|
||||
def __init__(self,
|
||||
option_strings,
|
||||
prog,
|
||||
parser_class,
|
||||
dest=SUPPRESS,
|
||||
help=None,
|
||||
metavar=None):
|
||||
def __init__(
|
||||
self,
|
||||
option_strings,
|
||||
prog,
|
||||
parser_class,
|
||||
dest=SUPPRESS,
|
||||
help=None,
|
||||
metavar=None,
|
||||
):
|
||||
|
||||
self._prog_prefix = prog
|
||||
self._parser_class = parser_class
|
||||
@ -1068,7 +1124,8 @@ class _SubParsersAction(Action):
|
||||
nargs=PARSER,
|
||||
choices=self._name_parser_map,
|
||||
help=help,
|
||||
metavar=metavar)
|
||||
metavar=metavar,
|
||||
)
|
||||
|
||||
def add_parser(self, name, **kwargs):
|
||||
# set prog from the existing prefix
|
||||
@ -1108,7 +1165,9 @@ class _SubParsersAction(Action):
|
||||
# parse all the remaining options into the namespace
|
||||
# store any unrecognized options on the object, so that the top
|
||||
# level parser can decide what to do with them
|
||||
namespace, arg_strings = parser.parse_known_args(arg_strings, namespace)
|
||||
namespace, arg_strings = parser.parse_known_args(
|
||||
arg_strings, namespace,
|
||||
)
|
||||
if arg_strings:
|
||||
vars(namespace).setdefault(_UNRECOGNIZED_ARGS_ATTR, [])
|
||||
getattr(namespace, _UNRECOGNIZED_ARGS_ATTR).extend(arg_strings)
|
||||
@ -1119,6 +1178,7 @@ class _SubParsersAction(Action):
|
||||
# ==============
|
||||
|
||||
class FileType(object):
|
||||
|
||||
"""Factory for creating file object types
|
||||
|
||||
Instances of FileType are typically passed as type= arguments to the
|
||||
@ -1161,7 +1221,9 @@ class FileType(object):
|
||||
# Optional and Positional Parsing
|
||||
# ===========================
|
||||
|
||||
|
||||
class Namespace(_AttributeHolder):
|
||||
|
||||
"""Simple object for storing attributes.
|
||||
|
||||
Implements equality by attribute names and values, and provides a simple
|
||||
@ -1186,11 +1248,13 @@ class Namespace(_AttributeHolder):
|
||||
|
||||
class _ActionsContainer(object):
|
||||
|
||||
def __init__(self,
|
||||
description,
|
||||
prefix_chars,
|
||||
argument_default,
|
||||
conflict_handler):
|
||||
def __init__(
|
||||
self,
|
||||
description,
|
||||
prefix_chars,
|
||||
argument_default,
|
||||
conflict_handler,
|
||||
):
|
||||
super(_ActionsContainer, self).__init__()
|
||||
|
||||
self.description = description
|
||||
@ -1263,7 +1327,6 @@ class _ActionsContainer(object):
|
||||
return action.default
|
||||
return self._defaults.get(dest, None)
|
||||
|
||||
|
||||
# =======================
|
||||
# Adding argument actions
|
||||
# =======================
|
||||
@ -1360,7 +1423,8 @@ class _ActionsContainer(object):
|
||||
title_group_map[group.title] = self.add_argument_group(
|
||||
title=group.title,
|
||||
description=group.description,
|
||||
conflict_handler=group.conflict_handler)
|
||||
conflict_handler=group.conflict_handler,
|
||||
)
|
||||
|
||||
# map the actions to their new group
|
||||
for action in group._group_actions:
|
||||
@ -1371,7 +1435,8 @@ class _ActionsContainer(object):
|
||||
# description= then this code will need to be expanded as above
|
||||
for group in container._mutually_exclusive_groups:
|
||||
mutex_group = self.add_mutually_exclusive_group(
|
||||
required=group.required)
|
||||
required=group.required,
|
||||
)
|
||||
|
||||
# map the actions to their new mutex group
|
||||
for action in group._group_actions:
|
||||
@ -1404,8 +1469,10 @@ class _ActionsContainer(object):
|
||||
for option_string in args:
|
||||
# error on strings that don't start with an appropriate prefix
|
||||
if not option_string[0] in self.prefix_chars:
|
||||
msg = _('invalid option string %r: '
|
||||
'must start with a character %r')
|
||||
msg = _(
|
||||
'invalid option string %r: '
|
||||
'must start with a character %r',
|
||||
)
|
||||
tup = option_string, self.prefix_chars
|
||||
raise ValueError(msg % tup)
|
||||
|
||||
@ -1461,9 +1528,11 @@ class _ActionsContainer(object):
|
||||
|
||||
def _handle_conflict_error(self, action, conflicting_actions):
|
||||
message = _('conflicting option string(s): %s')
|
||||
conflict_string = ', '.join([option_string
|
||||
for option_string, action
|
||||
in conflicting_actions])
|
||||
conflict_string = ', '.join([
|
||||
option_string
|
||||
for option_string, action
|
||||
in conflicting_actions
|
||||
])
|
||||
raise ArgumentError(action, message % conflict_string)
|
||||
|
||||
def _handle_conflict_resolve(self, action, conflicting_actions):
|
||||
@ -1535,6 +1604,7 @@ class _MutuallyExclusiveGroup(_ArgumentGroup):
|
||||
|
||||
|
||||
class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
||||
|
||||
"""Object for parsing command line strings into Python objects.
|
||||
|
||||
Keyword Arguments:
|
||||
@ -1552,19 +1622,21 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
||||
- add_help -- Add a -h/-help option
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
prog=None,
|
||||
usage=None,
|
||||
description=None,
|
||||
epilog=None,
|
||||
version=None,
|
||||
parents=[],
|
||||
formatter_class=HelpFormatter,
|
||||
prefix_chars='-',
|
||||
fromfile_prefix_chars=None,
|
||||
argument_default=None,
|
||||
conflict_handler='error',
|
||||
add_help=True):
|
||||
def __init__(
|
||||
self,
|
||||
prog=None,
|
||||
usage=None,
|
||||
description=None,
|
||||
epilog=None,
|
||||
version=None,
|
||||
parents=[],
|
||||
formatter_class=HelpFormatter,
|
||||
prefix_chars='-',
|
||||
fromfile_prefix_chars=None,
|
||||
argument_default=None,
|
||||
conflict_handler='error',
|
||||
add_help=True,
|
||||
):
|
||||
|
||||
if version is not None:
|
||||
import warnings
|
||||
@ -1572,13 +1644,16 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
||||
"""The "version" argument to ArgumentParser is deprecated. """
|
||||
"""Please use """
|
||||
""""add_argument(..., action='version', version="N", ...)" """
|
||||
"""instead""", DeprecationWarning)
|
||||
"""instead""", DeprecationWarning,
|
||||
)
|
||||
|
||||
superinit = super(ArgumentParser, self).__init__
|
||||
superinit(description=description,
|
||||
prefix_chars=prefix_chars,
|
||||
argument_default=argument_default,
|
||||
conflict_handler=conflict_handler)
|
||||
superinit(
|
||||
description=description,
|
||||
prefix_chars=prefix_chars,
|
||||
argument_default=argument_default,
|
||||
conflict_handler=conflict_handler,
|
||||
)
|
||||
|
||||
# default setting for prog
|
||||
if prog is None:
|
||||
@ -1610,15 +1685,17 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
||||
default_prefix = prefix_chars[0]
|
||||
if self.add_help:
|
||||
self.add_argument(
|
||||
default_prefix+'h', default_prefix*2+'help',
|
||||
default_prefix + 'h', default_prefix * 2 + 'help',
|
||||
action='help', default=SUPPRESS,
|
||||
help=_('show this help message and exit'))
|
||||
help=_('show this help message and exit'),
|
||||
)
|
||||
if self.version:
|
||||
self.add_argument(
|
||||
default_prefix+'v', default_prefix*2+'version',
|
||||
default_prefix + 'v', default_prefix * 2 + 'version',
|
||||
action='version', default=SUPPRESS,
|
||||
version=self.version,
|
||||
help=_("show program's version number and exit"))
|
||||
help=_("show program's version number and exit"),
|
||||
)
|
||||
|
||||
# add parent arguments and defaults
|
||||
for parent in parents:
|
||||
@ -1687,14 +1764,18 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
||||
return action
|
||||
|
||||
def _get_optional_actions(self):
|
||||
return [action
|
||||
for action in self._actions
|
||||
if action.option_strings]
|
||||
return [
|
||||
action
|
||||
for action in self._actions
|
||||
if action.option_strings
|
||||
]
|
||||
|
||||
def _get_positional_actions(self):
|
||||
return [action
|
||||
for action in self._actions
|
||||
if not action.option_strings]
|
||||
return [
|
||||
action
|
||||
for action in self._actions
|
||||
if not action.option_strings
|
||||
]
|
||||
|
||||
# =====================================
|
||||
# Command line argument parsing methods
|
||||
@ -1918,7 +1999,8 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
||||
next_option_string_index = min([
|
||||
index
|
||||
for index in option_string_indices
|
||||
if index >= start_index])
|
||||
if index >= start_index
|
||||
])
|
||||
if start_index != next_option_string_index:
|
||||
positionals_end_index = consume_positionals(start_index)
|
||||
|
||||
@ -1967,9 +2049,11 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
||||
|
||||
# if no actions were used, report the error
|
||||
else:
|
||||
names = [_get_action_name(action)
|
||||
for action in group._group_actions
|
||||
if action.help is not SUPPRESS]
|
||||
names = [
|
||||
_get_action_name(action)
|
||||
for action in group._group_actions
|
||||
if action.help is not SUPPRESS
|
||||
]
|
||||
msg = _('one of the arguments %s is required')
|
||||
self.error(msg % ' '.join(names))
|
||||
|
||||
@ -2033,8 +2117,10 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
||||
result = []
|
||||
for i in range(len(actions), 0, -1):
|
||||
actions_slice = actions[:i]
|
||||
pattern = ''.join([self._get_nargs_pattern(action)
|
||||
for action in actions_slice])
|
||||
pattern = ''.join([
|
||||
self._get_nargs_pattern(action)
|
||||
for action in actions_slice
|
||||
])
|
||||
match = _re.match(pattern, arg_strings_pattern)
|
||||
if match is not None:
|
||||
result.extend([len(string) for string in match.groups()])
|
||||
@ -2074,8 +2160,9 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
||||
|
||||
# if multiple actions match, the option string was ambiguous
|
||||
if len(option_tuples) > 1:
|
||||
options = ', '.join([option_string
|
||||
for action, option_string, explicit_arg in option_tuples])
|
||||
options = ', '.join(
|
||||
[option_string for action, option_string, explicit_arg in option_tuples],
|
||||
)
|
||||
tup = arg_string, options
|
||||
self.error(_('ambiguous option: %s could match %s') % tup)
|
||||
|
||||
@ -2205,8 +2292,10 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
||||
|
||||
# when nargs='*' on a positional, if there were no command-line
|
||||
# args, use the default if it is anything other than None
|
||||
elif (not arg_strings and action.nargs == ZERO_OR_MORE and
|
||||
not action.option_strings):
|
||||
elif (
|
||||
not arg_strings and action.nargs == ZERO_OR_MORE and
|
||||
not action.option_strings
|
||||
):
|
||||
if action.default is not None:
|
||||
value = action.default
|
||||
else:
|
||||
@ -2274,16 +2363,20 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
||||
# =======================
|
||||
def format_usage(self):
|
||||
formatter = self._get_formatter()
|
||||
formatter.add_usage(self.usage, self._actions,
|
||||
self._mutually_exclusive_groups)
|
||||
formatter.add_usage(
|
||||
self.usage, self._actions,
|
||||
self._mutually_exclusive_groups,
|
||||
)
|
||||
return formatter.format_help()
|
||||
|
||||
def format_help(self):
|
||||
formatter = self._get_formatter()
|
||||
|
||||
# usage
|
||||
formatter.add_usage(self.usage, self._actions,
|
||||
self._mutually_exclusive_groups)
|
||||
formatter.add_usage(
|
||||
self.usage, self._actions,
|
||||
self._mutually_exclusive_groups,
|
||||
)
|
||||
|
||||
# description
|
||||
formatter.add_text(self.description)
|
||||
@ -2306,7 +2399,8 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
||||
warnings.warn(
|
||||
'The format_version method is deprecated -- the "version" '
|
||||
'argument to ArgumentParser is no longer supported.',
|
||||
DeprecationWarning)
|
||||
DeprecationWarning,
|
||||
)
|
||||
formatter = self._get_formatter()
|
||||
formatter.add_text(self.version)
|
||||
return formatter.format_help()
|
||||
@ -2332,7 +2426,8 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
||||
warnings.warn(
|
||||
'The print_version method is deprecated -- the "version" '
|
||||
'argument to ArgumentParser is no longer supported.',
|
||||
DeprecationWarning)
|
||||
DeprecationWarning,
|
||||
)
|
||||
self._print_message(self.format_version(), file)
|
||||
|
||||
def _print_message(self, message, file=None):
|
||||
|
148
bin/autojump_data.py
Normal file
148
bin/autojump_data.py
Normal file
@ -0,0 +1,148 @@
|
||||
#!/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'])
|
129
bin/autojump_match.py
Normal file
129
bin/autojump_match.py
Normal file
@ -0,0 +1,129 @@
|
||||
#!/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)
|
211
bin/autojump_utils.py
Normal file
211
bin/autojump_utils.py
Normal file
@ -0,0 +1,211 @@
|
||||
#!/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
Normal file
21
bin/j.bat
Normal file
@ -0,0 +1,21 @@
|
||||
@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" %*
|
||||
)
|
8
bin/jc.bat
Normal file
8
bin/jc.bat
Normal file
@ -0,0 +1,8 @@
|
||||
@echo off
|
||||
|
||||
echo %*|>nul findstr /rx \-.*
|
||||
if ERRORLEVEL 1 (
|
||||
"%~dp0\j.bat" "%cd%" %*
|
||||
) else (
|
||||
python "%~dp0\autojump" %*
|
||||
)
|
8
bin/jco.bat
Normal file
8
bin/jco.bat
Normal file
@ -0,0 +1,8 @@
|
||||
@echo off
|
||||
|
||||
echo %*|>nul findstr /rx \-.*
|
||||
if ERRORLEVEL 1 (
|
||||
"%~dp0\jc.bat" "%cd%" %*
|
||||
) else (
|
||||
python "%~dp0\autojump" %*
|
||||
)
|
15
bin/jo.bat
Normal file
15
bin/jo.bat
Normal file
@ -0,0 +1,15 @@
|
||||
@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" %*
|
||||
)
|
241
docs/autojump.1
241
docs/autojump.1
@ -1,59 +1,70 @@
|
||||
.TH autojump 1 "10 April 2012" "release\-v20"
|
||||
.\" Automatically generated by Pandoc 1.16.0.2
|
||||
.\"
|
||||
.TH "autojump" "1" "2018\-09\-09" "release\-v22.5.3" ""
|
||||
.hy
|
||||
.SS NAME
|
||||
.PP
|
||||
autojump \- a faster way to navigate your filesystem
|
||||
.SS SYNOPSIS
|
||||
.SS DESCRIPTION
|
||||
.PP
|
||||
Jump to a previously visited directory that contains \[aq]foo\[aq]:
|
||||
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.
|
||||
.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
|
||||
.nf
|
||||
\f[C]
|
||||
j\ foo
|
||||
\f[]
|
||||
.fi
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
Jump To A Child Directory:
|
||||
.RS 2
|
||||
.PP
|
||||
Jump to a previously visited subdirectory of the current directory:
|
||||
Sometimes it\[aq]s convenient to jump to a child directory
|
||||
(sub\-directory of current directory) rather than typing out the full
|
||||
name.
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
jc\ bar
|
||||
\f[]
|
||||
.fi
|
||||
.PP
|
||||
Show database entries and their respective key weights:
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
j\ \-\-stat
|
||||
\f[]
|
||||
.fi
|
||||
.SS DESCRIPTION
|
||||
.PP
|
||||
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
|
||||
.nf
|
||||
\f[C]
|
||||
\-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[]
|
||||
.fi
|
||||
.SS ADVANCED USAGE
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
Using Multiple Arguments
|
||||
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
|
||||
.IP \[bu] 2
|
||||
Using Multiple Arguments:
|
||||
.RS 2
|
||||
.PP
|
||||
Let\[aq]s assume the following database:
|
||||
@ -69,132 +80,24 @@ Let\[aq]s assume the following database:
|
||||
weighted entry.
|
||||
However you can pass multiple arguments to autojump to prefer a
|
||||
different entry.
|
||||
In the above example, \f[C]j\ w\ in\f[] would then jump you into
|
||||
In the above example, \f[C]j\ w\ in\f[] would then change directory to
|
||||
/home/user/work/inbox.
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
Jump To A Child Directory.
|
||||
.RS 2
|
||||
.PP
|
||||
Sometimes it\[aq]s convenient to jump to a child directory
|
||||
(sub\-directory of current directory) rather than typing out the full
|
||||
name.
|
||||
For more options refer to help:
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
jc\ images
|
||||
autojump\ \-\-help
|
||||
\f[]
|
||||
.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
|
||||
.IP \[bu] 2
|
||||
For bash users, autojump keeps track of directories as a pre\-command
|
||||
hook by modifying
|
||||
\f[I]P\f[]\f[I]R\f[]\f[I]O\f[]\f[I]M\f[]\f[I]P\f[]\f[I]T\f[]~\f[I]C\f[]~\f[I]O\f[]\f[I]M\f[]\f[I]M\f[]\f[I]A\f[]\f[I]N\f[]\f[I]D\f[]. \f[I]I\f[]\f[I]f\f[]\f[I]y\f[]\f[I]o\f[]\f[I]u\f[]\f[I]o\f[]\f[I]v\f[]\f[I]e\f[]\f[I]r\f[]\f[I]w\f[]\f[I]r\f[]\f[I]i\f[]\f[I]t\f[]\f[I]e\f[]PROMPT_COMMAND
|
||||
in ~/.bashrc you can cause problems.
|
||||
Don\[aq]t do this:
|
||||
autojump does not support directories that begin with \f[C]\-\f[].
|
||||
.IP \[bu] 2
|
||||
For bash users, autojump keeps track of directories by modifying
|
||||
\f[C]$PROMPT_COMMAND\f[].
|
||||
Do not overwrite \f[C]$PROMPT_COMMAND\f[]:
|
||||
.RS 2
|
||||
.IP
|
||||
.nf
|
||||
@ -203,7 +106,7 @@ export\ PROMPT_COMMAND="history\ \-a"
|
||||
\f[]
|
||||
.fi
|
||||
.PP
|
||||
Do this:
|
||||
Instead append to the end of the existing $PROMPT_COMMAND:
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
@ -211,33 +114,23 @@ export\ PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND\ ;}\ history\ \-a"
|
||||
\f[]
|
||||
.fi
|
||||
.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\f[]DATA_HOME/autojump/autojump.txt_.
|
||||
.SS REPORTING BUGS
|
||||
.PP
|
||||
For any usage related issues or feature requests please visit:
|
||||
.PP
|
||||
\f[I]https://github.com/joelthelion/autojump/issues\f[]
|
||||
.SS THANKS
|
||||
.PP
|
||||
Special thanks goes out to: Pierre Gueth, Simon Marache\-Francisco,
|
||||
Daniel Jackoway, and many others.
|
||||
For any questions or issues please visit:
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
https://github.com/wting/autojump/issues
|
||||
\f[]
|
||||
.fi
|
||||
.SS AUTHORS
|
||||
.PP
|
||||
autojump was originally written by Joël Schaerer, and currently
|
||||
maintained by William Ting.
|
||||
More contributors can be found in \f[C]AUTHORS\f[].
|
||||
.SS COPYRIGHT
|
||||
.PP
|
||||
Copyright © 2012 Free Software Foundation, Inc.
|
||||
Copyright © 2016 Free Software Foundation, Inc.
|
||||
License GPLv3+: GNU GPL version 3 or later
|
||||
<http://gnu.org/licenses/gpl.html>.
|
||||
This is free software: you are free to change and redistribute it.
|
||||
|
137
docs/body.md
137
docs/body.md
@ -1,139 +1,34 @@
|
||||
## OPTIONS
|
||||
KNOWN ISSUES
|
||||
------------
|
||||
|
||||
Options must be passed to 'autojump' and not the 'j' wrapper function.
|
||||
- autojump does not support directories that begin with `-`.
|
||||
|
||||
-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
|
||||
|
||||
- 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:
|
||||
- For bash users, autojump keeps track of directories by modifying
|
||||
`$PROMPT_COMMAND`. Do not overwrite `$PROMPT_COMMAND`:
|
||||
|
||||
export PROMPT_COMMAND="history -a"
|
||||
|
||||
Do this:
|
||||
Instead append to the end of the existing \$PROMPT\_COMMAND:
|
||||
|
||||
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`.
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
|
||||
## FILES
|
||||
For any questions or issues please visit:
|
||||
|
||||
If installed locally, autojump is self-contained in _~/.autojump/_.
|
||||
https://github.com/wting/autojump/issues
|
||||
|
||||
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
|
||||
AUTHORS
|
||||
-------
|
||||
|
||||
autojump was originally written by Joël Schaerer, and currently maintained by
|
||||
William Ting.
|
||||
William Ting. More contributors can be found in `AUTHORS`.
|
||||
|
||||
## COPYRIGHT
|
||||
COPYRIGHT
|
||||
---------
|
||||
|
||||
Copyright © 2012 Free Software Foundation, Inc. License GPLv3+: GNU GPL version
|
||||
Copyright © 2016 Free Software Foundation, Inc. License GPLv3+: GNU GPL 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 WARRANTY, to the extent
|
||||
permitted by law.
|
||||
|
@ -1,13 +0,0 @@
|
||||
## 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
|
||||
|
||||
Unit tests are available in `./tests/`. Run unit tests with the command:
|
||||
|
||||
make test
|
@ -1,23 +1,56 @@
|
||||
## NAME
|
||||
NAME
|
||||
----
|
||||
|
||||
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 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.
|
||||
database of the directories you use the most from the command line.
|
||||
|
||||
*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,77 +2,75 @@
|
||||
|
||||
### REQUIREMENTS
|
||||
|
||||
- Python v2.6+
|
||||
- Bash v4.0 for tab completion (or zsh)
|
||||
- Python v2.6+ or Python v3.3+
|
||||
- Supported shells
|
||||
- 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
|
||||
|
||||
If you are unable to update Python to a supported version, older versions of
|
||||
autojump can be [downloaded][dl] and installed manually.
|
||||
Due to limited time and resources, only "first class support" items will be
|
||||
maintained by the primary committers. All "community supported" items will be
|
||||
updated based on pull requests submitted by the general public.
|
||||
|
||||
- Python v2.4 is supported by [release v12][v12].
|
||||
Please continue opening issues and providing feedback for community supported
|
||||
items since consolidating information helps other users troubleshoot and submit
|
||||
enhancements and fixes.
|
||||
|
||||
### AUTOMATIC INSTALLATION
|
||||
### MANUAL
|
||||
|
||||
**Linux**
|
||||
Grab a copy of autojump:
|
||||
|
||||
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
|
||||
package management utilities to install (e.g. yum, apt-get, etc):
|
||||
package management utilities to install (e.g. apt-get, yum, pacman, 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
|
||||
|
||||
Install `autojump-zsh` for zsh, `autojump-fish` for fish, etc.
|
||||
|
||||
- ArchLinux
|
||||
- Gentoo
|
||||
- Frugalware
|
||||
- Slackware
|
||||
|
||||
\* Requires manual activation for policy reasons, please see
|
||||
``/usr/share/doc/autojump/README.Debian``.
|
||||
|
||||
**Mac**
|
||||
#### OS X
|
||||
|
||||
Homebrew is the recommended installation method for Mac OS X:
|
||||
|
||||
brew install autojump
|
||||
|
||||
MacPorts also available:
|
||||
MacPorts is also available:
|
||||
|
||||
port install autojump
|
||||
|
||||
**Other**
|
||||
## Windows
|
||||
|
||||
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.
|
||||
|
||||
[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
|
||||
Windows support is enabled by [clink](https://mridgers.github.io/clink/) which
|
||||
should be installed prior to installing autojump.
|
||||
|
@ -1,3 +1,3 @@
|
||||
% autojump(1) release-v20
|
||||
% autojump(1) release-v22.5.3
|
||||
%
|
||||
% 10 April 2012
|
||||
% 2018-09-09
|
||||
|
236
install.py
Executable file
236
install.py
Executable file
@ -0,0 +1,236 @@
|
||||
#!/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()))
|
246
install.sh
246
install.sh
@ -1,246 +0,0 @@
|
||||
#!/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" ]]; 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
|
||||
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.sh"
|
||||
if [[ ${local} ]]; then
|
||||
aj_shell_file="~/.autojump/etc/profile.d/autojump.sh"
|
||||
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
|
0
tests/__init__.py
Normal file
0
tests/__init__.py
Normal file
0
tests/integration/__init__.py
Normal file
0
tests/integration/__init__.py
Normal file
0
tests/unit/__init__.py
Normal file
0
tests/unit/__init__.py
Normal file
131
tests/unit/autojump_match_test.py
Normal file
131
tests/unit/autojump_match_test.py
Normal file
@ -0,0 +1,131 @@
|
||||
#!/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]
|
145
tests/unit/autojump_utils_test.py
Normal file
145
tests/unit/autojump_utils_test.py
Normal file
@ -0,0 +1,145 @@
|
||||
#!/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,32 +1,39 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
IPython autojump magic
|
||||
|
||||
Written by keith hughitt <keith.hughitt@gmail.com>, based on an earlier
|
||||
version by Mario Pastorelli <pastorelli.mario@gmail.com>.
|
||||
|
||||
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:
|
||||
To install, create a new IPython user profile by running:
|
||||
|
||||
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/").
|
||||
|
||||
@TODO: extend %cd to call "autojump -a"
|
||||
"""
|
||||
import os
|
||||
import subprocess as sub
|
||||
from IPython.core.magic import (register_line_magic, register_cell_magic,
|
||||
register_line_cell_magic)
|
||||
from subprocess import PIPE
|
||||
from subprocess import Popen
|
||||
|
||||
from IPython.core.magic import register_line_magic
|
||||
|
||||
ip = get_ipython() # noqa
|
||||
|
||||
ip = get_ipython()
|
||||
|
||||
@register_line_magic
|
||||
def j(path):
|
||||
cmd = ['autojump'] + path.split()
|
||||
newpath = sub.Popen(cmd, stdout=sub.PIPE, shell=False).communicate()[0][:-1] # delete last '\n'
|
||||
newpath = Popen(
|
||||
cmd,
|
||||
stdout=PIPE,
|
||||
shell=False,
|
||||
).communicate()[0].strip()
|
||||
|
||||
if newpath:
|
||||
ip.magic('cd %s' % newpath)
|
||||
ip.magic('cd %s' % newpath.decode('utf-8'))
|
||||
|
||||
|
||||
# remove from namespace
|
||||
del j
|
||||
|
33
tox.ini
Normal file
33
tox.ini
Normal file
@ -0,0 +1,33 @@
|
||||
[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
Executable file
217
uninstall.py
Executable file
@ -0,0 +1,217 @@
|
||||
#!/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
94
uninstall.sh
@ -1,94 +0,0 @@
|
||||
#!/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