From 09aa626a8653e758cda3f3cab8a6d8188e10cbd7 Mon Sep 17 00:00:00 2001
From: Ajeet D'Souza <98ajeet@gmail.com>
Date: Mon, 5 May 2025 22:58:54 -0700
Subject: [PATCH] Add support for csh (#1047)
---
CHANGELOG.md | 11 +++++
README.md | 2 +-
contrib/completions/_zoxide | 2 +-
contrib/completions/zoxide.bash | 2 +-
contrib/completions/zoxide.ts | 1 +
shell.nix | 5 ++-
src/cmd/cmd.rs | 5 ++-
src/cmd/init.rs | 3 +-
src/shell.rs | 15 +++++++
templates/bash.txt | 1 +
templates/csh.txt | 74 +++++++++++++++++++++++++++++++++
templates/xonsh.txt | 2 +-
12 files changed, 115 insertions(+), 8 deletions(-)
create mode 100644 templates/csh.txt
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d47ae49..4d67b22 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,10 +9,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
+### Added
+
+- Support for Csh.
+- Added `--score` flag to `zoxide add`.
+
### Changed
- Bash: zoxide will now rewrite the prompt when using Space-Tab completions.
+### Fixed
+
+- Nushell: stop ignoring symlinks when `cd`-ing into a directory.
+- Fzf: updated minimum supported version to v0.51.0.
+- PowerShell: avoid setting `$error` when defining `__zoxide_hooked`.
+
## [0.9.7] - 2025-02-10
### Added
diff --git a/README.md b/README.md
index fd20f32..5e3d883 100644
--- a/README.md
+++ b/README.md
@@ -323,7 +323,7 @@ zoxide can be installed in 4 easy steps:
interactive selection. It can be installed from [here][fzf-installation].
> **Note**
- > The minimum supported fzf version is v0.33.0 on most platforms and v0.51.0 on Windows.
+ > The minimum supported fzf version is v0.51.0.
4. **Import your data** (optional)
diff --git a/contrib/completions/_zoxide b/contrib/completions/_zoxide
index dbf0196..3bbb5cf 100644
--- a/contrib/completions/_zoxide
+++ b/contrib/completions/_zoxide
@@ -114,7 +114,7 @@ _arguments "${_arguments_options[@]}" : \
'--help[Print help]' \
'-V[Print version]' \
'--version[Print version]' \
-':shell:(bash elvish fish nushell posix powershell xonsh zsh)' \
+':shell:(bash csh elvish fish nushell posix powershell xonsh zsh)' \
&& ret=0
;;
(query)
diff --git a/contrib/completions/zoxide.bash b/contrib/completions/zoxide.bash
index 8c524aa..2601198 100644
--- a/contrib/completions/zoxide.bash
+++ b/contrib/completions/zoxide.bash
@@ -173,7 +173,7 @@ _zoxide() {
return 0
;;
zoxide__init)
- opts="-h -V --no-cmd --cmd --hook --help --version bash elvish fish nushell posix powershell xonsh zsh"
+ opts="-h -V --no-cmd --cmd --hook --help --version bash csh elvish fish nushell posix powershell xonsh zsh"
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 87003b9..88f034b 100644
--- a/contrib/completions/zoxide.ts
+++ b/contrib/completions/zoxide.ts
@@ -189,6 +189,7 @@ const completion: Fig.Spec = {
name: "shell",
suggestions: [
"bash",
+ "csh",
"elvish",
"fish",
"nushell",
diff --git a/shell.nix b/shell.nix
index b63d44c..b7b7400 100644
--- a/shell.nix
+++ b/shell.nix
@@ -1,10 +1,10 @@
let
pkgs = import (builtins.fetchTarball
- "https://github.com/NixOS/nixpkgs/archive/056faf24027e12f0ba6edebe299ed136e030d29a.tar.gz") {
+ "https://github.com/NixOS/nixpkgs/archive/ec9ef366451af88284d7dfd18ee017b7e86a0710.tar.gz") {
overlays = [ rust ];
};
rust = import (builtins.fetchTarball
- "https://github.com/oxalica/rust-overlay/archive/f61820fa2c3844d6940cce269a6afdec30aa2e6c.tar.gz");
+ "https://github.com/oxalica/rust-overlay/archive/026e8fedefd6b167d92ed04b195c658d95ffc7a5.tar.gz");
rust-nightly =
pkgs.rust-bin.selectLatestNightlyWith (toolchain: toolchain.minimal);
@@ -27,6 +27,7 @@ in pkgs.mkShell {
pkgs.ksh
pkgs.nushell
pkgs.powershell
+ pkgs.tcsh
pkgs.xonsh
pkgs.zsh
diff --git a/src/cmd/cmd.rs b/src/cmd/cmd.rs
index 184a5f2..6b79c5c 100644
--- a/src/cmd/cmd.rs
+++ b/src/cmd/cmd.rs
@@ -59,7 +59,8 @@ pub struct Add {
#[clap(num_args = 1.., required = true, value_hint = ValueHint::DirPath)]
pub paths: Vec,
- /// The rank to increment the entry if it exists or initialize it with if it doesn't
+ /// The rank to increment the entry if it exists or initialize it with if it
+ /// doesn't
#[clap(short, long)]
pub score: Option,
}
@@ -146,6 +147,8 @@ pub enum InitHook {
#[derive(ValueEnum, Clone, Debug)]
pub enum InitShell {
Bash,
+ #[clap(alias = "tcsh")]
+ Csh,
Elvish,
Fish,
Nushell,
diff --git a/src/cmd/init.rs b/src/cmd/init.rs
index 3f79ed6..6c15831 100644
--- a/src/cmd/init.rs
+++ b/src/cmd/init.rs
@@ -6,7 +6,7 @@ use rinja::Template;
use crate::cmd::{Init, InitShell, Run};
use crate::config;
use crate::error::BrokenPipeHandler;
-use crate::shell::{Bash, Elvish, Fish, Nushell, Opts, Posix, Powershell, Xonsh, Zsh};
+use crate::shell::{Bash, Csh, Elvish, Fish, Nushell, Opts, Posix, Powershell, Xonsh, Zsh};
impl Run for Init {
fn run(&self) -> Result<()> {
@@ -17,6 +17,7 @@ impl Run for Init {
let source = match self.shell {
InitShell::Bash => Bash(opts).render(),
+ InitShell::Csh => Csh(opts).render(),
InitShell::Elvish => Elvish(opts).render(),
InitShell::Fish => Fish(opts).render(),
InitShell::Nushell => Nushell(opts).render(),
diff --git a/src/shell.rs b/src/shell.rs
index 721553d..78bf2f3 100644
--- a/src/shell.rs
+++ b/src/shell.rs
@@ -24,6 +24,7 @@ macro_rules! make_template {
}
make_template!(Bash, "bash.txt");
+make_template!(Csh, "csh.txt");
make_template!(Elvish, "elvish.txt");
make_template!(Fish, "fish.txt");
make_template!(Nushell, "nushell.txt");
@@ -93,6 +94,20 @@ mod tests {
.stderr("");
}
+ #[apply(opts)]
+ fn csh_tcsh(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
+ let opts = Opts { cmd, hook, echo, resolve_symlinks };
+ let source = Csh(&opts).render().unwrap();
+
+ Command::new("tcsh")
+ .args(["-e", "-f", "-s"])
+ .write_stdin(source)
+ .assert()
+ .success()
+ .stdout("")
+ .stderr("");
+ }
+
#[apply(opts)]
fn elvish_elvish(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
let opts = Opts { cmd, hook, echo, resolve_symlinks };
diff --git a/templates/bash.txt b/templates/bash.txt
index a4177a8..162ca6c 100644
--- a/templates/bash.txt
+++ b/templates/bash.txt
@@ -160,6 +160,7 @@ if [[ ${BASH_VERSINFO[0]:-0} -eq 4 && ${BASH_VERSINFO[1]:-0} -ge 4 || ${BASH_VER
\builtin bind '"\e[0n": redraw-current-line'
\builtin printf '\e[5n'
+ # shellcheck disable=SC2016
\builtin bind -x '"\e[0n": __zoxide_z_complete_helper "${result}"'
\builtin printf '\e[5n'
}
diff --git a/templates/csh.txt b/templates/csh.txt
new file mode 100644
index 0000000..1145052
--- /dev/null
+++ b/templates/csh.txt
@@ -0,0 +1,74 @@
+{%- let section = "# =============================================================================\n#" -%}
+{%- let not_configured = "# -- not configured --" -%}
+
+{%- let pwd_cmd -%}
+{%- if resolve_symlinks -%}
+{%- let pwd_cmd = "pwd -P" -%}
+{%- else -%}
+{%- let pwd_cmd = "pwd -L" -%}
+{%- endif -%}
+
+{{ section }}
+# Hook configuration for zoxide.
+#
+{%- if hook != InitHook::None %}
+
+# Hook to add new entries to the database.
+{%- if hook == InitHook::Prompt %}
+alias __zoxide_hook 'zoxide add -- "`{{ pwd_cmd }}`"'
+
+{%- else if hook == InitHook::Pwd %}
+set __zoxide_pwd_old = `{{ pwd_cmd }}`
+alias __zoxide_hook 'set __zoxide_pwd_tmp = "`{{ pwd_cmd }}`"; test "$__zoxide_pwd_tmp" != "$__zoxide_pwd_old" && zoxide add -- "$__zoxide_pwd_tmp"; set __zoxide_pwd_old = "$__zoxide_pwd_tmp"'
+{%- endif %}
+
+# Initialize hook.
+alias precmd ';__zoxide_hook'
+
+{%- endif %}
+
+{{ section }}
+# When using zoxide with --no-cmd, alias these internal functions as desired.
+#
+
+# Jump to a directory using only keywords.
+alias __zoxide_z 'set __zoxide_args = (\!*)\
+if ("$#__zoxide_args" == 0) then\
+ cd ~\
+else\
+ if ("$#__zoxide_args" == 1 && "$__zoxide_args[1]" == "-") then\
+ cd -\
+ else if ("$#__zoxide_args" == 1 && -d "$__zoxide_args[1]") then\
+ cd "$__zoxide_args[1]"\
+ else\
+ set __zoxide_pwd = `{{ pwd_cmd }}`\
+ set __zoxide_result = "`zoxide query --exclude '"'"'$__zoxide_pwd'"'"' -- $__zoxide_args`" && cd "$__zoxide_result"\
+ endif\
+endif'
+
+# Jump to a directory using interactive search.
+alias __zoxide_zi 'set __zoxide_args = (\!*)\
+set __zoxide_pwd = `{{ pwd_cmd }}`\
+set __zoxide_result = "`zoxide query --exclude '"'"'$__zoxide_pwd'"'"' --interactive -- $__zoxide_args`" && cd "$__zoxide_result"'
+
+{{ section }}
+# Commands for zoxide. Disable these using --no-cmd.
+#
+
+{%- match cmd %}
+{%- when Some with (cmd) %}
+
+alias {{cmd}} __zoxide_z
+alias {{cmd}}i __zoxide_zi
+
+{%- when None %}
+
+{{ not_configured }}
+
+{%- endmatch %}
+
+{{ section }}
+# To initialize zoxide, add this to your shell configuration file (usually ~/.cshrc or ~/.tcshrc):
+#
+# zoxide init csh > ~/.zoxide.csh
+# source ~/.zoxide.csh
diff --git a/templates/xonsh.txt b/templates/xonsh.txt
index c769795..f5c92f2 100644
--- a/templates/xonsh.txt
+++ b/templates/xonsh.txt
@@ -64,7 +64,7 @@ class ZoxideSilentException(Exception):
def __zoxide_errhandler(
- func: typing.Callable[[list[str]], None]
+ func: typing.Callable[[list[str]], None],
) -> typing.Callable[[list[str]], int]:
"""Print exception and exit with error code 1."""