mirror of
https://github.com/Llewellynvdm/zoxide.git
synced 2025-01-23 15:18:32 +00:00
Split crates
This commit is contained in:
parent
eaf63bcc69
commit
aca2477b68
120
.gitignore
vendored
120
.gitignore
vendored
@ -1,123 +1,7 @@
|
||||
# Created by https://www.gitignore.io/api/rust
|
||||
# Edit at https://www.gitignore.io/?templates=rust
|
||||
|
||||
### Rust ###
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
debug/
|
||||
target/
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
# End of https://www.gitignore.io/api/rust
|
||||
|
||||
|
||||
# Created by https://www.gitignore.io/api/python
|
||||
# Edit at https://www.gitignore.io/?templates=python
|
||||
|
||||
### Python ###
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
pip-wheel-metadata/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# celery beat schedule file
|
||||
celerybeat-schedule
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# Mr Developer
|
||||
.mr.developer.cfg
|
||||
.project
|
||||
.pydevproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# End of https://www.gitignore.io/api/python
|
||||
|
@ -17,6 +17,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- `zoxide init --no-aliases` no longer generates `z` or `zi`.
|
||||
|
||||
### Removed
|
||||
|
||||
- Deprecated PWD hooks for POSIX shells.
|
||||
|
||||
## [0.4.3] - 2020-07-04
|
||||
|
||||
### Fixed
|
||||
|
547
Cargo.lock
generated
547
Cargo.lock
generated
@ -1,474 +1,619 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.11.0"
|
||||
name = "anyhow"
|
||||
version = "1.0.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1fd36ffbb1fb7c834eac128ea8d0e310c5aeb635548f9d58861e1308d46e71c"
|
||||
|
||||
[[package]]
|
||||
name = "askama"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70a6e7ebd44d0047fd48206c83c5cd3214acc7b9d87f001da170145c47ef7d12"
|
||||
dependencies = [
|
||||
"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"askama_derive",
|
||||
"askama_escape",
|
||||
"askama_shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.32"
|
||||
name = "askama_derive"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1d7169690c4f56343dcd821ab834972a22570a2662a19a84fd7775d5e1c3881"
|
||||
dependencies = [
|
||||
"askama_shared",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.6"
|
||||
name = "askama_escape"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90c108c1a94380c89d2215d0ac54ce09796823cca0fd91b299cfff3b33e346fb"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.5.1"
|
||||
name = "askama_shared"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62fc272363345c8cdc030e4c259d9d028237f8b057dc9bb327772a257bde6bb5"
|
||||
dependencies = [
|
||||
"askama_escape",
|
||||
"nom",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "assert_cmd"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c88b9ca26f9c16ec830350d309397e74ee9abdfd8eb1f71cb6ecc71a3fc818da"
|
||||
dependencies = [
|
||||
"doc-comment",
|
||||
"predicates",
|
||||
"predicates-core",
|
||||
"predicates-tree",
|
||||
"wait-timeout",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f30d3a39baa26f9651f17b375061f3233dde33424a8b72b0dbe93a68a0bc896d"
|
||||
dependencies = [
|
||||
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.116 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "blake2b_simd"
|
||||
version = "0.5.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.33.3"
|
||||
version = "3.0.0-beta.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bd1061998a501ee7d4b6d449020df3266ca3124b941ec56cf2005c3779ca142"
|
||||
dependencies = [
|
||||
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"atty",
|
||||
"bitflags",
|
||||
"clap_derive",
|
||||
"indexmap",
|
||||
"lazy_static",
|
||||
"os_str_bytes",
|
||||
"strsim",
|
||||
"termcolor",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
"vec_map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.7.2"
|
||||
name = "clap_derive"
|
||||
version = "3.0.0-beta.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "370f715b81112975b1b69db93e0b56ea4cd4e5002ac43b2da8474106a54096a1"
|
||||
dependencies = [
|
||||
"autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "3.0.1"
|
||||
name = "difference"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
|
||||
|
||||
[[package]]
|
||||
name = "dirs-next"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf36e65a80337bea855cd4ef9b8401ffce06a7baedf2e85ec467b1ac3f6e82b6"
|
||||
dependencies = [
|
||||
"dirs-sys 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 1.0.0",
|
||||
"dirs-sys-next",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.3.5"
|
||||
name = "dirs-sys-next"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99de365f605554ae33f115102a02057d4fc18b01f3284d6870be0938743cfe7d"
|
||||
dependencies = [
|
||||
"libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_users 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc",
|
||||
"redox_users",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "doc-comment"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
|
||||
|
||||
[[package]]
|
||||
name = "dunce"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "float-ord"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2641c4a7c0c4101df53ea572bffdc561c146f6c2eb09e4df02bc4811e3feeb4"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.1.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
|
||||
dependencies = [
|
||||
"unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c30f6d0bc6b00693347368a67d41b58f2fb851215ff1da49e90fe2c5c667151"
|
||||
dependencies = [
|
||||
"libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa7087f49d294270db4e1928fc110c976cd4b9e5a16348e0a1df09afa99e6c98"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "5.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "260e51e7efe62b592207e9e13a68e43692a7a279171d6ba57abd208bf23645ad"
|
||||
|
||||
[[package]]
|
||||
name = "ordered-float"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fe9037165d7023b1228bc4ae9a2fa1a2b0095eca6c2998c624723dfd01314a5"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "2.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ac6fe3538f701e339953a3ebbe4f39941aababa8a3f6964635b24ab526daeac"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20"
|
||||
|
||||
[[package]]
|
||||
name = "predicates"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96bfead12e90dccead362d62bb2c90a5f6fc4584963645bc7f71a735e0b0735a"
|
||||
dependencies = [
|
||||
"difference",
|
||||
"predicates-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "predicates-core"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06075c3a3e92559ff8929e7a280684489ea27fe44805174c3ebd9328dcb37178"
|
||||
|
||||
[[package]]
|
||||
name = "predicates-tree"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e63c4859013b38a76eca2414c64911fba30def9e3202ac461a2d22831220124"
|
||||
dependencies = [
|
||||
"predicates-core",
|
||||
"treeline",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
|
||||
dependencies = [
|
||||
"unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
||||
dependencies = [
|
||||
"getrandom 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"getrandom",
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_hc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
||||
dependencies = [
|
||||
"ppv-lite86 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
||||
dependencies = [
|
||||
"getrandom 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
||||
dependencies = [
|
||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.57"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d"
|
||||
dependencies = [
|
||||
"getrandom 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rust-argon2 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"getrandom",
|
||||
"redox_syscall",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-argon2"
|
||||
version = "0.8.2"
|
||||
name = "remove_dir_all"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
|
||||
dependencies = [
|
||||
"base64 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.116"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5"
|
||||
dependencies = [
|
||||
"serde_derive 1.0.116 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.116"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "structopt"
|
||||
version = "0.3.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"structopt-derive 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "structopt-derive"
|
||||
version = "0.4.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro-error 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.42"
|
||||
version = "1.0.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea9c5432ff16d6152371f808fb5a871cd67368171b09bb21b43df8e4a47a3556"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
"libc",
|
||||
"rand",
|
||||
"redox_syscall",
|
||||
"remove_dir_all",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "203008d98caf094106cfaba70acfed15e18ed3ddb7d94e49baec153a2b462789"
|
||||
dependencies = [
|
||||
"unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "treeline"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
|
||||
|
||||
[[package]]
|
||||
name = "wait-timeout"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.9.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "zoxide"
|
||||
version = "0.4.3"
|
||||
dependencies = [
|
||||
"anyhow 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bincode 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dirs 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dunce 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"float-ord 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.116 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"structopt 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"anyhow",
|
||||
"clap",
|
||||
"dirs-next",
|
||||
"dunce",
|
||||
"glob",
|
||||
"once_cell",
|
||||
"zoxide-engine",
|
||||
"zoxide-shell",
|
||||
]
|
||||
|
||||
[metadata]
|
||||
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
"checksum anyhow 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)" = "6b602bfe940d21c130f3895acd65221e8a61270debe89d628b9cb4e3ccb8569b"
|
||||
"checksum arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
|
||||
"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
|
||||
"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
"checksum autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
"checksum base64 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
|
||||
"checksum bincode 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f30d3a39baa26f9651f17b375061f3233dde33424a8b72b0dbe93a68a0bc896d"
|
||||
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
"checksum blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a"
|
||||
"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
||||
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
"checksum clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)" = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
|
||||
"checksum constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
||||
"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
||||
"checksum dirs 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "142995ed02755914747cc6ca76fc7e4583cd18578746716d0508ea6ed558b9ff"
|
||||
"checksum dirs-sys 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a"
|
||||
"checksum dunce 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b2641c4a7c0c4101df53ea572bffdc561c146f6c2eb09e4df02bc4811e3feeb4"
|
||||
"checksum float-ord 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7bad48618fdb549078c333a7a8528acb57af271d0433bdecd523eb620628364e"
|
||||
"checksum getrandom 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6"
|
||||
"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
|
||||
"checksum hermit-abi 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c30f6d0bc6b00693347368a67d41b58f2fb851215ff1da49e90fe2c5c667151"
|
||||
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
"checksum libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)" = "aa7087f49d294270db4e1928fc110c976cd4b9e5a16348e0a1df09afa99e6c98"
|
||||
"checksum ppv-lite86 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20"
|
||||
"checksum proc-macro-error 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||
"checksum proc-macro-error-attr 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
"checksum proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
|
||||
"checksum quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
|
||||
"checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
||||
"checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
||||
"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
||||
"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
||||
"checksum redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)" = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
|
||||
"checksum redox_users 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d"
|
||||
"checksum rust-argon2 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9dab61250775933275e84053ac235621dfb739556d5c54a2f2e9313b7cf43a19"
|
||||
"checksum serde 1.0.116 (registry+https://github.com/rust-lang/crates.io-index)" = "96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5"
|
||||
"checksum serde_derive 1.0.116 (registry+https://github.com/rust-lang/crates.io-index)" = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8"
|
||||
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
"checksum structopt 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)" = "a33f6461027d7f08a13715659b2948e1602c31a3756aeae9378bfe7518c72e82"
|
||||
"checksum structopt-derive 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c92e775028122a4b3dd55d58f14fc5120289c69bee99df1d117ae30f84b225c9"
|
||||
"checksum syn 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)" = "9c51d92969d209b54a98397e1b91c8ae82d8c87a7bb87df0b29aa2ad81454228"
|
||||
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
|
||||
"checksum unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
|
||||
"checksum unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
||||
"checksum uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11"
|
||||
"checksum vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||
"checksum version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
|
||||
"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||
"checksum winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
[[package]]
|
||||
name = "zoxide-engine"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
"ordered-float",
|
||||
"serde",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zoxide-shell"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"askama",
|
||||
"assert_cmd",
|
||||
"once_cell",
|
||||
]
|
||||
|
21
Cargo.toml
21
Cargo.toml
@ -5,24 +5,21 @@ authors = ["Ajeet D'Souza <98ajeet@gmail.com>"]
|
||||
description = "A faster way to navigate your filesystem"
|
||||
repository = "https://github.com/ajeetdsouza/zoxide/"
|
||||
edition = "2018"
|
||||
|
||||
keywords = ["cli"]
|
||||
categories = ["command-line-utilities", "filesystem"]
|
||||
license = "MIT"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.28"
|
||||
bincode = "1.2.1"
|
||||
clap = "2.33.0"
|
||||
dirs = "3.0.0"
|
||||
dunce = "1.0.0"
|
||||
float-ord = "0.2.0"
|
||||
anyhow = "1.0.32"
|
||||
clap = "3.0.0-beta.2"
|
||||
dirs-next = "1.0.2"
|
||||
dunce = "1.0.1"
|
||||
glob = "0.3.0"
|
||||
serde = { version = "1.0.106", features = ["derive"] }
|
||||
structopt = "0.3.12"
|
||||
uuid = { version = "0.8.1", features = ["v4"] }
|
||||
once_cell = "1.4.1"
|
||||
zoxide-engine = { path = "crates/zoxide-engine" }
|
||||
zoxide-shell = { path = "crates/zoxide-shell" }
|
||||
|
||||
[workspace]
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
|
4
build.rs
4
build.rs
@ -1,5 +1,7 @@
|
||||
use std::process::Command;
|
||||
|
||||
fn main() {
|
||||
let git_describe = std::process::Command::new("git")
|
||||
let git_describe = Command::new("git")
|
||||
.args(&["describe", "--tags", "--broken"])
|
||||
.output()
|
||||
.ok()
|
||||
|
11
crates/zoxide-engine/.gitignore
vendored
Normal file
11
crates/zoxide-engine/.gitignore
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
debug/
|
||||
target/
|
||||
|
||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||
Cargo.lock
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
14
crates/zoxide-engine/Cargo.toml
Normal file
14
crates/zoxide-engine/Cargo.toml
Normal file
@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "zoxide-engine"
|
||||
version = "0.1.0"
|
||||
authors = ["Ajeet D'Souza <98ajeet@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.33"
|
||||
bincode = "1.3.1"
|
||||
ordered-float = "2.0.0"
|
||||
serde = { version = "1.0.116", features = ["derive"] }
|
||||
tempfile = "3.1.0"
|
42
crates/zoxide-engine/src/dir.rs
Normal file
42
crates/zoxide-engine/src/dir.rs
Normal file
@ -0,0 +1,42 @@
|
||||
use crate::query::Query;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct Dir {
|
||||
pub path: String,
|
||||
pub rank: Rank,
|
||||
pub last_accessed: Epoch,
|
||||
}
|
||||
|
||||
impl Dir {
|
||||
pub fn is_dir(&self) -> bool {
|
||||
Path::new(&self.path).is_dir()
|
||||
}
|
||||
|
||||
pub fn is_match(&self, query: &Query) -> bool {
|
||||
query.matches(&self.path)
|
||||
}
|
||||
|
||||
pub fn get_score(&self, now: Epoch) -> Rank {
|
||||
const HOUR: Epoch = 60 * 60;
|
||||
const DAY: Epoch = 24 * HOUR;
|
||||
const WEEK: Epoch = 7 * DAY;
|
||||
|
||||
let duration = now - self.last_accessed;
|
||||
if duration < HOUR {
|
||||
self.rank * 4.0
|
||||
} else if duration < DAY {
|
||||
self.rank * 2.0
|
||||
} else if duration < WEEK {
|
||||
self.rank * 0.5
|
||||
} else {
|
||||
self.rank * 0.25
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type Rank = f64;
|
||||
pub type Epoch = i64; // use a signed integer so subtraction can be performed on it
|
7
crates/zoxide-engine/src/lib.rs
Normal file
7
crates/zoxide-engine/src/lib.rs
Normal file
@ -0,0 +1,7 @@
|
||||
pub mod dir;
|
||||
mod query;
|
||||
mod store;
|
||||
|
||||
pub use dir::{Dir, Epoch};
|
||||
pub use query::Query;
|
||||
pub use store::Store;
|
100
crates/zoxide-engine/src/query.rs
Normal file
100
crates/zoxide-engine/src/query.rs
Normal file
@ -0,0 +1,100 @@
|
||||
use std::path::Path;
|
||||
|
||||
pub struct Query(Vec<String>);
|
||||
|
||||
impl Query {
|
||||
pub fn new<I, S>(keywords: I) -> Query
|
||||
where
|
||||
I: IntoIterator<Item = S>,
|
||||
S: AsRef<str>,
|
||||
{
|
||||
Query(
|
||||
keywords
|
||||
.into_iter()
|
||||
.map(|s: S| s.as_ref().to_lowercase())
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn keywords(&self) -> &[String] {
|
||||
&self.0
|
||||
}
|
||||
|
||||
pub fn matches<S: AsRef<str>>(&self, path: S) -> bool {
|
||||
let path = path.as_ref().to_lowercase();
|
||||
let keywords = self.keywords();
|
||||
|
||||
let get_filenames = || {
|
||||
let query_name = Path::new(keywords.last()?).file_name()?.to_str().unwrap();
|
||||
let dir_name = Path::new(&path).file_name()?.to_str().unwrap();
|
||||
Some((query_name, dir_name))
|
||||
};
|
||||
|
||||
if let Some((query_name, dir_name)) = get_filenames() {
|
||||
if !dir_name.contains(query_name) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
let mut subpath = path.as_str();
|
||||
|
||||
for keyword in keywords.iter() {
|
||||
match subpath.find(keyword) {
|
||||
Some(idx) => subpath = &subpath[idx + keyword.len()..],
|
||||
None => return false,
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Query;
|
||||
|
||||
#[test]
|
||||
fn test_query_normalization() {
|
||||
assert!(Query::new(&["fOo", "bAr"]).matches("/foo/bar"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_query_filename() {
|
||||
assert!(Query::new(&["ba"]).matches("/foo/bar"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_query_not_filename() {
|
||||
assert!(!Query::new(&["fo"]).matches("/foo/bar"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_query_not_filename_slash() {
|
||||
assert!(!Query::new(&["foo/"]).matches("/foo/bar"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_query_path_separator() {
|
||||
assert!(Query::new(&["/", "fo", "/", "ar"]).matches("/foo/bar"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_query_path_separator_between() {
|
||||
assert!(Query::new(&["oo/ba"]).matches("/foo/bar"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_query_overlap_text() {
|
||||
assert!(!Query::new(&["foo", "o", "bar"]).matches("/foo/bar"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_query_overlap_slash() {
|
||||
assert!(!Query::new(&["/foo/", "/bar"]).matches("/foo/bar"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_query_consecutive_slash() {
|
||||
assert!(Query::new(&["/foo/", "/baz"]).matches("/foo/bar/baz"));
|
||||
}
|
||||
}
|
186
crates/zoxide-engine/src/store.rs
Normal file
186
crates/zoxide-engine/src/store.rs
Normal file
@ -0,0 +1,186 @@
|
||||
use crate::dir::{Dir, Epoch, Rank};
|
||||
use crate::query::Query;
|
||||
|
||||
use anyhow::{bail, Context, Result};
|
||||
use bincode::Options;
|
||||
use ordered_float::OrderedFloat;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
use std::cmp::Reverse;
|
||||
use std::fs;
|
||||
use std::io::{self, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Store {
|
||||
pub dirs: Vec<Dir>,
|
||||
pub modified: bool,
|
||||
data_dir: PathBuf,
|
||||
}
|
||||
|
||||
impl Store {
|
||||
pub const CURRENT_VERSION: StoreVersion = StoreVersion(3);
|
||||
const MAX_SIZE: u64 = 8 * 1024 * 1024; // 8 MiB
|
||||
|
||||
pub fn open<P: Into<PathBuf>>(data_dir: P) -> Result<Store> {
|
||||
let data_dir = data_dir.into();
|
||||
let path = Self::get_path(&data_dir);
|
||||
|
||||
let buffer = match fs::read(&path) {
|
||||
Ok(buffer) => buffer,
|
||||
Err(e) if e.kind() == io::ErrorKind::NotFound => {
|
||||
fs::create_dir_all(&data_dir).with_context(|| {
|
||||
format!("unable to create data directory: {}", path.display())
|
||||
})?;
|
||||
return Ok(Store {
|
||||
dirs: Vec::new(),
|
||||
modified: false,
|
||||
data_dir,
|
||||
});
|
||||
}
|
||||
Err(e) => {
|
||||
Err(e).with_context(|| format!("could not read from store: {}", path.display()))?
|
||||
}
|
||||
};
|
||||
|
||||
let deserializer = &mut bincode::options()
|
||||
.with_fixint_encoding()
|
||||
.with_limit(Self::MAX_SIZE);
|
||||
|
||||
let version_size = deserializer
|
||||
.serialized_size(&Self::CURRENT_VERSION)
|
||||
.unwrap() as _;
|
||||
|
||||
if buffer.len() < version_size {
|
||||
bail!("data store may be corrupted: {}", path.display());
|
||||
}
|
||||
|
||||
let (buffer_version, buffer_dirs) = buffer.split_at(version_size);
|
||||
|
||||
let version = deserializer
|
||||
.deserialize(buffer_version)
|
||||
.with_context(|| format!("could not deserialize store version: {}", path.display()))?;
|
||||
|
||||
let dirs = match version {
|
||||
Self::CURRENT_VERSION => deserializer
|
||||
.deserialize(buffer_dirs)
|
||||
.with_context(|| format!("could not deserialize store: {}", path.display()))?,
|
||||
version => bail!(
|
||||
"unsupported store version, got={}, supported={}: {}",
|
||||
version.0,
|
||||
Self::CURRENT_VERSION.0,
|
||||
path.display()
|
||||
),
|
||||
};
|
||||
|
||||
Ok(Store {
|
||||
dirs,
|
||||
modified: false,
|
||||
data_dir,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn save(&mut self) -> Result<()> {
|
||||
if !self.modified {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let (buffer, buffer_size) = (|| -> bincode::Result<_> {
|
||||
let version_size = bincode::serialized_size(&Self::CURRENT_VERSION)?;
|
||||
let dirs_size = bincode::serialized_size(&self.dirs)?;
|
||||
|
||||
let buffer_size = version_size + dirs_size;
|
||||
let mut buffer = Vec::with_capacity(buffer_size as _);
|
||||
|
||||
bincode::serialize_into(&mut buffer, &Self::CURRENT_VERSION)?;
|
||||
bincode::serialize_into(&mut buffer, &self.dirs)?;
|
||||
|
||||
Ok((buffer, buffer_size))
|
||||
})()
|
||||
.context("could not serialize store")?;
|
||||
|
||||
let mut file = NamedTempFile::new_in(&self.data_dir).unwrap();
|
||||
let _ = file.as_file().set_len(buffer_size);
|
||||
file.write_all(&buffer).unwrap();
|
||||
file.persist(Self::get_path(&self.data_dir)).unwrap();
|
||||
|
||||
self.modified = false;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add<S: AsRef<str>>(&mut self, path: S, now: Epoch) {
|
||||
let path = path.as_ref();
|
||||
debug_assert!(Path::new(path).is_absolute());
|
||||
|
||||
match self.dirs.iter_mut().find(|dir| dir.path == path) {
|
||||
None => self.dirs.push(Dir {
|
||||
path: path.into(),
|
||||
last_accessed: now,
|
||||
rank: 1.0,
|
||||
}),
|
||||
Some(dir) => {
|
||||
dir.last_accessed = now;
|
||||
dir.rank += 1.0;
|
||||
}
|
||||
};
|
||||
|
||||
self.modified = true;
|
||||
}
|
||||
|
||||
pub fn iter_matches<'a>(
|
||||
&'a mut self,
|
||||
query: &'a Query,
|
||||
now: Epoch,
|
||||
) -> impl DoubleEndedIterator<Item = &'a Dir> {
|
||||
self.dirs
|
||||
.sort_unstable_by_key(|dir| Reverse(OrderedFloat(dir.get_score(now))));
|
||||
self.dirs.iter().filter(move |dir| dir.is_match(&query))
|
||||
}
|
||||
|
||||
pub fn remove<S: AsRef<str>>(&mut self, path: S) -> bool {
|
||||
let path = path.as_ref();
|
||||
|
||||
if let Some(idx) = self.dirs.iter().position(|dir| dir.path == path) {
|
||||
self.dirs.swap_remove(idx);
|
||||
self.modified = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub fn age(&mut self, max_age: Rank) {
|
||||
let sum_age = self.dirs.iter().map(|dir| dir.rank).sum::<Rank>();
|
||||
|
||||
if sum_age > max_age {
|
||||
let factor = 0.9 * max_age / sum_age;
|
||||
|
||||
for idx in (0..self.dirs.len()).rev() {
|
||||
let dir = &mut self.dirs[idx];
|
||||
|
||||
dir.rank *= factor;
|
||||
if dir.rank < 1.0 {
|
||||
self.dirs.swap_remove(idx);
|
||||
}
|
||||
}
|
||||
|
||||
self.modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
fn get_path<P: AsRef<Path>>(data_dir: P) -> PathBuf {
|
||||
data_dir.as_ref().join("db.zo")
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Store {
|
||||
fn drop(&mut self) {
|
||||
if let Err(e) = self.save() {
|
||||
println!("Error: {}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
pub struct StoreVersion(pub u32);
|
43
crates/zoxide-engine/tests/store.rs
Normal file
43
crates/zoxide-engine/tests/store.rs
Normal file
@ -0,0 +1,43 @@
|
||||
use zoxide_engine::Store;
|
||||
|
||||
#[test]
|
||||
fn test_add() {
|
||||
let path = "/foo/bar";
|
||||
let now = 946684800;
|
||||
|
||||
let data_dir = tempfile::tempdir().unwrap();
|
||||
{
|
||||
let mut store = Store::open(data_dir.path()).unwrap();
|
||||
store.add(path, now);
|
||||
store.add(path, now);
|
||||
}
|
||||
{
|
||||
let store = Store::open(data_dir.path()).unwrap();
|
||||
assert_eq!(store.dirs.len(), 1);
|
||||
|
||||
let dir = &store.dirs[0];
|
||||
assert_eq!(dir.path, path);
|
||||
assert_eq!(dir.last_accessed, now);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_remove() {
|
||||
let path = "/foo/bar";
|
||||
let now = 946684800;
|
||||
|
||||
let data_dir = tempfile::tempdir().unwrap();
|
||||
{
|
||||
let mut store = Store::open(data_dir.path()).unwrap();
|
||||
store.add(path, now);
|
||||
}
|
||||
{
|
||||
let mut store = Store::open(data_dir.path()).unwrap();
|
||||
assert!(store.remove(path));
|
||||
}
|
||||
{
|
||||
let mut store = Store::open(data_dir.path()).unwrap();
|
||||
assert!(store.dirs.is_empty());
|
||||
assert!(!store.remove(path));
|
||||
}
|
||||
}
|
11
crates/zoxide-shell/.gitignore
vendored
Normal file
11
crates/zoxide-shell/.gitignore
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
debug/
|
||||
target/
|
||||
|
||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||
Cargo.lock
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
15
crates/zoxide-shell/Cargo.toml
Normal file
15
crates/zoxide-shell/Cargo.toml
Normal file
@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "zoxide-shell"
|
||||
version = "0.1.0"
|
||||
authors = ["Ajeet D'Souza <98ajeet@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.33"
|
||||
askama = { version = "0.10.3", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
assert_cmd = "1.0.1"
|
||||
once_cell = "1.4.1"
|
97
crates/zoxide-shell/src/lib.rs
Normal file
97
crates/zoxide-shell/src/lib.rs
Normal file
@ -0,0 +1,97 @@
|
||||
use anyhow::{Context, Result};
|
||||
use askama::Template;
|
||||
|
||||
use std::io::Write;
|
||||
use std::ops::Deref;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum Hook {
|
||||
None,
|
||||
Prompt,
|
||||
Pwd,
|
||||
}
|
||||
|
||||
pub trait Generator {
|
||||
fn generate<W: Write>(&self, writer: &mut W) -> Result<()>;
|
||||
}
|
||||
|
||||
impl<T: Template> Generator for T {
|
||||
fn generate<W: Write>(&self, writer: &mut W) -> Result<()> {
|
||||
let source = &self.render().context("could not render template")?;
|
||||
writeln!(writer, "{}", source).context("could not write to output")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Opts<'a> {
|
||||
pub cmd: Option<&'a str>,
|
||||
pub hook: Hook,
|
||||
pub echo: bool,
|
||||
pub resolve_symlinks: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Template)]
|
||||
#[template(path = "bash.txt")]
|
||||
pub struct Bash<'a>(pub &'a Opts<'a>);
|
||||
|
||||
impl<'a> Deref for Bash<'a> {
|
||||
type Target = Opts<'a>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Template)]
|
||||
#[template(path = "fish.txt")]
|
||||
pub struct Fish<'a>(pub &'a Opts<'a>);
|
||||
|
||||
impl<'a> Deref for Fish<'a> {
|
||||
type Target = Opts<'a>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Template)]
|
||||
#[template(path = "posix.txt")]
|
||||
pub struct Posix<'a>(pub &'a Opts<'a>);
|
||||
|
||||
impl<'a> Deref for Posix<'a> {
|
||||
type Target = Opts<'a>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Template)]
|
||||
#[template(path = "powershell.txt")]
|
||||
pub struct PowerShell<'a>(pub &'a Opts<'a>);
|
||||
|
||||
impl<'a> Deref for PowerShell<'a> {
|
||||
type Target = Opts<'a>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Template)]
|
||||
#[template(path = "xonsh.txt")]
|
||||
pub struct Xonsh<'a>(pub &'a Opts<'a>);
|
||||
|
||||
impl<'a> Deref for Xonsh<'a> {
|
||||
type Target = Opts<'a>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Template)]
|
||||
#[template(path = "zsh.txt")]
|
||||
pub struct Zsh<'a>(pub &'a Opts<'a>);
|
||||
|
||||
impl<'a> Deref for Zsh<'a> {
|
||||
type Target = Opts<'a>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.0
|
||||
}
|
||||
}
|
142
crates/zoxide-shell/templates/bash.txt
Normal file
142
crates/zoxide-shell/templates/bash.txt
Normal file
@ -0,0 +1,142 @@
|
||||
{%- let SECTION = "# =============================================================================\n#" -%}
|
||||
{%- let NOT_CONFIGURED = "# -- not configured --" -%}
|
||||
|
||||
{{ SECTION }}
|
||||
# Utility functions for zoxide.
|
||||
#
|
||||
|
||||
# pwd based on the value of _ZO_RESOLVE_SYMLINKS.
|
||||
function __zoxide_pwd() {
|
||||
{%- if resolve_symlinks %}
|
||||
pwd -P
|
||||
{%- else %}
|
||||
pwd -L
|
||||
{%- endif %}
|
||||
}
|
||||
|
||||
# cd + custom logic based on the value of _ZO_ECHO.
|
||||
function __zoxide_cd() {
|
||||
# shellcheck disable=SC2164
|
||||
cd "$@" {%- if echo %} && __zoxide_pwd {%- endif %}
|
||||
}
|
||||
|
||||
{{ SECTION }}
|
||||
# Hook configuration for zoxide.
|
||||
#
|
||||
|
||||
# Hook to add new entries to the database.
|
||||
{%- match hook %}
|
||||
{%- when Hook::None %}
|
||||
{{ NOT_CONFIGURED }}
|
||||
|
||||
{%- when Hook::Prompt %}
|
||||
function __zoxide_hook() {
|
||||
zoxide add "$(__zoxide_pwd)"
|
||||
}
|
||||
|
||||
{%- when Hook::Pwd %}
|
||||
function __zoxide_hook() {
|
||||
local -r __zoxide_pwd_tmp="$(__zoxide_pwd)"
|
||||
if [ -z "$__zoxide_pwd_old" ]; then
|
||||
__zoxide_pwd_old="$__zoxide_pwd_tmp"
|
||||
elif [ "$__zoxide_pwd_old" != "$__zoxide_pwd_tmp" ]; then
|
||||
__zoxide_pwd_old="$__zoxide_pwd_tmp"
|
||||
zoxide add "$__zoxide_pwd_old"
|
||||
fi
|
||||
}
|
||||
{%- endmatch %}
|
||||
|
||||
# Initialize hook.
|
||||
{%- if hook == Hook::None %}
|
||||
{{ NOT_CONFIGURED }}
|
||||
|
||||
{%- else %}
|
||||
case "$PROMPT_COMMAND" in
|
||||
*__zoxide_hook*) ;;
|
||||
*) PROMPT_COMMAND="${PROMPT_COMMAND:+${PROMPT_COMMAND};}__zoxide_hook" ;;
|
||||
esac
|
||||
|
||||
{%- endif %}
|
||||
|
||||
{{ SECTION }}
|
||||
# When using zoxide with --no-aliases, alias these internal functions as
|
||||
# desired.
|
||||
#
|
||||
|
||||
# Jump to a directory using only keywords.
|
||||
function __zoxide_z() {
|
||||
if [ "$#" -eq 0 ]; then
|
||||
__zoxide_cd ~
|
||||
elif [ "$#" -eq 1 ] && [ "$1" = '-' ]; then
|
||||
if [ -n "$OLDPWD" ]; then
|
||||
__zoxide_cd "$OLDPWD"
|
||||
else
|
||||
echo "zoxide: \\$OLDPWD is not set"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
local __zoxide_result
|
||||
__zoxide_result="$(zoxide query -- "$@")" && __zoxide_cd "$__zoxide_result"
|
||||
fi
|
||||
}
|
||||
|
||||
# Jump to a directory using interactive search.
|
||||
function __zoxide_zi() {
|
||||
local __zoxide_result
|
||||
__zoxide_result="$(zoxide query -i -- "$@")" && __zoxide_cd "$__zoxide_result"
|
||||
}
|
||||
|
||||
# Add a new entry to the database.
|
||||
function __zoxide_za() {
|
||||
zoxide add "$@"
|
||||
}
|
||||
|
||||
# Query an entry from the database using only keywords.
|
||||
function __zoxide_zq() {
|
||||
zoxide query "$@"
|
||||
}
|
||||
|
||||
# Query an entry from the database using interactive selection.
|
||||
function __zoxide_zqi() {
|
||||
zoxide query -i "$@"
|
||||
}
|
||||
|
||||
# Remove an entry from the database using the exact path.
|
||||
function __zoxide_zr() {
|
||||
zoxide remove "$@"
|
||||
}
|
||||
|
||||
# Remove an entry from the database using interactive selection.
|
||||
function __zoxide_zri() {
|
||||
local __zoxide_result
|
||||
__zoxide_result="$(zoxide query -i -- "$@")" && zoxide remove "$__zoxide_result"
|
||||
}
|
||||
|
||||
{{ SECTION }}
|
||||
# Convenient aliases for zoxide. Disable these using --no-aliases.
|
||||
#
|
||||
|
||||
{%- match cmd %}
|
||||
{%- when Some with (cmd) %}
|
||||
|
||||
alias {{cmd}}='__zoxide_z'
|
||||
alias {{cmd}}i='__zoxide_zi'
|
||||
|
||||
alias {{cmd}}a='__zoxide_za'
|
||||
|
||||
alias {{cmd}}q='__zoxide_zq'
|
||||
alias {{cmd}}qi='__zoxide_zqi'
|
||||
|
||||
alias {{cmd}}r='__zoxide_zr'
|
||||
alias {{cmd}}ri='__zoxide_zri'
|
||||
|
||||
{%- when None %}
|
||||
{{ NOT_CONFIGURED }}
|
||||
|
||||
{%- endmatch %}
|
||||
|
||||
{{ SECTION }}
|
||||
# To initialize zoxide with bash, add the following line to your bash
|
||||
# configuration file (usually ~/.bashrc):
|
||||
#
|
||||
# eval "$(zoxide init bash)"
|
139
crates/zoxide-shell/templates/fish.txt
Normal file
139
crates/zoxide-shell/templates/fish.txt
Normal file
@ -0,0 +1,139 @@
|
||||
{%- let SECTION = "# =============================================================================\n#" -%}
|
||||
{%- let NOT_CONFIGURED = "# -- not configured --" -%}
|
||||
|
||||
{{ SECTION }}
|
||||
# Utility functions for zoxide.
|
||||
#
|
||||
|
||||
# pwd based on the value of _ZO_RESOLVE_SYMLINKS.
|
||||
function __zoxide_pwd
|
||||
{%- if resolve_symlinks %}
|
||||
pwd -P
|
||||
{%- else %}
|
||||
pwd -L
|
||||
{%- endif %}
|
||||
end
|
||||
|
||||
# cd + custom logic based on the value of _ZO_ECHO.
|
||||
function __zoxide_cd
|
||||
cd $argv
|
||||
{%- if echo %}
|
||||
and __zoxide_pwd
|
||||
{%- endif %}
|
||||
and commandline -f repaint
|
||||
end
|
||||
|
||||
{{ SECTION }}
|
||||
# Hook configuration for zoxide.
|
||||
#
|
||||
|
||||
# Initialize hook to add new entries to the database.
|
||||
{%- match hook %}
|
||||
{%- when Hook::None %}
|
||||
function __zoxide_hook
|
||||
|
||||
{%- when Hook::Prompt %}
|
||||
function __zoxide_hook --on-event fish_prompt
|
||||
|
||||
{%- when Hook::Pwd %}
|
||||
function __zoxide_hook --on-variable PWD
|
||||
|
||||
{%- endmatch %}
|
||||
zoxide add (__zoxide_pwd)
|
||||
end
|
||||
|
||||
{{ SECTION }}
|
||||
# When using zoxide with --no-aliases, alias these internal functions as
|
||||
# desired.
|
||||
#
|
||||
|
||||
# Jump to a directory using only keywords.
|
||||
function __zoxide_z
|
||||
set argc (count $argv)
|
||||
if test $argc -eq 0
|
||||
__zoxide_cd $HOME
|
||||
else if begin; test $argc -eq 1; and test $argv[1] = '-'; end
|
||||
__zoxide_cd -
|
||||
else
|
||||
set -l __zoxide_result (zoxide query -- $argv)
|
||||
and __zoxide_cd $__zoxide_result
|
||||
end
|
||||
end
|
||||
|
||||
# Jump to a directory using interactive search.
|
||||
function __zoxide_zi
|
||||
set -l __zoxide_result (zoxide query -i -- $argv)
|
||||
and __zoxide_cd $__zoxide_result
|
||||
end
|
||||
|
||||
# Add a new entry to the database.
|
||||
function __zoxide_za
|
||||
zoxide add $argv
|
||||
end
|
||||
|
||||
# Query an entry from the database using only keywords.
|
||||
function __zoxide_zq
|
||||
zoxide query $argv
|
||||
end
|
||||
|
||||
# Query an entry from the database using interactive selection.
|
||||
function __zoxide_zqi
|
||||
zoxide query -i $argv
|
||||
end
|
||||
|
||||
# Remove an entry from the database using the exact path.
|
||||
function __zoxide_zr
|
||||
zoxide remove $argv
|
||||
end
|
||||
|
||||
# Remove an entry from the database using interactive selection.
|
||||
function __zoxide_zri
|
||||
set -l __zoxide_result (zoxide query -i -- $argv)
|
||||
and zoxide remove $__zoxide_result
|
||||
end
|
||||
|
||||
{{ SECTION }}
|
||||
# Convenient aliases for zoxide. Disable these using --no-aliases.
|
||||
#
|
||||
|
||||
{%- match cmd %}
|
||||
{%- when Some with (cmd) %}
|
||||
|
||||
function {{cmd}}
|
||||
__zoxide_z $argv
|
||||
end
|
||||
|
||||
function {{cmd}}i
|
||||
__zoxide_zi $argv
|
||||
end
|
||||
|
||||
function {{cmd}}a
|
||||
__zoxide_za $argv
|
||||
end
|
||||
|
||||
function {{cmd}}q
|
||||
__zoxide_zq $argv
|
||||
end
|
||||
|
||||
function {{cmd}}qi
|
||||
__zoxide_zqi $argv
|
||||
end
|
||||
|
||||
function {{cmd}}r
|
||||
__zoxide_zr $argv
|
||||
end
|
||||
|
||||
function {{cmd}}ri
|
||||
__zoxide_zri $argv
|
||||
end
|
||||
|
||||
{%- when None %}
|
||||
{{ NOT_CONFIGURED }}
|
||||
|
||||
{%- endmatch %}
|
||||
|
||||
{{ SECTION }}
|
||||
# To initialize zoxide with fish, add the following line to your fish
|
||||
# configuration file (usually ~/.config/fish/config.fish):
|
||||
#
|
||||
# zoxide init fish | source
|
142
crates/zoxide-shell/templates/posix.txt
Normal file
142
crates/zoxide-shell/templates/posix.txt
Normal file
@ -0,0 +1,142 @@
|
||||
{%- let SECTION = "# =============================================================================\n#" -%}
|
||||
{%- let NOT_CONFIGURED = "# -- not configured --" -%}
|
||||
|
||||
{% if hook == Hook::Pwd -%}
|
||||
echo "\
|
||||
zoxide: PWD hooks are not supported on POSIX shells.
|
||||
Use '--hook prompt' when initializing zoxide."
|
||||
{%- endif %}
|
||||
|
||||
{{ SECTION }}
|
||||
# Utility functions for zoxide.
|
||||
#
|
||||
|
||||
# pwd based on the value of _ZO_RESOLVE_SYMLINKS.
|
||||
__zoxide_pwd() {
|
||||
{%- if resolve_symlinks %}
|
||||
pwd -P
|
||||
{%- else %}
|
||||
pwd -L
|
||||
{%- endif %}
|
||||
}
|
||||
|
||||
# cd + custom logic based on the value of _ZO_ECHO.
|
||||
__zoxide_cd() {
|
||||
# shellcheck disable=SC2164
|
||||
cd "$@" {%- if echo %} && __zoxide_pwd {%- endif %}
|
||||
}
|
||||
|
||||
{{ SECTION }}
|
||||
# Hook configuration for zoxide.
|
||||
#
|
||||
|
||||
# Hook to add new entries to the database.
|
||||
{%- match hook %}
|
||||
{%- when Hook::None %}
|
||||
{{ NOT_CONFIGURED }}
|
||||
|
||||
{%- when Hook::Prompt %}
|
||||
__zoxide_hook() {
|
||||
zoxide add "$(__zoxide_pwd)"
|
||||
}
|
||||
|
||||
{%- when Hook::Pwd %}
|
||||
{{ NOT_CONFIGURED }}
|
||||
|
||||
{%- endmatch %}
|
||||
|
||||
# Initialize hook.
|
||||
{%- match hook %}
|
||||
{%- when Hook::None %}
|
||||
{{ NOT_CONFIGURED }}
|
||||
|
||||
{%- when Hook::Prompt %}
|
||||
case "$PS1" in
|
||||
*\$\(__zoxide_hook\)*) ;;
|
||||
*) PS1="${PS1}\$(__zoxide_hook)" ;;
|
||||
esac
|
||||
|
||||
{%- when Hook::Pwd %}
|
||||
{{ NOT_CONFIGURED }}
|
||||
|
||||
{%- endmatch %}
|
||||
|
||||
{{ SECTION }}
|
||||
# When using zoxide with --no-aliases, alias these internal functions as
|
||||
# desired.
|
||||
#
|
||||
|
||||
# Jump to a directory using only keywords.
|
||||
__zoxide_z() {
|
||||
if [ "$#" -eq 0 ]; then
|
||||
__zoxide_cd ~
|
||||
elif [ "$#" -eq 1 ] && [ "$1" = '-' ]; then
|
||||
if [ -n "$OLDPWD" ]; then
|
||||
__zoxide_cd "$OLDPWD"
|
||||
else
|
||||
echo "zoxide: \\$OLDPWD is not set"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
__zoxide_result="$(zoxide query -- "$@")" && __zoxide_cd "$__zoxide_result"
|
||||
fi
|
||||
}
|
||||
|
||||
# Jump to a directory using interactive search.
|
||||
__zoxide_zi() {
|
||||
__zoxide_result="$(zoxide query -i -- "$@")" && __zoxide_cd "$__zoxide_result"
|
||||
}
|
||||
|
||||
# Add a new entry to the database.
|
||||
__zoxide_za() {
|
||||
zoxide add "$@"
|
||||
}
|
||||
|
||||
# Query an entry from the database using only keywords.
|
||||
__zoxide_zq() {
|
||||
zoxide query "$@"
|
||||
}
|
||||
|
||||
# Query an entry from the database using interactive selection.
|
||||
__zoxide_zqi() {
|
||||
zoxide query -i "$@"
|
||||
}
|
||||
|
||||
# Remove an entry from the database using the exact path.
|
||||
__zoxide_zr() {
|
||||
zoxide remove "$@"
|
||||
}
|
||||
|
||||
# Remove an entry from the database using interactive selection.
|
||||
__zoxide_zri() {
|
||||
__zoxide_result="$(zoxide query -i -- "$@")" && zoxide remove "$__zoxide_result"
|
||||
}
|
||||
|
||||
{{ SECTION }}
|
||||
# Convenient aliases for zoxide. Disable these using --no-aliases.
|
||||
#
|
||||
|
||||
{%- match cmd %}
|
||||
{%- when Some with (cmd) %}
|
||||
|
||||
alias {{cmd}}='__zoxide_z'
|
||||
alias {{cmd}}i='__zoxide_zi'
|
||||
|
||||
alias {{cmd}}a='__zoxide_za'
|
||||
|
||||
alias {{cmd}}q='__zoxide_zq'
|
||||
alias {{cmd}}qi='__zoxide_zqi'
|
||||
|
||||
alias {{cmd}}r='__zoxide_zr'
|
||||
alias {{cmd}}ri='__zoxide_zri'
|
||||
|
||||
{%- when None %}
|
||||
{{ NOT_CONFIGURED }}
|
||||
|
||||
{%- endmatch %}
|
||||
|
||||
{{ SECTION }}
|
||||
# To initialize zoxide with your POSIX shell, add the following line to your
|
||||
# shell configuration file:
|
||||
#
|
||||
# eval "$(zoxide init posix --hook prompt)"
|
146
crates/zoxide-shell/templates/powershell.txt
Normal file
146
crates/zoxide-shell/templates/powershell.txt
Normal file
@ -0,0 +1,146 @@
|
||||
{%- let SECTION = "# =============================================================================\n#" -%}
|
||||
{%- let NOT_CONFIGURED = "# -- not configured --" -%}
|
||||
|
||||
{{ SECTION }}
|
||||
# Utility functions for zoxide.
|
||||
#
|
||||
|
||||
# pwd based on the value of _ZO_RESOLVE_SYMLINKS.
|
||||
function __zoxide_pwd {
|
||||
$(Get-Location).Path
|
||||
}
|
||||
|
||||
# cd + custom logic based on the value of _ZO_ECHO.
|
||||
function __zoxide_cd($dir) {
|
||||
Set-Location $dir -ea Stop
|
||||
{%- if echo %}
|
||||
__zoxide_pwd
|
||||
{%- endif %}
|
||||
}
|
||||
|
||||
{{ SECTION }}
|
||||
# Hook configuration for zoxide.
|
||||
#
|
||||
|
||||
# Hook to add new entries to the database.
|
||||
function __zoxide_hook {
|
||||
zoxide add $(__zoxide_pwd)
|
||||
}
|
||||
|
||||
# Initialize hook.
|
||||
{%- match hook %}
|
||||
{%- when Hook::None %}
|
||||
{{ NOT_CONFIGURED }}
|
||||
|
||||
{%- when Hook::Prompt %}
|
||||
$PreZoxidePrompt = $function:prompt
|
||||
function prompt {
|
||||
$null = __zoxide_hook
|
||||
& $PreZoxidePrompt
|
||||
}
|
||||
|
||||
{%- when Hook::Pwd %}
|
||||
if ($PSVersionTable.PSVersion.Major -ge 6) {
|
||||
$ExecutionContext.InvokeCommand.LocationChangedAction = {
|
||||
$null = __zoxide_hook
|
||||
}
|
||||
} else {
|
||||
Write-Error "`
|
||||
zoxide: PWD hooks are not supported below PowerShell 6.
|
||||
Use '--hook prompt' when initializing zoxide."
|
||||
}
|
||||
|
||||
{%- endmatch %}
|
||||
|
||||
{{ SECTION }}
|
||||
# When using zoxide with --no-aliases, alias these internal functions as
|
||||
# desired.
|
||||
#
|
||||
|
||||
# Jump to a directory using only keywords.
|
||||
function __zoxide_z {
|
||||
if ($args.Length -eq 0) {
|
||||
__zoxide_cd ~
|
||||
}
|
||||
elseif ($args.Length -eq 1 -and $args[0] -eq '-') {
|
||||
__zoxide_cd -
|
||||
}
|
||||
else {
|
||||
$__zoxide_result = zoxide query -- @args
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
__zoxide_cd $__zoxide_result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Jump to a directory using interactive search.
|
||||
function zi {
|
||||
$__zoxide_result = zoxide query -i -- @args
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
__zoxide_cd $__zoxide_result
|
||||
}
|
||||
}
|
||||
|
||||
# Add a new entry to the database.
|
||||
function __zoxide_za {
|
||||
zoxide add @args
|
||||
}
|
||||
|
||||
# Query an entry from the database using only keywords.
|
||||
function __zoxide_zq {
|
||||
zoxide query @args
|
||||
}
|
||||
|
||||
# Query an entry from the database using interactive selection.
|
||||
function __zoxide_zqi {
|
||||
zoxide query -i @args
|
||||
}
|
||||
|
||||
# Remove an entry from the database using the exact path.
|
||||
function __zoxide_zr {
|
||||
zoxide remove @args
|
||||
}
|
||||
|
||||
# Remove an entry from the database using interactive selection.
|
||||
function __zoxide_zri {
|
||||
$_zoxide_result = zoxide query -i -- @args
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
zoxide remove $_zoxide_result
|
||||
}
|
||||
}
|
||||
|
||||
{{ SECTION }}
|
||||
# Convenient aliases for zoxide. Disable these using --no-aliases.
|
||||
#
|
||||
|
||||
{%- match cmd %}
|
||||
{%- when Some with (cmd) %}
|
||||
|
||||
Set-Alias {{cmd}} __zoxide_z
|
||||
Set-Alias {{cmd}}i __zoxide_zi
|
||||
|
||||
Set-Alias {{cmd}}a __zoxide_za
|
||||
|
||||
Set-Alias {{cmd}}q __zoxide_zq
|
||||
Set-Alias {{cmd}}qi __zoxide_zqi
|
||||
|
||||
Set-Alias {{cmd}}r __zoxide_zr
|
||||
Set-Alias {{cmd}}ri __zoxide_zri
|
||||
|
||||
{%- when None %}
|
||||
{{ NOT_CONFIGURED }}
|
||||
|
||||
{%- endmatch %}
|
||||
|
||||
{{ SECTION }}
|
||||
# To initialize zoxide with PowerShell, add the following line to your
|
||||
# PowerShell configuration file (the location is stored in $profile):
|
||||
#
|
||||
# Invoke-Expression (& {
|
||||
# $hook = if ($PSVersionTable.PSVersion.Major -ge 6) {
|
||||
# 'pwd'
|
||||
# } else {
|
||||
# 'prompt'
|
||||
# }
|
||||
# (zoxide init powershell --hook $hook) -join "`n"
|
||||
# })
|
114
crates/zoxide-shell/templates/xonsh.txt
Normal file
114
crates/zoxide-shell/templates/xonsh.txt
Normal file
@ -0,0 +1,114 @@
|
||||
{%- let SECTION = "# =============================================================================\n#" -%}
|
||||
{%- let NOT_CONFIGURED = "# -- not configured --" -%}
|
||||
|
||||
{%- if resolve_symlinks -%}
|
||||
import os
|
||||
{%- endif %}
|
||||
import os.path
|
||||
|
||||
{{ SECTION }}
|
||||
# Utility functions for zoxide.
|
||||
#
|
||||
|
||||
# pwd based on the value of _ZO_RESOLVE_SYMLINKS.
|
||||
def __zoxide_pwd() -> str:
|
||||
{%- if resolve_symlinks %}
|
||||
return os.getcwd()
|
||||
{%- else %}
|
||||
return $PWD
|
||||
{%- endif %}
|
||||
|
||||
# cd + custom logic based on the value of _ZO_ECHO.
|
||||
def __zoxide_cd(path: str):
|
||||
cd @(path) {%- if echo %} and print(__zoxide_pwd()) {%- endif %}
|
||||
|
||||
{{ SECTION }}
|
||||
# Hook configuration for zoxide.
|
||||
#
|
||||
|
||||
# Initialize hook to add new entries to the database.
|
||||
{%- match hook %}
|
||||
{%- when Hook::None %}
|
||||
{{ NOT_CONFIGURED }}
|
||||
|
||||
{%- when Hook::Prompt %}
|
||||
@events.on_post_prompt
|
||||
|
||||
{%- when Hook::Pwd %}
|
||||
@events.on_chdir
|
||||
|
||||
{%- endmatch %}
|
||||
def __zoxide_hook(**kwargs):
|
||||
zoxide add @(__zoxide_pwd())
|
||||
|
||||
{{ SECTION }}
|
||||
# When using zoxide with --no-aliases, alias these internal functions as
|
||||
# desired.
|
||||
#
|
||||
|
||||
# Jump to a directory using only keywords.
|
||||
def __zoxide_z(keywords: [str]):
|
||||
if keywords == []:
|
||||
__zoxide_cd($HOME)
|
||||
elif keywords == ['-']:
|
||||
__zoxide_cd('-')
|
||||
elif len(keywords) == 1 and os.path.isdir(keywords[0]):
|
||||
__zoxide_cd(keywords[0])
|
||||
else:
|
||||
__zoxide_result = $(zoxide query -- @(keywords))[:-1]
|
||||
if __zoxide_result:
|
||||
__zoxide_cd(__zoxide_result)
|
||||
|
||||
# Jump to a directory using interactive search.
|
||||
def __zoxide_zi(keywords: [str]):
|
||||
__zoxide_result = $(zoxide query -- @(keywords))[:-1]
|
||||
if __zoxide_result:
|
||||
__zoxide_cd(__zoxide_result)
|
||||
|
||||
# Add a new entry to the database.
|
||||
def __zoxide_za(args: [str]):
|
||||
zoxide add @(args)
|
||||
|
||||
# Query an entry from the database using only keywords.
|
||||
def __zoxide_zq(args: [str]):
|
||||
zoxide query @(args)
|
||||
|
||||
# Query an entry from the database using interactive selection.
|
||||
def __zoxide_zqi(args: [str]):
|
||||
zoxide query -i @(args)
|
||||
|
||||
# Remove an entry from the database using the exact path.
|
||||
def __zoxide_zr(args: [str]):
|
||||
zoxide remove @(args)
|
||||
|
||||
# Remove an entry from the database using interactive selection.
|
||||
def __zoxide_zri(keywords: [str]):
|
||||
__zoxide_result = $(zoxide query -- @(keywords))[:-1]
|
||||
if __zoxide_result:
|
||||
zoxide remove @(__zoxide_result)
|
||||
|
||||
{{ SECTION }}
|
||||
# Convenient aliases for zoxide. Disable these using --no-aliases.
|
||||
#
|
||||
|
||||
{%- match cmd %}
|
||||
{%- when Some with (cmd) %}
|
||||
|
||||
aliases['{{cmd}}'] = __zoxide_z
|
||||
aliases['{{cmd}}i'] = __zoxide_zi
|
||||
aliases['{{cmd}}a'] = __zoxide_za
|
||||
aliases['{{cmd}}q'] = __zoxide_zq
|
||||
aliases['{{cmd}}qi'] = __zoxide_zqi
|
||||
aliases['{{cmd}}r'] = __zoxide_zr
|
||||
aliases['{{cmd}}ri'] = __zoxide_zri
|
||||
|
||||
{%- when None %}
|
||||
{{ NOT_CONFIGURED }}
|
||||
|
||||
{%- endmatch %}
|
||||
|
||||
{{ SECTION }}
|
||||
# To initialize zoxide with xonsh, add the following line to your xonsh
|
||||
# configuration file (usually ~/.xonshrc):
|
||||
#
|
||||
# execx($(zoxide init xonsh), 'exec', __xonsh__.ctx, filename='zoxide')
|
129
crates/zoxide-shell/templates/zsh.txt
Normal file
129
crates/zoxide-shell/templates/zsh.txt
Normal file
@ -0,0 +1,129 @@
|
||||
{%- let SECTION = "# =============================================================================\n#" -%}
|
||||
{%- let NOT_CONFIGURED = "# -- not configured --" -%}
|
||||
|
||||
{{ SECTION }}
|
||||
# Utility functions for zoxide.
|
||||
#
|
||||
|
||||
# pwd based on the value of _ZO_RESOLVE_SYMLINKS.
|
||||
function __zoxide_pwd() {
|
||||
{%- if resolve_symlinks %}
|
||||
pwd -P
|
||||
{%- else %}
|
||||
pwd -L
|
||||
{%- endif %}
|
||||
}
|
||||
|
||||
# cd + custom logic based on the value of _ZO_ECHO.
|
||||
function __zoxide_cd() {
|
||||
cd "$@" {%- if echo %} && __zoxide_pwd {%- endif %}
|
||||
}
|
||||
|
||||
{{ SECTION }}
|
||||
# Hook configuration for zoxide.
|
||||
#
|
||||
|
||||
# Hook to add new entries to the database.
|
||||
function __zoxide_hook() {
|
||||
zoxide add "$(__zoxide_pwd)"
|
||||
}
|
||||
|
||||
# Initialize hook.
|
||||
{%- match hook %}
|
||||
{%- when Hook::None %}
|
||||
{{ NOT_CONFIGURED }}
|
||||
|
||||
{%- when Hook::Prompt %}
|
||||
[[ -n "${precmd_functions[(r)__zoxide_hook]}" ]] || {
|
||||
precmd_functions+=(__zoxide_hook)
|
||||
}
|
||||
|
||||
{%- when Hook::Pwd %}
|
||||
chpwd_functions=(${chpwd_functions[@]} "__zoxide_hook")
|
||||
|
||||
{%- endmatch %}
|
||||
|
||||
{{ SECTION }}
|
||||
# When using zoxide with --no-aliases, alias these internal functions as
|
||||
# desired.
|
||||
#
|
||||
|
||||
# Jump to a directory using only keywords.
|
||||
function __zoxide_z() {
|
||||
if [ "$#" -eq 0 ]; then
|
||||
__zoxide_cd ~
|
||||
elif [ "$#" -eq 1 ] && [ "$1" = '-' ]; then
|
||||
if [ -n "$OLDPWD" ]; then
|
||||
__zoxide_cd "$OLDPWD"
|
||||
else
|
||||
echo "zoxide: \\$OLDPWD is not set"
|
||||
return 1
|
||||
fi
|
||||
elif [ "$#" -eq 1 ] && [ -d "$1" ]; then
|
||||
__zoxide_cd "$1"
|
||||
else
|
||||
local __zoxide_result
|
||||
__zoxide_result="$(zoxide query -- "$@")" && __zoxide_cd "$__zoxide_result"
|
||||
fi
|
||||
}
|
||||
|
||||
# Jump to a directory using interactive search.
|
||||
function __zoxide_zi() {
|
||||
local __zoxide_result
|
||||
__zoxide_result="$(zoxide query -i -- "$@")" && __zoxide_cd "$__zoxide_result"
|
||||
}
|
||||
|
||||
# Add a new entry to the database.
|
||||
function __zoxide_za() {
|
||||
zoxide add "$@"
|
||||
}
|
||||
|
||||
# Query an entry from the database using only keywords.
|
||||
function __zoxide_zq() {
|
||||
zoxide query "$@"
|
||||
}
|
||||
|
||||
# Query an entry from the database using interactive selection.
|
||||
function __zoxide_zqi() {
|
||||
zoxide query -i "$@"
|
||||
}
|
||||
|
||||
# Remove an entry from the database using the exact path.
|
||||
function __zoxide_zr() {
|
||||
zoxide remove "$@"
|
||||
}
|
||||
|
||||
# Remove an entry from the database using interactive selection.
|
||||
function __zoxide_zri() {
|
||||
local __zoxide_result
|
||||
__zoxide_result="$(zoxide query -i -- "$@")" && zoxide remove "$__zoxide_result"
|
||||
}
|
||||
|
||||
{{ SECTION }}
|
||||
# Convenient aliases for zoxide. Disable these using --no-aliases.
|
||||
#
|
||||
|
||||
{%- match cmd %}
|
||||
{%- when Some with (cmd) %}
|
||||
|
||||
alias {{cmd}}='__zoxide_z'
|
||||
alias {{cmd}}i='__zoxide_zi'
|
||||
|
||||
alias {{cmd}}a='__zoxide_za'
|
||||
|
||||
alias {{cmd}}q='__zoxide_zq'
|
||||
alias {{cmd}}qi='__zoxide_zqi'
|
||||
|
||||
alias {{cmd}}r='__zoxide_zr'
|
||||
alias {{cmd}}ri='__zoxide_zri'
|
||||
|
||||
{%- when None %}
|
||||
{{ NOT_CONFIGURED }}
|
||||
|
||||
{%- endmatch %}
|
||||
|
||||
{{ SECTION }}
|
||||
# To initialize zoxide with zsh, add the following line to your zsh
|
||||
# configuration file (usually ~/.zshrc):
|
||||
#
|
||||
# eval "$(zoxide init zsh)"
|
151
crates/zoxide-shell/tests/syntax.rs
Normal file
151
crates/zoxide-shell/tests/syntax.rs
Normal file
@ -0,0 +1,151 @@
|
||||
use askama::Template;
|
||||
use assert_cmd::Command;
|
||||
use once_cell::sync::OnceCell;
|
||||
use zoxide_shell::{Bash, Fish, Hook, Opts, Posix, PowerShell, Xonsh, Zsh};
|
||||
|
||||
fn opts() -> &'static [Opts<'static>] {
|
||||
static OPTS: OnceCell<Vec<Opts>> = OnceCell::new();
|
||||
OPTS.get_or_init(|| {
|
||||
let mut opts = Vec::new();
|
||||
for &echo in &[false, true] {
|
||||
for &resolve_symlinks in &[false, true] {
|
||||
for &hook in &[Hook::None, Hook::Prompt, Hook::Pwd] {
|
||||
for &cmd in &[None, Some("z")] {
|
||||
opts.push(Opts {
|
||||
echo,
|
||||
resolve_symlinks,
|
||||
hook,
|
||||
cmd,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
opts
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bash() {
|
||||
for opts in opts() {
|
||||
let source = crate::Bash(opts).render().unwrap();
|
||||
Command::new("bash")
|
||||
.args(&["-c", &source])
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("")
|
||||
.stderr("");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bash_posix() {
|
||||
for opts in opts() {
|
||||
let source = crate::Posix(opts).render().unwrap();
|
||||
let assert = Command::new("bash")
|
||||
.args(&["--posix", "-c", &source])
|
||||
.assert()
|
||||
.success()
|
||||
.stderr("");
|
||||
|
||||
if opts.hook != Hook::Pwd {
|
||||
assert.stdout("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dash() {
|
||||
for opts in opts() {
|
||||
let source = crate::Posix(opts).render().unwrap();
|
||||
let assert = Command::new("bash")
|
||||
.args(&["--posix", "-c", &source])
|
||||
.assert()
|
||||
.success()
|
||||
.stderr("");
|
||||
|
||||
if opts.hook != Hook::Pwd {
|
||||
assert.stdout("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fish() {
|
||||
for opts in opts() {
|
||||
let source = crate::Fish(opts).render().unwrap();
|
||||
Command::new("fish")
|
||||
.args(&["-c", &source])
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("")
|
||||
.stderr("");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pwsh() {
|
||||
for opts in opts() {
|
||||
let source = crate::PowerShell(opts).render().unwrap();
|
||||
Command::new("pwsh")
|
||||
.args(&["-c", &source])
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("")
|
||||
.stderr("");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_shellcheck_bash() {
|
||||
for opts in opts() {
|
||||
let source = crate::Bash(opts).render().unwrap();
|
||||
Command::new("shellcheck")
|
||||
.args(&["--shell", "bash", "-"])
|
||||
.write_stdin(source.as_bytes())
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("")
|
||||
.stderr("");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_shellcheck_sh() {
|
||||
for opts in opts() {
|
||||
let source = crate::Posix(opts).render().unwrap();
|
||||
Command::new("shellcheck")
|
||||
.args(&["--shell", "sh", "-"])
|
||||
.write_stdin(source.as_bytes())
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("")
|
||||
.stderr("");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_xonsh() {
|
||||
for opts in opts() {
|
||||
let source = crate::Xonsh(opts).render().unwrap();
|
||||
Command::new("xonsh")
|
||||
.args(&["-c", &source])
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("")
|
||||
.stderr("");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zsh() {
|
||||
for opts in opts() {
|
||||
let source = crate::Zsh(opts).render().unwrap();
|
||||
Command::new("zsh")
|
||||
.args(&["-c", &source])
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("")
|
||||
.stderr("");
|
||||
}
|
||||
}
|
@ -1,10 +1,9 @@
|
||||
use crate::db::Rank;
|
||||
|
||||
use anyhow::{bail, Context, Result};
|
||||
use dirs_next as dirs;
|
||||
use zoxide_engine::dir::Rank;
|
||||
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub fn zo_data_dir() -> Result<PathBuf> {
|
||||
@ -19,11 +18,6 @@ pub fn zo_data_dir() -> Result<PathBuf> {
|
||||
},
|
||||
};
|
||||
|
||||
// This will fail when `data_dir` points to a file or a broken symlink, but
|
||||
// will no-op on a valid symlink (to a directory), or an actual directory.
|
||||
fs::create_dir_all(&data_dir)
|
||||
.with_context(|| format!("could not create data directory: {}", data_dir.display()))?;
|
||||
|
||||
Ok(data_dir)
|
||||
}
|
||||
|
||||
|
294
src/db.rs
294
src/db.rs
@ -1,294 +0,0 @@
|
||||
use anyhow::{bail, Context, Result};
|
||||
use bincode::Options;
|
||||
use float_ord::FloatOrd;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
use std::cmp::Reverse;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::fs::{self, OpenOptions};
|
||||
use std::io::{self, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[derive(Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
struct DbVersion(u32);
|
||||
|
||||
pub struct Db {
|
||||
pub dirs: Vec<Dir>,
|
||||
pub modified: bool,
|
||||
data_dir: PathBuf,
|
||||
}
|
||||
|
||||
impl Db {
|
||||
const CURRENT_VERSION: DbVersion = DbVersion(3);
|
||||
const MAX_SIZE: u64 = 8 * 1024 * 1024; // 8 MiB
|
||||
|
||||
pub fn open(data_dir: PathBuf) -> Result<Db> {
|
||||
fs::create_dir_all(&data_dir)
|
||||
.with_context(|| format!("unable to create data directory: {}", data_dir.display()))?;
|
||||
|
||||
let path = Self::get_path(&data_dir);
|
||||
|
||||
let buffer = match fs::read(&path) {
|
||||
Ok(buffer) => buffer,
|
||||
Err(e) if e.kind() == io::ErrorKind::NotFound => {
|
||||
return Ok(Db {
|
||||
dirs: Vec::new(),
|
||||
modified: false,
|
||||
data_dir,
|
||||
})
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(e)
|
||||
.with_context(|| format!("could not read from database: {}", path.display()))
|
||||
}
|
||||
};
|
||||
|
||||
if buffer.is_empty() {
|
||||
return Ok(Db {
|
||||
dirs: Vec::new(),
|
||||
modified: false,
|
||||
data_dir,
|
||||
});
|
||||
}
|
||||
|
||||
let deserializer = &mut bincode::options()
|
||||
.with_fixint_encoding()
|
||||
.with_limit(Self::MAX_SIZE);
|
||||
|
||||
let version_size = deserializer
|
||||
.serialized_size(&Self::CURRENT_VERSION)
|
||||
.context("could not determine size of database version field")?
|
||||
as _;
|
||||
|
||||
if buffer.len() < version_size {
|
||||
bail!("database is corrupted: {}", path.display());
|
||||
}
|
||||
|
||||
let (buffer_version, buffer_dirs) = buffer.split_at(version_size);
|
||||
|
||||
let version = deserializer.deserialize(buffer_version).with_context(|| {
|
||||
format!("could not deserialize database version: {}", path.display())
|
||||
})?;
|
||||
|
||||
let dirs = match version {
|
||||
Self::CURRENT_VERSION => deserializer
|
||||
.deserialize(buffer_dirs)
|
||||
.with_context(|| format!("could not deserialize database: {}", path.display()))?,
|
||||
DbVersion(version_num) => bail!(
|
||||
"zoxide {} does not support schema v{}: {}",
|
||||
env!("ZOXIDE_VERSION"),
|
||||
version_num,
|
||||
path.display(),
|
||||
),
|
||||
};
|
||||
|
||||
Ok(Db {
|
||||
dirs,
|
||||
modified: false,
|
||||
data_dir,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn save(&mut self) -> Result<()> {
|
||||
if !self.modified {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let (buffer, buffer_size) = (|| -> bincode::Result<_> {
|
||||
let version_size = bincode::serialized_size(&Self::CURRENT_VERSION)?;
|
||||
let dirs_size = bincode::serialized_size(&self.dirs)?;
|
||||
|
||||
let buffer_size = version_size + dirs_size;
|
||||
let mut buffer = Vec::with_capacity(buffer_size as _);
|
||||
|
||||
bincode::serialize_into(&mut buffer, &Self::CURRENT_VERSION)?;
|
||||
bincode::serialize_into(&mut buffer, &self.dirs)?;
|
||||
|
||||
Ok((buffer, buffer_size))
|
||||
})()
|
||||
.context("could not serialize database")?;
|
||||
|
||||
let db_path_tmp = Self::get_path_tmp(&self.data_dir);
|
||||
|
||||
let mut db_file_tmp = OpenOptions::new()
|
||||
.create_new(true)
|
||||
.write(true)
|
||||
.open(&db_path_tmp)
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"could not create temporary database: {}",
|
||||
db_path_tmp.display()
|
||||
)
|
||||
})?;
|
||||
|
||||
// File::set_len() can fail on some filesystems, so we ignore errors
|
||||
let _ = db_file_tmp.set_len(buffer_size);
|
||||
|
||||
(|| -> anyhow::Result<()> {
|
||||
db_file_tmp.write_all(&buffer).with_context(|| {
|
||||
format!(
|
||||
"could not write to temporary database: {}",
|
||||
db_path_tmp.display()
|
||||
)
|
||||
})?;
|
||||
|
||||
let db_path = Self::get_path(&self.data_dir);
|
||||
|
||||
fs::rename(&db_path_tmp, &db_path)
|
||||
.with_context(|| format!("could not create database: {}", db_path.display()))
|
||||
})()
|
||||
.map_err(|e| {
|
||||
fs::remove_file(&db_path_tmp)
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"could not remove temporary database: {}",
|
||||
db_path_tmp.display()
|
||||
)
|
||||
})
|
||||
.err()
|
||||
.unwrap_or(e)
|
||||
})?;
|
||||
|
||||
self.modified = true;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn matches<'a>(
|
||||
&'a mut self,
|
||||
now: Epoch,
|
||||
keywords: &[String],
|
||||
) -> impl Iterator<Item = &'a Dir> {
|
||||
self.dirs
|
||||
.sort_unstable_by_key(|dir| Reverse(FloatOrd(dir.get_score(now))));
|
||||
|
||||
let keywords: Vec<String> = keywords
|
||||
.iter()
|
||||
.map(|keyword| keyword.to_lowercase())
|
||||
.collect();
|
||||
|
||||
self.dirs
|
||||
.iter()
|
||||
.filter(move |dir| dir.is_match(&keywords) && dir.is_valid())
|
||||
}
|
||||
|
||||
fn get_path<P: AsRef<Path>>(data_dir: P) -> PathBuf {
|
||||
data_dir.as_ref().join("db.zo")
|
||||
}
|
||||
|
||||
fn get_path_tmp<P: AsRef<Path>>(data_dir: P) -> PathBuf {
|
||||
let file_name = format!("db-{}.zo.tmp", Uuid::new_v4());
|
||||
data_dir.as_ref().join(file_name)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Db {
|
||||
fn drop(&mut self) {
|
||||
if let Err(e) = self.save() {
|
||||
eprintln!("{:#}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type Rank = f64;
|
||||
pub type Epoch = i64; // use a signed integer so subtraction can be performed on it
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct Dir {
|
||||
pub path: String,
|
||||
pub rank: Rank,
|
||||
pub last_accessed: Epoch,
|
||||
}
|
||||
|
||||
impl Dir {
|
||||
pub fn is_valid(&self) -> bool {
|
||||
self.rank.is_finite() && self.rank >= 1.0 && Path::new(&self.path).is_dir()
|
||||
}
|
||||
|
||||
pub fn is_match(&self, query: &[String]) -> bool {
|
||||
let path_lower = self.path.to_lowercase();
|
||||
|
||||
let get_filenames = || {
|
||||
let query_name = Path::new(query.last()?).file_name()?.to_str()?;
|
||||
let dir_name = Path::new(&path_lower).file_name()?.to_str()?;
|
||||
Some((query_name, dir_name))
|
||||
};
|
||||
|
||||
if let Some((query_name, dir_name)) = get_filenames() {
|
||||
if !dir_name.contains(query_name) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
let mut subpath = path_lower.as_str();
|
||||
|
||||
for subquery in query.iter() {
|
||||
match subpath.find(subquery) {
|
||||
Some(idx) => subpath = &subpath[idx + subquery.len()..],
|
||||
None => return false,
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
pub fn get_score(&self, now: Epoch) -> Rank {
|
||||
const HOUR: Epoch = 60 * 60;
|
||||
const DAY: Epoch = 24 * HOUR;
|
||||
const WEEK: Epoch = 7 * DAY;
|
||||
|
||||
let duration = now - self.last_accessed;
|
||||
if duration < HOUR {
|
||||
self.rank * 4.0
|
||||
} else if duration < DAY {
|
||||
self.rank * 2.0
|
||||
} else if duration < WEEK {
|
||||
self.rank * 0.5
|
||||
} else {
|
||||
self.rank * 0.25
|
||||
}
|
||||
}
|
||||
|
||||
pub fn display(&self) -> DirDisplay {
|
||||
DirDisplay { dir: self }
|
||||
}
|
||||
|
||||
pub fn display_score(&self, now: Epoch) -> DirScoreDisplay {
|
||||
DirScoreDisplay { dir: self, now }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DirDisplay<'a> {
|
||||
dir: &'a Dir,
|
||||
}
|
||||
|
||||
impl Display for DirDisplay<'_> {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.dir.path)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DirScoreDisplay<'a> {
|
||||
dir: &'a Dir,
|
||||
now: Epoch,
|
||||
}
|
||||
|
||||
impl Display for DirScoreDisplay<'_> {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
const SCORE_MIN: Rank = 0.0;
|
||||
const SCORE_MAX: Rank = 9999.0;
|
||||
|
||||
let score = self.dir.get_score(self.now);
|
||||
|
||||
let score_clamped = if score > SCORE_MAX {
|
||||
SCORE_MAX
|
||||
} else if score > SCORE_MIN {
|
||||
score
|
||||
} else {
|
||||
SCORE_MIN
|
||||
};
|
||||
|
||||
write!(f, "{:>4.0} {}", score_clamped, self.dir.path)
|
||||
}
|
||||
}
|
12
src/error.rs
12
src/error.rs
@ -1,12 +0,0 @@
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SilentExit {
|
||||
pub code: i32,
|
||||
}
|
||||
|
||||
impl Display for SilentExit {
|
||||
fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
|
||||
Ok(())
|
||||
}
|
||||
}
|
62
src/fzf.rs
62
src/fzf.rs
@ -1,62 +0,0 @@
|
||||
use crate::config::zo_fzf_opts;
|
||||
use crate::error::SilentExit;
|
||||
|
||||
use anyhow::{bail, Context, Result};
|
||||
|
||||
use std::io::Write;
|
||||
use std::process::{Child, Command, Stdio};
|
||||
|
||||
pub struct Fzf {
|
||||
child: Child,
|
||||
}
|
||||
|
||||
impl Fzf {
|
||||
pub fn new() -> Result<Self> {
|
||||
let mut command = Command::new("fzf");
|
||||
command
|
||||
.arg("-n2..")
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped());
|
||||
|
||||
if let Some(fzf_opts) = zo_fzf_opts() {
|
||||
command.env("FZF_DEFAULT_OPTS", fzf_opts);
|
||||
}
|
||||
|
||||
let child = command.spawn().context("could not launch fzf")?;
|
||||
|
||||
Ok(Fzf { child })
|
||||
}
|
||||
|
||||
pub fn write(&mut self, line: String) -> Result<()> {
|
||||
// unwrap() is safe here since we have captured `stdin`
|
||||
let stdin = self.child.stdin.as_mut().unwrap();
|
||||
writeln!(stdin, "{}", line).context("could not write into fzf stdin")
|
||||
}
|
||||
|
||||
pub fn wait_select(self) -> Result<Option<String>> {
|
||||
let output = self
|
||||
.child
|
||||
.wait_with_output()
|
||||
.context("wait failed on fzf")?;
|
||||
|
||||
match output.status.code() {
|
||||
// normal exit
|
||||
Some(0) => String::from_utf8(output.stdout)
|
||||
.context("invalid utf-8 sequence in fzf output")
|
||||
.map(Some),
|
||||
|
||||
// no match
|
||||
Some(1) => Ok(None),
|
||||
|
||||
// error
|
||||
Some(2) => bail!("fzf returned an error"),
|
||||
|
||||
// terminated by a signal
|
||||
Some(code @ 130) => bail!(SilentExit { code }),
|
||||
Some(128..=254) | None => bail!("fzf was terminated"),
|
||||
|
||||
// unknown
|
||||
_ => bail!("fzf returned an unknown error"),
|
||||
}
|
||||
}
|
||||
}
|
2
src/lib.rs
Normal file
2
src/lib.rs
Normal file
@ -0,0 +1,2 @@
|
||||
pub mod config;
|
||||
pub mod util;
|
252
src/main.rs
252
src/main.rs
@ -1,42 +1,232 @@
|
||||
#![forbid(unsafe_code)]
|
||||
use anyhow::{Context, Result};
|
||||
use clap::{AppSettings, ArgEnum, Clap};
|
||||
use once_cell::sync::OnceCell;
|
||||
use zoxide::{config, util};
|
||||
use zoxide_engine::{Dir, Query, Store};
|
||||
use zoxide_shell::{self as zs, Generator};
|
||||
|
||||
mod config;
|
||||
mod db;
|
||||
mod error;
|
||||
mod fzf;
|
||||
mod subcommand;
|
||||
mod util;
|
||||
use std::io::{self, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use crate::error::SilentExit;
|
||||
fn env_help() -> &'static str {
|
||||
static ENV_HELP: OnceCell<String> = OnceCell::new();
|
||||
ENV_HELP.get_or_init(|| {
|
||||
const PATH_SPLIT_SEPARATOR: u8 = if cfg!(any(target_os = "redox", target_os = "windows")) {
|
||||
b';'
|
||||
} else {
|
||||
b':'
|
||||
};
|
||||
|
||||
use anyhow::Result;
|
||||
use structopt::StructOpt;
|
||||
format!(
|
||||
"\
|
||||
ENVIRONMENT VARIABLES:
|
||||
_ZO_DATA_DIR Path for zoxide data files (current: `{data_dir}`)
|
||||
_ZO_ECHO Prints the matched directory before navigating to it when set to 1
|
||||
_ZO_EXCLUDE_DIRS List of directories to be excluded, separated by `{split_paths_separator}`
|
||||
_ZO_FZF_OPTS Custom flags to pass to fzf
|
||||
_ZO_MAXAGE Maximum total age after which entries start getting deleted
|
||||
_ZO_RESOLVE_SYMLINKS Resolve symlinks when storing paths",
|
||||
data_dir=config::zo_data_dir().unwrap_or_else(|_| "none".into()).display(),
|
||||
split_paths_separator=PATH_SPLIT_SEPARATOR as char)
|
||||
})
|
||||
}
|
||||
|
||||
use std::process;
|
||||
// TODO: import
|
||||
// TODO: query interactive
|
||||
#[derive(Debug, Clap)]
|
||||
#[clap(
|
||||
about,
|
||||
author,
|
||||
global_setting(AppSettings::ColoredHelp),
|
||||
global_setting(AppSettings::GlobalVersion),
|
||||
global_setting(AppSettings::VersionlessSubcommands),
|
||||
version = env!("ZOXIDE_VERSION"))]
|
||||
enum Opts {
|
||||
/// Adds a new directory or increments its rank
|
||||
Add { path: Option<PathBuf> },
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
#[structopt(about, version = env!("ZOXIDE_VERSION"))]
|
||||
enum Zoxide {
|
||||
Add(subcommand::Add),
|
||||
Import(subcommand::Import),
|
||||
Init(subcommand::Init),
|
||||
Query(subcommand::Query),
|
||||
Remove(subcommand::Remove),
|
||||
/// Generates shell configuration
|
||||
#[clap(after_help(env_help()))]
|
||||
Init {
|
||||
#[clap(arg_enum)]
|
||||
shell: Shell,
|
||||
|
||||
/// Prevents zoxide from defining any commands
|
||||
#[clap(long)]
|
||||
no_aliases: bool,
|
||||
|
||||
/// Renames the 'z' command and corresponding aliases
|
||||
#[clap(long, default_value = "z")]
|
||||
cmd: String,
|
||||
|
||||
/// Chooses event upon which an entry is added to the database
|
||||
#[clap(arg_enum, long, default_value = "pwd")]
|
||||
hook: Hook,
|
||||
},
|
||||
|
||||
/// Searches for a directory
|
||||
Query {
|
||||
keywords: Vec<String>,
|
||||
|
||||
/// Lists all matching directories
|
||||
#[clap(long, short)]
|
||||
list: bool,
|
||||
|
||||
/// Prints score with results
|
||||
#[clap(long, short)]
|
||||
score: bool,
|
||||
},
|
||||
|
||||
/// Removes a directory
|
||||
Remove { path: String },
|
||||
}
|
||||
|
||||
#[derive(ArgEnum, Debug)]
|
||||
enum Shell {
|
||||
Bash,
|
||||
Fish,
|
||||
Posix,
|
||||
Powershell,
|
||||
Xonsh,
|
||||
Zsh,
|
||||
}
|
||||
|
||||
#[derive(ArgEnum, Debug)]
|
||||
enum Hook {
|
||||
None,
|
||||
Prompt,
|
||||
Pwd,
|
||||
}
|
||||
|
||||
pub fn main() -> Result<()> {
|
||||
let opt = Zoxide::from_args();
|
||||
let opts = Opts::parse();
|
||||
|
||||
let res = match opt {
|
||||
Zoxide::Add(add) => add.run(),
|
||||
Zoxide::Import(import) => import.run(),
|
||||
Zoxide::Init(init) => init.run(),
|
||||
Zoxide::Query(query) => query.run(),
|
||||
Zoxide::Remove(remove) => remove.run(),
|
||||
};
|
||||
match opts {
|
||||
Opts::Add { path } => {
|
||||
let path = match path {
|
||||
Some(path) => {
|
||||
if config::zo_resolve_symlinks() {
|
||||
util::canonicalize(&path)
|
||||
} else {
|
||||
util::resolve_path(&path)
|
||||
}
|
||||
}
|
||||
None => util::current_dir(),
|
||||
}?;
|
||||
|
||||
res.map_err(|e| match e.downcast::<SilentExit>() {
|
||||
Ok(SilentExit { code }) => process::exit(code),
|
||||
Err(e) => e,
|
||||
})
|
||||
if config::zo_exclude_dirs()?
|
||||
.iter()
|
||||
.any(|pattern| pattern.matches_path(&path))
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let path = util::path_to_str(&path)?;
|
||||
let now = util::current_time()?;
|
||||
|
||||
let data_dir = config::zo_data_dir()?;
|
||||
let max_age = config::zo_maxage()?;
|
||||
|
||||
let mut store = Store::open(&data_dir)?;
|
||||
store.add(path, now);
|
||||
store.age(max_age);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Opts::Init {
|
||||
shell,
|
||||
no_aliases,
|
||||
cmd,
|
||||
hook,
|
||||
} => {
|
||||
let cmd = if no_aliases { None } else { Some(cmd.as_str()) };
|
||||
|
||||
let hook = match hook {
|
||||
Hook::None => zs::Hook::None,
|
||||
Hook::Prompt => zs::Hook::Prompt,
|
||||
Hook::Pwd => zs::Hook::Pwd,
|
||||
};
|
||||
|
||||
let echo = config::zo_echo();
|
||||
let resolve_symlinks = config::zo_resolve_symlinks();
|
||||
|
||||
let opts = &zs::Opts {
|
||||
cmd,
|
||||
hook,
|
||||
echo,
|
||||
resolve_symlinks,
|
||||
};
|
||||
|
||||
let stdout = io::stdout();
|
||||
let handle = &mut stdout.lock();
|
||||
|
||||
match shell {
|
||||
Shell::Bash => zs::Bash(opts).generate(handle),
|
||||
Shell::Fish => zs::Bash(opts).generate(handle),
|
||||
Shell::Posix => zs::Bash(opts).generate(handle),
|
||||
Shell::Powershell => zs::Bash(opts).generate(handle),
|
||||
Shell::Xonsh => zs::Xonsh(opts).generate(handle),
|
||||
Shell::Zsh => zs::Zsh(opts).generate(handle),
|
||||
}?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Opts::Query {
|
||||
keywords,
|
||||
list,
|
||||
score,
|
||||
} => {
|
||||
let data_dir = config::zo_data_dir()?;
|
||||
let mut store = Store::open(&data_dir)?;
|
||||
|
||||
let query = Query::new(&keywords);
|
||||
let now = util::current_time()?;
|
||||
|
||||
let stdout = io::stdout();
|
||||
let mut handle = stdout.lock();
|
||||
|
||||
let mut print_dir = |dir: &Dir| {
|
||||
if score {
|
||||
let dir_score = dir.get_score(now);
|
||||
let dir_score_clamped = if dir_score > 9999.0 {
|
||||
9999
|
||||
} else if dir_score > 0.0 {
|
||||
dir_score as _
|
||||
} else {
|
||||
0
|
||||
};
|
||||
writeln!(&mut handle, "{:>4} {}", dir_score_clamped, dir.path)
|
||||
} else {
|
||||
writeln!(&mut handle, "{}", dir.path)
|
||||
}
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
let mut matches = store
|
||||
.iter_matches(&query, now)
|
||||
.filter(|dir| Path::new(&dir.path).is_dir());
|
||||
|
||||
if list {
|
||||
for dir in matches {
|
||||
print_dir(dir);
|
||||
}
|
||||
} else {
|
||||
let dir = matches.next().context("no match found")?;
|
||||
print_dir(dir);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Opts::Remove { path } => {
|
||||
let data_dir = config::zo_data_dir()?;
|
||||
|
||||
let mut store = Store::open(&data_dir)?;
|
||||
store.remove(path);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,86 +0,0 @@
|
||||
use crate::config;
|
||||
use crate::db::{Db, Dir, Rank};
|
||||
use crate::util;
|
||||
|
||||
use anyhow::Result;
|
||||
use structopt::StructOpt;
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
/// Add a new directory or increment its rank
|
||||
#[derive(Debug, StructOpt)]
|
||||
#[structopt()]
|
||||
pub struct Add {
|
||||
path: Option<PathBuf>,
|
||||
}
|
||||
|
||||
impl Add {
|
||||
pub fn run(&self) -> Result<()> {
|
||||
let current_dir;
|
||||
let path = match &self.path {
|
||||
Some(path) => path,
|
||||
None => {
|
||||
current_dir = util::get_current_dir()?;
|
||||
¤t_dir
|
||||
}
|
||||
};
|
||||
|
||||
add(&path)
|
||||
}
|
||||
}
|
||||
|
||||
fn add<P: AsRef<Path>>(path: P) -> Result<()> {
|
||||
let path = path.as_ref();
|
||||
let path = if config::zo_resolve_symlinks() {
|
||||
util::canonicalize(&path)?
|
||||
} else {
|
||||
util::resolve_path(&path)?
|
||||
};
|
||||
|
||||
if config::zo_exclude_dirs()?
|
||||
.iter()
|
||||
.any(|pattern| pattern.matches_path(&path))
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut db = util::get_db()?;
|
||||
let now = util::get_current_time()?;
|
||||
let path = util::path_to_str(&path)?;
|
||||
let maxage = config::zo_maxage()?;
|
||||
|
||||
match db.dirs.iter_mut().find(|dir| dir.path == path) {
|
||||
None => db.dirs.push(Dir {
|
||||
path: path.to_string(),
|
||||
last_accessed: now,
|
||||
rank: 1.0,
|
||||
}),
|
||||
Some(dir) => {
|
||||
dir.last_accessed = now;
|
||||
dir.rank += 1.0;
|
||||
}
|
||||
};
|
||||
|
||||
age(&mut db, maxage);
|
||||
db.modified = true;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn age(db: &mut Db, maxage: Rank) {
|
||||
let sum_age = db.dirs.iter().map(|dir| dir.rank).sum::<Rank>();
|
||||
|
||||
if sum_age > maxage {
|
||||
let factor = 0.9 * maxage / sum_age;
|
||||
for dir in &mut db.dirs {
|
||||
dir.rank *= factor;
|
||||
}
|
||||
|
||||
for idx in (0..db.dirs.len()).rev() {
|
||||
let dir = &db.dirs[idx];
|
||||
if dir.rank < 1.0 {
|
||||
db.dirs.swap_remove(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
use crate::config;
|
||||
use crate::db::{Db, Dir};
|
||||
use crate::util;
|
||||
|
||||
use anyhow::{bail, Context, Result};
|
||||
use structopt::StructOpt;
|
||||
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
/// Import from z database
|
||||
#[derive(Debug, StructOpt)]
|
||||
#[structopt()]
|
||||
pub struct Import {
|
||||
path: PathBuf,
|
||||
|
||||
/// Merge entries into existing database
|
||||
#[structopt(long)]
|
||||
merge: bool,
|
||||
}
|
||||
|
||||
impl Import {
|
||||
pub fn run(&self) -> Result<()> {
|
||||
import(&self.path, self.merge)
|
||||
}
|
||||
}
|
||||
|
||||
fn import<P: AsRef<Path>>(path: P, merge: bool) -> Result<()> {
|
||||
let path = path.as_ref();
|
||||
let mut db = util::get_db()?;
|
||||
|
||||
if !db.dirs.is_empty() && !merge {
|
||||
bail!(
|
||||
"To prevent conflicts, you can only import from z with an empty zoxide database!\n\
|
||||
If you wish to merge the two, specify the `--merge` flag."
|
||||
);
|
||||
}
|
||||
|
||||
let buffer = fs::read_to_string(&path)
|
||||
.with_context(|| format!("could not read z database: {}", path.display()))?;
|
||||
|
||||
for (idx, line) in buffer.lines().enumerate() {
|
||||
if let Err(e) = import_line(&mut db, line, config::zo_resolve_symlinks()) {
|
||||
let line_num = idx + 1;
|
||||
eprintln!("Error on line {}: {}", line_num, e);
|
||||
}
|
||||
}
|
||||
|
||||
db.modified = true;
|
||||
println!("Completed import.");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn import_line(db: &mut Db, line: &str, resolve_symlinks: bool) -> Result<()> {
|
||||
let mut split_line = line.rsplitn(3, '|');
|
||||
|
||||
let (path, epoch_str, rank_str) = (|| {
|
||||
let epoch_str = split_line.next()?;
|
||||
let rank_str = split_line.next()?;
|
||||
let path = split_line.next()?;
|
||||
Some((path, epoch_str, rank_str))
|
||||
})()
|
||||
.with_context(|| format!("invalid entry: {}", line))?;
|
||||
|
||||
let epoch = epoch_str
|
||||
.parse::<i64>()
|
||||
.with_context(|| format!("invalid epoch: {}", epoch_str))?;
|
||||
|
||||
let rank = rank_str
|
||||
.parse::<f64>()
|
||||
.with_context(|| format!("invalid rank: {}", rank_str))?;
|
||||
|
||||
let path = if resolve_symlinks {
|
||||
util::canonicalize(&path)?
|
||||
} else {
|
||||
util::resolve_path(&path)?
|
||||
};
|
||||
let path = util::path_to_str(&path)?;
|
||||
|
||||
// If the path exists in the database, add the ranks and set the epoch to
|
||||
// the more recent of the parsed epoch and the already present epoch.
|
||||
if let Some(dir) = db.dirs.iter_mut().find(|dir| dir.path == path) {
|
||||
dir.rank += rank;
|
||||
dir.last_accessed = epoch.max(dir.last_accessed);
|
||||
} else {
|
||||
db.dirs.push(Dir {
|
||||
path: path.to_string(),
|
||||
rank,
|
||||
last_accessed: epoch,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
@ -1,182 +0,0 @@
|
||||
use anyhow::Result;
|
||||
|
||||
use std::io::Write;
|
||||
|
||||
use super::{Hook, Init};
|
||||
use crate::config;
|
||||
|
||||
pub fn run<W: Write>(writer: &mut W, options: &Init) -> Result<()> {
|
||||
const NOT_CONFIGURED: &str = "\
|
||||
# -- not configured --";
|
||||
|
||||
let __zoxide_pwd = if config::zo_resolve_symlinks() {
|
||||
"\
|
||||
__zoxide_pwd() {
|
||||
pwd -P
|
||||
}"
|
||||
} else {
|
||||
"\
|
||||
__zoxide_pwd() {
|
||||
pwd -L
|
||||
}"
|
||||
};
|
||||
|
||||
let __zoxide_cd = if config::zo_echo() {
|
||||
"\
|
||||
__zoxide_cd() {
|
||||
cd \"$@\" || return \"$?\"
|
||||
__zoxide_pwd
|
||||
}"
|
||||
} else {
|
||||
"\
|
||||
__zoxide_cd() {
|
||||
cd \"$@\" || return \"$?\"
|
||||
}"
|
||||
};
|
||||
|
||||
let __zoxide_hook = match options.hook {
|
||||
Hook::none => NOT_CONFIGURED,
|
||||
Hook::prompt => {
|
||||
"\
|
||||
__zoxide_hook() {
|
||||
zoxide add \"$(__zoxide_pwd)\"
|
||||
}"
|
||||
}
|
||||
Hook::pwd => {
|
||||
"\
|
||||
__zoxide_hook() {
|
||||
local -r __zoxide_pwd_tmp=\"$(__zoxide_pwd)\"
|
||||
if [ -z \"$__zoxide_pwd_old\" ]; then
|
||||
__zoxide_pwd_old=\"$__zoxide_pwd_tmp\"
|
||||
elif [ \"$__zoxide_pwd_old\" != \"$__zoxide_pwd_tmp\" ]; then
|
||||
__zoxide_pwd_old=\"$__zoxide_pwd_tmp\"
|
||||
zoxide add \"$__zoxide_pwd_old\"
|
||||
fi
|
||||
}"
|
||||
}
|
||||
};
|
||||
|
||||
let hook_init = match options.hook {
|
||||
Hook::none => NOT_CONFIGURED,
|
||||
_ => {
|
||||
"\
|
||||
case \"$PROMPT_COMMAND\" in
|
||||
*__zoxide_hook*) ;;
|
||||
*) PROMPT_COMMAND=\"${PROMPT_COMMAND:+${PROMPT_COMMAND};}__zoxide_hook\" ;;
|
||||
esac"
|
||||
}
|
||||
};
|
||||
|
||||
let aliases = if options.no_aliases {
|
||||
NOT_CONFIGURED.into()
|
||||
} else {
|
||||
format!(
|
||||
"\
|
||||
alias {}='__zoxide_z'
|
||||
alias {cmd}i='__zoxide_zi'
|
||||
alias {cmd}a='__zoxide_za'
|
||||
|
||||
alias {cmd}q='__zoxide_zq'
|
||||
alias {cmd}qi='__zoxide_zqi'
|
||||
|
||||
alias {cmd}r='__zoxide_zr'
|
||||
alias {cmd}ri='__zoxide_zri'",
|
||||
cmd = options.cmd
|
||||
)
|
||||
};
|
||||
|
||||
write!(
|
||||
writer,
|
||||
"\
|
||||
# =============================================================================
|
||||
#
|
||||
# Utility functions for zoxide.
|
||||
#
|
||||
|
||||
# pwd based on the value of _ZO_RESOLVE_SYMLINKS.
|
||||
{__zoxide_pwd}
|
||||
|
||||
# cd + custom logic based on the value of _ZO_ECHO.
|
||||
{__zoxide_cd}
|
||||
|
||||
# =============================================================================
|
||||
#
|
||||
# Hook configuration for zoxide.
|
||||
#
|
||||
|
||||
# Hook to add new entries to the database.
|
||||
{__zoxide_hook}
|
||||
|
||||
# Initialize hook.
|
||||
{hook_init}
|
||||
|
||||
# =============================================================================
|
||||
#
|
||||
# When using zoxide with --no-aliases, alias these internal functions as
|
||||
# desired.
|
||||
#
|
||||
|
||||
# Jump to a directory using only keywords.
|
||||
__zoxide_z() {{
|
||||
if [ \"$#\" -eq 0 ]; then
|
||||
__zoxide_cd ~
|
||||
elif [ \"$#\" -eq 1 ] && [ \"$1\" = '-' ]; then
|
||||
if [ -n \"$OLDPWD\" ]; then
|
||||
__zoxide_cd \"$OLDPWD\"
|
||||
else
|
||||
echo \"zoxide: \\$OLDPWD is not set\"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
local __zoxide_result
|
||||
__zoxide_result=\"$(zoxide query -- \"$@\")\" && __zoxide_cd \"$__zoxide_result\"
|
||||
fi
|
||||
}}
|
||||
|
||||
# Jump to a directory using interactive search.
|
||||
__zoxide_zi() {{
|
||||
local __zoxide_result
|
||||
__zoxide_result=\"$(zoxide query -i -- \"$@\")\" && __zoxide_cd \"$__zoxide_result\"
|
||||
}}
|
||||
|
||||
# Add a new entry to the database.
|
||||
alias __zoxide_za='zoxide add'
|
||||
|
||||
# Query an entry from the database using only keywords.
|
||||
alias __zoxide_zq='zoxide query'
|
||||
|
||||
# Query an entry from the database using interactive selection.
|
||||
alias __zoxide_zqi='zoxide query -i'
|
||||
|
||||
# Remove an entry from the database using the exact path.
|
||||
alias __zoxide_zr='zoxide remove'
|
||||
|
||||
# Remove an entry from the database using interactive selection.
|
||||
__zoxide_zri() {{
|
||||
local __zoxide_result
|
||||
__zoxide_result=\"$(zoxide query -i -- \"$@\")\" && zoxide remove \"$__zoxide_result\"
|
||||
}}
|
||||
|
||||
# =============================================================================
|
||||
#
|
||||
# Convenient aliases for zoxide. Disable these using --no-aliases.
|
||||
#
|
||||
|
||||
{aliases}
|
||||
|
||||
# =============================================================================
|
||||
#
|
||||
# To initialize zoxide with bash, add the following line to your bash
|
||||
# configuration file (usually ~/.bashrc):
|
||||
#
|
||||
# eval \"$(zoxide init bash)\"
|
||||
",
|
||||
__zoxide_pwd = __zoxide_pwd,
|
||||
__zoxide_cd = __zoxide_cd,
|
||||
__zoxide_hook = __zoxide_hook,
|
||||
hook_init = hook_init,
|
||||
aliases = aliases,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
@ -1,191 +0,0 @@
|
||||
use anyhow::Result;
|
||||
|
||||
use std::io::Write;
|
||||
|
||||
use super::{Hook, Init};
|
||||
use crate::config;
|
||||
|
||||
pub fn run<W: Write>(writer: &mut W, options: &Init) -> Result<()> {
|
||||
const NOT_CONFIGURED: &str = "\
|
||||
# -- not configured --";
|
||||
|
||||
let __zoxide_pwd = if config::zo_resolve_symlinks() {
|
||||
"\
|
||||
function __zoxide_pwd
|
||||
pwd -P
|
||||
end"
|
||||
} else {
|
||||
"\
|
||||
function __zoxide_pwd
|
||||
pwd -L
|
||||
end"
|
||||
};
|
||||
|
||||
let __zoxide_cd = if config::zo_echo() {
|
||||
"\
|
||||
function __zoxide_cd
|
||||
cd $argv
|
||||
or return $status
|
||||
|
||||
commandline -f repaint
|
||||
__zoxide_pwd
|
||||
end"
|
||||
} else {
|
||||
"\
|
||||
function __zoxide_cd
|
||||
cd $argv
|
||||
or return $status
|
||||
|
||||
commandline -f repaint
|
||||
end"
|
||||
};
|
||||
|
||||
let __zoxide_hook = "\
|
||||
function __zoxide_hook
|
||||
zoxide add (__zoxide_pwd)
|
||||
end";
|
||||
|
||||
let hook_init = match options.hook {
|
||||
Hook::none => NOT_CONFIGURED,
|
||||
Hook::prompt => {
|
||||
"\
|
||||
function __zoxide_hook_prompt --on-event fish_prompt
|
||||
__zoxide_hook
|
||||
end"
|
||||
}
|
||||
Hook::pwd => {
|
||||
"\
|
||||
function __zoxide_hook_pwd --on-variable PWD
|
||||
__zoxide_hook
|
||||
end"
|
||||
}
|
||||
};
|
||||
|
||||
let aliases = if options.no_aliases {
|
||||
NOT_CONFIGURED.into()
|
||||
} else {
|
||||
format!(
|
||||
"\
|
||||
function {cmd}
|
||||
__zoxide_z $argv
|
||||
end
|
||||
|
||||
function {cmd}i
|
||||
__zoxide_zi $argv
|
||||
end
|
||||
|
||||
function {cmd}a
|
||||
__zoxide_za $argv
|
||||
end
|
||||
|
||||
function {cmd}q
|
||||
__zoxide_zq $argv
|
||||
end
|
||||
|
||||
function {cmd}qi
|
||||
__zoxide_zqi $argv
|
||||
end
|
||||
|
||||
function {cmd}r
|
||||
__zoxide_zr $argv
|
||||
end
|
||||
|
||||
function {cmd}ri
|
||||
__zoxide_zri $argv
|
||||
end",
|
||||
cmd = options.cmd
|
||||
)
|
||||
};
|
||||
|
||||
writeln!(
|
||||
writer,
|
||||
"\
|
||||
# =============================================================================
|
||||
#
|
||||
# Utility functions for zoxide.
|
||||
#
|
||||
|
||||
# pwd based on the value of _ZO_RESOLVE_SYMLINKS.
|
||||
{__zoxide_pwd}
|
||||
|
||||
# cd + custom logic based on the value of _ZO_ECHO.
|
||||
{__zoxide_cd}
|
||||
|
||||
# =============================================================================
|
||||
#
|
||||
# Hook configuration for zoxide.
|
||||
#
|
||||
|
||||
# Hook to add new entries to the database.
|
||||
{__zoxide_hook}
|
||||
|
||||
# Initialize hook.
|
||||
{hook_init}
|
||||
|
||||
# =============================================================================
|
||||
#
|
||||
# When using zoxide with --no-aliases, alias these internal functions as
|
||||
# desired.
|
||||
#
|
||||
|
||||
# Jump to a directory using only keywords.
|
||||
function __zoxide_z
|
||||
set argc (count $argv)
|
||||
|
||||
if test $argc -eq 0
|
||||
__zoxide_cd $HOME
|
||||
else if begin; test $argc -eq 1; and test $argv[1] = '-'; end
|
||||
__zoxide_cd -
|
||||
else
|
||||
set -l __zoxide_result (zoxide query -- $argv)
|
||||
and __zoxide_cd $__zoxide_result
|
||||
end
|
||||
end
|
||||
|
||||
# Jump to a directory using interactive search.
|
||||
function __zoxide_zi
|
||||
set -l __zoxide_result (zoxide query -i -- $argv)
|
||||
and __zoxide_cd $__zoxide_result
|
||||
end
|
||||
|
||||
# Add a new entry to the database.
|
||||
abbr -a __zoxide_za 'zoxide add'
|
||||
|
||||
# Query an entry from the database using only keywords.
|
||||
abbr -a __zoxide_zq 'zoxide query'
|
||||
|
||||
# Query an entry from the database using interactive selection.
|
||||
abbr -a __zoxide_zqi 'zoxide query -i'
|
||||
|
||||
# Remove an entry from the database using the exact path.
|
||||
abbr -a __zoxide_zr 'zoxide remove'
|
||||
|
||||
# Remove an entry from the database using interactive selection.
|
||||
function __zoxide_zri
|
||||
set -l __zoxide_result (zoxide query -i -- $argv)
|
||||
and zoxide remove $__zoxide_result
|
||||
end
|
||||
|
||||
# =============================================================================
|
||||
#
|
||||
# Convenient aliases for zoxide. Disable these using --no-aliases.
|
||||
#
|
||||
|
||||
{aliases}
|
||||
|
||||
# =============================================================================
|
||||
#
|
||||
# To initialize zoxide with fish, add the following line to your fish
|
||||
# configuration file (usually ~/.config/fish/config.fish):
|
||||
#
|
||||
# zoxide init fish | source
|
||||
",
|
||||
__zoxide_pwd = __zoxide_pwd,
|
||||
__zoxide_cd = __zoxide_cd,
|
||||
__zoxide_hook = __zoxide_hook,
|
||||
hook_init = hook_init,
|
||||
aliases = aliases,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
mod bash;
|
||||
mod fish;
|
||||
mod posix;
|
||||
mod powershell;
|
||||
mod zsh;
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use clap::arg_enum;
|
||||
use structopt::StructOpt;
|
||||
|
||||
use std::io;
|
||||
|
||||
/// Generates shell configuration
|
||||
#[derive(Debug, StructOpt)]
|
||||
#[structopt()]
|
||||
pub struct Init {
|
||||
#[structopt(possible_values = &Shell::variants(), case_insensitive = true)]
|
||||
shell: Shell,
|
||||
|
||||
/// Renames the 'z' command and corresponding aliases
|
||||
#[structopt(long, alias = "z-cmd", default_value = "z")]
|
||||
cmd: String,
|
||||
|
||||
/// Prevents zoxide from defining any commands
|
||||
#[structopt(long, alias = "no-define-aliases")]
|
||||
no_aliases: bool,
|
||||
|
||||
/// Chooses event on which an entry is added to the database
|
||||
#[structopt(
|
||||
long,
|
||||
possible_values = &Hook::variants(),
|
||||
default_value = "pwd",
|
||||
case_insensitive = true
|
||||
)]
|
||||
hook: Hook,
|
||||
}
|
||||
|
||||
impl Init {
|
||||
pub fn run(&self) -> Result<()> {
|
||||
let stdout = io::stdout();
|
||||
let mut handle = stdout.lock();
|
||||
|
||||
match self.shell {
|
||||
Shell::bash => bash::run(&mut handle, self),
|
||||
Shell::fish => fish::run(&mut handle, self),
|
||||
Shell::posix => posix::run(&mut handle, self),
|
||||
Shell::powershell => powershell::run(&mut handle, self),
|
||||
Shell::zsh => zsh::run(&mut handle, self),
|
||||
}
|
||||
.context("could not initialize zoxide")
|
||||
}
|
||||
}
|
||||
|
||||
arg_enum! {
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Debug)]
|
||||
enum Shell {
|
||||
bash,
|
||||
fish,
|
||||
posix,
|
||||
powershell,
|
||||
zsh,
|
||||
}
|
||||
}
|
||||
|
||||
arg_enum! {
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Debug)]
|
||||
enum Hook {
|
||||
none,
|
||||
prompt,
|
||||
pwd,
|
||||
}
|
||||
}
|
@ -1,232 +0,0 @@
|
||||
use super::{Hook, Init};
|
||||
use crate::config;
|
||||
use crate::util;
|
||||
|
||||
use std::io::Write;
|
||||
|
||||
use anyhow::Result;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub fn run<W: Write>(writer: &mut W, options: &Init) -> Result<()> {
|
||||
const NOT_CONFIGURED: &str = "\
|
||||
# -- not configured --";
|
||||
|
||||
let __zoxide_pwd = if config::zo_resolve_symlinks() {
|
||||
"\
|
||||
__zoxide_pwd() {
|
||||
pwd -P
|
||||
}"
|
||||
} else {
|
||||
"\
|
||||
__zoxide_pwd() {
|
||||
pwd -L
|
||||
}"
|
||||
};
|
||||
|
||||
let __zoxide_cd = if config::zo_echo() {
|
||||
"\
|
||||
__zoxide_cd() {
|
||||
cd \"$@\" || return \"$?\"
|
||||
__zoxide_pwd
|
||||
}"
|
||||
} else {
|
||||
"\
|
||||
__zoxide_cd() {
|
||||
cd \"$@\" || return \"$?\"
|
||||
}"
|
||||
};
|
||||
|
||||
let __zoxide_hook = match options.hook {
|
||||
Hook::none => NOT_CONFIGURED.into(),
|
||||
Hook::prompt => "\
|
||||
__zoxide_hook() {
|
||||
zoxide add \"$(__zoxide_pwd)\"
|
||||
}"
|
||||
.into(),
|
||||
Hook::pwd => {
|
||||
let mut tmp_path = std::env::temp_dir();
|
||||
tmp_path.push("zoxide");
|
||||
let tmp_path_str = util::path_to_str(&tmp_path)?;
|
||||
|
||||
let pwd_path = tmp_path.join(format!("pwd-{}", Uuid::new_v4()));
|
||||
let pwd_path_str = util::path_to_str(&pwd_path)?;
|
||||
|
||||
format!(
|
||||
"\
|
||||
# PWD hooks in POSIX use a temporary file, located at `$__zoxide_pwd_path`, to track
|
||||
# changes in the current directory. These files are removed upon restart,
|
||||
# but they should ideally also be cleaned up once the shell exits using traps.
|
||||
#
|
||||
# This can be done as follows:
|
||||
#
|
||||
# trap '__zoxide_cleanup' EXIT HUP KILL TERM
|
||||
# trap '__zoxide_cleanup; trap - INT; kill -s INT \"$$\"' INT
|
||||
# trap '__zoxide_cleanup; trap - QUIT; kill -s QUIT \"$$\"' QUIT
|
||||
#
|
||||
# By default, traps are not set up because they override all previous traps.
|
||||
# It is therefore up to the user to add traps to their shell configuration.
|
||||
|
||||
__zoxide_tmp_path={tmp_path}
|
||||
__zoxide_pwd_path={pwd_path}
|
||||
|
||||
__zoxide_cleanup() {{
|
||||
rm -f \"$__zoxide_pwd_path\"
|
||||
}}
|
||||
|
||||
__zoxide_setpwd() {{
|
||||
mkdir -p \"$__zoxide_tmp_path\"
|
||||
echo \"$PWD\" > \"$__zoxide_pwd_path\"
|
||||
}}
|
||||
|
||||
__zoxide_setpwd
|
||||
|
||||
__zoxide_hook() {{
|
||||
_ZO_OLDPWD=\"$(cat \"$__zoxide_pwd_path\")\"
|
||||
if [ -z \"$_ZO_OLDPWD\" ] || [ \"$_ZO_OLDPWD\" != \"$PWD\" ]; then
|
||||
__zoxide_setpwd && zoxide add \"$(pwd -L)\" > /dev/null
|
||||
fi
|
||||
}}",
|
||||
tmp_path = posix_quote(tmp_path_str),
|
||||
pwd_path = posix_quote(pwd_path_str),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let hook_init = match options.hook {
|
||||
Hook::none => NOT_CONFIGURED,
|
||||
_ => {
|
||||
"\
|
||||
case \"$PS1\" in
|
||||
*\\$\\(__zoxide_hook\\)*) ;;
|
||||
*) PS1=\"${PS1}\\$(__zoxide_hook)\" ;;
|
||||
esac"
|
||||
}
|
||||
};
|
||||
|
||||
let aliases = if options.no_aliases {
|
||||
NOT_CONFIGURED.into()
|
||||
} else {
|
||||
format!(
|
||||
"\
|
||||
alias {cmd}='__zoxide_z'
|
||||
alias {cmd}i='__zoxide_zi'
|
||||
|
||||
alias {cmd}a='__zoxide_za'
|
||||
|
||||
alias {cmd}q='__zoxide_zq'
|
||||
alias {cmd}qi='__zoxide_zqi'
|
||||
|
||||
alias {cmd}r='__zoxide_zr'
|
||||
alias {cmd}ri='__zoxide_zri'",
|
||||
cmd = options.cmd
|
||||
)
|
||||
};
|
||||
|
||||
writeln!(
|
||||
writer,
|
||||
"\
|
||||
# =============================================================================
|
||||
#
|
||||
# Utility functions for zoxide.
|
||||
#
|
||||
|
||||
# pwd based on the value of _ZO_RESOLVE_SYMLINKS.
|
||||
{__zoxide_pwd}
|
||||
|
||||
# cd + custom logic based on the value of _ZO_ECHO.
|
||||
{__zoxide_cd}
|
||||
|
||||
# =============================================================================
|
||||
#
|
||||
# Hook configuration for zoxide.
|
||||
#
|
||||
|
||||
# Hook to add new entries to the database.
|
||||
{__zoxide_hook}
|
||||
|
||||
# Initialize hook.
|
||||
{hook_init}
|
||||
|
||||
# =============================================================================
|
||||
#
|
||||
# When using zoxide with --no-aliases, alias these internal functions as
|
||||
# desired.
|
||||
#
|
||||
|
||||
# Jump to a directory using only keywords.
|
||||
__zoxide_z() {{
|
||||
if [ \"$#\" -eq 0 ]; then
|
||||
__zoxide_cd ~
|
||||
elif [ \"$#\" -eq 1 ] && [ \"$1\" = '-' ]; then
|
||||
if [ -n \"$OLDPWD\" ]; then
|
||||
__zoxide_cd \"$OLDPWD\"
|
||||
else
|
||||
echo \"zoxide: \\$OLDPWD is not set\"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
__zoxide_result=\"$(zoxide query -- \"$@\")\" && __zoxide_cd \"$__zoxide_result\"
|
||||
fi
|
||||
}}
|
||||
|
||||
# Jump to a directory using interactive search.
|
||||
__zoxide_zi() {{
|
||||
__zoxide_result=\"$(zoxide query -i -- \"$@\")\" && __zoxide_cd \"$__zoxide_result\"
|
||||
}}
|
||||
|
||||
# Add a new entry to the database.
|
||||
alias __zoxide_za='zoxide add'
|
||||
|
||||
# Query an entry from the database using only keywords.
|
||||
alias __zoxide_zq='zoxide query'
|
||||
|
||||
# Query an entry from the database using interactive selection.
|
||||
alias __zoxide_zqi='zoxide query -i'
|
||||
|
||||
# Remove an entry from the database using the exact path.
|
||||
alias __zoxide_zr='zoxide remove'
|
||||
|
||||
# Remove an entry from the database using interactive selection.
|
||||
__zoxide_zri() {{
|
||||
__zoxide_result=\"$(zoxide query -i -- \"$@\")\" && zoxide remove \"$__zoxide_result\"
|
||||
}}
|
||||
|
||||
# =============================================================================
|
||||
#
|
||||
# Convenient aliases for zoxide. Disable these using --no-aliases.
|
||||
#
|
||||
|
||||
{aliases}
|
||||
|
||||
# =============================================================================
|
||||
#
|
||||
# To initialize zoxide with your POSIX shell, add the following line to your
|
||||
# shell configuration file:
|
||||
#
|
||||
# eval \"$(zoxide init posix --prompt hook)\"
|
||||
",
|
||||
__zoxide_pwd = __zoxide_pwd,
|
||||
__zoxide_cd = __zoxide_cd,
|
||||
__zoxide_hook = __zoxide_hook,
|
||||
hook_init = hook_init,
|
||||
aliases = aliases,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn posix_quote(string: &str) -> String {
|
||||
let mut quoted = String::with_capacity(string.len() + 2);
|
||||
|
||||
quoted.push('\'');
|
||||
for ch in string.chars() {
|
||||
match ch {
|
||||
'\\' => quoted.push_str(r"\\"),
|
||||
'\'' => quoted.push_str(r"'\''"),
|
||||
_ => quoted.push(ch),
|
||||
}
|
||||
}
|
||||
quoted.push('\'');
|
||||
|
||||
quoted
|
||||
}
|
@ -1,180 +0,0 @@
|
||||
use anyhow::Result;
|
||||
|
||||
use std::io::Write;
|
||||
|
||||
use super::{Hook, Init};
|
||||
use crate::config;
|
||||
|
||||
pub fn run<W: Write>(writer: &mut W, options: &Init) -> Result<()> {
|
||||
const NOT_CONFIGURED: &str = "\
|
||||
# -- not configured --";
|
||||
|
||||
let __zoxide_pwd = "\
|
||||
function __zoxide_pwd {
|
||||
$(Get-Location).Path
|
||||
}";
|
||||
|
||||
let __zoxide_cd = if config::zo_echo() {
|
||||
"\
|
||||
function __zoxide_cd($dir) {
|
||||
Set-Location $dir -ea Stop
|
||||
__zoxide_pwd
|
||||
}"
|
||||
} else {
|
||||
"\
|
||||
function __zoxide_cd($dir) {
|
||||
Set-Location $dir -ea Stop
|
||||
}"
|
||||
};
|
||||
|
||||
let __zoxide_hook = "\
|
||||
function __zoxide_hook {
|
||||
zoxide add $(__zoxide_pwd)
|
||||
}";
|
||||
|
||||
let hook_init = match options.hook {
|
||||
Hook::none => NOT_CONFIGURED,
|
||||
Hook::prompt => {
|
||||
"\
|
||||
$PreZoxidePrompt = $function:prompt
|
||||
function prompt {
|
||||
$null = __zoxide_hook
|
||||
& $PreZoxidePrompt
|
||||
}"
|
||||
}
|
||||
Hook::pwd => {
|
||||
"\
|
||||
if ($PSVersionTable.PSVersion.Major -ge 6) {
|
||||
$ExecutionContext.InvokeCommand.LocationChangedAction = {
|
||||
$null = __zoxide_hook
|
||||
}
|
||||
} else {
|
||||
Write-Error \"zoxide: PWD hooks are not supported below PowerShell 6, use 'zoxide init powershell --hook prompt' instead.\"
|
||||
}"
|
||||
}
|
||||
};
|
||||
|
||||
let aliases = if options.no_aliases {
|
||||
NOT_CONFIGURED.into()
|
||||
} else {
|
||||
format!(
|
||||
"\
|
||||
Set-Alias {cmd} __zoxide_z
|
||||
Set-Alias {cmd}i __zoxide_zi
|
||||
|
||||
Set-Alias {cmd}a __zoxide_za
|
||||
|
||||
Set-Alias {cmd}q __zoxide_zq
|
||||
Set-Alias {cmd}qi __zoxide_zqi
|
||||
|
||||
Set-Alias {cmd}r __zoxide_zr
|
||||
Set-Alias {cmd}ri __zoxide_zri",
|
||||
cmd = options.cmd
|
||||
)
|
||||
};
|
||||
|
||||
writeln!(
|
||||
writer,
|
||||
"\
|
||||
# =============================================================================
|
||||
#
|
||||
# Utility functions for zoxide.
|
||||
#
|
||||
|
||||
# pwd based on the value of _ZO_RESOLVE_SYMLINKS.
|
||||
{__zoxide_pwd}
|
||||
|
||||
# cd + custom logic based on the value of _ZO_ECHO.
|
||||
{__zoxide_cd}
|
||||
|
||||
# =============================================================================
|
||||
#
|
||||
# Hook configuration for zoxide.
|
||||
#
|
||||
|
||||
# Hook to add new entries to the database.
|
||||
{__zoxide_hook}
|
||||
|
||||
# Initialize hook.
|
||||
{hook_init}
|
||||
|
||||
# =============================================================================
|
||||
#
|
||||
# When using zoxide with --no-aliases, alias these internal functions as
|
||||
# desired.
|
||||
#
|
||||
|
||||
# Jump to a directory using only keywords.
|
||||
function __zoxide_z {{
|
||||
if ($args.Length -eq 0) {{
|
||||
__zoxide_cd ~
|
||||
}}
|
||||
elseif ($args.Length -eq 1 -and $args[0] -eq '-') {{
|
||||
__zoxide_cd -
|
||||
}}
|
||||
else {{
|
||||
$__zoxide_result = zoxide query -- @args
|
||||
if ($LASTEXITCODE -eq 0) {{
|
||||
__zoxide_cd $__zoxide_result
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
|
||||
# Jump to a directory using interactive search.
|
||||
function zi {{
|
||||
$__zoxide_result = zoxide query -i -- @args
|
||||
if ($LASTEXITCODE -eq 0) {{
|
||||
__zoxide_cd $__zoxide_result
|
||||
}}
|
||||
}}
|
||||
|
||||
# Add a new entry to the database.
|
||||
function __zoxide_za {{ zoxide add @args }}
|
||||
|
||||
# Query an entry from the database using only keywords.
|
||||
function __zoxide_zq {{ zoxide query @args }}
|
||||
|
||||
# Query an entry from the database using interactive selection.
|
||||
function __zoxide_zqi {{ zoxide query -i @args }}
|
||||
|
||||
# Remove an entry from the database using the exact path.
|
||||
function __zoxide_zr {{ zoxide remove @args }}
|
||||
|
||||
# Remove an entry from the database using interactive selection.
|
||||
function __zoxide_zri {{
|
||||
$_zoxide_result = zoxide query -i -- @args
|
||||
if ($LASTEXITCODE -eq 0) {{
|
||||
zoxide remove $_zoxide_result
|
||||
}}
|
||||
}}
|
||||
|
||||
# =============================================================================
|
||||
#
|
||||
# Convenient aliases for zoxide. Disable these using --no-aliases.
|
||||
#
|
||||
|
||||
{aliases}
|
||||
|
||||
# =============================================================================
|
||||
#
|
||||
# To initialize zoxide with PowerShell, add the following line to your
|
||||
# PowerShell configuration file (the location is stored in $profile):
|
||||
#
|
||||
# Invoke-Expression (& {{
|
||||
# $hook = if ($PSVersionTable.PSVersion.Major -ge 6) {{
|
||||
# 'pwd'
|
||||
# }} else {{
|
||||
# 'prompt'
|
||||
# }}
|
||||
# (zoxide init powershell --hook $hook) -join \"`n\"
|
||||
# }})
|
||||
",
|
||||
__zoxide_pwd = __zoxide_pwd,
|
||||
__zoxide_cd = __zoxide_cd,
|
||||
__zoxide_hook = __zoxide_hook,
|
||||
hook_init = hook_init,
|
||||
aliases = aliases,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
@ -1,174 +0,0 @@
|
||||
use anyhow::Result;
|
||||
|
||||
use std::io::Write;
|
||||
|
||||
use super::{Hook, Init};
|
||||
use crate::config;
|
||||
|
||||
pub fn run<W: Write>(writer: &mut W, options: &Init) -> Result<()> {
|
||||
const NOT_CONFIGURED: &str = "\
|
||||
# -- not configured --";
|
||||
|
||||
let __zoxide_pwd = if config::zo_resolve_symlinks() {
|
||||
"\
|
||||
__zoxide_pwd() {
|
||||
pwd -P
|
||||
}"
|
||||
} else {
|
||||
"\
|
||||
__zoxide_pwd() {
|
||||
pwd -L
|
||||
}"
|
||||
};
|
||||
|
||||
let __zoxide_cd = if config::zo_echo() {
|
||||
"\
|
||||
__zoxide_cd() {
|
||||
cd \"$@\" || return \"$?\"
|
||||
__zoxide_pwd
|
||||
}"
|
||||
} else {
|
||||
"\
|
||||
__zoxide_cd() {
|
||||
cd \"$@\" || return \"$?\"
|
||||
}"
|
||||
};
|
||||
|
||||
let __zoxide_hook = match options.hook {
|
||||
Hook::none => NOT_CONFIGURED,
|
||||
_ => {
|
||||
"\
|
||||
__zoxide_hook() {
|
||||
zoxide add \"$(__zoxide_pwd)\"
|
||||
}"
|
||||
}
|
||||
};
|
||||
|
||||
let hook_init = match options.hook {
|
||||
Hook::none => NOT_CONFIGURED,
|
||||
Hook::prompt => {
|
||||
"\
|
||||
[[ -n \"${precmd_functions[(r)__zoxide_hook]}\" ]] || {
|
||||
precmd_functions+=(__zoxide_hook)
|
||||
}"
|
||||
}
|
||||
Hook::pwd => {
|
||||
"\
|
||||
chpwd_functions=(${chpwd_functions[@]} \"__zoxide_hook\")"
|
||||
}
|
||||
};
|
||||
|
||||
let aliases = if options.no_aliases {
|
||||
NOT_CONFIGURED.into()
|
||||
} else {
|
||||
format!(
|
||||
"\
|
||||
alias {cmd}='__zoxide_z'
|
||||
alias {cmd}i='__zoxide_zi'
|
||||
|
||||
alias {cmd}a='__zoxide_za'
|
||||
|
||||
alias {cmd}q='__zoxide_zq'
|
||||
alias {cmd}qi='__zoxide_zqi'
|
||||
|
||||
alias {cmd}r='__zoxide_zr'
|
||||
alias {cmd}ri='__zoxide_zri'",
|
||||
cmd = options.cmd
|
||||
)
|
||||
};
|
||||
|
||||
write!(
|
||||
writer,
|
||||
"\
|
||||
# =============================================================================
|
||||
#
|
||||
# Utility functions for zoxide.
|
||||
#
|
||||
|
||||
# pwd based on the value of _ZO_RESOLVE_SYMLINKS.
|
||||
{__zoxide_pwd}
|
||||
|
||||
# cd + custom logic based on the value of _ZO_ECHO.
|
||||
{__zoxide_cd}
|
||||
|
||||
# =============================================================================
|
||||
#
|
||||
# Hook configuration for zoxide.
|
||||
#
|
||||
|
||||
# Hook to add new entries to the database.
|
||||
{__zoxide_hook}
|
||||
|
||||
# Initialize hook.
|
||||
{hook_init}
|
||||
|
||||
# =============================================================================
|
||||
#
|
||||
# When using zoxide with --no-aliases, alias these internal functions as
|
||||
# desired.
|
||||
#
|
||||
|
||||
# Jump to a directory using only keywords.
|
||||
__zoxide_z() {{
|
||||
if [ \"$#\" -eq 0 ]; then
|
||||
__zoxide_cd ~
|
||||
elif [ \"$#\" -eq 1 ] && [ \"$1\" = '-' ]; then
|
||||
if [ -n \"$OLDPWD\" ]; then
|
||||
__zoxide_cd \"$OLDPWD\"
|
||||
else
|
||||
echo \"zoxide: \\$OLDPWD is not set\"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
local __zoxide_result
|
||||
__zoxide_result=\"$(zoxide query -- \"$@\")\" && __zoxide_cd \"$__zoxide_result\"
|
||||
fi
|
||||
}}
|
||||
|
||||
# Jump to a directory using interactive search.
|
||||
__zoxide_zi() {{
|
||||
local __zoxide_result
|
||||
__zoxide_result=\"$(zoxide query -i -- \"$@\")\" && __zoxide_cd \"$__zoxide_result\"
|
||||
}}
|
||||
|
||||
# Add a new entry to the database.
|
||||
alias __zoxide_za='zoxide add'
|
||||
|
||||
# Query an entry from the database using only keywords.
|
||||
alias __zoxide_zq='zoxide query'
|
||||
|
||||
# Query an entry from the database using interactive selection.
|
||||
alias __zoxide_zqi='zoxide query -i'
|
||||
|
||||
# Remove an entry from the database using the exact path.
|
||||
alias __zoxide_zr='zoxide remove'
|
||||
|
||||
# Remove an entry from the database using interactive selection.
|
||||
__zoxide_zri() {{
|
||||
local __zoxide_result
|
||||
__zoxide_result=\"$(zoxide query -i -- \"$@\")\" && zoxide remove \"$__zoxide_result\"
|
||||
}}
|
||||
|
||||
# =============================================================================
|
||||
#
|
||||
# Convenient aliases for zoxide. Disable these using --no-aliases.
|
||||
#
|
||||
|
||||
{aliases}
|
||||
|
||||
# =============================================================================
|
||||
#
|
||||
# To initialize zoxide with zsh, add the following line to your zsh
|
||||
# configuration file (usually ~/.zshrc):
|
||||
#
|
||||
# eval \"$(zoxide init zsh)\"
|
||||
",
|
||||
__zoxide_pwd = __zoxide_pwd,
|
||||
__zoxide_cd = __zoxide_cd,
|
||||
__zoxide_hook = __zoxide_hook,
|
||||
hook_init = hook_init,
|
||||
aliases = aliases,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
mod add;
|
||||
mod import;
|
||||
mod init;
|
||||
mod query;
|
||||
mod remove;
|
||||
|
||||
pub use add::Add;
|
||||
pub use import::Import;
|
||||
pub use init::Init;
|
||||
pub use query::Query;
|
||||
pub use remove::Remove;
|
@ -1,127 +0,0 @@
|
||||
use crate::db::Dir;
|
||||
use crate::fzf::Fzf;
|
||||
use crate::util;
|
||||
|
||||
use anyhow::{bail, Context, Result};
|
||||
use structopt::StructOpt;
|
||||
|
||||
use std::io::{self, Write};
|
||||
use std::path::Path;
|
||||
|
||||
/// Search for a directory
|
||||
#[derive(Debug, StructOpt)]
|
||||
#[structopt()]
|
||||
pub struct Query {
|
||||
keywords: Vec<String>,
|
||||
|
||||
/// Opens an interactive selection menu using fzf
|
||||
#[structopt(short, long, conflicts_with = "list")]
|
||||
interactive: bool,
|
||||
|
||||
/// List all matching directories
|
||||
#[structopt(short, long, conflicts_with = "interactive")]
|
||||
list: bool,
|
||||
|
||||
/// Display score along with result
|
||||
#[structopt(short, long)]
|
||||
score: bool,
|
||||
}
|
||||
|
||||
impl Query {
|
||||
pub fn run(&self) -> Result<()> {
|
||||
if self.list {
|
||||
return self.query_list();
|
||||
}
|
||||
|
||||
if self.interactive {
|
||||
return self.query_interactive();
|
||||
}
|
||||
|
||||
// if the input is already a valid path, simply print it as-is
|
||||
if let [path] = self.keywords.as_slice() {
|
||||
if Path::new(path).is_dir() {
|
||||
let dir = Dir {
|
||||
path: path.to_string(),
|
||||
rank: 0.0,
|
||||
last_accessed: 0,
|
||||
};
|
||||
|
||||
if self.score {
|
||||
println!("{}", dir.display_score(0))
|
||||
} else {
|
||||
println!("{}", dir.display());
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
self.query()
|
||||
}
|
||||
|
||||
fn query(&self) -> Result<()> {
|
||||
let mut db = util::get_db()?;
|
||||
let now = util::get_current_time()?;
|
||||
|
||||
let mut matches = db.matches(now, &self.keywords);
|
||||
|
||||
match matches.next() {
|
||||
Some(dir) => {
|
||||
if self.score {
|
||||
println!("{}", dir.display_score(now))
|
||||
} else {
|
||||
println!("{}", dir.display());
|
||||
}
|
||||
}
|
||||
None => bail!("no match found"),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn query_interactive(&self) -> Result<()> {
|
||||
let mut db = util::get_db()?;
|
||||
let now = util::get_current_time()?;
|
||||
|
||||
let mut fzf = Fzf::new()?;
|
||||
|
||||
for dir in db.matches(now, &self.keywords) {
|
||||
fzf.write(format!("{}", dir.display_score(now)))?;
|
||||
}
|
||||
|
||||
match fzf.wait_select()? {
|
||||
Some(selection) => {
|
||||
if self.score {
|
||||
print!("{}", selection)
|
||||
} else {
|
||||
let selection = selection
|
||||
.get(5..)
|
||||
.with_context(|| format!("fzf returned invalid output: {}", selection))?;
|
||||
print!("{}", selection)
|
||||
}
|
||||
}
|
||||
None => bail!("no match found"),
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn query_list(&self) -> Result<()> {
|
||||
let mut db = util::get_db()?;
|
||||
let now = util::get_current_time()?;
|
||||
|
||||
let stdout = io::stdout();
|
||||
let mut handle = stdout.lock();
|
||||
|
||||
for dir in db.matches(now, &self.keywords) {
|
||||
if self.score {
|
||||
writeln!(handle, "{}", dir.display_score(now))
|
||||
} else {
|
||||
writeln!(handle, "{}", dir.display())
|
||||
}
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
use crate::util;
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use structopt::StructOpt;
|
||||
|
||||
/// Remove a directory
|
||||
#[derive(Debug, StructOpt)]
|
||||
#[structopt()]
|
||||
pub struct Remove {
|
||||
path: String,
|
||||
}
|
||||
|
||||
impl Remove {
|
||||
pub fn run(&self) -> Result<()> {
|
||||
remove(&self.path)
|
||||
}
|
||||
}
|
||||
|
||||
fn remove(path: &str) -> Result<()> {
|
||||
let mut db = util::get_db()?;
|
||||
|
||||
if let Some(idx) = db.dirs.iter().position(|dir| dir.path == path) {
|
||||
db.dirs.swap_remove(idx);
|
||||
db.modified = true;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let path = util::resolve_path(&path)?;
|
||||
let path = util::path_to_str(&path)?;
|
||||
|
||||
if let Some(idx) = db.dirs.iter().position(|dir| dir.path == path) {
|
||||
db.dirs.swap_remove(idx);
|
||||
db.modified = true;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
bail!("could not find path in database: {}", path)
|
||||
}
|
39
src/util.rs
39
src/util.rs
@ -1,17 +1,21 @@
|
||||
use crate::config;
|
||||
use crate::db::{Db, Epoch};
|
||||
use zoxide_engine::Epoch;
|
||||
|
||||
use anyhow::{bail, Context, Result};
|
||||
|
||||
use std::env;
|
||||
use std::path::{Component, Path, PathBuf};
|
||||
use std::time::SystemTime;
|
||||
|
||||
pub fn get_db() -> Result<Db> {
|
||||
let data_dir = config::zo_data_dir()?;
|
||||
Db::open(data_dir)
|
||||
pub fn canonicalize<P: AsRef<Path>>(path: &P) -> Result<PathBuf> {
|
||||
dunce::canonicalize(path)
|
||||
.with_context(|| format!("could not resolve path: {}", path.as_ref().display()))
|
||||
}
|
||||
|
||||
pub fn get_current_time() -> Result<Epoch> {
|
||||
pub fn current_dir() -> Result<PathBuf> {
|
||||
env::current_dir().context("could not get current directory")
|
||||
}
|
||||
|
||||
pub fn current_time() -> Result<Epoch> {
|
||||
let current_time = SystemTime::now()
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.context("system clock set to invalid time")?
|
||||
@ -20,9 +24,10 @@ pub fn get_current_time() -> Result<Epoch> {
|
||||
Ok(current_time as _)
|
||||
}
|
||||
|
||||
pub fn canonicalize<P: AsRef<Path>>(path: &P) -> Result<PathBuf> {
|
||||
pub fn path_to_str<P: AsRef<Path>>(path: &P) -> Result<&str> {
|
||||
let path = path.as_ref();
|
||||
dunce::canonicalize(path).with_context(|| format!("could not resolve path: {}", path.display()))
|
||||
path.to_str()
|
||||
.with_context(|| format!("invalid UTF-8 in path: {}", path.display()))
|
||||
}
|
||||
|
||||
/// Resolves the absolute version of a path.
|
||||
@ -31,7 +36,7 @@ pub fn canonicalize<P: AsRef<Path>>(path: &P) -> Result<PathBuf> {
|
||||
/// character.
|
||||
/// If path is relative, use the current directory to build the absolute path.
|
||||
#[cfg(any(unix, windows))]
|
||||
pub fn resolve_path<P: AsRef<Path>>(path: P) -> Result<PathBuf> {
|
||||
pub fn resolve_path<P: AsRef<Path>>(path: &P) -> Result<PathBuf> {
|
||||
let path = path.as_ref();
|
||||
let base_path;
|
||||
|
||||
@ -46,7 +51,7 @@ pub fn resolve_path<P: AsRef<Path>>(path: P) -> Result<PathBuf> {
|
||||
stack.push(root);
|
||||
}
|
||||
_ => {
|
||||
base_path = get_current_dir()?;
|
||||
base_path = current_dir()?;
|
||||
stack.extend(base_path.components());
|
||||
}
|
||||
}
|
||||
@ -73,7 +78,7 @@ pub fn resolve_path<P: AsRef<Path>>(path: P) -> Result<PathBuf> {
|
||||
}
|
||||
|
||||
fn get_drive_relative(drive_letter: u8) -> Result<PathBuf> {
|
||||
let path = get_current_dir()?;
|
||||
let path = current_dir()?;
|
||||
if Some(drive_letter) == get_drive_letter(&path) {
|
||||
return Ok(path);
|
||||
}
|
||||
@ -124,7 +129,7 @@ pub fn resolve_path<P: AsRef<Path>>(path: P) -> Result<PathBuf> {
|
||||
stack.extend(base_path.components());
|
||||
}
|
||||
_ => {
|
||||
base_path = get_current_dir()?;
|
||||
base_path = current_dir()?;
|
||||
stack.extend(base_path.components());
|
||||
}
|
||||
}
|
||||
@ -149,13 +154,3 @@ pub fn resolve_path<P: AsRef<Path>>(path: P) -> Result<PathBuf> {
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub fn get_current_dir() -> Result<PathBuf> {
|
||||
env::current_dir().context("could not get current path")
|
||||
}
|
||||
|
||||
pub fn path_to_str<P: AsRef<Path>>(path: &P) -> Result<&str> {
|
||||
let path = path.as_ref();
|
||||
path.to_str()
|
||||
.with_context(|| format!("invalid utf-8 sequence in path: {}", path.display()))
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user