Merge branch 'main' into install

This commit is contained in:
Ajeet D'Souza 2022-03-09 20:02:08 +05:30
commit 9348fb3710
33 changed files with 553 additions and 546 deletions

View File

@ -3,6 +3,3 @@ version = 1
[[analyzers]]
name = "rust"
enabled = true
[analyzers.meta]
edition = 2018

View File

@ -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' }}

View File

@ -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
View File

@ -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",
]

View File

@ -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

View File

@ -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

View File

@ -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(())
}

View File

@ -130,4 +130,4 @@ _zoxide__remove_commands() {
_describe -t commands 'zoxide remove commands' commands "$@"
}
_zoxide "$@"
_zoxide "$@"

View File

@ -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

View File

@ -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
;;
*)

View File

@ -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'

View File

@ -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

View File

@ -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 {

View File

@ -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(),
}
}
}

View File

@ -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),

View File

@ -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};

View File

@ -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};

View File

@ -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
View 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(),
}
}
}

View File

@ -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<()> {

View File

@ -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<()> {

View File

@ -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,

View File

@ -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<()>;
}

View File

@ -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"),
}
}
}

View File

@ -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) => {

View File

@ -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();

View File

@ -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()))

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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 }}

View File

@ -1,5 +1,5 @@
//! Test clap generated completions.
#![cfg(feature = "nix")]
#![cfg(feature = "nix-dev")]
use assert_cmd::Command;

View File

@ -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"