Split crates
This commit is contained in:
parent
eaf63bcc69
commit
aca2477b68
|
|
@ -1,123 +1,7 @@
|
||||||
# Created by https://www.gitignore.io/api/rust
|
|
||||||
# Edit at https://www.gitignore.io/?templates=rust
|
|
||||||
|
|
||||||
### Rust ###
|
|
||||||
# Generated by Cargo
|
# Generated by Cargo
|
||||||
# will have compiled files and executables
|
# will have compiled files and executables
|
||||||
/target/
|
debug/
|
||||||
|
target/
|
||||||
|
|
||||||
# These are backup files generated by rustfmt
|
# These are backup files generated by rustfmt
|
||||||
**/*.rs.bk
|
**/*.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`.
|
- `zoxide init --no-aliases` no longer generates `z` or `zi`.
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- Deprecated PWD hooks for POSIX shells.
|
||||||
|
|
||||||
## [0.4.3] - 2020-07-04
|
## [0.4.3] - 2020-07-04
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
|
||||||
|
|
@ -1,474 +1,619 @@
|
||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ansi_term"
|
name = "anyhow"
|
||||||
version = "0.11.0"
|
version = "1.0.33"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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 = [
|
dependencies = [
|
||||||
"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"askama_derive",
|
||||||
|
"askama_escape",
|
||||||
|
"askama_shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "askama_derive"
|
||||||
version = "1.0.32"
|
version = "0.10.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e1d7169690c4f56343dcd821ab834972a22570a2662a19a84fd7775d5e1c3881"
|
||||||
|
dependencies = [
|
||||||
|
"askama_shared",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrayref"
|
name = "askama_escape"
|
||||||
version = "0.3.6"
|
version = "0.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "90c108c1a94380c89d2215d0ac54ce09796823cca0fd91b299cfff3b33e346fb"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrayvec"
|
name = "askama_shared"
|
||||||
version = "0.5.1"
|
version = "0.10.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "atty"
|
name = "atty"
|
||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hermit-abi",
|
||||||
"libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc",
|
||||||
"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||||
[[package]]
|
|
||||||
name = "base64"
|
|
||||||
version = "0.12.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bincode"
|
name = "bincode"
|
||||||
version = "1.3.1"
|
version = "1.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f30d3a39baa26f9651f17b375061f3233dde33424a8b72b0dbe93a68a0bc896d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder",
|
||||||
"serde 1.0.116 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.2.1"
|
version = "1.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||||
[[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)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
version = "1.3.4"
|
version = "1.3.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "0.1.10"
|
version = "0.1.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "2.33.3"
|
version = "3.0.0-beta.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4bd1061998a501ee7d4b6d449020df3266ca3124b941ec56cf2005c3779ca142"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"atty",
|
||||||
"atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags",
|
||||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clap_derive",
|
||||||
"strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"indexmap",
|
||||||
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static",
|
||||||
"unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"os_str_bytes",
|
||||||
"vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"strsim",
|
||||||
|
"termcolor",
|
||||||
|
"textwrap",
|
||||||
|
"unicode-width",
|
||||||
|
"vec_map",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "constant_time_eq"
|
name = "clap_derive"
|
||||||
version = "0.1.5"
|
version = "3.0.0-beta.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-utils"
|
|
||||||
version = "0.7.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "370f715b81112975b1b69db93e0b56ea4cd4e5002ac43b2da8474106a54096a1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"heck",
|
||||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro-error",
|
||||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dirs"
|
name = "difference"
|
||||||
version = "3.0.1"
|
version = "2.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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 = [
|
dependencies = [
|
||||||
"dirs-sys 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cfg-if 1.0.0",
|
||||||
|
"dirs-sys-next",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dirs-sys"
|
name = "dirs-sys-next"
|
||||||
version = "0.3.5"
|
version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "99de365f605554ae33f115102a02057d4fc18b01f3284d6870be0938743cfe7d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc",
|
||||||
"redox_users 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"redox_users",
|
||||||
"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "doc-comment"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dunce"
|
name = "dunce"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b2641c4a7c0c4101df53ea572bffdc561c146f6c2eb09e4df02bc4811e3feeb4"
|
||||||
[[package]]
|
|
||||||
name = "float-ord"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.1.15"
|
version = "0.1.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cfg-if 0.1.10",
|
||||||
"libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc",
|
||||||
"wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"wasi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glob"
|
name = "glob"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-segmentation",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.1.16"
|
version = "0.1.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4c30f6d0bc6b00693347368a67d41b58f2fb851215ff1da49e90fe2c5c667151"
|
||||||
dependencies = [
|
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]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.78"
|
version = "0.2.78"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "ppv-lite86"
|
name = "ppv-lite86"
|
||||||
version = "0.2.9"
|
version = "0.2.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "proc-macro-error"
|
name = "proc-macro-error"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro-error-attr 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro-error-attr",
|
||||||
"proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2",
|
||||||
"quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote",
|
||||||
"syn 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn",
|
||||||
"version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-error-attr"
|
name = "proc-macro-error-attr"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2",
|
||||||
"quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote",
|
||||||
"version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.24"
|
version = "1.0.24"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.7.3"
|
version = "0.7.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
"getrandom",
|
||||||
"libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc",
|
||||||
"rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand_chacha",
|
||||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand_core",
|
||||||
"rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand_hc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand_chacha"
|
name = "rand_chacha"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ppv-lite86 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ppv-lite86",
|
||||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand_core"
|
name = "rand_core"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
"getrandom",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand_hc"
|
name = "rand_hc"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.1.57"
|
version = "0.1.57"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_users"
|
name = "redox_users"
|
||||||
version = "0.3.5"
|
version = "0.3.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
"getrandom",
|
||||||
"redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)",
|
"redox_syscall",
|
||||||
"rust-argon2 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rust-argon2"
|
name = "remove_dir_all"
|
||||||
version = "0.8.2"
|
version = "0.5.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi",
|
||||||
"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)",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.116"
|
version = "1.0.116"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive 1.0.116 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.116"
|
version = "1.0.116"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2",
|
||||||
"quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote",
|
||||||
"syn 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.8.0"
|
version = "0.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
[[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)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.42"
|
version = "1.0.45"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ea9c5432ff16d6152371f808fb5a871cd67368171b09bb21b43df8e4a47a3556"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2",
|
||||||
"quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote",
|
||||||
"unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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]]
|
[[package]]
|
||||||
name = "textwrap"
|
name = "textwrap"
|
||||||
version = "0.11.0"
|
version = "0.12.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "203008d98caf094106cfaba70acfed15e18ed3ddb7d94e49baec153a2b462789"
|
||||||
dependencies = [
|
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]]
|
[[package]]
|
||||||
name = "unicode-segmentation"
|
name = "unicode-segmentation"
|
||||||
version = "1.6.0"
|
version = "1.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-width"
|
name = "unicode-width"
|
||||||
version = "0.1.8"
|
version = "0.1.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-xid"
|
name = "unicode-xid"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
||||||
[[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)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vec_map"
|
name = "vec_map"
|
||||||
version = "0.8.2"
|
version = "0.8.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.2"
|
version = "0.9.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.9.0+wasi-snapshot-preview1"
|
version = "0.9.0+wasi-snapshot-preview1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winapi-i686-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 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi-x86_64-pc-windows-gnu",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi-i686-pc-windows-gnu"
|
name = "winapi-i686-pc-windows-gnu"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "winapi-x86_64-pc-windows-gnu"
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zoxide"
|
name = "zoxide"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
"anyhow",
|
||||||
"bincode 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clap",
|
||||||
"clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"dirs-next",
|
||||||
"dirs 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"dunce",
|
||||||
"dunce 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"glob",
|
||||||
"float-ord 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"once_cell",
|
||||||
"glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"zoxide-engine",
|
||||||
"serde 1.0.116 (registry+https://github.com/rust-lang/crates.io-index)",
|
"zoxide-shell",
|
||||||
"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)",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[metadata]
|
[[package]]
|
||||||
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
name = "zoxide-engine"
|
||||||
"checksum anyhow 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)" = "6b602bfe940d21c130f3895acd65221e8a61270debe89d628b9cb4e3ccb8569b"
|
version = "0.1.0"
|
||||||
"checksum arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
|
dependencies = [
|
||||||
"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
|
"anyhow",
|
||||||
"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
"bincode",
|
||||||
"checksum autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
"ordered-float",
|
||||||
"checksum base64 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
|
"serde",
|
||||||
"checksum bincode 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f30d3a39baa26f9651f17b375061f3233dde33424a8b72b0dbe93a68a0bc896d"
|
"tempfile",
|
||||||
"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"
|
[[package]]
|
||||||
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
name = "zoxide-shell"
|
||||||
"checksum clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)" = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
|
version = "0.1.0"
|
||||||
"checksum constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
dependencies = [
|
||||||
"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
"anyhow",
|
||||||
"checksum dirs 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "142995ed02755914747cc6ca76fc7e4583cd18578746716d0508ea6ed558b9ff"
|
"askama",
|
||||||
"checksum dirs-sys 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a"
|
"assert_cmd",
|
||||||
"checksum dunce 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b2641c4a7c0c4101df53ea572bffdc561c146f6c2eb09e4df02bc4811e3feeb4"
|
"once_cell",
|
||||||
"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"
|
|
||||||
|
|
|
||||||
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"
|
description = "A faster way to navigate your filesystem"
|
||||||
repository = "https://github.com/ajeetdsouza/zoxide/"
|
repository = "https://github.com/ajeetdsouza/zoxide/"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
keywords = ["cli"]
|
keywords = ["cli"]
|
||||||
categories = ["command-line-utilities", "filesystem"]
|
categories = ["command-line-utilities", "filesystem"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.28"
|
anyhow = "1.0.32"
|
||||||
bincode = "1.2.1"
|
clap = "3.0.0-beta.2"
|
||||||
clap = "2.33.0"
|
dirs-next = "1.0.2"
|
||||||
dirs = "3.0.0"
|
dunce = "1.0.1"
|
||||||
dunce = "1.0.0"
|
|
||||||
float-ord = "0.2.0"
|
|
||||||
glob = "0.3.0"
|
glob = "0.3.0"
|
||||||
serde = { version = "1.0.106", features = ["derive"] }
|
once_cell = "1.4.1"
|
||||||
structopt = "0.3.12"
|
zoxide-engine = { path = "crates/zoxide-engine" }
|
||||||
uuid = { version = "0.8.1", features = ["v4"] }
|
zoxide-shell = { path = "crates/zoxide-shell" }
|
||||||
|
|
||||||
|
[workspace]
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
|
|
|
||||||
4
build.rs
4
build.rs
|
|
@ -1,5 +1,7 @@
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let git_describe = std::process::Command::new("git")
|
let git_describe = Command::new("git")
|
||||||
.args(&["describe", "--tags", "--broken"])
|
.args(&["describe", "--tags", "--broken"])
|
||||||
.output()
|
.output()
|
||||||
.ok()
|
.ok()
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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"
|
||||||
|
|
@ -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
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
pub mod dir;
|
||||||
|
mod query;
|
||||||
|
mod store;
|
||||||
|
|
||||||
|
pub use dir::{Dir, Epoch};
|
||||||
|
pub use query::Query;
|
||||||
|
pub use store::Store;
|
||||||
|
|
@ -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"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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"
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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)"
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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)"
|
||||||
|
|
@ -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"
|
||||||
|
# })
|
||||||
|
|
@ -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')
|
||||||
|
|
@ -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)"
|
||||||
|
|
@ -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 anyhow::{bail, Context, Result};
|
||||||
|
use dirs_next as dirs;
|
||||||
|
use zoxide_engine::dir::Rank;
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::fs;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
pub fn zo_data_dir() -> Result<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)
|
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"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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;
|
use std::io::{self, Write};
|
||||||
mod db;
|
use std::path::{Path, PathBuf};
|
||||||
mod error;
|
|
||||||
mod fzf;
|
|
||||||
mod subcommand;
|
|
||||||
mod util;
|
|
||||||
|
|
||||||
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;
|
format!(
|
||||||
use structopt::StructOpt;
|
"\
|
||||||
|
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)]
|
/// Generates shell configuration
|
||||||
#[structopt(about, version = env!("ZOXIDE_VERSION"))]
|
#[clap(after_help(env_help()))]
|
||||||
enum Zoxide {
|
Init {
|
||||||
Add(subcommand::Add),
|
#[clap(arg_enum)]
|
||||||
Import(subcommand::Import),
|
shell: Shell,
|
||||||
Init(subcommand::Init),
|
|
||||||
Query(subcommand::Query),
|
/// Prevents zoxide from defining any commands
|
||||||
Remove(subcommand::Remove),
|
#[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<()> {
|
pub fn main() -> Result<()> {
|
||||||
let opt = Zoxide::from_args();
|
let opts = Opts::parse();
|
||||||
|
|
||||||
let res = match opt {
|
match opts {
|
||||||
Zoxide::Add(add) => add.run(),
|
Opts::Add { path } => {
|
||||||
Zoxide::Import(import) => import.run(),
|
let path = match path {
|
||||||
Zoxide::Init(init) => init.run(),
|
Some(path) => {
|
||||||
Zoxide::Query(query) => query.run(),
|
if config::zo_resolve_symlinks() {
|
||||||
Zoxide::Remove(remove) => remove.run(),
|
util::canonicalize(&path)
|
||||||
};
|
} else {
|
||||||
|
util::resolve_path(&path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => util::current_dir(),
|
||||||
|
}?;
|
||||||
|
|
||||||
res.map_err(|e| match e.downcast::<SilentExit>() {
|
if config::zo_exclude_dirs()?
|
||||||
Ok(SilentExit { code }) => process::exit(code),
|
.iter()
|
||||||
Err(e) => e,
|
.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 zoxide_engine::Epoch;
|
||||||
use crate::db::{Db, Epoch};
|
|
||||||
|
|
||||||
use anyhow::{bail, Context, Result};
|
use anyhow::{bail, Context, Result};
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::path::{Component, Path, PathBuf};
|
use std::path::{Component, Path, PathBuf};
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
|
|
||||||
pub fn get_db() -> Result<Db> {
|
pub fn canonicalize<P: AsRef<Path>>(path: &P) -> Result<PathBuf> {
|
||||||
let data_dir = config::zo_data_dir()?;
|
dunce::canonicalize(path)
|
||||||
Db::open(data_dir)
|
.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()
|
let current_time = SystemTime::now()
|
||||||
.duration_since(SystemTime::UNIX_EPOCH)
|
.duration_since(SystemTime::UNIX_EPOCH)
|
||||||
.context("system clock set to invalid time")?
|
.context("system clock set to invalid time")?
|
||||||
|
|
@ -20,9 +24,10 @@ pub fn get_current_time() -> Result<Epoch> {
|
||||||
Ok(current_time as _)
|
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();
|
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.
|
/// Resolves the absolute version of a path.
|
||||||
|
|
@ -31,7 +36,7 @@ pub fn canonicalize<P: AsRef<Path>>(path: &P) -> Result<PathBuf> {
|
||||||
/// character.
|
/// character.
|
||||||
/// If path is relative, use the current directory to build the absolute path.
|
/// If path is relative, use the current directory to build the absolute path.
|
||||||
#[cfg(any(unix, windows))]
|
#[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 path = path.as_ref();
|
||||||
let base_path;
|
let base_path;
|
||||||
|
|
||||||
|
|
@ -46,7 +51,7 @@ pub fn resolve_path<P: AsRef<Path>>(path: P) -> Result<PathBuf> {
|
||||||
stack.push(root);
|
stack.push(root);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
base_path = get_current_dir()?;
|
base_path = current_dir()?;
|
||||||
stack.extend(base_path.components());
|
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> {
|
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) {
|
if Some(drive_letter) == get_drive_letter(&path) {
|
||||||
return Ok(path);
|
return Ok(path);
|
||||||
}
|
}
|
||||||
|
|
@ -124,7 +129,7 @@ pub fn resolve_path<P: AsRef<Path>>(path: P) -> Result<PathBuf> {
|
||||||
stack.extend(base_path.components());
|
stack.extend(base_path.components());
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
base_path = get_current_dir()?;
|
base_path = current_dir()?;
|
||||||
stack.extend(base_path.components());
|
stack.extend(base_path.components());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -149,13 +154,3 @@ pub fn resolve_path<P: AsRef<Path>>(path: P) -> Result<PathBuf> {
|
||||||
}
|
}
|
||||||
Ok(result)
|
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…
Reference in New Issue