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."""