diff --git a/src/shell.rs b/src/shell.rs index 8812b1c..3b2f38d 100644 --- a/src/shell.rs +++ b/src/shell.rs @@ -36,6 +36,10 @@ make_template!(Zsh, "zsh.txt"); #[cfg(feature = "nix-dev")] #[cfg(test)] mod tests { + use std::fs; + #[cfg(unix)] + use std::os::unix::fs::{PermissionsExt, symlink}; + use askama::Template; use assert_cmd::Command; use rstest::rstest; @@ -343,4 +347,44 @@ mod tests { .stdout("") .stderr(""); } + + #[cfg(unix)] + #[test] + fn zsh_prefers_builtin_cd_for_symlink_relative_paths() { + let tempdir = tempfile::tempdir().unwrap(); + let tempdir = tempdir.path(); + let bin_dir = tempdir.join("bin"); + let query_log = tempdir.join("query.log"); + + fs::create_dir_all(&bin_dir).unwrap(); + fs::create_dir_all(tempdir.join("foo/bar")).unwrap(); + symlink("foo/bar", tempdir.join("baz")).unwrap(); + + let zoxide = bin_dir.join("zoxide"); + fs::write( + &zoxide, + format!("#!/bin/sh\nprintf '%s\\n' \"$*\" >> {}\nexit 1\n", query_log.display()), + ) + .unwrap(); + let mut permissions = fs::metadata(&zoxide).unwrap().permissions(); + permissions.set_mode(0o755); + fs::set_permissions(&zoxide, permissions).unwrap(); + + let opts = + Opts { cmd: Some("z"), hook: InitHook::None, echo: false, resolve_symlinks: false }; + let source = Zsh(&opts).render().unwrap(); + let script = format!("{source}\ncd -- \"$REPRO/baz\"\nz ../foo\nprintf '%s\\n' \"$PWD\"\n"); + let path = std::env::var("PATH").unwrap(); + + Command::new("zsh") + .env("PATH", format!("{}:{path}", bin_dir.display())) + .env("REPRO", tempdir) + .args(["-e", "-u", "-o", "pipefail", "--no-globalrcs", "--no-rcs", "-c", &script]) + .assert() + .success() + .stdout(format!("{}/foo\n", tempdir.display())) + .stderr(""); + + assert_eq!(fs::read_to_string(query_log).unwrap_or_default(), ""); + } } diff --git a/templates/zsh.txt b/templates/zsh.txt index a66f960..22b91af 100644 --- a/templates/zsh.txt +++ b/templates/zsh.txt @@ -88,8 +88,16 @@ function __zoxide_z() { __zoxide_doctor if [[ "$#" -eq 0 ]]; then __zoxide_cd ~ - elif [[ "$#" -eq 1 ]] && { [[ -d "$1" ]] || [[ "$1" = '-' ]] || [[ "$1" =~ ^[-+][0-9]+$ ]]; }; then - __zoxide_cd "$1" + elif [[ "$#" -eq 1 ]]; then + if [[ "$1" = '-' ]] || [[ "$1" =~ ^[-+][0-9]+$ ]]; then + __zoxide_cd "$1" + elif [[ -d "$1" ]]; then + __zoxide_cd "$1" + elif ! __zoxide_cd "$1" 2>/dev/null; then + \builtin local result + # shellcheck disable=SC2312 + result="$(\command zoxide query --exclude "$(__zoxide_pwd)" -- "$@")" && __zoxide_cd "${result}" + fi elif [[ "$#" -eq 2 ]] && [[ "$1" = "--" ]]; then __zoxide_cd "$2" else