mirror of
https://github.com/Llewellynvdm/zoxide.git
synced 2024-11-22 21:05:16 +00:00
commit
8abba828ea
93
CHANGELOG.md
Normal file
93
CHANGELOG.md
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
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/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [0.3.0] - 2020-03-30
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Automatic migration from `v0.2.x` databases.
|
||||||
|
- `$_ZO_EXCLUDE_DIRS` to prevent certain directories from being added to the database.
|
||||||
|
- Support for POSIX-compliant shells.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Database location defaults to user's local data directory.
|
||||||
|
- Database schema now includes a version number.
|
||||||
|
- `migrate` subcommand renamed to `import`.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Achieve thread safety using unique temporary database file names for each `zoxide` instance.
|
||||||
|
- Incomprehensive "could not allocate" message on database corruption.
|
||||||
|
|
||||||
|
## [0.2.2] - 2020-03-20
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Incorrect exit codes in `z` command on `fish`.
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- File locks on database.
|
||||||
|
|
||||||
|
## [0.2.1] - 2020-03-16
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- `$_ZO_ECHO` to echo match before `cd`ing.
|
||||||
|
- Minimal `ranger` plugin.
|
||||||
|
- PWD hook to only update the database when the current directory is changed.
|
||||||
|
- Support for the `bash` shell.
|
||||||
|
- `migrate` subcommand to allow users to migrate from `z`.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Interactive queries causing other open shells to hang.
|
||||||
|
|
||||||
|
## [0.2.0] - 2020-03-11
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- `init` subcommand to remove dependency on shell plugin managers.
|
||||||
|
- Support for `z -` command to go to previous directory.
|
||||||
|
- `Cargo.lock` for more reproducible builds.
|
||||||
|
- Support for the `fish` shell.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- `_zoxide_precmd` overriding other precmd hooks on `zsh`.
|
||||||
|
|
||||||
|
## [0.1.1] - 2020-03-08
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Install script for Linux/macOS users.
|
||||||
|
- Aging algorithm to remove stale entries.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Database schema now uses `f64` values for rank instead of `i32`.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Multiple hooks being added upon initializing `zoxide` multiple times.
|
||||||
|
|
||||||
|
## [0.1.0] - 2020-03-05
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- GitHub Actions pipeline to build and upload releases.
|
||||||
|
- Support for the `zsh` shell.
|
||||||
|
|
||||||
|
[0.3.0]: https://github.com/ajeetdsouza/zoxide/compare/v0.2.2...v0.3.0
|
||||||
|
[0.2.2]: https://github.com/ajeetdsouza/zoxide/compare/v0.2.1...v0.2.2
|
||||||
|
[0.2.1]: https://github.com/ajeetdsouza/zoxide/compare/v0.2.0...v0.2.1
|
||||||
|
[0.2.0]: https://github.com/ajeetdsouza/zoxide/compare/v0.1.1...v0.2.0
|
||||||
|
[0.1.1]: https://github.com/ajeetdsouza/zoxide/compare/v0.1.0...v0.1.1
|
||||||
|
[0.1.0]: https://github.com/ajeetdsouza/zoxide/commits/v0.1.0
|
164
Cargo.lock
generated
164
Cargo.lock
generated
@ -10,7 +10,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.26"
|
version = "1.0.27"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -29,7 +29,7 @@ version = "0.2.14"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ version = "1.2.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -67,6 +67,16 @@ dependencies = [
|
|||||||
"constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bstr"
|
||||||
|
version = "0.2.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"regex-automata 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
version = "1.3.4"
|
version = "1.3.4"
|
||||||
@ -121,26 +131,18 @@ version = "0.3.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"redox_users 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"redox_users 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "envy"
|
|
||||||
version = "0.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.1.14"
|
version = "0.1.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -157,7 +159,7 @@ name = "hermit-abi"
|
|||||||
version = "0.1.8"
|
version = "0.1.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -167,29 +169,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.67"
|
version = "0.2.68"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ppv-lite86"
|
||||||
|
version = "0.2.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-error"
|
name = "proc-macro-error"
|
||||||
version = "0.4.11"
|
version = "0.4.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro-error-attr 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro-error-attr 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-error-attr"
|
name = "proc-macro-error-attr"
|
||||||
version = "0.4.11"
|
version = "0.4.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
@ -210,6 +222,43 @@ dependencies = [
|
|||||||
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.7.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_hc"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.1.56"
|
version = "0.1.56"
|
||||||
@ -225,6 +274,14 @@ dependencies = [
|
|||||||
"rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.1.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rust-argon2"
|
name = "rust-argon2"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
@ -238,20 +295,20 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.104"
|
version = "1.0.105"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_derive 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.104"
|
version = "1.0.105"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -261,29 +318,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "structopt"
|
name = "structopt"
|
||||||
version = "0.3.11"
|
version = "0.3.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"structopt-derive 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"structopt-derive 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "structopt-derive"
|
name = "structopt-derive"
|
||||||
version = "0.4.4"
|
version = "0.4.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"proc-macro-error 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro-error 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.16"
|
version = "1.0.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -298,7 +355,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -324,6 +381,14 @@ name = "unicode-xid"
|
|||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uuid"
|
||||||
|
version = "0.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vec_map"
|
name = "vec_map"
|
||||||
version = "0.8.1"
|
version = "0.8.1"
|
||||||
@ -362,18 +427,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
name = "zoxide"
|
name = "zoxide"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)",
|
"anyhow 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"bstr 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"envy 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
"structopt 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"structopt 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||||
"checksum anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "7825f6833612eb2414095684fcf6c635becf3ce97fe48cf6421321e93bfbd53c"
|
"checksum anyhow 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "013a6e0a2cbe3d20f9c60b65458f7a7f7a5e636c5d0f45a5a6aee5d4b1f01785"
|
||||||
"checksum arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
|
"checksum arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
|
||||||
"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
|
"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
|
||||||
"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||||
@ -382,6 +448,7 @@ dependencies = [
|
|||||||
"checksum bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5753e2a71534719bf3f4e57006c3a4f0d2c672a4b676eec84161f763eca87dbf"
|
"checksum bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5753e2a71534719bf3f4e57006c3a4f0d2c672a4b676eec84161f763eca87dbf"
|
||||||
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||||
"checksum blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a"
|
"checksum blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a"
|
||||||
|
"checksum bstr 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "2889e6d50f394968c8bf4240dc3f2a7eb4680844d27308f798229ac9d4725f41"
|
||||||
"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
||||||
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||||
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
|
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
|
||||||
@ -389,30 +456,37 @@ dependencies = [
|
|||||||
"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
||||||
"checksum dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3"
|
"checksum dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3"
|
||||||
"checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b"
|
"checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b"
|
||||||
"checksum envy 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f938a4abd5b75fe3737902dbc2e79ca142cc1526827a9e40b829a086758531a9"
|
|
||||||
"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
|
"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
|
||||||
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
|
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
|
||||||
"checksum hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8"
|
"checksum hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8"
|
||||||
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
"checksum libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018"
|
"checksum libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)" = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0"
|
||||||
"checksum proc-macro-error 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e7959c6467d962050d639361f7703b2051c43036d03493c36f01d440fdd3138a"
|
"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
|
||||||
"checksum proc-macro-error-attr 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e4002d9f55991d5e019fb940a90e1a95eb80c24e77cb2462dd4dc869604d543a"
|
"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
|
||||||
|
"checksum proc-macro-error 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "18f33027081eba0a6d8aba6d1b1c3a3be58cbb12106341c2d5759fcd9b5277e7"
|
||||||
|
"checksum proc-macro-error-attr 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "8a5b4b77fdb63c1eca72173d68d24501c54ab1269409f6b672c85deb18af69de"
|
||||||
"checksum proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435"
|
"checksum proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435"
|
||||||
"checksum quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f"
|
"checksum quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f"
|
||||||
|
"checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
||||||
|
"checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
||||||
|
"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
||||||
|
"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
||||||
"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
|
"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
|
||||||
"checksum redox_users 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431"
|
"checksum redox_users 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431"
|
||||||
|
"checksum regex-automata 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4"
|
||||||
"checksum rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017"
|
"checksum rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017"
|
||||||
"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449"
|
"checksum serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)" = "e707fbbf255b8fc8c3b99abb91e7257a622caeb20a9818cbadbeeede4e0932ff"
|
||||||
"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64"
|
"checksum serde_derive 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)" = "ac5d00fc561ba2724df6758a17de23df5914f20e41cb00f94d5b7ae42fffaff8"
|
||||||
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||||
"checksum structopt 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe43617218c0805c6eb37160119dc3c548110a67786da7218d1c6555212f073"
|
"checksum structopt 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "c8faa2719539bbe9d77869bfb15d4ee769f99525e707931452c97b693b3f159d"
|
||||||
"checksum structopt-derive 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c6e79c80e0f4efd86ca960218d4e056249be189ff1c42824dcd9a7f51a56f0bd"
|
"checksum structopt-derive 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f88b8e18c69496aad6f9ddf4630dd7d585bcaf765786cb415b9aec2fe5a0430"
|
||||||
"checksum syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "123bd9499cfb380418d509322d7a6d52e5315f064fe4b3ad18a53d6b92c07859"
|
"checksum syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03"
|
||||||
"checksum syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a"
|
"checksum syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a"
|
||||||
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||||
"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
|
"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
|
||||||
"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
|
"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
|
||||||
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
||||||
|
"checksum uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11"
|
||||||
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
|
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
|
||||||
"checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce"
|
"checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce"
|
||||||
"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||||
|
11
Cargo.toml
11
Cargo.toml
@ -13,13 +13,16 @@ license = "MIT"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.26"
|
anyhow = "1.0.27"
|
||||||
bincode = "1.2.1"
|
bincode = "1.2.1"
|
||||||
clap = "2.33.0"
|
clap = "2.33.0"
|
||||||
dirs = "2.0.2"
|
dirs = "2.0.2"
|
||||||
envy = "0.4.1"
|
serde = { version = "1.0.105", features = ["derive"] }
|
||||||
serde = { version = "1.0.104", features = ["derive"] }
|
structopt = "0.3.12"
|
||||||
structopt = "0.3.11"
|
uuid = { version = "0.8.1", features = ["v4"] }
|
||||||
|
|
||||||
|
[target.'cfg(unix)'.dependencies]
|
||||||
|
bstr = "0.2.12"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
|
29
README.md
29
README.md
@ -22,7 +22,10 @@ A cd command that learns your habits
|
|||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
`zoxide` is a blazing fast alternative to `cd`, inspired by [`z`](https://github.com/rupa/z) and [`z.lua`](https://github.com/skywind3000/z.lua). It keeps track of the directories you use most frequently, and uses a ranking algorithm to navigate to the best match.
|
`zoxide` is a blazing fast alternative to `cd`, inspired by
|
||||||
|
[`z`](https://github.com/rupa/z) and [`z.lua`](https://github.com/skywind3000/z.lua).
|
||||||
|
It keeps track of the directories you use most frequently, and uses a ranking algorithm
|
||||||
|
to navigate to the best match.
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
@ -56,14 +59,16 @@ Otherwise, try the install script:
|
|||||||
curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/ajeetdsouza/zoxide/master/install.sh | sh
|
curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/ajeetdsouza/zoxide/master/install.sh | sh
|
||||||
```
|
```
|
||||||
|
|
||||||
If you want the interactive fuzzy selection feature, you will also need to install [`fzf`](https://github.com/junegunn/fzf.git).
|
If you want the interactive fuzzy selection feature, you will also need to install
|
||||||
|
[`fzf`](https://github.com/junegunn/fzf.git).
|
||||||
|
|
||||||
### Step 2: Adding `zoxide` to your shell
|
### Step 2: Adding `zoxide` to your shell
|
||||||
|
|
||||||
If you currently use `z`, `z.lua`, or `zsh-z`, you may want to first migrate your existing database to `zoxide`:
|
If you currently use `z`, `z.lua`, or `zsh-z`, you may want to first import
|
||||||
|
your existing database into `zoxide`:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
zoxide migrate /path/to/db
|
zoxide import /path/to/db
|
||||||
```
|
```
|
||||||
|
|
||||||
#### zsh
|
#### zsh
|
||||||
@ -92,17 +97,17 @@ zoxide init fish | source
|
|||||||
|
|
||||||
#### POSIX
|
#### POSIX
|
||||||
|
|
||||||
Add the following line to your shell's configuration file (or, run it manually):
|
Add the following line to your shell's configuration file:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
eval "$(zoxide init posix)"
|
eval "$(zoxide init posix)"
|
||||||
```
|
```
|
||||||
|
|
||||||
NOTE: If you modify your `PS1` at any point, you may need to re-run the above command. This is due
|
NOTE: If you modify your `PS1` at any point, you may need to re-run the above command. This is due
|
||||||
to the fact that we store our hook in `PS1`, in order to be evaluated every time the prompt is
|
to the fact that the hook is stored in `PS1`, in order to be evaluated every time the prompt is
|
||||||
displayed.
|
displayed.
|
||||||
|
|
||||||
NOTE: There is no PWD hook provided for POSIX shells.
|
NOTE: PWD hooks are currently not supported for POSIX shells.
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
@ -110,12 +115,18 @@ NOTE: There is no PWD hook provided for POSIX shells.
|
|||||||
|
|
||||||
- `--no-define-aliases`: don't define extra aliases like `zi`, `zq`, `za`, and `zr`
|
- `--no-define-aliases`: don't define extra aliases like `zi`, `zq`, `za`, and `zr`
|
||||||
- `--hook <HOOK>`: change the event that adds a new entry to the database (default: `prompt`)
|
- `--hook <HOOK>`: change the event that adds a new entry to the database (default: `prompt`)
|
||||||
- `none`: never add entries - this will make `zoxide` useless unless you manually configure a hook
|
- `none`: never add entries (this will make `zoxide` useless unless you manually configure a hook)
|
||||||
- `prompt`: add an entry at every prompt
|
- `prompt`: add an entry at every prompt
|
||||||
- `pwd`: add an entry whenever you change directories
|
- `pwd`: add an entry whenever you change directories
|
||||||
|
|
||||||
### Environment variables
|
### Environment variables
|
||||||
|
|
||||||
|
- `$_ZO_DATA_DIR`: directory where `zoxide` will store its data files (default:
|
||||||
|
platform-specific; see the [`dirs` documentation] for more information)
|
||||||
- `$_ZO_ECHO`: `z` will print the matched directory before navigating to it
|
- `$_ZO_ECHO`: `z` will print the matched directory before navigating to it
|
||||||
- `$_ZO_DATA`: sets the location of the database (default: `~/.zo`)
|
- `$_ZO_EXCLUDE_DIRS`: list of directories separated by platform-specific
|
||||||
|
characters ("`:`" on Linux and macOS, and "`;`" on Windows) to be excluded from
|
||||||
|
the database
|
||||||
- `$_ZO_MAXAGE`: sets the maximum total rank after which entries start getting deleted
|
- `$_ZO_MAXAGE`: sets the maximum total rank after which entries start getting deleted
|
||||||
|
|
||||||
|
[`dirs` documentation]: https://docs.rs/dirs/latest/dirs/fn.data_local_dir.html
|
||||||
|
53
src/config.rs
Normal file
53
src/config.rs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
use crate::db::DBVersion;
|
||||||
|
use crate::dir::Rank;
|
||||||
|
|
||||||
|
use anyhow::{bail, Context, Result};
|
||||||
|
|
||||||
|
use std::env;
|
||||||
|
use std::fs;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
pub const DB_MAX_SIZE: u64 = 8 * 1024 * 1024; // 8 MiB
|
||||||
|
pub const DB_VERSION: DBVersion = 3;
|
||||||
|
|
||||||
|
pub fn zo_data_dir() -> Result<PathBuf> {
|
||||||
|
let data_dir = match env::var_os("_ZO_DATA_DIR") {
|
||||||
|
Some(data_osstr) => PathBuf::from(data_osstr),
|
||||||
|
None => match dirs::data_local_dir() {
|
||||||
|
Some(mut data_dir) => {
|
||||||
|
data_dir.push("zoxide");
|
||||||
|
data_dir
|
||||||
|
}
|
||||||
|
None => bail!("could not find database directory, please set _ZO_DATA_DIR manually"),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// This will fail when `data_dir` points to a file or a broken symlink, but
|
||||||
|
// will no-op on a valid symlink (to a directory), or an actual directory.
|
||||||
|
fs::create_dir_all(&data_dir).context("could not create data directory")?;
|
||||||
|
|
||||||
|
Ok(data_dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn zo_exclude_dirs() -> Vec<PathBuf> {
|
||||||
|
match env::var_os("_ZO_EXCLUDE_DIRS") {
|
||||||
|
Some(dirs_osstr) => env::split_paths(&dirs_osstr).collect(),
|
||||||
|
None => Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn zo_maxage() -> Result<Rank> {
|
||||||
|
match env::var_os("_ZO_MAXAGE") {
|
||||||
|
Some(maxage_osstr) => match maxage_osstr.to_str() {
|
||||||
|
Some(maxage_str) => {
|
||||||
|
let maxage = maxage_str
|
||||||
|
.parse::<i64>()
|
||||||
|
.context("unable to parse _ZO_MAXAGE as integer")?;
|
||||||
|
|
||||||
|
Ok(maxage as Rank)
|
||||||
|
}
|
||||||
|
None => bail!("invalid Unicode in _ZO_MAXAGE"),
|
||||||
|
},
|
||||||
|
None => Ok(1000.0),
|
||||||
|
}
|
||||||
|
}
|
203
src/db.rs
203
src/db.rs
@ -1,36 +1,77 @@
|
|||||||
use crate::dir::Dir;
|
use crate::config;
|
||||||
use crate::types::{Epoch, Rank};
|
use crate::dir::{Dir, Epoch, Rank};
|
||||||
|
|
||||||
use anyhow::{anyhow, bail, Context, Result};
|
use anyhow::{anyhow, bail, Context, Result};
|
||||||
use std::fs::{self, File};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
use std::fs::{self, File, OpenOptions};
|
||||||
use std::io::{self, BufRead, BufReader, BufWriter};
|
use std::io::{self, BufRead, BufReader, BufWriter};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
pub use i32 as DBVersion;
|
||||||
|
|
||||||
pub struct DB {
|
pub struct DB {
|
||||||
path: PathBuf,
|
data: DBData,
|
||||||
dirs: Vec<Dir>,
|
|
||||||
modified: bool,
|
modified: bool,
|
||||||
|
path: PathBuf,
|
||||||
|
// FIXME: remove after next breaking version
|
||||||
|
path_old: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DB {
|
impl DB {
|
||||||
pub fn open<P: AsRef<Path>>(path: P) -> Result<DB> {
|
pub fn open<P: AsRef<Path>>(path: P) -> Result<DB> {
|
||||||
let path = path.as_ref().to_path_buf();
|
let data = match File::open(&path) {
|
||||||
|
|
||||||
let dirs = match File::open(&path) {
|
|
||||||
Ok(file) => {
|
Ok(file) => {
|
||||||
let reader = BufReader::new(&file);
|
let reader = BufReader::new(&file);
|
||||||
bincode::deserialize_from(reader)
|
bincode::config()
|
||||||
.with_context(|| anyhow!("could not deserialize database"))?
|
.limit(config::DB_MAX_SIZE)
|
||||||
|
.deserialize_from(reader)
|
||||||
|
.context("could not deserialize database")?
|
||||||
}
|
}
|
||||||
Err(err) => match err.kind() {
|
Err(err) => match err.kind() {
|
||||||
io::ErrorKind::NotFound => Vec::<Dir>::new(),
|
io::ErrorKind::NotFound => DBData::default(),
|
||||||
_ => return Err(err).with_context(|| anyhow!("could not open database file")),
|
_ => return Err(err).context("could not open database file"),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if data.version != config::DB_VERSION {
|
||||||
|
bail!("database version '{}' is unsupported", data.version);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(DB {
|
Ok(DB {
|
||||||
path,
|
data,
|
||||||
dirs,
|
|
||||||
modified: false,
|
modified: false,
|
||||||
|
path: path.as_ref().to_path_buf(),
|
||||||
|
path_old: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: remove after next breaking version
|
||||||
|
pub fn open_and_migrate<P1, P2>(path_old: P1, path: P2) -> Result<DB>
|
||||||
|
where
|
||||||
|
P1: AsRef<Path>,
|
||||||
|
P2: AsRef<Path>,
|
||||||
|
{
|
||||||
|
let file = File::open(&path_old).context("could not open old database file")?;
|
||||||
|
let reader = BufReader::new(&file);
|
||||||
|
|
||||||
|
let dirs = bincode::config()
|
||||||
|
.limit(config::DB_MAX_SIZE)
|
||||||
|
.deserialize_from(reader)
|
||||||
|
.context("could not deserialize old database")?;
|
||||||
|
|
||||||
|
let data = DBData {
|
||||||
|
version: config::DB_VERSION,
|
||||||
|
dirs,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(DB {
|
||||||
|
data,
|
||||||
|
modified: true,
|
||||||
|
path: path.as_ref().to_path_buf(),
|
||||||
|
path_old: Some(path_old.as_ref().to_path_buf()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,30 +79,34 @@ impl DB {
|
|||||||
if self.modified {
|
if self.modified {
|
||||||
let path_tmp = self.get_path_tmp();
|
let path_tmp = self.get_path_tmp();
|
||||||
|
|
||||||
let file_tmp = File::create(&path_tmp)
|
let file_tmp = OpenOptions::new()
|
||||||
.with_context(|| anyhow!("could not open temporary database file"))?;
|
.write(true)
|
||||||
|
.create_new(true)
|
||||||
|
.open(&path_tmp)
|
||||||
|
.context("could not open temporary database file")?;
|
||||||
|
|
||||||
let writer = BufWriter::new(&file_tmp);
|
let writer = BufWriter::new(&file_tmp);
|
||||||
bincode::serialize_into(writer, &self.dirs)
|
bincode::serialize_into(writer, &self.data).context("could not serialize database")?;
|
||||||
.with_context(|| anyhow!("could not serialize database"))?;
|
|
||||||
|
|
||||||
fs::rename(&path_tmp, &self.path)
|
if let Err(e) = fs::rename(&path_tmp, &self.path) {
|
||||||
.with_context(|| anyhow!("could not move temporary database file"))?;
|
fs::remove_file(&path_tmp)
|
||||||
|
.context("could not move or delete temporary database file")?;
|
||||||
|
return Err(e).context("could not move temporary database file");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn migrate<P: AsRef<Path>>(&mut self, path: P, merge: bool) -> Result<()> {
|
pub fn import<P: AsRef<Path>>(&mut self, path: P, merge: bool) -> Result<()> {
|
||||||
if !self.dirs.is_empty() && !merge {
|
if !self.data.dirs.is_empty() && !merge {
|
||||||
bail!(
|
bail!(
|
||||||
"To prevent conflicts, you can only migrate from z with an empty zoxide database!
|
"To prevent conflicts, you can only import from z with an empty zoxide database!\n\
|
||||||
If you wish to merge the two, specify the `--merge` flag."
|
If you wish to merge the two, specify the `--merge` flag."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let z_db_file =
|
let z_db_file = File::open(path).context("could not open z database file")?;
|
||||||
File::open(path).with_context(|| anyhow!("could not open z database file"))?;
|
|
||||||
let reader = BufReader::new(z_db_file);
|
let reader = BufReader::new(z_db_file);
|
||||||
|
|
||||||
for (idx, read_line) in reader.lines().enumerate() {
|
for (idx, read_line) in reader.lines().enumerate() {
|
||||||
@ -104,22 +149,13 @@ If you wish to merge the two, specify the `--merge` flag."
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let path_str = match path_abs.to_str() {
|
|
||||||
Some(path) => path,
|
|
||||||
None => {
|
|
||||||
eprintln!(
|
|
||||||
"invalid unicode in path '{}' at line {}",
|
|
||||||
path_abs.display(),
|
|
||||||
line_number
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if merge {
|
if merge {
|
||||||
// If the path exists in the database, add the ranks and set the epoch to
|
// If the path exists in the database, add the ranks and set the epoch to
|
||||||
// the largest of the parsed epoch and the already present epoch.
|
// the largest of the parsed epoch and the already present epoch.
|
||||||
if let Some(dir) = self.dirs.iter_mut().find(|dir| dir.path == path_str) {
|
if let Some(dir) =
|
||||||
|
self.data.dirs.iter_mut().find(|dir| dir.path == path_abs)
|
||||||
|
{
|
||||||
dir.rank += rank;
|
dir.rank += rank;
|
||||||
dir.last_accessed = Epoch::max(epoch, dir.last_accessed);
|
dir.last_accessed = Epoch::max(epoch, dir.last_accessed);
|
||||||
|
|
||||||
@ -127,10 +163,8 @@ If you wish to merge the two, specify the `--merge` flag."
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: When we switch to PathBuf for storing directories inside Dir, just
|
self.data.dirs.push(Dir {
|
||||||
// pass `PathBuf::from(path_str)`
|
path: path_abs,
|
||||||
self.dirs.push(Dir {
|
|
||||||
path: path_str.to_string(),
|
|
||||||
rank,
|
rank,
|
||||||
last_accessed: epoch,
|
last_accessed: epoch,
|
||||||
});
|
});
|
||||||
@ -154,13 +188,9 @@ If you wish to merge the two, specify the `--merge` flag."
|
|||||||
.canonicalize()
|
.canonicalize()
|
||||||
.with_context(|| anyhow!("could not access directory: {}", path.as_ref().display()))?;
|
.with_context(|| anyhow!("could not access directory: {}", path.as_ref().display()))?;
|
||||||
|
|
||||||
let path_str = path_abs
|
match self.data.dirs.iter_mut().find(|dir| dir.path == path_abs) {
|
||||||
.to_str()
|
None => self.data.dirs.push(Dir {
|
||||||
.ok_or_else(|| anyhow!("invalid unicode in path: {}", path_abs.display()))?;
|
path: path_abs,
|
||||||
|
|
||||||
match self.dirs.iter_mut().find(|dir| dir.path == path_str) {
|
|
||||||
None => self.dirs.push(Dir {
|
|
||||||
path: path_str.to_string(),
|
|
||||||
last_accessed: now,
|
last_accessed: now,
|
||||||
rank: 1.0,
|
rank: 1.0,
|
||||||
}),
|
}),
|
||||||
@ -170,43 +200,52 @@ If you wish to merge the two, specify the `--merge` flag."
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let sum_age = self.dirs.iter().map(|dir| dir.rank).sum::<Rank>();
|
let sum_age = self.data.dirs.iter().map(|dir| dir.rank).sum::<Rank>();
|
||||||
|
|
||||||
if sum_age > max_age {
|
if sum_age > max_age {
|
||||||
let factor = 0.9 * max_age / sum_age;
|
let factor = 0.9 * max_age / sum_age;
|
||||||
for dir in &mut self.dirs {
|
for dir in &mut self.data.dirs {
|
||||||
dir.rank *= factor;
|
dir.rank *= factor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.data.dirs.retain(|dir| dir.rank >= 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.dirs.retain(|dir| dir.rank >= 1.0);
|
|
||||||
self.modified = true;
|
self.modified = true;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn query(&mut self, keywords: &[String], now: Epoch) -> Option<Dir> {
|
pub fn query(&mut self, keywords: &[String], now: Epoch) -> Option<Dir> {
|
||||||
loop {
|
let (idx, dir, _) = self
|
||||||
let (idx, dir) = self
|
.data
|
||||||
.dirs
|
.dirs
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter(|(_, dir)| dir.is_match(keywords))
|
.filter(|(_, dir)| dir.is_match(&keywords))
|
||||||
.max_by_key(|(_, dir)| dir.get_frecency(now) as i64)?;
|
.map(|(idx, dir)| (idx, dir, dir.get_frecency(now)))
|
||||||
|
.max_by(|(_, _, frecency1), (_, _, frecency2)| {
|
||||||
|
frecency1.partial_cmp(frecency2).unwrap_or(Ordering::Equal)
|
||||||
|
})?;
|
||||||
|
|
||||||
if dir.is_dir() {
|
if dir.is_dir() {
|
||||||
return Some(dir.to_owned());
|
Some(dir.to_owned())
|
||||||
} else {
|
} else {
|
||||||
self.dirs.remove(idx);
|
self.data.dirs.swap_remove(idx);
|
||||||
self.modified = true;
|
self.modified = true;
|
||||||
}
|
self.query(keywords, now)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn query_all(&mut self, keywords: &[String]) -> Vec<Dir> {
|
pub fn query_all(&mut self, keywords: &[String]) -> Vec<Dir> {
|
||||||
self.remove_invalid();
|
let orig_len = self.data.dirs.len();
|
||||||
|
self.data.dirs.retain(Dir::is_dir);
|
||||||
|
|
||||||
self.dirs
|
if orig_len != self.data.dirs.len() {
|
||||||
|
self.modified = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.data
|
||||||
|
.dirs
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|dir| dir.is_match(&keywords))
|
.filter(|dir| dir.is_match(&keywords))
|
||||||
.cloned()
|
.cloned()
|
||||||
@ -219,12 +258,8 @@ If you wish to merge the two, specify the `--merge` flag."
|
|||||||
Err(_) => path.as_ref().to_path_buf(),
|
Err(_) => path.as_ref().to_path_buf(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let path_str = path_abs
|
if let Some(idx) = self.data.dirs.iter().position(|dir| dir.path == path_abs) {
|
||||||
.to_str()
|
self.data.dirs.swap_remove(idx);
|
||||||
.ok_or_else(|| anyhow!("invalid unicode in path"))?;
|
|
||||||
|
|
||||||
if let Some(idx) = self.dirs.iter().position(|dir| dir.path == path_str) {
|
|
||||||
self.dirs.remove(idx);
|
|
||||||
self.modified = true;
|
self.modified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,25 +267,39 @@ If you wish to merge the two, specify the `--merge` flag."
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_path_tmp(&self) -> PathBuf {
|
fn get_path_tmp(&self) -> PathBuf {
|
||||||
|
let file_name = format!(".{}.zo", Uuid::new_v4());
|
||||||
|
|
||||||
let mut path_tmp = self.path.clone();
|
let mut path_tmp = self.path.clone();
|
||||||
path_tmp.set_file_name(".zo.tmp");
|
path_tmp.set_file_name(file_name);
|
||||||
|
|
||||||
path_tmp
|
path_tmp
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_invalid(&mut self) {
|
|
||||||
let orig_len = self.dirs.len();
|
|
||||||
self.dirs.retain(Dir::is_dir);
|
|
||||||
|
|
||||||
if orig_len != self.dirs.len() {
|
|
||||||
self.modified = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for DB {
|
impl Drop for DB {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if let Err(e) = self.save() {
|
if let Err(e) = self.save() {
|
||||||
eprintln!("{:#}", e);
|
eprintln!("{:#}", e);
|
||||||
|
} else if let Some(path_old) = &self.path_old {
|
||||||
|
// FIXME: remove this branch after next breaking release
|
||||||
|
if let Err(e) = fs::remove_file(path_old).context("could not remove old database") {
|
||||||
|
eprintln!("{:#}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
struct DBData {
|
||||||
|
version: DBVersion,
|
||||||
|
dirs: Vec<Dir>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for DBData {
|
||||||
|
fn default() -> DBData {
|
||||||
|
DBData {
|
||||||
|
version: config::DB_VERSION,
|
||||||
|
dirs: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
44
src/dir.rs
44
src/dir.rs
@ -1,36 +1,50 @@
|
|||||||
use crate::types::{Epoch, Rank};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::path::Path;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
pub use f64 as Rank;
|
||||||
|
pub use i64 as Epoch; // use a signed integer so subtraction can be performed on it
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
||||||
pub struct Dir {
|
pub struct Dir {
|
||||||
pub path: String,
|
pub path: PathBuf,
|
||||||
pub rank: Rank,
|
pub rank: Rank,
|
||||||
pub last_accessed: Epoch,
|
pub last_accessed: Epoch,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Dir {
|
impl Dir {
|
||||||
pub fn is_dir(&self) -> bool {
|
pub fn is_dir(&self) -> bool {
|
||||||
Path::new(&self.path).is_dir()
|
self.path.is_dir()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
pub fn is_match(&self, query: &[String]) -> bool {
|
pub fn is_match(&self, query: &[String]) -> bool {
|
||||||
let path = self.path.to_ascii_lowercase();
|
use bstr::ByteSlice;
|
||||||
|
use std::os::unix::ffi::OsStrExt;
|
||||||
|
|
||||||
if let Some(query_name) = query.last().and_then(|word| Path::new(word).file_name()) {
|
let path_bytes = self.path.as_os_str().as_bytes().to_lowercase();
|
||||||
if let Some(path_name) = Path::new(&path).file_name() {
|
let mut subpath = path_bytes.as_slice();
|
||||||
// `unwrap()` here should be safe because the values are already encoded as UTF-8
|
|
||||||
let query_name = query_name.to_str().unwrap();
|
|
||||||
let path_name = path_name.to_str().unwrap();
|
|
||||||
|
|
||||||
if !path_name.contains(&query_name) {
|
for subquery in query.iter() {
|
||||||
return false;
|
let subquery_bytes = subquery.as_bytes();
|
||||||
}
|
match subpath.find(subquery_bytes) {
|
||||||
|
Some(idx) => subpath = &subpath[idx + subquery_bytes.len()..],
|
||||||
|
None => return false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut subpath = path.as_str();
|
true
|
||||||
for subquery in query {
|
}
|
||||||
|
|
||||||
|
#[cfg(not(unix))]
|
||||||
|
pub fn is_match(&self, query: &[String]) -> bool {
|
||||||
|
let path_str = match self.path.to_str() {
|
||||||
|
Some(path_str) => path_str.to_lowercase(),
|
||||||
|
None => return false, // silently ignore invalid UTF-8
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut subpath = path_str.as_str();
|
||||||
|
|
||||||
|
for subquery in query.iter() {
|
||||||
match subpath.find(subquery) {
|
match subpath.find(subquery) {
|
||||||
Some(idx) => subpath = &subpath[idx + subquery.len()..],
|
Some(idx) => subpath = &subpath[idx + subquery.len()..],
|
||||||
None => return false,
|
None => return false,
|
||||||
|
21
src/env.rs
21
src/env.rs
@ -1,21 +0,0 @@
|
|||||||
use serde::Deserialize;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
pub struct Env {
|
|
||||||
#[serde(default = "default_maxage")]
|
|
||||||
pub maxage: i64,
|
|
||||||
|
|
||||||
#[serde(default = "default_data")]
|
|
||||||
pub data: Option<PathBuf>,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn default_maxage() -> i64 {
|
|
||||||
1000
|
|
||||||
}
|
|
||||||
|
|
||||||
fn default_data() -> Option<PathBuf> {
|
|
||||||
let mut path = dirs::home_dir()?;
|
|
||||||
path.push(".zo");
|
|
||||||
Some(path)
|
|
||||||
}
|
|
19
src/main.rs
19
src/main.rs
@ -1,36 +1,31 @@
|
|||||||
|
mod config;
|
||||||
mod db;
|
mod db;
|
||||||
mod dir;
|
mod dir;
|
||||||
mod env;
|
|
||||||
mod subcommand;
|
mod subcommand;
|
||||||
mod types;
|
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
use crate::env::Env;
|
use anyhow::Result;
|
||||||
use anyhow::{Context, Result};
|
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
#[derive(Debug, StructOpt)]
|
#[derive(Debug, StructOpt)]
|
||||||
#[structopt(about = "A cd command that learns your habits")]
|
#[structopt(about = "A cd command that learns your habits")]
|
||||||
enum Zoxide {
|
enum Zoxide {
|
||||||
Add(subcommand::Add),
|
Add(subcommand::Add),
|
||||||
|
Import(subcommand::Import),
|
||||||
Init(subcommand::Init),
|
Init(subcommand::Init),
|
||||||
Migrate(subcommand::Migrate),
|
|
||||||
Query(subcommand::Query),
|
Query(subcommand::Query),
|
||||||
Remove(subcommand::Remove),
|
Remove(subcommand::Remove),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main() -> Result<()> {
|
pub fn main() -> Result<()> {
|
||||||
let opt = Zoxide::from_args();
|
let opt = Zoxide::from_args();
|
||||||
let env = envy::prefixed("_ZO_")
|
|
||||||
.from_env::<Env>()
|
|
||||||
.with_context(|| "could not parse environment variables")?;
|
|
||||||
|
|
||||||
match opt {
|
match opt {
|
||||||
Zoxide::Add(add) => add.run(&env)?,
|
Zoxide::Add(add) => add.run()?,
|
||||||
|
Zoxide::Import(import) => import.run()?,
|
||||||
Zoxide::Init(init) => init.run()?,
|
Zoxide::Init(init) => init.run()?,
|
||||||
Zoxide::Migrate(migrate) => migrate.run(&env)?,
|
Zoxide::Query(query) => query.run()?,
|
||||||
Zoxide::Query(query) => query.run(&env)?,
|
Zoxide::Remove(remove) => remove.run()?,
|
||||||
Zoxide::Remove(remove) => remove.run(&env)?,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1,29 +1,34 @@
|
|||||||
use crate::env::Env;
|
use crate::config;
|
||||||
use crate::types::Rank;
|
|
||||||
use crate::util;
|
use crate::util;
|
||||||
use anyhow::{anyhow, Context, Result};
|
|
||||||
use std::env;
|
use anyhow::{Context, Result};
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
|
use std::env;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
#[derive(Debug, StructOpt)]
|
#[derive(Debug, StructOpt)]
|
||||||
#[structopt(about = "Add a new directory or increment its rank")]
|
#[structopt(about = "Add a new directory or increment its rank")]
|
||||||
pub struct Add {
|
pub struct Add {
|
||||||
path: Option<String>,
|
path: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Add {
|
impl Add {
|
||||||
pub fn run(&self, env: &Env) -> Result<()> {
|
pub fn run(&self) -> Result<()> {
|
||||||
let mut db = util::get_db(env)?;
|
let mut db = util::get_db()?;
|
||||||
let now = util::get_current_time()?;
|
let now = util::get_current_time()?;
|
||||||
let maxage = env.maxage as Rank;
|
let maxage = config::zo_maxage()?;
|
||||||
|
let excluded_dirs = config::zo_exclude_dirs();
|
||||||
|
|
||||||
match &self.path {
|
let path = match &self.path {
|
||||||
Some(path) => db.add(path, maxage, now),
|
Some(path) => path.clone(),
|
||||||
None => {
|
None => env::current_dir().context("unable to fetch current directory")?,
|
||||||
let current_dir = env::current_dir()
|
};
|
||||||
.with_context(|| anyhow!("unable to fetch current directory"))?;
|
|
||||||
db.add(current_dir, maxage, now)
|
if excluded_dirs.contains(&path) {
|
||||||
}
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
db.add(path, maxage, now)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
21
src/subcommand/import.rs
Normal file
21
src/subcommand/import.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
use crate::util;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use structopt::StructOpt;
|
||||||
|
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
#[derive(Debug, StructOpt)]
|
||||||
|
#[structopt(about = "Import from z database")]
|
||||||
|
pub struct Import {
|
||||||
|
path: PathBuf,
|
||||||
|
|
||||||
|
#[structopt(long, help = "Merge entries into existing database")]
|
||||||
|
merge: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Import {
|
||||||
|
pub fn run(&self) -> Result<()> {
|
||||||
|
util::get_db()?.import(&self.path, self.merge)
|
||||||
|
}
|
||||||
|
}
|
@ -1,19 +0,0 @@
|
|||||||
use crate::env::Env;
|
|
||||||
use crate::util;
|
|
||||||
use anyhow::Result;
|
|
||||||
use structopt::StructOpt;
|
|
||||||
|
|
||||||
#[derive(Debug, StructOpt)]
|
|
||||||
#[structopt(about = "Migrate from z database")]
|
|
||||||
pub struct Migrate {
|
|
||||||
path: String,
|
|
||||||
|
|
||||||
#[structopt(long, help = "Merge entries into existing database")]
|
|
||||||
merge: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Migrate {
|
|
||||||
pub fn run(&self, env: &Env) -> Result<()> {
|
|
||||||
util::get_db(env)?.migrate(&self.path, self.merge)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +1,11 @@
|
|||||||
mod add;
|
mod add;
|
||||||
|
mod import;
|
||||||
mod init;
|
mod init;
|
||||||
mod migrate;
|
|
||||||
mod query;
|
mod query;
|
||||||
mod remove;
|
mod remove;
|
||||||
|
|
||||||
pub use add::Add;
|
pub use add::Add;
|
||||||
|
pub use import::Import;
|
||||||
pub use init::Init;
|
pub use init::Init;
|
||||||
pub use migrate::Migrate;
|
|
||||||
pub use query::Query;
|
pub use query::Query;
|
||||||
pub use remove::Remove;
|
pub use remove::Remove;
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
use crate::env::Env;
|
|
||||||
use crate::util;
|
use crate::util;
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use std::path::Path;
|
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
|
use std::io::{self, Write};
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
#[derive(Debug, StructOpt)]
|
#[derive(Debug, StructOpt)]
|
||||||
#[structopt(about = "Search for a directory")]
|
#[structopt(about = "Search for a directory")]
|
||||||
pub struct Query {
|
pub struct Query {
|
||||||
@ -13,49 +15,58 @@ pub struct Query {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Query {
|
impl Query {
|
||||||
pub fn run(mut self, env: &Env) -> Result<()> {
|
pub fn run(mut self) -> Result<()> {
|
||||||
let path_opt = if self.interactive {
|
let path_opt = if self.interactive {
|
||||||
self.query_interactive(env)?
|
self.query_interactive()?
|
||||||
} else {
|
} else {
|
||||||
self.query(env)?
|
self.query()?
|
||||||
};
|
};
|
||||||
|
|
||||||
match path_opt {
|
match path_opt {
|
||||||
Some(path) => println!("query: {}", path.trim()),
|
Some(path) => {
|
||||||
|
let stdout = io::stdout();
|
||||||
|
let mut handle = stdout.lock();
|
||||||
|
handle.write_all(b"query: ").unwrap();
|
||||||
|
handle.write_all(&path).unwrap();
|
||||||
|
handle.write_all(b"\n").unwrap();
|
||||||
|
}
|
||||||
None => bail!("no match found"),
|
None => bail!("no match found"),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn query(&mut self, env: &Env) -> Result<Option<String>> {
|
fn query(&mut self) -> Result<Option<Vec<u8>>> {
|
||||||
if let [path] = self.keywords.as_slice() {
|
if let [path] = self.keywords.as_slice() {
|
||||||
if Path::new(path).is_dir() {
|
if Path::new(path).is_dir() {
|
||||||
return Ok(Some(path.to_string()));
|
return Ok(Some(path.as_bytes().to_vec()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for keyword in &mut self.keywords {
|
|
||||||
keyword.make_ascii_lowercase();
|
|
||||||
}
|
|
||||||
|
|
||||||
let now = util::get_current_time()?;
|
let now = util::get_current_time()?;
|
||||||
|
|
||||||
if let Some(dir) = util::get_db(env)?.query(&self.keywords, now) {
|
for keyword in &mut self.keywords {
|
||||||
Ok(Some(dir.path))
|
*keyword = keyword.to_lowercase();
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn query_interactive(&mut self, env: &Env) -> Result<Option<String>> {
|
let path_opt = util::get_db()?.query(&self.keywords, now).map(|dir| {
|
||||||
|
// `path_to_bytes` is guaranteed to succeed here since
|
||||||
|
// the path has already been queried successfully
|
||||||
|
let path_bytes = util::path_to_bytes(&dir.path).unwrap();
|
||||||
|
path_bytes.to_vec()
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(path_opt)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn query_interactive(&mut self) -> Result<Option<Vec<u8>>> {
|
||||||
let now = util::get_current_time()?;
|
let now = util::get_current_time()?;
|
||||||
|
|
||||||
for keyword in &mut self.keywords {
|
for keyword in &mut self.keywords {
|
||||||
keyword.make_ascii_lowercase();
|
*keyword = keyword.to_lowercase();
|
||||||
}
|
}
|
||||||
|
|
||||||
let dirs = util::get_db(env)?.query_all(&self.keywords);
|
let dirs = util::get_db()?.query_all(&self.keywords);
|
||||||
util::fzf_helper(now, dirs)
|
util::fzf_helper(now, dirs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,18 @@
|
|||||||
use crate::env::Env;
|
|
||||||
use crate::util;
|
use crate::util;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
#[derive(Debug, StructOpt)]
|
#[derive(Debug, StructOpt)]
|
||||||
#[structopt(about = "Remove a directory")]
|
#[structopt(about = "Remove a directory")]
|
||||||
pub struct Remove {
|
pub struct Remove {
|
||||||
path: String,
|
path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Remove {
|
impl Remove {
|
||||||
pub fn run(&self, env: &Env) -> Result<()> {
|
pub fn run(&self) -> Result<()> {
|
||||||
util::get_db(env)?.remove(&self.path)
|
util::get_db()?.remove(&self.path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
pub use f64 as Rank;
|
|
||||||
pub use i64 as Epoch; // use a signed integer so subtraction can be performed on it
|
|
102
src/util.rs
102
src/util.rs
@ -1,36 +1,61 @@
|
|||||||
|
use crate::config;
|
||||||
use crate::db::DB;
|
use crate::db::DB;
|
||||||
use crate::dir::Dir;
|
use crate::dir::{Dir, Epoch};
|
||||||
use crate::env::Env;
|
|
||||||
use crate::types::Epoch;
|
|
||||||
use anyhow::{anyhow, bail, Context, Result};
|
use anyhow::{anyhow, bail, Context, Result};
|
||||||
|
|
||||||
|
use std::cmp::{Ordering, PartialOrd};
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
|
use std::path::Path;
|
||||||
use std::process::{Command, Stdio};
|
use std::process::{Command, Stdio};
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
|
|
||||||
pub fn get_db(env: &Env) -> Result<DB> {
|
#[cfg(unix)]
|
||||||
let path = env
|
pub fn path_to_bytes<P: AsRef<Path>>(path: &P) -> Option<&[u8]> {
|
||||||
.data
|
use std::os::unix::ffi::OsStrExt;
|
||||||
.as_ref()
|
|
||||||
.ok_or_else(|| anyhow!("could not locate database file"))?;
|
Some(path.as_ref().as_os_str().as_bytes())
|
||||||
DB::open(path)
|
}
|
||||||
|
|
||||||
|
#[cfg(not(unix))]
|
||||||
|
pub fn path_to_bytes<P: AsRef<Path>>(path: &P) -> Option<&[u8]> {
|
||||||
|
Some(path.as_ref().to_str()?.as_bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_db() -> Result<DB> {
|
||||||
|
let mut db_path = config::zo_data_dir()?;
|
||||||
|
db_path.push("db.zo");
|
||||||
|
|
||||||
|
// FIXME: fallback to old database location; remove in next breaking version
|
||||||
|
if !db_path.is_file() {
|
||||||
|
if let Some(mut old_db_path) = dirs::home_dir() {
|
||||||
|
old_db_path.push(".zo");
|
||||||
|
|
||||||
|
if old_db_path.is_file() {
|
||||||
|
return DB::open_and_migrate(old_db_path, db_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DB::open(db_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_current_time() -> Result<Epoch> {
|
pub fn get_current_time() -> Result<Epoch> {
|
||||||
let current_time = SystemTime::now()
|
let current_time = SystemTime::now()
|
||||||
.duration_since(SystemTime::UNIX_EPOCH)
|
.duration_since(SystemTime::UNIX_EPOCH)
|
||||||
.with_context(|| "system clock set to invalid time")?
|
.context("system clock set to invalid time")?
|
||||||
.as_secs();
|
.as_secs();
|
||||||
|
|
||||||
Ok(current_time as Epoch)
|
Ok(current_time as Epoch)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fzf_helper(now: Epoch, mut dirs: Vec<Dir>) -> Result<Option<String>> {
|
pub fn fzf_helper(now: Epoch, mut dirs: Vec<Dir>) -> Result<Option<Vec<u8>>> {
|
||||||
let mut fzf = Command::new("fzf")
|
let mut fzf = Command::new("fzf")
|
||||||
.arg("-n2..")
|
.arg("-n2..")
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.spawn()
|
.spawn()
|
||||||
.with_context(|| anyhow!("could not launch fzf"))?;
|
.context("could not launch fzf")?;
|
||||||
|
|
||||||
let fzf_stdin = fzf
|
let fzf_stdin = fzf
|
||||||
.stdin
|
.stdin
|
||||||
@ -41,20 +66,25 @@ pub fn fzf_helper(now: Epoch, mut dirs: Vec<Dir>) -> Result<Option<String>> {
|
|||||||
dir.rank = dir.get_frecency(now);
|
dir.rank = dir.get_frecency(now);
|
||||||
}
|
}
|
||||||
|
|
||||||
dirs.sort_by_key(|dir| std::cmp::Reverse(dir.rank as i64));
|
dirs.sort_unstable_by(|dir1, dir2| {
|
||||||
|
dir1.rank
|
||||||
|
.partial_cmp(&dir2.rank)
|
||||||
|
.unwrap_or(Ordering::Equal)
|
||||||
|
.reverse()
|
||||||
|
});
|
||||||
|
|
||||||
for dir in dirs.iter() {
|
for dir in dirs.iter() {
|
||||||
// ensure that frecency fits in 4 characters
|
// ensure that frecency fits in 4 characters
|
||||||
let frecency = if dir.rank > 9999.0 {
|
let frecency = clamp(dir.rank, 0.0, 9999.0);
|
||||||
9999
|
|
||||||
} else if dir.rank > 0.0 {
|
|
||||||
dir.rank as i32
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
writeln!(fzf_stdin, "{:>4} {}", frecency, dir.path)
|
if let Some(path_bytes) = path_to_bytes(&dir.path) {
|
||||||
.with_context(|| anyhow!("could not write into fzf stdin"))?;
|
(|| {
|
||||||
|
write!(fzf_stdin, "{:>4.0} ", frecency)?;
|
||||||
|
fzf_stdin.write_all(path_bytes)?;
|
||||||
|
fzf_stdin.write_all(b"\n")
|
||||||
|
})()
|
||||||
|
.context("could not write into fzf stdin")?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let fzf_stdout = fzf
|
let fzf_stdout = fzf
|
||||||
@ -62,17 +92,16 @@ pub fn fzf_helper(now: Epoch, mut dirs: Vec<Dir>) -> Result<Option<String>> {
|
|||||||
.as_mut()
|
.as_mut()
|
||||||
.ok_or_else(|| anyhow!("could not connect to fzf stdout"))?;
|
.ok_or_else(|| anyhow!("could not connect to fzf stdout"))?;
|
||||||
|
|
||||||
let mut output = String::new();
|
let mut buffer = Vec::new();
|
||||||
fzf_stdout
|
fzf_stdout
|
||||||
.read_to_string(&mut output)
|
.read_to_end(&mut buffer)
|
||||||
.with_context(|| anyhow!("could not read from fzf stdout"))?;
|
.context("could not read from fzf stdout")?;
|
||||||
|
|
||||||
let status = fzf.wait().with_context(|| "could not wait on fzf")?;
|
|
||||||
|
|
||||||
|
let status = fzf.wait().context("wait failed on fzf")?;
|
||||||
match status.code() {
|
match status.code() {
|
||||||
// normal exit
|
// normal exit
|
||||||
Some(0) => match output.get(12..) {
|
Some(0) => match buffer.get(12..buffer.len() - 1) {
|
||||||
Some(path) => Ok(Some(path.to_string())),
|
Some(path) => Ok(Some(path.to_vec())),
|
||||||
None => bail!("fzf returned invalid output"),
|
None => bail!("fzf returned invalid output"),
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -89,3 +118,18 @@ pub fn fzf_helper(now: Epoch, mut dirs: Vec<Dir>) -> Result<Option<String>> {
|
|||||||
_ => bail!("fzf returned an unknown error"),
|
_ => bail!("fzf returned an unknown error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: replace with f64::clamp once it is stable <https://github.com/rust-lang/rust/issues/44095>
|
||||||
|
#[must_use = "method returns a new number and does not mutate the original value"]
|
||||||
|
#[inline]
|
||||||
|
pub fn clamp(val: f64, min: f64, max: f64) -> f64 {
|
||||||
|
assert!(min <= max);
|
||||||
|
|
||||||
|
if val < min {
|
||||||
|
min
|
||||||
|
} else if val > max {
|
||||||
|
max
|
||||||
|
} else {
|
||||||
|
val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user