Merge branch 'main' into query-i-s

This commit is contained in:
Ajeet D'Souza 2022-04-13 16:59:47 +05:30
commit 086867f335
41 changed files with 585 additions and 549 deletions

View File

@ -10,9 +10,12 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
matrix: matrix:
os: [ubuntu-latest, macos-latest, windows-latest] # FIXME: Enable macos-latest when this is merged: https://nixpk.gs/pr-tracker.html?pr=163924
os: [ubuntu-latest, windows-latest]
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with:
fetch-depth: 0
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
if: ${{ matrix.os == 'windows-latest' }} if: ${{ matrix.os == 'windows-latest' }}

1
.gitignore vendored
View File

@ -5,6 +5,7 @@
# Compiled files and executables # Compiled files and executables
debug/ debug/
target/ target/
target_nix/
# Backup files generated by rustfmt # Backup files generated by rustfmt
**/*.rs.bk **/*.rs.bk

View File

@ -11,12 +11,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed ### Changed
- manpages: moved to `man/man1/*.1`. - Manpages: moved to `man/man1/*.1`.
- Replace `--no-aliases` with `--no-cmd`.
### Fixed ### 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. - Elvish: upgrade to new lambda syntax.
- Fzf: added `--keep-right` option by default, upgrade minimum supported version
to v0.21.0.
- Bash: only enable completions on 4.4+.
- Fzf: bypass `ls` alias in preview window.
- Retain ownership of database file.
- Elvish: upgrade to new try-catch syntax, upgrade minimum supported version to
v0.18.0.
## [0.8.0] - 2021-12-25 ## [0.8.0] - 2021-12-25
@ -27,7 +36,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed ### Changed
- Fzf: better default options. - 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. - PowerShell: installation instructions.
### Fixed ### Fixed
@ -128,7 +138,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Auto-generated shell completions. - Auto-generated shell completions.
- `zoxide query --all` for listing deleted directories. - `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+. - Nushell: support for 0.32.0+.
### Fixed ### Fixed
@ -155,7 +166,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed ### Fixed
- `cd -` on fish shells. - `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 ### Removed
@ -192,7 +204,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- `$_ZO_EXCLUDE_DIRS` now supports globs. - `$_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. - Support for the [xonsh](https://xon.sh/) shell.
- `zoxide import` can now import from Autojump. - `zoxide import` can now import from Autojump.

221
Cargo.lock generated
View File

@ -13,15 +13,15 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.52" version = "1.0.56"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84450d0b4a8bd1ba4144ce8ce718fbc5d071358b1e5384bace6536b3d1f2d5b3" checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27"
[[package]] [[package]]
name = "askama" name = "askama"
version = "0.11.0" version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d8f355701c672c2ba3d718acbd213f740beea577cc4eae66accdffe15be1882" checksum = "fb98f10f371286b177db5eeb9a6e5396609555686a35e1d4f7b9a9c6d8af0139"
dependencies = [ dependencies = [
"askama_derive", "askama_derive",
"askama_escape", "askama_escape",
@ -30,9 +30,9 @@ dependencies = [
[[package]] [[package]]
name = "askama_derive" name = "askama_derive"
version = "0.11.0" version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84704cab5b7ae0fd3a9f78ee5eb7b27f3749df445f04623db6633459ae283267" checksum = "87bf87e6e8b47264efa9bde63d6225c6276a52e05e91bf37eaa8afd0032d6b71"
dependencies = [ dependencies = [
"askama_shared", "askama_shared",
"proc-macro2", "proc-macro2",
@ -41,17 +41,19 @@ dependencies = [
[[package]] [[package]]
name = "askama_escape" name = "askama_escape"
version = "0.10.2" version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a1bb320f97e6edf9f756bf015900038e43c7700e059688e5724a928c8f3b8d5" checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341"
[[package]] [[package]]
name = "askama_shared" name = "askama_shared"
version = "0.12.0" version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dae03eebba55a2697a376e58b573a29fe36893157173ac8df312ad85f3c0e012" checksum = "bf722b94118a07fcbc6640190f247334027685d4e218b794dbfe17c32bf38ed0"
dependencies = [ dependencies = [
"askama_escape", "askama_escape",
"mime",
"mime_guess",
"nom", "nom",
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -85,9 +87,9 @@ dependencies = [
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.0.1" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]] [[package]]
name = "bincode" name = "bincode"
@ -115,6 +117,12 @@ dependencies = [
"regex-automata", "regex-automata",
] ]
[[package]]
name = "cc"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "1.0.0" version = "1.0.0"
@ -123,9 +131,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "clap" name = "clap"
version = "3.0.10" version = "3.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a30c3bf9ff12dfe5dae53f0a96e0febcd18420d1c0e7fad77796d9d5c4b5375" checksum = "71c47df61d9e16dc010b55dba1952a57d8c215dbb533fd13cdd13369aac73b1c"
dependencies = [ dependencies = [
"atty", "atty",
"bitflags", "bitflags",
@ -140,18 +148,18 @@ dependencies = [
[[package]] [[package]]
name = "clap_complete" name = "clap_complete"
version = "3.0.4" version = "3.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d044e9db8cd0f68191becdeb5246b7462e4cf0c069b19ae00d1bf3fa9889498d" checksum = "df6f3613c0a3cddfd78b41b10203eb322cb29b600cbdf808a7d3db95691b8e25"
dependencies = [ dependencies = [
"clap", "clap",
] ]
[[package]] [[package]]
name = "clap_complete_fig" name = "clap_complete_fig"
version = "3.0.2" version = "3.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29cc003d824770d10072f4aa4a958e66d33d74a9cb7339595ac2a445d80d50a0" checksum = "690eb5abb7a98df1a64a3028beaf95af7e0ceb13da3186e6d0a86161af76309e"
dependencies = [ dependencies = [
"clap", "clap",
"clap_complete", "clap_complete",
@ -159,9 +167,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_derive" name = "clap_derive"
version = "3.0.6" version = "3.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "517358c28fcef6607bf6f76108e02afad7e82297d132a6b846dcc1fc3efcd153" checksum = "a3aab4734e083b809aaf5794e14e756d1c798d2c69c7f7de7a09a2f5214993c1"
dependencies = [ dependencies = [
"heck", "heck",
"proc-macro-error", "proc-macro-error",
@ -172,9 +180,9 @@ dependencies = [
[[package]] [[package]]
name = "crossbeam-utils" name = "crossbeam-utils"
version = "0.8.6" version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfcae03edb34f947e64acdb1c33ec169824e20657e9ecb61cef6c8c74dcb8120" checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"lazy_static", "lazy_static",
@ -197,9 +205,9 @@ dependencies = [
[[package]] [[package]]
name = "dirs-sys" name = "dirs-sys"
version = "0.3.6" version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
dependencies = [ dependencies = [
"libc", "libc",
"redox_users", "redox_users",
@ -226,9 +234,9 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]] [[package]]
name = "fastrand" name = "fastrand"
version = "1.6.0" version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "779d043b6a0b90cc4c0ed7ee380a6504394cee7efd7db050e3774eee387324b2" checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf"
dependencies = [ dependencies = [
"instant", "instant",
] ]
@ -241,9 +249,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.4" version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c" checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
@ -310,9 +318,9 @@ dependencies = [
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "1.8.0" version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"hashbrown", "hashbrown",
@ -344,15 +352,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.113" version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eef78b64d87775463c549fbd80e19249ef436ea3bf1de2a1eb7e717ec7fab1e9" checksum = "ec647867e2bf0772e28c8bcde4f0d19a9216916e890543b5a03ed8ef27b8f259"
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.14" version = "0.4.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
] ]
@ -363,6 +371,31 @@ version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" 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]] [[package]]
name = "minimal-lexical" name = "minimal-lexical"
version = "0.2.1" version = "0.2.1"
@ -370,14 +403,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]] [[package]]
name = "nom" name = "nix"
version = "7.1.0" version = "0.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109" checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6"
dependencies = [
"bitflags",
"cc",
"cfg-if",
"libc",
"memoffset",
]
[[package]]
name = "nom"
version = "7.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36"
dependencies = [ dependencies = [
"memchr", "memchr",
"minimal-lexical", "minimal-lexical",
"version_check",
] ]
[[package]] [[package]]
@ -391,9 +436,9 @@ dependencies = [
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.9.0" version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
[[package]] [[package]]
name = "ordered-float" name = "ordered-float"
@ -466,64 +511,47 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.36" version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1"
dependencies = [ dependencies = [
"unicode-xid", "unicode-xid",
] ]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.14" version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d" checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "rand"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
dependencies = [
"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]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.2.10" version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42"
dependencies = [ dependencies = [
"bitflags", "bitflags",
] ]
[[package]] [[package]]
name = "redox_users" name = "redox_users"
version = "0.4.0" version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
dependencies = [ dependencies = [
"getrandom", "getrandom",
"redox_syscall", "redox_syscall",
"thiserror",
] ]
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.5.4" version = "1.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@ -564,6 +592,17 @@ dependencies = [
"syn", "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]] [[package]]
name = "rustc_version" name = "rustc_version"
version = "0.4.0" version = "0.4.0"
@ -584,24 +623,24 @@ dependencies = [
[[package]] [[package]]
name = "semver" name = "semver"
version = "1.0.4" version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" checksum = "d65bd28f48be7196d222d95b9243287f48d27aca604e08497513019ff0502cc4"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.133" version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97565067517b60e2d1ea8b268e59ce036de907ac523ad83a0475da04e818989a" checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.133" version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed201699328568d8d08208fdd080e3ff594e6c422e438b6705905da01005d537" checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -610,9 +649,9 @@ dependencies = [
[[package]] [[package]]
name = "shell-words" name = "shell-words"
version = "1.0.0" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6fa3938c99da4914afedd13bf3d79bcb6c277d1b2c398d23257a304d9e1b074" checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
[[package]] [[package]]
name = "strsim" name = "strsim"
@ -622,9 +661,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.86" version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -647,9 +686,9 @@ dependencies = [
[[package]] [[package]]
name = "termcolor" name = "termcolor"
version = "1.1.2" version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
dependencies = [ dependencies = [
"winapi-util", "winapi-util",
] ]
@ -662,9 +701,9 @@ checksum = "507e9898683b6c43a9aa55b64259b721b52ba226e0f3779137e50ad114a4c90b"
[[package]] [[package]]
name = "textwrap" name = "textwrap"
version = "0.14.2" version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
[[package]] [[package]]
name = "thiserror" name = "thiserror"
@ -688,13 +727,22 @@ dependencies = [
[[package]] [[package]]
name = "thread_local" name = "thread_local"
version = "1.1.3" version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd" checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180"
dependencies = [ dependencies = [
"once_cell", "once_cell",
] ]
[[package]]
name = "unicase"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
dependencies = [
"version_check",
]
[[package]] [[package]]
name = "unicode-xid" name = "unicode-xid"
version = "0.2.2" version = "0.2.2"
@ -787,11 +835,12 @@ dependencies = [
"clap_complete_fig", "clap_complete_fig",
"dirs", "dirs",
"dunce", "dunce",
"fastrand",
"glob", "glob",
"nix",
"ordered-float", "ordered-float",
"rand",
"rstest", "rstest",
"rstest_reuse",
"serde", "serde",
"tempfile", "tempfile",
"thiserror",
] ]

View File

@ -7,7 +7,7 @@ keywords = ["cli"]
license = "MIT" license = "MIT"
name = "zoxide" name = "zoxide"
repository = "https://github.com/ajeetdsouza/zoxide" repository = "https://github.com/ajeetdsouza/zoxide"
rust-version = "1.56" rust-version = "1.59"
version = "0.8.0" version = "0.8.0"
[badges] [badges]
@ -20,35 +20,33 @@ members = ["xtask/"]
anyhow = "1.0.32" anyhow = "1.0.32"
askama = { version = "0.11.0", default-features = false } askama = { version = "0.11.0", default-features = false }
bincode = "1.3.1" bincode = "1.3.1"
clap = { version = "3.0.0", features = ["derive"] } clap = { version = "3.1.0", features = ["derive"] }
dirs = "4.0.0" dirs = "4.0.0"
dunce = "1.0.1" dunce = "1.0.1"
fastrand = "1.7.0"
glob = "0.3.0" glob = "0.3.0"
ordered-float = "2.0.0" ordered-float = "2.0.0"
serde = { version = "1.0.116", features = ["derive"] } serde = { version = "1.0.116", features = ["derive"] }
tempfile = "3.1.0"
thiserror = "1.0.30"
[target.'cfg(windows)'.dependencies] [target.'cfg(unix)'.dependencies]
rand = { version = "0.8.4", features = [ nix = "0.23.1"
"getrandom",
"small_rng",
], default-features = false }
[build-dependencies] [build-dependencies]
clap = { version = "3.0.0", features = ["derive"] } clap = { version = "3.1.0", features = ["derive"] }
clap_complete = "3.0.0" clap_complete = "3.1.0"
clap_complete_fig = "3.0.0" clap_complete_fig = "3.1.0"
[dev-dependencies] [dev-dependencies]
assert_cmd = "2.0.0" assert_cmd = "2.0.0"
rstest = "0.12.0" rstest = "0.12.0"
rstest_reuse = "0.3.0"
tempfile = "3.1.0"
[features] [features]
default = [] default = []
nix = [] nix-dev = []
[profile.release] [profile.release]
codegen-units = 1 codegen-units = 1
lto = true lto = true
# strip = true strip = true

View File

@ -44,7 +44,7 @@ z - # cd into previous directory
zi foo # cd with interactive selection (using fzf) 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]. Read more about the matching algorithm [here][algorithm-matching].
@ -171,7 +171,7 @@ Add this to your configuration (usually `~/.elvish/rc.elv`):
eval (zoxide init elvish | slurp) eval (zoxide init elvish | slurp)
``` ```
Note: zoxide only supports elvish v0.16.0 and above. Note: zoxide only supports elvish v0.18.0 and above.
</details> </details>
@ -241,8 +241,9 @@ Add this to your configuration (usually `~/.zshrc`):
eval "$(zoxide init zsh)" eval "$(zoxide init zsh)"
``` ```
For completions to work, the above line must be added _after_ `compinit` is For completions to work, the above line must be added *after* `compinit` is
called. You may have to rebuild your cache by running `rm ~/.zcompdump*; compinit`. called. You may have to rebuild your cache by running
`rm ~/.zcompdump*; compinit`.
</details> </details>
@ -260,7 +261,8 @@ eval "$(zoxide init posix --hook prompt)"
### *Step 3: Install fzf (optional)* ### *Step 3: Install fzf (optional)*
[fzf] is a command-line fuzzy finder, used by zoxide for interactive [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)* ### *Step 4: Import your data (optional)*
@ -292,8 +294,8 @@ zoxide import --from z path/to/db
When calling `zoxide init`, the following flags are available: When calling `zoxide init`, the following flags are available:
- `--cmd` - `--cmd`
- Changes the prefix of predefined aliases (`z`, `zi`). - Changes the prefix of the `z` and `zi` commands.
- `--cmd j` would change the aliases to (`j`, `ji`). - `--cmd j` would change the commands to (`j`, `ji`).
- `--cmd cd` would replace the `cd` command (doesn't work on Nushell / POSIX shells). - `--cmd cd` would replace the `cd` command (doesn't work on Nushell / POSIX shells).
- `--hook <HOOK>` - `--hook <HOOK>`
- Changes how often zoxide increments a directory's score: - Changes how often zoxide increments a directory's score:
@ -302,8 +304,8 @@ When calling `zoxide init`, the following flags are available:
| `none` | Never | | `none` | Never |
| `prompt` | At every shell prompt | | `prompt` | At every shell prompt |
| `pwd` | Whenever the directory is changed | | `pwd` | Whenever the directory is changed |
- `--no-aliases` - `--no-cmd`
- Don't define aliases (`z`, `zi`). - Prevents zoxide from defining the `z` and `zi` commands.
- These functions will still be available in your shell as `__zoxide_z` and - These functions will still be available in your shell as `__zoxide_z` and
`__zoxide_zi`, should you choose to redefine them. `__zoxide_zi`, should you choose to redefine them.
@ -319,7 +321,7 @@ They must be set before `zoxide init` is called.
| ----------- | ---------------------------------------- | ------------------------------------------ | | ----------- | ---------------------------------------- | ------------------------------------------ |
| Linux / BSD | `$XDG_DATA_HOME` or `$HOME/.local/share` | `/home/alice/.local/share` | | Linux / BSD | `$XDG_DATA_HOME` or `$HOME/.local/share` | `/home/alice/.local/share` |
| macOS | `$HOME/Library/Application Support` | `/Users/Alice/Library/Application Support` | | 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` - `_ZO_ECHO`
- When set to 1, `z` will print the matched directory before navigating to - When set to 1, `z` will print the matched directory before navigating to
it. it.
@ -346,15 +348,18 @@ They must be set before `zoxide init` is called.
## Third-party integrations ## Third-party integrations
| Application | Description | Plugin | | Application | Description | Plugin |
| ------------------ | --------------------------------------- | -------------------------- | | ------------------ | -------------------------------------------- | -------------------------- |
| [clink] | Improved cmd.exe for Windows | [clink-zoxide] |
| [emacs] | Text editor | [zoxide.el] | | [emacs] | Text editor | [zoxide.el] |
| [felix] | File manager | Natively supported |
| [nnn] | File manager | [nnn-autojump] | | [nnn] | File manager | [nnn-autojump] |
| [ranger] | File manager | [ranger-zoxide] | | [ranger] | File manager | [ranger-zoxide] |
| [telescope.nvim] | Fuzzy finder for Neovim | [telescope-zoxide] | | [telescope.nvim] | Fuzzy finder for Neovim | [telescope-zoxide] |
| [vim] | Text editor | [zoxide.vim] | | [vim] | Text editor | [zoxide.vim] |
| [xplr] | File manager | [zoxide.xplr] | | [xplr] | File manager | [zoxide.xplr] |
| [xxh] | Transports shell configuration over SSH | [xxh-plugin-prerun-zoxide] | | [xxh] | Transports shell configuration over SSH | [xxh-plugin-prerun-zoxide] |
| [zsh-autocomplete] | Realtime completions for zsh | Supported by default | | [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-aging]: https://github.com/ajeetdsouza/zoxide/wiki/Algorithm#aging
[algorithm-matching]: https://github.com/ajeetdsouza/zoxide/wiki/Algorithm#matching [algorithm-matching]: https://github.com/ajeetdsouza/zoxide/wiki/Algorithm#matching
@ -363,6 +368,8 @@ They must be set before `zoxide init` is called.
[builtwithnix-badge]: https://img.shields.io/badge/builtwith-nix-7d81f7?style=flat-square [builtwithnix-badge]: https://img.shields.io/badge/builtwith-nix-7d81f7?style=flat-square
[builtwithnix]: https://builtwithnix.org/ [builtwithnix]: https://builtwithnix.org/
[chocolatey]: https://community.chocolatey.org/packages/zoxide [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 [conda-forge]: https://anaconda.org/conda-forge/zoxide
[copr]: https://copr.fedorainfracloud.org/coprs/atim/zoxide/ [copr]: https://copr.fedorainfracloud.org/coprs/atim/zoxide/
[crates.io-badge]: https://img.shields.io/crates/v/zoxide?style=flat-square [crates.io-badge]: https://img.shields.io/crates/v/zoxide?style=flat-square
@ -373,6 +380,7 @@ They must be set before `zoxide init` is called.
[dports]: https://github.com/DragonFlyBSD/DPorts/tree/master/sysutils/zoxide [dports]: https://github.com/DragonFlyBSD/DPorts/tree/master/sysutils/zoxide
[emacs]: https://www.gnu.org/software/emacs/ [emacs]: https://www.gnu.org/software/emacs/
[fedora packages]: https://src.fedoraproject.org/rpms/rust-zoxide [fedora packages]: https://src.fedoraproject.org/rpms/rust-zoxide
[felix]: https://github.com/kyoheiu/felix
[freshports]: https://www.freshports.org/sysutils/zoxide/ [freshports]: https://www.freshports.org/sysutils/zoxide/
[fzf-installation]: https://github.com/junegunn/fzf#installation [fzf-installation]: https://github.com/junegunn/fzf#installation
[fzf-man]: https://manpages.ubuntu.com/manpages/en/man1/fzf.1.html [fzf-man]: https://manpages.ubuntu.com/manpages/en/man1/fzf.1.html
@ -404,6 +412,7 @@ They must be set before `zoxide init` is called.
[xplr]: https://github.com/sayanarijit/xplr [xplr]: https://github.com/sayanarijit/xplr
[xxh-plugin-prerun-zoxide]: https://github.com/xxh/xxh-plugin-prerun-zoxide [xxh-plugin-prerun-zoxide]: https://github.com/xxh/xxh-plugin-prerun-zoxide
[xxh]: https://github.com/xxh/xxh [xxh]: https://github.com/xxh/xxh
[zabb]: https://github.com/Mellbourn/zabb
[zoxide.el]: https://gitlab.com/Vonfry/zoxide.el [zoxide.el]: https://gitlab.com/Vonfry/zoxide.el
[zoxide.vim]: https://github.com/nanotee/zoxide.vim [zoxide.vim]: https://github.com/nanotee/zoxide.vim
[zoxide.xplr]: https://github.com/sayanarijit/zoxide.xplr [zoxide.xplr]: https://github.com/sayanarijit/zoxide.xplr

View File

@ -32,25 +32,25 @@ fn git_version() -> Option<String> {
} }
fn generate_completions() -> io::Result<()> { fn generate_completions() -> io::Result<()> {
#[path = "src/app/_app.rs"] #[path = "src/cmd/_cmd.rs"]
mod app; mod cmd;
use app::App; use clap::CommandFactory;
use clap::IntoApp;
use clap_complete::generate_to; use clap_complete::generate_to;
use clap_complete::Shell::{Bash, Elvish, Fish, PowerShell, Zsh}; use clap_complete::shells::{Bash, Elvish, Fish, PowerShell, Zsh};
use clap_complete_fig::Fig; 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 bin_name = env!("CARGO_PKG_NAME");
let out_dir = "contrib/completions"; let out_dir = "contrib/completions";
generate_to(Bash, app, bin_name, out_dir)?; generate_to(Bash, cmd, bin_name, out_dir)?;
generate_to(Elvish, app, bin_name, out_dir)?; generate_to(Elvish, cmd, bin_name, out_dir)?;
generate_to(Fig, app, bin_name, out_dir)?; generate_to(Fig, cmd, bin_name, out_dir)?;
generate_to(Fish, app, bin_name, out_dir)?; generate_to(Fish, cmd, bin_name, out_dir)?;
generate_to(PowerShell, app, bin_name, out_dir)?; generate_to(PowerShell, cmd, bin_name, out_dir)?;
generate_to(Zsh, app, bin_name, out_dir)?; generate_to(Zsh, cmd, bin_name, out_dir)?;
Ok(()) Ok(())
} }

View File

@ -50,9 +50,9 @@ _arguments "${_arguments_options[@]}" \
;; ;;
(init) (init)
_arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \
'--cmd=[Renames the '\''z'\'' command and corresponding aliases]:CMD: ' \ '--cmd=[Changes the prefix of the `z` and `zi` commands]:CMD: ' \
'--hook=[Chooses event upon which an entry is added to the database]:HOOK:(none prompt pwd)' \ '--hook=[Changes how often zoxide increments a directory'\''s score]:HOOK:(none prompt pwd)' \
'--no-aliases[Prevents zoxide from defining any commands]' \ '--no-cmd[Prevents zoxide from defining the `z` and `zi` commands]' \
'-h[Print help information]' \ '-h[Print help information]' \
'--help[Print help information]' \ '--help[Print help information]' \
'-V[Print version information]' \ '-V[Print version information]' \

View File

@ -12,7 +12,8 @@ Register-ArgumentCompleter -Native -CommandName 'zoxide' -ScriptBlock {
$element = $commandElements[$i] $element = $commandElements[$i]
if ($element -isnot [StringConstantExpressionAst] -or if ($element -isnot [StringConstantExpressionAst] -or
$element.StringConstantType -ne [StringConstantType]::BareWord -or $element.StringConstantType -ne [StringConstantType]::BareWord -or
$element.Value.StartsWith('-')) { $element.Value.StartsWith('-') -or
$element.Value -eq $wordToComplete) {
break break
} }
$element.Value $element.Value
@ -48,9 +49,9 @@ Register-ArgumentCompleter -Native -CommandName 'zoxide' -ScriptBlock {
break break
} }
'zoxide;init' { 'zoxide;init' {
[CompletionResult]::new('--cmd', 'cmd', [CompletionResultType]::ParameterName, 'Renames the ''z'' command and corresponding aliases') [CompletionResult]::new('--cmd', 'cmd', [CompletionResultType]::ParameterName, 'Changes the prefix of the `z` and `zi` commands')
[CompletionResult]::new('--hook', 'hook', [CompletionResultType]::ParameterName, 'Chooses event upon which an entry is added to the database') [CompletionResult]::new('--hook', 'hook', [CompletionResultType]::ParameterName, 'Changes how often zoxide increments a directory''s score')
[CompletionResult]::new('--no-aliases', 'no-aliases', [CompletionResultType]::ParameterName, 'Prevents zoxide from defining any commands') [CompletionResult]::new('--no-cmd', 'no-cmd', [CompletionResultType]::ParameterName, 'Prevents zoxide from defining the `z` and `zi` commands')
[CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help information') [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help information')
[CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help information') [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help information')
[CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Print version information') [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Print version information')

View File

@ -69,7 +69,7 @@ _zoxide() {
fi fi
case "${prev}" in case "${prev}" in
--from) --from)
COMPREPLY=($(compgen -W "autojump z" -- "${cur}")) COMPREPLY=($(compgen -W "" -- "${cur}"))
return 0 return 0
;; ;;
*) *)
@ -80,7 +80,7 @@ _zoxide() {
return 0 return 0
;; ;;
zoxide__init) zoxide__init)
opts="-h -V --no-aliases --cmd --hook --help --version bash elvish fish nushell posix powershell xonsh zsh" opts="-h -V --no-cmd --cmd --hook --help --version bash elvish fish nushell posix powershell xonsh zsh"
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0 return 0
@ -91,7 +91,7 @@ _zoxide() {
return 0 return 0
;; ;;
--hook) --hook)
COMPREPLY=($(compgen -W "none prompt pwd" -- "${cur}")) COMPREPLY=($(compgen -W "" -- "${cur}"))
return 0 return 0
;; ;;
*) *)

View File

@ -43,9 +43,9 @@ set edit:completion:arg-completer[zoxide] = {|@words|
cand --version 'Print version information' cand --version 'Print version information'
} }
&'zoxide;init'= { &'zoxide;init'= {
cand --cmd 'Renames the ''z'' command and corresponding aliases' cand --cmd 'Changes the prefix of the `z` and `zi` commands'
cand --hook 'Chooses event upon which an entry is added to the database' cand --hook 'Changes how often zoxide increments a directory''s score'
cand --no-aliases 'Prevents zoxide from defining any commands' cand --no-cmd 'Prevents zoxide from defining the `z` and `zi` commands'
cand -h 'Print help information' cand -h 'Print help information'
cand --help 'Print help information' cand --help 'Print help information'
cand -V 'Print version information' cand -V 'Print version information'

View File

@ -11,9 +11,9 @@ complete -c zoxide -n "__fish_seen_subcommand_from import" -l from -d 'Applicati
complete -c zoxide -n "__fish_seen_subcommand_from import" -l merge -d 'Merge into existing database' complete -c zoxide -n "__fish_seen_subcommand_from import" -l merge -d 'Merge into existing database'
complete -c zoxide -n "__fish_seen_subcommand_from import" -s h -l help -d 'Print help information' complete -c zoxide -n "__fish_seen_subcommand_from import" -s h -l help -d 'Print help information'
complete -c zoxide -n "__fish_seen_subcommand_from import" -s V -l version -d 'Print version information' complete -c zoxide -n "__fish_seen_subcommand_from import" -s V -l version -d 'Print version information'
complete -c zoxide -n "__fish_seen_subcommand_from init" -l cmd -d 'Renames the \'z\' command and corresponding aliases' -r complete -c zoxide -n "__fish_seen_subcommand_from init" -l cmd -d 'Changes the prefix of the `z` and `zi` commands' -r
complete -c zoxide -n "__fish_seen_subcommand_from init" -l hook -d 'Chooses event upon which an entry is added to the database' -r -f -a "{none ,prompt ,pwd }" complete -c zoxide -n "__fish_seen_subcommand_from init" -l hook -d 'Changes how often zoxide increments a directory\'s score' -r -f -a "{none ,prompt ,pwd }"
complete -c zoxide -n "__fish_seen_subcommand_from init" -l no-aliases -d 'Prevents zoxide from defining any commands' complete -c zoxide -n "__fish_seen_subcommand_from init" -l no-cmd -d 'Prevents zoxide from defining the `z` and `zi` commands'
complete -c zoxide -n "__fish_seen_subcommand_from init" -s h -l help -d 'Print help information' complete -c zoxide -n "__fish_seen_subcommand_from init" -s h -l help -d 'Print help information'
complete -c zoxide -n "__fish_seen_subcommand_from init" -s V -l version -d 'Print version information' complete -c zoxide -n "__fish_seen_subcommand_from init" -s V -l version -d 'Print version information'
complete -c zoxide -n "__fish_seen_subcommand_from query" -l exclude -d 'Exclude a path from results' -r -f -a "(__fish_complete_directories)" complete -c zoxide -n "__fish_seen_subcommand_from query" -l exclude -d 'Exclude a path from results' -r -f -a "(__fish_complete_directories)"

View File

@ -31,13 +31,9 @@ const completion: Fig.Spec = {
args: { args: {
name: "from", name: "from",
suggestions: [ suggestions: [
{ "autojump",
name: "autojump", "z",
}, ],
{
name: "z",
},
]
}, },
}, },
{ {
@ -64,7 +60,7 @@ const completion: Fig.Spec = {
options: [ options: [
{ {
name: "--cmd", name: "--cmd",
description: "Renames the 'z' command and corresponding aliases", description: "Changes the prefix of the `z` and `zi` commands",
args: { args: {
name: "cmd", name: "cmd",
isOptional: true, isOptional: true,
@ -72,26 +68,20 @@ const completion: Fig.Spec = {
}, },
{ {
name: "--hook", name: "--hook",
description: "Chooses event upon which an entry is added to the database", description: "Changes how often zoxide increments a directory's score",
args: { args: {
name: "hook", name: "hook",
isOptional: true, isOptional: true,
suggestions: [ suggestions: [
{ "none",
name: "none", "prompt",
}, "pwd",
{ ],
name: "prompt",
},
{
name: "pwd",
},
]
}, },
}, },
{ {
name: "--no-aliases", name: "--no-cmd",
description: "Prevents zoxide from defining any commands", description: "Prevents zoxide from defining the `z` and `zi` commands",
}, },
{ {
name: ["-h", "--help"], name: ["-h", "--help"],
@ -105,31 +95,15 @@ const completion: Fig.Spec = {
args: { args: {
name: "shell", name: "shell",
suggestions: [ suggestions: [
{ "bash",
name: "bash", "elvish",
}, "fish",
{ "nushell",
name: "elvish", "posix",
}, "powershell",
{ "xonsh",
name: "fish", "zsh",
}, ],
{
name: "nushell",
},
{
name: "posix",
},
{
name: "powershell",
},
{
name: "xonsh",
},
{
name: "zsh",
},
]
}, },
}, },
{ {
@ -152,14 +126,26 @@ const completion: Fig.Spec = {
{ {
name: ["-i", "--interactive"], name: ["-i", "--interactive"],
description: "Use interactive selection", description: "Use interactive selection",
exclusiveOn: [
"-l",
"--list",
],
}, },
{ {
name: ["-l", "--list"], name: ["-l", "--list"],
description: "List all matching directories", description: "List all matching directories",
exclusiveOn: [
"-i",
"--interactive",
],
}, },
{ {
name: ["-s", "--score"], name: ["-s", "--score"],
description: "Print score with results", description: "Print score with results",
exclusiveOn: [
"-i",
"--interactive",
],
}, },
{ {
name: ["-h", "--help"], name: ["-h", "--help"],

View File

@ -20,7 +20,7 @@ Add this to your configuration (usually \fB~/.elvish/rc.elv\fR):
\fBeval $(zoxide init elvish | slurp)\fR \fBeval $(zoxide init elvish | slurp)\fR
.fi .fi
.sp .sp
Note: zoxide only supports elvish v0.16.0 and above. Note: zoxide only supports elvish v0.18.0 and above.
.TP .TP
.B fish .B fish
Add this to your configuration (usually \fB~/.config/fish/config.fish\fR): Add this to your configuration (usually \fB~/.config/fish/config.fish\fR):
@ -74,9 +74,9 @@ Add this to your configuration:
.SH OPTIONS .SH OPTIONS
.TP .TP
.B --cmd .B --cmd
Changes the prefix of predefined aliases (\fBz\fR, \fBzi\fR). Changes the prefix of the \fBz\fR and \fBzi\fR commands.
.br .br
\fB--cmd j\fR would change the aliases to (\fBj\fR, \fBji\fR). \fB--cmd j\fR would change the commands to (\fBj\fR, \fBji\fR).
.br .br
\fB--cmd cd\fR would replace the \fBcd\fR command (doesn't work on Nushell / \fB--cmd cd\fR would replace the \fBcd\fR command (doesn't work on Nushell /
POSIX shells). POSIX shells).
@ -94,10 +94,10 @@ l l.
\fBpwd\fR|Whenever the directory is changed \fBpwd\fR|Whenever the directory is changed
.TE .TE
.TP .TP
.B --no-aliases .B --no-cmd
Don't define extra aliases (\fBz\fR, \fBzi\fR). These functions will still be Prevents zoxide from defining the \fBz\fR and \fBzi\fR commands. These functions
available in your shell as \fB__zoxide_z\fR and \fB__zoxide_zi\fR, should you will still be available in your shell as \fB__zoxide_z\fR and \fB__zoxide_zi\fR,
choose to redefine them. should you choose to redefine them.
.SH REPORTING BUGS .SH REPORTING BUGS
For any issues, feature requests, or questions, please visit: For any issues, feature requests, or questions, please visit:
.sp .sp

View File

@ -9,16 +9,18 @@ directories you use most frequently, and uses a ranking algorithm to navigate
to the best match. to the best match.
.SH USAGE .SH USAGE
.nf .nf
$ z foo # cd into highest ranked directory matching foo z foo # cd into highest ranked directory matching foo
$ z foo bar # cd into highest ranked directory matching foo and bar z foo bar # cd into highest ranked directory matching foo and bar
$ z foo / # cd into a subdirectory starting with foo z foo / # cd into a subdirectory starting with foo
.sp .sp
$ z ~/foo # z also works like a regular cd command z ~/foo # z also works like a regular cd command
$ z foo/ # cd into relative path z foo/ # cd into relative path
$ z .. # cd one level up z .. # cd one level up
$ z - # cd into previous directory z - # cd into previous directory
.sp .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 .fi
.SH SUBCOMMANDS .SH SUBCOMMANDS
.TP .TP
@ -63,7 +65,7 @@ T}
\fB/Users/Alice/Library/Application Support\fR \fB/Users/Alice/Library/Application Support\fR
T} T}
\fBWindows\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} T}
.TE .TE
.TP .TP

View File

@ -1,8 +1,8 @@
let let
rust = import (builtins.fetchTarball 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 pkgs = import (builtins.fetchTarball
"https://github.com/NixOS/nixpkgs/archive/fae46e66a5df220327b45e0d7c27c6961cf922ce.tar.gz") { "https://github.com/NixOS/nixpkgs/archive/d19a9162c848517cfc9437f10945b736d718b948.tar.gz") {
overlays = [ rust ]; overlays = [ rust ];
}; };
in pkgs.mkShell { 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 std::path::PathBuf;
use clap::{AppSettings, ArgEnum, Parser, ValueHint}; use clap::{ArgEnum, Parser, ValueHint};
const ENV_HELP: &str = "ENVIRONMENT VARIABLES: const ENV_HELP: &str = "ENVIRONMENT VARIABLES:
_ZO_DATA_DIR Path for zoxide data files _ZO_DATA_DIR Path for zoxide data files
@ -16,11 +16,11 @@ const ENV_HELP: &str = "ENVIRONMENT VARIABLES:
about, about,
author, author,
after_help = ENV_HELP, after_help = ENV_HELP,
global_setting(AppSettings::DisableHelpSubcommand), disable_help_subcommand = true,
global_setting(AppSettings::PropagateVersion), propagate_version = true,
version = option_env!("ZOXIDE_VERSION").unwrap_or_default() version = option_env!("ZOXIDE_VERSION").unwrap_or_default()
)] )]
pub enum App { pub enum Cmd {
Add(Add), Add(Add),
Import(Import), Import(Import),
Init(Init), Init(Init),
@ -62,15 +62,15 @@ pub struct Init {
#[clap(arg_enum)] #[clap(arg_enum)]
pub shell: InitShell, pub shell: InitShell,
/// Prevents zoxide from defining any commands /// Prevents zoxide from defining the `z` and `zi` commands
#[clap(long)] #[clap(long, alias = "no-aliases")]
pub no_aliases: bool, pub no_cmd: bool,
/// Renames the 'z' command and corresponding aliases /// Changes the prefix of the `z` and `zi` commands
#[clap(long, default_value = "z")] #[clap(long, default_value = "z")]
pub cmd: String, pub cmd: String,
/// Chooses event upon which an entry is added to the database /// Changes how often zoxide increments a directory's score
#[clap(arg_enum, long, default_value = "pwd")] #[clap(arg_enum, long, default_value = "pwd")]
pub hook: InitHook, pub hook: InitHook,
} }

View File

@ -2,7 +2,7 @@ use std::path::Path;
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use crate::app::{Add, Run}; use crate::cmd::{Add, Run};
use crate::db::DatabaseFile; use crate::db::DatabaseFile;
use crate::{config, util}; use crate::{config, util};

View File

@ -2,7 +2,7 @@ use std::fs;
use anyhow::{bail, Context, Result}; use anyhow::{bail, Context, Result};
use crate::app::{Import, ImportFrom, Run}; use crate::cmd::{Import, ImportFrom, Run};
use crate::config; use crate::config;
use crate::db::{Database, DatabaseFile, Dir}; use crate::db::{Database, DatabaseFile, Dir};

View File

@ -3,14 +3,14 @@ use std::io::{self, Write};
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use askama::Template; use askama::Template;
use crate::app::{Init, InitShell, Run}; use crate::cmd::{Init, InitShell, Run};
use crate::config; use crate::config;
use crate::error::BrokenPipeHandler; use crate::error::BrokenPipeHandler;
use crate::shell::{self, Opts}; use crate::shell::{self, Opts};
impl Run for Init { impl Run for Init {
fn run(&self) -> Result<()> { fn run(&self) -> Result<()> {
let cmd = if self.no_aliases { None } else { Some(self.cmd.as_str()) }; let cmd = if self.no_cmd { None } else { Some(self.cmd.as_str()) };
let echo = config::echo(); let echo = config::echo();
let resolve_symlinks = config::resolve_symlinks(); let resolve_symlinks = config::resolve_symlinks();

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 anyhow::{Context, Result};
use crate::app::{Query, Run}; use crate::cmd::{Query, Run};
use crate::config;
use crate::db::{Database, DatabaseFile}; use crate::db::{Database, DatabaseFile};
use crate::error::BrokenPipeHandler; use crate::error::BrokenPipeHandler;
use crate::fzf::Fzf; use crate::util::{self, Fzf};
use crate::{config, util};
impl Run for Query { impl Run for Query {
fn run(&self) -> Result<()> { fn run(&self) -> Result<()> {

View File

@ -2,10 +2,10 @@ use std::io::{self, Write};
use anyhow::{bail, Context, Result}; use anyhow::{bail, Context, Result};
use crate::app::{Remove, Run}; use crate::cmd::{Remove, Run};
use crate::config;
use crate::db::DatabaseFile; use crate::db::DatabaseFile;
use crate::fzf::Fzf; use crate::util::{self, Fzf};
use crate::{config, util};
impl Run for Remove { impl Run for Remove {
fn run(&self) -> Result<()> { fn run(&self) -> Result<()> {

View File

@ -2,13 +2,14 @@ mod dir;
mod stream; mod stream;
use std::fs; use std::fs;
use std::io::{self, Write}; use std::io;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use anyhow::{Context, Result}; use anyhow::{Context, Result};
pub use dir::{Dir, DirList, Epoch, Rank}; pub use dir::{Dir, DirList, Epoch, Rank};
pub use stream::Stream; pub use stream::Stream;
use tempfile::{NamedTempFile, PersistError};
use crate::util;
#[derive(Debug)] #[derive(Debug)]
pub struct Database<'file> { pub struct Database<'file> {
@ -24,18 +25,8 @@ impl<'file> Database<'file> {
} }
let buffer = self.dirs.to_bytes()?; 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); 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; self.modified = false;
Ok(()) 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 { pub struct DatabaseFile {
buffer: Vec<u8>, buffer: Vec<u8>,
data_dir: PathBuf, data_dir: PathBuf,

View File

@ -1,19 +1,20 @@
use std::fmt::{self, Display, Formatter};
use std::io; use std::io;
use anyhow::{bail, Context, Result}; 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. /// Custom error type for early exit.
#[derive(Debug, Error)] #[derive(Debug)]
#[error("")]
pub struct SilentExit { pub struct SilentExit {
pub code: i32, pub code: i32,
} }
impl Display for SilentExit {
fn fmt(&self, _: &mut Formatter<'_>) -> fmt::Result {
Ok(())
}
}
pub trait BrokenPipeHandler { pub trait BrokenPipeHandler {
fn pipe_exit(self, device: &str) -> Result<()>; 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 config;
mod db; mod db;
mod error; mod error;
mod fzf;
mod shell; mod shell;
mod util; mod util;
@ -11,7 +16,7 @@ use std::{env, process};
use clap::Parser; use clap::Parser;
use crate::app::{App, Run}; use crate::cmd::{Cmd, Run};
use crate::error::SilentExit; use crate::error::SilentExit;
pub fn main() { pub fn main() {
@ -19,7 +24,7 @@ pub fn main() {
env::remove_var("RUST_LIB_BACKTRACE"); env::remove_var("RUST_LIB_BACKTRACE");
env::remove_var("RUST_BACKTRACE"); env::remove_var("RUST_BACKTRACE");
if let Err(e) = App::parse().run() { if let Err(e) = Cmd::parse().run() {
match e.downcast::<SilentExit>() { match e.downcast::<SilentExit>() {
Ok(SilentExit { code }) => process::exit(code), Ok(SilentExit { code }) => process::exit(code),
Err(e) => { Err(e) => {

View File

@ -1,4 +1,4 @@
use crate::app::InitHook; use crate::cmd::InitHook;
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub struct Opts<'a> { pub struct Opts<'a> {
@ -32,22 +32,28 @@ make_template!(Powershell, "powershell.txt");
make_template!(Xonsh, "xonsh.txt"); make_template!(Xonsh, "xonsh.txt");
make_template!(Zsh, "zsh.txt"); make_template!(Zsh, "zsh.txt");
#[cfg(feature = "nix")] #[cfg(feature = "nix-dev")]
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use askama::Template; use askama::Template;
use assert_cmd::Command; use assert_cmd::Command;
use rstest::rstest; use rstest::rstest;
use rstest_reuse::{apply, template};
use super::*; use super::*;
#[template]
#[rstest] #[rstest]
fn bash_bash( fn opts(
#[values(None, Some("z"))] cmd: Option<&str>, #[values(None, Some("z"))] cmd: Option<&str>,
#[values(InitHook::None, InitHook::Prompt, InitHook::Pwd)] hook: InitHook, #[values(InitHook::None, InitHook::Prompt, InitHook::Pwd)] hook: InitHook,
#[values(false, true)] echo: bool, #[values(false, true)] echo: bool,
#[values(false, true)] resolve_symlinks: 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 opts = Opts { cmd, hook, echo, resolve_symlinks };
let source = Bash(&opts).render().unwrap(); let source = Bash(&opts).render().unwrap();
Command::new("bash") Command::new("bash")
@ -58,13 +64,8 @@ mod tests {
.stderr(""); .stderr("");
} }
#[rstest] #[apply(opts)]
fn bash_shellcheck( fn bash_shellcheck(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
#[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,
) {
let opts = Opts { cmd, hook, echo, resolve_symlinks }; let opts = Opts { cmd, hook, echo, resolve_symlinks };
let source = Bash(&opts).render().unwrap(); let source = Bash(&opts).render().unwrap();
@ -77,13 +78,8 @@ mod tests {
.stderr(""); .stderr("");
} }
#[rstest] #[apply(opts)]
fn bash_shfmt( fn bash_shfmt(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
#[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,
) {
let opts = Opts { cmd, hook, echo, resolve_symlinks }; let opts = Opts { cmd, hook, echo, resolve_symlinks };
let mut source = Bash(&opts).render().unwrap(); let mut source = Bash(&opts).render().unwrap();
source.push('\n'); source.push('\n');
@ -97,13 +93,8 @@ mod tests {
.stderr(""); .stderr("");
} }
#[rstest] #[apply(opts)]
fn elvish_elvish( fn elvish_elvish(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
#[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,
) {
let opts = Opts { cmd, hook, echo, resolve_symlinks }; let opts = Opts { cmd, hook, echo, resolve_symlinks };
let mut source = String::new(); let mut source = String::new();
@ -117,13 +108,8 @@ mod tests {
Command::new("elvish").args(&["-c", &source, "-norc"]).assert().success().stdout("").stderr(""); Command::new("elvish").args(&["-c", &source, "-norc"]).assert().success().stdout("").stderr("");
} }
#[rstest] #[apply(opts)]
fn fish_fish( fn fish_fish(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
#[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,
) {
let opts = Opts { cmd, hook, echo, resolve_symlinks }; let opts = Opts { cmd, hook, echo, resolve_symlinks };
let source = Fish(&opts).render().unwrap(); let source = Fish(&opts).render().unwrap();
@ -139,13 +125,8 @@ mod tests {
.stderr(""); .stderr("");
} }
#[rstest] #[apply(opts)]
fn fish_fishindent( fn fish_fishindent(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
#[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,
) {
let opts = Opts { cmd, hook, echo, resolve_symlinks }; let opts = Opts { cmd, hook, echo, resolve_symlinks };
let mut source = Fish(&opts).render().unwrap(); let mut source = Fish(&opts).render().unwrap();
source.push('\n'); source.push('\n');
@ -162,13 +143,8 @@ mod tests {
.stderr(""); .stderr("");
} }
#[rstest] #[apply(opts)]
fn nushell_nushell( fn nushell_nushell(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
#[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,
) {
let opts = Opts { cmd, hook, echo, resolve_symlinks }; let opts = Opts { cmd, hook, echo, resolve_symlinks };
let source = Nushell(&opts).render().unwrap(); let source = Nushell(&opts).render().unwrap();
@ -183,13 +159,8 @@ mod tests {
} }
} }
#[rstest] #[apply(opts)]
fn posix_bash( fn posix_bash(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
#[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,
) {
let opts = Opts { cmd, hook, echo, resolve_symlinks }; let opts = Opts { cmd, hook, echo, resolve_symlinks };
let source = Posix(&opts).render().unwrap(); let source = Posix(&opts).render().unwrap();
@ -203,13 +174,8 @@ mod tests {
} }
} }
#[rstest] #[apply(opts)]
fn posix_dash( fn posix_dash(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
#[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,
) {
let opts = Opts { cmd, hook, echo, resolve_symlinks }; let opts = Opts { cmd, hook, echo, resolve_symlinks };
let source = Posix(&opts).render().unwrap(); let source = Posix(&opts).render().unwrap();
@ -219,13 +185,8 @@ mod tests {
} }
} }
#[rstest] #[apply(opts)]
fn posix_shellcheck_( fn posix_shellcheck_(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
#[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,
) {
let opts = Opts { cmd, hook, echo, resolve_symlinks }; let opts = Opts { cmd, hook, echo, resolve_symlinks };
let source = Posix(&opts).render().unwrap(); let source = Posix(&opts).render().unwrap();
@ -238,13 +199,8 @@ mod tests {
.stderr(""); .stderr("");
} }
#[rstest] #[apply(opts)]
fn posix_shfmt( fn posix_shfmt(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
#[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,
) {
let opts = Opts { cmd, hook, echo, resolve_symlinks }; let opts = Opts { cmd, hook, echo, resolve_symlinks };
let mut source = Posix(&opts).render().unwrap(); let mut source = Posix(&opts).render().unwrap();
source.push('\n'); source.push('\n');
@ -258,13 +214,8 @@ mod tests {
.stderr(""); .stderr("");
} }
#[rstest] #[apply(opts)]
fn powershell_pwsh( fn powershell_pwsh(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
#[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,
) {
let opts = Opts { cmd, hook, echo, resolve_symlinks }; let opts = Opts { cmd, hook, echo, resolve_symlinks };
let mut source = "Set-StrictMode -Version latest\n".to_string(); let mut source = "Set-StrictMode -Version latest\n".to_string();
Powershell(&opts).render_into(&mut source).unwrap(); Powershell(&opts).render_into(&mut source).unwrap();
@ -277,13 +228,8 @@ mod tests {
.stderr(""); .stderr("");
} }
#[rstest] #[apply(opts)]
fn xonsh_black( fn xonsh_black(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
#[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,
) {
let opts = Opts { cmd, hook, echo, resolve_symlinks }; let opts = Opts { cmd, hook, echo, resolve_symlinks };
let mut source = Xonsh(&opts).render().unwrap(); let mut source = Xonsh(&opts).render().unwrap();
source.push('\n'); source.push('\n');
@ -291,26 +237,16 @@ mod tests {
Command::new("black").args(&["--check", "--diff", "-"]).write_stdin(source).assert().success().stdout(""); Command::new("black").args(&["--check", "--diff", "-"]).write_stdin(source).assert().success().stdout("");
} }
#[rstest] #[apply(opts)]
fn xonsh_mypy( fn xonsh_mypy(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
#[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,
) {
let opts = Opts { cmd, hook, echo, resolve_symlinks }; let opts = Opts { cmd, hook, echo, resolve_symlinks };
let source = Xonsh(&opts).render().unwrap(); let source = Xonsh(&opts).render().unwrap();
Command::new("mypy").args(&["--command", &source, "--strict"]).assert().success().stderr(""); Command::new("mypy").args(&["--command", &source, "--strict"]).assert().success().stderr("");
} }
#[rstest] #[apply(opts)]
fn xonsh_pylint( fn xonsh_pylint(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
#[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,
) {
let opts = Opts { cmd, hook, echo, resolve_symlinks }; let opts = Opts { cmd, hook, echo, resolve_symlinks };
let mut source = Xonsh(&opts).render().unwrap(); let mut source = Xonsh(&opts).render().unwrap();
source.push('\n'); source.push('\n');
@ -323,13 +259,8 @@ mod tests {
.stderr(""); .stderr("");
} }
#[rstest] #[apply(opts)]
fn xonsh_xonsh( fn xonsh_xonsh(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
#[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,
) {
let opts = Opts { cmd, hook, echo, resolve_symlinks }; let opts = Opts { cmd, hook, echo, resolve_symlinks };
let source = Xonsh(&opts).render().unwrap(); let source = Xonsh(&opts).render().unwrap();
@ -345,13 +276,8 @@ mod tests {
.stderr(""); .stderr("");
} }
#[rstest] #[apply(opts)]
fn zsh_shellcheck( fn zsh_shellcheck(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
#[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,
) {
let opts = Opts { cmd, hook, echo, resolve_symlinks }; let opts = Opts { cmd, hook, echo, resolve_symlinks };
let source = Zsh(&opts).render().unwrap(); let source = Zsh(&opts).render().unwrap();
@ -365,13 +291,8 @@ mod tests {
.stderr(""); .stderr("");
} }
#[rstest] #[apply(opts)]
fn zsh_zsh( fn zsh_zsh(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
#[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,
) {
let opts = Opts { cmd, hook, echo, resolve_symlinks }; let opts = Opts { cmd, hook, echo, resolve_symlinks };
let source = Zsh(&opts).render().unwrap(); let source = Zsh(&opts).render().unwrap();

View File

@ -1,11 +1,172 @@
use std::env; 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::path::{Component, Path, PathBuf};
use std::process::Command; use std::process::Command;
use std::process::{Child, ChildStdin, Stdio};
use std::time::SystemTime; use std::time::SystemTime;
use anyhow::{bail, Context, Result}; use anyhow::{anyhow, bail, Context, Result};
use crate::config;
use crate::db::Epoch; 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> { pub fn canonicalize<P: AsRef<Path>>(path: &P) -> Result<PathBuf> {
dunce::canonicalize(path).with_context(|| format!("could not resolve path: {}", path.as_ref().display())) dunce::canonicalize(path).with_context(|| format!("could not resolve path: {}", path.as_ref().display()))

View File

@ -58,7 +58,7 @@ fi
{% endif -%} {% endif -%}
{{ section }} {{ section }}
# When using zoxide with --no-aliases, alias these internal functions as # When using zoxide with --no-cmd, alias these internal functions as
# desired. # desired.
# #
@ -91,7 +91,7 @@ function __zoxide_zi() {
} }
{{ section }} {{ section }}
# Convenient aliases for zoxide. Disable these using --no-aliases. # Commands for zoxide. Disable these using --no-cmd.
# #
{%- match cmd %} {%- match cmd %}
@ -115,11 +115,12 @@ function {{cmd}}i() {
} }
# Load completions. # 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 # - Completions require line editing. Since Bash supports only two modes of
# line editing (`vim` and `emacs`), we check if either them is enabled. # line editing (`vim` and `emacs`), we check if either them is enabled.
# - Completions don't work on `dumb` terminals. # - 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. # Use `printf '\e[5n'` to redraw line after fzf closes.
\builtin bind '"\e[0n": redraw-current-line' &>/dev/null \builtin bind '"\e[0n": redraw-current-line' &>/dev/null

View File

@ -41,7 +41,7 @@ if (builtin:not (builtin:eq $E:__zoxide_shlvl $E:SHLVL)) {
{%- endif %} {%- endif %}
{{ section }} {{ section }}
# When using zoxide with --no-aliases, alias these internal functions as # When using zoxide with --no-cmd, alias these internal functions as
# desired. # desired.
# #
@ -57,7 +57,7 @@ fn __zoxide_z {|@rest|
var path var path
try { try {
set path = (zoxide query --exclude $pwd -- $@rest) set path = (zoxide query --exclude $pwd -- $@rest)
} except { } catch {
} else { } else {
__zoxide_cd $path __zoxide_cd $path
} }
@ -70,7 +70,7 @@ fn __zoxide_zi {|@rest|
var path var path
try { try {
set path = (zoxide query -i -- $@rest) set path = (zoxide query -i -- $@rest)
} except { } catch {
} else { } else {
__zoxide_cd $path __zoxide_cd $path
} }
@ -78,7 +78,7 @@ fn __zoxide_zi {|@rest|
edit:add-var __zoxide_zi~ $__zoxide_zi~ edit:add-var __zoxide_zi~ $__zoxide_zi~
{{ section }} {{ section }}
# Convenient aliases for zoxide. Disable these using --no-aliases. # Commands for zoxide. Disable these using --no-cmd.
# #
{%- match cmd %} {%- match cmd %}
@ -116,4 +116,4 @@ set edit:completion:arg-completer[{{cmd}}] = $__zoxide_z_complete~
# #
# eval (zoxide init elvish | slurp) # eval (zoxide init elvish | slurp)
# #
# Note: zoxide only supports elvish v0.17.0 and above. # Note: zoxide only supports elvish v0.18.0 and above.

View File

@ -53,7 +53,7 @@ end
{%- endif %} {%- endif %}
{{ section }} {{ section }}
# When using zoxide with --no-aliases, alias these internal functions as # When using zoxide with --no-cmd, alias these internal functions as
# desired. # desired.
# #
@ -84,8 +84,8 @@ function __zoxide_z_complete
# If the last argument is empty, use interactive selection. # If the last argument is empty, use interactive selection.
set -l query $tokens[2..-1] set -l query $tokens[2..-1]
set -l result (zoxide query -i -- $query) set -l result (zoxide query -i -- $query)
and commandline -p "$tokens[1] "(string escape $result) commandline --current-process "$tokens[1] "(string escape $result)
commandline -f repaint commandline --function repaint
end end
end end
@ -96,7 +96,7 @@ function __zoxide_zi
end end
{{ section }} {{ section }}
# Convenient aliases for zoxide. Disable these using --no-aliases. # Commands for zoxide. Disable these using --no-cmd.
# #
{%- match cmd %} {%- match cmd %}

View File

@ -45,7 +45,7 @@ $'zoxide: PWD hooks are not supported on Nushell.(char nl)Use (char sq)zoxide in
{%- endmatch %} {%- endmatch %}
{{ section }} {{ section }}
# When using zoxide with --no-aliases, alias these internal functions as # When using zoxide with --no-cmd, alias these internal functions as
# desired. # desired.
# #
@ -86,7 +86,7 @@ def __zoxide_zi [...rest:string] {
} }
{{ section }} {{ section }}
# Convenient aliases for zoxide. Disable these using --no-aliases. # Commands for zoxide. Disable these using --no-cmd.
# #
{%- match cmd %} {%- match cmd %}

View File

@ -47,7 +47,7 @@ fi
{%- endmatch %} {%- endmatch %}
{{ section }} {{ section }}
# When using zoxide with --no-aliases, alias these internal functions as # When using zoxide with --no-cmd, alias these internal functions as
# desired. # desired.
# #
@ -77,7 +77,7 @@ __zoxide_zi() {
} }
{{ section }} {{ section }}
# Convenient aliases for zoxide. Disable these using --no-aliases. # Commands for zoxide. Disable these using --no-cmd.
# #
{%- match cmd %} {%- match cmd %}

View File

@ -67,7 +67,7 @@ if ($__zoxide_hooked -ne 1) {
} }
{{ section }} {{ section }}
# When using zoxide with --no-aliases, alias these internal functions as # When using zoxide with --no-cmd, alias these internal functions as
# desired. # desired.
# #
@ -105,7 +105,7 @@ function __zoxide_zi {
} }
{{ section }} {{ section }}
# Convenient aliases for zoxide. Disable these using --no-aliases. # Commands for zoxide. Disable these using --no-cmd.
# #
{%- match cmd %} {%- match cmd %}

View File

@ -108,7 +108,7 @@ if "__zoxide_hook" not in globals():
{% endif %} {% endif %}
{{ section }} {{ section }}
# When using zoxide with --no-aliases, alias these internal functions as # When using zoxide with --no-cmd, alias these internal functions as
# desired. # desired.
# #
@ -157,7 +157,7 @@ def __zoxide_zi(args: typing.List[str]) -> None:
{{ section }} {{ section }}
# Convenient aliases for zoxide. Disable these using --no-aliases. # Commands for zoxide. Disable these using --no-cmd.
# #
{%- match cmd %} {%- match cmd %}

View File

@ -46,7 +46,7 @@ fi
{%- endif %} {%- endif %}
{{ section }} {{ section }}
# When using zoxide with --no-aliases, alias these internal functions as # When using zoxide with --no-cmd, alias these internal functions as
# desired. # desired.
# #
@ -85,7 +85,7 @@ function __zoxide_zi() {
} }
{{ section }} {{ section }}
# Convenient aliases for zoxide. Disable these using --no-aliases. # Commands for zoxide. Disable these using --no-cmd.
# #
{%- match cmd %} {%- match cmd %}

View File

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

View File

@ -6,6 +6,6 @@ publish = false
[dependencies] [dependencies]
anyhow = "1.0.32" anyhow = "1.0.32"
clap = { version = "3.0.0", features = ["derive"] } clap = { version = "3.1.0", features = ["derive"] }
ignore = "0.4.18" ignore = "0.4.18"
shell-words = "1.0.0" shell-words = "1.0.0"

View File

@ -8,11 +8,10 @@ use std::path::PathBuf;
use std::process::{self, Command}; use std::process::{self, Command};
fn main() -> Result<()> { fn main() -> Result<()> {
let nix_enabled = enable_nix();
let dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); let dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let dir = dir.parent().with_context(|| format!("could not find workspace root: {}", dir.display()))?; let dir = dir.parent().with_context(|| format!("could not find workspace root: {}", dir.display()))?;
env::set_current_dir(dir).with_context(|| format!("could not set current directory: {}", dir.display()))?; env::set_current_dir(dir).with_context(|| format!("could not set current directory: {}", dir.display()))?;
let nix_enabled = enable_nix();
let app = App::parse(); let app = App::parse();
match app { match app {
@ -147,8 +146,11 @@ fn enable_nix() -> bool {
println!("Detected Nix in environment, re-running in Nix."); println!("Detected Nix in environment, re-running in Nix.");
let args = env::args(); let args = env::args();
let cmd = shell_words::join(args); let cmd = shell_words::join(args);
let mut nix_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
nix_path.push("../shell.nix"); let status = Command::new("nix-shell")
let status = Command::new("nix-shell").args(&["--pure", "--run", &cmd, "--"]).arg(nix_path).status().unwrap(); .args(&["--pure", "--run", &cmd, "--", "shell.nix"])
.env("CARGO_TARGET_DIR", "target_nix")
.status()
.unwrap();
process::exit(status.code().unwrap_or(1)); process::exit(status.code().unwrap_or(1));
} }