Merge branch 'main' of github.com:ajeetdsouza/zoxide

This commit is contained in:
dracarys18 2026-06-07 01:38:56 +05:30
commit e3613ec49b
No known key found for this signature in database
36 changed files with 1824 additions and 671 deletions

16
.github/workflows/cd.yml vendored Normal file
View File

@ -0,0 +1,16 @@
name: Continuous Deployment
on:
push:
tags:
- "v*.*.*"
jobs:
publish-crates-io:
name: Publish on crates.io
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v6
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Publish
run: cargo publish --token ${{ secrets.CARGO_TOKEN }}

View File

@ -21,7 +21,7 @@ jobs:
matrix: matrix:
os: [ubuntu-latest] os: [ubuntu-latest]
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
with: with:
fetch-depth: 0 fetch-depth: 0
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
@ -40,13 +40,13 @@ jobs:
if: ${{ matrix.os != 'windows-latest' }} if: ${{ matrix.os != 'windows-latest' }}
with: with:
nix_path: nixpkgs=channel:nixos-unstable nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v16 - uses: cachix/cachix-action@v17
if: ${{ matrix.os != 'windows-latest' && env.CACHIX_AUTH_TOKEN != '' }} if: ${{ matrix.os != 'windows-latest' && env.CACHIX_AUTH_TOKEN != '' }}
with: with:
authToken: ${{ env.CACHIX_AUTH_TOKEN }} authToken: ${{ env.CACHIX_AUTH_TOKEN }}
name: zoxide name: zoxide
- name: Setup cache - name: Setup cache
uses: Swatinem/rust-cache@v2.8.1 uses: Swatinem/rust-cache@v2.9.1
with: with:
key: ${{ matrix.os }} key: ${{ matrix.os }}
- name: Install just - name: Install just

View File

@ -30,8 +30,13 @@ jobs:
- os: ubuntu-latest - os: ubuntu-latest
target: i686-unknown-linux-musl target: i686-unknown-linux-musl
deb: true deb: true
- os: ubuntu-latest
target: riscv64gc-unknown-linux-musl
deb: true
- os: ubuntu-latest - os: ubuntu-latest
target: aarch64-linux-android target: aarch64-linux-android
- os: ubuntu-latest
target: armv7-linux-androideabi
- os: macos-latest - os: macos-latest
target: x86_64-apple-darwin target: x86_64-apple-darwin
- os: macos-latest - os: macos-latest
@ -42,7 +47,7 @@ jobs:
target: aarch64-pc-windows-msvc target: aarch64-pc-windows-msvc
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v5 uses: actions/checkout@v6
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Get version - name: Get version
@ -59,7 +64,7 @@ jobs:
override: true override: true
target: ${{ matrix.target }} target: ${{ matrix.target }}
- name: Setup cache - name: Setup cache
uses: Swatinem/rust-cache@v2.8.1 uses: Swatinem/rust-cache@v2.9.1
with: with:
key: ${{ matrix.target }} key: ${{ matrix.target }}
- name: Install cross - name: Install cross
@ -100,7 +105,7 @@ jobs:
CHANGELOG.md LICENSE README.md ./man/ ./contrib/completions/ ` CHANGELOG.md LICENSE README.md ./man/ ./contrib/completions/ `
./target/${{ matrix.target }}/release/zoxide.exe ./target/${{ matrix.target }}/release/zoxide.exe
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v7
with: with:
name: ${{ matrix.target }} name: ${{ matrix.target }}
path: | path: |
@ -110,7 +115,7 @@ jobs:
- name: Create release - name: Create release
if: | if: |
github.ref == 'refs/heads/main' && startsWith(github.event.head_commit.message, 'chore(release)') github.ref == 'refs/heads/main' && startsWith(github.event.head_commit.message, 'chore(release)')
uses: softprops/action-gh-release@v2 uses: softprops/action-gh-release@v3
with: with:
draft: true draft: true
files: | files: |

View File

@ -7,6 +7,38 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased
### Added
- POSIX: support for non-Cygwin Windows environments (e.g. Busybox).
- `import` now supports fetching entries from `atuin`.
### Changed
- `import` now auto-detects database files.
### Fixed
- PowerShell: use fully qualified names when invoking cmdlets.
- Bash/Fish/POSIX/Zsh: resolve symlinks on Windows.
## [0.9.9] - 2026-01-31
### Added
- Support for Android ARMv7.
- Fish: support for v4.1.0+.
### Fixed
- Nushell: use sigil operator when calling external commands.
- Zsh: support multiple digits in `z +N` and `z -N` dirstack commands.
- Bash: avoid downcasting `$PROMPT_COMMAND` array into a string.
- Bash: avoid overwriting `$PIPESTATUS`.
- POSIX: remove non-POSIX compliant calls to `builtin`.
- Fish: clear existing completions when defining `z` command.
## [0.9.8] - 2025-05-27 ## [0.9.8] - 2025-05-27
### Added ### Added
@ -22,7 +54,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed ### Fixed
- Bash: doctor now handles `PROMPT_COMMAND` being an array. - Bash: doctor now handles `$PROMPT_COMMAND` being an array.
- Bash: doctor now handles Visual Studio Code's shell integration. - Bash: doctor now handles Visual Studio Code's shell integration.
- Bash: completions now work with `ble.sh`. - Bash: completions now work with `ble.sh`.
- Nushell: stop ignoring symlinks when `cd`-ing into a directory. - Nushell: stop ignoring symlinks when `cd`-ing into a directory.
@ -35,7 +67,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- Nushell: support for 0.102.0. - Nushell: support for v0.102.0.
- Bash / Zsh: add doctor to diagnose common issues. - Bash / Zsh: add doctor to diagnose common issues.
### Fixed ### Fixed
@ -302,7 +334,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `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 - Lazy deletion for removed directories that have not been accessed in > 90
days. days.
- Nushell: support for 0.32.0+. - Nushell: support for v0.32.0+.
### Fixed ### Fixed
@ -536,6 +568,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- GitHub Actions pipeline to build and upload releases. - GitHub Actions pipeline to build and upload releases.
- Add support for Zsh. - Add support for Zsh.
[0.9.9]: https://github.com/ajeetdsouza/zoxide/compare/v0.9.8...v0.9.9
[0.9.8]: https://github.com/ajeetdsouza/zoxide/compare/v0.9.7...v0.9.8 [0.9.8]: https://github.com/ajeetdsouza/zoxide/compare/v0.9.7...v0.9.8
[0.9.7]: https://github.com/ajeetdsouza/zoxide/compare/v0.9.6...v0.9.7 [0.9.7]: https://github.com/ajeetdsouza/zoxide/compare/v0.9.6...v0.9.7
[0.9.6]: https://github.com/ajeetdsouza/zoxide/compare/v0.9.5...v0.9.6 [0.9.6]: https://github.com/ajeetdsouza/zoxide/compare/v0.9.5...v0.9.6

691
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -9,15 +9,15 @@ license = "MIT"
name = "zoxide" name = "zoxide"
readme = "README.md" readme = "README.md"
repository = "https://github.com/ajeetdsouza/zoxide" repository = "https://github.com/ajeetdsouza/zoxide"
rust-version = "1.85.0" rust-version = "1.88.0"
version = "0.9.8" version = "0.9.9"
[badges] [badges]
maintenance = { status = "actively-developed" } maintenance = { status = "actively-developed" }
[dependencies] [dependencies]
anyhow = "1.0.32" anyhow = "1.0.32"
askama = { version = "0.14.0", default-features = false, features = [ askama = { version = "0.16.0", default-features = false, features = [
"derive", "derive",
"std", "std",
] } ] }
@ -30,15 +30,10 @@ fastrand = "2.0.0"
glob = "0.3.0" glob = "0.3.0"
ouroboros = "0.18.3" ouroboros = "0.18.3"
serde = { version = "1.0.116", features = ["derive"] } serde = { version = "1.0.116", features = ["derive"] }
time = { version = "0.3.47", default-features = false, features = ["parsing", "macros", "std"] }
[target.'cfg(unix)'.dependencies]
nix = { version = "0.30.1", default-features = false, features = [
"fs",
"user",
] }
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]
which = "7.0.3" which = "8.0.2"
[build-dependencies] [build-dependencies]
clap = { version = "4.3.0", features = ["derive"] } clap = { version = "4.3.0", features = ["derive"] }

110
README.md
View File

@ -11,15 +11,28 @@
<sup>Special thanks to:</sup> <sup>Special thanks to:</sup>
<!-- markdownlint-disable-next-line MD013 --> <table>
<div><a href="https://go.warp.dev/zoxide"><img alt="Sponsored by Warp" width="230" src="https://raw.githubusercontent.com/warpdotdev/brand-assets/refs/heads/main/Github/Sponsor/Warp-Github-LG-03.png" /></a></div> <tr>
<div><sup><b>Warp, built for coding with multiple AI agents.</b></sup></div> <td align="center">
<div><sup>Available for macOS, Linux, and Windows.</sup></div> <!-- markdownlint-disable-next-line MD013 -->
<div><sup> <a href="https://go.warp.dev/zoxide"><img alt="Sponsored by Warp" width="230" src="https://raw.githubusercontent.com/warpdotdev/brand-assets/refs/heads/main/Github/Sponsor/Warp-Github-LG-03.png" /></a>
Visit <div><sup><b>Warp, built for coding with multiple AI agents.</b></sup></div>
<a href="https://go.warp.dev/zoxide"><u>warp.dev</u></a> <div><sup>Available for macOS, Linux, and Windows.</sup></div>
to learn more. <div><sup>
</sup></div> Visit
<a href="https://go.warp.dev/zoxide"><u>warp.dev</u></a>
to learn more.
</sup></div>
</td>
<td align="center">
<!-- markdownlint-disable-next-line MD013 -->
<a href="https://www.recall.ai/careers?ashby_jid=7b02811e-bc91-4ef2-925d-f56a5acac13b&utm_source=github&utm_medium=sponsorship&utm_campaign=zoxide"><img alt="Sponsored by Recall.ai" width="230" src="https://github.com/user-attachments/assets/0c5cb177-561c-4637-bef6-cf584939c829" /></a>
<div><sup>Processing over 3TB/s of video at peak load,</sup></div>
<!-- markdownlint-disable-next-line MD013 -->
<div><sup>now <a href="https://www.recall.ai/careers?ashby_jid=7b02811e-bc91-4ef2-925d-f56a5acac13b&utm_source=github&utm_medium=sponsorship&utm_campaign=zoxide">hiring in SF.</a></sup></div>
</td>
</tr>
</table>
<hr /> <hr />
@ -58,7 +71,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 4.4+/fish/zsh only) z foo<SPACE><TAB> # show interactive completions (bash 4.4+/fish/zsh only)
``` ```
Read more about the matching algorithm [here][algorithm-matching]. Read more about the matching algorithm [here][algorithm-matching].
@ -222,7 +235,7 @@ zoxide can be installed in 4 easy steps:
> eval (zoxide init elvish | slurp) > eval (zoxide init elvish | slurp)
> ``` > ```
> >
> **Note** > **Note:**
> zoxide only supports elvish v0.18.0 and above. > zoxide only supports elvish v0.18.0 and above.
</details> </details>
@ -256,7 +269,7 @@ zoxide can be installed in 4 easy steps:
> source ~/.zoxide.nu > source ~/.zoxide.nu
> ``` > ```
> >
> **Note** > **Note:**
> zoxide only supports Nushell v0.89.0+. > zoxide only supports Nushell v0.89.0+.
</details> </details>
@ -322,72 +335,36 @@ zoxide can be installed in 4 easy steps:
</details> </details>
> **Note:**
> [Warp] provides its own completions, so `Space+Tab` completions are not
> supported there.
3. **Install fzf** <sup>(optional)</sup> 3. **Install fzf** <sup>(optional)</sup>
[fzf] is a command-line fuzzy finder, used by zoxide for completions / [fzf] is a command-line fuzzy finder, used by zoxide for completions /
interactive selection. It can be installed from [here][fzf-installation]. interactive selection. It can be installed from [here][fzf-installation].
> **Note** > **Note:**
> The minimum supported fzf version is v0.51.0. > The minimum supported fzf version is v0.51.0.
4. **Import your data** <sup>(optional)</sup> 4. **Import your data** <sup>(optional)</sup>
If you currently use any of these plugins, you may want to import your data If you currently use any of these plugins, you may want to import your data
into zoxide: into zoxide. The data file is auto-detected using each plugin's standard
conventions.
<details> ```sh
<summary>autojump</summary> zoxide import <plugin>
```
> Run this command in your terminal: | Plugin | Command |
> | ---------- | ------------------------- |
> ```sh | atuin | `zoxide import atuin` |
> zoxide import --from=autojump "/path/to/autojump/db" | autojump | `zoxide import autojump` |
> ``` | fasd | `zoxide import fasd` |
> | z | `zoxide import z` |
> The path usually varies according to your system: | z.lua | `zoxide import z.lua` |
> | zsh-z | `zoxide import zsh-z` |
> | OS | Path | Example |
> | ------- | ------------------------------------------------------------------------------------ | ------------------------------------------------------ |
> | Linux | `$XDG_DATA_HOME/autojump/autojump.txt` or `$HOME/.local/share/autojump/autojump.txt` | `/home/alice/.local/share/autojump/autojump.txt` |
> | macOS | `$HOME/Library/autojump/autojump.txt` | `/Users/Alice/Library/autojump/autojump.txt` |
> | Windows | `%APPDATA%\autojump\autojump.txt` | `C:\Users\Alice\AppData\Roaming\autojump\autojump.txt` |
</details>
<details>
<summary>fasd, z, z.lua, zsh-z</summary>
> Run this command in your terminal:
>
> ```sh
> zoxide import --from=z "path/to/z/db"
> ```
>
> The path usually varies according to your system:
>
> | Plugin | Path |
> | ---------------- | ----------------------------------------------------------------------------------- |
> | fasd | `$_FASD_DATA` or `$HOME/.fasd` |
> | z (bash/zsh) | `$_Z_DATA` or `$HOME/.z` |
> | z (fish) | `$Z_DATA` or `$XDG_DATA_HOME/z/data` or `$HOME/.local/share/z/data` |
> | z.lua (bash/zsh) | `$_ZL_DATA` or `$HOME/.zlua` |
> | z.lua (fish) | `$XDG_DATA_HOME/zlua/zlua.txt` or `$HOME/.local/share/zlua/zlua.txt` or `$_ZL_DATA` |
> | zsh-z | `$ZSHZ_DATA` or `$_Z_DATA` or `$HOME/.z` |
</details>
<details>
<summary>ZLocation</summary>
> Run this command in PowerShell:
>
> ```powershell
> $db = New-TemporaryFile
> (Get-ZLocation).GetEnumerator() | ForEach-Object { Write-Output ($_.Name+'|'+$_.Value+'|0') } | Out-File $db
> zoxide import --from=z $db
> ```
</details>
## Configuration ## Configuration
@ -554,6 +531,7 @@ Environment variables[^2] can be used for configuration. They must be set before
[ubuntu packages]: https://packages.ubuntu.com/jammy/zoxide [ubuntu packages]: https://packages.ubuntu.com/jammy/zoxide
[vim]: https://github.com/vim/vim [vim]: https://github.com/vim/vim
[void linux packages]: https://github.com/void-linux/void-packages/tree/master/srcpkgs/zoxide [void linux packages]: https://github.com/void-linux/void-packages/tree/master/srcpkgs/zoxide
[warp]: https://www.warp.dev
[wiki-env]: https://github.com/ajeetdsouza/zoxide/wiki/HOWTO:-set-environment-variables "HOWTO: set environment variables" [wiki-env]: https://github.com/ajeetdsouza/zoxide/wiki/HOWTO:-set-environment-variables "HOWTO: set environment variables"
[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

View File

@ -45,7 +45,7 @@ _arguments "${_arguments_options[@]}" : \
'--help[Print help]' \ '--help[Print help]' \
'-V[Print version]' \ '-V[Print version]' \
'--version[Print version]' \ '--version[Print version]' \
":: :_zoxide__edit_commands" \ ":: :_zoxide__subcmd__edit_commands" \
"*::: :->edit" \ "*::: :->edit" \
&& ret=0 && ret=0
@ -96,14 +96,78 @@ esac
;; ;;
(import) (import)
_arguments "${_arguments_options[@]}" : \ _arguments "${_arguments_options[@]}" : \
'--from=[Application to import from]:FROM:(autojump z)' \
'--merge[Merge into existing database]' \ '--merge[Merge into existing database]' \
'-h[Print help]' \ '-h[Print help]' \
'--help[Print help]' \ '--help[Print help]' \
'-V[Print version]' \ '-V[Print version]' \
'--version[Print version]' \ '--version[Print version]' \
':path:_files' \ ":: :_zoxide__subcmd__import_commands" \
"*::: :->import" \
&& ret=0 && ret=0
case $state in
(import)
words=($line[1] "${words[@]}")
(( CURRENT += 1 ))
curcontext="${curcontext%:*:*}:zoxide-import-command-$line[1]:"
case $line[1] in
(atuin)
_arguments "${_arguments_options[@]}" : \
'--merge[Merge into existing database]' \
'-h[Print help]' \
'--help[Print help]' \
'-V[Print version]' \
'--version[Print version]' \
&& ret=0
;;
(autojump)
_arguments "${_arguments_options[@]}" : \
'--merge[Merge into existing database]' \
'-h[Print help]' \
'--help[Print help]' \
'-V[Print version]' \
'--version[Print version]' \
&& ret=0
;;
(fasd)
_arguments "${_arguments_options[@]}" : \
'--merge[Merge into existing database]' \
'-h[Print help]' \
'--help[Print help]' \
'-V[Print version]' \
'--version[Print version]' \
&& ret=0
;;
(z)
_arguments "${_arguments_options[@]}" : \
'--merge[Merge into existing database]' \
'-h[Print help]' \
'--help[Print help]' \
'-V[Print version]' \
'--version[Print version]' \
&& ret=0
;;
(z.lua)
_arguments "${_arguments_options[@]}" : \
'--merge[Merge into existing database]' \
'-h[Print help]' \
'--help[Print help]' \
'-V[Print version]' \
'--version[Print version]' \
&& ret=0
;;
(zsh-z)
_arguments "${_arguments_options[@]}" : \
'--merge[Merge into existing database]' \
'-h[Print help]' \
'--help[Print help]' \
'-V[Print version]' \
'--version[Print version]' \
&& ret=0
;;
esac
;;
esac
;; ;;
(init) (init)
_arguments "${_arguments_options[@]}" : \ _arguments "${_arguments_options[@]}" : \
@ -162,13 +226,13 @@ _zoxide_commands() {
) )
_describe -t commands 'zoxide commands' commands "$@" _describe -t commands 'zoxide commands' commands "$@"
} }
(( $+functions[_zoxide__add_commands] )) || (( $+functions[_zoxide__subcmd__add_commands] )) ||
_zoxide__add_commands() { _zoxide__subcmd__add_commands() {
local commands; commands=() local commands; commands=()
_describe -t commands 'zoxide add commands' commands "$@" _describe -t commands 'zoxide add commands' commands "$@"
} }
(( $+functions[_zoxide__edit_commands] )) || (( $+functions[_zoxide__subcmd__edit_commands] )) ||
_zoxide__edit_commands() { _zoxide__subcmd__edit_commands() {
local commands; commands=( local commands; commands=(
'decrement:' \ 'decrement:' \
'delete:' \ 'delete:' \
@ -177,43 +241,80 @@ _zoxide__edit_commands() {
) )
_describe -t commands 'zoxide edit commands' commands "$@" _describe -t commands 'zoxide edit commands' commands "$@"
} }
(( $+functions[_zoxide__edit__decrement_commands] )) || (( $+functions[_zoxide__subcmd__edit__subcmd__decrement_commands] )) ||
_zoxide__edit__decrement_commands() { _zoxide__subcmd__edit__subcmd__decrement_commands() {
local commands; commands=() local commands; commands=()
_describe -t commands 'zoxide edit decrement commands' commands "$@" _describe -t commands 'zoxide edit decrement commands' commands "$@"
} }
(( $+functions[_zoxide__edit__delete_commands] )) || (( $+functions[_zoxide__subcmd__edit__subcmd__delete_commands] )) ||
_zoxide__edit__delete_commands() { _zoxide__subcmd__edit__subcmd__delete_commands() {
local commands; commands=() local commands; commands=()
_describe -t commands 'zoxide edit delete commands' commands "$@" _describe -t commands 'zoxide edit delete commands' commands "$@"
} }
(( $+functions[_zoxide__edit__increment_commands] )) || (( $+functions[_zoxide__subcmd__edit__subcmd__increment_commands] )) ||
_zoxide__edit__increment_commands() { _zoxide__subcmd__edit__subcmd__increment_commands() {
local commands; commands=() local commands; commands=()
_describe -t commands 'zoxide edit increment commands' commands "$@" _describe -t commands 'zoxide edit increment commands' commands "$@"
} }
(( $+functions[_zoxide__edit__reload_commands] )) || (( $+functions[_zoxide__subcmd__edit__subcmd__reload_commands] )) ||
_zoxide__edit__reload_commands() { _zoxide__subcmd__edit__subcmd__reload_commands() {
local commands; commands=() local commands; commands=()
_describe -t commands 'zoxide edit reload commands' commands "$@" _describe -t commands 'zoxide edit reload commands' commands "$@"
} }
(( $+functions[_zoxide__import_commands] )) || (( $+functions[_zoxide__subcmd__import_commands] )) ||
_zoxide__import_commands() { _zoxide__subcmd__import_commands() {
local commands; commands=() local commands; commands=(
'atuin:Import from atuin' \
'autojump:Import from autojump' \
'fasd:Import from fasd' \
'z:Import from z' \
'z.lua:Import from z.lua' \
'zsh-z:Import from zsh-z' \
)
_describe -t commands 'zoxide import commands' commands "$@" _describe -t commands 'zoxide import commands' commands "$@"
} }
(( $+functions[_zoxide__init_commands] )) || (( $+functions[_zoxide__subcmd__import__subcmd__atuin_commands] )) ||
_zoxide__init_commands() { _zoxide__subcmd__import__subcmd__atuin_commands() {
local commands; commands=()
_describe -t commands 'zoxide import atuin commands' commands "$@"
}
(( $+functions[_zoxide__subcmd__import__subcmd__autojump_commands] )) ||
_zoxide__subcmd__import__subcmd__autojump_commands() {
local commands; commands=()
_describe -t commands 'zoxide import autojump commands' commands "$@"
}
(( $+functions[_zoxide__subcmd__import__subcmd__fasd_commands] )) ||
_zoxide__subcmd__import__subcmd__fasd_commands() {
local commands; commands=()
_describe -t commands 'zoxide import fasd commands' commands "$@"
}
(( $+functions[_zoxide__subcmd__import__subcmd__z_commands] )) ||
_zoxide__subcmd__import__subcmd__z_commands() {
local commands; commands=()
_describe -t commands 'zoxide import z commands' commands "$@"
}
(( $+functions[_zoxide__subcmd__import__subcmd__z.lua_commands] )) ||
_zoxide__subcmd__import__subcmd__z.lua_commands() {
local commands; commands=()
_describe -t commands 'zoxide import z.lua commands' commands "$@"
}
(( $+functions[_zoxide__subcmd__import__subcmd__zsh-z_commands] )) ||
_zoxide__subcmd__import__subcmd__zsh-z_commands() {
local commands; commands=()
_describe -t commands 'zoxide import zsh-z commands' commands "$@"
}
(( $+functions[_zoxide__subcmd__init_commands] )) ||
_zoxide__subcmd__init_commands() {
local commands; commands=() local commands; commands=()
_describe -t commands 'zoxide init commands' commands "$@" _describe -t commands 'zoxide init commands' commands "$@"
} }
(( $+functions[_zoxide__query_commands] )) || (( $+functions[_zoxide__subcmd__query_commands] )) ||
_zoxide__query_commands() { _zoxide__subcmd__query_commands() {
local commands; commands=() local commands; commands=()
_describe -t commands 'zoxide query commands' commands "$@" _describe -t commands 'zoxide query commands' commands "$@"
} }
(( $+functions[_zoxide__remove_commands] )) || (( $+functions[_zoxide__subcmd__remove_commands] )) ||
_zoxide__remove_commands() { _zoxide__subcmd__remove_commands() {
local commands; commands=() local commands; commands=()
_describe -t commands 'zoxide remove commands' commands "$@" _describe -t commands 'zoxide remove commands' commands "$@"
} }

View File

@ -82,7 +82,60 @@ Register-ArgumentCompleter -Native -CommandName 'zoxide' -ScriptBlock {
break break
} }
'zoxide;import' { 'zoxide;import' {
[CompletionResult]::new('--from', '--from', [CompletionResultType]::ParameterName, 'Application to import from') [CompletionResult]::new('--merge', '--merge', [CompletionResultType]::ParameterName, 'Merge into existing database')
[CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help')
[CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help')
[CompletionResult]::new('-V', '-V ', [CompletionResultType]::ParameterName, 'Print version')
[CompletionResult]::new('--version', '--version', [CompletionResultType]::ParameterName, 'Print version')
[CompletionResult]::new('atuin', 'atuin', [CompletionResultType]::ParameterValue, 'Import from atuin')
[CompletionResult]::new('autojump', 'autojump', [CompletionResultType]::ParameterValue, 'Import from autojump')
[CompletionResult]::new('fasd', 'fasd', [CompletionResultType]::ParameterValue, 'Import from fasd')
[CompletionResult]::new('z', 'z', [CompletionResultType]::ParameterValue, 'Import from z')
[CompletionResult]::new('z.lua', 'z.lua', [CompletionResultType]::ParameterValue, 'Import from z.lua')
[CompletionResult]::new('zsh-z', 'zsh-z', [CompletionResultType]::ParameterValue, 'Import from zsh-z')
break
}
'zoxide;import;atuin' {
[CompletionResult]::new('--merge', '--merge', [CompletionResultType]::ParameterName, 'Merge into existing database')
[CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help')
[CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help')
[CompletionResult]::new('-V', '-V ', [CompletionResultType]::ParameterName, 'Print version')
[CompletionResult]::new('--version', '--version', [CompletionResultType]::ParameterName, 'Print version')
break
}
'zoxide;import;autojump' {
[CompletionResult]::new('--merge', '--merge', [CompletionResultType]::ParameterName, 'Merge into existing database')
[CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help')
[CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help')
[CompletionResult]::new('-V', '-V ', [CompletionResultType]::ParameterName, 'Print version')
[CompletionResult]::new('--version', '--version', [CompletionResultType]::ParameterName, 'Print version')
break
}
'zoxide;import;fasd' {
[CompletionResult]::new('--merge', '--merge', [CompletionResultType]::ParameterName, 'Merge into existing database')
[CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help')
[CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help')
[CompletionResult]::new('-V', '-V ', [CompletionResultType]::ParameterName, 'Print version')
[CompletionResult]::new('--version', '--version', [CompletionResultType]::ParameterName, 'Print version')
break
}
'zoxide;import;z' {
[CompletionResult]::new('--merge', '--merge', [CompletionResultType]::ParameterName, 'Merge into existing database')
[CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help')
[CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help')
[CompletionResult]::new('-V', '-V ', [CompletionResultType]::ParameterName, 'Print version')
[CompletionResult]::new('--version', '--version', [CompletionResultType]::ParameterName, 'Print version')
break
}
'zoxide;import;z.lua' {
[CompletionResult]::new('--merge', '--merge', [CompletionResultType]::ParameterName, 'Merge into existing database')
[CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help')
[CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help')
[CompletionResult]::new('-V', '-V ', [CompletionResultType]::ParameterName, 'Print version')
[CompletionResult]::new('--version', '--version', [CompletionResultType]::ParameterName, 'Print version')
break
}
'zoxide;import;zsh-z' {
[CompletionResult]::new('--merge', '--merge', [CompletionResultType]::ParameterName, 'Merge into existing database') [CompletionResult]::new('--merge', '--merge', [CompletionResultType]::ParameterName, 'Merge into existing database')
[CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help')
[CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help')

View File

@ -17,34 +17,52 @@ _zoxide() {
cmd="zoxide" cmd="zoxide"
;; ;;
zoxide,add) zoxide,add)
cmd="zoxide__add" cmd="zoxide__subcmd__add"
;; ;;
zoxide,edit) zoxide,edit)
cmd="zoxide__edit" cmd="zoxide__subcmd__edit"
;; ;;
zoxide,import) zoxide,import)
cmd="zoxide__import" cmd="zoxide__subcmd__import"
;; ;;
zoxide,init) zoxide,init)
cmd="zoxide__init" cmd="zoxide__subcmd__init"
;; ;;
zoxide,query) zoxide,query)
cmd="zoxide__query" cmd="zoxide__subcmd__query"
;; ;;
zoxide,remove) zoxide,remove)
cmd="zoxide__remove" cmd="zoxide__subcmd__remove"
;; ;;
zoxide__edit,decrement) zoxide__subcmd__edit,decrement)
cmd="zoxide__edit__decrement" cmd="zoxide__subcmd__edit__subcmd__decrement"
;; ;;
zoxide__edit,delete) zoxide__subcmd__edit,delete)
cmd="zoxide__edit__delete" cmd="zoxide__subcmd__edit__subcmd__delete"
;; ;;
zoxide__edit,increment) zoxide__subcmd__edit,increment)
cmd="zoxide__edit__increment" cmd="zoxide__subcmd__edit__subcmd__increment"
;; ;;
zoxide__edit,reload) zoxide__subcmd__edit,reload)
cmd="zoxide__edit__reload" cmd="zoxide__subcmd__edit__subcmd__reload"
;;
zoxide__subcmd__import,atuin)
cmd="zoxide__subcmd__import__subcmd__atuin"
;;
zoxide__subcmd__import,autojump)
cmd="zoxide__subcmd__import__subcmd__autojump"
;;
zoxide__subcmd__import,fasd)
cmd="zoxide__subcmd__import__subcmd__fasd"
;;
zoxide__subcmd__import,z)
cmd="zoxide__subcmd__import__subcmd__z"
;;
zoxide__subcmd__import,z.lua)
cmd="zoxide__subcmd__import__subcmd__z.lua"
;;
zoxide__subcmd__import,zsh-z)
cmd="zoxide__subcmd__import__subcmd__zsh__subcmd__z"
;; ;;
*) *)
;; ;;
@ -66,7 +84,7 @@ _zoxide() {
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0 return 0
;; ;;
zoxide__add) zoxide__subcmd__add)
opts="-s -h -V --score --help --version <PATHS>..." opts="-s -h -V --score --help --version <PATHS>..."
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
@ -88,7 +106,7 @@ _zoxide() {
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0 return 0
;; ;;
zoxide__edit) zoxide__subcmd__edit)
opts="-h -V --help --version decrement delete increment reload" opts="-h -V --help --version decrement delete increment reload"
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
@ -102,7 +120,7 @@ _zoxide() {
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0 return 0
;; ;;
zoxide__edit__decrement) zoxide__subcmd__edit__subcmd__decrement)
opts="-h -V --help --version <PATH>" opts="-h -V --help --version <PATH>"
if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
@ -116,7 +134,7 @@ _zoxide() {
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0 return 0
;; ;;
zoxide__edit__delete) zoxide__subcmd__edit__subcmd__delete)
opts="-h -V --help --version <PATH>" opts="-h -V --help --version <PATH>"
if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
@ -130,7 +148,7 @@ _zoxide() {
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0 return 0
;; ;;
zoxide__edit__increment) zoxide__subcmd__edit__subcmd__increment)
opts="-h -V --help --version <PATH>" opts="-h -V --help --version <PATH>"
if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
@ -144,7 +162,7 @@ _zoxide() {
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0 return 0
;; ;;
zoxide__edit__reload) zoxide__subcmd__edit__subcmd__reload)
opts="-h -V --help --version" opts="-h -V --help --version"
if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
@ -158,17 +176,13 @@ _zoxide() {
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0 return 0
;; ;;
zoxide__import) zoxide__subcmd__import)
opts="-h -V --from --merge --help --version <PATH>" opts="-h -V --merge --help --version atuin autojump fasd z z.lua zsh-z"
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
fi fi
case "${prev}" in case "${prev}" in
--from)
COMPREPLY=($(compgen -W "autojump z" -- "${cur}"))
return 0
;;
*) *)
COMPREPLY=() COMPREPLY=()
;; ;;
@ -176,7 +190,91 @@ _zoxide() {
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0 return 0
;; ;;
zoxide__init) zoxide__subcmd__import__subcmd__atuin)
opts="-h -V --merge --help --version"
if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
fi
case "${prev}" in
*)
COMPREPLY=()
;;
esac
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
;;
zoxide__subcmd__import__subcmd__autojump)
opts="-h -V --merge --help --version"
if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
fi
case "${prev}" in
*)
COMPREPLY=()
;;
esac
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
;;
zoxide__subcmd__import__subcmd__fasd)
opts="-h -V --merge --help --version"
if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
fi
case "${prev}" in
*)
COMPREPLY=()
;;
esac
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
;;
zoxide__subcmd__import__subcmd__z)
opts="-h -V --merge --help --version"
if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
fi
case "${prev}" in
*)
COMPREPLY=()
;;
esac
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
;;
zoxide__subcmd__import__subcmd__z.lua)
opts="-h -V --merge --help --version"
if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
fi
case "${prev}" in
*)
COMPREPLY=()
;;
esac
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
;;
zoxide__subcmd__import__subcmd__zsh__subcmd__z)
opts="-h -V --merge --help --version"
if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
fi
case "${prev}" in
*)
COMPREPLY=()
;;
esac
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
;;
zoxide__subcmd__init)
opts="-h -V --no-cmd --cmd --hook --help --version bash elvish fish nushell posix powershell tcsh xonsh zsh" opts="-h -V --no-cmd --cmd --hook --help --version bash elvish fish nushell posix powershell tcsh 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}") )
@ -198,7 +296,7 @@ _zoxide() {
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0 return 0
;; ;;
zoxide__query) zoxide__subcmd__query)
opts="-a -i -l -s -h -V --all --interactive --list --score --exclude --base-dir --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 if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
@ -226,7 +324,7 @@ _zoxide() {
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0 return 0
;; ;;
zoxide__remove) zoxide__subcmd__remove)
opts="-h -V --help --version [PATHS]..." opts="-h -V --help --version [PATHS]..."
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )

View File

@ -72,7 +72,54 @@ set edit:completion:arg-completer[zoxide] = {|@words|
cand --version 'Print version' cand --version 'Print version'
} }
&'zoxide;import'= { &'zoxide;import'= {
cand --from 'Application to import from' cand --merge 'Merge into existing database'
cand -h 'Print help'
cand --help 'Print help'
cand -V 'Print version'
cand --version 'Print version'
cand atuin 'Import from atuin'
cand autojump 'Import from autojump'
cand fasd 'Import from fasd'
cand z 'Import from z'
cand z.lua 'Import from z.lua'
cand zsh-z 'Import from zsh-z'
}
&'zoxide;import;atuin'= {
cand --merge 'Merge into existing database'
cand -h 'Print help'
cand --help 'Print help'
cand -V 'Print version'
cand --version 'Print version'
}
&'zoxide;import;autojump'= {
cand --merge 'Merge into existing database'
cand -h 'Print help'
cand --help 'Print help'
cand -V 'Print version'
cand --version 'Print version'
}
&'zoxide;import;fasd'= {
cand --merge 'Merge into existing database'
cand -h 'Print help'
cand --help 'Print help'
cand -V 'Print version'
cand --version 'Print version'
}
&'zoxide;import;z'= {
cand --merge 'Merge into existing database'
cand -h 'Print help'
cand --help 'Print help'
cand -V 'Print version'
cand --version 'Print version'
}
&'zoxide;import;z.lua'= {
cand --merge 'Merge into existing database'
cand -h 'Print help'
cand --help 'Print help'
cand -V 'Print version'
cand --version 'Print version'
}
&'zoxide;import;zsh-z'= {
cand --merge 'Merge into existing database' cand --merge 'Merge into existing database'
cand -h 'Print help' cand -h 'Print help'
cand --help 'Print help' cand --help 'Print help'

View File

@ -49,11 +49,33 @@ complete -c zoxide -n "__fish_zoxide_using_subcommand edit; and __fish_seen_subc
complete -c zoxide -n "__fish_zoxide_using_subcommand edit; and __fish_seen_subcommand_from increment" -s V -l version -d 'Print version' complete -c zoxide -n "__fish_zoxide_using_subcommand edit; and __fish_seen_subcommand_from increment" -s V -l version -d 'Print version'
complete -c zoxide -n "__fish_zoxide_using_subcommand edit; and __fish_seen_subcommand_from reload" -s h -l help -d 'Print help' complete -c zoxide -n "__fish_zoxide_using_subcommand edit; and __fish_seen_subcommand_from reload" -s h -l help -d 'Print help'
complete -c zoxide -n "__fish_zoxide_using_subcommand edit; and __fish_seen_subcommand_from reload" -s V -l version -d 'Print version' complete -c zoxide -n "__fish_zoxide_using_subcommand edit; and __fish_seen_subcommand_from reload" -s V -l version -d 'Print version'
complete -c zoxide -n "__fish_zoxide_using_subcommand import" -l from -d 'Application to import from' -r -f -a "autojump\t'' complete -c zoxide -n "__fish_zoxide_using_subcommand import; and not __fish_seen_subcommand_from atuin autojump fasd z z.lua zsh-z" -l merge -d 'Merge into existing database'
z\t''" complete -c zoxide -n "__fish_zoxide_using_subcommand import; and not __fish_seen_subcommand_from atuin autojump fasd z z.lua zsh-z" -s h -l help -d 'Print help'
complete -c zoxide -n "__fish_zoxide_using_subcommand import" -l merge -d 'Merge into existing database' complete -c zoxide -n "__fish_zoxide_using_subcommand import; and not __fish_seen_subcommand_from atuin autojump fasd z z.lua zsh-z" -s V -l version -d 'Print version'
complete -c zoxide -n "__fish_zoxide_using_subcommand import" -s h -l help -d 'Print help' complete -c zoxide -n "__fish_zoxide_using_subcommand import; and not __fish_seen_subcommand_from atuin autojump fasd z z.lua zsh-z" -f -a "atuin" -d 'Import from atuin'
complete -c zoxide -n "__fish_zoxide_using_subcommand import" -s V -l version -d 'Print version' complete -c zoxide -n "__fish_zoxide_using_subcommand import; and not __fish_seen_subcommand_from atuin autojump fasd z z.lua zsh-z" -f -a "autojump" -d 'Import from autojump'
complete -c zoxide -n "__fish_zoxide_using_subcommand import; and not __fish_seen_subcommand_from atuin autojump fasd z z.lua zsh-z" -f -a "fasd" -d 'Import from fasd'
complete -c zoxide -n "__fish_zoxide_using_subcommand import; and not __fish_seen_subcommand_from atuin autojump fasd z z.lua zsh-z" -f -a "z" -d 'Import from z'
complete -c zoxide -n "__fish_zoxide_using_subcommand import; and not __fish_seen_subcommand_from atuin autojump fasd z z.lua zsh-z" -f -a "z.lua" -d 'Import from z.lua'
complete -c zoxide -n "__fish_zoxide_using_subcommand import; and not __fish_seen_subcommand_from atuin autojump fasd z z.lua zsh-z" -f -a "zsh-z" -d 'Import from zsh-z'
complete -c zoxide -n "__fish_zoxide_using_subcommand import; and __fish_seen_subcommand_from atuin" -l merge -d 'Merge into existing database'
complete -c zoxide -n "__fish_zoxide_using_subcommand import; and __fish_seen_subcommand_from atuin" -s h -l help -d 'Print help'
complete -c zoxide -n "__fish_zoxide_using_subcommand import; and __fish_seen_subcommand_from atuin" -s V -l version -d 'Print version'
complete -c zoxide -n "__fish_zoxide_using_subcommand import; and __fish_seen_subcommand_from autojump" -l merge -d 'Merge into existing database'
complete -c zoxide -n "__fish_zoxide_using_subcommand import; and __fish_seen_subcommand_from autojump" -s h -l help -d 'Print help'
complete -c zoxide -n "__fish_zoxide_using_subcommand import; and __fish_seen_subcommand_from autojump" -s V -l version -d 'Print version'
complete -c zoxide -n "__fish_zoxide_using_subcommand import; and __fish_seen_subcommand_from fasd" -l merge -d 'Merge into existing database'
complete -c zoxide -n "__fish_zoxide_using_subcommand import; and __fish_seen_subcommand_from fasd" -s h -l help -d 'Print help'
complete -c zoxide -n "__fish_zoxide_using_subcommand import; and __fish_seen_subcommand_from fasd" -s V -l version -d 'Print version'
complete -c zoxide -n "__fish_zoxide_using_subcommand import; and __fish_seen_subcommand_from z" -l merge -d 'Merge into existing database'
complete -c zoxide -n "__fish_zoxide_using_subcommand import; and __fish_seen_subcommand_from z" -s h -l help -d 'Print help'
complete -c zoxide -n "__fish_zoxide_using_subcommand import; and __fish_seen_subcommand_from z" -s V -l version -d 'Print version'
complete -c zoxide -n "__fish_zoxide_using_subcommand import; and __fish_seen_subcommand_from z.lua" -l merge -d 'Merge into existing database'
complete -c zoxide -n "__fish_zoxide_using_subcommand import; and __fish_seen_subcommand_from z.lua" -s h -l help -d 'Print help'
complete -c zoxide -n "__fish_zoxide_using_subcommand import; and __fish_seen_subcommand_from z.lua" -s V -l version -d 'Print version'
complete -c zoxide -n "__fish_zoxide_using_subcommand import; and __fish_seen_subcommand_from zsh-z" -l merge -d 'Merge into existing database'
complete -c zoxide -n "__fish_zoxide_using_subcommand import; and __fish_seen_subcommand_from zsh-z" -s h -l help -d 'Print help'
complete -c zoxide -n "__fish_zoxide_using_subcommand import; and __fish_seen_subcommand_from zsh-z" -s V -l version -d 'Print version'
complete -c zoxide -n "__fish_zoxide_using_subcommand init" -l cmd -d 'Changes the prefix of the `z` and `zi` commands' -r complete -c zoxide -n "__fish_zoxide_using_subcommand init" -l cmd -d 'Changes the prefix of the `z` and `zi` commands' -r
complete -c zoxide -n "__fish_zoxide_using_subcommand init" -l hook -d 'Changes how often zoxide increments a directory\'s score' -r -f -a "none\t'' complete -c zoxide -n "__fish_zoxide_using_subcommand init" -l hook -d 'Changes how often zoxide increments a directory\'s score' -r -f -a "none\t''
prompt\t'' prompt\t''

View File

@ -8,10 +8,10 @@ module completions {
# Add a new directory or increment its rank # Add a new directory or increment its rank
export extern "zoxide add" [ export extern "zoxide add" [
...paths: path
--score(-s): string # The rank to increment the entry if it exists or initialize it with if it doesn't --score(-s): string # The rank to increment the entry if it exists or initialize it with if it doesn't
--help(-h) # Print help --help(-h) # Print help
--version(-V) # Print version --version(-V) # Print version
...paths: path
] ]
# Edit the database # Edit the database
@ -21,21 +21,21 @@ module completions {
] ]
export extern "zoxide edit decrement" [ export extern "zoxide edit decrement" [
path: string
--help(-h) # Print help --help(-h) # Print help
--version(-V) # Print version --version(-V) # Print version
path: string
] ]
export extern "zoxide edit delete" [ export extern "zoxide edit delete" [
path: string
--help(-h) # Print help --help(-h) # Print help
--version(-V) # Print version --version(-V) # Print version
path: string
] ]
export extern "zoxide edit increment" [ export extern "zoxide edit increment" [
path: string
--help(-h) # Print help --help(-h) # Print help
--version(-V) # Print version --version(-V) # Print version
path: string
] ]
export extern "zoxide edit reload" [ export extern "zoxide edit reload" [
@ -43,14 +43,50 @@ module completions {
--version(-V) # Print version --version(-V) # Print version
] ]
def "nu-complete zoxide import from" [] {
[ "autojump" "z" ]
}
# Import entries from another application # Import entries from another application
export extern "zoxide import" [ export extern "zoxide import" [
path: path --merge # Merge into existing database
--from: string@"nu-complete zoxide import from" # Application to import from --help(-h) # Print help
--version(-V) # Print version
]
# Import from atuin
export extern "zoxide import atuin" [
--merge # Merge into existing database
--help(-h) # Print help
--version(-V) # Print version
]
# Import from autojump
export extern "zoxide import autojump" [
--merge # Merge into existing database
--help(-h) # Print help
--version(-V) # Print version
]
# Import from fasd
export extern "zoxide import fasd" [
--merge # Merge into existing database
--help(-h) # Print help
--version(-V) # Print version
]
# Import from z
export extern "zoxide import z" [
--merge # Merge into existing database
--help(-h) # Print help
--version(-V) # Print version
]
# Import from z.lua
export extern "zoxide import z.lua" [
--merge # Merge into existing database
--help(-h) # Print help
--version(-V) # Print version
]
# Import from zsh-z
export extern "zoxide import zsh-z" [
--merge # Merge into existing database --merge # Merge into existing database
--help(-h) # Print help --help(-h) # Print help
--version(-V) # Print version --version(-V) # Print version
@ -66,17 +102,16 @@ module completions {
# Generate shell configuration # Generate shell configuration
export extern "zoxide init" [ export extern "zoxide init" [
shell: string@"nu-complete zoxide init shell"
--no-cmd # Prevents zoxide from defining the `z` and `zi` commands --no-cmd # Prevents zoxide from defining the `z` and `zi` commands
--cmd: string # Changes the prefix of the `z` and `zi` commands --cmd: string # Changes the prefix of the `z` and `zi` commands
--hook: string@"nu-complete zoxide init hook" # Changes how often zoxide increments a directory's score --hook: string@"nu-complete zoxide init hook" # Changes how often zoxide increments a directory's score
--help(-h) # Print help --help(-h) # Print help
--version(-V) # Print version --version(-V) # Print version
shell: string@"nu-complete zoxide init shell"
] ]
# Search for a directory in the database # Search for a directory in the database
export extern "zoxide query" [ export extern "zoxide query" [
...keywords: string
--all(-a) # Show unavailable directories --all(-a) # Show unavailable directories
--interactive(-i) # Use interactive selection --interactive(-i) # Use interactive selection
--list(-l) # List all matching directories --list(-l) # List all matching directories
@ -85,13 +120,14 @@ module completions {
--base-dir: path # Only search within this directory --base-dir: path # Only search within this directory
--help(-h) # Print help --help(-h) # Print help
--version(-V) # Print version --version(-V) # Print version
...keywords: string
] ]
# Remove a directory from the database # Remove a directory from the database
export extern "zoxide remove" [ export extern "zoxide remove" [
...paths: path
--help(-h) # Print help --help(-h) # Print help
--version(-V) # Print version --version(-V) # Print version
...paths: path
] ]
} }

View File

@ -114,19 +114,117 @@ const completion: Fig.Spec = {
{ {
name: "import", name: "import",
description: "Import entries from another application", description: "Import entries from another application",
options: [ subcommands: [
{ {
name: "--from", name: "atuin",
description: "Application to import from", description: "Import from atuin",
isRepeatable: true, options: [
args: { {
name: "from", name: "--merge",
suggestions: [ description: "Merge into existing database",
"autojump", },
"z", {
], name: ["-h", "--help"],
}, description: "Print help",
},
{
name: ["-V", "--version"],
description: "Print version",
},
],
}, },
{
name: "autojump",
description: "Import from autojump",
options: [
{
name: "--merge",
description: "Merge into existing database",
},
{
name: ["-h", "--help"],
description: "Print help",
},
{
name: ["-V", "--version"],
description: "Print version",
},
],
},
{
name: "fasd",
description: "Import from fasd",
options: [
{
name: "--merge",
description: "Merge into existing database",
},
{
name: ["-h", "--help"],
description: "Print help",
},
{
name: ["-V", "--version"],
description: "Print version",
},
],
},
{
name: "z",
description: "Import from z",
options: [
{
name: "--merge",
description: "Merge into existing database",
},
{
name: ["-h", "--help"],
description: "Print help",
},
{
name: ["-V", "--version"],
description: "Print version",
},
],
},
{
name: "z.lua",
description: "Import from z.lua",
options: [
{
name: "--merge",
description: "Merge into existing database",
},
{
name: ["-h", "--help"],
description: "Print help",
},
{
name: ["-V", "--version"],
description: "Print version",
},
],
},
{
name: "zsh-z",
description: "Import from zsh-z",
options: [
{
name: "--merge",
description: "Merge into existing database",
},
{
name: ["-h", "--help"],
description: "Print help",
},
{
name: ["-V", "--version"],
description: "Print version",
},
],
},
],
options: [
{ {
name: "--merge", name: "--merge",
description: "Merge into existing database", description: "Merge into existing database",
@ -140,10 +238,6 @@ const completion: Fig.Spec = {
description: "Print version", description: "Print version",
}, },
], ],
args: {
name: "path",
template: "filepaths",
},
}, },
{ {
name: "init", name: "init",

View File

@ -19,7 +19,7 @@ main() {
parse_args "$@" parse_args "$@"
local _arch local _arch
_arch="${ARCH:-$(ensure get_architecture)}" _arch="${_ZOXIDE_ARCH:-$(get_architecture)}" || exit $?
assert_nz "${_arch}" "arch" assert_nz "${_arch}" "arch"
echo "Detected architecture: ${_arch}" echo "Detected architecture: ${_arch}"
@ -31,12 +31,12 @@ main() {
# Create and enter a temporary directory. # Create and enter a temporary directory.
local _tmp_dir local _tmp_dir
_tmp_dir="$(mktemp -d)" || err "mktemp: could not create temporary directory" _tmp_dir="$(mktemp -d /tmp/zoxide_XXXXXX)" || err "mktemp: could not create temporary directory"
cd "${_tmp_dir}" || err "cd: failed to enter directory: ${_tmp_dir}" cd "${_tmp_dir}" || err "cd: failed to enter directory: ${_tmp_dir}"
# Download and extract zoxide. # Download and extract zoxide.
local _package local _package
_package="$(ensure download_zoxide "${_arch}")" _package="$(download_zoxide "${_arch}")" || exit $?
assert_nz "${_package}" "package" assert_nz "${_package}" "package"
echo "Downloaded package: ${_package}" echo "Downloaded package: ${_package}"
case "${_package}" in case "${_package}" in
@ -54,44 +54,44 @@ main() {
esac esac
# Install binary. # Install binary.
ensure try_sudo mkdir -p -- "${BIN_DIR}" ensure try_sudo mkdir -p -- "${_ZOXIDE_BIN_DIR}"
ensure try_sudo cp -- "${_bin_name}" "${BIN_DIR}/${_bin_name}" ensure try_sudo cp -- "${_bin_name}" "${_ZOXIDE_BIN_DIR}/${_bin_name}"
ensure try_sudo chmod +x "${BIN_DIR}/${_bin_name}" ensure try_sudo chmod +x "${_ZOXIDE_BIN_DIR}/${_bin_name}"
echo "Installed zoxide to ${BIN_DIR}" echo "Installed zoxide to ${_ZOXIDE_BIN_DIR}"
# Install manpages. # Install manpages.
ensure try_sudo mkdir -p -- "${MAN_DIR}/man1" ensure try_sudo mkdir -p -- "${_ZOXIDE_MAN_DIR}/man1"
ensure try_sudo cp -- "man/man1/"* "${MAN_DIR}/man1/" ensure try_sudo cp -- "man/man1/"* "${_ZOXIDE_MAN_DIR}/man1/"
echo "Installed manpages to ${MAN_DIR}" echo "Installed manpages to ${_ZOXIDE_MAN_DIR}"
# Print success message and check $PATH. # Print success message and check $PATH.
echo "" echo ""
echo "zoxide is installed!" echo "zoxide is installed!"
if ! echo ":${PATH}:" | grep -Fq ":${BIN_DIR}:"; then if ! echo ":${PATH}:" | grep -Fq ":${_ZOXIDE_BIN_DIR}:"; then
echo "Note: ${BIN_DIR} is not on your \$PATH. zoxide will not work unless it is added to \$PATH." echo "Note: ${_ZOXIDE_BIN_DIR} is not on your \$PATH. zoxide will not work unless it is added to \$PATH."
fi fi
} }
# Parse the arguments passed and set variables accordingly. # Parse the arguments passed and set variables accordingly.
parse_args() { parse_args() {
BIN_DIR_DEFAULT="${HOME}/.local/bin" _ZOXIDE_BIN_DIR_DEFAULT="${HOME}/.local/bin"
MAN_DIR_DEFAULT="${HOME}/.local/share/man" _ZOXIDE_MAN_DIR_DEFAULT="${HOME}/.local/share/man"
SUDO_DEFAULT="sudo" _ZOXIDE_SUDO_DEFAULT="sudo"
BIN_DIR="${BIN_DIR_DEFAULT}" _ZOXIDE_BIN_DIR="${_ZOXIDE_BIN_DIR_DEFAULT}"
MAN_DIR="${MAN_DIR_DEFAULT}" _ZOXIDE_MAN_DIR="${_ZOXIDE_MAN_DIR_DEFAULT}"
SUDO="${SUDO_DEFAULT}" _ZOXIDE_SUDO="${_ZOXIDE_SUDO_DEFAULT}"
while [ "$#" -gt 0 ]; do while [ "$#" -gt 0 ]; do
case "$1" in case "$1" in
--arch) ARCH="$2" && shift 2 ;; --arch) _ZOXIDE_ARCH="$2" && shift 2 ;;
--arch=*) ARCH="${1#*=}" && shift 1 ;; --arch=*) _ZOXIDE_ARCH="${1#*=}" && shift 1 ;;
--bin-dir) BIN_DIR="$2" && shift 2 ;; --bin-dir) _ZOXIDE_BIN_DIR="$2" && shift 2 ;;
--bin-dir=*) BIN_DIR="${1#*=}" && shift 1 ;; --bin-dir=*) _ZOXIDE_BIN_DIR="${1#*=}" && shift 1 ;;
--man-dir) MAN_DIR="$2" && shift 2 ;; --man-dir) _ZOXIDE_MAN_DIR="$2" && shift 2 ;;
--man-dir=*) MAN_DIR="${1#*=}" && shift 1 ;; --man-dir=*) _ZOXIDE_MAN_DIR="${1#*=}" && shift 1 ;;
--sudo) SUDO="$2" && shift 2 ;; --sudo) _ZOXIDE_SUDO="$2" && shift 2 ;;
--sudo=*) SUDO="${1#*=}" && shift 1 ;; --sudo=*) _ZOXIDE_SUDO="${1#*=}" && shift 1 ;;
-h | --help) usage && exit 0 ;; -h | --help) usage && exit 0 ;;
*) err "Unknown option: $1" ;; *) err "Unknown option: $1" ;;
esac esac
@ -119,9 +119,9 @@ ${_text_heading}Usage:${_text_reset}
${_text_heading}Options:${_text_reset} ${_text_heading}Options:${_text_reset}
--arch Override the architecture identified by the installer [current: ${_arch}] --arch Override the architecture identified by the installer [current: ${_arch}]
--bin-dir Override the installation directory [default: ${BIN_DIR_DEFAULT}] --bin-dir Override the installation directory [default: ${_ZOXIDE_BIN_DIR_DEFAULT}]
--man-dir Override the manpage installation directory [default: ${MAN_DIR_DEFAULT}] --man-dir Override the manpage installation directory [default: ${_ZOXIDE_MAN_DIR_DEFAULT}]
--sudo Override the command used to elevate to root privileges [default: ${SUDO_DEFAULT}] --sudo Override the command used to elevate to root privileges [default: ${_ZOXIDE_SUDO_DEFAULT}]
-h, --help Print help" -h, --help Print help"
} }
@ -176,19 +176,19 @@ try_sudo() {
fi fi
need_sudo need_sudo
"${SUDO}" "$@" "${_ZOXIDE_SUDO}" "$@"
} }
need_sudo() { need_sudo() {
if ! check_cmd "${SUDO}"; then if ! check_cmd "${_ZOXIDE_SUDO}"; then
err "\ err "\
could not find the command \`${SUDO}\` needed to get permissions for install. could not find the command \`${_ZOXIDE_SUDO}\` needed to get permissions for install.
If you are on Windows, please run your shell as an administrator, then rerun this script. If you are on Windows, please run your shell as an administrator, then rerun this script.
Otherwise, please run this script as root, or install \`sudo\`." Otherwise, please run this script as root, or install \`sudo\`."
fi fi
if ! "${SUDO}" -v; then if ! "${_ZOXIDE_SUDO}" -v; then
err "sudo permissions not granted, aborting installation" err "sudo permissions not granted, aborting installation"
fi fi
} }

View File

@ -4,7 +4,7 @@ let
overlays = [ rust ]; overlays = [ rust ];
}; };
rust = import (builtins.fetchTarball rust = import (builtins.fetchTarball
"https://github.com/oxalica/rust-overlay/archive/026e8fedefd6b167d92ed04b195c658d95ffc7a5.tar.gz"); "https://github.com/oxalica/rust-overlay/archive/4568a557ca325ff81fb354382d4a9968daa1001a.tar.gz");
rust-nightly = rust-nightly =
pkgs.rust-bin.selectLatestNightlyWith (toolchain: toolchain.minimal); pkgs.rust-bin.selectLatestNightlyWith (toolchain: toolchain.minimal);

View File

@ -95,23 +95,30 @@ pub enum EditCommand {
help_template = HelpTemplate, help_template = HelpTemplate,
)] )]
pub struct Import { pub struct Import {
#[clap(value_hint = ValueHint::FilePath)] #[clap(subcommand)]
pub path: PathBuf,
/// Application to import from
#[clap(value_enum, long)]
pub from: ImportFrom, pub from: ImportFrom,
/// Merge into existing database /// Merge into existing database
#[clap(long)] #[clap(long, global = true)]
pub merge: bool, pub merge: bool,
} }
#[derive(ValueEnum, Clone, Debug)] #[derive(Subcommand, Clone, Debug)]
pub enum ImportFrom { pub enum ImportFrom {
/// Import from atuin
Atuin,
/// Import from autojump
Autojump, Autojump,
#[clap(alias = "fasd")] /// Import from fasd
Fasd,
/// Import from z
Z, Z,
/// Import from z.lua
#[clap(name = "z.lua")]
ZLua,
/// Import from zsh-z
#[clap(name = "zsh-z")]
ZshZ,
} }
/// Generate shell configuration /// Generate shell configuration

View File

@ -1,166 +1,25 @@
use std::fs; use anyhow::{Result, bail};
use anyhow::{Context, Result, bail};
use crate::cmd::{Import, ImportFrom, Run}; use crate::cmd::{Import, ImportFrom, Run};
use crate::db::Database; use crate::db::Database;
use crate::import;
impl Run for Import { impl Run for Import {
fn run(&self) -> Result<()> { fn run(&self) -> Result<()> {
let buffer = fs::read_to_string(&self.path).with_context(|| {
format!("could not open database for importing: {}", &self.path.display())
})?;
let mut db = Database::open()?; let mut db = Database::open()?;
if !self.merge && !db.dirs().is_empty() { if !self.merge && !db.dirs().is_empty() {
bail!("current database is not empty, specify --merge to continue anyway"); bail!("current database is not empty, specify --merge to continue anyway");
} }
match self.from { match self.from {
ImportFrom::Autojump => import_autojump(&mut db, &buffer), ImportFrom::Atuin => import::run(&import::Atuin {}, &mut db)?,
ImportFrom::Z => import_z(&mut db, &buffer), ImportFrom::Autojump => import::run(&import::Autojump {}, &mut db)?,
ImportFrom::Fasd => import::run(&import::Fasd {}, &mut db)?,
ImportFrom::Z => import::run(&import::Z {}, &mut db)?,
ImportFrom::ZLua => import::run(&import::ZLua {}, &mut db)?,
ImportFrom::ZshZ => import::run(&import::ZshZ {}, &mut db)?,
} }
.context("import error")?;
db.save() db.save()
} }
} }
fn import_autojump(db: &mut Database, buffer: &str) -> Result<()> {
for line in buffer.lines() {
if line.is_empty() {
continue;
}
let (rank, path) =
line.split_once('\t').with_context(|| format!("invalid entry: {line}"))?;
let mut rank = rank.parse::<f64>().with_context(|| format!("invalid rank: {rank}"))?;
// Normalize the rank using a sigmoid function. Don't import actual ranks from
// autojump, since its scoring algorithm is very different and might
// take a while to get normalized.
rank = sigmoid(rank);
db.add_unchecked(path, rank, 0);
}
if db.dirty() {
db.dedup();
}
Ok(())
}
fn import_z(db: &mut Database, buffer: &str) -> Result<()> {
for line in buffer.lines() {
if line.is_empty() {
continue;
}
let mut split = line.rsplitn(3, '|');
let last_accessed = split.next().with_context(|| format!("invalid entry: {line}"))?;
let last_accessed =
last_accessed.parse().with_context(|| format!("invalid epoch: {last_accessed}"))?;
let rank = split.next().with_context(|| format!("invalid entry: {line}"))?;
let rank = rank.parse().with_context(|| format!("invalid rank: {rank}"))?;
let path = split.next().with_context(|| format!("invalid entry: {line}"))?;
db.add_unchecked(path, rank, last_accessed);
}
if db.dirty() {
db.dedup();
}
Ok(())
}
fn sigmoid(x: f64) -> f64 {
1.0 / (1.0 + (-x).exp())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::db::Dir;
#[test]
fn from_autojump() {
let data_dir = tempfile::tempdir().unwrap();
let mut db = Database::open_dir(data_dir.path()).unwrap();
for (path, rank, last_accessed) in [
("/quux/quuz", 1.0, 100),
("/corge/grault/garply", 6.0, 600),
("/waldo/fred/plugh", 3.0, 300),
("/xyzzy/thud", 8.0, 800),
("/foo/bar", 9.0, 900),
] {
db.add_unchecked(path, rank, last_accessed);
}
let buffer = "\
7.0 /baz
2.0 /foo/bar
5.0 /quux/quuz";
import_autojump(&mut db, buffer).unwrap();
db.sort_by_path();
println!("got: {:?}", &db.dirs());
let exp = [
Dir { path: "/baz".into(), rank: sigmoid(7.0), last_accessed: 0 },
Dir { path: "/corge/grault/garply".into(), rank: 6.0, last_accessed: 600 },
Dir { path: "/foo/bar".into(), rank: 9.0 + sigmoid(2.0), last_accessed: 900 },
Dir { path: "/quux/quuz".into(), rank: 1.0 + sigmoid(5.0), last_accessed: 100 },
Dir { path: "/waldo/fred/plugh".into(), rank: 3.0, last_accessed: 300 },
Dir { path: "/xyzzy/thud".into(), rank: 8.0, last_accessed: 800 },
];
println!("exp: {exp:?}");
for (dir1, dir2) in db.dirs().iter().zip(exp) {
assert_eq!(dir1.path, dir2.path);
assert!((dir1.rank - dir2.rank).abs() < 0.01);
assert_eq!(dir1.last_accessed, dir2.last_accessed);
}
}
#[test]
fn from_z() {
let data_dir = tempfile::tempdir().unwrap();
let mut db = Database::open_dir(data_dir.path()).unwrap();
for (path, rank, last_accessed) in [
("/quux/quuz", 1.0, 100),
("/corge/grault/garply", 6.0, 600),
("/waldo/fred/plugh", 3.0, 300),
("/xyzzy/thud", 8.0, 800),
("/foo/bar", 9.0, 900),
] {
db.add_unchecked(path, rank, last_accessed);
}
let buffer = "\
/baz|7|700
/quux/quuz|4|400
/foo/bar|2|200
/quux/quuz|5|500";
import_z(&mut db, buffer).unwrap();
db.sort_by_path();
println!("got: {:?}", &db.dirs());
let exp = [
Dir { path: "/baz".into(), rank: 7.0, last_accessed: 700 },
Dir { path: "/corge/grault/garply".into(), rank: 6.0, last_accessed: 600 },
Dir { path: "/foo/bar".into(), rank: 11.0, last_accessed: 900 },
Dir { path: "/quux/quuz".into(), rank: 10.0, last_accessed: 500 },
Dir { path: "/waldo/fred/plugh".into(), rank: 3.0, last_accessed: 300 },
Dir { path: "/xyzzy/thud".into(), rank: 8.0, last_accessed: 800 },
];
println!("exp: {exp:?}");
for (dir1, dir2) in db.dirs().iter().zip(exp) {
assert_eq!(dir1.path, dir2.path);
assert!((dir1.rank - dir2.rank).abs() < 0.01);
assert_eq!(dir1.last_accessed, dir2.last_accessed);
}
}
}

View File

@ -76,8 +76,9 @@ impl Database {
} }
/// Creates a new directory. This will create a duplicate entry if this /// Creates a new directory. This will create a duplicate entry if this
/// directory is always in the database, it is expected that the user either /// directory is already in the database, it is expected that the user
/// does a check before calling this, or calls `dedup()` afterward. /// either does a check before calling this, or calls `dedup()`
/// afterward.
pub fn add_unchecked(&mut self, path: impl AsRef<str> + Into<String>, rank: Rank, now: Epoch) { pub fn add_unchecked(&mut self, path: impl AsRef<str> + Into<String>, rank: Rank, now: Epoch) {
self.with_dirs_mut(|dirs| { self.with_dirs_mut(|dirs| {
dirs.push(Dir { path: path.into().into(), rank, last_accessed: now }) dirs.push(Dir { path: path.into().into(), rank, last_accessed: now })

View File

@ -77,7 +77,7 @@ impl<'a> Stream<'a> {
} }
// The logic here is reversed - if we resolve symlinks when adding entries to // 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, we should not return symlinks when querying from
// the database. // the database.
let resolver = let resolver =
if self.options.resolve_symlinks { fs::symlink_metadata } else { fs::metadata }; if self.options.resolve_symlinks { fs::symlink_metadata } else { fs::metadata };

75
src/import.rs Normal file
View File

@ -0,0 +1,75 @@
pub(crate) use crate::import::atuin::Atuin;
pub(crate) use crate::import::autojump::Autojump;
pub(crate) use crate::import::fasd::Fasd;
pub(crate) use crate::import::z::Z;
pub(crate) use crate::import::z_lua::ZLua;
pub(crate) use crate::import::zsh_z::ZshZ;
mod atuin;
mod autojump;
mod fasd;
mod z;
mod z_lua;
mod zsh_z;
use std::io::{self, Write};
use std::path::PathBuf;
use anyhow::Result;
use crate::config;
use crate::db::{Database, Dir};
pub(crate) trait Importer {
/// Yields directory entries to be imported.
///
/// The outer `Result` reports failure to fetch the input (e.g. missing
/// file, subprocess errored). The per-item `Result` reports a malformed
/// row, which doesn't necessarily abort the whole import.
fn dirs(&self) -> Result<impl Iterator<Item = Result<Dir<'static>, ImportError>>>;
}
/// A single record that failed to import.
#[derive(Debug)]
pub(crate) struct ImportError {
/// Path of the source file containing the offending record. `None` if the
/// importer is not file-based (e.g. atuin streams from a subprocess).
pub path: Option<PathBuf>,
/// 1-indexed line number of the offending input.
pub line_num: usize,
/// Underlying reason the record could not be imported.
pub source: anyhow::Error,
}
/// Drives a single importer end-to-end: writes each `Ok` dir into the
/// database and prints each `Err` to stderr in `<path>:<line>: <reason>`
/// format. Doesn't abort on per-record errors — bad rows are skipped, the
/// rest of the import continues. After the iteration completes successfully,
/// the database is deduplicated and aged.
pub(crate) fn run(importer: &impl Importer, db: &mut Database) -> Result<()> {
let stderr = io::stderr();
let mut stderr = stderr.lock();
for entry in importer.dirs()? {
match entry {
Ok(dir) => db.add_unchecked(dir.path, dir.rank, dir.last_accessed),
Err(e) => {
let location = match &e.path {
Some(path) => format!("{}:{}", path.display(), e.line_num),
None => format!("line {}", e.line_num),
};
_ = writeln!(stderr, "{location}: {:#}", e.source);
}
}
}
if db.dirty() {
db.dedup();
let max_age = config::maxage()?;
db.age(max_age);
}
Ok(())
}

116
src/import/atuin.rs Normal file
View File

@ -0,0 +1,116 @@
use std::borrow::Cow;
use std::io::{BufRead, BufReader};
use std::process::{Child, ChildStdout, Command, Stdio};
use std::str;
use anyhow::{Context, Result, anyhow};
use crate::db::{Dir, Epoch};
use crate::import::{ImportError, Importer};
#[derive(clap::Args, Clone, Debug)]
pub(crate) struct Atuin {}
impl Importer for Atuin {
fn dirs(&self) -> Result<impl Iterator<Item = Result<Dir<'static>, ImportError>>> {
// atuin renders `{time}` as `YYYY-MM-DD HH:MM:SS` in UTC.
let mut child = Command::new("atuin")
.args(["history", "list", "--format={time}\t{directory}", "--print0"])
.stdout(Stdio::piped())
.spawn()
.context("failed to run `atuin`; is it installed and on PATH?")?;
let stdout = child.stdout.take().expect("stdout piped");
let reader = BufReader::new(stdout);
Ok(Iter::new(reader, child))
}
}
/// Iterates atuin's NUL-separated `{time}\t{directory}` records, emitting one
/// `Dir` per directory transition (consecutive same-path records collapse).
/// Owns the `Child` handle so the subprocess is reaped on Drop.
struct Iter {
reader: BufReader<ChildStdout>,
buf: Vec<u8>,
line_num: usize,
child: Child,
prev_cwd: Option<String>,
}
impl Iter {
fn new(reader: BufReader<ChildStdout>, child: Child) -> Self {
Self { reader, buf: Vec::new(), line_num: 0, child, prev_cwd: None }
}
fn err(&self, source: anyhow::Error) -> ImportError {
ImportError { path: None, line_num: self.line_num, source }
}
fn parse_line(&self, line: &[u8]) -> Result<Dir<'static>, ImportError> {
let line =
str::from_utf8(line).map_err(|e| self.err(anyhow!(e).context("invalid utf-8")))?;
let (timestamp, path) =
line.split_once('\t').ok_or_else(|| self.err(anyhow!("invalid entry: {line}")))?;
let timestamp_format =
time::macros::format_description!("[year]-[month]-[day] [hour]:[minute]:[second]");
let timestamp = time::PrimitiveDateTime::parse(timestamp, timestamp_format)
.map_err(|e| self.err(anyhow!(e).context(format!("invalid timestamp: {timestamp:?}"))))?
.assume_utc()
.unix_timestamp();
let dir = Dir {
path: Cow::Owned(path.to_string()),
rank: 1.0,
last_accessed: timestamp as Epoch,
};
Ok(dir)
}
}
impl Iterator for Iter {
type Item = Result<Dir<'static>, ImportError>;
fn next(&mut self) -> Option<Self::Item> {
loop {
self.buf.clear();
self.line_num += 1;
match self.reader.read_until(b'\0', &mut self.buf) {
Ok(0) => return None,
Ok(_) => {
if self.buf.last() == Some(&b'\0') {
self.buf.pop();
}
if self.buf.is_empty() {
continue;
}
let result = self.parse_line(&self.buf);
match &result {
Ok(dir) => {
let path = dir.path.as_ref();
if self.prev_cwd.as_deref() == Some(path) {
continue; // dedup consecutive same-path entries
}
self.prev_cwd = Some(path.to_string());
return Some(result);
}
Err(_) => return Some(result),
}
}
Err(e) => {
return Some(Err(self.err(anyhow!(e).context("could not read from atuin"))));
}
}
}
}
}
impl Drop for Iter {
fn drop(&mut self) {
_ = self.child.kill();
_ = self.child.wait();
}
}

124
src/import/autojump.rs Normal file
View File

@ -0,0 +1,124 @@
use std::borrow::Cow;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::path::PathBuf;
use std::{env, str};
use anyhow::{Context, Result, anyhow};
use crate::db::Dir;
use crate::import::{ImportError, Importer};
#[derive(clap::Args, Clone, Debug)]
pub(crate) struct Autojump {}
impl Importer for Autojump {
fn dirs(&self) -> Result<impl Iterator<Item = Result<Dir<'static>, ImportError>>> {
let path = data_path()?;
let file = File::open(&path).with_context(|| format!("could not read {path:?}"))?;
let reader = BufReader::new(file);
Ok(Iter::new(reader, path))
}
}
struct Iter<R: BufRead> {
reader: R,
buf: Vec<u8>,
line_num: usize,
path: PathBuf,
}
impl<R: BufRead> Iter<R> {
fn new(reader: R, path: PathBuf) -> Self {
Self { reader, buf: Vec::new(), line_num: 0, path }
}
fn err(&self, source: anyhow::Error) -> ImportError {
ImportError { path: Some(self.path.clone()), line_num: self.line_num, source }
}
fn parse_line(&self, line: &[u8]) -> Result<Dir<'static>, ImportError> {
let line =
str::from_utf8(line).map_err(|e| self.err(anyhow!(e).context("invalid utf-8")))?;
let (rank, path) =
line.split_once('\t').ok_or_else(|| self.err(anyhow!("invalid entry: {line}")))?;
let rank = rank
.parse::<f64>()
.map_err(|e| self.err(anyhow!(e).context(format!("invalid rank: {rank}"))))?;
// Normalize the rank using a sigmoid function. Don't import actual ranks from
// autojump, since its scoring algorithm is very different and might
// take a while to normalize.
let rank = sigmoid(rank);
Ok(Dir { path: Cow::Owned(path.to_string()), rank, last_accessed: 0 })
}
}
impl<R: BufRead> Iterator for Iter<R> {
type Item = Result<Dir<'static>, ImportError>;
fn next(&mut self) -> Option<Self::Item> {
loop {
self.buf.clear();
self.line_num += 1;
match self.reader.read_until(b'\n', &mut self.buf) {
Ok(0) => return None,
Ok(_) => {
if self.buf.last() == Some(&b'\n') {
self.buf.pop();
}
if self.buf.last() == Some(&b'\r') {
self.buf.pop();
}
if self.buf.is_empty() {
continue;
}
return Some(self.parse_line(&self.buf));
}
Err(e) => return Some(Err(self.err(anyhow::Error::from(e)))),
}
}
}
}
/// Mirrors autojump's path logic:
///
/// ```python
/// if is_osx():
/// data_home = os.path.join(os.path.expanduser('~'), 'Library')
/// elif is_windows():
/// data_home = os.getenv('APPDATA')
/// else:
/// data_home = os.getenv(
/// 'XDG_DATA_HOME',
/// os.path.join(os.path.expanduser('~'), '.local', 'share'),
/// )
/// data_path = os.path.join(data_home, 'autojump', 'autojump.txt')
/// ```
fn data_path() -> Result<PathBuf> {
let mut path = if cfg!(target_os = "macos") {
let mut path = dirs::home_dir().context("could not find home directory")?;
path.push("Library");
path
} else if cfg!(target_os = "windows") {
let appdata = env::var_os("APPDATA").context("%APPDATA% is not set")?;
PathBuf::from(appdata)
} else if let Some(xdg) = env::var_os("XDG_DATA_HOME") {
PathBuf::from(xdg)
} else {
let mut path = dirs::home_dir().context("could not find home directory")?;
path.push(".local");
path.push("share");
path
};
path.push("autojump");
path.push("autojump.txt");
Ok(path)
}
fn sigmoid(x: f64) -> f64 {
1.0 / (1.0 + (-x).exp())
}

39
src/import/fasd.rs Normal file
View File

@ -0,0 +1,39 @@
use std::env;
use std::fs::File;
use std::io::BufReader;
use std::path::PathBuf;
use anyhow::{Context, Result};
use crate::db::Dir;
use crate::import::{ImportError, Importer, z};
#[derive(clap::Args, Clone, Debug)]
pub(crate) struct Fasd {}
impl Importer for Fasd {
fn dirs(&self) -> Result<impl Iterator<Item = Result<Dir<'static>, ImportError>>> {
let path = data_path()?;
let file = File::open(&path).with_context(|| format!("could not read {path:?}"))?;
let reader = BufReader::new(file);
// fasd uses the same `path|rank|last_accessed` line format as z, so reuse z's
// iterator.
Ok(z::Iter::new(reader, path))
}
}
/// Mirrors fasd's path logic:
///
/// ```sh
/// [ -z "$_FASD_DATA" ] && _FASD_DATA="$HOME/.fasd"
/// ```
fn data_path() -> Result<PathBuf> {
match env::var_os("_FASD_DATA") {
Some(path) => Ok(PathBuf::from(path)),
None => {
let mut path = dirs::home_dir().context("could not find home directory")?;
path.push(".fasd");
Ok(path)
}
}
}

103
src/import/z.rs Normal file
View File

@ -0,0 +1,103 @@
use std::borrow::Cow;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::path::PathBuf;
use std::{env, str};
use anyhow::{Context, Result, anyhow};
use crate::db::Dir;
use crate::import::{ImportError, Importer};
#[derive(clap::Args, Clone, Debug)]
pub(crate) struct Z {}
impl Importer for Z {
fn dirs(&self) -> Result<impl Iterator<Item = Result<Dir<'static>, ImportError>>> {
let path = data_path()?;
let file = File::open(&path).with_context(|| format!("could not read {path:?}"))?;
let reader = BufReader::new(file);
Ok(Iter::new(reader, path))
}
}
pub(crate) struct Iter<R: BufRead> {
reader: R,
buf: Vec<u8>,
line_num: usize,
path: PathBuf,
}
impl<R: BufRead> Iter<R> {
pub(crate) fn new(reader: R, path: PathBuf) -> Self {
Self { reader, buf: Vec::new(), line_num: 0, path }
}
fn err(&self, source: anyhow::Error) -> ImportError {
ImportError { path: Some(self.path.clone()), line_num: self.line_num, source }
}
fn parse_line(&self, line: &[u8]) -> Result<Dir<'static>, ImportError> {
let line =
str::from_utf8(line).map_err(|e| self.err(anyhow!(e).context("invalid utf-8")))?;
let err = || self.err(anyhow!("invalid entry: {line}"));
// z stores entries as `path|rank|last_accessed`. Use `rsplitn` so paths
// containing `|` are preserved.
let mut split = line.rsplitn(3, '|');
let last_accessed = split.next().ok_or_else(err)?;
let last_accessed = last_accessed.parse::<u64>().map_err(|_| err())?;
let rank = split.next().ok_or_else(err)?;
let rank = rank.parse::<f64>().map_err(|_| err())?;
let path = split.next().ok_or_else(err)?;
Ok(Dir { path: Cow::Owned(path.to_string()), rank, last_accessed })
}
}
impl<R: BufRead> Iterator for Iter<R> {
type Item = Result<Dir<'static>, ImportError>;
fn next(&mut self) -> Option<Self::Item> {
loop {
self.buf.clear();
self.line_num += 1;
match self.reader.read_until(b'\n', &mut self.buf) {
Ok(0) => return None,
Ok(_) => {
if self.buf.last() == Some(&b'\n') {
self.buf.pop();
}
if self.buf.last() == Some(&b'\r') {
self.buf.pop();
}
if self.buf.is_empty() {
continue;
}
return Some(self.parse_line(&self.buf));
}
Err(e) => return Some(Err(self.err(anyhow::Error::from(e)))),
}
}
}
}
/// Mirrors z's path logic:
///
/// ```sh
/// local datafile="${_Z_DATA:-$HOME/.z}"
/// ```
fn data_path() -> Result<PathBuf> {
match env::var_os("_Z_DATA") {
Some(path) => Ok(PathBuf::from(path)),
None => {
let mut path = dirs::home_dir().context("could not find home directory")?;
path.push(".z");
Ok(path)
}
}
}

108
src/import/z_lua.rs Normal file
View File

@ -0,0 +1,108 @@
use std::env;
use std::ffi::OsStr;
use std::fs::File;
use std::io::{self, BufReader};
use std::path::PathBuf;
use anyhow::{Context, Result};
use crate::db::Dir;
use crate::import::{ImportError, Importer, z};
#[derive(clap::Args, Clone, Debug)]
pub(crate) struct ZLua {}
impl Importer for ZLua {
fn dirs(&self) -> Result<impl Iterator<Item = Result<Dir<'static>, ImportError>>> {
let path = data_path()?;
let err = match File::open(&path) {
Ok(file) => return Ok(z::Iter::new(BufReader::new(file), path)),
Err(e) if e.kind() == io::ErrorKind::NotFound => e,
Err(e) => return Err(e).with_context(|| format!("could not read {path:?}")),
};
let fish_path = data_path_fish()?;
let file = match File::open(&fish_path) {
Ok(file) => file,
// Both paths missing - report the original path's error.
Err(e) if e.kind() == io::ErrorKind::NotFound => {
return Err(err).with_context(|| format!("could not read {path:?}"));
}
// Fish path failed for some other reason (permissions, etc.)
Err(e) => return Err(e).with_context(|| format!("could not read {fish_path:?}")),
};
// z.lua uses the same `path|rank|last_accessed` line format as z.
Ok(z::Iter::new(BufReader::new(file), fish_path))
}
}
/// Mirrors z.lua's path logic:
///
/// ```lua
/// DATA_FILE = '~/.zlua' -- default
///
/// -- in z_init():
/// local _zl_data = os.getenv('_ZL_DATA')
/// if _zl_data ~= nil and _zl_data ~= "" then
/// if windows then
/// DATA_FILE = _zl_data
/// else
/// -- avoid windows environments affect cygwin & msys
/// if not string.match(_zl_data, '^%a:[/\\]') then
/// DATA_FILE = _zl_data
/// end
/// end
/// end
/// ```
fn data_path() -> Result<PathBuf> {
if let Some(path) = env::var_os("_ZL_DATA")
// Skip empty paths.
.filter(|path| !path.is_empty())
// On non-Windows, skip values that look like a Windows path (`C:\...`)
// — guards against Cygwin/MSYS environments leaking through.
.filter(|path| cfg!(target_os = "windows") || !looks_like_windows_path(path))
{
return Ok(PathBuf::from(path));
}
let mut path = dirs::home_dir().context("could not find home directory")?;
path.push(".zlua");
Ok(path)
}
/// Mirrors z.lua's path logic on Fish:
///
/// ```fish
/// if test -z "$XDG_DATA_HOME"
/// set -U _ZL_DATA_DIR "$HOME/.local/share/zlua"
/// else
/// set -U _ZL_DATA_DIR "$XDG_DATA_HOME/zlua"
/// end
/// set -x _ZL_DATA "$_ZL_DATA_DIR/zlua.txt"
/// ```
fn data_path_fish() -> Result<PathBuf> {
let mut path = match env::var_os("XDG_DATA_HOME") {
Some(xdg) => PathBuf::from(xdg),
None => {
let mut path = dirs::home_dir().context("could not find home directory")?;
path.push(".local");
path.push("share");
path
}
};
path.push("zlua");
path.push("zlua.txt");
Ok(path)
}
/// Matches Lua's `^%a:[/\\]` — ASCII letter, colon, slash-or-backslash.
fn looks_like_windows_path(s: &OsStr) -> bool {
let bytes = s.as_encoded_bytes();
bytes.len() >= 3
&& bytes[0].is_ascii_alphabetic()
&& bytes[1] == b':'
&& (bytes[2] == b'/' || bytes[2] == b'\\')
}

41
src/import/zsh_z.rs Normal file
View File

@ -0,0 +1,41 @@
use std::env;
use std::fs::File;
use std::io::BufReader;
use std::path::PathBuf;
use anyhow::{Context, Result};
use crate::db::Dir;
use crate::import::{ImportError, Importer, z};
#[derive(clap::Args, Clone, Debug)]
pub(crate) struct ZshZ {}
impl Importer for ZshZ {
fn dirs(&self) -> Result<impl Iterator<Item = Result<Dir<'static>, ImportError>>> {
let path = data_path()?;
let file = File::open(&path).with_context(|| format!("could not read {path:?}"))?;
let reader = BufReader::new(file);
// zsh-z uses the same `path|rank|last_accessed` line format as z.
Ok(z::Iter::new(reader, path))
}
}
/// Mirrors zsh-z's path logic:
///
/// ```sh
/// # Allow the user to specify a custom datafile in $ZSHZ_DATA (or legacy $_Z_DATA)
/// local custom_datafile="${ZSHZ_DATA:-$_Z_DATA}"
/// # If the user specified a datafile, use that or default to ~/.z
/// local datafile=${${custom_datafile:-$HOME/.z}:A}
/// ```
fn data_path() -> Result<PathBuf> {
match env::var_os("ZSHZ_DATA").or_else(|| env::var_os("_Z_DATA")) {
Some(path) => Ok(PathBuf::from(path)),
None => {
let mut path = dirs::home_dir().context("could not find home directory")?;
path.push(".z");
Ok(path)
}
}
}

View File

@ -4,6 +4,7 @@ mod cmd;
mod config; mod config;
mod db; mod db;
mod error; mod error;
mod import;
mod shell; mod shell;
mod util; mod util;

View File

@ -100,7 +100,7 @@ mod tests {
let mut source = String::new(); let mut source = String::new();
// Filter out lines using edit:*, since those functions are only available in // Filter out lines using edit:*, since those functions are only available in
// the interactive editor. // interactive editor mode.
for line in Elvish(&opts).render().unwrap().lines().filter(|line| !line.contains("edit:")) { for line in Elvish(&opts).render().unwrap().lines().filter(|line| !line.contains("edit:")) {
source.push_str(line); source.push_str(line);
source.push('\n'); source.push('\n');

View File

@ -168,13 +168,9 @@ pub fn write(path: impl AsRef<Path>, contents: impl AsRef<[u8]>) -> Result<()> {
// Set the owner of the tmpfile (UNIX only). // Set the owner of the tmpfile (UNIX only).
#[cfg(unix)] #[cfg(unix)]
if let Ok(metadata) = path.metadata() { if let Ok(metadata) = path.metadata() {
use std::os::unix::fs::MetadataExt; use std::os::unix::fs::{MetadataExt, fchown};
use nix::unistd::{self, Gid, Uid}; _ = fchown(&tmp_file, Some(metadata.uid()), Some(metadata.gid()));
let uid = Uid::from_raw(metadata.uid());
let gid = Gid::from_raw(metadata.gid());
_ = unistd::fchown(&tmp_file, Some(uid), Some(gid));
} }
// Close and rename the tmpfile. // Close and rename the tmpfile.

View File

@ -9,12 +9,16 @@
# pwd based on the value of _ZO_RESOLVE_SYMLINKS. # pwd based on the value of _ZO_RESOLVE_SYMLINKS.
function __zoxide_pwd() { function __zoxide_pwd() {
{%- decl pwd -%}
{%- if resolve_symlinks -%}
{%- let pwd = "\\builtin pwd -P" -%}
{%- else -%}
{%- let pwd = "\\builtin pwd -L" -%}
{%- endif -%}
{%- if cfg!(windows) %} {%- if cfg!(windows) %}
\command cygpath -w "$(\builtin pwd -P)" \command cygpath -w "{{ pwd }}"
{%- else if resolve_symlinks %}
\builtin pwd -P
{%- else %} {%- else %}
\builtin pwd -L {{ pwd }}
{%- endif %} {%- endif %}
} }
@ -59,7 +63,7 @@ if [[ ${PROMPT_COMMAND:=} != *'__zoxide_hook'* ]]; then
PROMPT_COMMAND=("${PROMPT_COMMAND[@]}" __zoxide_hook) PROMPT_COMMAND=("${PROMPT_COMMAND[@]}" __zoxide_hook)
else else
# shellcheck disable=SC2128,SC2178 # shellcheck disable=SC2128,SC2178
PROMPT_COMMAND="${PROMPT_COMMAND%"${PROMPT_COMMAND##*[![:space:]]}"}" PROMPT_COMMAND="${PROMPT_COMMAND%"${PROMPT_COMMAND##*[![:space:];]}"}"
# shellcheck disable=SC2128,SC2178 # shellcheck disable=SC2128,SC2178
PROMPT_COMMAND="${PROMPT_COMMAND:+${PROMPT_COMMAND};}__zoxide_hook" PROMPT_COMMAND="${PROMPT_COMMAND:+${PROMPT_COMMAND};}__zoxide_hook"
fi fi

View File

@ -7,19 +7,27 @@
# pwd based on the value of _ZO_RESOLVE_SYMLINKS. # pwd based on the value of _ZO_RESOLVE_SYMLINKS.
function __zoxide_pwd function __zoxide_pwd
{%- decl pwd -%}
{%- if resolve_symlinks -%}
{%- let pwd = "builtin pwd -P" -%}
{%- else -%}
{%- let pwd = "builtin pwd -L" -%}
{%- endif -%}
{%- if cfg!(windows) %} {%- if cfg!(windows) %}
command cygpath -w (builtin pwd -P) command cygpath -w ({{ pwd }})
{%- else if resolve_symlinks %}
builtin pwd -P
{%- else %} {%- else %}
builtin pwd -L {{ pwd }}
{%- endif %} {%- endif %}
end end
# A copy of fish's internal cd function. This makes it possible to use # A copy of fish's internal cd function. This makes it possible to use
# `alias cd=z` without causing an infinite loop. # `alias cd=z` without causing an infinite loop.
if ! builtin functions --query __zoxide_cd_internal if ! builtin functions --query __zoxide_cd_internal
string replace --regex -- '^function cd\s' 'function __zoxide_cd_internal ' <$__fish_data_dir/functions/cd.fish | source if status list-files functions/cd.fish &>/dev/null
status get-file functions/cd.fish | string replace --regex -- '^function cd\s' 'function __zoxide_cd_internal ' | source
else
string replace --regex -- '^function cd\s' 'function __zoxide_cd_internal ' <$__fish_data_dir/functions/cd.fish | source
end
end end
# cd + custom logic based on the value of _ZO_ECHO. # cd + custom logic based on the value of _ZO_ECHO.
@ -113,9 +121,11 @@ end
{%- when Some with (cmd) %} {%- when Some with (cmd) %}
abbr --erase {{cmd}} &>/dev/null abbr --erase {{cmd}} &>/dev/null
complete --erase --command {{cmd}}
alias {{cmd}}=__zoxide_z alias {{cmd}}=__zoxide_z
abbr --erase {{cmd}}i &>/dev/null abbr --erase {{cmd}}i &>/dev/null
complete --erase --command {{cmd}}i
alias {{cmd}}i=__zoxide_zi alias {{cmd}}i=__zoxide_zi
{%- when None %} {%- when None %}

View File

@ -8,15 +8,28 @@
# #
# pwd based on the value of _ZO_RESOLVE_SYMLINKS. # pwd based on the value of _ZO_RESOLVE_SYMLINKS.
__zoxide_pwd() { {%- decl pwd -%}
{%- if resolve_symlinks -%}
{%- let pwd = "\\command pwd -P" -%}
{%- else -%}
{%- let pwd = "\\command pwd -L" -%}
{%- endif -%}
{%- if cfg!(windows) %} {%- if cfg!(windows) %}
\command cygpath -w "$(\builtin pwd -P)" if \command -v cygpath >/dev/null
{%- else if resolve_symlinks %} then
\command pwd -P __zoxide_pwd() {
\command cygpath -w "$({{ pwd }})"
}
else
__zoxide_pwd() {
{{ pwd }}
}
fi
{%- else %} {%- else %}
\command pwd -L __zoxide_pwd() {
{%- endif %} {{ pwd }}
} }
{%- endif %}
# cd + custom logic based on the value of _ZO_ECHO. # cd + custom logic based on the value of _ZO_ECHO.
__zoxide_cd() { __zoxide_cd() {
@ -35,7 +48,7 @@ __zoxide_cd() {
{%- when InitHook::Prompt -%} {%- when InitHook::Prompt -%}
# Hook to add new entries to the database. # Hook to add new entries to the database.
__zoxide_hook() { __zoxide_hook() {
\command zoxide add -- "$(__zoxide_pwd || \builtin true)" \command zoxide add -- "$(__zoxide_pwd || \command true)"
} }
# Initialize hook. # Initialize hook.
@ -95,7 +108,7 @@ __zoxide_z() {
elif [ "$#" -eq 1 ] && [ -d "$1" ]; then elif [ "$#" -eq 1 ] && [ -d "$1" ]; then
__zoxide_cd "$1" __zoxide_cd "$1"
else else
__zoxide_result="$(\command zoxide query --exclude "$(__zoxide_pwd || \builtin true)" -- "$@")" && __zoxide_result="$(\command zoxide query --exclude "$(__zoxide_pwd || \command true)" -- "$@")" &&
__zoxide_cd "${__zoxide_result}" __zoxide_cd "${__zoxide_result}"
fi fi
} }

View File

@ -19,7 +19,7 @@ function global:__zoxide_bin {
# pwd based on zoxide's format. # pwd based on zoxide's format.
function global:__zoxide_pwd { function global:__zoxide_pwd {
$cwd = Get-Location $cwd = Microsoft.PowerShell.Management\Get-Location
if ($cwd.Provider.Name -eq "FileSystem") { if ($cwd.Provider.Name -eq "FileSystem") {
$cwd.ProviderPath $cwd.ProviderPath
} }
@ -28,20 +28,24 @@ function global:__zoxide_pwd {
# cd + custom logic based on the value of _ZO_ECHO. # cd + custom logic based on the value of _ZO_ECHO.
function global:__zoxide_cd($dir, $literal) { function global:__zoxide_cd($dir, $literal) {
$dir = if ($literal) { $dir = if ($literal) {
Set-Location -LiteralPath $dir -Passthru -ErrorAction Stop if ($null -eq $dir) {
Microsoft.PowerShell.Management\Set-Location
} else {
Microsoft.PowerShell.Management\Set-Location -LiteralPath $dir -Passthru -ErrorAction Stop
}
} else { } else {
if ($dir -eq '-' -and ($PSVersionTable.PSVersion -lt 6.1)) { if ($dir -eq '-' -and ($PSVersionTable.PSVersion -lt 6.1)) {
Write-Error "cd - is not supported below PowerShell 6.1. Please upgrade your version of PowerShell." Microsoft.PowerShell.Utility\Write-Error "cd - is not supported below PowerShell 6.1. Please upgrade your version of PowerShell."
} }
elseif ($dir -eq '+' -and ($PSVersionTable.PSVersion -lt 6.2)) { elseif ($dir -eq '+' -and ($PSVersionTable.PSVersion -lt 6.2)) {
Write-Error "cd + is not supported below PowerShell 6.2. Please upgrade your version of PowerShell." Microsoft.PowerShell.Utility\Write-Error "cd + is not supported below PowerShell 6.2. Please upgrade your version of PowerShell."
} }
else { else {
Set-Location -Path $dir -Passthru -ErrorAction Stop Microsoft.PowerShell.Management\Set-Location -Path $dir -Passthru -ErrorAction Stop
} }
} }
{%- if echo %} {%- if echo %}
Write-Output $dir.Path Microsoft.PowerShell.Utility\Write-Output $dir.Path
{%- endif %} {%- endif %}
} }
@ -80,7 +84,7 @@ function global:__zoxide_hook {
{%- endif %} {%- endif %}
# Initialize hook. # Initialize hook.
$global:__zoxide_hooked = (Get-Variable __zoxide_hooked -ErrorAction Ignore -ValueOnly) $global:__zoxide_hooked = (Microsoft.PowerShell.Utility\Get-Variable __zoxide_hooked -ErrorAction Ignore -ValueOnly)
if ($global:__zoxide_hooked -ne 1) { if ($global:__zoxide_hooked -ne 1) {
$global:__zoxide_hooked = 1 $global:__zoxide_hooked = 1
$global:__zoxide_prompt_old = $function:prompt $global:__zoxide_prompt_old = $function:prompt
@ -101,15 +105,15 @@ if ($global:__zoxide_hooked -ne 1) {
# Jump to a directory using only keywords. # Jump to a directory using only keywords.
function global:__zoxide_z { function global:__zoxide_z {
if ($args.Length -eq 0) { if ($args.Length -eq 0) {
__zoxide_cd ~ $true __zoxide_cd $null $true
} }
elseif ($args.Length -eq 1 -and ($args[0] -eq '-' -or $args[0] -eq '+')) { elseif ($args.Length -eq 1 -and ($args[0] -eq '-' -or $args[0] -eq '+')) {
__zoxide_cd $args[0] $false __zoxide_cd $args[0] $false
} }
elseif ($args.Length -eq 1 -and (Test-Path -PathType Container -LiteralPath $args[0])) { elseif ($args.Length -eq 1 -and (Microsoft.PowerShell.Management\Test-Path -PathType Container -LiteralPath $args[0])) {
__zoxide_cd $args[0] $true __zoxide_cd $args[0] $true
} }
elseif ($args.Length -eq 1 -and (Test-Path -PathType Container -Path $args[0] )) { elseif ($args.Length -eq 1 -and (Microsoft.PowerShell.Management\Test-Path -PathType Container -Path $args[0] )) {
__zoxide_cd $args[0] $false __zoxide_cd $args[0] $false
} }
else { else {
@ -141,8 +145,8 @@ function global:__zoxide_zi {
{%- match cmd %} {%- match cmd %}
{%- when Some with (cmd) %} {%- when Some with (cmd) %}
Set-Alias -Name {{cmd}} -Value __zoxide_z -Option AllScope -Scope Global -Force Microsoft.PowerShell.Utility\Set-Alias -Name {{cmd}} -Value __zoxide_z -Option AllScope -Scope Global -Force
Set-Alias -Name {{cmd}}i -Value __zoxide_zi -Option AllScope -Scope Global -Force Microsoft.PowerShell.Utility\Set-Alias -Name {{cmd}}i -Value __zoxide_zi -Option AllScope -Scope Global -Force
{%- when None %} {%- when None %}

View File

@ -1,7 +1,7 @@
{%- let section = "# =============================================================================\n#" -%} {%- let section = "# =============================================================================\n#" -%}
{%- let not_configured = "# -- not configured --" -%} {%- let not_configured = "# -- not configured --" -%}
{%- let pwd_cmd -%} {%- decl pwd_cmd -%}
{%- if resolve_symlinks -%} {%- if resolve_symlinks -%}
{%- let pwd_cmd = "pwd -P" -%} {%- let pwd_cmd = "pwd -P" -%}
{%- else -%} {%- else -%}

View File

@ -9,12 +9,16 @@
# pwd based on the value of _ZO_RESOLVE_SYMLINKS. # pwd based on the value of _ZO_RESOLVE_SYMLINKS.
function __zoxide_pwd() { function __zoxide_pwd() {
{%- decl pwd -%}
{%- if resolve_symlinks -%}
{%- let pwd = "\\builtin pwd -P" -%}
{%- else -%}
{%- let pwd = "\\builtin pwd -L" -%}
{%- endif -%}
{%- if cfg!(windows) %} {%- if cfg!(windows) %}
\command cygpath -w "$(\builtin pwd -P)" \command cygpath -w "{{ pwd }}"
{%- else if resolve_symlinks %}
\builtin pwd -P
{%- else %} {%- else %}
\builtin pwd -L {{ pwd }}
{%- endif %} {%- endif %}
} }
@ -55,6 +59,7 @@ function __zoxide_doctor() {
{%- else %} {%- else %}
[[ ${_ZO_DOCTOR:-1} -ne 0 ]] || return 0 [[ ${_ZO_DOCTOR:-1} -ne 0 ]] || return 0
[[ $- == *i* ]] || return 0
{%- if hook == InitHook::Prompt %} {%- if hook == InitHook::Prompt %}
[[ ${precmd_functions[(Ie)__zoxide_hook]:-} -eq 0 ]] || return 0 [[ ${precmd_functions[(Ie)__zoxide_hook]:-} -eq 0 ]] || return 0