diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index d6427cc..87368c6 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -21,7 +21,7 @@ jobs:
matrix:
os: [ubuntu-latest]
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
with:
fetch-depth: 0
- uses: actions-rs/toolchain@v1
@@ -46,7 +46,7 @@ jobs:
authToken: ${{ env.CACHIX_AUTH_TOKEN }}
name: zoxide
- name: Setup cache
- uses: Swatinem/rust-cache@v2.7.8
+ uses: Swatinem/rust-cache@v2.8.1
with:
key: ${{ matrix.os }}
- name: Install just
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 6a23046..7398a6a 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -42,7 +42,7 @@ jobs:
target: aarch64-pc-windows-msvc
steps:
- name: Checkout repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Get version
@@ -59,7 +59,7 @@ jobs:
override: true
target: ${{ matrix.target }}
- name: Setup cache
- uses: Swatinem/rust-cache@v2.7.8
+ uses: Swatinem/rust-cache@v2.8.1
with:
key: ${{ matrix.target }}
- name: Install cross
@@ -67,7 +67,7 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: install
- args: --color=always --git=https://github.com/cross-rs/cross.git --locked --rev=02bf930e0cb0c6f1beffece0788f3932ecb2c7eb --verbose cross
+ args: --color=always --git=https://github.com/cross-rs/cross.git --locked --rev=e281947ca900da425e4ecea7483cfde646c8a1ea --verbose cross
- name: Build binary
uses: actions-rs/cargo@v1
with:
@@ -100,7 +100,7 @@ jobs:
CHANGELOG.md LICENSE README.md ./man/ ./contrib/completions/ `
./target/${{ matrix.target }}/release/zoxide.exe
- name: Upload artifact
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v5
with:
name: ${{ matrix.target }}
path: |
diff --git a/Cargo.lock b/Cargo.lock
index 25a01db..732e696 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -335,7 +335,19 @@ checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
dependencies = [
"cfg-if",
"libc",
- "wasi",
+ "wasi 0.11.0+wasi-snapshot-preview1",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "r-efi",
+ "wasi 0.14.2+wasi-0.2.4",
]
[[package]]
@@ -384,12 +396,6 @@ dependencies = [
"libc",
]
-[[package]]
-name = "linux-raw-sys"
-version = "0.4.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
-
[[package]]
name = "linux-raw-sys"
version = "0.9.4"
@@ -545,6 +551,12 @@ dependencies = [
"proc-macro2",
]
+[[package]]
+name = "r-efi"
+version = "5.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
+
[[package]]
name = "rand"
version = "0.8.5"
@@ -572,7 +584,7 @@ version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
- "getrandom",
+ "getrandom 0.2.16",
]
[[package]]
@@ -581,7 +593,7 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b"
dependencies = [
- "getrandom",
+ "getrandom 0.2.16",
"libredox",
"thiserror",
]
@@ -623,19 +635,18 @@ checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2"
[[package]]
name = "rstest"
-version = "0.25.0"
+version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6fc39292f8613e913f7df8fa892b8944ceb47c247b78e1b1ae2f09e019be789d"
+checksum = "f5a3193c063baaa2a95a33f03035c8a72b83d97a54916055ba22d35ed3839d49"
dependencies = [
"rstest_macros",
- "rustc_version",
]
[[package]]
name = "rstest_macros"
-version = "0.25.0"
+version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f168d99749d307be9de54d23fd226628d99768225ef08f6ffb52e0182a27746"
+checksum = "9c845311f0ff7951c5506121a9ad75aec44d083c31583b2ea5a30bcb0b0abba0"
dependencies = [
"cfg-if",
"glob",
@@ -674,19 +685,6 @@ dependencies = [
"semver",
]
-[[package]]
-name = "rustix"
-version = "0.38.44"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
-dependencies = [
- "bitflags",
- "errno",
- "libc",
- "linux-raw-sys 0.4.15",
- "windows-sys",
-]
-
[[package]]
name = "rustix"
version = "1.0.7"
@@ -696,7 +694,7 @@ dependencies = [
"bitflags",
"errno",
"libc",
- "linux-raw-sys 0.9.4",
+ "linux-raw-sys",
"windows-sys",
]
@@ -769,15 +767,14 @@ dependencies = [
[[package]]
name = "tempfile"
-version = "3.15.0"
+version = "3.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704"
+checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1"
dependencies = [
- "cfg-if",
"fastrand",
- "getrandom",
+ "getrandom 0.3.3",
"once_cell",
- "rustix 0.38.44",
+ "rustix",
"windows-sys",
]
@@ -840,6 +837,15 @@ version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+[[package]]
+name = "wasi"
+version = "0.14.2+wasi-0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
+dependencies = [
+ "wit-bindgen-rt",
+]
+
[[package]]
name = "which"
version = "7.0.3"
@@ -848,7 +854,7 @@ checksum = "24d643ce3fd3e5b54854602a080f34fb10ab75e0b813ee32d00ca2b44fa74762"
dependencies = [
"either",
"env_home",
- "rustix 1.0.7",
+ "rustix",
"winsafe",
]
@@ -940,6 +946,15 @@ version = "0.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
+[[package]]
+name = "wit-bindgen-rt"
+version = "0.39.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
+dependencies = [
+ "bitflags",
+]
+
[[package]]
name = "yansi"
version = "1.0.1"
diff --git a/Cargo.toml b/Cargo.toml
index 8e9fb37..58b0d57 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -49,9 +49,9 @@ color-print = "0.3.4"
[dev-dependencies]
assert_cmd = "2.0.0"
-rstest = { version = "0.25.0", default-features = false }
+rstest = { version = "0.26.0", default-features = false }
rstest_reuse = "0.7.0"
-tempfile = "=3.15.0"
+tempfile = "3.15.0"
[features]
default = []
diff --git a/README.md b/README.md
index 9ddd8d8..b397f82 100644
--- a/README.md
+++ b/README.md
@@ -11,12 +11,13 @@
Special thanks to:
-

-Warp, the intelligent terminal
-Available for MacOS, Linux, and Windows
+
+
+Warp, built for coding with multiple AI agents.
+Available for macOS, Linux, and Windows.
@@ -62,10 +63,6 @@ z foo # show interactive completions (zoxide v0.8.0+, bash 4.4+/fis
Read more about the matching algorithm [here][algorithm-matching].
-
-
-
-
## Installation
zoxide can be installed in 4 easy steps:
@@ -86,35 +83,30 @@ zoxide can be installed in 4 easy steps:
>
> Or, you can use a package manager:
>
- > | Distribution | Repository | Instructions |
- > | ------------------- | ------------------------- | ----------------------------------------------------------------------------------------------------- |
- > | **_Any_** | **[crates.io]** | `cargo install zoxide --locked` |
- > | _Any_ | [asdf] | `asdf plugin add zoxide https://github.com/nyrst/asdf-zoxide.git`
`asdf install zoxide latest` |
- > | _Any_ | [conda-forge] | `conda install -c conda-forge zoxide` |
- > | _Any_ | [guix] | `guix install zoxide` |
- > | _Any_ | [Linuxbrew] | `brew install zoxide` |
- > | _Any_ | [nixpkgs] | `nix-env -iA nixpkgs.zoxide` |
- > | AlmaLinux 8–9[^3] | | `dnf install zoxide` |
- > | Alpine Linux 3.13+ | [Alpine Linux Packages] | `apk add zoxide` |
- > | Arch Linux | [Arch Linux Extra] | `pacman -S zoxide` |
- > | CentOS Stream 8–9 | | `dnf install zoxide` |
- > | ~Debian 11+~[^1] | ~[Debian Packages]~ | ~`apt install zoxide`~ |
- > | Devuan 4.0+ | [Devuan Packages] | `apt install zoxide` |
- > | Exherbo Linux | [Exherbo packages] | `cave resolve -x repository/rust`
`cave resolve -x zoxide` |
- > | Fedora 32+ | [Fedora Packages] | `dnf install zoxide` |
- > | Gentoo | [Gentoo Packages] | `emerge app-shells/zoxide` |
- > | Linux Mint | [apt.cli.rs] (unofficial) | [Setup the repository][apt.cli.rs-setup], then `apt install zoxide` |
- > | Manjaro | | `pacman -S zoxide` |
- > | openSUSE Tumbleweed | [openSUSE Factory] | `zypper install zoxide` |
- > | ~Parrot OS~[^1] | | ~`apt install zoxide`~ |
- > | ~Raspbian 11+~[^1] | ~[Raspbian Packages]~ | ~`apt install zoxide`~ |
- > | RHEL 8–9[^3] | | `dnf install zoxide` |
- > | Rhino Linux | [Pacstall Packages] | `pacstall -I zoxide-deb` |
- > | Rocky Linux 8–9[^3] | | `dnf install zoxide` |
- > | Slackware 15.0+ | [SlackBuilds] | [Instructions][slackbuilds-howto] |
- > | Solus | [Solus Packages] | `eopkg install zoxide` |
- > | Ubuntu | [apt.cli.rs] (unofficial) | [Setup the repository][apt.cli.rs-setup], then `apt install zoxide` |
- > | Void Linux | [Void Linux Packages] | `xbps-install -S zoxide` |
+ > | Distribution | Repository | Instructions |
+ > | ------------------- | --------------------------- | ----------------------------------------------------------------------------------------------------- |
+ > | **_Any_** | **[crates.io]** | `cargo install zoxide --locked` |
+ > | _Any_ | [asdf] | `asdf plugin add zoxide https://github.com/nyrst/asdf-zoxide.git`
`asdf install zoxide latest` |
+ > | _Any_ | [conda-forge] | `conda install -c conda-forge zoxide` |
+ > | _Any_ | [guix] | `guix install zoxide` |
+ > | _Any_ | [Linuxbrew] | `brew install zoxide` |
+ > | _Any_ | [nixpkgs] | `nix-env -iA nixpkgs.zoxide` |
+ > | Alpine Linux 3.13+ | [Alpine Linux Packages] | `apk add zoxide` |
+ > | Arch Linux | [Arch Linux Extra] | `pacman -S zoxide` |
+ > | ~Debian~[^1] | ~[Debian Packages]~ | ~`apt install zoxide`~ |
+ > | Devuan 4.0+ | [Devuan Packages] | `apt install zoxide` |
+ > | Exherbo Linux | [Exherbo packages] | `cave resolve -x repository/rust`
`cave resolve -x zoxide` |
+ > | Fedora 32+ | [Fedora Packages] | `dnf install zoxide` |
+ > | Gentoo | [Gentoo Packages] | `emerge app-shells/zoxide` |
+ > | Manjaro | | `pacman -S zoxide` |
+ > | openSUSE Tumbleweed | [openSUSE Factory] | `zypper install zoxide` |
+ > | ~Parrot OS~[^1] | | ~`apt install zoxide`~ |
+ > | ~Raspbian~[^1] | ~[Raspbian Packages]~ | ~`apt install zoxide`~ |
+ > | Rhino Linux | [Pacstall Packages] | `pacstall -I zoxide-deb` |
+ > | Slackware 15.0+ | [SlackBuilds] | [Instructions][slackbuilds-howto] |
+ > | Solus | [Solus Packages] | `eopkg install zoxide` |
+ > | ~Ubuntu~[^1] | ~[Ubuntu Packages]~ | ~`apt install zoxide`~ |
+ > | Void Linux | [Void Linux Packages] | `xbps-install -S zoxide` |
@@ -474,6 +466,7 @@ Environment variables[^2] can be used for configuration. They must be set before
| [lf] | File manager | See the [wiki][lf-wiki] |
| [nnn] | File manager | [nnn-autojump] |
| [ranger] | File manager | [ranger-zoxide] |
+| [raycast] | macOS launcher | [raycast-zoxide] |
| [rfm] | File manager | Natively supported |
| [sesh] | `tmux` session manager | Natively supported |
| [telescope.nvim] | Fuzzy finder for Neovim | [telescope-zoxide] |
@@ -488,24 +481,19 @@ Environment variables[^2] can be used for configuration. They must be set before
| [zsh-autocomplete] | Realtime completions for zsh | Natively supported |
[^1]:
- Debian and its derivatives update their packages very slowly. If you're
+ Debian / Ubuntu derivatives update their packages very slowly. If you're
using one of these distributions, consider using the install script instead.
[^2]:
If you're not sure how to set an environment variable on your shell, check
out the [wiki][wiki-env].
-[^3]:
- Zoxide won't be branched for EPEL 10 due to lack of maintainer.
-
[aerc]: https://github.com/rjarry/aerc
[alfred]: https://www.alfredapp.com/
[alfred-zoxide]: https://github.com/yihou/alfred-zoxide
[algorithm-aging]: https://github.com/ajeetdsouza/zoxide/wiki/Algorithm#aging
[algorithm-matching]: https://github.com/ajeetdsouza/zoxide/wiki/Algorithm#matching
[alpine linux packages]: https://pkgs.alpinelinux.org/packages?name=zoxide
-[apt.cli.rs]: https://apt.cli.rs/
-[apt.cli.rs-setup]: https://github.com/emmatyping/apt.cli.rs#how-to-add-the-repo
[arch linux extra]: https://archlinux.org/packages/extra/x86_64/zoxide/
[asdf]: https://github.com/asdf-vm/asdf
[builtwithnix-badge]: https://img.shields.io/badge/builtwith-nix-7d81f7?logo=nixos&logoColor=white&style=flat-square
@@ -548,6 +536,8 @@ Environment variables[^2] can be used for configuration. They must be set before
[ranger-zoxide]: https://github.com/jchook/ranger-zoxide
[ranger]: https://github.com/ranger/ranger
[raspbian packages]: https://archive.raspbian.org/raspbian/pool/main/r/rust-zoxide/
+[raycast]: https://www.raycast.com/
+[raycast-zoxide]: https://www.raycast.com/mrpunkin/raycast-zoxide
[releases]: https://github.com/ajeetdsouza/zoxide/releases
[rfm]: https://github.com/dsxmachina/rfm
[scoop]: https://github.com/ScoopInstaller/Main/tree/master/bucket/zoxide.json
@@ -561,6 +551,7 @@ Environment variables[^2] can be used for configuration. They must be set before
[tmux-session-wizard]: https://github.com/27medkamal/tmux-session-wizard
[tmux-sessionx]: https://github.com/omerxx/tmux-sessionx
[tutorial]: contrib/tutorial.webp
+[ubuntu packages]: https://packages.ubuntu.com/jammy/zoxide
[vim]: https://github.com/vim/vim
[void linux packages]: https://github.com/void-linux/void-packages/tree/master/srcpkgs/zoxide
[wiki-env]: https://github.com/ajeetdsouza/zoxide/wiki/HOWTO:-set-environment-variables "HOWTO: set environment variables"
diff --git a/contrib/completions/_zoxide b/contrib/completions/_zoxide
index 33aaace..97e654f 100644
--- a/contrib/completions/_zoxide
+++ b/contrib/completions/_zoxide
@@ -120,6 +120,7 @@ _arguments "${_arguments_options[@]}" : \
(query)
_arguments "${_arguments_options[@]}" : \
'--exclude=[Exclude the current directory]:path:_files -/' \
+'--base-dir=[Only search within this directory]:path:_files -/' \
'-a[Show unavailable directories]' \
'--all[Show unavailable directories]' \
'(-l --list)-i[Use interactive selection]' \
diff --git a/contrib/completions/_zoxide.ps1 b/contrib/completions/_zoxide.ps1
index a26adda..bb47d3a 100644
--- a/contrib/completions/_zoxide.ps1
+++ b/contrib/completions/_zoxide.ps1
@@ -102,6 +102,7 @@ Register-ArgumentCompleter -Native -CommandName 'zoxide' -ScriptBlock {
}
'zoxide;query' {
[CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'Exclude the current directory')
+ [CompletionResult]::new('--base-dir', '--base-dir', [CompletionResultType]::ParameterName, 'Only search within this directory')
[CompletionResult]::new('-a', '-a', [CompletionResultType]::ParameterName, 'Show unavailable directories')
[CompletionResult]::new('--all', '--all', [CompletionResultType]::ParameterName, 'Show unavailable directories')
[CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'Use interactive selection')
diff --git a/contrib/completions/zoxide.bash b/contrib/completions/zoxide.bash
index 1c2ed84..82b174e 100644
--- a/contrib/completions/zoxide.bash
+++ b/contrib/completions/zoxide.bash
@@ -199,7 +199,7 @@ _zoxide() {
return 0
;;
zoxide__query)
- opts="-a -i -l -s -h -V --all --interactive --list --score --exclude --help --version [KEYWORDS]..."
+ opts="-a -i -l -s -h -V --all --interactive --list --score --exclude --base-dir --help --version [KEYWORDS]..."
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
@@ -212,6 +212,13 @@ _zoxide() {
fi
return 0
;;
+ --base-dir)
+ COMPREPLY=()
+ if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
+ compopt -o plusdirs
+ fi
+ return 0
+ ;;
*)
COMPREPLY=()
;;
diff --git a/contrib/completions/zoxide.elv b/contrib/completions/zoxide.elv
index e4cb36b..93c57af 100644
--- a/contrib/completions/zoxide.elv
+++ b/contrib/completions/zoxide.elv
@@ -90,6 +90,7 @@ set edit:completion:arg-completer[zoxide] = {|@words|
}
&'zoxide;query'= {
cand --exclude 'Exclude the current directory'
+ cand --base-dir 'Only search within this directory'
cand -a 'Show unavailable directories'
cand --all 'Show unavailable directories'
cand -i 'Use interactive selection'
diff --git a/contrib/completions/zoxide.fish b/contrib/completions/zoxide.fish
index 85c3c49..3a0bfe7 100644
--- a/contrib/completions/zoxide.fish
+++ b/contrib/completions/zoxide.fish
@@ -62,6 +62,7 @@ complete -c zoxide -n "__fish_zoxide_using_subcommand init" -l no-cmd -d 'Preven
complete -c zoxide -n "__fish_zoxide_using_subcommand init" -s h -l help -d 'Print help'
complete -c zoxide -n "__fish_zoxide_using_subcommand init" -s V -l version -d 'Print version'
complete -c zoxide -n "__fish_zoxide_using_subcommand query" -l exclude -d 'Exclude the current directory' -r -f -a "(__fish_complete_directories)"
+complete -c zoxide -n "__fish_zoxide_using_subcommand query" -l base-dir -d 'Only search within this directory' -r -f -a "(__fish_complete_directories)"
complete -c zoxide -n "__fish_zoxide_using_subcommand query" -s a -l all -d 'Show unavailable directories'
complete -c zoxide -n "__fish_zoxide_using_subcommand query" -s i -l interactive -d 'Use interactive selection'
complete -c zoxide -n "__fish_zoxide_using_subcommand query" -s l -l list -d 'List all matching directories'
diff --git a/contrib/completions/zoxide.nu b/contrib/completions/zoxide.nu
index 34b3ac0..642908e 100644
--- a/contrib/completions/zoxide.nu
+++ b/contrib/completions/zoxide.nu
@@ -82,6 +82,7 @@ module completions {
--list(-l) # List all matching directories
--score(-s) # Print score with results
--exclude: path # Exclude the current directory
+ --base-dir: path # Only search within this directory
--help(-h) # Print help
--version(-V) # Print version
]
diff --git a/contrib/completions/zoxide.ts b/contrib/completions/zoxide.ts
index 9e593d0..1e0d404 100644
--- a/contrib/completions/zoxide.ts
+++ b/contrib/completions/zoxide.ts
@@ -214,6 +214,16 @@ const completion: Fig.Spec = {
template: "folders",
},
},
+ {
+ name: "--base-dir",
+ description: "Only search within this directory",
+ isRepeatable: true,
+ args: {
+ name: "base_dir",
+ isOptional: true,
+ template: "folders",
+ },
+ },
{
name: ["-a", "--all"],
description: "Show unavailable directories",
diff --git a/contrib/warp-packs-green.png b/contrib/warp-packs-green.png
deleted file mode 100644
index f10f0e4..0000000
Binary files a/contrib/warp-packs-green.png and /dev/null differ
diff --git a/contrib/warp.png b/contrib/warp.png
deleted file mode 100644
index 897cd24..0000000
Binary files a/contrib/warp.png and /dev/null differ
diff --git a/src/cmd/cmd.rs b/src/cmd/cmd.rs
index d25cda3..7359786 100644
--- a/src/cmd/cmd.rs
+++ b/src/cmd/cmd.rs
@@ -186,6 +186,10 @@ pub struct Query {
/// Exclude the current directory
#[clap(long, value_hint = ValueHint::DirPath, value_name = "path")]
pub exclude: Option,
+
+ /// Only search within this directory
+ #[clap(long, value_hint = ValueHint::DirPath, value_name = "path")]
+ pub base_dir: Option,
}
/// Remove a directory from the database
diff --git a/src/cmd/query.rs b/src/cmd/query.rs
index 362d80a..6539c2e 100644
--- a/src/cmd/query.rs
+++ b/src/cmd/query.rs
@@ -79,7 +79,8 @@ impl Query {
fn get_stream<'a>(&self, db: &'a mut Database, now: Epoch) -> Result> {
let mut options = StreamOptions::new(now)
.with_keywords(self.keywords.iter().map(|s| s.as_str()))
- .with_exclude(config::exclude_dirs()?);
+ .with_exclude(config::exclude_dirs()?)
+ .with_base_dir(self.base_dir.clone());
if !self.all {
let resolve_symlinks = config::resolve_symlinks();
options = options.with_exists(true).with_resolve_symlinks(resolve_symlinks);
diff --git a/src/db/mod.rs b/src/db/mod.rs
index a19efe9..d459f39 100644
--- a/src/db/mod.rs
+++ b/src/db/mod.rs
@@ -183,7 +183,7 @@ impl Database {
*self.borrow_dirty()
}
- pub fn dirs(&self) -> &[Dir] {
+ pub fn dirs(&self) -> &[Dir<'_>] {
self.borrow_dirs()
}
@@ -203,7 +203,7 @@ impl Database {
.context("could not serialize database")
}
- fn deserialize(bytes: &[u8]) -> Result> {
+ fn deserialize(bytes: &[u8]) -> Result>> {
// Assume a maximum size for the database. This prevents bincode from throwing
// strange errors when it encounters invalid data.
const MAX_SIZE: u64 = 32 << 20; // 32 MiB
diff --git a/src/db/stream.rs b/src/db/stream.rs
index 4af7d7a..4b06193 100644
--- a/src/db/stream.rs
+++ b/src/db/stream.rs
@@ -1,5 +1,6 @@
use std::iter::Rev;
use std::ops::Range;
+use std::path::Path;
use std::{fs, path};
use glob::Pattern;
@@ -20,7 +21,7 @@ impl<'a> Stream<'a> {
Stream { db, idxs, options }
}
- pub fn next(&mut self) -> Option<&Dir> {
+ pub fn next(&mut self) -> Option<&Dir<'_>> {
while let Some(idx) = self.idxs.next() {
let dir = &self.db.dirs()[idx];
@@ -28,11 +29,16 @@ impl<'a> Stream<'a> {
continue;
}
+ if !self.filter_by_base_dir(&dir.path) {
+ continue;
+ }
+
if !self.filter_by_exclude(&dir.path) {
self.db.swap_remove(idx);
continue;
}
+ // Exists queries are slow, this should always be checked last.
if !self.filter_by_exists(&dir.path) {
if dir.last_accessed < self.options.ttl {
self.db.swap_remove(idx);
@@ -47,6 +53,30 @@ impl<'a> Stream<'a> {
None
}
+ fn filter_by_base_dir(&self, path: &str) -> bool {
+ match &self.options.base_dir {
+ Some(base_dir) => Path::new(path).starts_with(base_dir),
+ None => true,
+ }
+ }
+
+ fn filter_by_exclude(&self, path: &str) -> bool {
+ !self.options.exclude.iter().any(|pattern| pattern.matches(path))
+ }
+
+ fn filter_by_exists(&self, path: &str) -> bool {
+ if !self.options.exists {
+ return true;
+ }
+
+ // The logic here is reversed - if we resolve symlinks when adding entries to
+ // the database, we should not return symlinks when querying back from
+ // the database.
+ let resolver =
+ if self.options.resolve_symlinks { fs::symlink_metadata } else { fs::metadata };
+ resolver(path).map(|metadata| metadata.is_dir()).unwrap_or_default()
+ }
+
fn filter_by_keywords(&self, path: &str) -> bool {
let (keywords_last, keywords) = match self.options.keywords.split_last() {
Some(split) => split,
@@ -74,23 +104,6 @@ impl<'a> Stream<'a> {
true
}
-
- fn filter_by_exclude(&self, path: &str) -> bool {
- !self.options.exclude.iter().any(|pattern| pattern.matches(path))
- }
-
- fn filter_by_exists(&self, path: &str) -> bool {
- if !self.options.exists {
- return true;
- }
-
- // The logic here is reversed - if we resolve symlinks when adding entries to
- // the database, we should not return symlinks when querying back from
- // the database.
- let resolver =
- if self.options.resolve_symlinks { fs::symlink_metadata } else { fs::metadata };
- resolver(path).map(|metadata| metadata.is_dir()).unwrap_or_default()
- }
}
pub struct StreamOptions {
@@ -112,6 +125,10 @@ pub struct StreamOptions {
/// Directories that do not exist and haven't been accessed since TTL will
/// be lazily removed.
ttl: Epoch,
+
+ /// Only return directories within this parent directory
+ /// Does not check if the path exists
+ base_dir: Option,
}
impl StreamOptions {
@@ -123,6 +140,7 @@ impl StreamOptions {
exists: false,
resolve_symlinks: false,
ttl: now.saturating_sub(3 * MONTH),
+ base_dir: None,
}
}
@@ -149,6 +167,11 @@ impl StreamOptions {
self.resolve_symlinks = resolve_symlinks;
self
}
+
+ pub fn with_base_dir(mut self, base_dir: Option) -> Self {
+ self.base_dir = base_dir;
+ self
+ }
}
#[cfg(test)]
diff --git a/src/shell.rs b/src/shell.rs
index e77ddd1..37fe1a2 100644
--- a/src/shell.rs
+++ b/src/shell.rs
@@ -97,7 +97,7 @@ mod tests {
#[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::default();
+ let mut source = String::new();
// Filter out lines using edit:*, since those functions are only available in
// the interactive editor.
diff --git a/src/util.rs b/src/util.rs
index f74acaf..996f61d 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -135,7 +135,7 @@ impl FzfChild {
mem::drop(self.0.stdin.take());
let mut stdout = self.0.stdout.take().unwrap();
- let mut output = String::default();
+ let mut output = String::new();
stdout.read_to_string(&mut output).context("failed to read from fzf")?;
let status = self.0.wait().context("wait failed on fzf")?;
diff --git a/templates/bash.txt b/templates/bash.txt
index 84be3a0..8c96deb 100644
--- a/templates/bash.txt
+++ b/templates/bash.txt
@@ -55,7 +55,12 @@ function __zoxide_hook() {
# Initialize hook.
if [[ ${PROMPT_COMMAND:=} != *'__zoxide_hook'* ]]; then
- PROMPT_COMMAND="__zoxide_hook;${PROMPT_COMMAND#;}"
+ if [[ "$(declare -p PROMPT_COMMAND 2>&1)" == "declare -a"* ]]; then
+ PROMPT_COMMAND=(__zoxide_hook "${PROMPT_COMMAND[@]}")
+ else
+ # shellcheck disable=SC2178
+ PROMPT_COMMAND="__zoxide_hook;${PROMPT_COMMAND#;}"
+ fi
fi
{%- endif %}
diff --git a/templates/zsh.txt b/templates/zsh.txt
index 631251a..80cd428 100644
--- a/templates/zsh.txt
+++ b/templates/zsh.txt
@@ -84,7 +84,7 @@ function __zoxide_z() {
__zoxide_doctor
if [[ "$#" -eq 0 ]]; then
__zoxide_cd ~
- elif [[ "$#" -eq 1 ]] && { [[ -d "$1" ]] || [[ "$1" = '-' ]] || [[ "$1" =~ ^[-+][0-9]$ ]]; }; then
+ elif [[ "$#" -eq 1 ]] && { [[ -d "$1" ]] || [[ "$1" = '-' ]] || [[ "$1" =~ ^[-+][0-9]+$ ]]; }; then
__zoxide_cd "$1"
elif [[ "$#" -eq 2 ]] && [[ "$1" = "--" ]]; then
__zoxide_cd "$2"