mirror of
https://github.com/Llewellynvdm/zoxide.git
synced 2024-11-22 04:45:20 +00:00
Merge branch 'main' into install
This commit is contained in:
commit
9348fb3710
@ -3,6 +3,3 @@ version = 1
|
||||
[[analyzers]]
|
||||
name = "rust"
|
||||
enabled = true
|
||||
|
||||
[analyzers.meta]
|
||||
edition = 2018
|
||||
|
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@ -13,6 +13,8 @@ jobs:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
@ -24,7 +26,7 @@ jobs:
|
||||
- uses: cachix/install-nix-action@v15
|
||||
if: ${{ matrix.os != 'windows-latest' }}
|
||||
with:
|
||||
nix_path: nixpkgs=https://github.com/NixOS/nixpkgs/archive/20.09.tar.gz
|
||||
nix_path: nixpkgs=channel:nixpkgs-unstable
|
||||
|
||||
- run: cargo xtask ci
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
|
23
CHANGELOG.md
23
CHANGELOG.md
@ -11,11 +11,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
### Changed
|
||||
|
||||
- manpages: moved to `man/man1/*.1`.
|
||||
- Manpages: moved to `man/man1/*.1`.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Rename `_z` completion function to avoid conflicts with other shell plugins.
|
||||
- Bash/Zsh: rename `_z` completion function to avoid conflicts with other shell
|
||||
plugins.
|
||||
- Elvish: upgrade to new lambda syntax.
|
||||
- Fzf: added `--keep-right` option by default, upgraded minimum version to
|
||||
v0.21.0.
|
||||
- Bash: only enable completions on 4.4+.
|
||||
- Fzf: bypass `ls` alias in preview window.
|
||||
- Retain ownership of database file.
|
||||
|
||||
## [0.8.0] - 2021-12-25
|
||||
|
||||
@ -26,7 +33,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Changed
|
||||
|
||||
- Fzf: better default options.
|
||||
- Fish: interactive completions are only triggered when the last argument is empty.
|
||||
- Fish: interactive completions are only triggered when the last argument is
|
||||
empty.
|
||||
- PowerShell: installation instructions.
|
||||
|
||||
### Fixed
|
||||
@ -127,7 +135,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- Auto-generated shell completions.
|
||||
- `zoxide query --all` for listing deleted directories.
|
||||
- Lazy deletion for removed directories that have not been accessed in > 90 days.
|
||||
- Lazy deletion for removed directories that have not been accessed in > 90
|
||||
days.
|
||||
- Nushell: support for 0.32.0+.
|
||||
|
||||
### Fixed
|
||||
@ -154,7 +163,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Fixed
|
||||
|
||||
- `cd -` on fish shells.
|
||||
- `__zoxide_hook` no longer changes value of `$?` within `$PROMPT_COMMAND` on bash.
|
||||
- `__zoxide_hook` no longer changes value of `$?` within `$PROMPT_COMMAND` on
|
||||
bash.
|
||||
|
||||
### Removed
|
||||
|
||||
@ -191,7 +201,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Added
|
||||
|
||||
- `$_ZO_EXCLUDE_DIRS` now supports globs.
|
||||
- `zoxide init` now defines `__zoxide_z*` functions that can be aliased as needed.
|
||||
- `zoxide init` now defines `__zoxide_z*` functions that can be aliased as
|
||||
needed.
|
||||
- Support for the [xonsh](https://xon.sh/) shell.
|
||||
- `zoxide import` can now import from Autojump.
|
||||
|
||||
|
340
Cargo.lock
generated
340
Cargo.lock
generated
@ -13,15 +13,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.52"
|
||||
version = "1.0.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84450d0b4a8bd1ba4144ce8ce718fbc5d071358b1e5384bace6536b3d1f2d5b3"
|
||||
checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27"
|
||||
|
||||
[[package]]
|
||||
name = "askama"
|
||||
version = "0.11.0"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d8f355701c672c2ba3d718acbd213f740beea577cc4eae66accdffe15be1882"
|
||||
checksum = "fb98f10f371286b177db5eeb9a6e5396609555686a35e1d4f7b9a9c6d8af0139"
|
||||
dependencies = [
|
||||
"askama_derive",
|
||||
"askama_escape",
|
||||
@ -30,9 +30,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "askama_derive"
|
||||
version = "0.11.0"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84704cab5b7ae0fd3a9f78ee5eb7b27f3749df445f04623db6633459ae283267"
|
||||
checksum = "87bf87e6e8b47264efa9bde63d6225c6276a52e05e91bf37eaa8afd0032d6b71"
|
||||
dependencies = [
|
||||
"askama_shared",
|
||||
"proc-macro2",
|
||||
@ -41,17 +41,19 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "askama_escape"
|
||||
version = "0.10.2"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a1bb320f97e6edf9f756bf015900038e43c7700e059688e5724a928c8f3b8d5"
|
||||
checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341"
|
||||
|
||||
[[package]]
|
||||
name = "askama_shared"
|
||||
version = "0.12.0"
|
||||
version = "0.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dae03eebba55a2697a376e58b573a29fe36893157173ac8df312ad85f3c0e012"
|
||||
checksum = "bf722b94118a07fcbc6640190f247334027685d4e218b794dbfe17c32bf38ed0"
|
||||
dependencies = [
|
||||
"askama_escape",
|
||||
"mime",
|
||||
"mime_guess",
|
||||
"nom",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -60,9 +62,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "assert_cmd"
|
||||
version = "2.0.2"
|
||||
version = "2.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e996dc7940838b7ef1096b882e29ec30a3149a3a443cdc8dba19ed382eca1fe2"
|
||||
checksum = "93ae1ddd39efd67689deb1979d80bad3bf7f2b09c6e6117c8d1f2443b5e2f83e"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"doc-comment",
|
||||
@ -85,9 +87,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
@ -115,6 +117,12 @@ dependencies = [
|
||||
"regex-automata",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
@ -123,9 +131,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "3.0.0-rc.8"
|
||||
version = "3.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "484f17839417b695a6f4a75c20e49820ba0a1d00aa41ebd8ba0e5dfe0fbc3b74"
|
||||
checksum = "d8c93436c21e4698bacadf42917db28b23017027a4deccb35dbe47a7e7840123"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
@ -139,10 +147,29 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "3.0.0-rc.8"
|
||||
name = "clap_complete"
|
||||
version = "3.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a86d4ec799f94ddc4a4a4edf652f89b360219905f86edcb8abe5974dfef135b8"
|
||||
checksum = "df6f3613c0a3cddfd78b41b10203eb322cb29b600cbdf808a7d3db95691b8e25"
|
||||
dependencies = [
|
||||
"clap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_complete_fig"
|
||||
version = "3.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c11f6f44afea4aee21bb57a5297879c88ac8dc97224fbbbe796edd60a098f0e"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"clap_complete",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "3.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da95d038ede1a964ce99f49cbe27a7fb538d1da595e4b4f70b8c8f338d17bf16"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
@ -151,30 +178,11 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_generate"
|
||||
version = "3.0.0-rc.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46edf9e899ef90f3cefafb75dfae4c52746911cb905408bdf147a4bfe6fd72aa"
|
||||
dependencies = [
|
||||
"clap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_generate_fig"
|
||||
version = "3.0.0-rc.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbb18e26b66468ccfcbd787003403c1307dfe913c08c157c8d0f3b6e270015e2"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"clap_generate",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.5"
|
||||
version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db"
|
||||
checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"lazy_static",
|
||||
@ -224,6 +232,15 @@ version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf"
|
||||
dependencies = [
|
||||
"instant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
@ -232,9 +249,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.3"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
|
||||
checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
@ -268,12 +285,9 @@ checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.3.3"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
@ -304,14 +318,23 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.7.0"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
|
||||
checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.3"
|
||||
@ -329,9 +352,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.112"
|
||||
version = "0.2.119"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125"
|
||||
checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
@ -348,12 +371,50 @@ version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
version = "0.3.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
|
||||
|
||||
[[package]]
|
||||
name = "mime_guess"
|
||||
version = "2.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef"
|
||||
dependencies = [
|
||||
"mime",
|
||||
"unicase",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.23.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"memoffset",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.0"
|
||||
@ -376,15 +437,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.9.0"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
|
||||
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
|
||||
|
||||
[[package]]
|
||||
name = "ordered-float"
|
||||
version = "2.8.0"
|
||||
version = "2.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97c9d06878b3a851e8026ef94bf7fef9ba93062cd412601da4d9cf369b1cc62d"
|
||||
checksum = "7940cf2ca942593318d07fcf2596cdca60a85c9e7fab408a5e21a4f9dcd40d87"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
@ -398,17 +459,11 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba"
|
||||
|
||||
[[package]]
|
||||
name = "predicates"
|
||||
version = "2.1.0"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95e5a7689e456ab905c22c2b48225bb921aba7c8dfa58440d68ba13f6222a715"
|
||||
checksum = "a5aab5be6e4732b473071984b3164dbbfb7a3674d30ea5ff44410b6bcd960c3c"
|
||||
dependencies = [
|
||||
"difflib",
|
||||
"itertools",
|
||||
@ -417,15 +472,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "predicates-core"
|
||||
version = "1.0.2"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57e35a3326b75e49aa85f5dc6ec15b41108cf5aee58eabb1f274dd18b73c2451"
|
||||
checksum = "da1c2388b1513e1b605fcec39a95e0a9e8ef088f71443ef37099fa9ae6673fcb"
|
||||
|
||||
[[package]]
|
||||
name = "predicates-tree"
|
||||
version = "1.0.4"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "338c7be2905b732ae3984a2f40032b5e94fd8f52505b186c7d4d68d193445df7"
|
||||
checksum = "4d86de6de25020a36c6d3643a86d9a6a9f552107c0559c60ea03551b5e16c032"
|
||||
dependencies = [
|
||||
"predicates-core",
|
||||
"termtree",
|
||||
@ -457,67 +512,27 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.34"
|
||||
version = "1.0.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f84e92c0f7c9d58328b85a78557813e4bd845130db68d7184635344399423b1"
|
||||
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.10"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
|
||||
checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_hc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.10"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
|
||||
checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
@ -534,9 +549,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.5.4"
|
||||
version = "1.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
|
||||
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
@ -577,6 +592,17 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rstest_reuse"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b29d3117bce27ea307d1fb7ce12c64ba11b3fd04311a42d32bc5f0072e6e3d4d"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"rustc_version",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.0"
|
||||
@ -597,24 +623,24 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.4"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012"
|
||||
checksum = "a4a3381e03edd24287172047536f20cabde766e2cd3e65e6b00fb3af51c4f38d"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.132"
|
||||
version = "1.0.136"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b9875c23cf305cd1fd7eb77234cbb705f21ea6a72c637a5c6db5fe4b8e7f008"
|
||||
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.132"
|
||||
version = "1.0.136"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ecc0db5cb2556c0e558887d9bbdcf6ac4471e83ff66cf696e5419024d1606276"
|
||||
checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -623,9 +649,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "shell-words"
|
||||
version = "1.0.0"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6fa3938c99da4914afedd13bf3d79bcb6c277d1b2c398d23257a304d9e1b074"
|
||||
checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
@ -635,9 +661,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.83"
|
||||
version = "1.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23a1dfb999630e338648c83e91c59a4e9fb7620f520c3194b6b89e276f2f1959"
|
||||
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -646,13 +672,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.2.0"
|
||||
version = "3.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
|
||||
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"libc",
|
||||
"rand",
|
||||
"redox_syscall",
|
||||
"remove_dir_all",
|
||||
"winapi",
|
||||
@ -660,59 +686,42 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
|
||||
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termtree"
|
||||
version = "0.2.3"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13a4ec180a2de59b57434704ccfad967f789b12737738798fa08798cd5824c16"
|
||||
checksum = "507e9898683b6c43a9aa55b64259b721b52ba226e0f3779137e50ad114a4c90b"
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.14.2"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.1.3"
|
||||
version = "1.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd"
|
||||
checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.8.0"
|
||||
name = "unicase"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
|
||||
checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
|
||||
dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
@ -722,9 +731,9 @@ checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.3"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "wait-timeout"
|
||||
@ -802,15 +811,16 @@ dependencies = [
|
||||
"assert_cmd",
|
||||
"bincode",
|
||||
"clap",
|
||||
"clap_generate",
|
||||
"clap_generate_fig",
|
||||
"clap_complete",
|
||||
"clap_complete_fig",
|
||||
"dirs",
|
||||
"dunce",
|
||||
"fastrand",
|
||||
"glob",
|
||||
"nix",
|
||||
"ordered-float",
|
||||
"rand",
|
||||
"rstest",
|
||||
"rstest_reuse",
|
||||
"serde",
|
||||
"tempfile",
|
||||
"thiserror",
|
||||
]
|
||||
|
25
Cargo.toml
25
Cargo.toml
@ -7,7 +7,7 @@ keywords = ["cli"]
|
||||
license = "MIT"
|
||||
name = "zoxide"
|
||||
repository = "https://github.com/ajeetdsouza/zoxide"
|
||||
rust-version = "1.56"
|
||||
rust-version = "1.59"
|
||||
version = "0.8.0"
|
||||
|
||||
[badges]
|
||||
@ -20,34 +20,33 @@ members = ["xtask/"]
|
||||
anyhow = "1.0.32"
|
||||
askama = { version = "0.11.0", default-features = false }
|
||||
bincode = "1.3.1"
|
||||
clap = { version = "=3.0.0-rc.8", features = ["derive"] }
|
||||
clap = { version = "3.1.0", features = ["derive"] }
|
||||
dirs = "4.0.0"
|
||||
dunce = "1.0.1"
|
||||
fastrand = "1.7.0"
|
||||
glob = "0.3.0"
|
||||
ordered-float = "2.0.0"
|
||||
serde = { version = "1.0.116", features = ["derive"] }
|
||||
tempfile = "3.1.0"
|
||||
thiserror = "1.0.30"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
rand = { version = "0.8.4", features = [
|
||||
"getrandom",
|
||||
"small_rng",
|
||||
], default-features = false }
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
nix = "0.23.1"
|
||||
|
||||
[build-dependencies]
|
||||
clap = { version = "=3.0.0-rc.8", features = ["derive"] }
|
||||
clap_generate = "=3.0.0-rc.8"
|
||||
clap_generate_fig = "=3.0.0-rc.8"
|
||||
clap = { version = "3.1.0", features = ["derive"] }
|
||||
clap_complete = "3.1.0"
|
||||
clap_complete_fig = "3.1.0"
|
||||
|
||||
[dev-dependencies]
|
||||
assert_cmd = "2.0.0"
|
||||
rstest = "0.12.0"
|
||||
rstest_reuse = "0.3.0"
|
||||
tempfile = "3.1.0"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
nix = []
|
||||
nix-dev = []
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
lto = true
|
||||
strip = true
|
||||
|
33
README.md
33
README.md
@ -35,6 +35,7 @@ zoxide works on all major shells.
|
||||
```sh
|
||||
z foo # cd into highest ranked directory matching foo
|
||||
z foo bar # cd into highest ranked directory matching foo and bar
|
||||
z foo / # cd into a subdirectory starting with foo
|
||||
|
||||
z ~/foo # z also works like a regular cd command
|
||||
z foo/ # cd into relative path
|
||||
@ -43,7 +44,7 @@ z - # cd into previous directory
|
||||
|
||||
zi foo # cd with interactive selection (using fzf)
|
||||
|
||||
z foo<SPACE><TAB> # show interactive completions (zoxide v0.8.0+, bash/fish/zsh only)
|
||||
z foo<SPACE><TAB> # show interactive completions (zoxide v0.8.0+, bash 4.4+/fish/zsh only)
|
||||
```
|
||||
|
||||
Read more about the matching algorithm [here][algorithm-matching].
|
||||
@ -259,7 +260,8 @@ eval "$(zoxide init posix --hook prompt)"
|
||||
### *Step 3: Install fzf (optional)*
|
||||
|
||||
[fzf] is a command-line fuzzy finder, used by zoxide for interactive
|
||||
selection. It can be installed from [here][fzf-installation].
|
||||
selection. It can be installed from [here][fzf-installation]. zoxide supports
|
||||
fzf v0.21.0+.
|
||||
|
||||
### *Step 4: Import your data (optional)*
|
||||
|
||||
@ -318,7 +320,7 @@ They must be set before `zoxide init` is called.
|
||||
| ----------- | ---------------------------------------- | ------------------------------------------ |
|
||||
| Linux / BSD | `$XDG_DATA_HOME` or `$HOME/.local/share` | `/home/alice/.local/share` |
|
||||
| macOS | `$HOME/Library/Application Support` | `/Users/Alice/Library/Application Support` |
|
||||
| Windows | `{FOLDERID_RoamingAppData}` | `C:\Users\Alice\AppData\Roaming` |
|
||||
| Windows | `%LOCALAPPDATA%` | `C:\Users\Alice\AppData\Local` |
|
||||
- `_ZO_ECHO`
|
||||
- When set to 1, `z` will print the matched directory before navigating to
|
||||
it.
|
||||
@ -344,16 +346,18 @@ They must be set before `zoxide init` is called.
|
||||
|
||||
## Third-party integrations
|
||||
|
||||
| Application | Description | Plugin |
|
||||
| ------------------ | --------------------------------------- | -------------------------- |
|
||||
| [emacs] | Text editor | [zoxide.el] |
|
||||
| [nnn] | File manager | [nnn-autojump] |
|
||||
| [ranger] | File manager | [ranger-zoxide] |
|
||||
| [telescope.nvim] | Fuzzy finder for Neovim | [telescope-zoxide] |
|
||||
| [vim] | Text editor | [zoxide.vim] |
|
||||
| [xplr] | File manager | [zoxide.xplr] |
|
||||
| [xxh] | Transports shell configuration over SSH | [xxh-plugin-prerun-zoxide] |
|
||||
| [zsh-autocomplete] | Realtime completions for zsh | Supported by default |
|
||||
| Application | Description | Plugin |
|
||||
| ------------------ | -------------------------------------------- | -------------------------- |
|
||||
| [clink] | Improved cmd.exe for Windows | [clink-zoxide] |
|
||||
| [emacs] | Text editor | [zoxide.el] |
|
||||
| [nnn] | File manager | [nnn-autojump] |
|
||||
| [ranger] | File manager | [ranger-zoxide] |
|
||||
| [telescope.nvim] | Fuzzy finder for Neovim | [telescope-zoxide] |
|
||||
| [vim] | Text editor | [zoxide.vim] |
|
||||
| [xplr] | File manager | [zoxide.xplr] |
|
||||
| [xxh] | Transports shell configuration over SSH | [xxh-plugin-prerun-zoxide] |
|
||||
| [zabb] | Finds the shortest possible query for a path | Natively supported |
|
||||
| [zsh-autocomplete] | Realtime completions for zsh | Natively supported |
|
||||
|
||||
[algorithm-aging]: https://github.com/ajeetdsouza/zoxide/wiki/Algorithm#aging
|
||||
[algorithm-matching]: https://github.com/ajeetdsouza/zoxide/wiki/Algorithm#matching
|
||||
@ -362,6 +366,8 @@ They must be set before `zoxide init` is called.
|
||||
[builtwithnix-badge]: https://img.shields.io/badge/builtwith-nix-7d81f7?style=flat-square
|
||||
[builtwithnix]: https://builtwithnix.org/
|
||||
[chocolatey]: https://community.chocolatey.org/packages/zoxide
|
||||
[clink-zoxide]: https://github.com/shunsambongi/clink-zoxide
|
||||
[clink]: https://github.com/mridgers/clink
|
||||
[conda-forge]: https://anaconda.org/conda-forge/zoxide
|
||||
[copr]: https://copr.fedorainfracloud.org/coprs/atim/zoxide/
|
||||
[crates.io-badge]: https://img.shields.io/crates/v/zoxide?style=flat-square
|
||||
@ -403,6 +409,7 @@ They must be set before `zoxide init` is called.
|
||||
[xplr]: https://github.com/sayanarijit/xplr
|
||||
[xxh-plugin-prerun-zoxide]: https://github.com/xxh/xxh-plugin-prerun-zoxide
|
||||
[xxh]: https://github.com/xxh/xxh
|
||||
[zabb]: https://github.com/Mellbourn/zabb
|
||||
[zoxide.el]: https://gitlab.com/Vonfry/zoxide.el
|
||||
[zoxide.vim]: https://github.com/nanotee/zoxide.vim
|
||||
[zoxide.xplr]: https://github.com/sayanarijit/zoxide.xplr
|
||||
|
28
build.rs
28
build.rs
@ -32,25 +32,25 @@ fn git_version() -> Option<String> {
|
||||
}
|
||||
|
||||
fn generate_completions() -> io::Result<()> {
|
||||
#[path = "src/app/_app.rs"]
|
||||
mod app;
|
||||
#[path = "src/cmd/_cmd.rs"]
|
||||
mod cmd;
|
||||
|
||||
use app::App;
|
||||
use clap::IntoApp;
|
||||
use clap_generate::generate_to;
|
||||
use clap_generate::generators::{Bash, Elvish, Fish, PowerShell, Zsh};
|
||||
use clap_generate_fig::Fig;
|
||||
use clap::CommandFactory;
|
||||
use clap_complete::generate_to;
|
||||
use clap_complete::shells::{Bash, Elvish, Fish, PowerShell, Zsh};
|
||||
use clap_complete_fig::Fig;
|
||||
use cmd::Cmd;
|
||||
|
||||
let app = &mut App::into_app();
|
||||
let cmd = &mut Cmd::command();
|
||||
let bin_name = env!("CARGO_PKG_NAME");
|
||||
let out_dir = "contrib/completions";
|
||||
|
||||
generate_to(Bash, app, bin_name, out_dir)?;
|
||||
generate_to(Elvish, app, bin_name, out_dir)?;
|
||||
generate_to(Fig, app, bin_name, out_dir)?;
|
||||
generate_to(Fish, app, bin_name, out_dir)?;
|
||||
generate_to(PowerShell, app, bin_name, out_dir)?;
|
||||
generate_to(Zsh, app, bin_name, out_dir)?;
|
||||
generate_to(Bash, cmd, bin_name, out_dir)?;
|
||||
generate_to(Elvish, cmd, bin_name, out_dir)?;
|
||||
generate_to(Fig, cmd, bin_name, out_dir)?;
|
||||
generate_to(Fish, cmd, bin_name, out_dir)?;
|
||||
generate_to(PowerShell, cmd, bin_name, out_dir)?;
|
||||
generate_to(Zsh, cmd, bin_name, out_dir)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
2
contrib/completions/_zoxide
generated
2
contrib/completions/_zoxide
generated
@ -130,4 +130,4 @@ _zoxide__remove_commands() {
|
||||
_describe -t commands 'zoxide remove commands' commands "$@"
|
||||
}
|
||||
|
||||
_zoxide "$@"
|
||||
_zoxide "$@"
|
||||
|
3
contrib/completions/_zoxide.ps1
generated
3
contrib/completions/_zoxide.ps1
generated
@ -12,7 +12,8 @@ Register-ArgumentCompleter -Native -CommandName 'zoxide' -ScriptBlock {
|
||||
$element = $commandElements[$i]
|
||||
if ($element -isnot [StringConstantExpressionAst] -or
|
||||
$element.StringConstantType -ne [StringConstantType]::BareWord -or
|
||||
$element.Value.StartsWith('-')) {
|
||||
$element.Value.StartsWith('-') -or
|
||||
$element.Value -eq $wordToComplete) {
|
||||
break
|
||||
}
|
||||
$element.Value
|
||||
|
4
contrib/completions/zoxide.bash
generated
4
contrib/completions/zoxide.bash
generated
@ -69,7 +69,7 @@ _zoxide() {
|
||||
fi
|
||||
case "${prev}" in
|
||||
--from)
|
||||
COMPREPLY=($(compgen -W "autojump z" -- "${cur}"))
|
||||
COMPREPLY=($(compgen -W "" -- "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
@ -91,7 +91,7 @@ _zoxide() {
|
||||
return 0
|
||||
;;
|
||||
--hook)
|
||||
COMPREPLY=($(compgen -W "none prompt pwd" -- "${cur}"))
|
||||
COMPREPLY=($(compgen -W "" -- "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
|
6
contrib/completions/zoxide.elv
generated
6
contrib/completions/zoxide.elv
generated
@ -2,11 +2,11 @@
|
||||
use builtin;
|
||||
use str;
|
||||
|
||||
set edit:completion:arg-completer[zoxide] = [@words]{
|
||||
fn spaces [n]{
|
||||
set edit:completion:arg-completer[zoxide] = {|@words|
|
||||
fn spaces {|n|
|
||||
builtin:repeat $n ' ' | str:join ''
|
||||
}
|
||||
fn cand [text desc]{
|
||||
fn cand {|text desc|
|
||||
edit:complex-candidate $text &display=$text' '(spaces (- 14 (wcswidth $text)))$desc
|
||||
}
|
||||
var command = 'zoxide'
|
||||
|
@ -9,15 +9,18 @@ directories you use most frequently, and uses a ranking algorithm to navigate
|
||||
to the best match.
|
||||
.SH USAGE
|
||||
.nf
|
||||
$ z foo # cd into highest ranked directory matching foo
|
||||
$ z foo bar # cd into highest ranked directory matching foo and bar
|
||||
z foo # cd into highest ranked directory matching foo
|
||||
z foo bar # cd into highest ranked directory matching foo and bar
|
||||
z foo / # cd into a subdirectory starting with foo
|
||||
.sp
|
||||
$ z ~/foo # z also works like a regular cd command
|
||||
$ z foo/ # cd into relative path
|
||||
$ z .. # cd one level up
|
||||
$ z - # cd into previous directory
|
||||
z ~/foo # z also works like a regular cd command
|
||||
z foo/ # cd into relative path
|
||||
z .. # cd one level up
|
||||
z - # cd into previous directory
|
||||
.sp
|
||||
$ zi foo # cd with interactive selection (using fzf)
|
||||
zi foo # cd with interactive selection (using fzf)
|
||||
.sp
|
||||
z foo<SPACE><TAB> # show interactive completions (bash 4.4+/fish/zsh only)
|
||||
.fi
|
||||
.SH SUBCOMMANDS
|
||||
.TP
|
||||
@ -62,7 +65,7 @@ T}
|
||||
\fB/Users/Alice/Library/Application Support\fR
|
||||
T}
|
||||
\fBWindows\fR|T{
|
||||
\fB{FOLDERID_RoamingAppData}\fR, eg. \fBC:\\Users\\Alice\\AppData\\Roaming\fR
|
||||
\fB%LOCALAPPDATA%\fR, eg. \fBC:\\Users\\Alice\\AppData\\Local\fR
|
||||
T}
|
||||
.TE
|
||||
.TP
|
||||
|
@ -1,8 +1,8 @@
|
||||
let
|
||||
rust = import (builtins.fetchTarball
|
||||
"https://github.com/oxalica/rust-overlay/archive/203dc4fc3fe2a5df1aa481a3fc8a1bb27074d677.tar.gz");
|
||||
"https://github.com/oxalica/rust-overlay/archive/46d8d20fce510c6a25fa66f36e31f207f6ea49e4.tar.gz");
|
||||
pkgs = import (builtins.fetchTarball
|
||||
"https://github.com/NixOS/nixpkgs/archive/eac07edbd20ed4908b98790ba299250b5527ecdf.tar.gz") {
|
||||
"https://github.com/NixOS/nixpkgs/archive/fae46e66a5df220327b45e0d7c27c6961cf922ce.tar.gz") {
|
||||
overlays = [ rust ];
|
||||
};
|
||||
in pkgs.mkShell {
|
||||
|
@ -1,26 +0,0 @@
|
||||
mod _app;
|
||||
mod add;
|
||||
mod import;
|
||||
mod init;
|
||||
mod query;
|
||||
mod remove;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
pub use crate::app::_app::*;
|
||||
|
||||
pub trait Run {
|
||||
fn run(&self) -> Result<()>;
|
||||
}
|
||||
|
||||
impl Run for App {
|
||||
fn run(&self) -> Result<()> {
|
||||
match self {
|
||||
App::Add(cmd) => cmd.run(),
|
||||
App::Import(cmd) => cmd.run(),
|
||||
App::Init(cmd) => cmd.run(),
|
||||
App::Query(cmd) => cmd.run(),
|
||||
App::Remove(cmd) => cmd.run(),
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use clap::{AppSettings, ArgEnum, Parser, ValueHint};
|
||||
use clap::{ArgEnum, Parser, ValueHint};
|
||||
|
||||
const ENV_HELP: &str = "ENVIRONMENT VARIABLES:
|
||||
_ZO_DATA_DIR Path for zoxide data files
|
||||
@ -16,11 +16,11 @@ const ENV_HELP: &str = "ENVIRONMENT VARIABLES:
|
||||
about,
|
||||
author,
|
||||
after_help = ENV_HELP,
|
||||
global_setting(AppSettings::DisableHelpSubcommand),
|
||||
global_setting(AppSettings::PropagateVersion),
|
||||
disable_help_subcommand = true,
|
||||
propagate_version = true,
|
||||
version = option_env!("ZOXIDE_VERSION").unwrap_or_default()
|
||||
)]
|
||||
pub enum App {
|
||||
pub enum Cmd {
|
||||
Add(Add),
|
||||
Import(Import),
|
||||
Init(Init),
|
@ -2,7 +2,7 @@ use std::path::Path;
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
|
||||
use crate::app::{Add, Run};
|
||||
use crate::cmd::{Add, Run};
|
||||
use crate::db::DatabaseFile;
|
||||
use crate::{config, util};
|
||||
|
@ -2,7 +2,7 @@ use std::fs;
|
||||
|
||||
use anyhow::{bail, Context, Result};
|
||||
|
||||
use crate::app::{Import, ImportFrom, Run};
|
||||
use crate::cmd::{Import, ImportFrom, Run};
|
||||
use crate::config;
|
||||
use crate::db::{Database, DatabaseFile, Dir};
|
||||
|
@ -3,7 +3,7 @@ use std::io::{self, Write};
|
||||
use anyhow::{Context, Result};
|
||||
use askama::Template;
|
||||
|
||||
use crate::app::{Init, InitShell, Run};
|
||||
use crate::cmd::{Init, InitShell, Run};
|
||||
use crate::config;
|
||||
use crate::error::BrokenPipeHandler;
|
||||
use crate::shell::{self, Opts};
|
26
src/cmd/mod.rs
Normal file
26
src/cmd/mod.rs
Normal file
@ -0,0 +1,26 @@
|
||||
mod _cmd;
|
||||
mod add;
|
||||
mod import;
|
||||
mod init;
|
||||
mod query;
|
||||
mod remove;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
pub use crate::cmd::_cmd::*;
|
||||
|
||||
pub trait Run {
|
||||
fn run(&self) -> Result<()>;
|
||||
}
|
||||
|
||||
impl Run for Cmd {
|
||||
fn run(&self) -> Result<()> {
|
||||
match self {
|
||||
Cmd::Add(cmd) => cmd.run(),
|
||||
Cmd::Import(cmd) => cmd.run(),
|
||||
Cmd::Init(cmd) => cmd.run(),
|
||||
Cmd::Query(cmd) => cmd.run(),
|
||||
Cmd::Remove(cmd) => cmd.run(),
|
||||
}
|
||||
}
|
||||
}
|
@ -2,11 +2,11 @@ use std::io::{self, Write};
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
|
||||
use crate::app::{Query, Run};
|
||||
use crate::cmd::{Query, Run};
|
||||
use crate::config;
|
||||
use crate::db::{Database, DatabaseFile};
|
||||
use crate::error::BrokenPipeHandler;
|
||||
use crate::fzf::Fzf;
|
||||
use crate::{config, util};
|
||||
use crate::util::{self, Fzf};
|
||||
|
||||
impl Run for Query {
|
||||
fn run(&self) -> Result<()> {
|
@ -2,10 +2,10 @@ use std::io::{self, Write};
|
||||
|
||||
use anyhow::{bail, Context, Result};
|
||||
|
||||
use crate::app::{Remove, Run};
|
||||
use crate::cmd::{Remove, Run};
|
||||
use crate::config;
|
||||
use crate::db::DatabaseFile;
|
||||
use crate::fzf::Fzf;
|
||||
use crate::{config, util};
|
||||
use crate::util::{self, Fzf};
|
||||
|
||||
impl Run for Remove {
|
||||
fn run(&self) -> Result<()> {
|
@ -2,13 +2,14 @@ mod dir;
|
||||
mod stream;
|
||||
|
||||
use std::fs;
|
||||
use std::io::{self, Write};
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
pub use dir::{Dir, DirList, Epoch, Rank};
|
||||
pub use stream::Stream;
|
||||
use tempfile::{NamedTempFile, PersistError};
|
||||
|
||||
use crate::util;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Database<'file> {
|
||||
@ -24,18 +25,8 @@ impl<'file> Database<'file> {
|
||||
}
|
||||
|
||||
let buffer = self.dirs.to_bytes()?;
|
||||
let mut file = NamedTempFile::new_in(self.data_dir)
|
||||
.with_context(|| format!("could not create temporary database in: {}", self.data_dir.display()))?;
|
||||
|
||||
// Preallocate enough space on the file, preventing copying later on. This optimization may
|
||||
// fail on some filesystems, but it is safe to ignore it and proceed.
|
||||
let _ = file.as_file().set_len(buffer.len() as _);
|
||||
file.write_all(&buffer)
|
||||
.with_context(|| format!("could not write to temporary database: {}", file.path().display()))?;
|
||||
|
||||
let path = db_path(&self.data_dir);
|
||||
persist(file, &path).with_context(|| format!("could not replace database: {}", path.display()))?;
|
||||
|
||||
util::write(&path, &buffer).context("could not write to database")?;
|
||||
self.modified = false;
|
||||
Ok(())
|
||||
}
|
||||
@ -120,44 +111,6 @@ impl<'file> Database<'file> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn persist<P: AsRef<Path>>(file: NamedTempFile, path: P) -> Result<(), PersistError> {
|
||||
file.persist(path)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn persist<P: AsRef<Path>>(mut file: NamedTempFile, path: P) -> Result<(), PersistError> {
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use rand::distributions::{Distribution, Uniform};
|
||||
use rand::rngs::SmallRng;
|
||||
use rand::SeedableRng;
|
||||
|
||||
// File renames on Windows are not atomic and sometimes fail with `PermissionDenied`. This is
|
||||
// extremely unlikely unless it's running in a loop on multiple threads. Nevertheless, we guard
|
||||
// against it by retrying the rename a fixed number of times.
|
||||
const MAX_TRIES: usize = 10;
|
||||
let mut rng = None;
|
||||
|
||||
for _ in 0..MAX_TRIES {
|
||||
match file.persist(&path) {
|
||||
Ok(_) => break,
|
||||
Err(e) if e.error.kind() == io::ErrorKind::PermissionDenied => {
|
||||
let mut rng = rng.get_or_insert_with(SmallRng::from_entropy);
|
||||
let between = Uniform::from(50..150);
|
||||
let duration = Duration::from_millis(between.sample(&mut rng));
|
||||
thread::sleep(duration);
|
||||
file = e.file;
|
||||
}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub struct DatabaseFile {
|
||||
buffer: Vec<u8>,
|
||||
data_dir: PathBuf,
|
||||
|
15
src/error.rs
15
src/error.rs
@ -1,19 +1,20 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::io;
|
||||
|
||||
use anyhow::{bail, Context, Result};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
#[error("could not find fzf, is it installed?")]
|
||||
pub struct FzfNotFound;
|
||||
|
||||
/// Custom error type for early exit.
|
||||
#[derive(Debug, Error)]
|
||||
#[error("")]
|
||||
#[derive(Debug)]
|
||||
pub struct SilentExit {
|
||||
pub code: i32,
|
||||
}
|
||||
|
||||
impl Display for SilentExit {
|
||||
fn fmt(&self, _: &mut Formatter<'_>) -> fmt::Result {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait BrokenPipeHandler {
|
||||
fn pipe_exit(self, device: &str) -> Result<()>;
|
||||
}
|
||||
|
70
src/fzf.rs
70
src/fzf.rs
@ -1,70 +0,0 @@
|
||||
use std::io::{self, Read};
|
||||
use std::mem;
|
||||
use std::process::{Child, ChildStdin, Stdio};
|
||||
|
||||
use anyhow::{bail, Context, Result};
|
||||
|
||||
use crate::error::{FzfNotFound, SilentExit};
|
||||
use crate::{config, util};
|
||||
|
||||
pub struct Fzf {
|
||||
child: Child,
|
||||
}
|
||||
|
||||
impl Fzf {
|
||||
pub fn new(multiple: bool) -> Result<Self> {
|
||||
let bin = if cfg!(windows) { "fzf.exe" } else { "fzf" };
|
||||
let mut command = util::get_command(bin).map_err(|_| FzfNotFound)?;
|
||||
if multiple {
|
||||
command.arg("-m");
|
||||
}
|
||||
command.arg("-n2..").stdin(Stdio::piped()).stdout(Stdio::piped());
|
||||
if let Some(fzf_opts) = config::fzf_opts() {
|
||||
command.env("FZF_DEFAULT_OPTS", fzf_opts);
|
||||
} else {
|
||||
command.args(&[
|
||||
"--bind=ctrl-z:ignore",
|
||||
"--exit-0",
|
||||
"--height=40%",
|
||||
"--inline-info",
|
||||
"--no-sort",
|
||||
"--reverse",
|
||||
"--select-1",
|
||||
]);
|
||||
if cfg!(unix) {
|
||||
command.arg("--preview=ls -p {2..}");
|
||||
}
|
||||
}
|
||||
|
||||
let child = match command.spawn() {
|
||||
Ok(child) => child,
|
||||
Err(e) if e.kind() == io::ErrorKind::NotFound => bail!(FzfNotFound),
|
||||
Err(e) => Err(e).context("could not launch fzf")?,
|
||||
};
|
||||
|
||||
Ok(Fzf { child })
|
||||
}
|
||||
|
||||
pub fn stdin(&mut self) -> &mut ChildStdin {
|
||||
self.child.stdin.as_mut().unwrap()
|
||||
}
|
||||
|
||||
pub fn select(mut self) -> Result<String> {
|
||||
// Drop stdin to prevent deadlock.
|
||||
mem::drop(self.child.stdin.take());
|
||||
|
||||
let mut stdout = self.child.stdout.take().unwrap();
|
||||
let mut output = String::new();
|
||||
stdout.read_to_string(&mut output).context("failed to read from fzf")?;
|
||||
|
||||
let status = self.child.wait().context("wait failed on fzf")?;
|
||||
match status.code() {
|
||||
Some(0) => Ok(output),
|
||||
Some(1) => bail!("no match found"),
|
||||
Some(2) => bail!("fzf returned an error"),
|
||||
Some(code @ 130) => bail!(SilentExit { code }),
|
||||
Some(128..=254) | None => bail!("fzf was terminated"),
|
||||
_ => bail!("fzf returned an unknown error"),
|
||||
}
|
||||
}
|
||||
}
|
13
src/main.rs
13
src/main.rs
@ -1,8 +1,13 @@
|
||||
mod app;
|
||||
#![allow(clippy::single_component_path_imports)]
|
||||
|
||||
// rstest_reuse must be imported at the top of the crate.
|
||||
#[cfg(test)]
|
||||
use rstest_reuse;
|
||||
|
||||
mod cmd;
|
||||
mod config;
|
||||
mod db;
|
||||
mod error;
|
||||
mod fzf;
|
||||
mod shell;
|
||||
mod util;
|
||||
|
||||
@ -11,7 +16,7 @@ use std::{env, process};
|
||||
|
||||
use clap::Parser;
|
||||
|
||||
use crate::app::{App, Run};
|
||||
use crate::cmd::{Cmd, Run};
|
||||
use crate::error::SilentExit;
|
||||
|
||||
pub fn main() {
|
||||
@ -19,7 +24,7 @@ pub fn main() {
|
||||
env::remove_var("RUST_LIB_BACKTRACE");
|
||||
env::remove_var("RUST_BACKTRACE");
|
||||
|
||||
if let Err(e) = App::parse().run() {
|
||||
if let Err(e) = Cmd::parse().run() {
|
||||
match e.downcast::<SilentExit>() {
|
||||
Ok(SilentExit { code }) => process::exit(code),
|
||||
Err(e) => {
|
||||
|
172
src/shell.rs
172
src/shell.rs
@ -1,4 +1,4 @@
|
||||
use crate::app::InitHook;
|
||||
use crate::cmd::InitHook;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct Opts<'a> {
|
||||
@ -32,22 +32,28 @@ make_template!(Powershell, "powershell.txt");
|
||||
make_template!(Xonsh, "xonsh.txt");
|
||||
make_template!(Zsh, "zsh.txt");
|
||||
|
||||
#[cfg(feature = "nix")]
|
||||
#[cfg(feature = "nix-dev")]
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use askama::Template;
|
||||
use assert_cmd::Command;
|
||||
use rstest::rstest;
|
||||
use rstest_reuse::{apply, template};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[template]
|
||||
#[rstest]
|
||||
fn bash_bash(
|
||||
fn opts(
|
||||
#[values(None, Some("z"))] cmd: Option<&str>,
|
||||
#[values(InitHook::None, InitHook::Prompt, InitHook::Pwd)] hook: InitHook,
|
||||
#[values(false, true)] echo: bool,
|
||||
#[values(false, true)] resolve_symlinks: bool,
|
||||
) {
|
||||
}
|
||||
|
||||
#[apply(opts)]
|
||||
fn bash_bash(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
|
||||
let opts = Opts { cmd, hook, echo, resolve_symlinks };
|
||||
let source = Bash(&opts).render().unwrap();
|
||||
Command::new("bash")
|
||||
@ -58,13 +64,8 @@ mod tests {
|
||||
.stderr("");
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn bash_shellcheck(
|
||||
#[values(None, Some("z"))] cmd: Option<&str>,
|
||||
#[values(InitHook::None, InitHook::Prompt, InitHook::Pwd)] hook: InitHook,
|
||||
#[values(false, true)] echo: bool,
|
||||
#[values(false, true)] resolve_symlinks: bool,
|
||||
) {
|
||||
#[apply(opts)]
|
||||
fn bash_shellcheck(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
|
||||
let opts = Opts { cmd, hook, echo, resolve_symlinks };
|
||||
let source = Bash(&opts).render().unwrap();
|
||||
|
||||
@ -77,13 +78,8 @@ mod tests {
|
||||
.stderr("");
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn bash_shfmt(
|
||||
#[values(None, Some("z"))] cmd: Option<&str>,
|
||||
#[values(InitHook::None, InitHook::Prompt, InitHook::Pwd)] hook: InitHook,
|
||||
#[values(false, true)] echo: bool,
|
||||
#[values(false, true)] resolve_symlinks: bool,
|
||||
) {
|
||||
#[apply(opts)]
|
||||
fn bash_shfmt(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
|
||||
let opts = Opts { cmd, hook, echo, resolve_symlinks };
|
||||
let mut source = Bash(&opts).render().unwrap();
|
||||
source.push('\n');
|
||||
@ -97,13 +93,8 @@ mod tests {
|
||||
.stderr("");
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn elvish_elvish(
|
||||
#[values(None, Some("z"))] cmd: Option<&str>,
|
||||
#[values(InitHook::None, InitHook::Prompt, InitHook::Pwd)] hook: InitHook,
|
||||
#[values(false, true)] echo: bool,
|
||||
#[values(false, true)] resolve_symlinks: bool,
|
||||
) {
|
||||
#[apply(opts)]
|
||||
fn elvish_elvish(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
|
||||
let opts = Opts { cmd, hook, echo, resolve_symlinks };
|
||||
let mut source = String::new();
|
||||
|
||||
@ -117,13 +108,8 @@ mod tests {
|
||||
Command::new("elvish").args(&["-c", &source, "-norc"]).assert().success().stdout("").stderr("");
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn fish_fish(
|
||||
#[values(None, Some("z"))] cmd: Option<&str>,
|
||||
#[values(InitHook::None, InitHook::Prompt, InitHook::Pwd)] hook: InitHook,
|
||||
#[values(false, true)] echo: bool,
|
||||
#[values(false, true)] resolve_symlinks: bool,
|
||||
) {
|
||||
#[apply(opts)]
|
||||
fn fish_fish(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
|
||||
let opts = Opts { cmd, hook, echo, resolve_symlinks };
|
||||
let source = Fish(&opts).render().unwrap();
|
||||
|
||||
@ -139,13 +125,8 @@ mod tests {
|
||||
.stderr("");
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn fish_fishindent(
|
||||
#[values(None, Some("z"))] cmd: Option<&str>,
|
||||
#[values(InitHook::None, InitHook::Prompt, InitHook::Pwd)] hook: InitHook,
|
||||
#[values(false, true)] echo: bool,
|
||||
#[values(false, true)] resolve_symlinks: bool,
|
||||
) {
|
||||
#[apply(opts)]
|
||||
fn fish_fishindent(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
|
||||
let opts = Opts { cmd, hook, echo, resolve_symlinks };
|
||||
let mut source = Fish(&opts).render().unwrap();
|
||||
source.push('\n');
|
||||
@ -162,13 +143,8 @@ mod tests {
|
||||
.stderr("");
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn nushell_nushell(
|
||||
#[values(None, Some("z"))] cmd: Option<&str>,
|
||||
#[values(InitHook::None, InitHook::Prompt, InitHook::Pwd)] hook: InitHook,
|
||||
#[values(false, true)] echo: bool,
|
||||
#[values(false, true)] resolve_symlinks: bool,
|
||||
) {
|
||||
#[apply(opts)]
|
||||
fn nushell_nushell(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
|
||||
let opts = Opts { cmd, hook, echo, resolve_symlinks };
|
||||
let source = Nushell(&opts).render().unwrap();
|
||||
|
||||
@ -183,13 +159,8 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn posix_bash(
|
||||
#[values(None, Some("z"))] cmd: Option<&str>,
|
||||
#[values(InitHook::None, InitHook::Prompt, InitHook::Pwd)] hook: InitHook,
|
||||
#[values(false, true)] echo: bool,
|
||||
#[values(false, true)] resolve_symlinks: bool,
|
||||
) {
|
||||
#[apply(opts)]
|
||||
fn posix_bash(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
|
||||
let opts = Opts { cmd, hook, echo, resolve_symlinks };
|
||||
let source = Posix(&opts).render().unwrap();
|
||||
|
||||
@ -203,13 +174,8 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn posix_dash(
|
||||
#[values(None, Some("z"))] cmd: Option<&str>,
|
||||
#[values(InitHook::None, InitHook::Prompt, InitHook::Pwd)] hook: InitHook,
|
||||
#[values(false, true)] echo: bool,
|
||||
#[values(false, true)] resolve_symlinks: bool,
|
||||
) {
|
||||
#[apply(opts)]
|
||||
fn posix_dash(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
|
||||
let opts = Opts { cmd, hook, echo, resolve_symlinks };
|
||||
let source = Posix(&opts).render().unwrap();
|
||||
|
||||
@ -219,13 +185,8 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn posix_shellcheck_(
|
||||
#[values(None, Some("z"))] cmd: Option<&str>,
|
||||
#[values(InitHook::None, InitHook::Prompt, InitHook::Pwd)] hook: InitHook,
|
||||
#[values(false, true)] echo: bool,
|
||||
#[values(false, true)] resolve_symlinks: bool,
|
||||
) {
|
||||
#[apply(opts)]
|
||||
fn posix_shellcheck_(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
|
||||
let opts = Opts { cmd, hook, echo, resolve_symlinks };
|
||||
let source = Posix(&opts).render().unwrap();
|
||||
|
||||
@ -238,13 +199,8 @@ mod tests {
|
||||
.stderr("");
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn posix_shfmt(
|
||||
#[values(None, Some("z"))] cmd: Option<&str>,
|
||||
#[values(InitHook::None, InitHook::Prompt, InitHook::Pwd)] hook: InitHook,
|
||||
#[values(false, true)] echo: bool,
|
||||
#[values(false, true)] resolve_symlinks: bool,
|
||||
) {
|
||||
#[apply(opts)]
|
||||
fn posix_shfmt(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
|
||||
let opts = Opts { cmd, hook, echo, resolve_symlinks };
|
||||
let mut source = Posix(&opts).render().unwrap();
|
||||
source.push('\n');
|
||||
@ -258,13 +214,8 @@ mod tests {
|
||||
.stderr("");
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn powershell_pwsh(
|
||||
#[values(None, Some("z"))] cmd: Option<&str>,
|
||||
#[values(InitHook::None, InitHook::Prompt, InitHook::Pwd)] hook: InitHook,
|
||||
#[values(false, true)] echo: bool,
|
||||
#[values(false, true)] resolve_symlinks: bool,
|
||||
) {
|
||||
#[apply(opts)]
|
||||
fn powershell_pwsh(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
|
||||
let opts = Opts { cmd, hook, echo, resolve_symlinks };
|
||||
let mut source = "Set-StrictMode -Version latest\n".to_string();
|
||||
Powershell(&opts).render_into(&mut source).unwrap();
|
||||
@ -277,13 +228,8 @@ mod tests {
|
||||
.stderr("");
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn xonsh_black(
|
||||
#[values(None, Some("z"))] cmd: Option<&str>,
|
||||
#[values(InitHook::None, InitHook::Prompt, InitHook::Pwd)] hook: InitHook,
|
||||
#[values(false, true)] echo: bool,
|
||||
#[values(false, true)] resolve_symlinks: bool,
|
||||
) {
|
||||
#[apply(opts)]
|
||||
fn xonsh_black(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
|
||||
let opts = Opts { cmd, hook, echo, resolve_symlinks };
|
||||
let mut source = Xonsh(&opts).render().unwrap();
|
||||
source.push('\n');
|
||||
@ -291,40 +237,30 @@ mod tests {
|
||||
Command::new("black").args(&["--check", "--diff", "-"]).write_stdin(source).assert().success().stdout("");
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn xonsh_mypy(
|
||||
#[values(None, Some("z"))] cmd: Option<&str>,
|
||||
#[values(InitHook::None, InitHook::Prompt, InitHook::Pwd)] hook: InitHook,
|
||||
#[values(false, true)] echo: bool,
|
||||
#[values(false, true)] resolve_symlinks: bool,
|
||||
) {
|
||||
#[apply(opts)]
|
||||
fn xonsh_mypy(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
|
||||
let opts = Opts { cmd, hook, echo, resolve_symlinks };
|
||||
let source = Xonsh(&opts).render().unwrap();
|
||||
|
||||
Command::new("mypy").args(&["--command", &source, "--strict"]).assert().success().stderr("");
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn xonsh_pylint(
|
||||
#[values(None, Some("z"))] cmd: Option<&str>,
|
||||
#[values(InitHook::None, InitHook::Prompt, InitHook::Pwd)] hook: InitHook,
|
||||
#[values(false, true)] echo: bool,
|
||||
#[values(false, true)] resolve_symlinks: bool,
|
||||
) {
|
||||
#[apply(opts)]
|
||||
fn xonsh_pylint(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
|
||||
let opts = Opts { cmd, hook, echo, resolve_symlinks };
|
||||
let mut source = Xonsh(&opts).render().unwrap();
|
||||
source.push('\n');
|
||||
|
||||
Command::new("pylint").args(&["--from-stdin", "zoxide"]).write_stdin(source).assert().success().stderr("");
|
||||
Command::new("pylint")
|
||||
.args(&["--from-stdin", "--persistent=n", "zoxide"])
|
||||
.write_stdin(source)
|
||||
.assert()
|
||||
.success()
|
||||
.stderr("");
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn xonsh_xonsh(
|
||||
#[values(None, Some("z"))] cmd: Option<&str>,
|
||||
#[values(InitHook::None, InitHook::Prompt, InitHook::Pwd)] hook: InitHook,
|
||||
#[values(false, true)] echo: bool,
|
||||
#[values(false, true)] resolve_symlinks: bool,
|
||||
) {
|
||||
#[apply(opts)]
|
||||
fn xonsh_xonsh(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
|
||||
let opts = Opts { cmd, hook, echo, resolve_symlinks };
|
||||
let source = Xonsh(&opts).render().unwrap();
|
||||
|
||||
@ -340,13 +276,8 @@ mod tests {
|
||||
.stderr("");
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn zsh_shellcheck(
|
||||
#[values(None, Some("z"))] cmd: Option<&str>,
|
||||
#[values(InitHook::None, InitHook::Prompt, InitHook::Pwd)] hook: InitHook,
|
||||
#[values(false, true)] echo: bool,
|
||||
#[values(false, true)] resolve_symlinks: bool,
|
||||
) {
|
||||
#[apply(opts)]
|
||||
fn zsh_shellcheck(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
|
||||
let opts = Opts { cmd, hook, echo, resolve_symlinks };
|
||||
let source = Zsh(&opts).render().unwrap();
|
||||
|
||||
@ -360,13 +291,8 @@ mod tests {
|
||||
.stderr("");
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn zsh_zsh(
|
||||
#[values(None, Some("z"))] cmd: Option<&str>,
|
||||
#[values(InitHook::None, InitHook::Prompt, InitHook::Pwd)] hook: InitHook,
|
||||
#[values(false, true)] echo: bool,
|
||||
#[values(false, true)] resolve_symlinks: bool,
|
||||
) {
|
||||
#[apply(opts)]
|
||||
fn zsh_zsh(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
|
||||
let opts = Opts { cmd, hook, echo, resolve_symlinks };
|
||||
let source = Zsh(&opts).render().unwrap();
|
||||
|
||||
|
163
src/util.rs
163
src/util.rs
@ -1,11 +1,172 @@
|
||||
use std::env;
|
||||
use std::fs::{self, File, OpenOptions};
|
||||
use std::io::{self, Read, Write};
|
||||
use std::mem;
|
||||
use std::path::{Component, Path, PathBuf};
|
||||
use std::process::Command;
|
||||
use std::process::{Child, ChildStdin, Stdio};
|
||||
use std::time::SystemTime;
|
||||
|
||||
use anyhow::{bail, Context, Result};
|
||||
use anyhow::{anyhow, bail, Context, Result};
|
||||
|
||||
use crate::config;
|
||||
use crate::db::Epoch;
|
||||
use crate::error::SilentExit;
|
||||
|
||||
pub struct Fzf {
|
||||
child: Child,
|
||||
}
|
||||
|
||||
impl Fzf {
|
||||
const ERR_NOT_FOUND: &'static str = "could not find fzf, is it installed?";
|
||||
|
||||
pub fn new(multiple: bool) -> Result<Self> {
|
||||
let bin = if cfg!(windows) { "fzf.exe" } else { "fzf" };
|
||||
let mut command = get_command(bin).map_err(|_| anyhow!(Self::ERR_NOT_FOUND))?;
|
||||
if multiple {
|
||||
command.arg("-m");
|
||||
}
|
||||
command.arg("-n2..").stdin(Stdio::piped()).stdout(Stdio::piped());
|
||||
if let Some(fzf_opts) = config::fzf_opts() {
|
||||
command.env("FZF_DEFAULT_OPTS", fzf_opts);
|
||||
} else {
|
||||
command.args(&[
|
||||
// Search result
|
||||
"--no-sort",
|
||||
// Interface
|
||||
"--keep-right",
|
||||
// Layout
|
||||
"--height=40%",
|
||||
"--info=inline",
|
||||
"--layout=reverse",
|
||||
// Scripting
|
||||
"--exit-0",
|
||||
"--select-1",
|
||||
// Key/Event bindings
|
||||
"--bind=ctrl-z:ignore",
|
||||
]);
|
||||
if cfg!(unix) {
|
||||
command.env("SHELL", "sh");
|
||||
command.arg(r"--preview=\command -p ls -p {2..}");
|
||||
}
|
||||
}
|
||||
|
||||
let child = match command.spawn() {
|
||||
Ok(child) => child,
|
||||
Err(e) if e.kind() == io::ErrorKind::NotFound => bail!(Self::ERR_NOT_FOUND),
|
||||
Err(e) => Err(e).context("could not launch fzf")?,
|
||||
};
|
||||
|
||||
Ok(Fzf { child })
|
||||
}
|
||||
|
||||
pub fn stdin(&mut self) -> &mut ChildStdin {
|
||||
self.child.stdin.as_mut().unwrap()
|
||||
}
|
||||
|
||||
pub fn select(mut self) -> Result<String> {
|
||||
// Drop stdin to prevent deadlock.
|
||||
mem::drop(self.child.stdin.take());
|
||||
|
||||
let mut stdout = self.child.stdout.take().unwrap();
|
||||
let mut output = String::new();
|
||||
stdout.read_to_string(&mut output).context("failed to read from fzf")?;
|
||||
|
||||
let status = self.child.wait().context("wait failed on fzf")?;
|
||||
match status.code() {
|
||||
Some(0) => Ok(output),
|
||||
Some(1) => bail!("no match found"),
|
||||
Some(2) => bail!("fzf returned an error"),
|
||||
Some(code @ 130) => bail!(SilentExit { code }),
|
||||
Some(128..=254) | None => bail!("fzf was terminated"),
|
||||
_ => bail!("fzf returned an unknown error"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Similar to [`fs::write`], but atomic (best effort on Windows).
|
||||
pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> Result<()> {
|
||||
let path = path.as_ref();
|
||||
let contents = contents.as_ref();
|
||||
let dir = path.parent().unwrap();
|
||||
|
||||
// Create a tmpfile.
|
||||
let (mut tmp_file, tmp_path) = tmpfile(dir)?;
|
||||
let result = (|| {
|
||||
// Write to the tmpfile.
|
||||
let _ = tmp_file.set_len(contents.len() as u64);
|
||||
tmp_file.write_all(contents).with_context(|| format!("could not write to file: {}", tmp_path.display()))?;
|
||||
|
||||
// Set the owner of the tmpfile (UNIX only).
|
||||
#[cfg(unix)]
|
||||
if let Ok(metadata) = path.metadata() {
|
||||
use nix::unistd::{self, Gid, Uid};
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
|
||||
let uid = Uid::from_raw(metadata.uid());
|
||||
let gid = Gid::from_raw(metadata.gid());
|
||||
let _ = unistd::fchown(tmp_file.as_raw_fd(), Some(uid), Some(gid));
|
||||
}
|
||||
|
||||
// Close and rename the tmpfile.
|
||||
mem::drop(tmp_file);
|
||||
rename(&tmp_path, path)
|
||||
})();
|
||||
// In case of an error, delete the tmpfile.
|
||||
if result.is_err() {
|
||||
let _ = fs::remove_file(&tmp_path);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
/// Atomically create a tmpfile in the given directory.
|
||||
fn tmpfile<P: AsRef<Path>>(dir: P) -> Result<(File, PathBuf)> {
|
||||
const MAX_ATTEMPTS: usize = 5;
|
||||
const TMP_NAME_LEN: usize = 16;
|
||||
let dir = dir.as_ref();
|
||||
|
||||
let mut attempts = 0;
|
||||
loop {
|
||||
attempts += 1;
|
||||
|
||||
// Generate a random name for the tmpfile.
|
||||
let mut name = String::with_capacity(TMP_NAME_LEN);
|
||||
name.push_str("tmp_");
|
||||
while name.len() < TMP_NAME_LEN {
|
||||
name.push(fastrand::alphanumeric());
|
||||
}
|
||||
let path = dir.join(name);
|
||||
|
||||
// Atomically create the tmpfile.
|
||||
match OpenOptions::new().write(true).create_new(true).open(&path) {
|
||||
Ok(file) => break Ok((file, path)),
|
||||
Err(e) if e.kind() == io::ErrorKind::AlreadyExists && attempts < MAX_ATTEMPTS => (),
|
||||
Err(e) => break Err(e).with_context(|| format!("could not create file: {}", path.display())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Similar to [`fs::rename`], but retries on Windows.
|
||||
fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> Result<()> {
|
||||
const MAX_ATTEMPTS: usize = 5;
|
||||
let from = from.as_ref();
|
||||
let to = to.as_ref();
|
||||
|
||||
if cfg!(windows) {
|
||||
let mut attempts = 0;
|
||||
loop {
|
||||
attempts += 1;
|
||||
match fs::rename(from, to) {
|
||||
Err(e) if e.kind() == io::ErrorKind::PermissionDenied && attempts < MAX_ATTEMPTS => (),
|
||||
result => break result,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fs::rename(from, to)
|
||||
}
|
||||
.with_context(|| format!("could not rename file: {} -> {}", from.display(), to.display()))
|
||||
}
|
||||
|
||||
pub fn canonicalize<P: AsRef<Path>>(path: &P) -> Result<PathBuf> {
|
||||
dunce::canonicalize(path).with_context(|| format!("could not resolve path: {}", path.as_ref().display()))
|
||||
|
@ -17,7 +17,7 @@ function __zoxide_pwd() {
|
||||
# cd + custom logic based on the value of _ZO_ECHO.
|
||||
function __zoxide_cd() {
|
||||
# shellcheck disable=SC2164
|
||||
\builtin cd "$@" {%- if echo %} && __zoxide_pwd {%- endif %}
|
||||
\builtin cd -- "$@" {%- if echo %} && __zoxide_pwd {%- endif %}
|
||||
}
|
||||
|
||||
{{ section }}
|
||||
@ -115,11 +115,12 @@ function {{cmd}}i() {
|
||||
}
|
||||
|
||||
# Load completions.
|
||||
# - Bash 4.0+ is needed to use `mapfile`.
|
||||
# - Bash 4.4+ is required to use `@Q`.
|
||||
# - Completions require line editing. Since Bash supports only two modes of
|
||||
# line editing (`vim` and `emacs`), we check if either them is enabled.
|
||||
# - Completions don't work on `dumb` terminals.
|
||||
if [[ ${BASH_VERSINFO:-0} -ge 4 && :"${SHELLOPTS}": =~ :(vi|emacs): && ${TERM} != 'dumb' ]]; then
|
||||
if [[ ${BASH_VERSINFO[0]:-0} -eq 4 && ${BASH_VERSINFO[1]:-0} -ge 4 || ${BASH_VERSINFO[0]:-0} -ge 5 ]] &&
|
||||
[[ :"${SHELLOPTS}": =~ :(vi|emacs): && ${TERM} != 'dumb' ]]; then
|
||||
# Use `printf '\e[5n'` to redraw line after fzf closes.
|
||||
\builtin bind '"\e[0n": redraw-current-line' &>/dev/null
|
||||
|
||||
|
@ -9,7 +9,7 @@ use path
|
||||
#
|
||||
|
||||
# cd + custom logic based on the value of _ZO_ECHO.
|
||||
fn __zoxide_cd [path]{
|
||||
fn __zoxide_cd {|path|
|
||||
builtin:cd $path
|
||||
{%- if echo %}
|
||||
builtin:echo $pwd
|
||||
@ -22,7 +22,7 @@ fn __zoxide_cd [path]{
|
||||
|
||||
# Initialize hook to track previous directory.
|
||||
var oldpwd = $builtin:pwd
|
||||
set builtin:before-chdir = [$@builtin:before-chdir [_]{ edit:add-var oldpwd $builtin:pwd }]
|
||||
set builtin:before-chdir = [$@builtin:before-chdir {|_| edit:add-var oldpwd $builtin:pwd }]
|
||||
|
||||
# Initialize hook to add directories to zoxide.
|
||||
{%- if hook == InitHook::None %}
|
||||
@ -32,9 +32,9 @@ set builtin:before-chdir = [$@builtin:before-chdir [_]{ edit:add-var oldpwd $bui
|
||||
if (builtin:not (builtin:eq $E:__zoxide_shlvl $E:SHLVL)) {
|
||||
set E:__zoxide_shlvl = $E:SHLVL
|
||||
{%- if hook == InitHook::Prompt %}
|
||||
set edit:before-readline = [$@edit:before-readline []{ zoxide add -- $pwd }]
|
||||
set edit:before-readline = [$@edit:before-readline {|| zoxide add -- $pwd }]
|
||||
{%- else if hook == InitHook::Pwd %}
|
||||
set builtin:after-chdir = [$@builtin:after-chdir [_]{ zoxide add -- $pwd }]
|
||||
set builtin:after-chdir = [$@builtin:after-chdir {|_| zoxide add -- $pwd }]
|
||||
{%- endif %}
|
||||
}
|
||||
|
||||
@ -46,7 +46,7 @@ if (builtin:not (builtin:eq $E:__zoxide_shlvl $E:SHLVL)) {
|
||||
#
|
||||
|
||||
# Jump to a directory using only keywords.
|
||||
fn __zoxide_z [@rest]{
|
||||
fn __zoxide_z {|@rest|
|
||||
if (builtin:eq [] $rest) {
|
||||
__zoxide_cd ~
|
||||
} elif (builtin:eq [-] $rest) {
|
||||
@ -66,7 +66,7 @@ fn __zoxide_z [@rest]{
|
||||
edit:add-var __zoxide_z~ $__zoxide_z~
|
||||
|
||||
# Jump to a directory using interactive search.
|
||||
fn __zoxide_zi [@rest]{
|
||||
fn __zoxide_zi {|@rest|
|
||||
var path
|
||||
try {
|
||||
set path = (zoxide query -i -- $@rest)
|
||||
@ -90,12 +90,12 @@ edit:add-var {{cmd}}i~ $__zoxide_zi~
|
||||
# Load completions.
|
||||
{# zoxide-based completions are currently not possible, because Elvish only
|
||||
# prints a completion if the current token is a prefix of it. -#}
|
||||
fn __zoxide_z_complete [@rest]{
|
||||
fn __zoxide_z_complete {|@rest|
|
||||
if (!= (builtin:count $rest) 2) {
|
||||
builtin:return
|
||||
}
|
||||
edit:complete-filename $rest[1] |
|
||||
builtin:each [completion]{
|
||||
builtin:each {|completion|
|
||||
var dir = $completion[stem]
|
||||
if (path:is-dir $dir) {
|
||||
builtin:put $dir
|
||||
@ -116,4 +116,4 @@ set edit:completion:arg-completer[{{cmd}}] = $__zoxide_z_complete~
|
||||
#
|
||||
# eval (zoxide init elvish | slurp)
|
||||
#
|
||||
# Note: zoxide only supports elvish v0.16.0 and above.
|
||||
# Note: zoxide only supports elvish v0.17.0 and above.
|
||||
|
@ -74,8 +74,8 @@ end
|
||||
|
||||
# Completions for `z`.
|
||||
function __zoxide_z_complete
|
||||
set -l tokens (commandline -op)
|
||||
set -l curr_tokens (commandline -cop)
|
||||
set -l tokens (commandline --current-process --tokenize)
|
||||
set -l curr_tokens (commandline --cut-at-cursor --current-process --tokenize)
|
||||
|
||||
if test (count $tokens) -le 2 -a (count $curr_tokens) -eq 1
|
||||
# If there are < 2 arguments, use `cd` completions.
|
||||
@ -84,8 +84,8 @@ function __zoxide_z_complete
|
||||
# If the last argument is empty, use interactive selection.
|
||||
set -l query $tokens[2..-1]
|
||||
set -l result (zoxide query -i -- $query)
|
||||
and commandline -p "$tokens[1] "(string escape $result)
|
||||
commandline -f repaint
|
||||
commandline --current-process "$tokens[1] "(string escape $result)
|
||||
commandline --function repaint
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -17,7 +17,7 @@ function __zoxide_pwd() {
|
||||
# cd + custom logic based on the value of _ZO_ECHO.
|
||||
function __zoxide_cd() {
|
||||
# shellcheck disable=SC2164
|
||||
\builtin cd "$@" {%- if echo %} && __zoxide_pwd {%- endif %}
|
||||
\builtin cd -- "$@" {%- if echo %} && __zoxide_pwd {%- endif %}
|
||||
}
|
||||
|
||||
{{ section }}
|
||||
|
@ -1,5 +1,5 @@
|
||||
//! Test clap generated completions.
|
||||
#![cfg(feature = "nix")]
|
||||
#![cfg(feature = "nix-dev")]
|
||||
|
||||
use assert_cmd::Command;
|
||||
|
||||
|
@ -6,6 +6,6 @@ publish = false
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.32"
|
||||
clap = { version = "=3.0.0-rc.8", features = ["derive"] }
|
||||
clap = { version = "3.1.0", features = ["derive"] }
|
||||
ignore = "0.4.18"
|
||||
shell-words = "1.0.0"
|
||||
|
Loading…
Reference in New Issue
Block a user