From 4a47da0ed488ae379f8b6b80c92d3bae62ebd7ad Mon Sep 17 00:00:00 2001
From: Ajeet D'Souza <98ajeet@gmail.com>
Date: Fri, 28 Oct 2022 18:58:07 +0530
Subject: [PATCH 01/17] Don't hide output from chpwd hooks (#474)
---
CHANGELOG.md | 1 +
templates/zsh.txt | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a8645a6..c765038 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Zsh: completions clashing with `zsh-autocomplete`.
- Fzf: 'invalid option' on macOS.
- PowerShell: handle UTF-8 encoding correctly.
+- Zsh: don't hide output from `chpwd` hooks.
## [0.8.3] - 2022-09-02
diff --git a/templates/zsh.txt b/templates/zsh.txt
index c850847..58679a9 100644
--- a/templates/zsh.txt
+++ b/templates/zsh.txt
@@ -19,7 +19,7 @@ function __zoxide_pwd() {
# cd + custom logic based on the value of _ZO_ECHO.
function __zoxide_cd() {
# shellcheck disable=SC2164
- \builtin cd -- "$@" >/dev/null {%- if echo %} && __zoxide_pwd {%- endif %}
+ \builtin cd -- "$@" {%- if echo %} && __zoxide_pwd {%- endif %}
}
{{ section }}
From 1c947110db6d6af0c6d48e0e4582548004385976 Mon Sep 17 00:00:00 2001
From: Ajeet D'Souza <98ajeet@gmail.com>
Date: Fri, 28 Oct 2022 20:20:23 +0530
Subject: [PATCH 02/17] Add Slackware to README (#475)
---
README.md | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 3a49a5c..93d7c2a 100644
--- a/README.md
+++ b/README.md
@@ -81,10 +81,11 @@ Or, you can use a package manager:
| Fedora 32+ | [Fedora Packages] | `dnf install zoxide` |
| Gentoo | [GURU Overlay] | `eselect repository enable guru`
`emerge --sync guru`
`emerge app-shells/zoxide` |
| Manjaro | | `pacman -S zoxide` |
-| NixOS | [nixpkgs] | `nix-env -iA nixpkgs.zoxide` |
+| NixOS 21.05+ | [nixpkgs] | `nix-env -iA nixpkgs.zoxide` |
| openSUSE Tumbleweed | [openSUSE Factory] | `zypper install zoxide` |
| Parrot OS | | `apt install zoxide` |
| Raspbian 11+ | [Raspbian Packages] | `apt install zoxide` |
+| Slackware 15.0+ | [SlackBuilds] | [Instructions][slackbuilds-howto] |
| Ubuntu 21.04+ | [Ubuntu Packages] | `apt install zoxide` |
| Void Linux | [Void Linux Packages] | `xbps-install -S zoxide` |
@@ -450,6 +451,7 @@ They must be set before `zoxide init` is called.
[raspbian packages]: https://archive.raspbian.org/raspbian/pool/main/r/rust-zoxide/
[releases]: https://github.com/ajeetdsouza/zoxide/releases
[scoop]: https://github.com/ScoopInstaller/Main/tree/master/bucket/zoxide.json
+[slackbuilds-howto]: https://slackbuilds.org/howto/
[telescope-zoxide]: https://github.com/jvgrootveld/telescope-zoxide
[telescope.nvim]: https://github.com/nvim-telescope/telescope.nvim
[termux]: https://github.com/termux/termux-packages/tree/master/packages/zoxide
From b7d6b1eea75d529c75368193c4db8c1a9cf84645 Mon Sep 17 00:00:00 2001
From: Elbert Ronnie <103196773+elbertronnie@users.noreply.github.com>
Date: Sat, 29 Oct 2022 19:46:10 +0530
Subject: [PATCH 03/17] Updated clap to version 4.0 (#476)
Co-authored-by: Ajeet D'Souza <98ajeet@gmail.com>
---
Cargo.lock | 59 +++++++++++++++++++++++++++------
Cargo.toml | 8 ++---
contrib/completions/zoxide.bash | 28 ++++++++--------
contrib/completions/zoxide.ts | 6 ++++
src/cmd/cmd.rs | 16 ++++-----
5 files changed, 80 insertions(+), 37 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 18ae546..7f4c021 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -131,8 +131,8 @@ checksum = "a3dbbb6653e7c55cc8595ad3e1f7be8f32aba4eb7ff7f0fd1163d4f3d137c0a9"
dependencies = [
"atty",
"bitflags",
- "clap_derive",
- "clap_lex",
+ "clap_derive 3.2.15",
+ "clap_lex 0.2.4",
"indexmap",
"once_cell",
"strsim",
@@ -141,21 +141,36 @@ dependencies = [
]
[[package]]
-name = "clap_complete"
-version = "3.2.3"
+name = "clap"
+version = "4.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ead064480dfc4880a10764488415a97fdd36a4cf1bb022d372f02e8faf8386e1"
+checksum = "335867764ed2de42325fafe6d18b8af74ba97ee0c590fa016f157535b42ab04b"
dependencies = [
- "clap",
+ "atty",
+ "bitflags",
+ "clap_derive 4.0.18",
+ "clap_lex 0.3.0",
+ "once_cell",
+ "strsim",
+ "termcolor",
+]
+
+[[package]]
+name = "clap_complete"
+version = "4.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfe581a2035db4174cdbdc91265e1aba50f381577f0510d0ad36c7bc59cc84a3"
+dependencies = [
+ "clap 4.0.18",
]
[[package]]
name = "clap_complete_fig"
-version = "3.2.4"
+version = "4.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed37b4c0c1214673eba6ad8ea31666626bf72be98ffb323067d973c48b4964b9"
+checksum = "b36d1abc7184a737efc9f589e6e783e8b56c72e71fca748cf9947ed0a6f46d44"
dependencies = [
- "clap",
+ "clap 4.0.18",
"clap_complete",
]
@@ -172,6 +187,19 @@ dependencies = [
"syn",
]
+[[package]]
+name = "clap_derive"
+version = "4.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16a1b0f6422af32d5da0c58e2703320f379216ee70198241c84173a8c5ac28f3"
+dependencies = [
+ "heck",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "clap_lex"
version = "0.2.4"
@@ -181,6 +209,15 @@ dependencies = [
"os_str_bytes",
]
+[[package]]
+name = "clap_lex"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8"
+dependencies = [
+ "os_str_bytes",
+]
+
[[package]]
name = "crossbeam-utils"
version = "0.8.11"
@@ -809,7 +846,7 @@ name = "xtask"
version = "0.1.0"
dependencies = [
"anyhow",
- "clap",
+ "clap 3.2.16",
"ignore",
"shell-words",
]
@@ -822,7 +859,7 @@ dependencies = [
"askama",
"assert_cmd",
"bincode",
- "clap",
+ "clap 4.0.18",
"clap_complete",
"clap_complete_fig",
"dirs",
diff --git a/Cargo.toml b/Cargo.toml
index 8c9c349..3d5fba3 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -22,7 +22,7 @@ members = ["xtask/"]
anyhow = "1.0.32"
askama = { version = "0.11.0", default-features = false }
bincode = "1.3.1"
-clap = { version = "3.1.0", features = ["derive"] }
+clap = { version = "4.0.0", features = ["derive"] }
dirs = "4.0.0"
dunce = "1.0.1"
fastrand = "1.7.0"
@@ -39,9 +39,9 @@ nix = { version = "0.24.1", default-features = false, features = [
which = "4.2.5"
[build-dependencies]
-clap = { version = "3.1.0", features = ["derive"] }
-clap_complete = "3.1.0"
-clap_complete_fig = "3.1.0"
+clap = { version = "4.0.0", features = ["derive"] }
+clap_complete = "4.0.0"
+clap_complete_fig = "4.0.0"
[dev-dependencies]
assert_cmd = "2.0.0"
diff --git a/contrib/completions/zoxide.bash b/contrib/completions/zoxide.bash
index 03ad7a4..f606b60 100644
--- a/contrib/completions/zoxide.bash
+++ b/contrib/completions/zoxide.bash
@@ -8,24 +8,24 @@ _zoxide() {
for i in ${COMP_WORDS[@]}
do
- case "${i}" in
- "$1")
+ case "${cmd},${i}" in
+ ",$1")
cmd="zoxide"
;;
- add)
- cmd+="__add"
+ zoxide,add)
+ cmd="zoxide__add"
;;
- import)
- cmd+="__import"
+ zoxide,import)
+ cmd="zoxide__import"
;;
- init)
- cmd+="__init"
+ zoxide,init)
+ cmd="zoxide__init"
;;
- query)
- cmd+="__query"
+ zoxide,query)
+ cmd="zoxide__query"
;;
- remove)
- cmd+="__remove"
+ zoxide,remove)
+ cmd="zoxide__remove"
;;
*)
;;
@@ -102,7 +102,7 @@ _zoxide() {
return 0
;;
zoxide__query)
- opts="-i -l -s -h -V --all --interactive --list --score --exclude --help --version ..."
+ opts="-i -l -s -h -V --all --interactive --list --score --exclude --help --version [KEYWORDS]..."
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
@@ -120,7 +120,7 @@ _zoxide() {
return 0
;;
zoxide__remove)
- opts="-i -h -V --interactive --help --version ..."
+ opts="-i -h -V --interactive --help --version [PATHS]..."
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
diff --git a/contrib/completions/zoxide.ts b/contrib/completions/zoxide.ts
index fe986b7..dd37351 100644
--- a/contrib/completions/zoxide.ts
+++ b/contrib/completions/zoxide.ts
@@ -28,6 +28,7 @@ const completion: Fig.Spec = {
{
name: "--from",
description: "Application to import from",
+ isRepeatable: true,
args: {
name: "from",
suggestions: [
@@ -61,6 +62,7 @@ const completion: Fig.Spec = {
{
name: "--cmd",
description: "Changes the prefix of the `z` and `zi` commands",
+ isRepeatable: true,
args: {
name: "cmd",
isOptional: true,
@@ -69,6 +71,7 @@ const completion: Fig.Spec = {
{
name: "--hook",
description: "Changes how often zoxide increments a directory's score",
+ isRepeatable: true,
args: {
name: "hook",
isOptional: true,
@@ -113,6 +116,7 @@ const completion: Fig.Spec = {
{
name: "--exclude",
description: "Exclude a path from results",
+ isRepeatable: true,
args: {
name: "exclude",
isOptional: true,
@@ -154,6 +158,7 @@ const completion: Fig.Spec = {
],
args: {
name: "keywords",
+ isVariadic: true,
isOptional: true,
},
},
@@ -176,6 +181,7 @@ const completion: Fig.Spec = {
],
args: {
name: "paths",
+ isVariadic: true,
isOptional: true,
template: "folders",
},
diff --git a/src/cmd/cmd.rs b/src/cmd/cmd.rs
index 59775c6..4d82991 100644
--- a/src/cmd/cmd.rs
+++ b/src/cmd/cmd.rs
@@ -2,7 +2,7 @@
use std::path::PathBuf;
-use clap::{ArgEnum, Parser, ValueHint};
+use clap::{Parser, ValueEnum, ValueHint};
const ENV_HELP: &str = "ENVIRONMENT VARIABLES:
_ZO_DATA_DIR Path for zoxide data files
@@ -33,7 +33,7 @@ pub enum Cmd {
/// Add a new directory or increment its rank
#[derive(Debug, Parser)]
pub struct Add {
- #[clap(min_values = 1, required = true, value_hint = ValueHint::DirPath)]
+ #[clap(num_args = 1.., required = true, value_hint = ValueHint::DirPath)]
pub paths: Vec,
}
@@ -44,7 +44,7 @@ pub struct Import {
pub path: PathBuf,
/// Application to import from
- #[clap(arg_enum, long)]
+ #[clap(value_enum, long)]
pub from: ImportFrom,
/// Merge into existing database
@@ -52,7 +52,7 @@ pub struct Import {
pub merge: bool,
}
-#[derive(ArgEnum, Clone, Debug)]
+#[derive(ValueEnum, Clone, Debug)]
pub enum ImportFrom {
Autojump,
Z,
@@ -61,7 +61,7 @@ pub enum ImportFrom {
/// Generate shell configuration
#[derive(Debug, Parser)]
pub struct Init {
- #[clap(arg_enum)]
+ #[clap(value_enum)]
pub shell: InitShell,
/// Prevents zoxide from defining the `z` and `zi` commands
@@ -73,18 +73,18 @@ pub struct Init {
pub cmd: String,
/// Changes how often zoxide increments a directory's score
- #[clap(arg_enum, long, default_value = "pwd")]
+ #[clap(value_enum, long, default_value = "pwd")]
pub hook: InitHook,
}
-#[derive(ArgEnum, Clone, Copy, Debug, Eq, PartialEq)]
+#[derive(ValueEnum, Clone, Copy, Debug, Eq, PartialEq)]
pub enum InitHook {
None,
Prompt,
Pwd,
}
-#[derive(ArgEnum, Clone, Debug)]
+#[derive(ValueEnum, Clone, Debug)]
pub enum InitShell {
Bash,
Elvish,
From 6210d28d5f1de82a5061b493b0c8953055bda8e6 Mon Sep 17 00:00:00 2001
From: Ajeet D'Souza <98ajeet@gmail.com>
Date: Sat, 29 Oct 2022 21:06:16 +0530
Subject: [PATCH 04/17] Remove unneeded audit (#478)
---
.cargo/audit.toml | 2 --
1 file changed, 2 deletions(-)
delete mode 100644 .cargo/audit.toml
diff --git a/.cargo/audit.toml b/.cargo/audit.toml
deleted file mode 100644
index 69f3b0f..0000000
--- a/.cargo/audit.toml
+++ /dev/null
@@ -1,2 +0,0 @@
-[advisories]
-ignore = ["RUSTSEC-2020-0095"]
From c7b8f2f01105ec66a41f88f4bf7fd8f8b8a5027a Mon Sep 17 00:00:00 2001
From: Ajeet D'Souza <98ajeet@gmail.com>
Date: Sat, 29 Oct 2022 21:28:53 +0530
Subject: [PATCH 05/17] Use workspace dependencies (#477)
---
.github/workflows/release.yml | 5 +-
Cargo.lock | 161 +++++++++++-----------------------
Cargo.toml | 58 +++++++-----
shell.nix | 2 +-
xtask/Cargo.toml | 8 +-
5 files changed, 94 insertions(+), 140 deletions(-)
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 3180683..7a1e63a 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -48,10 +48,7 @@ jobs:
- name: Get version
id: get_version
- uses: SebRollen/toml-action@v1.0.0
- with:
- file: Cargo.toml
- field: package.version
+ run: sed -En 's/^version = "(.*)"/value=\1/p' Cargo.toml >> $GITHUB_OUTPUT
- name: Install Rust
uses: actions-rs/toolchain@v1
diff --git a/Cargo.lock b/Cargo.lock
index 7f4c021..e413350 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4,18 +4,18 @@ version = 3
[[package]]
name = "aho-corasick"
-version = "0.7.18"
+version = "0.7.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
+checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e"
dependencies = [
"memchr",
]
[[package]]
name = "anyhow"
-version = "1.0.61"
+version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "508b352bb5c066aac251f6daf6b36eccd03e8a88e8081cd44959ea277a3af9a8"
+checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
[[package]]
name = "askama"
@@ -62,9 +62,9 @@ dependencies = [
[[package]]
name = "assert_cmd"
-version = "2.0.4"
+version = "2.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93ae1ddd39efd67689deb1979d80bad3bf7f2b09c6e6117c8d1f2443b5e2f83e"
+checksum = "d5c2ca00549910ec251e3bd15f87aeeb206c9456b9a77b43ff6c97c54042a472"
dependencies = [
"bstr",
"doc-comment",
@@ -123,23 +123,6 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
-[[package]]
-name = "clap"
-version = "3.2.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3dbbb6653e7c55cc8595ad3e1f7be8f32aba4eb7ff7f0fd1163d4f3d137c0a9"
-dependencies = [
- "atty",
- "bitflags",
- "clap_derive 3.2.15",
- "clap_lex 0.2.4",
- "indexmap",
- "once_cell",
- "strsim",
- "termcolor",
- "textwrap",
-]
-
[[package]]
name = "clap"
version = "4.0.18"
@@ -148,8 +131,8 @@ checksum = "335867764ed2de42325fafe6d18b8af74ba97ee0c590fa016f157535b42ab04b"
dependencies = [
"atty",
"bitflags",
- "clap_derive 4.0.18",
- "clap_lex 0.3.0",
+ "clap_derive",
+ "clap_lex",
"once_cell",
"strsim",
"termcolor",
@@ -161,7 +144,7 @@ version = "4.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfe581a2035db4174cdbdc91265e1aba50f381577f0510d0ad36c7bc59cc84a3"
dependencies = [
- "clap 4.0.18",
+ "clap",
]
[[package]]
@@ -170,23 +153,10 @@ version = "4.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b36d1abc7184a737efc9f589e6e783e8b56c72e71fca748cf9947ed0a6f46d44"
dependencies = [
- "clap 4.0.18",
+ "clap",
"clap_complete",
]
-[[package]]
-name = "clap_derive"
-version = "3.2.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ba52acd3b0a5c33aeada5cdaa3267cdc7c594a98731d4268cdc1532f4264cb4"
-dependencies = [
- "heck",
- "proc-macro-error",
- "proc-macro2",
- "quote",
- "syn",
-]
-
[[package]]
name = "clap_derive"
version = "4.0.18"
@@ -200,15 +170,6 @@ dependencies = [
"syn",
]
-[[package]]
-name = "clap_lex"
-version = "0.2.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
-dependencies = [
- "os_str_bytes",
-]
-
[[package]]
name = "clap_lex"
version = "0.3.0"
@@ -220,12 +181,11 @@ dependencies = [
[[package]]
name = "crossbeam-utils"
-version = "0.8.11"
+version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc"
+checksum = "edbafec5fa1f196ca66527c1b12c2ec4745ca14b50f1ad8f9f6f720b55d11fac"
dependencies = [
"cfg-if",
- "once_cell",
]
[[package]]
@@ -262,15 +222,15 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
[[package]]
name = "dunce"
-version = "1.0.2"
+version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "453440c271cf5577fd2a40e4942540cb7d0d2f85e27c8d07dd0023c925a67541"
+checksum = "0bd4b30a6560bbd9b4620f4de34c3f14f60848e58a9b7216801afcb4c7b31c3c"
[[package]]
name = "either"
-version = "1.7.0"
+version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be"
+checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
[[package]]
name = "fastrand"
@@ -289,9 +249,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "getrandom"
-version = "0.2.7"
+version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
+checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
dependencies = [
"cfg-if",
"libc",
@@ -317,12 +277,6 @@ dependencies = [
"regex",
]
-[[package]]
-name = "hashbrown"
-version = "0.12.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
-
[[package]]
name = "heck"
version = "0.4.0"
@@ -356,16 +310,6 @@ dependencies = [
"winapi-util",
]
-[[package]]
-name = "indexmap"
-version = "1.9.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
-dependencies = [
- "autocfg",
- "hashbrown",
-]
-
[[package]]
name = "instant"
version = "0.1.12"
@@ -377,9 +321,9 @@ dependencies = [
[[package]]
name = "itertools"
-version = "0.10.3"
+version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
+checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
dependencies = [
"either",
]
@@ -392,9 +336,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
-version = "0.2.131"
+version = "0.2.137"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04c3b4822ccebfa39c02fc03d1534441b22ead323fa0f48bb7ddd8e6ba076a40"
+checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
[[package]]
name = "log"
@@ -435,10 +379,11 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "nix"
-version = "0.24.2"
+version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "195cdbc1741b8134346d515b3a56a1c94b0912758009cfd53f99ea0f57b065fc"
+checksum = "e322c04a9e3440c327fca7b6c8a63e6890a32fa2ad689db972425f07e0d22abb"
dependencies = [
+ "autocfg",
"bitflags",
"cfg-if",
"libc",
@@ -456,15 +401,15 @@ dependencies = [
[[package]]
name = "once_cell"
-version = "1.13.0"
+version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
+checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
[[package]]
name = "os_str_bytes"
-version = "6.2.0"
+version = "6.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "648001efe5d5c0102d8cea768e348da85d90af8ba91f0bea908f157951493cd4"
+checksum = "3baf96e39c5359d2eb0dd6ccb42c62b91d9678aa68160d261b9e0ccbf9e9dea9"
[[package]]
name = "predicates"
@@ -519,9 +464,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
-version = "1.0.43"
+version = "1.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab"
+checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
dependencies = [
"unicode-ident",
]
@@ -641,24 +586,24 @@ dependencies = [
[[package]]
name = "semver"
-version = "1.0.13"
+version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93f6841e709003d68bb2deee8c343572bf446003ec20a583e76f7b15cebf3711"
+checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
[[package]]
name = "serde"
-version = "1.0.143"
+version = "1.0.147"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53e8e5d5b70924f74ff5c6d64d9a5acd91422117c60f48c4e07855238a254553"
+checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.143"
+version = "1.0.147"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3d8e8de557aee63c26b85b947f5e59b690d0454c753f3adeb5cd7835ab88391"
+checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852"
dependencies = [
"proc-macro2",
"quote",
@@ -679,9 +624,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
-version = "1.0.99"
+version = "1.0.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13"
+checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d"
dependencies = [
"proc-macro2",
"quote",
@@ -717,26 +662,20 @@ version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "507e9898683b6c43a9aa55b64259b721b52ba226e0f3779137e50ad114a4c90b"
-[[package]]
-name = "textwrap"
-version = "0.15.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
-
[[package]]
name = "thiserror"
-version = "1.0.32"
+version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f5f6586b7f764adc0231f4c79be7b920e766bb2f3e51b3661cdb263828f19994"
+checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.32"
+version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12bafc5b54507e0149cdf1b145a5d80ab80a90bcd9275df43d4fff68460f6c21"
+checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
dependencies = [
"proc-macro2",
"quote",
@@ -763,9 +702,9 @@ dependencies = [
[[package]]
name = "unicode-ident"
-version = "1.0.3"
+version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf"
+checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
[[package]]
name = "version_check"
@@ -801,13 +740,13 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "which"
-version = "4.2.5"
+version = "4.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae"
+checksum = "1c831fbbee9e129a8cf93e7747a82da9d95ba8e16621cae60ec2cdc849bacb7b"
dependencies = [
"either",
- "lazy_static",
"libc",
+ "once_cell",
]
[[package]]
@@ -846,7 +785,7 @@ name = "xtask"
version = "0.1.0"
dependencies = [
"anyhow",
- "clap 3.2.16",
+ "clap",
"ignore",
"shell-words",
]
@@ -859,7 +798,7 @@ dependencies = [
"askama",
"assert_cmd",
"bincode",
- "clap 4.0.18",
+ "clap",
"clap_complete",
"clap_complete_fig",
"dirs",
diff --git a/Cargo.toml b/Cargo.toml
index 3d5fba3..b5986a1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,7 +9,7 @@ license = "MIT"
name = "zoxide"
readme = "README.md"
repository = "https://github.com/ajeetdsouza/zoxide"
-rust-version = "1.62"
+rust-version = "1.64"
version = "0.8.3"
[badges]
@@ -18,44 +18,62 @@ maintenance = { status = "actively-developed" }
[workspace]
members = ["xtask/"]
-[dependencies]
+[workspace.dependencies]
anyhow = "1.0.32"
askama = { version = "0.11.0", default-features = false }
+assert_cmd = "2.0.0"
bincode = "1.3.1"
clap = { version = "4.0.0", features = ["derive"] }
+clap_complete = "4.0.0"
+clap_complete_fig = "4.0.0"
dirs = "4.0.0"
dunce = "1.0.1"
fastrand = "1.7.0"
glob = "0.3.0"
-serde = { version = "1.0.116", features = ["derive"] }
-
-[target.'cfg(unix)'.dependencies]
-nix = { version = "0.24.1", default-features = false, features = [
+ignore = "0.4.18"
+nix = { version = "0.25.0", default-features = false, features = [
"fs",
"user",
] }
-
-[target.'cfg(windows)'.dependencies]
-which = "4.2.5"
-
-[build-dependencies]
-clap = { version = "4.0.0", features = ["derive"] }
-clap_complete = "4.0.0"
-clap_complete_fig = "4.0.0"
-
-[dev-dependencies]
-assert_cmd = "2.0.0"
rstest = { version = "0.15.0", default-features = false }
rstest_reuse = "0.4.0"
+serde = { version = "1.0.116", features = ["derive"] }
+shell-words = "1.0.0"
tempfile = "3.1.0"
+which = "4.2.5"
+
+[dependencies]
+anyhow.workspace = true
+askama.workspace = true
+bincode.workspace = true
+clap.workspace = true
+dirs.workspace = true
+dunce.workspace = true
+fastrand.workspace = true
+glob.workspace = true
+serde.workspace = true
+
+[target.'cfg(unix)'.dependencies]
+nix.workspace = true
+
+[target.'cfg(windows)'.dependencies]
+which.workspace = true
+
+[build-dependencies]
+clap.workspace = true
+clap_complete.workspace = true
+clap_complete_fig.workspace = true
+
+[dev-dependencies]
+assert_cmd.workspace = true
+rstest.workspace = true
+rstest_reuse.workspace = true
+tempfile.workspace = true
[features]
default = []
nix-dev = []
-[profile.dev]
-debug = 0
-
[profile.release]
codegen-units = 1
debug = 0
diff --git a/shell.nix b/shell.nix
index 3c5e68c..3c85f4b 100644
--- a/shell.nix
+++ b/shell.nix
@@ -1,6 +1,6 @@
let
rust = import (builtins.fetchTarball
- "https://github.com/oxalica/rust-overlay/archive/60c2cfaa8b90ed8cebd18b214fac8682dcf222dd.tar.gz");
+ "https://github.com/oxalica/rust-overlay/archive/34d76c0a001d81a0fac342698ce7926da37b8ea5.tar.gz");
pkgs = import (builtins.fetchTarball
"https://github.com/NixOS/nixpkgs/archive/0323e1f8bac882f19905174639a89397db1930f1.tar.gz") {
overlays = [ rust ];
diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml
index b77af24..263575e 100644
--- a/xtask/Cargo.toml
+++ b/xtask/Cargo.toml
@@ -5,7 +5,7 @@ edition = "2021"
publish = false
[dependencies]
-anyhow = "1.0.32"
-clap = { version = "3.1.0", features = ["derive"] }
-ignore = "0.4.18"
-shell-words = "1.0.0"
+anyhow.workspace = true
+clap.workspace = true
+ignore.workspace = true
+shell-words.workspace = true
From d99e9b7d8671946dafe53662c519045f84d1d334 Mon Sep 17 00:00:00 2001
From: Ajeet D'Souza <98ajeet@gmail.com>
Date: Tue, 15 Nov 2022 13:47:37 +0530
Subject: [PATCH 06/17] Fix badge
---
Cargo.toml | 2 +-
README.md | 11 ++++-------
build.rs | 2 +-
shell.nix | 2 +-
src/cmd/query.rs | 6 +-----
src/cmd/remove.rs | 6 +-----
src/db/mod.rs | 6 ++----
src/shell.rs | 34 +++++++++++++++++-----------------
src/util.rs | 4 ++--
tests/completions.rs | 8 ++++----
xtask/src/main.rs | 10 +++++-----
11 files changed, 39 insertions(+), 52 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
index b5986a1..6c4d906 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,7 +9,7 @@ license = "MIT"
name = "zoxide"
readme = "README.md"
repository = "https://github.com/ajeetdsouza/zoxide"
-rust-version = "1.64"
+rust-version = "1.65"
version = "0.8.3"
[badges]
diff --git a/README.md b/README.md
index 93d7c2a..660b13f 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,6 @@
[![crates.io][crates.io-badge]][crates.io]
[![Downloads][downloads-badge]][releases]
-[![License][license-badge]][license]
[![Built with Nix][builtwithnix-badge]][builtwithnix]
zoxide is a **smarter cd command**, inspired by z and autojump.
@@ -399,7 +398,7 @@ They must be set before `zoxide init` is called.
| [nnn] | File manager | [nnn-autojump] |
| [ranger] | File manager | [ranger-zoxide] |
| [telescope.nvim] | Fuzzy finder for Neovim | [telescope-zoxide] |
-| [vim] | Text editor | [zoxide.vim] |
+| [vim] / [neovim] | Text editor | [zoxide.vim] |
| [xplr] | File manager | [zoxide.xplr] |
| [xxh] | Transports shell configuration over SSH | [xxh-plugin-prerun-zoxide] |
| [zabb] | Finds the shortest possible query for a path | Natively supported |
@@ -409,18 +408,18 @@ They must be set before `zoxide init` is called.
[algorithm-matching]: https://github.com/ajeetdsouza/zoxide/wiki/Algorithm#matching
[alpine linux packages]: https://pkgs.alpinelinux.org/packages?name=zoxide
[arch linux community]: https://archlinux.org/packages/community/x86_64/zoxide/
-[builtwithnix-badge]: https://img.shields.io/badge/builtwith-nix-7d81f7?style=flat-square
+[builtwithnix-badge]: https://img.shields.io/badge/builtwith-nix-7d81f7?logo=nixos&logoColor=white&style=flat-square
[builtwithnix]: https://builtwithnix.org/
[chocolatey]: https://community.chocolatey.org/packages/zoxide
[clink-zoxide]: https://github.com/shunsambongi/clink-zoxide
[clink]: https://github.com/mridgers/clink
[conda-forge]: https://anaconda.org/conda-forge/zoxide
[copr]: https://copr.fedorainfracloud.org/coprs/atim/zoxide/
-[crates.io-badge]: https://img.shields.io/crates/v/zoxide?style=flat-square
+[crates.io-badge]: https://img.shields.io/crates/v/zoxide?logo=rust&logoColor=white&style=flat-square
[crates.io]: https://crates.io/crates/zoxide
[debian packages]: https://packages.debian.org/stable/admin/zoxide
[devuan packages]: https://pkginfo.devuan.org/cgi-bin/package-query.html?c=package&q=zoxide
-[downloads-badge]: https://img.shields.io/endpoint?color=bright-green&label=downloads&style=flat-square&cacheSeconds=3600&url=https%3A%2F%2Fzoxide-dl-rlvir7rbe5ac.runkit.sh%2F
+[downloads-badge]: https://img.shields.io/github/downloads/ajeetdsouza/zoxide/total?logo=github&logoColor=white&style=flat-square
[dports]: https://github.com/DragonFlyBSD/DPorts/tree/master/sysutils/zoxide
[emacs]: https://www.gnu.org/software/emacs/
[fedora packages]: https://src.fedoraproject.org/rpms/rust-zoxide
@@ -436,8 +435,6 @@ They must be set before `zoxide init` is called.
[joshuto]: https://github.com/kamiyaa/joshuto
[lf]: https://github.com/gokcehan/lf
[lf-wiki]: https://github.com/gokcehan/lf/wiki/Integrations#zoxide
-[license-badge]: https://img.shields.io/github/license/ajeetdsouza/zoxide?color=lightgray&style=flat-square
-[license]: https://github.com/ajeetdsouza/zoxide/blob/main/LICENSE
[linuxbrew]: https://formulae.brew.sh/formula-linux/zoxide
[macports]: https://ports.macports.org/port/zoxide/summary
[neovim]: https://github.com/neovim/neovim
diff --git a/build.rs b/build.rs
index aa561b2..a9aa7e5 100644
--- a/build.rs
+++ b/build.rs
@@ -22,7 +22,7 @@ fn main() {
fn git_version() -> Option {
let dir = env!("CARGO_MANIFEST_DIR");
let mut git = Command::new("git");
- git.args(&["-C", dir, "describe", "--tags", "--match=v*.*.*", "--always", "--broken"]);
+ git.args(["-C", dir, "describe", "--tags", "--match=v*.*.*", "--always", "--broken"]);
let output = git.output().ok()?;
if !output.status.success() || output.stdout.is_empty() || !output.stderr.is_empty() {
diff --git a/shell.nix b/shell.nix
index 3c85f4b..47fc397 100644
--- a/shell.nix
+++ b/shell.nix
@@ -1,6 +1,6 @@
let
rust = import (builtins.fetchTarball
- "https://github.com/oxalica/rust-overlay/archive/34d76c0a001d81a0fac342698ce7926da37b8ea5.tar.gz");
+ "https://github.com/oxalica/rust-overlay/archive/2342f70f7257046effc031333c4cfdea66c91d82.tar.gz");
pkgs = import (builtins.fetchTarball
"https://github.com/NixOS/nixpkgs/archive/0323e1f8bac882f19905174639a89397db1930f1.tar.gz") {
overlays = [ rust ];
diff --git a/src/cmd/query.rs b/src/cmd/query.rs
index b6a9657..397a5b4 100644
--- a/src/cmd/query.rs
+++ b/src/cmd/query.rs
@@ -35,11 +35,7 @@ impl Query {
let stdin = fzf.stdin();
let selection = loop {
- let dir = match stream.next() {
- Some(dir) => dir,
- None => break fzf.select()?,
- };
-
+ let Some(dir) = stream.next() else { break fzf.select()? };
match writeln!(stdin, "{}", dir.display_score(now)) {
Err(e) if e.kind() == io::ErrorKind::BrokenPipe => break fzf.select()?,
result => result.context("could not write to fzf")?,
diff --git a/src/cmd/remove.rs b/src/cmd/remove.rs
index 45b1c9b..e5ed48c 100644
--- a/src/cmd/remove.rs
+++ b/src/cmd/remove.rs
@@ -22,11 +22,7 @@ impl Run for Remove {
let stdin = fzf.stdin();
let selection = loop {
- let dir = match stream.next() {
- Some(dir) => dir,
- None => break fzf.select()?,
- };
-
+ let Some(dir) = stream.next() else { break fzf.select()? };
match writeln!(stdin, "{}", dir.display_score(now)) {
Err(e) if e.kind() == io::ErrorKind::BrokenPipe => break fzf.select()?,
result => result.context("could not write to fzf")?,
diff --git a/src/db/mod.rs b/src/db/mod.rs
index cf9b54a..41db369 100644
--- a/src/db/mod.rs
+++ b/src/db/mod.rs
@@ -24,7 +24,7 @@ impl<'file> Database<'file> {
}
let buffer = self.dirs.to_bytes()?;
- let path = db_path(&self.data_dir);
+ let path = db_path(self.data_dir);
util::write(&path, &buffer).context("could not write to database")?;
self.modified = false;
Ok(())
@@ -35,13 +35,11 @@ impl<'file> Database<'file> {
let path = path.as_ref();
match self.dirs.iter_mut().find(|dir| dir.path == path) {
- None => {
- self.dirs.push(Dir { path: path.to_string().into(), last_accessed: now, rank: 1.0 });
- }
Some(dir) => {
dir.last_accessed = now;
dir.rank += 1.0;
}
+ None => self.dirs.push(Dir { path: path.to_string().into(), last_accessed: now, rank: 1.0 }),
};
self.modified = true;
diff --git a/src/shell.rs b/src/shell.rs
index 5662aa0..53a742d 100644
--- a/src/shell.rs
+++ b/src/shell.rs
@@ -57,7 +57,7 @@ mod tests {
let opts = Opts { cmd, hook, echo, resolve_symlinks };
let source = Bash(&opts).render().unwrap();
Command::new("bash")
- .args(&["--noprofile", "--norc", "-e", "-u", "-o", "pipefail", "-c", &source])
+ .args(["--noprofile", "--norc", "-e", "-u", "-o", "pipefail", "-c", &source])
.assert()
.success()
.stdout("")
@@ -70,7 +70,7 @@ mod tests {
let source = Bash(&opts).render().unwrap();
Command::new("shellcheck")
- .args(&["--enable", "all", "--shell", "bash", "-"])
+ .args(["--enable", "all", "--shell", "bash", "-"])
.write_stdin(source)
.assert()
.success()
@@ -85,7 +85,7 @@ mod tests {
source.push('\n');
Command::new("shfmt")
- .args(&["-d", "-s", "-ln", "bash", "-i", "4", "-ci", "-"])
+ .args(["-d", "-s", "-ln", "bash", "-i", "4", "-ci", "-"])
.write_stdin(source)
.assert()
.success()
@@ -105,7 +105,7 @@ mod tests {
source.push('\n');
}
- Command::new("elvish").args(&["-c", &source, "-norc"]).assert().success().stdout("").stderr("");
+ Command::new("elvish").args(["-c", &source, "-norc"]).assert().success().stdout("").stderr("");
}
#[apply(opts)]
@@ -118,7 +118,7 @@ mod tests {
Command::new("fish")
.env("HOME", tempdir)
- .args(&["--command", &source, "--private"])
+ .args(["--command", &source, "--no-config", "--private"])
.assert()
.success()
.stdout("")
@@ -152,7 +152,7 @@ mod tests {
let tempdir = tempdir.path();
let assert =
- Command::new("nu").env("HOME", tempdir).args(&["--commands", &source]).assert().success().stderr("");
+ Command::new("nu").env("HOME", tempdir).args(["--commands", &source]).assert().success().stderr("");
if opts.hook != InitHook::Pwd {
assert.stdout("");
@@ -165,7 +165,7 @@ mod tests {
let source = Posix(&opts).render().unwrap();
let assert = Command::new("bash")
- .args(&["--posix", "--noprofile", "--norc", "-e", "-u", "-o", "pipefail", "-c", &source])
+ .args(["--posix", "--noprofile", "--norc", "-e", "-u", "-o", "pipefail", "-c", &source])
.assert()
.success()
.stderr("");
@@ -179,7 +179,7 @@ mod tests {
let opts = Opts { cmd, hook, echo, resolve_symlinks };
let source = Posix(&opts).render().unwrap();
- let assert = Command::new("dash").args(&["-e", "-u", "-c", &source]).assert().success().stderr("");
+ let assert = Command::new("dash").args(["-e", "-u", "-c", &source]).assert().success().stderr("");
if opts.hook != InitHook::Pwd {
assert.stdout("");
}
@@ -191,7 +191,7 @@ mod tests {
let source = Posix(&opts).render().unwrap();
Command::new("shellcheck")
- .args(&["--enable", "all", "--shell", "sh", "-"])
+ .args(["--enable", "all", "--shell", "sh", "-"])
.write_stdin(source)
.assert()
.success()
@@ -206,7 +206,7 @@ mod tests {
source.push('\n');
Command::new("shfmt")
- .args(&["-d", "-s", "-ln", "posix", "-i", "4", "-ci", "-"])
+ .args(["-d", "-s", "-ln", "posix", "-i", "4", "-ci", "-"])
.write_stdin(source)
.assert()
.success()
@@ -221,7 +221,7 @@ mod tests {
Powershell(&opts).render_into(&mut source).unwrap();
Command::new("pwsh")
- .args(&["-NoLogo", "-NonInteractive", "-NoProfile", "-Command", &source])
+ .args(["-NoLogo", "-NonInteractive", "-NoProfile", "-Command", &source])
.assert()
.success()
.stdout("")
@@ -234,7 +234,7 @@ mod tests {
let mut source = Xonsh(&opts).render().unwrap();
source.push('\n');
- Command::new("black").args(&["--check", "--diff", "-"]).write_stdin(source).assert().success().stdout("");
+ Command::new("black").args(["--check", "--diff", "-"]).write_stdin(source).assert().success().stdout("");
}
#[apply(opts)]
@@ -242,7 +242,7 @@ mod tests {
let opts = Opts { cmd, hook, echo, resolve_symlinks };
let source = Xonsh(&opts).render().unwrap();
- Command::new("mypy").args(&["--command", &source, "--strict"]).assert().success().stderr("");
+ Command::new("mypy").args(["--command", &source, "--strict"]).assert().success().stderr("");
}
#[apply(opts)]
@@ -252,7 +252,7 @@ mod tests {
source.push('\n');
Command::new("pylint")
- .args(&["--from-stdin", "--persistent=n", "zoxide"])
+ .args(["--from-stdin", "--persistent=n", "zoxide"])
.write_stdin(source)
.assert()
.success()
@@ -268,7 +268,7 @@ mod tests {
let tempdir = tempdir.path().to_str().unwrap();
Command::new("xonsh")
- .args(&["-c", &source, "--no-rc"])
+ .args(["-c", &source, "--no-rc"])
.env("HOME", tempdir)
.assert()
.success()
@@ -283,7 +283,7 @@ mod tests {
// ShellCheck doesn't support zsh yet: https://github.com/koalaman/shellcheck/issues/809
Command::new("shellcheck")
- .args(&["--enable", "all", "--shell", "bash", "-"])
+ .args(["--enable", "all", "--shell", "bash", "-"])
.write_stdin(source)
.assert()
.success()
@@ -297,7 +297,7 @@ mod tests {
let source = Zsh(&opts).render().unwrap();
Command::new("zsh")
- .args(&["-e", "-u", "-o", "pipefail", "--no-globalrcs", "--no-rcs", "-c", &source])
+ .args(["-e", "-u", "-o", "pipefail", "--no-globalrcs", "--no-rcs", "-c", &source])
.assert()
.success()
.stdout("")
diff --git a/src/util.rs b/src/util.rs
index d73e2cd..8c4c300 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -36,7 +36,7 @@ impl Fzf {
if let Some(fzf_opts) = config::fzf_opts() {
command.env("FZF_DEFAULT_OPTS", fzf_opts);
} else {
- command.args(&[
+ command.args([
// Search result
"--no-sort",
// Interface
@@ -58,7 +58,7 @@ impl Fzf {
} else {
r"\command -p ls -Cp {2..}"
};
- command.args(&["--preview", PREVIEW_CMD, "--preview-window=down,30%"]).env("SHELL", "sh");
+ command.args(["--preview", PREVIEW_CMD, "--preview-window=down,30%"]).env("SHELL", "sh");
}
}
diff --git a/tests/completions.rs b/tests/completions.rs
index 881242c..d122eb5 100644
--- a/tests/completions.rs
+++ b/tests/completions.rs
@@ -6,7 +6,7 @@ use assert_cmd::Command;
#[test]
fn completions_bash() {
let source = include_str!("../contrib/completions/zoxide.bash");
- Command::new("bash").args(&["--noprofile", "--norc", "-c", source]).assert().success().stdout("").stderr("");
+ Command::new("bash").args(["--noprofile", "--norc", "-c", source]).assert().success().stdout("").stderr("");
}
// Elvish: the completions file uses editor commands to add completions to the shell. However,
@@ -21,7 +21,7 @@ fn completions_fish() {
Command::new("fish")
.env("HOME", tempdir)
- .args(&["--command", source, "--private"])
+ .args(["--command", source, "--private"])
.assert()
.success()
.stdout("")
@@ -32,7 +32,7 @@ fn completions_fish() {
fn completions_powershell() {
let source = include_str!("../contrib/completions/_zoxide.ps1");
Command::new("pwsh")
- .args(&["-NoLogo", "-NonInteractive", "-NoProfile", "-Command", source])
+ .args(["-NoLogo", "-NonInteractive", "-NoProfile", "-Command", source])
.assert()
.success()
.stdout("")
@@ -50,5 +50,5 @@ fn completions_zsh() {
compinit -u
"#;
- Command::new("zsh").args(&["-c", source, "--no-rcs"]).assert().success().stdout("").stderr("");
+ Command::new("zsh").args(["-c", source, "--no-rcs"]).assert().success().stdout("").stderr("");
}
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
index 424f363..fba3c65 100644
--- a/xtask/src/main.rs
+++ b/xtask/src/main.rs
@@ -55,7 +55,7 @@ impl CommandExt for &mut Command {
fn run_ci(nix_enabled: bool) -> Result<()> {
// Run cargo-clippy.
- Command::new("cargo").args(&["clippy", "--all-features", "--all-targets"]).args(&["--", "-Dwarnings"]).run()?;
+ Command::new("cargo").args(["clippy", "--all-features", "--all-targets"]).args(["--", "-Dwarnings"]).run()?;
run_fmt(nix_enabled, true)?;
run_lint(nix_enabled)?;
run_tests(nix_enabled, "")
@@ -84,7 +84,7 @@ fn run_fmt(nix_enabled: bool, check: bool) -> Result<()> {
fn run_lint(nix_enabled: bool) -> Result<()> {
if nix_enabled {
// Run cargo-audit.
- Command::new("cargo").args(&["audit", "--deny=warnings"]).run()?;
+ Command::new("cargo").args(["audit", "--deny=warnings"]).run()?;
// Run markdownlint.
for result in Walk::new("./") {
@@ -100,7 +100,7 @@ fn run_lint(nix_enabled: bool) -> Result<()> {
let entry = result.unwrap();
let path = entry.path();
if path.is_file() && path.extension() == Some(OsStr::new("1")) {
- Command::new("mandoc").args(&["-man", "-Wall", "-Tlint", "--"]).arg(path).run()?;
+ Command::new("mandoc").args(["-man", "-Wall", "-Tlint", "--"]).arg(path).run()?;
}
}
}
@@ -110,7 +110,7 @@ fn run_lint(nix_enabled: bool) -> Result<()> {
fn run_tests(nix_enabled: bool, name: &str) -> Result<()> {
let args: &[&str] = if nix_enabled { &["nextest", "run", "--all-features"] } else { &["test"] };
- Command::new("cargo").args(args).args(&["--no-fail-fast", "--workspace", "--", name]).run()
+ Command::new("cargo").args(args).args(["--no-fail-fast", "--workspace", "--", name]).run()
}
fn enable_nix() -> bool {
@@ -131,6 +131,6 @@ fn enable_nix() -> bool {
let args = env::args();
let cmd = shell_words::join(args);
- let status = Command::new("nix-shell").args(&["--pure", "--run", &cmd, "--", "shell.nix"]).status().unwrap();
+ let status = Command::new("nix-shell").args(["--pure", "--run", &cmd, "--", "shell.nix"]).status().unwrap();
process::exit(status.code().unwrap_or(1));
}
From f74873b80317cc5079ac44d9e72b5974bdaa9b16 Mon Sep 17 00:00:00 2001
From: Ajeet D'Souza <98ajeet@gmail.com>
Date: Wed, 7 Dec 2022 17:28:33 +0530
Subject: [PATCH 07/17] Improve help page consistency
---
shell.nix | 1 -
src/cmd/cmd.rs | 14 +++++++-------
xtask/src/main.rs | 3 ---
3 files changed, 7 insertions(+), 11 deletions(-)
diff --git a/shell.nix b/shell.nix
index 47fc397..e22aef8 100644
--- a/shell.nix
+++ b/shell.nix
@@ -21,7 +21,6 @@ in pkgs.mkShell {
pkgs.zsh
# Tools
- pkgs.cargo-audit
pkgs.cargo-nextest
pkgs.mandoc
pkgs.nixfmt
diff --git a/src/cmd/cmd.rs b/src/cmd/cmd.rs
index 4d82991..c22a283 100644
--- a/src/cmd/cmd.rs
+++ b/src/cmd/cmd.rs
@@ -4,13 +4,13 @@ use std::path::PathBuf;
use clap::{Parser, ValueEnum, ValueHint};
-const ENV_HELP: &str = "ENVIRONMENT VARIABLES:
- _ZO_DATA_DIR Path for zoxide data files
- _ZO_ECHO Print the matched directory before navigating to it when set to 1
- _ZO_EXCLUDE_DIRS List of directory globs to be excluded
- _ZO_FZF_OPTS Custom flags to pass to fzf
- _ZO_MAXAGE Maximum total age after which entries start getting deleted
- _ZO_RESOLVE_SYMLINKS Resolve symlinks when storing paths";
+const ENV_HELP: &str = "Environment variables:
+ _ZO_DATA_DIR Path for zoxide data files
+ _ZO_ECHO Print the matched directory before navigating to it when set to 1
+ _ZO_EXCLUDE_DIRS List of directory globs to be excluded
+ _ZO_FZF_OPTS Custom flags to pass to fzf
+ _ZO_MAXAGE Maximum total age after which entries start getting deleted
+ _ZO_RESOLVE_SYMLINKS Resolve symlinks when storing paths";
#[derive(Debug, Parser)]
#[clap(
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
index fba3c65..ab99020 100644
--- a/xtask/src/main.rs
+++ b/xtask/src/main.rs
@@ -83,9 +83,6 @@ fn run_fmt(nix_enabled: bool, check: bool) -> Result<()> {
fn run_lint(nix_enabled: bool) -> Result<()> {
if nix_enabled {
- // Run cargo-audit.
- Command::new("cargo").args(["audit", "--deny=warnings"]).run()?;
-
// Run markdownlint.
for result in Walk::new("./") {
let entry = result.unwrap();
From e8c5f7a97523be5c14d98894a2c29d8965993a78 Mon Sep 17 00:00:00 2001
From: Ajeet D'Souza <98ajeet@gmail.com>
Date: Thu, 8 Dec 2022 23:24:43 +0530
Subject: [PATCH 08/17] Upgrade Nushell to v0.73.0 (#495)
---
CHANGELOG.md | 1 +
README.md | 4 ++--
man/man1/zoxide-init.1 | 4 ++--
templates/nushell.txt | 6 +++---
4 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c765038..c6c5e3c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fzf: 'invalid option' on macOS.
- PowerShell: handle UTF-8 encoding correctly.
- Zsh: don't hide output from `chpwd` hooks.
+- Nushell: upgrade minimum supported version to v0.73.0.
## [0.8.3] - 2022-09-02
diff --git a/README.md b/README.md
index 660b13f..2d65d42 100644
--- a/README.md
+++ b/README.md
@@ -204,7 +204,7 @@ zoxide init fish | source
Add this to your env file (find it by running `$nu.env-path` in Nushell):
```sh
-zoxide init nushell | save ~/.zoxide.nu
+zoxide init nushell | save -f ~/.zoxide.nu
```
Now, add this to the end of your config file (find it by running
@@ -215,7 +215,7 @@ source ~/.zoxide.nu
```
> **Note**
-> zoxide only supports Nushell v0.63.0 and above.
+> zoxide only supports Nushell v0.73.0 and above.
diff --git a/man/man1/zoxide-init.1 b/man/man1/zoxide-init.1
index 996e72c..0d7f51b 100644
--- a/man/man1/zoxide-init.1
+++ b/man/man1/zoxide-init.1
@@ -35,7 +35,7 @@ Note: zoxide only supports fish v3.4.0 and above.
Add this to your env file (find it by running \fB$nu.env-path\fR in Nushell):
.sp
.nf
- \fBzoxide init nushell --hook prompt | save ~/.zoxide.nu\fR
+ \fBzoxide init nushell --hook prompt | save -f ~/.zoxide.nu\fR
.fi
.sp
Now, add this to the end of your config file (find it by running
@@ -45,7 +45,7 @@ Now, add this to the end of your config file (find it by running
\fBsource ~/.zoxide.nu\fR
.fi
.sp
-Note: zoxide only supports Nushell v0.63.0 and above.
+Note: zoxide only supports Nushell v0.73.0 and above.
.TP
.B powershell
Add this to your configuration (find it by running \fBecho $profile\fR in
diff --git a/templates/nushell.txt b/templates/nushell.txt
index 7576e6c..df39c29 100644
--- a/templates/nushell.txt
+++ b/templates/nushell.txt
@@ -39,7 +39,7 @@ let-env config = ($env.config | update hooks.env_change.PWD ($env.config.hooks.e
def-env __zoxide_z [...rest:string] {
# `z -` does not work yet, see https://github.com/nushell/nushell/issues/4769
let arg0 = ($rest | append '~').0
- let path = if (($rest | length) <= 1) && ($arg0 == '-' || ($arg0 | path expand | path type) == dir) {
+ let path = if (($rest | length) <= 1) and ($arg0 == '-' or ($arg0 | path expand | path type) == dir) {
$arg0
} else {
(zoxide query --exclude $env.PWD -- $rest | str trim -r -c "\n")
@@ -77,11 +77,11 @@ alias {{cmd}}i = __zoxide_zi
{{ section }}
# Add this to your env file (find it by running `$nu.env-path` in Nushell):
#
-# zoxide init nushell --hook prompt | save ~/.zoxide.nu
+# zoxide init nushell --hook prompt | save -f ~/.zoxide.nu
#
# Now, add this to the end of your config file (find it by running
# `$nu.config-path` in Nushell):
#
# source ~/.zoxide.nu
#
-# Note: zoxide only supports Nushell v0.63.0 and above.
+# Note: zoxide only supports Nushell v0.73.0 and above.
From 82d4f73aae39ab2f85e1fe688fafbe90bd64b086 Mon Sep 17 00:00:00 2001
From: Ajeet D'Souza <98ajeet@gmail.com>
Date: Fri, 9 Dec 2022 01:35:13 +0530
Subject: [PATCH 09/17] Use tab to cycle through completions (#496)
---
CHANGELOG.md | 2 ++
src/util.rs | 5 ++++-
templates/zsh.txt | 6 +-----
3 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c6c5e3c..a101954 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- PowerShell: handle UTF-8 encoding correctly.
- Zsh: don't hide output from `chpwd` hooks.
- Nushell: upgrade minimum supported version to v0.73.0.
+- Zsh: fix extra space in interactive completions when no match is found.
+- Fzf: `` now cycles through completions.
## [0.8.3] - 2022-09-02
diff --git a/src/util.rs b/src/util.rs
index 8c4c300..2476e7e 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -30,7 +30,9 @@ impl Fzf {
#[cfg(not(windows))]
let mut command = Command::new("fzf");
if multiple {
- command.arg("-m");
+ command.arg("--multi");
+ } else {
+ command.arg("--bind=tab:down,btab:up");
}
command.arg("--nth=2..").stdin(Stdio::piped()).stdout(Stdio::piped());
if let Some(fzf_opts) = config::fzf_opts() {
@@ -40,6 +42,7 @@ impl Fzf {
// Search result
"--no-sort",
// Interface
+ "--cycle",
"--keep-right",
// Layout
"--height=50%",
diff --git a/templates/zsh.txt b/templates/zsh.txt
index 58679a9..1e0e132 100644
--- a/templates/zsh.txt
+++ b/templates/zsh.txt
@@ -112,11 +112,7 @@ if [[ -o zle ]]; then
# shellcheck disable=SC2296
compadd -Q "${(q-)result}"
else
-{#-
- zsh-autocomplete calls the completion function multiple times if no match is
- returned.
-#}
- compadd ""
+ return 0
fi
\builtin printf '\e[5n'
fi
From 7af4da1dabfcfc9a4b23cc8807150bf2f61a0df6 Mon Sep 17 00:00:00 2001
From: Ajeet D'Souza <98ajeet@gmail.com>
Date: Fri, 9 Dec 2022 01:36:32 +0530
Subject: [PATCH 10/17] fzf: enable colors in preview when possible on macOS /
BSD
---
CHANGELOG.md | 1 +
src/util.rs | 6 +++++-
templates/zsh.txt | 7 +++----
3 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a101954..f8d9010 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Nushell: upgrade minimum supported version to v0.73.0.
- Zsh: fix extra space in interactive completions when no match is found.
- Fzf: `` now cycles through completions.
+- Fzf: enable colors in preview when possible on macOS / BSD.
## [0.8.3] - 2022-09-02
diff --git a/src/util.rs b/src/util.rs
index 2476e7e..9e4cef7 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -61,7 +61,11 @@ impl Fzf {
} else {
r"\command -p ls -Cp {2..}"
};
- command.args(["--preview", PREVIEW_CMD, "--preview-window=down,30%"]).env("SHELL", "sh");
+ command.args(["--preview", PREVIEW_CMD, "--preview-window=down,30%"]).envs([
+ ("CLICOLOR", "1"),
+ ("CLICOLOR_FORCE", "1"),
+ ("SHELL", "sh"),
+ ]);
}
}
diff --git a/templates/zsh.txt b/templates/zsh.txt
index 1e0e132..cfa9bb1 100644
--- a/templates/zsh.txt
+++ b/templates/zsh.txt
@@ -100,7 +100,7 @@ if [[ -o zle ]]; then
function __zoxide_z_complete() {
# Only show completions when the cursor is at the end of the line.
# shellcheck disable=SC2154
- [[ "{{ "${#words[@]}" }}" -eq "${CURRENT}" ]] || return
+ [[ "{{ "${#words[@]}" }}" -eq "${CURRENT}" ]] || return 0
if [[ "{{ "${#words[@]}" }}" -eq 2 ]]; then
_files -/
@@ -111,14 +111,13 @@ if [[ -o zle ]]; then
result="${__zoxide_z_prefix}${result}"
# shellcheck disable=SC2296
compadd -Q "${(q-)result}"
- else
- return 0
fi
\builtin printf '\e[5n'
fi
+ return 0
}
- \builtin bindkey "\e[0n" 'reset-prompt'
+ \builtin bindkey '\e[0n' 'reset-prompt'
if [[ "${+functions[compdef]}" -ne 0 ]]; then
\compdef -d {{cmd}}
\compdef -d {{cmd}}i
From cf0c9c002e3c5eabb40016a14d49e40da9e3edc4 Mon Sep 17 00:00:00 2001
From: Ajeet D'Souza <98ajeet@gmail.com>
Date: Sat, 7 Jan 2023 01:31:49 +0530
Subject: [PATCH 11/17] Add no response workflow
---
.github/workflows/ci.yml | 7 +------
.github/workflows/no-response.yml | 22 ++++++++++++++++++++++
.github/workflows/release.yml | 6 +-----
shell.nix | 4 ++--
src/db/mod.rs | 2 +-
5 files changed, 27 insertions(+), 14 deletions(-)
create mode 100644 .github/workflows/no-response.yml
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 9c0972b..cb15ac9 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,24 +1,19 @@
name: ci
on:
push:
- branches:
- - main
- - next
+ branches: [main]
pull_request:
workflow_dispatch:
-
env:
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
CARGO_INCREMENTAL: 0
CARGO_TERM_COLOR: always
-
jobs:
ci:
name: ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
- # FIXME: Enable macos-latest when this is merged: https://nixpk.gs/pr-tracker.html?pr=163924
os: [ubuntu-latest, windows-latest]
steps:
- uses: actions/checkout@v2
diff --git a/.github/workflows/no-response.yml b/.github/workflows/no-response.yml
new file mode 100644
index 0000000..b73a46c
--- /dev/null
+++ b/.github/workflows/no-response.yml
@@ -0,0 +1,22 @@
+name: no-response
+on:
+ issue_comment:
+ types: [created]
+ schedule:
+ - cron: "0 0 * * *" # daily at 00:00
+permissions:
+ issues: write
+jobs:
+ no-response:
+ if: github.repository == 'ajeetdsouza/zoxide'
+ runs-on: ubuntu-latest
+ steps:
+ - uses: lee-dohm/no-response@v0.5.0
+ with:
+ token: ${{ github.token }}
+ daysUntilClose: 30
+ responseRequiredLabel: waiting-for-response
+ closeComment: >
+ This issue has been automatically closed due to inactivity. If you
+ feel this is still relevant, please comment here or create a fresh
+ issue.
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 7a1e63a..4ca6aae 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -1,15 +1,11 @@
name: release
on:
push:
- branches:
- - main
- - next
+ branches: [main]
pull_request:
workflow_dispatch:
-
env:
CARGO_INCREMENTAL: 0
-
jobs:
release:
name: ${{ matrix.target }}
diff --git a/shell.nix b/shell.nix
index e22aef8..689a4b1 100644
--- a/shell.nix
+++ b/shell.nix
@@ -1,8 +1,8 @@
let
rust = import (builtins.fetchTarball
- "https://github.com/oxalica/rust-overlay/archive/2342f70f7257046effc031333c4cfdea66c91d82.tar.gz");
+ "https://github.com/oxalica/rust-overlay/archive/9096306d4a1c3adcc8d20f2c9dcaee3dee30d1ad.tar.gz");
pkgs = import (builtins.fetchTarball
- "https://github.com/NixOS/nixpkgs/archive/0323e1f8bac882f19905174639a89397db1930f1.tar.gz") {
+ "https://github.com/NixOS/nixpkgs/archive/5f902ae769594aaeaf326e8623a48482eeacfe89.tar.gz") {
overlays = [ rust ];
};
in pkgs.mkShell {
diff --git a/src/db/mod.rs b/src/db/mod.rs
index 41db369..12f6475 100644
--- a/src/db/mod.rs
+++ b/src/db/mod.rs
@@ -25,7 +25,7 @@ impl<'file> Database<'file> {
let buffer = self.dirs.to_bytes()?;
let path = db_path(self.data_dir);
- util::write(&path, &buffer).context("could not write to database")?;
+ util::write(path, buffer).context("could not write to database")?;
self.modified = false;
Ok(())
}
From 3ab0a7b8fd8dca9c287745fe3cb72ae264205e34 Mon Sep 17 00:00:00 2001
From: Ajeet D'Souza <98ajeet@gmail.com>
Date: Sat, 7 Jan 2023 22:58:10 +0530
Subject: [PATCH 12/17] Edit subcommand (#498)
---
CHANGELOG.md | 12 +-
Cargo.lock | 343 ++++++++++++++++++++++---------
Cargo.toml | 6 +-
contrib/completions/_zoxide | 88 +++++++-
contrib/completions/_zoxide.ps1 | 42 +++-
contrib/completions/zoxide.bash | 89 +++++++-
contrib/completions/zoxide.elv | 37 +++-
contrib/completions/zoxide.fish | 16 +-
contrib/completions/zoxide.ts | 85 +++++++-
man/man1/zoxide-init.1 | 2 +-
rustfmt.toml | 1 -
src/cmd/add.rs | 16 +-
src/cmd/cmd.rs | 25 ++-
src/cmd/edit.rs | 83 ++++++++
src/cmd/import.rs | 109 +++++-----
src/cmd/init.rs | 2 -
src/cmd/mod.rs | 2 +
src/cmd/query.rs | 111 ++++++----
src/cmd/remove.rs | 51 +----
src/db/dir.rs | 151 +++-----------
src/db/mod.rs | 354 +++++++++++++++++++-------------
src/db/stream.rs | 33 ++-
src/util.rs | 203 +++++++++++-------
templates/nushell.txt | 31 +--
24 files changed, 1248 insertions(+), 644 deletions(-)
create mode 100644 src/cmd/edit.rs
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f8d9010..ae496c3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
+### Added
+
+- `edit` subcommand to adjust the scores of entries.
+
### Fixed
- Zsh: completions clashing with `zsh-autocomplete`.
@@ -17,8 +21,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Zsh: don't hide output from `chpwd` hooks.
- Nushell: upgrade minimum supported version to v0.73.0.
- Zsh: fix extra space in interactive completions when no match is found.
-- Fzf: `` now cycles through completions.
-- Fzf: enable colors in preview when possible on macOS / BSD.
+- Fzf: various improvements.
+- Nushell: Accidental redefinition of hooks when initialized twice.
+
+### Removed
+
+- `remove -i` subcommand: use `edit` instead.
## [0.8.3] - 2022-09-02
diff --git a/Cargo.lock b/Cargo.lock
index e413350..8df0463 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3,19 +3,31 @@
version = 3
[[package]]
-name = "aho-corasick"
-version = "0.7.19"
+name = "Inflector"
+version = "0.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e"
+checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
+
+[[package]]
+name = "aho-corasick"
+version = "0.7.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
dependencies = [
"memchr",
]
[[package]]
-name = "anyhow"
-version = "1.0.66"
+name = "aliasable"
+version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
+checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd"
+
+[[package]]
+name = "anyhow"
+version = "1.0.68"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61"
[[package]]
name = "askama"
@@ -62,9 +74,9 @@ dependencies = [
[[package]]
name = "assert_cmd"
-version = "2.0.5"
+version = "2.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d5c2ca00549910ec251e3bd15f87aeeb206c9456b9a77b43ff6c97c54042a472"
+checksum = "fa3d466004a8b4cb1bc34044240a2fd29d17607e2e3bd613eb44fd48e8100da3"
dependencies = [
"bstr",
"doc-comment",
@@ -74,23 +86,6 @@ dependencies = [
"wait-timeout",
]
-[[package]]
-name = "atty"
-version = "0.2.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
-dependencies = [
- "hermit-abi",
- "libc",
- "winapi",
-]
-
-[[package]]
-name = "autocfg"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
-
[[package]]
name = "bincode"
version = "1.3.3"
@@ -108,15 +103,22 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bstr"
-version = "0.2.17"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
+checksum = "b45ea9b00a7b3f2988e9a65ad3917e62123c38dba709b666506207be96d1790b"
dependencies = [
- "lazy_static",
"memchr",
+ "once_cell",
"regex-automata",
+ "serde",
]
+[[package]]
+name = "cc"
+version = "1.0.78"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d"
+
[[package]]
name = "cfg-if"
version = "1.0.0"
@@ -125,14 +127,14 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
-version = "4.0.18"
+version = "4.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "335867764ed2de42325fafe6d18b8af74ba97ee0c590fa016f157535b42ab04b"
+checksum = "a7db700bc935f9e43e88d00b0850dae18a63773cfbec6d8e070fccf7fef89a39"
dependencies = [
- "atty",
"bitflags",
"clap_derive",
"clap_lex",
+ "is-terminal",
"once_cell",
"strsim",
"termcolor",
@@ -140,18 +142,18 @@ dependencies = [
[[package]]
name = "clap_complete"
-version = "4.0.3"
+version = "4.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dfe581a2035db4174cdbdc91265e1aba50f381577f0510d0ad36c7bc59cc84a3"
+checksum = "10861370d2ba66b0f5989f83ebf35db6421713fd92351790e7fdd6c36774c56b"
dependencies = [
"clap",
]
[[package]]
name = "clap_complete_fig"
-version = "4.0.1"
+version = "4.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b36d1abc7184a737efc9f589e6e783e8b56c72e71fca748cf9947ed0a6f46d44"
+checksum = "46b30e010e669cd021e5004f3be26cff6b7c08d2a8a0d65b48d43a8cc0efd6c3"
dependencies = [
"clap",
"clap_complete",
@@ -159,9 +161,9 @@ dependencies = [
[[package]]
name = "clap_derive"
-version = "4.0.18"
+version = "4.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "16a1b0f6422af32d5da0c58e2703320f379216ee70198241c84173a8c5ac28f3"
+checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014"
dependencies = [
"heck",
"proc-macro-error",
@@ -179,15 +181,6 @@ dependencies = [
"os_str_bytes",
]
-[[package]]
-name = "crossbeam-utils"
-version = "0.8.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "edbafec5fa1f196ca66527c1b12c2ec4745ca14b50f1ad8f9f6f720b55d11fac"
-dependencies = [
- "cfg-if",
-]
-
[[package]]
name = "difflib"
version = "0.4.0"
@@ -232,6 +225,27 @@ version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
+[[package]]
+name = "errno"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
+dependencies = [
+ "errno-dragonfly",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "errno-dragonfly"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
+dependencies = [
+ "cc",
+ "libc",
+]
+
[[package]]
name = "fastrand"
version = "1.8.0"
@@ -260,15 +274,15 @@ dependencies = [
[[package]]
name = "glob"
-version = "0.3.0"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
+checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]]
name = "globset"
-version = "0.4.9"
+version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a"
+checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc"
dependencies = [
"aho-corasick",
"bstr",
@@ -285,20 +299,19 @@ checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
[[package]]
name = "hermit-abi"
-version = "0.1.19"
+version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
dependencies = [
"libc",
]
[[package]]
name = "ignore"
-version = "0.4.18"
+version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d"
+checksum = "a05705bc64e0b66a806c3740bd6578ea66051b157ec42dc219c785cbf185aef3"
dependencies = [
- "crossbeam-utils",
"globset",
"lazy_static",
"log",
@@ -319,6 +332,28 @@ dependencies = [
"cfg-if",
]
+[[package]]
+name = "io-lifetimes"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c"
+dependencies = [
+ "libc",
+ "windows-sys",
+]
+
+[[package]]
+name = "is-terminal"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189"
+dependencies = [
+ "hermit-abi",
+ "io-lifetimes",
+ "rustix",
+ "windows-sys",
+]
+
[[package]]
name = "itertools"
version = "0.10.5"
@@ -336,9 +371,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
-version = "0.2.137"
+version = "0.2.139"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
+checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
[[package]]
name = "log"
@@ -379,21 +420,21 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "nix"
-version = "0.25.0"
+version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e322c04a9e3440c327fca7b6c8a63e6890a32fa2ad689db972425f07e0d22abb"
+checksum = "46a58d1d356c6597d08cde02c2f09d785b09e28711837b1ed667dc652c08a694"
dependencies = [
- "autocfg",
"bitflags",
"cfg-if",
"libc",
+ "static_assertions",
]
[[package]]
name = "nom"
-version = "7.1.1"
+version = "7.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36"
+checksum = "e5507769c4919c998e69e49c839d9dc6e693ede4cc4290d6ad8b41d4f09c548c"
dependencies = [
"memchr",
"minimal-lexical",
@@ -401,21 +442,44 @@ dependencies = [
[[package]]
name = "once_cell"
-version = "1.16.0"
+version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
+checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
[[package]]
name = "os_str_bytes"
-version = "6.3.1"
+version = "6.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3baf96e39c5359d2eb0dd6ccb42c62b91d9678aa68160d261b9e0ccbf9e9dea9"
+checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
+
+[[package]]
+name = "ouroboros"
+version = "0.15.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfbb50b356159620db6ac971c6d5c9ab788c9cc38a6f49619fca2a27acb062ca"
+dependencies = [
+ "aliasable",
+ "ouroboros_macro",
+]
+
+[[package]]
+name = "ouroboros_macro"
+version = "0.15.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a0d9d1a6191c4f391f87219d1ea42b23f09ee84d64763cd05ee6ea88d9f384d"
+dependencies = [
+ "Inflector",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
[[package]]
name = "predicates"
-version = "2.1.1"
+version = "2.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a5aab5be6e4732b473071984b3164dbbfb7a3674d30ea5ff44410b6bcd960c3c"
+checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd"
dependencies = [
"difflib",
"itertools",
@@ -424,15 +488,15 @@ dependencies = [
[[package]]
name = "predicates-core"
-version = "1.0.3"
+version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da1c2388b1513e1b605fcec39a95e0a9e8ef088f71443ef37099fa9ae6673fcb"
+checksum = "72f883590242d3c6fc5bf50299011695fa6590c2c70eac95ee1bdb9a733ad1a2"
[[package]]
name = "predicates-tree"
-version = "1.0.5"
+version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d86de6de25020a36c6d3643a86d9a6a9f552107c0559c60ea03551b5e16c032"
+checksum = "54ff541861505aabf6ea722d2131ee980b8276e10a1297b94e896dd8b621850d"
dependencies = [
"predicates-core",
"termtree",
@@ -464,18 +528,18 @@ dependencies = [
[[package]]
name = "proc-macro2"
-version = "1.0.47"
+version = "1.0.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
+checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
-version = "1.0.21"
+version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
+checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
dependencies = [
"proc-macro2",
]
@@ -502,9 +566,9 @@ dependencies = [
[[package]]
name = "regex"
-version = "1.6.0"
+version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
+checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
dependencies = [
"aho-corasick",
"memchr",
@@ -519,9 +583,9 @@ checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
[[package]]
name = "regex-syntax"
-version = "0.6.27"
+version = "0.6.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
+checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
[[package]]
name = "remove_dir_all"
@@ -534,9 +598,9 @@ dependencies = [
[[package]]
name = "rstest"
-version = "0.15.0"
+version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e9c9dc66cc29792b663ffb5269be669f1613664e69ad56441fdb895c2347b930"
+checksum = "b07f2d176c472198ec1e6551dc7da28f1c089652f66a7b722676c2238ebc0edf"
dependencies = [
"rstest_macros",
"rustc_version",
@@ -544,15 +608,16 @@ dependencies = [
[[package]]
name = "rstest_macros"
-version = "0.14.0"
+version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5015e68a0685a95ade3eee617ff7101ab6a3fc689203101ca16ebc16f2b89c66"
+checksum = "7229b505ae0706e64f37ffc54a9c163e11022a6636d58fe1f3f52018257ff9f7"
dependencies = [
"cfg-if",
"proc-macro2",
"quote",
"rustc_version",
"syn",
+ "unicode-ident",
]
[[package]]
@@ -575,6 +640,20 @@ dependencies = [
"semver",
]
+[[package]]
+name = "rustix"
+version = "0.36.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4feacf7db682c6c329c4ede12649cd36ecab0f3be5b7d74e6a20304725db4549"
+dependencies = [
+ "bitflags",
+ "errno",
+ "io-lifetimes",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys",
+]
+
[[package]]
name = "same-file"
version = "1.0.6"
@@ -586,24 +665,24 @@ dependencies = [
[[package]]
name = "semver"
-version = "1.0.14"
+version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
+checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a"
[[package]]
name = "serde"
-version = "1.0.147"
+version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
+checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.147"
+version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852"
+checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
dependencies = [
"proc-macro2",
"quote",
@@ -616,6 +695,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
+[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+
[[package]]
name = "strsim"
version = "0.10.0"
@@ -624,9 +709,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
-version = "1.0.103"
+version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d"
+checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
dependencies = [
"proc-macro2",
"quote",
@@ -658,24 +743,24 @@ dependencies = [
[[package]]
name = "termtree"
-version = "0.2.4"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "507e9898683b6c43a9aa55b64259b721b52ba226e0f3779137e50ad114a4c90b"
+checksum = "95059e91184749cb66be6dc994f67f182b6d897cb3df74a5bf66b5e709295fd8"
[[package]]
name = "thiserror"
-version = "1.0.37"
+version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
+checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.37"
+version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
+checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
dependencies = [
"proc-macro2",
"quote",
@@ -702,9 +787,9 @@ dependencies = [
[[package]]
name = "unicode-ident"
-version = "1.0.5"
+version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
+checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
[[package]]
name = "version_check"
@@ -780,6 +865,63 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+[[package]]
+name = "windows-sys"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
+
[[package]]
name = "xtask"
version = "0.1.0"
@@ -806,6 +948,7 @@ dependencies = [
"fastrand",
"glob",
"nix",
+ "ouroboros",
"rstest",
"rstest_reuse",
"serde",
diff --git a/Cargo.toml b/Cargo.toml
index 6c4d906..c6834f4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -31,11 +31,12 @@ dunce = "1.0.1"
fastrand = "1.7.0"
glob = "0.3.0"
ignore = "0.4.18"
-nix = { version = "0.25.0", default-features = false, features = [
+nix = { version = "0.26.1", default-features = false, features = [
"fs",
"user",
] }
-rstest = { version = "0.15.0", default-features = false }
+ouroboros = "0.15.5"
+rstest = { version = "0.16.0", default-features = false }
rstest_reuse = "0.4.0"
serde = { version = "1.0.116", features = ["derive"] }
shell-words = "1.0.0"
@@ -51,6 +52,7 @@ dirs.workspace = true
dunce.workspace = true
fastrand.workspace = true
glob.workspace = true
+ouroboros.workspace = true
serde.workspace = true
[target.'cfg(unix)'.dependencies]
diff --git a/contrib/completions/_zoxide b/contrib/completions/_zoxide
index 312adb6..3a5c48c 100644
--- a/contrib/completions/_zoxide
+++ b/contrib/completions/_zoxide
@@ -37,6 +37,61 @@ _arguments "${_arguments_options[@]}" \
'*::paths:_files -/' \
&& ret=0
;;
+(edit)
+_arguments "${_arguments_options[@]}" \
+'-h[Print help information]' \
+'--help[Print help information]' \
+'-V[Print version information]' \
+'--version[Print version information]' \
+":: :_zoxide__edit_commands" \
+"*::: :->edit" \
+&& ret=0
+
+ case $state in
+ (edit)
+ words=($line[1] "${words[@]}")
+ (( CURRENT += 1 ))
+ curcontext="${curcontext%:*:*}:zoxide-edit-command-$line[1]:"
+ case $line[1] in
+ (decrement)
+_arguments "${_arguments_options[@]}" \
+'-h[Print help information]' \
+'--help[Print help information]' \
+'-V[Print version information]' \
+'--version[Print version information]' \
+':path:' \
+&& ret=0
+;;
+(delete)
+_arguments "${_arguments_options[@]}" \
+'-h[Print help information]' \
+'--help[Print help information]' \
+'-V[Print version information]' \
+'--version[Print version information]' \
+':path:' \
+&& ret=0
+;;
+(increment)
+_arguments "${_arguments_options[@]}" \
+'-h[Print help information]' \
+'--help[Print help information]' \
+'-V[Print version information]' \
+'--version[Print version information]' \
+':path:' \
+&& ret=0
+;;
+(reload)
+_arguments "${_arguments_options[@]}" \
+'-h[Print help information]' \
+'--help[Print help information]' \
+'-V[Print version information]' \
+'--version[Print version information]' \
+&& ret=0
+;;
+ esac
+ ;;
+esac
+;;
(import)
_arguments "${_arguments_options[@]}" \
'--from=[Application to import from]:FROM:(autojump z)' \
@@ -79,8 +134,6 @@ _arguments "${_arguments_options[@]}" \
;;
(remove)
_arguments "${_arguments_options[@]}" \
-'-i[Use interactive selection]' \
-'--interactive[Use interactive selection]' \
'-h[Print help information]' \
'--help[Print help information]' \
'-V[Print version information]' \
@@ -97,6 +150,7 @@ esac
_zoxide_commands() {
local commands; commands=(
'add:Add a new directory or increment its rank' \
+'edit:Edit the database' \
'import:Import entries from another application' \
'init:Generate shell configuration' \
'query:Search for a directory in the database' \
@@ -109,11 +163,36 @@ _zoxide__add_commands() {
local commands; commands=()
_describe -t commands 'zoxide add commands' commands "$@"
}
+(( $+functions[_zoxide__edit__decrement_commands] )) ||
+_zoxide__edit__decrement_commands() {
+ local commands; commands=()
+ _describe -t commands 'zoxide edit decrement commands' commands "$@"
+}
+(( $+functions[_zoxide__edit__delete_commands] )) ||
+_zoxide__edit__delete_commands() {
+ local commands; commands=()
+ _describe -t commands 'zoxide edit delete commands' commands "$@"
+}
+(( $+functions[_zoxide__edit_commands] )) ||
+_zoxide__edit_commands() {
+ local commands; commands=(
+'decrement:' \
+'delete:' \
+'increment:' \
+'reload:' \
+ )
+ _describe -t commands 'zoxide edit commands' commands "$@"
+}
(( $+functions[_zoxide__import_commands] )) ||
_zoxide__import_commands() {
local commands; commands=()
_describe -t commands 'zoxide import commands' commands "$@"
}
+(( $+functions[_zoxide__edit__increment_commands] )) ||
+_zoxide__edit__increment_commands() {
+ local commands; commands=()
+ _describe -t commands 'zoxide edit increment commands' commands "$@"
+}
(( $+functions[_zoxide__init_commands] )) ||
_zoxide__init_commands() {
local commands; commands=()
@@ -124,6 +203,11 @@ _zoxide__query_commands() {
local commands; commands=()
_describe -t commands 'zoxide query commands' commands "$@"
}
+(( $+functions[_zoxide__edit__reload_commands] )) ||
+_zoxide__edit__reload_commands() {
+ local commands; commands=()
+ _describe -t commands 'zoxide edit reload commands' commands "$@"
+}
(( $+functions[_zoxide__remove_commands] )) ||
_zoxide__remove_commands() {
local commands; commands=()
diff --git a/contrib/completions/_zoxide.ps1 b/contrib/completions/_zoxide.ps1
index f1e0571..abdee9d 100644
--- a/contrib/completions/_zoxide.ps1
+++ b/contrib/completions/_zoxide.ps1
@@ -26,6 +26,7 @@ Register-ArgumentCompleter -Native -CommandName 'zoxide' -ScriptBlock {
[CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Print version information')
[CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Print version information')
[CompletionResult]::new('add', 'add', [CompletionResultType]::ParameterValue, 'Add a new directory or increment its rank')
+ [CompletionResult]::new('edit', 'edit', [CompletionResultType]::ParameterValue, 'Edit the database')
[CompletionResult]::new('import', 'import', [CompletionResultType]::ParameterValue, 'Import entries from another application')
[CompletionResult]::new('init', 'init', [CompletionResultType]::ParameterValue, 'Generate shell configuration')
[CompletionResult]::new('query', 'query', [CompletionResultType]::ParameterValue, 'Search for a directory in the database')
@@ -39,6 +40,45 @@ Register-ArgumentCompleter -Native -CommandName 'zoxide' -ScriptBlock {
[CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Print version information')
break
}
+ 'zoxide;edit' {
+ [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help information')
+ [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help information')
+ [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Print version information')
+ [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Print version information')
+ [CompletionResult]::new('decrement', 'decrement', [CompletionResultType]::ParameterValue, 'decrement')
+ [CompletionResult]::new('delete', 'delete', [CompletionResultType]::ParameterValue, 'delete')
+ [CompletionResult]::new('increment', 'increment', [CompletionResultType]::ParameterValue, 'increment')
+ [CompletionResult]::new('reload', 'reload', [CompletionResultType]::ParameterValue, 'reload')
+ break
+ }
+ 'zoxide;edit;decrement' {
+ [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help information')
+ [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help information')
+ [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Print version information')
+ [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Print version information')
+ break
+ }
+ 'zoxide;edit;delete' {
+ [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help information')
+ [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help information')
+ [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Print version information')
+ [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Print version information')
+ break
+ }
+ 'zoxide;edit;increment' {
+ [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help information')
+ [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help information')
+ [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Print version information')
+ [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Print version information')
+ break
+ }
+ 'zoxide;edit;reload' {
+ [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help information')
+ [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help information')
+ [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Print version information')
+ [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Print version information')
+ break
+ }
'zoxide;import' {
[CompletionResult]::new('--from', 'from', [CompletionResultType]::ParameterName, 'Application to import from')
[CompletionResult]::new('--merge', 'merge', [CompletionResultType]::ParameterName, 'Merge into existing database')
@@ -74,8 +114,6 @@ Register-ArgumentCompleter -Native -CommandName 'zoxide' -ScriptBlock {
break
}
'zoxide;remove' {
- [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'Use interactive selection')
- [CompletionResult]::new('--interactive', 'interactive', [CompletionResultType]::ParameterName, 'Use interactive selection')
[CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help information')
[CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help information')
[CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Print version information')
diff --git a/contrib/completions/zoxide.bash b/contrib/completions/zoxide.bash
index f606b60..6583641 100644
--- a/contrib/completions/zoxide.bash
+++ b/contrib/completions/zoxide.bash
@@ -15,6 +15,9 @@ _zoxide() {
zoxide,add)
cmd="zoxide__add"
;;
+ zoxide,edit)
+ cmd="zoxide__edit"
+ ;;
zoxide,import)
cmd="zoxide__import"
;;
@@ -27,6 +30,18 @@ _zoxide() {
zoxide,remove)
cmd="zoxide__remove"
;;
+ zoxide__edit,decrement)
+ cmd="zoxide__edit__decrement"
+ ;;
+ zoxide__edit,delete)
+ cmd="zoxide__edit__delete"
+ ;;
+ zoxide__edit,increment)
+ cmd="zoxide__edit__increment"
+ ;;
+ zoxide__edit,reload)
+ cmd="zoxide__edit__reload"
+ ;;
*)
;;
esac
@@ -34,7 +49,7 @@ _zoxide() {
case "${cmd}" in
zoxide)
- opts="-h -V --help --version add import init query remove"
+ opts="-h -V --help --version add edit import init query remove"
if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
@@ -61,6 +76,76 @@ _zoxide() {
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
;;
+ zoxide__edit)
+ opts="-h -V --help --version decrement delete increment reload"
+ if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
+ COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
+ return 0
+ fi
+ case "${prev}" in
+ *)
+ COMPREPLY=()
+ ;;
+ esac
+ COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
+ return 0
+ ;;
+ zoxide__edit__decrement)
+ opts="-h -V --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__edit__delete)
+ opts="-h -V --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__edit__increment)
+ opts="-h -V --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__edit__reload)
+ opts="-h -V --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__import)
opts="-h -V --from --merge --help --version "
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
@@ -120,7 +205,7 @@ _zoxide() {
return 0
;;
zoxide__remove)
- opts="-i -h -V --interactive --help --version [PATHS]..."
+ opts="-h -V --help --version [PATHS]..."
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
diff --git a/contrib/completions/zoxide.elv b/contrib/completions/zoxide.elv
index 2e98e78..2bcdb9b 100644
--- a/contrib/completions/zoxide.elv
+++ b/contrib/completions/zoxide.elv
@@ -23,6 +23,7 @@ set edit:completion:arg-completer[zoxide] = {|@words|
cand -V 'Print version information'
cand --version 'Print version information'
cand add 'Add a new directory or increment its rank'
+ cand edit 'Edit the database'
cand import 'Import entries from another application'
cand init 'Generate shell configuration'
cand query 'Search for a directory in the database'
@@ -34,6 +35,40 @@ set edit:completion:arg-completer[zoxide] = {|@words|
cand -V 'Print version information'
cand --version 'Print version information'
}
+ &'zoxide;edit'= {
+ cand -h 'Print help information'
+ cand --help 'Print help information'
+ cand -V 'Print version information'
+ cand --version 'Print version information'
+ cand decrement 'decrement'
+ cand delete 'delete'
+ cand increment 'increment'
+ cand reload 'reload'
+ }
+ &'zoxide;edit;decrement'= {
+ cand -h 'Print help information'
+ cand --help 'Print help information'
+ cand -V 'Print version information'
+ cand --version 'Print version information'
+ }
+ &'zoxide;edit;delete'= {
+ cand -h 'Print help information'
+ cand --help 'Print help information'
+ cand -V 'Print version information'
+ cand --version 'Print version information'
+ }
+ &'zoxide;edit;increment'= {
+ cand -h 'Print help information'
+ cand --help 'Print help information'
+ cand -V 'Print version information'
+ cand --version 'Print version information'
+ }
+ &'zoxide;edit;reload'= {
+ cand -h 'Print help information'
+ cand --help 'Print help information'
+ cand -V 'Print version information'
+ cand --version 'Print version information'
+ }
&'zoxide;import'= {
cand --from 'Application to import from'
cand --merge 'Merge into existing database'
@@ -66,8 +101,6 @@ set edit:completion:arg-completer[zoxide] = {|@words|
cand --version 'Print version information'
}
&'zoxide;remove'= {
- cand -i 'Use interactive selection'
- cand --interactive 'Use interactive selection'
cand -h 'Print help information'
cand --help 'Print help information'
cand -V 'Print version information'
diff --git a/contrib/completions/zoxide.fish b/contrib/completions/zoxide.fish
index 16bf84a..9545776 100644
--- a/contrib/completions/zoxide.fish
+++ b/contrib/completions/zoxide.fish
@@ -1,12 +1,27 @@
complete -c zoxide -n "__fish_use_subcommand" -s h -l help -d 'Print help information'
complete -c zoxide -n "__fish_use_subcommand" -s V -l version -d 'Print version information'
complete -c zoxide -n "__fish_use_subcommand" -f -a "add" -d 'Add a new directory or increment its rank'
+complete -c zoxide -n "__fish_use_subcommand" -f -a "edit" -d 'Edit the database'
complete -c zoxide -n "__fish_use_subcommand" -f -a "import" -d 'Import entries from another application'
complete -c zoxide -n "__fish_use_subcommand" -f -a "init" -d 'Generate shell configuration'
complete -c zoxide -n "__fish_use_subcommand" -f -a "query" -d 'Search for a directory in the database'
complete -c zoxide -n "__fish_use_subcommand" -f -a "remove" -d 'Remove a directory from the database'
complete -c zoxide -n "__fish_seen_subcommand_from add" -s h -l help -d 'Print help information'
complete -c zoxide -n "__fish_seen_subcommand_from add" -s V -l version -d 'Print version information'
+complete -c zoxide -n "__fish_seen_subcommand_from edit; and not __fish_seen_subcommand_from decrement; and not __fish_seen_subcommand_from delete; and not __fish_seen_subcommand_from increment; and not __fish_seen_subcommand_from reload" -s h -l help -d 'Print help information'
+complete -c zoxide -n "__fish_seen_subcommand_from edit; and not __fish_seen_subcommand_from decrement; and not __fish_seen_subcommand_from delete; and not __fish_seen_subcommand_from increment; and not __fish_seen_subcommand_from reload" -s V -l version -d 'Print version information'
+complete -c zoxide -n "__fish_seen_subcommand_from edit; and not __fish_seen_subcommand_from decrement; and not __fish_seen_subcommand_from delete; and not __fish_seen_subcommand_from increment; and not __fish_seen_subcommand_from reload" -f -a "decrement"
+complete -c zoxide -n "__fish_seen_subcommand_from edit; and not __fish_seen_subcommand_from decrement; and not __fish_seen_subcommand_from delete; and not __fish_seen_subcommand_from increment; and not __fish_seen_subcommand_from reload" -f -a "delete"
+complete -c zoxide -n "__fish_seen_subcommand_from edit; and not __fish_seen_subcommand_from decrement; and not __fish_seen_subcommand_from delete; and not __fish_seen_subcommand_from increment; and not __fish_seen_subcommand_from reload" -f -a "increment"
+complete -c zoxide -n "__fish_seen_subcommand_from edit; and not __fish_seen_subcommand_from decrement; and not __fish_seen_subcommand_from delete; and not __fish_seen_subcommand_from increment; and not __fish_seen_subcommand_from reload" -f -a "reload"
+complete -c zoxide -n "__fish_seen_subcommand_from edit; and __fish_seen_subcommand_from decrement" -s h -l help -d 'Print help information'
+complete -c zoxide -n "__fish_seen_subcommand_from edit; and __fish_seen_subcommand_from decrement" -s V -l version -d 'Print version information'
+complete -c zoxide -n "__fish_seen_subcommand_from edit; and __fish_seen_subcommand_from delete" -s h -l help -d 'Print help information'
+complete -c zoxide -n "__fish_seen_subcommand_from edit; and __fish_seen_subcommand_from delete" -s V -l version -d 'Print version information'
+complete -c zoxide -n "__fish_seen_subcommand_from edit; and __fish_seen_subcommand_from increment" -s h -l help -d 'Print help information'
+complete -c zoxide -n "__fish_seen_subcommand_from edit; and __fish_seen_subcommand_from increment" -s V -l version -d 'Print version information'
+complete -c zoxide -n "__fish_seen_subcommand_from edit; and __fish_seen_subcommand_from reload" -s h -l help -d 'Print help information'
+complete -c zoxide -n "__fish_seen_subcommand_from edit; and __fish_seen_subcommand_from reload" -s V -l version -d 'Print version information'
complete -c zoxide -n "__fish_seen_subcommand_from import" -l from -d 'Application to import from' -r -f -a "{autojump ,z }"
complete -c zoxide -n "__fish_seen_subcommand_from import" -l merge -d 'Merge into existing database'
complete -c zoxide -n "__fish_seen_subcommand_from import" -s h -l help -d 'Print help information'
@@ -23,6 +38,5 @@ complete -c zoxide -n "__fish_seen_subcommand_from query" -s l -l list -d 'List
complete -c zoxide -n "__fish_seen_subcommand_from query" -s s -l score -d 'Print score with results'
complete -c zoxide -n "__fish_seen_subcommand_from query" -s h -l help -d 'Print help information'
complete -c zoxide -n "__fish_seen_subcommand_from query" -s V -l version -d 'Print version information'
-complete -c zoxide -n "__fish_seen_subcommand_from remove" -s i -l interactive -d 'Use interactive selection'
complete -c zoxide -n "__fish_seen_subcommand_from remove" -s h -l help -d 'Print help information'
complete -c zoxide -n "__fish_seen_subcommand_from remove" -s V -l version -d 'Print version information'
diff --git a/contrib/completions/zoxide.ts b/contrib/completions/zoxide.ts
index dd37351..624d3c2 100644
--- a/contrib/completions/zoxide.ts
+++ b/contrib/completions/zoxide.ts
@@ -21,6 +21,87 @@ const completion: Fig.Spec = {
template: "folders",
},
},
+ {
+ name: "edit",
+ description: "Edit the database",
+ subcommands: [
+ {
+ name: "decrement",
+ hidden: true,
+ options: [
+ {
+ name: ["-h", "--help"],
+ description: "Print help information",
+ },
+ {
+ name: ["-V", "--version"],
+ description: "Print version information",
+ },
+ ],
+ args: {
+ name: "path",
+ },
+ },
+ {
+ name: "delete",
+ hidden: true,
+ options: [
+ {
+ name: ["-h", "--help"],
+ description: "Print help information",
+ },
+ {
+ name: ["-V", "--version"],
+ description: "Print version information",
+ },
+ ],
+ args: {
+ name: "path",
+ },
+ },
+ {
+ name: "increment",
+ hidden: true,
+ options: [
+ {
+ name: ["-h", "--help"],
+ description: "Print help information",
+ },
+ {
+ name: ["-V", "--version"],
+ description: "Print version information",
+ },
+ ],
+ args: {
+ name: "path",
+ },
+ },
+ {
+ name: "reload",
+ hidden: true,
+ options: [
+ {
+ name: ["-h", "--help"],
+ description: "Print help information",
+ },
+ {
+ name: ["-V", "--version"],
+ description: "Print version information",
+ },
+ ],
+ },
+ ],
+ options: [
+ {
+ name: ["-h", "--help"],
+ description: "Print help information",
+ },
+ {
+ name: ["-V", "--version"],
+ description: "Print version information",
+ },
+ ],
+ },
{
name: "import",
description: "Import entries from another application",
@@ -166,10 +247,6 @@ const completion: Fig.Spec = {
name: "remove",
description: "Remove a directory from the database",
options: [
- {
- name: ["-i", "--interactive"],
- description: "Use interactive selection",
- },
{
name: ["-h", "--help"],
description: "Print help information",
diff --git a/man/man1/zoxide-init.1 b/man/man1/zoxide-init.1
index 0d7f51b..e3331fb 100644
--- a/man/man1/zoxide-init.1
+++ b/man/man1/zoxide-init.1
@@ -35,7 +35,7 @@ Note: zoxide only supports fish v3.4.0 and above.
Add this to your env file (find it by running \fB$nu.env-path\fR in Nushell):
.sp
.nf
- \fBzoxide init nushell --hook prompt | save -f ~/.zoxide.nu\fR
+ \fBzoxide init nushell | save -f ~/.zoxide.nu\fR
.fi
.sp
Now, add this to the end of your config file (find it by running
diff --git a/rustfmt.toml b/rustfmt.toml
index 5106da6..ebaf638 100644
--- a/rustfmt.toml
+++ b/rustfmt.toml
@@ -1,4 +1,3 @@
-comment_width = 100
group_imports = "StdExternalCrate"
imports_granularity = "Module"
max_width = 120
diff --git a/src/cmd/add.rs b/src/cmd/add.rs
index 34ba0c0..21514b8 100644
--- a/src/cmd/add.rs
+++ b/src/cmd/add.rs
@@ -3,22 +3,20 @@ use std::path::Path;
use anyhow::{bail, Result};
use crate::cmd::{Add, Run};
-use crate::db::DatabaseFile;
+use crate::db::Database;
use crate::{config, util};
impl Run for Add {
fn run(&self) -> Result<()> {
// These characters can't be printed cleanly to a single line, so they can cause confusion
- // when writing to fzf / stdout.
+ // when writing to stdout.
const EXCLUDE_CHARS: &[char] = &['\n', '\r'];
- let data_dir = config::data_dir()?;
let exclude_dirs = config::exclude_dirs()?;
let max_age = config::maxage()?;
let now = util::current_time()?;
- let mut db = DatabaseFile::new(data_dir);
- let mut db = db.open()?;
+ let mut db = Database::open()?;
for path in &self.paths {
let path = if config::resolve_symlinks() { util::canonicalize } else { util::resolve_path }(path)?;
@@ -31,14 +29,12 @@ impl Run for Add {
if !Path::new(path).is_dir() {
bail!("not a directory: {path}");
}
- db.add(path, now);
+ db.add_update(path, 1.0, now);
}
- if db.modified {
+ if db.dirty() {
db.age(max_age);
- db.save()?;
}
-
- Ok(())
+ db.save()
}
}
diff --git a/src/cmd/cmd.rs b/src/cmd/cmd.rs
index c22a283..1f19a80 100644
--- a/src/cmd/cmd.rs
+++ b/src/cmd/cmd.rs
@@ -2,7 +2,7 @@
use std::path::PathBuf;
-use clap::{Parser, ValueEnum, ValueHint};
+use clap::{Parser, Subcommand, ValueEnum, ValueHint};
const ENV_HELP: &str = "Environment variables:
_ZO_DATA_DIR Path for zoxide data files
@@ -24,6 +24,7 @@ const ENV_HELP: &str = "Environment variables:
)]
pub enum Cmd {
Add(Add),
+ Edit(Edit),
Import(Import),
Init(Init),
Query(Query),
@@ -37,6 +38,25 @@ pub struct Add {
pub paths: Vec,
}
+/// Edit the database
+#[derive(Debug, Parser)]
+pub struct Edit {
+ #[clap(subcommand)]
+ pub cmd: Option,
+}
+
+#[derive(Clone, Debug, Subcommand)]
+pub enum EditCommand {
+ #[clap(hide = true)]
+ Decrement { path: String },
+ #[clap(hide = true)]
+ Delete { path: String },
+ #[clap(hide = true)]
+ Increment { path: String },
+ #[clap(hide = true)]
+ Reload,
+}
+
/// Import entries from another application
#[derive(Debug, Parser)]
pub struct Import {
@@ -125,9 +145,6 @@ pub struct Query {
/// Remove a directory from the database
#[derive(Debug, Parser)]
pub struct Remove {
- /// Use interactive selection
- #[clap(long, short)]
- pub interactive: bool,
#[clap(value_hint = ValueHint::DirPath)]
pub paths: Vec,
}
diff --git a/src/cmd/edit.rs b/src/cmd/edit.rs
new file mode 100644
index 0000000..2bbaedc
--- /dev/null
+++ b/src/cmd/edit.rs
@@ -0,0 +1,83 @@
+use std::io::{self, Write};
+
+use anyhow::Result;
+
+use crate::cmd::{Edit, EditCommand, Run};
+use crate::db::Database;
+use crate::error::BrokenPipeHandler;
+use crate::util::{self, Fzf, FzfChild};
+
+impl Run for Edit {
+ fn run(&self) -> Result<()> {
+ let now = util::current_time()?;
+ let db = &mut Database::open()?;
+
+ match &self.cmd {
+ Some(cmd) => {
+ match cmd {
+ EditCommand::Decrement { path } => db.add(path, -1.0, now),
+ EditCommand::Delete { path } => {
+ db.remove(path);
+ }
+ EditCommand::Increment { path } => db.add(path, 1.0, now),
+ EditCommand::Reload => {}
+ }
+ db.save()?;
+
+ let stdout = &mut io::stdout().lock();
+ for dir in db.dirs().iter().rev() {
+ write!(stdout, "{}\0", dir.display().with_score(now).with_separator('\t')).pipe_exit("fzf")?;
+ }
+ Ok(())
+ }
+ None => {
+ db.sort_by_score(now);
+ db.save()?;
+ Self::get_fzf()?.wait()?;
+ Ok(())
+ }
+ }
+ }
+}
+
+impl Edit {
+ fn get_fzf() -> Result {
+ Fzf::new()?
+ .args([
+ // Search mode
+ "--scheme=path",
+ // Search result
+ "--tiebreak=end,chunk,index",
+ // Interface
+ "--bind=\
+btab:up,\
+ctrl-r:reload(zoxide edit reload),\
+ctrl-d:reload(zoxide edit delete {2..}),\
+ctrl-w:reload(zoxide edit increment {2..}),\
+ctrl-s:reload(zoxide edit decrement {2..}),\
+ctrl-z:ignore,\
+double-click:ignore,\
+enter:abort,\
+start:reload(zoxide edit reload),\
+tab:down",
+ "--cycle",
+ "--keep-right",
+ // Layout
+ "--border=sharp",
+ "--border-label= zoxide-edit ",
+ "--header=\
+ctrl-r:reload \tctrl-d:delete
+ctrl-w:increment\tctrl-s:decrement
+
+ SCORE\tPATH",
+ "--info=inline",
+ "--layout=reverse",
+ "--padding=1,0,0,0",
+ // Display
+ "--color=label:bold",
+ "--tabstop=1",
+ ])
+ .enable_preview()
+ .spawn()
+ }
+}
diff --git a/src/cmd/import.rs b/src/cmd/import.rs
index b5a2fd2..3a2c206 100644
--- a/src/cmd/import.rs
+++ b/src/cmd/import.rs
@@ -3,24 +3,21 @@ use std::fs;
use anyhow::{bail, Context, Result};
use crate::cmd::{Import, ImportFrom, Run};
-use crate::config;
-use crate::db::{Database, DatabaseFile, Dir};
+use crate::db::Database;
impl Run for Import {
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 data_dir = config::data_dir()?;
- let mut db = DatabaseFile::new(data_dir);
- let db = &mut db.open()?;
- if !self.merge && !db.dirs.is_empty() {
+ let mut db = Database::open()?;
+ if !self.merge && !db.dirs().is_empty() {
bail!("current database is not empty, specify --merge to continue anyway");
}
match self.from {
- ImportFrom::Autojump => from_autojump(db, &buffer),
- ImportFrom::Z => from_z(db, &buffer),
+ ImportFrom::Autojump => import_autojump(&mut db, &buffer),
+ ImportFrom::Z => import_z(&mut db, &buffer),
}
.context("import error")?;
@@ -28,7 +25,7 @@ impl Run for Import {
}
}
-fn from_autojump<'a>(db: &mut Database<'a>, buffer: &'a str) -> Result<()> {
+fn import_autojump(db: &mut Database, buffer: &str) -> Result<()> {
for line in buffer.lines() {
if line.is_empty() {
continue;
@@ -43,18 +40,16 @@ fn from_autojump<'a>(db: &mut Database<'a>, buffer: &'a str) -> Result<()> {
let path = split.next().with_context(|| format!("invalid entry: {line}"))?;
- db.dirs.push(Dir { path: path.into(), rank, last_accessed: 0 });
- db.modified = true;
+ db.add_unchecked(path, rank, 0);
}
- if db.modified {
+ if db.dirty() {
db.dedup();
}
-
Ok(())
}
-fn from_z<'a>(db: &mut Database<'a>, buffer: &'a str) -> Result<()> {
+fn import_z(db: &mut Database, buffer: &str) -> Result<()> {
for line in buffer.lines() {
if line.is_empty() {
continue;
@@ -69,14 +64,12 @@ fn from_z<'a>(db: &mut Database<'a>, buffer: &'a str) -> Result<()> {
let path = split.next().with_context(|| format!("invalid entry: {line}"))?;
- db.dirs.push(Dir { path: path.into(), rank, last_accessed });
- db.modified = true;
+ db.add_unchecked(path, rank, last_accessed);
}
- if db.modified {
+ if db.dirty() {
db.dedup();
}
-
Ok(())
}
@@ -86,33 +79,33 @@ fn sigmoid(x: f64) -> f64 {
#[cfg(test)]
mod tests {
- use super::sigmoid;
- use crate::db::{Database, Dir};
+ use super::*;
+ use crate::db::Dir;
#[test]
fn from_autojump() {
- let buffer = r#"
+ 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
-"#;
+5.0 /quux/quuz";
+ import_autojump(&mut db, buffer).unwrap();
- let dirs = vec![
- Dir { path: "/quux/quuz".into(), rank: 1.0, last_accessed: 100 },
- Dir { path: "/corge/grault/garply".into(), rank: 6.0, last_accessed: 600 },
- Dir { path: "/waldo/fred/plugh".into(), rank: 3.0, last_accessed: 300 },
- Dir { path: "/xyzzy/thud".into(), rank: 8.0, last_accessed: 800 },
- Dir { path: "/foo/bar".into(), rank: 9.0, last_accessed: 900 },
- ];
- let data_dir = tempfile::tempdir().unwrap();
- let data_dir = &data_dir.path().to_path_buf();
- let mut db = Database { dirs: dirs.into(), modified: false, data_dir };
+ db.sort_by_path();
+ println!("got: {:?}", &db.dirs());
- super::from_autojump(&mut db, buffer).unwrap();
- db.dirs.sort_by(|dir1, dir2| dir1.path.cmp(&dir2.path));
- println!("got: {:?}", &db.dirs.as_slice());
-
- let exp = &[
+ 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 },
@@ -122,7 +115,7 @@ mod tests {
];
println!("exp: {exp:?}");
- for (dir1, dir2) in db.dirs.iter().zip(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);
@@ -131,29 +124,29 @@ mod tests {
#[test]
fn from_z() {
- let buffer = r#"
+ 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
-"#;
+/quux/quuz|5|500";
+ import_z(&mut db, buffer).unwrap();
- let dirs = vec![
- Dir { path: "/quux/quuz".into(), rank: 1.0, last_accessed: 100 },
- Dir { path: "/corge/grault/garply".into(), rank: 6.0, last_accessed: 600 },
- Dir { path: "/waldo/fred/plugh".into(), rank: 3.0, last_accessed: 300 },
- Dir { path: "/xyzzy/thud".into(), rank: 8.0, last_accessed: 800 },
- Dir { path: "/foo/bar".into(), rank: 9.0, last_accessed: 900 },
- ];
- let data_dir = tempfile::tempdir().unwrap();
- let data_dir = &data_dir.path().to_path_buf();
- let mut db = Database { dirs: dirs.into(), modified: false, data_dir };
+ db.sort_by_path();
+ println!("got: {:?}", &db.dirs());
- super::from_z(&mut db, buffer).unwrap();
- db.dirs.sort_by(|dir1, dir2| dir1.path.cmp(&dir2.path));
- println!("got: {:?}", &db.dirs.as_slice());
-
- let exp = &[
+ 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 },
@@ -163,7 +156,7 @@ mod tests {
];
println!("exp: {exp:?}");
- for (dir1, dir2) in db.dirs.iter().zip(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);
diff --git a/src/cmd/init.rs b/src/cmd/init.rs
index 32f6896..2c7609d 100644
--- a/src/cmd/init.rs
+++ b/src/cmd/init.rs
@@ -11,10 +11,8 @@ use crate::shell::{self, Opts};
impl Run for Init {
fn run(&self) -> Result<()> {
let cmd = if self.no_cmd { None } else { Some(self.cmd.as_str()) };
-
let echo = config::echo();
let resolve_symlinks = config::resolve_symlinks();
-
let opts = &Opts { cmd, hook: self.hook, echo, resolve_symlinks };
let source = match self.shell {
diff --git a/src/cmd/mod.rs b/src/cmd/mod.rs
index 876a6aa..5c17474 100644
--- a/src/cmd/mod.rs
+++ b/src/cmd/mod.rs
@@ -1,5 +1,6 @@
mod add;
mod cmd;
+mod edit;
mod import;
mod init;
mod query;
@@ -17,6 +18,7 @@ impl Run for Cmd {
fn run(&self) -> Result<()> {
match self {
Cmd::Add(cmd) => cmd.run(),
+ Cmd::Edit(cmd) => cmd.run(),
Cmd::Import(cmd) => cmd.run(),
Cmd::Init(cmd) => cmd.run(),
Cmd::Query(cmd) => cmd.run(),
diff --git a/src/cmd/query.rs b/src/cmd/query.rs
index 397a5b4..14a25ef 100644
--- a/src/cmd/query.rs
+++ b/src/cmd/query.rs
@@ -4,15 +4,13 @@ use anyhow::{Context, Result};
use crate::cmd::{Query, Run};
use crate::config;
-use crate::db::{Database, DatabaseFile};
+use crate::db::{Database, Epoch, Stream};
use crate::error::BrokenPipeHandler;
-use crate::util::{self, Fzf};
+use crate::util::{self, Fzf, FzfChild};
impl Run for Query {
fn run(&self) -> Result<()> {
- let data_dir = config::data_dir()?;
- let mut db = DatabaseFile::new(data_dir);
- let mut db = db.open()?;
+ let mut db = crate::db::Database::open()?;
self.query(&mut db).and(db.save())
}
}
@@ -20,7 +18,44 @@ impl Run for Query {
impl Query {
fn query(&self, db: &mut Database) -> Result<()> {
let now = util::current_time()?;
+ let mut stream = self.get_stream(db, now);
+ if self.interactive {
+ let mut fzf = Self::get_fzf()?;
+ let selection = loop {
+ match stream.next() {
+ Some(dir) => {
+ if let Some(selection) = fzf.write(dir, now)? {
+ break selection;
+ }
+ }
+ None => break fzf.wait()?,
+ }
+ };
+
+ if self.score {
+ print!("{selection}");
+ } else {
+ let path = selection.get(7..).context("could not read selection from fzf")?;
+ print!("{path}");
+ }
+ } else if self.list {
+ let handle = &mut io::stdout().lock();
+ while let Some(dir) = stream.next() {
+ let dir = if self.score { dir.display().with_score(now) } else { dir.display() };
+ writeln!(handle, "{dir}").pipe_exit("stdout")?;
+ }
+ } else {
+ let handle = &mut io::stdout();
+ let dir = stream.next().context("no match found")?;
+ let dir = if self.score { dir.display().with_score(now) } else { dir.display() };
+ writeln!(handle, "{dir}").pipe_exit("stdout")?;
+ }
+
+ Ok(())
+ }
+
+ fn get_stream<'a>(&self, db: &'a mut Database, now: Epoch) -> Stream<'a> {
let mut stream = db.stream(now).with_keywords(&self.keywords);
if !self.all {
let resolve_symlinks = config::resolve_symlinks();
@@ -29,46 +64,36 @@ impl Query {
if let Some(path) = &self.exclude {
stream = stream.with_exclude(path);
}
+ stream
+ }
- if self.interactive {
- let mut fzf = Fzf::new(false)?;
- let stdin = fzf.stdin();
-
- let selection = loop {
- let Some(dir) = stream.next() else { break fzf.select()? };
- match writeln!(stdin, "{}", dir.display_score(now)) {
- Err(e) if e.kind() == io::ErrorKind::BrokenPipe => break fzf.select()?,
- result => result.context("could not write to fzf")?,
- }
- };
-
- if self.score {
- print!("{selection}");
- } else {
- let path = selection.get(5..).context("could not read selection from fzf")?;
- print!("{path}");
- }
- } else if self.list {
- let handle = &mut io::stdout().lock();
- while let Some(dir) = stream.next() {
- if self.score {
- writeln!(handle, "{}", dir.display_score(now))
- } else {
- writeln!(handle, "{}", dir.display())
- }
- .pipe_exit("stdout")?;
- }
- handle.flush().pipe_exit("stdout")?;
+ fn get_fzf() -> Result {
+ let mut fzf = Fzf::new()?;
+ if let Some(fzf_opts) = config::fzf_opts() {
+ fzf.env("FZF_DEFAULT_OPTS", fzf_opts)
} else {
- let dir = stream.next().context("no match found")?;
- if self.score {
- writeln!(io::stdout(), "{}", dir.display_score(now))
- } else {
- writeln!(io::stdout(), "{}", dir.display())
- }
- .pipe_exit("stdout")?;
+ fzf.args([
+ // Search mode
+ "--scheme=path",
+ // Search result
+ "--tiebreak=end,chunk,index",
+ // Interface
+ "--bind=ctrl-z:ignore,btab:up,tab:down",
+ "--cycle",
+ "--keep-right",
+ // Layout
+ "--border=sharp", // rounded edges don't display correctly on some terminals
+ "--height=45%",
+ "--info=inline",
+ "--layout=reverse",
+ // Display
+ "--tabstop=1",
+ // Scripting
+ "--exit-0",
+ "--select-1",
+ ])
+ .enable_preview()
}
-
- Ok(())
+ .spawn()
}
}
diff --git a/src/cmd/remove.rs b/src/cmd/remove.rs
index e5ed48c..55c6989 100644
--- a/src/cmd/remove.rs
+++ b/src/cmd/remove.rs
@@ -1,50 +1,19 @@
-use std::io::{self, Write};
-
-use anyhow::{bail, Context, Result};
+use anyhow::{bail, Result};
use crate::cmd::{Remove, Run};
-use crate::config;
-use crate::db::DatabaseFile;
-use crate::util::{self, Fzf};
+use crate::db::Database;
+use crate::util;
impl Run for Remove {
fn run(&self) -> Result<()> {
- let data_dir = config::data_dir()?;
- let mut db = DatabaseFile::new(data_dir);
- let mut db = db.open()?;
+ let mut db = Database::open()?;
- if self.interactive {
- let keywords = &self.paths;
- let now = util::current_time()?;
- let mut stream = db.stream(now).with_keywords(keywords);
-
- let mut fzf = Fzf::new(true)?;
- let stdin = fzf.stdin();
-
- let selection = loop {
- let Some(dir) = stream.next() else { break fzf.select()? };
- match writeln!(stdin, "{}", dir.display_score(now)) {
- Err(e) if e.kind() == io::ErrorKind::BrokenPipe => break fzf.select()?,
- result => result.context("could not write to fzf")?,
- }
- };
-
- let paths = selection.lines().filter_map(|line| line.get(5..));
- for path in paths {
- if !db.remove(path) {
- db.modified = false;
- bail!("path not found in database: {path}");
- }
- }
- } else {
- for path in &self.paths {
- if !db.remove(path) {
- let path_abs = util::resolve_path(path)?;
- let path_abs = util::path_to_str(&path_abs)?;
- if path_abs == path || !db.remove(path_abs) {
- db.modified = false;
- bail!("path not found in database: {path}")
- }
+ for path in &self.paths {
+ if !db.remove(path) {
+ let path_abs = util::resolve_path(path)?;
+ let path_abs = util::path_to_str(&path_abs)?;
+ if path_abs == path || !db.remove(path_abs) {
+ bail!("path not found in database: {path}")
}
}
}
diff --git a/src/db/dir.rs b/src/db/dir.rs
index c59a441..d545b40 100644
--- a/src/db/dir.rs
+++ b/src/db/dir.rs
@@ -1,83 +1,11 @@
-use std::borrow::Cow;
-use std::fmt::{self, Display, Formatter};
-use std::ops::{Deref, DerefMut};
+use std::{
+ borrow::Cow,
+ fmt::{self, Display, Formatter},
+};
-use anyhow::{bail, Context, Result};
-use bincode::Options as _;
use serde::{Deserialize, Serialize};
-#[derive(Debug, Deserialize, Serialize)]
-pub struct DirList<'a>(#[serde(borrow)] pub Vec>);
-
-impl DirList<'_> {
- const VERSION: u32 = 3;
-
- pub fn new() -> DirList<'static> {
- DirList(Vec::new())
- }
-
- pub fn from_bytes(bytes: &[u8]) -> Result {
- // Assume a maximum size for the database. This prevents bincode from throwing strange
- // errors when it encounters invalid data.
- const MAX_SIZE: u64 = 32 << 20; // 32 MiB
- let deserializer = &mut bincode::options().with_fixint_encoding().with_limit(MAX_SIZE);
-
- // Split bytes into sections.
- let version_size = deserializer.serialized_size(&Self::VERSION).unwrap() as _;
- if bytes.len() < version_size {
- bail!("could not deserialize database: corrupted data");
- }
- let (bytes_version, bytes_dirs) = bytes.split_at(version_size);
-
- // Deserialize sections.
- (|| {
- let version = deserializer.deserialize(bytes_version)?;
- match version {
- Self::VERSION => Ok(deserializer.deserialize(bytes_dirs)?),
- version => {
- bail!("unsupported version (got {version}, supports {})", Self::VERSION)
- }
- }
- })()
- .context("could not deserialize database")
- }
-
- pub fn to_bytes(&self) -> Result> {
- (|| -> bincode::Result<_> {
- // Preallocate buffer with combined size of sections.
- let version_size = bincode::serialized_size(&Self::VERSION)?;
- let dirs_size = bincode::serialized_size(&self)?;
- let buffer_size = version_size + dirs_size;
- let mut buffer = Vec::with_capacity(buffer_size as _);
-
- // Serialize sections into buffer.
- bincode::serialize_into(&mut buffer, &Self::VERSION)?;
- bincode::serialize_into(&mut buffer, &self)?;
- Ok(buffer)
- })()
- .context("could not serialize database")
- }
-}
-
-impl<'a> Deref for DirList<'a> {
- type Target = Vec>;
-
- fn deref(&self) -> &Self::Target {
- &self.0
- }
-}
-
-impl<'a> DerefMut for DirList<'a> {
- fn deref_mut(&mut self) -> &mut Self::Target {
- &mut self.0
- }
-}
-
-impl<'a> From>> for DirList<'a> {
- fn from(dirs: Vec>) -> Self {
- DirList(dirs)
- }
-}
+use crate::util::{DAY, HOUR, WEEK};
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Dir<'a> {
@@ -88,11 +16,11 @@ pub struct Dir<'a> {
}
impl Dir<'_> {
- pub fn score(&self, now: Epoch) -> Rank {
- const HOUR: Epoch = 60 * 60;
- const DAY: Epoch = 24 * HOUR;
- const WEEK: Epoch = 7 * DAY;
+ pub fn display(&self) -> DirDisplay<'_> {
+ DirDisplay::new(self)
+ }
+ pub fn score(&self, now: Epoch) -> Rank {
// The older the entry, the lesser its importance.
let duration = now.saturating_sub(self.last_accessed);
if duration < HOUR {
@@ -105,56 +33,39 @@ impl Dir<'_> {
self.rank * 0.25
}
}
-
- pub fn display(&self) -> DirDisplay {
- DirDisplay { dir: self }
- }
-
- pub fn display_score(&self, now: Epoch) -> DirDisplayScore {
- DirDisplayScore { dir: self, now }
- }
}
pub struct DirDisplay<'a> {
dir: &'a Dir<'a>,
+ now: Option,
+ separator: char,
+}
+
+impl<'a> DirDisplay<'a> {
+ fn new(dir: &'a Dir) -> Self {
+ Self { dir, separator: ' ', now: None }
+ }
+
+ pub fn with_score(mut self, now: Epoch) -> Self {
+ self.now = Some(now);
+ self
+ }
+
+ pub fn with_separator(mut self, separator: char) -> Self {
+ self.separator = separator;
+ self
+ }
}
impl Display for DirDisplay<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+ if let Some(now) = self.now {
+ let score = self.dir.score(now).clamp(0.0, 9999.0);
+ write!(f, "{score:>6.1}{}", self.separator)?;
+ }
write!(f, "{}", self.dir.path)
}
}
-pub struct DirDisplayScore<'a> {
- dir: &'a Dir<'a>,
- now: Epoch,
-}
-
-impl Display for DirDisplayScore<'_> {
- fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
- let score = self.dir.score(self.now).clamp(0.0, 9999.0) as u32;
- write!(f, "{:>4} {}", score, self.dir.path)
- }
-}
-
pub type Rank = f64;
pub type Epoch = u64;
-
-#[cfg(test)]
-mod tests {
- use std::borrow::Cow;
-
- use super::*;
-
- #[test]
- fn zero_copy() {
- let dirs = DirList(vec![Dir { path: "/".into(), rank: 0.0, last_accessed: 0 }]);
-
- let bytes = dirs.to_bytes().unwrap();
- let dirs = DirList::from_bytes(&bytes).unwrap();
-
- for dir in dirs.iter() {
- assert!(matches!(dir.path, Cow::Borrowed(_)))
- }
- }
-}
diff --git a/src/db/mod.rs b/src/db/mod.rs
index 12f6475..0e85e28 100644
--- a/src/db/mod.rs
+++ b/src/db/mod.rs
@@ -4,143 +4,220 @@ mod stream;
use std::path::{Path, PathBuf};
use std::{fs, io};
-use anyhow::{Context, Result};
-pub use dir::{Dir, DirList, Epoch, Rank};
-pub use stream::Stream;
+use anyhow::{bail, Context, Result};
+use bincode::Options;
+use ouroboros::self_referencing;
-use crate::util;
+pub use crate::db::dir::{Dir, Epoch, Rank};
+pub use crate::db::stream::Stream;
+use crate::{config, util};
-#[derive(Debug)]
-pub struct Database<'file> {
- pub dirs: DirList<'file>,
- pub modified: bool,
- pub data_dir: &'file Path,
+#[self_referencing]
+pub struct Database {
+ path: PathBuf,
+ bytes: Vec,
+ #[borrows(bytes)]
+ #[covariant]
+ pub dirs: Vec>,
+ dirty: bool,
}
-impl<'file> Database<'file> {
- pub fn save(&mut self) -> Result<()> {
- if !self.modified {
- return Ok(());
- }
+impl Database {
+ const VERSION: u32 = 3;
- let buffer = self.dirs.to_bytes()?;
- let path = db_path(self.data_dir);
- util::write(path, buffer).context("could not write to database")?;
- self.modified = false;
- Ok(())
+ pub fn open() -> Result {
+ let data_dir = config::data_dir()?;
+ Self::open_dir(data_dir)
}
- /// Adds a new directory or increments its rank. Also updates its last accessed time.
- pub fn add>(&mut self, path: S, now: Epoch) {
- let path = path.as_ref();
+ pub fn open_dir(data_dir: impl AsRef) -> Result {
+ let data_dir = data_dir.as_ref();
+ let path = data_dir.join("db.zo");
- match self.dirs.iter_mut().find(|dir| dir.path == path) {
- Some(dir) => {
- dir.last_accessed = now;
- dir.rank += 1.0;
- }
- None => self.dirs.push(Dir { path: path.to_string().into(), last_accessed: now, rank: 1.0 }),
- };
-
- self.modified = true;
- }
-
- pub fn dedup(&mut self) {
- // Sort by path, so that equal paths are next to each other.
- self.dirs.sort_by(|dir1, dir2| dir1.path.cmp(&dir2.path));
-
- for idx in (1..self.dirs.len()).rev() {
- // Check if curr_dir and next_dir have equal paths.
- let curr_dir = &self.dirs[idx];
- let next_dir = &self.dirs[idx - 1];
- if next_dir.path != curr_dir.path {
- continue;
- }
-
- // Merge curr_dir's rank and last_accessed into next_dir.
- let rank = curr_dir.rank;
- let last_accessed = curr_dir.last_accessed;
- let next_dir = &mut self.dirs[idx - 1];
- next_dir.last_accessed = next_dir.last_accessed.max(last_accessed);
- next_dir.rank += rank;
-
- // Delete curr_dir.
- self.dirs.swap_remove(idx);
- self.modified = true;
- }
- }
-
- // Streaming iterator for directories.
- pub fn stream(&mut self, now: Epoch) -> Stream<'_, 'file> {
- Stream::new(self, now)
- }
-
- /// Removes the directory with `path` from the store. This does not preserve ordering, but is
- /// O(1).
- pub fn remove>(&mut self, path: S) -> bool {
- let path = path.as_ref();
-
- if let Some(idx) = self.dirs.iter().position(|dir| dir.path == path) {
- self.dirs.swap_remove(idx);
- self.modified = true;
- return true;
- }
-
- false
- }
-
- pub fn age(&mut self, max_age: Rank) {
- let sum_age = self.dirs.iter().map(|dir| dir.rank).sum::();
- if sum_age > max_age {
- let factor = 0.9 * max_age / sum_age;
- for idx in (0..self.dirs.len()).rev() {
- let dir = &mut self.dirs[idx];
- dir.rank *= factor;
- if dir.rank < 1.0 {
- self.dirs.swap_remove(idx);
- }
- }
- self.modified = true;
- }
- }
-}
-
-pub struct DatabaseFile {
- buffer: Vec,
- data_dir: PathBuf,
-}
-
-impl DatabaseFile {
- pub fn new>(data_dir: P) -> Self {
- DatabaseFile { buffer: Vec::new(), data_dir: data_dir.into() }
- }
-
- pub fn open(&mut self) -> Result {
- // Read the entire database to memory. For smaller files, this is faster than
- // mmap / streaming, and allows for zero-copy deserialization.
- let path = db_path(&self.data_dir);
match fs::read(&path) {
- Ok(buffer) => {
- self.buffer = buffer;
- let dirs = DirList::from_bytes(&self.buffer)
- .with_context(|| format!("could not deserialize database: {}", path.display()))?;
- Ok(Database { dirs, modified: false, data_dir: &self.data_dir })
- }
+ Ok(bytes) => Self::try_new(path, bytes, |bytes| Self::deserialize(bytes), false),
Err(e) if e.kind() == io::ErrorKind::NotFound => {
// Create data directory, but don't create any file yet. The file will be created
// later by [`Database::save`] if any data is modified.
- fs::create_dir_all(&self.data_dir)
- .with_context(|| format!("unable to create data directory: {}", self.data_dir.display()))?;
- Ok(Database { dirs: DirList::new(), modified: false, data_dir: &self.data_dir })
+ fs::create_dir_all(data_dir)
+ .with_context(|| format!("unable to create data directory: {}", data_dir.display()))?;
+ Ok(Self::new(path, Vec::new(), |_| Vec::new(), false))
}
Err(e) => Err(e).with_context(|| format!("could not read from database: {}", path.display())),
}
}
-}
-fn db_path>(data_dir: P) -> PathBuf {
- const DB_FILENAME: &str = "db.zo";
- data_dir.as_ref().join(DB_FILENAME)
+ pub fn save(&mut self) -> Result<()> {
+ // Only write to disk if the database is modified.
+ if !self.dirty() {
+ return Ok(());
+ }
+
+ let bytes = Self::serialize(self.dirs())?;
+ util::write(self.borrow_path(), bytes).context("could not write to database")?;
+ self.with_dirty_mut(|dirty| *dirty = false);
+
+ Ok(())
+ }
+
+ /// Increments the rank of a directory, or creates it if it does not exist.
+ pub fn add(&mut self, path: impl AsRef + Into, by: Rank, now: Epoch) {
+ self.with_dirs_mut(|dirs| match dirs.iter_mut().find(|dir| dir.path == path.as_ref()) {
+ Some(dir) => dir.rank = (dir.rank + by).max(0.0),
+ None => dirs.push(Dir { path: path.into().into(), rank: by.max(0.0), last_accessed: now }),
+ });
+ self.with_dirty_mut(|dirty| *dirty = true);
+ }
+
+ /// 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
+ /// does a check before calling this, or calls `dedup()` afterward.
+ pub fn add_unchecked(&mut self, path: impl AsRef + Into, rank: Rank, now: Epoch) {
+ self.with_dirs_mut(|dirs| dirs.push(Dir { path: path.into().into(), rank, last_accessed: now }));
+ self.with_dirty_mut(|dirty| *dirty = true);
+ }
+
+ /// Increments the rank and updates the last_accessed of a directory, or
+ /// creates it if it does not exist.
+ pub fn add_update(&mut self, path: impl AsRef + Into, by: Rank, now: Epoch) {
+ self.with_dirs_mut(|dirs| match dirs.iter_mut().find(|dir| dir.path == path.as_ref()) {
+ Some(dir) => {
+ dir.rank = (dir.rank + by).max(0.0);
+ dir.last_accessed = now;
+ }
+ None => dirs.push(Dir { path: path.into().into(), rank: by.max(0.0), last_accessed: now }),
+ });
+ self.with_dirty_mut(|dirty| *dirty = true);
+ }
+
+ /// Removes the directory with `path` from the store. This does not preserve
+ /// ordering, but is O(1).
+ pub fn remove(&mut self, path: impl AsRef) -> bool {
+ match self.dirs().iter().position(|dir| dir.path == path.as_ref()) {
+ Some(idx) => {
+ self.swap_remove(idx);
+ true
+ }
+ None => false,
+ }
+ }
+
+ pub fn swap_remove(&mut self, idx: usize) {
+ self.with_dirs_mut(|dirs| dirs.swap_remove(idx));
+ self.with_dirty_mut(|dirty| *dirty = true);
+ }
+
+ pub fn age(&mut self, max_age: Rank) {
+ let mut dirty = false;
+ self.with_dirs_mut(|dirs| {
+ let total_age = dirs.iter().map(|dir| dir.rank).sum::();
+ if total_age > max_age {
+ let factor = 0.9 * max_age / total_age;
+ for idx in (0..dirs.len()).rev() {
+ let dir = &mut dirs[idx];
+ dir.rank *= factor;
+ if dir.rank < 1.0 {
+ dirs.swap_remove(idx);
+ }
+ }
+ dirty = true;
+ }
+ });
+ self.with_dirty_mut(|dirty_prev| *dirty_prev |= dirty);
+ }
+
+ pub fn stream(&mut self, now: Epoch) -> Stream {
+ Stream::new(self, now)
+ }
+
+ pub fn dedup(&mut self) {
+ // Sort by path, so that equal paths are next to each other.
+ self.sort_by_path();
+
+ let mut dirty = false;
+ self.with_dirs_mut(|dirs| {
+ for idx in (1..dirs.len()).rev() {
+ // Check if curr_dir and next_dir have equal paths.
+ let curr_dir = &dirs[idx];
+ let next_dir = &dirs[idx - 1];
+ if next_dir.path != curr_dir.path {
+ continue;
+ }
+
+ // Merge curr_dir's rank and last_accessed into next_dir.
+ let rank = curr_dir.rank;
+ let last_accessed = curr_dir.last_accessed;
+ let next_dir = &mut dirs[idx - 1];
+ next_dir.last_accessed = next_dir.last_accessed.max(last_accessed);
+ next_dir.rank += rank;
+
+ // Delete curr_dir.
+ dirs.swap_remove(idx);
+ dirty = true;
+ }
+ });
+ self.with_dirty_mut(|dirty_prev| *dirty_prev |= dirty);
+ }
+
+ pub fn sort_by_path(&mut self) {
+ self.with_dirs_mut(|dirs| dirs.sort_unstable_by(|dir1, dir2| dir1.path.cmp(&dir2.path)));
+ self.with_dirty_mut(|dirty| *dirty = true);
+ }
+
+ pub fn sort_by_score(&mut self, now: Epoch) {
+ self.with_dirs_mut(|dirs| {
+ dirs.sort_unstable_by(|dir1: &Dir, dir2: &Dir| dir1.score(now).total_cmp(&dir2.score(now)))
+ });
+ self.with_dirty_mut(|dirty| *dirty = true);
+ }
+
+ pub fn dirty(&self) -> bool {
+ *self.borrow_dirty()
+ }
+
+ pub fn dirs(&self) -> &[Dir] {
+ self.borrow_dirs()
+ }
+
+ fn serialize(dirs: &[Dir<'_>]) -> Result> {
+ (|| -> bincode::Result<_> {
+ // Preallocate buffer with combined size of sections.
+ let buffer_size = bincode::serialized_size(&Self::VERSION)? + bincode::serialized_size(&dirs)?;
+ let mut buffer = Vec::with_capacity(buffer_size as usize);
+
+ // Serialize sections into buffer.
+ bincode::serialize_into(&mut buffer, &Self::VERSION)?;
+ bincode::serialize_into(&mut buffer, &dirs)?;
+
+ Ok(buffer)
+ })()
+ .context("could not serialize database")
+ }
+
+ fn deserialize(bytes: &[u8]) -> Result> {
+ // Assume a maximum size for the database. This prevents bincode from throwing strange
+ // errors when it encounters invalid data.
+ const MAX_SIZE: u64 = 32 << 20; // 32 MiB
+ let deserializer = &mut bincode::options().with_fixint_encoding().with_limit(MAX_SIZE);
+
+ // Split bytes into sections.
+ let version_size = deserializer.serialized_size(&Self::VERSION).unwrap() as _;
+ if bytes.len() < version_size {
+ bail!("could not deserialize database: corrupted data");
+ }
+ let (bytes_version, bytes_dirs) = bytes.split_at(version_size);
+
+ // Deserialize sections.
+ let version = deserializer.deserialize(bytes_version)?;
+ let dirs = match version {
+ Self::VERSION => deserializer.deserialize(bytes_dirs).context("could not deserialize database")?,
+ version => {
+ bail!("unsupported version (got {version}, supports {})", Self::VERSION)
+ }
+ };
+
+ Ok(dirs)
+ }
}
#[cfg(test)]
@@ -149,50 +226,49 @@ mod tests {
#[test]
fn add() {
+ let data_dir = tempfile::tempdir().unwrap();
let path = if cfg!(windows) { r"C:\foo\bar" } else { "/foo/bar" };
let now = 946684800;
- let data_dir = tempfile::tempdir().unwrap();
{
- let mut db = DatabaseFile::new(data_dir.path());
- let mut db = db.open().unwrap();
- db.add(path, now);
- db.add(path, now);
+ let mut db = Database::open_dir(data_dir.path()).unwrap();
+ db.add(path, 1.0, now);
+ db.add(path, 1.0, now);
db.save().unwrap();
}
- {
- let mut db = DatabaseFile::new(data_dir.path());
- let db = db.open().unwrap();
- assert_eq!(db.dirs.len(), 1);
- let dir = &db.dirs[0];
+ {
+ let db = Database::open_dir(data_dir.path()).unwrap();
+ assert_eq!(db.dirs().len(), 1);
+
+ let dir = &db.dirs()[0];
assert_eq!(dir.path, path);
+ assert!((dir.rank - 2.0).abs() < 0.01);
assert_eq!(dir.last_accessed, now);
}
}
#[test]
fn remove() {
+ let data_dir = tempfile::tempdir().unwrap();
let path = if cfg!(windows) { r"C:\foo\bar" } else { "/foo/bar" };
let now = 946684800;
- let data_dir = tempfile::tempdir().unwrap();
{
- let mut db = DatabaseFile::new(data_dir.path());
- let mut db = db.open().unwrap();
- db.add(path, now);
+ let mut db = Database::open_dir(data_dir.path()).unwrap();
+ db.add(path, 1.0, now);
db.save().unwrap();
}
+
{
- let mut db = DatabaseFile::new(data_dir.path());
- let mut db = db.open().unwrap();
+ let mut db = Database::open_dir(data_dir.path()).unwrap();
assert!(db.remove(path));
db.save().unwrap();
}
+
{
- let mut db = DatabaseFile::new(data_dir.path());
- let mut db = db.open().unwrap();
- assert!(db.dirs.is_empty());
+ let mut db = Database::open_dir(data_dir.path()).unwrap();
+ assert!(db.dirs().is_empty());
assert!(!db.remove(path));
db.save().unwrap();
}
diff --git a/src/db/stream.rs b/src/db/stream.rs
index 275d52e..cdd280d 100644
--- a/src/db/stream.rs
+++ b/src/db/stream.rs
@@ -3,10 +3,10 @@ use std::ops::Range;
use std::{fs, path};
use crate::db::{Database, Dir, Epoch};
-use crate::util;
+use crate::util::{self, MONTH};
-pub struct Stream<'db, 'file> {
- db: &'db mut Database<'file>,
+pub struct Stream<'a> {
+ db: &'a mut Database,
idxs: Rev>,
keywords: Vec,
@@ -18,14 +18,14 @@ pub struct Stream<'db, 'file> {
exclude_path: Option,
}
-impl<'db, 'file> Stream<'db, 'file> {
- pub fn new(db: &'db mut Database<'file>, now: Epoch) -> Self {
- // Iterate in descending order of score.
- db.dirs.sort_unstable_by(|dir1, dir2| dir1.score(now).total_cmp(&dir2.score(now)));
- let idxs = (0..db.dirs.len()).rev();
+impl<'a> Stream<'a> {
+ pub fn new(db: &'a mut Database, now: Epoch) -> Self {
+ db.sort_by_score(now);
+ let idxs = (0..db.dirs().len()).rev();
- // If a directory is deleted and hasn't been used for 90 days, delete it from the database.
- let expire_below = now.saturating_sub(90 * 24 * 60 * 60);
+ // If a directory is deleted and hasn't been used for 3 months, delete
+ // it from the database.
+ let expire_below = now.saturating_sub(3 * MONTH);
Stream {
db,
@@ -54,9 +54,9 @@ impl<'db, 'file> Stream<'db, 'file> {
self
}
- pub fn next(&mut self) -> Option<&Dir<'file>> {
+ pub fn next(&mut self) -> Option<&Dir> {
while let Some(idx) = self.idxs.next() {
- let dir = &self.db.dirs[idx];
+ let dir = &self.db.dirs()[idx];
if !self.matches_keywords(&dir.path) {
continue;
@@ -64,8 +64,7 @@ impl<'db, 'file> Stream<'db, 'file> {
if !self.matches_exists(&dir.path) {
if dir.last_accessed < self.expire_below {
- self.db.dirs.swap_remove(idx);
- self.db.modified = true;
+ self.db.swap_remove(idx);
}
continue;
}
@@ -74,7 +73,7 @@ impl<'db, 'file> Stream<'db, 'file> {
continue;
}
- let dir = &self.db.dirs[idx];
+ let dir = &self.db.dirs()[idx];
return Some(dir);
}
@@ -147,8 +146,8 @@ mod tests {
#[case(&["/foo/", "/bar"], "/foo/bar", false)]
#[case(&["/foo/", "/bar"], "/foo/baz/bar", true)]
fn query(#[case] keywords: &[&str], #[case] path: &str, #[case] is_match: bool) {
- let mut db = Database { dirs: Vec::new().into(), modified: false, data_dir: &PathBuf::new() };
- let stream = db.stream(0).with_keywords(keywords);
+ let db = &mut Database::new(PathBuf::new(), Vec::new(), |_| Vec::new(), false);
+ let stream = Stream::new(db, 0).with_keywords(keywords);
assert_eq!(is_match, stream.matches_keywords(path));
}
}
diff --git a/src/util.rs b/src/util.rs
index 9e4cef7..7bf1bff 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -1,7 +1,8 @@
+use std::ffi::OsStr;
use std::fs::{self, File, OpenOptions};
use std::io::{self, Read, Write};
use std::path::{Component, Path, PathBuf};
-use std::process::{Child, ChildStdin, Command, Stdio};
+use std::process::{Child, Command, Stdio};
use std::time::SystemTime;
use std::{env, mem};
@@ -9,88 +10,133 @@ use std::{env, mem};
use anyhow::anyhow;
use anyhow::{bail, Context, Result};
-use crate::config;
-use crate::db::Epoch;
+use crate::db::{Dir, Epoch};
use crate::error::SilentExit;
-pub struct Fzf {
- child: Child,
-}
+pub const SECOND: Epoch = 1;
+pub const MINUTE: Epoch = 60 * SECOND;
+pub const HOUR: Epoch = 60 * MINUTE;
+pub const DAY: Epoch = 24 * HOUR;
+pub const WEEK: Epoch = 7 * DAY;
+pub const MONTH: Epoch = 30 * DAY;
+
+pub struct Fzf(Command);
impl Fzf {
- pub fn new(multiple: bool) -> Result {
- const ERR_FZF_NOT_FOUND: &str = "could not find fzf, is it installed?";
+ const ERR_FZF_NOT_FOUND: &str = "could not find fzf, is it installed?";
+ pub fn new() -> Result {
// On Windows, CreateProcess implicitly searches the current working
// directory for the executable, which is a potential security issue.
// Instead, we resolve the path to the executable and then pass it to
// CreateProcess.
#[cfg(windows)]
- let mut command = Command::new(which::which("fzf.exe").map_err(|_| anyhow!(ERR_FZF_NOT_FOUND))?);
+ let program = which::which("fzf.exe").map_err(|_| anyhow!(Self::ERR_FZF_NOT_FOUND))?;
#[cfg(not(windows))]
- let mut command = Command::new("fzf");
- if multiple {
- command.arg("--multi");
- } else {
- command.arg("--bind=tab:down,btab:up");
- }
- command.arg("--nth=2..").stdin(Stdio::piped()).stdout(Stdio::piped());
- if let Some(fzf_opts) = config::fzf_opts() {
- command.env("FZF_DEFAULT_OPTS", fzf_opts);
- } else {
- command.args([
- // Search result
- "--no-sort",
- // Interface
- "--cycle",
- "--keep-right",
- // Layout
- "--height=50%",
- "--info=inline",
- "--layout=reverse",
- // Scripting
- "--exit-0",
- "--select-1",
- // Key/Event bindings
- "--bind=ctrl-z:ignore",
- ]);
- if cfg!(unix) {
- // Non-POSIX args are only available on certain operating systems.
- const PREVIEW_CMD: &str = if cfg!(target_os = "linux") {
- r"\command -p ls -Cp --color=always --group-directories-first {2..}"
- } else {
- r"\command -p ls -Cp {2..}"
- };
- command.args(["--preview", PREVIEW_CMD, "--preview-window=down,30%"]).envs([
- ("CLICOLOR", "1"),
- ("CLICOLOR_FORCE", "1"),
- ("SHELL", "sh"),
- ]);
- }
- }
+ let program = "fzf";
- let child = match command.spawn() {
- Ok(child) => child,
- Err(e) if e.kind() == io::ErrorKind::NotFound => bail!(ERR_FZF_NOT_FOUND),
- Err(e) => Err(e).context("could not launch fzf")?,
- };
+ let mut cmd = Command::new(program);
+ cmd.args([
+ // Search mode
+ "--delimiter=\t",
+ "--nth=2",
+ // Scripting
+ "--read0",
+ ])
+ .stdin(Stdio::piped())
+ .stdout(Stdio::piped());
- Ok(Fzf { child })
+ Ok(Fzf(cmd))
}
- pub fn stdin(&mut self) -> &mut ChildStdin {
- self.child.stdin.as_mut().unwrap()
+ pub fn enable_preview(&mut self) -> &mut Self {
+ // Previews are only supported on UNIX.
+ if !cfg!(unix) {
+ return self;
+ }
+
+ self.args([
+ // Non-POSIX args are only available on certain operating systems.
+ if cfg!(target_os = "linux") {
+ r"--preview=\command -p ls -Cp --color=always --group-directories-first {2..}"
+ } else {
+ r"--preview=\command -p ls -Cp {2..}"
+ },
+ // Rounded edges don't display correctly on some terminals.
+ "--preview-window=down,30%,sharp",
+ ])
+ .envs([
+ // Enables colorized `ls` output on macOS / FreeBSD.
+ ("CLICOLOR", "1"),
+ // Forces colorized `ls` output when the output is not a
+ // TTY (like in fzf's preview window) on macOS /
+ // FreeBSD.
+ ("CLICOLOR_FORCE", "1"),
+ // Ensures that the preview command is run in a
+ // POSIX-compliant shell, regardless of what shell the
+ // user has selected.
+ ("SHELL", "sh"),
+ ])
}
- pub fn select(mut self) -> Result {
+ pub fn args(&mut self, args: I) -> &mut Self
+ where
+ I: IntoIterator- ,
+ S: AsRef,
+ {
+ self.0.args(args);
+ self
+ }
+
+ pub fn env(&mut self, key: K, val: V) -> &mut Self
+ where
+ K: AsRef,
+ V: AsRef,
+ {
+ self.0.env(key, val);
+ self
+ }
+
+ pub fn envs(&mut self, vars: I) -> &mut Self
+ where
+ I: IntoIterator
- ,
+ K: AsRef,
+ V: AsRef,
+ {
+ self.0.envs(vars);
+ self
+ }
+
+ pub fn spawn(&mut self) -> Result {
+ match self.0.spawn() {
+ Ok(child) => Ok(FzfChild(child)),
+ Err(e) if e.kind() == io::ErrorKind::NotFound => bail!(Self::ERR_FZF_NOT_FOUND),
+ Err(e) => Err(e).context("could not launch fzf"),
+ }
+ }
+}
+
+pub struct FzfChild(Child);
+
+impl FzfChild {
+ pub fn write(&mut self, dir: &Dir, now: Epoch) -> Result