From 85b2596b2974274c2a8e0ff96923a829ae2d6eed Mon Sep 17 00:00:00 2001 From: mataha Date: Wed, 10 May 2023 23:40:23 +0200 Subject: [PATCH 01/35] Add support for `cmd.exe` (experimental) --- CHANGELOG.md | 1 + contrib/completions/_zoxide | 2 +- contrib/completions/zoxide.bash | 2 +- contrib/completions/zoxide.nu | 2 +- contrib/completions/zoxide.ts | 1 + src/cmd/cmd.rs | 1 + src/cmd/init.rs | 3 +- src/shell.rs | 17 ++++ templates/cmd.txt | 156 ++++++++++++++++++++++++++++++++ 9 files changed, 181 insertions(+), 4 deletions(-) create mode 100644 templates/cmd.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b38fe2..7fb191c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - POSIX: support for non-Cygwin Windows environments (e.g. Busybox). +- Support for `cmd.exe` (experimental). ### Fixed diff --git a/contrib/completions/_zoxide b/contrib/completions/_zoxide index 97e654f..0db28b6 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 tcsh xonsh zsh)' \ +':shell:(bash cmd elvish fish nushell posix powershell tcsh xonsh zsh)' \ && ret=0 ;; (query) diff --git a/contrib/completions/zoxide.bash b/contrib/completions/zoxide.bash index 82b174e..8336144 100644 --- a/contrib/completions/zoxide.bash +++ b/contrib/completions/zoxide.bash @@ -177,7 +177,7 @@ _zoxide() { return 0 ;; zoxide__init) - opts="-h -V --no-cmd --cmd --hook --help --version bash elvish fish nushell posix powershell tcsh xonsh zsh" + opts="-h -V --no-cmd --cmd --hook --help --version bash cmd elvish fish nushell posix powershell tcsh xonsh zsh" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/contrib/completions/zoxide.nu b/contrib/completions/zoxide.nu index 642908e..334de3f 100644 --- a/contrib/completions/zoxide.nu +++ b/contrib/completions/zoxide.nu @@ -57,7 +57,7 @@ module completions { ] def "nu-complete zoxide init shell" [] { - [ "bash" "elvish" "fish" "nushell" "posix" "powershell" "tcsh" "xonsh" "zsh" ] + [ "bash" "cmd" "elvish" "fish" "nushell" "posix" "powershell" "tcsh" "xonsh" "zsh" ] } def "nu-complete zoxide init hook" [] { diff --git a/contrib/completions/zoxide.ts b/contrib/completions/zoxide.ts index 1e0d404..5ca0596 100644 --- a/contrib/completions/zoxide.ts +++ b/contrib/completions/zoxide.ts @@ -189,6 +189,7 @@ const completion: Fig.Spec = { name: "shell", suggestions: [ "bash", + "cmd", "elvish", "fish", "nushell", diff --git a/src/cmd/cmd.rs b/src/cmd/cmd.rs index 7359786..8fe0819 100644 --- a/src/cmd/cmd.rs +++ b/src/cmd/cmd.rs @@ -147,6 +147,7 @@ pub enum InitHook { #[derive(ValueEnum, Clone, Debug)] pub enum InitShell { Bash, + Cmd, Elvish, Fish, Nushell, diff --git a/src/cmd/init.rs b/src/cmd/init.rs index 980513e..2fc7efc 100644 --- a/src/cmd/init.rs +++ b/src/cmd/init.rs @@ -6,7 +6,7 @@ use askama::Template; use crate::cmd::{Init, InitShell, Run}; use crate::config; use crate::error::BrokenPipeHandler; -use crate::shell::{Bash, Elvish, Fish, Nushell, Opts, Posix, Powershell, Tcsh, Xonsh, Zsh}; +use crate::shell::{Bash, Cmd, Elvish, Fish, Nushell, Opts, Posix, Powershell, Tcsh, 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::Cmd => Cmd(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 8812b1c..ac15d17 100644 --- a/src/shell.rs +++ b/src/shell.rs @@ -24,6 +24,7 @@ macro_rules! make_template { } make_template!(Bash, "bash.txt"); +make_template!(Cmd, "cmd.txt"); make_template!(Elvish, "elvish.txt"); make_template!(Fish, "fish.txt"); make_template!(Nushell, "nushell.txt"); @@ -94,6 +95,22 @@ mod tests { .stderr(""); } + #[apply(opts)] + fn cmd_cmd(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) { + let opts = Opts { cmd, hook, echo, resolve_symlinks }; + let mut source = Cmd(&opts).render().unwrap(); + + // @TODO test this sometime, somehow + let tempfile = tempfile::tempfile(); + + Command::new("cmd") + .args(["/c", &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/cmd.txt b/templates/cmd.txt new file mode 100644 index 0000000..9dc65ed --- /dev/null +++ b/templates/cmd.txt @@ -0,0 +1,156 @@ +{%- let section = "@rem ==========================================================================\n@rem" -%} +{%- let not_configured = "@rem -- not configured --" -%} +@setlocal EnableDelayedExpansion EnableExtensions & set "CMD=!CMDCMDLINE!" 2>nul +@if /i not "!CMD!"=="!CMD:/=!" (goto :EOF) else @if not defined DEBUG (echo off) +@reg query "HKCU\Software\Microsoft\Command Processor" /v "AutoRun" /z >nul 2>&1 +@if !ERRORLEVEL! equ 0 (endlocal & set "CMD_ENV=%~0") else (echo(cmd& goto :EOF) + +{{ section }} +@rem Utility functions for zoxide. +@rem + +@rem Full credits to jeb for this - https://stackoverflow.com/a/76213522/6724141 +set i_AS_$*=%%^^^^ in ("") do @for /f "delims=" %%i in (^^""$*%%~^^"^") + +set __ZOXIDE_CD=chdir /d +set __ZOXIDE_PWD=chdir + +@rem cd + custom logic based on the value of _ZO_ECHO. +doskey cd = ( ^ +{#- Full credits to jeb (see https://stackoverflow.com/a/76213522/6724141) #} + for %%^^^^ in ("") do @for /f "delims=" %%i in (^^""$*%%~^^"^") do @( ^ + if "%%~i"=="" ( ^ + if defined USERPROFILE ( ^ + if /i not "%%CD%%"=="%%USERPROFILE%%" ( ^ + %__ZOXIDE_CD% "%%USERPROFILE%%" ^&^& ^ +} +{%- if echo %} + %__ZOXIDE_PWD% ^&^& ^ +{%- endif %} +{% if hook != InitHook::None -%} + if defined __ZOXIDE_HOOK (%%__ZOXIDE_HOOK%%) ^&^& ^ +{%- endif %} + set "OLDCD=%%CD%%" ^ + ) ^ + ) ^ + ) else if "%%~i"=="-" ( ^ + if defined OLDCD ( ^ + if /i not "%%CD%%"=="%%OLDCD%%" ( ^ + %__ZOXIDE_CD% "%%OLDCD%%" ^&^& ^ +{%- if echo %} + %__ZOXIDE_PWD% ^&^& ^ +{%- endif %} +{% if hook != InitHook::None -%} + if defined __ZOXIDE_HOOK (%%__ZOXIDE_HOOK%%) ^&^& ^ +{%- endif %} + set "OLDCD=%%CD%%" ^ + ) ^ + ) ^ + ) else ( ^ + ( ^ + if /i not "%%CD%%"=="%%~fi" ( ^ + %__ZOXIDE_CD% %%~fi ^&^& ^ +{%- if echo %} + %__ZOXIDE_PWD% ^&^& ^ +{%- endif %} +{% if hook != InitHook::None -%} + if defined __ZOXIDE_HOOK (%%__ZOXIDE_HOOK%%) ^&^& ^ +{%- endif %} + set "OLDCD=%%CD%%" ^ + ) ^ + ) ^ + ) ^ + ) ^ +) + +doskey pwd = (%__ZOXIDE_PWD%) + +{{ section }} +@rem Hook configuration for zoxide. +@rem + +if not defined __ZOXIDE_HOOKED ( + set __ZOXIDE_HOOKED=1 +{% if hook == InitHook::None -%} + @rem {{ not_configured }} + set __ZOXIDE_HOOK= +{%- else -%} + @rem Initialize hook to add new entries to the database. + set __ZOXIDE_HOOK=for /f "delims=" %%z in ('%__ZOXIDE_PWD%') do (zoxide add -- "%%~fz ") +{%- endif %} +) + +{{ section }} +@rem Commands for zoxide. Disable these using --no-cmd. +@rem + +{%- match cmd %} +{%- when Some with (cmd) %} + +@rem Jump to a directory using only keywords. +doskey {{cmd}} = ( ^ + for %%^^^^ in ("") do @for /f "delims=" %%i in (^^""$*%%~^^"^") do @( ^ + if "%%~i"=="" ( ^ + if defined HOME ( ^ + if /i not "%%CD%%"=="%%HOME%%" ( ^ + %__CD% "%%HOME%%" ^&^& ^ +{%- if echo %} + %__ZOXIDE_PWD% ^&^& ^ +{%- endif %} + set "OLDCD=%%CD%%" ^&^& ^ + %__ZOXIDE_HOOK% ^ + ) ^ + ) ^ + ) else if "%%~i"=="-" ( ^ + if defined OLDCD ( ^ + if /i not "%%CD%%"=="%%OLDCD%%" ( ^ + %__CD% "%%OLDCD%%" ^&^& ^ +{%- if echo %} + %__ZOXIDE_PWD% ^&^& ^ +{%- endif %} + set "OLDCD=%%CD%%" ^&^& ^ + %__ZOXIDE_HOOK% ^ + ) ^ + ) ^ + ) else ( ^ + for /f "delims=" %%p in ('zoxide query --exclude "%%CD%%" -- "%%~i"') do @( ^ + if /i not "%%CD%%"=="%%~fp" ( ^ + %__CD% %%~fp ^&^& ^ +{%- if echo %} + %__ZOXIDE_PWD% ^&^& ^ +{%- endif %} + set "OLDCD=%%CD%%" ^&^& ^ + %__ZOXIDE_HOOK% ^ + ) ^ + ) ^ + ) ^ + ) ^ +) + +@rem Jump to a directory using interactive search. +doskey {{cmd}}i = ( ^ + for %%^^^^ in ("") do @for /f "delims=" %%i in (^^""$*%%~^^"^") do @( ^ + for /f "delims=" %%q in ('zoxide query --interactive -- "%%~i"') do @( ^ + %__CD% %%~fq ^&^& ^ +{%- if echo %} + %__ZOXIDE_PWD% ^&^& ^ +{%- endif %} + set "OLDCD=%%CD%%" ^&^& ^ + %__ZOXIDE_HOOK% ^ + ) ^ + ) ^ +) + +{%- when None %} + +{{ not_configured }} + +{%- endmatch %} + +{{ section }} +@rem To initialize zoxide, add the contents of the following command to your +@rem configuration: +@rem +@rem zoxide init cmd +@rem +@rem If you don't have one: From bf8429db6bbde0bb6dbb9b8d5d44a9ac66114b5e Mon Sep 17 00:00:00 2001 From: mataha Date: Thu, 11 May 2023 02:46:45 +0200 Subject: [PATCH 02/35] Mark template tests with `cfg` directives --- src/shell.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/shell.rs b/src/shell.rs index ac15d17..b934a91 100644 --- a/src/shell.rs +++ b/src/shell.rs @@ -55,6 +55,7 @@ mod tests { } #[apply(opts)] + #[cfg(unix)] fn bash_bash(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) { let opts = Opts { cmd, hook, echo, resolve_symlinks }; let source = Bash(&opts).render().unwrap(); @@ -67,6 +68,7 @@ mod tests { } #[apply(opts)] + #[cfg(unix)] fn bash_shellcheck(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) { let opts = Opts { cmd, hook, echo, resolve_symlinks }; let source = Bash(&opts).render().unwrap(); @@ -81,6 +83,7 @@ mod tests { } #[apply(opts)] + #[cfg(unix)] fn bash_shfmt(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) { let opts = Opts { cmd, hook, echo, resolve_symlinks }; let mut source = Bash(&opts).render().unwrap(); @@ -96,6 +99,7 @@ mod tests { } #[apply(opts)] + #[cfg(windows)] fn cmd_cmd(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) { let opts = Opts { cmd, hook, echo, resolve_symlinks }; let mut source = Cmd(&opts).render().unwrap(); @@ -112,6 +116,7 @@ mod tests { } #[apply(opts)] + #[cfg(unix)] fn elvish_elvish(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) { let opts = Opts { cmd, hook, echo, resolve_symlinks }; let mut source = String::new(); @@ -132,6 +137,7 @@ mod tests { } #[apply(opts)] + #[cfg(unix)] fn fish_no_builtin_abbr(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) { let opts = Opts { cmd, hook, echo, resolve_symlinks }; let source = Fish(&opts).render().unwrap(); @@ -142,6 +148,7 @@ mod tests { } #[apply(opts)] + #[cfg(unix)] fn fish_fish(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) { let opts = Opts { cmd, hook, echo, resolve_symlinks }; let source = Fish(&opts).render().unwrap(); @@ -159,6 +166,7 @@ mod tests { } #[apply(opts)] + #[cfg(unix)] fn fish_fishindent(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) { let opts = Opts { cmd, hook, echo, resolve_symlinks }; let mut source = Fish(&opts).render().unwrap(); @@ -177,6 +185,7 @@ mod tests { } #[apply(opts)] + #[cfg(unix)] fn nushell_nushell(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) { let opts = Opts { cmd, hook, echo, resolve_symlinks }; let source = Nushell(&opts).render().unwrap(); @@ -197,6 +206,7 @@ mod tests { } #[apply(opts)] + #[cfg(unix)] fn posix_bash(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) { let opts = Opts { cmd, hook, echo, resolve_symlinks }; let source = Posix(&opts).render().unwrap(); @@ -212,6 +222,7 @@ mod tests { } #[apply(opts)] + #[cfg(unix)] fn posix_dash(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) { let opts = Opts { cmd, hook, echo, resolve_symlinks }; let source = Posix(&opts).render().unwrap(); @@ -224,6 +235,7 @@ mod tests { } #[apply(opts)] + #[cfg(unix)] fn posix_shellcheck(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) { let opts = Opts { cmd, hook, echo, resolve_symlinks }; let source = Posix(&opts).render().unwrap(); @@ -238,6 +250,7 @@ mod tests { } #[apply(opts)] + #[cfg(unix)] fn posix_shfmt(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) { let opts = Opts { cmd, hook, echo, resolve_symlinks }; let mut source = Posix(&opts).render().unwrap(); @@ -253,6 +266,7 @@ mod tests { } #[apply(opts)] + #[cfg(unix)] fn powershell_pwsh(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) { let opts = Opts { cmd, hook, echo, resolve_symlinks }; let mut source = "Set-StrictMode -Version latest\n".to_string(); @@ -267,6 +281,7 @@ mod tests { } #[apply(opts)] + #[cfg(unix)] fn tcsh_tcsh(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) { let opts = Opts { cmd, hook, echo, resolve_symlinks }; let source = Tcsh(&opts).render().unwrap(); @@ -281,6 +296,7 @@ mod tests { } #[apply(opts)] + #[cfg(unix)] fn xonsh_black(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) { let opts = Opts { cmd, hook, echo, resolve_symlinks }; let mut source = Xonsh(&opts).render().unwrap(); @@ -295,6 +311,7 @@ mod tests { } #[apply(opts)] + #[cfg(unix)] fn xonsh_mypy(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) { let opts = Opts { cmd, hook, echo, resolve_symlinks }; let source = Xonsh(&opts).render().unwrap(); @@ -303,6 +320,7 @@ mod tests { } #[apply(opts)] + #[cfg(unix)] fn xonsh_pylint(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) { let opts = Opts { cmd, hook, echo, resolve_symlinks }; let mut source = Xonsh(&opts).render().unwrap(); @@ -317,6 +335,7 @@ mod tests { } #[apply(opts)] + #[cfg(unix)] fn xonsh_xonsh(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) { let opts = Opts { cmd, hook, echo, resolve_symlinks }; let source = Xonsh(&opts).render().unwrap(); @@ -334,6 +353,7 @@ mod tests { } #[apply(opts)] + #[cfg(unix)] fn zsh_shellcheck(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) { let opts = Opts { cmd, hook, echo, resolve_symlinks }; let source = Zsh(&opts).render().unwrap(); @@ -349,6 +369,7 @@ mod tests { } #[apply(opts)] + #[cfg(unix)] fn zsh_zsh(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) { let opts = Opts { cmd, hook, echo, resolve_symlinks }; let source = Zsh(&opts).render().unwrap(); From b3fa50fa891901c5f8ebb03ee9e0dc7cf3612cbb Mon Sep 17 00:00:00 2001 From: mataha Date: Tue, 6 Jun 2023 00:57:02 +0200 Subject: [PATCH 03/35] Update `dunce` to 1.0.4 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d137115..41c3217 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ bincode = "1.3.1" clap = { version = "4.3.0", features = ["derive"] } color-print = "0.3.4" dirs = "6.0.0" -dunce = "1.0.1" +dunce = "1.0.4" fastrand = "2.0.0" glob = "0.3.0" ouroboros = "0.18.3" From 80d870c071e27af72b1af26f97f2ac657b8e85fc Mon Sep 17 00:00:00 2001 From: mataha Date: Tue, 6 Jun 2023 01:00:03 +0200 Subject: [PATCH 04/35] Normalize path prefix on Windows --- src/util.rs | 63 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 15 deletions(-) diff --git a/src/util.rs b/src/util.rs index 996f61d..18d1c75 100644 --- a/src/util.rs +++ b/src/util.rs @@ -296,44 +296,77 @@ pub fn resolve_path(path: impl AsRef) -> Result { } } - fn get_drive_path(drive_letter: u8) -> PathBuf { - format!(r"{}:\", drive_letter as char).into() + fn get_drive_prefix_path(drive_letter: u8) -> PathBuf { + format!(r"{}:\", patch_drive_letter(drive_letter)).into() } - fn get_drive_relative(drive_letter: u8) -> Result { + fn get_drive_relative_path(drive_letter: u8) -> Result { let path = current_dir()?; if Some(drive_letter) == get_drive_letter(&path) { - return Ok(path); + return Ok(patch_drive_prefix(path)); } - if let Some(path) = env::var_os(format!("={}:", drive_letter as char)) { - return Ok(path.into()); + if let Some(path) = env::var_os(format!("={}:", patch_drive_letter(drive_letter))) { + return Ok(patch_drive_prefix(path.into())); } - let path = get_drive_path(drive_letter); + let path = get_drive_prefix_path(drive_letter); Ok(path) } + #[inline(always)] + fn patch_drive_letter(drive_letter: u8) -> char { + drive_letter.to_ascii_uppercase() as char + } + + // https://github.com/rust-lang/rust-analyzer/pull/14689 + fn patch_drive_prefix(path: PathBuf) -> PathBuf { + let mut components = path.components(); + + match components.next() { + Some(Component::Prefix(prefix)) => { + let prefix = match prefix.kind() { + Prefix::Disk(drive_letter) => { + format!(r"{}:", patch_drive_letter(drive_letter)) + } + Prefix::VerbatimDisk(drive_letter) => { + format!(r"\\?\{}:", patch_drive_letter(drive_letter)) + } + _ => return path, + }; + + let mut path = PathBuf::default(); + path.push(prefix); + path.extend(components); + path + } + _ => path, + } + } + match components.peek() { Some(Component::Prefix(prefix)) => match prefix.kind() { Prefix::Disk(drive_letter) => { - let disk = components.next().unwrap(); + components.next(); if components.peek() == Some(&Component::RootDir) { - let root = components.next().unwrap(); - stack.push(disk); - stack.push(root); + components.next(); + base_path = get_drive_prefix_path(drive_letter); } else { - base_path = get_drive_relative(drive_letter)?; - stack.extend(base_path.components()); + base_path = get_drive_relative_path(drive_letter)?; } + + stack.extend(base_path.components()); } Prefix::VerbatimDisk(drive_letter) => { components.next(); if components.peek() == Some(&Component::RootDir) { components.next(); + base_path = get_drive_prefix_path(drive_letter); + } else { + // Verbatim prefix without a root component? Likely not a legal path + bail!("illegal path: {}", path.display()); } - base_path = get_drive_path(drive_letter); stack.extend(base_path.components()); } _ => bail!("invalid path: {}", path.display()), @@ -345,7 +378,7 @@ pub fn resolve_path(path: impl AsRef) -> Result { let drive_letter = get_drive_letter(¤t_dir).with_context(|| { format!("could not get drive letter: {}", current_dir.display()) })?; - base_path = get_drive_path(drive_letter); + base_path = get_drive_prefix_path(drive_letter); stack.extend(base_path.components()); } _ => { From ba2c1345e4119c26d5b7764b1238e56a1202e369 Mon Sep 17 00:00:00 2001 From: mataha Date: Tue, 6 Jun 2023 01:00:25 +0200 Subject: [PATCH 05/35] Add tests for path prefix normalization --- src/util.rs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/util.rs b/src/util.rs index 18d1c75..f0c8cdb 100644 --- a/src/util.rs +++ b/src/util.rs @@ -415,3 +415,39 @@ pub fn to_lowercase(s: impl AsRef) -> String { let s = s.as_ref(); if s.is_ascii() { s.to_ascii_lowercase() } else { s.to_lowercase() } } + +#[cfg(test)] +#[cfg(windows)] +mod tests_win { + use std::path::PathBuf; + + use rstest::rstest; + + #[rstest] + #[case(r"c:\", r"C:\")] + #[case(r"C:\", r"C:\")] + #[case(r"c:\\.", r"C:\")] + #[case(r"c:\..", r"C:\")] + #[case(r"C:\.\.", r"C:\")] + #[case(r"\\?\C:\", r"C:\")] + #[case(r"\\?\c:\", r"C:\")] + #[case(r"\\?\C:\\\", r"C:\")] + #[case(r"\\?\c:\\.\", r"C:\")] + #[case(r"c:\Windows", r"C:\Windows")] + #[case(r"C:\WINDOWS", r"C:\WINDOWS")] + #[case(r"c:\\\Windows\.", r"C:\Windows")] + #[case(r"C:\$WinREAgent", r"C:\$WinREAgent")] + #[case(r"\\?\c:\\Windows\\.", r"C:\Windows")] + #[case(r"\\?\c:\..\.\windows", r"C:\windows")] + #[case(r"c:\Windows\System32\.", r"C:\Windows\System32")] + #[case(r"c:\WINDOWS\..\..\Windows", r"C:\Windows")] + #[case(r"c:\Windows\..\.\.\..\Temp\..\tmp", r"C:\tmp")] + #[case(r"c:\.\Windows\..\..\Program Files", r"C:\Program Files")] + #[case(r"\\?\C:\\$WinREAgent\\..\Program Files\.", r"C:\Program Files")] + fn resolve_path(#[case] absolute_path: &str, #[case] normalized_form: &str) { + let path = PathBuf::from(absolute_path); + let resolved_path = super::resolve_path(path).unwrap(); + assert_eq!(resolved_path.to_str().unwrap(), normalized_form); + } + +} From 6e88046442486dbd54812d5f7279a220598dd279 Mon Sep 17 00:00:00 2001 From: mataha Date: Tue, 6 Jun 2023 01:24:24 +0200 Subject: [PATCH 06/35] Make the test run --- src/shell.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/shell.rs b/src/shell.rs index b934a91..9bc5dac 100644 --- a/src/shell.rs +++ b/src/shell.rs @@ -104,11 +104,9 @@ mod tests { let opts = Opts { cmd, hook, echo, resolve_symlinks }; let mut source = Cmd(&opts).render().unwrap(); - // @TODO test this sometime, somehow - let tempfile = tempfile::tempfile(); - - Command::new("cmd") - .args(["/c", &source]) + Command::new("cmd.exe") + .args(["/a", "/d", "/e:on", "/q", "/v:off", "/k", "@doskey", "/macros:cmd.exe"]) + .write_stdin(source) .assert() .success() .stdout("") From 1a403b4322a18c39d34b464461d472a2532da446 Mon Sep 17 00:00:00 2001 From: mataha Date: Tue, 6 Jun 2023 01:33:19 +0200 Subject: [PATCH 07/35] Fix rustfmt errors --- src/shell.rs | 2 +- src/util.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/shell.rs b/src/shell.rs index 9bc5dac..2a690b8 100644 --- a/src/shell.rs +++ b/src/shell.rs @@ -102,7 +102,7 @@ mod tests { #[cfg(windows)] fn cmd_cmd(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) { let opts = Opts { cmd, hook, echo, resolve_symlinks }; - let mut source = Cmd(&opts).render().unwrap(); + let source = Cmd(&opts).render().unwrap(); Command::new("cmd.exe") .args(["/a", "/d", "/e:on", "/q", "/v:off", "/k", "@doskey", "/macros:cmd.exe"]) diff --git a/src/util.rs b/src/util.rs index f0c8cdb..d9bedc3 100644 --- a/src/util.rs +++ b/src/util.rs @@ -449,5 +449,4 @@ mod tests_win { let resolved_path = super::resolve_path(path).unwrap(); assert_eq!(resolved_path.to_str().unwrap(), normalized_form); } - } From 06c19d8d310e8bf7bee514724f41f8de63f87055 Mon Sep 17 00:00:00 2001 From: mataha Date: Tue, 6 Jun 2023 23:01:19 +0200 Subject: [PATCH 08/35] Make percent characters work in all contexts --- README.md | 11 ++ src/shell.rs | 3 +- templates/cmd.txt | 242 ++++++++++++++++++-------------------- templates/utils/batch.txt | 9 ++ 4 files changed, 138 insertions(+), 127 deletions(-) create mode 100644 templates/utils/batch.txt diff --git a/README.md b/README.md index b397f82..c700244 100644 --- a/README.md +++ b/README.md @@ -213,6 +213,17 @@ zoxide can be installed in 4 easy steps: +
+ `cmd.exe` + + > Add this to the **end** of your config file or AutoRun command: + > + > ```batchfile + > zoxide init cmd | cmd /d >nul + > ``` + +
+
Elvish diff --git a/src/shell.rs b/src/shell.rs index 2a690b8..01de293 100644 --- a/src/shell.rs +++ b/src/shell.rs @@ -105,11 +105,10 @@ mod tests { let source = Cmd(&opts).render().unwrap(); Command::new("cmd.exe") - .args(["/a", "/d", "/e:on", "/q", "/v:off", "/k", "@doskey", "/macros:cmd.exe"]) + .args(["/a", "/d", "/e:on", "/q", "/v:off", "/k", "@doskey", "/macros:all"]) .write_stdin(source) .assert() .success() - .stdout("") .stderr(""); } diff --git a/templates/cmd.txt b/templates/cmd.txt index 9dc65ed..c427913 100644 --- a/templates/cmd.txt +++ b/templates/cmd.txt @@ -1,84 +1,91 @@ +{%- import "utils/batch.txt" as batch -%} + +{%- macro cd(directory, tabs) -%} if /i not "%$p%CD%$p%"=="{{ directory }}" (^ +{%- call batch::indent(tabs) %} %__builtin_cd% {{ directory|safe }}^ +{%- call batch::indent(tabs) %} ^&^& set "OLDPWD=%$p%CD%$p%"^ +{%- if echo -%} +{%- call batch::indent(tabs) %} ^&^& {%~ call pwd(tabs + 1) ~%}^ +{%- endif -%} +{%- if hook != InitHook::None -%} +{%- call batch::indent(tabs) %} ^&^& (for /f "delims=" %$p%a in ('"%__builtin_pwd%"') do @(zoxide add -- "%$p%~fa\."))^ +{%- endif -%} +{%- call batch::indent(tabs) %}) +{%- endmacro cd -%} + +{%- macro pwd(tabs) -%} (^ +{%- if resolve_symlinks -%} +{%- call batch::indent(tabs) %} (^ +{%- call batch::indent(tabs) %} for /f "skip=9 tokens=1,2,*" %$p%j in ('""%$fsutil%" reparsepoint query ."') do @(^ +{%- call batch::indent(tabs) %} if "%$p%~j"=="Print" if "%$p%~k"=="Name:" if not "%$p%~l"=="" (echo(%$p%~l)^ +{%- call batch::indent(tabs) %} )^ +{%- call batch::indent(tabs) %} ) ^|^| %__builtin_pwd%^ +{%- else -%} +{%- call batch::indent(tabs) %} %__builtin_pwd%^ +{%- endif -%} +{%- call batch::indent(tabs) %}) +{%- endmacro pwd -%} + {%- let section = "@rem ==========================================================================\n@rem" -%} {%- let not_configured = "@rem -- not configured --" -%} -@setlocal EnableDelayedExpansion EnableExtensions & set "CMD=!CMDCMDLINE!" 2>nul -@if /i not "!CMD!"=="!CMD:/=!" (goto :EOF) else @if not defined DEBUG (echo off) -@reg query "HKCU\Software\Microsoft\Command Processor" /v "AutoRun" /z >nul 2>&1 -@if !ERRORLEVEL! equ 0 (endlocal & set "CMD_ENV=%~0") else (echo(cmd& goto :EOF) + +@echo off & setlocal EnableDelayedExpansion EnableExtensions + +@if "%~f0"=="%~dpnx0" ( + set ^"$p=%%^&2 ^& %$false%^ + )^ + ) else if "%$p%~i"=="~" (^ + if defined USERPROFILE (^ + {% call cd("%$p%USERPROFILE%$p%", 4) %}^ + ) else (^ + (echo(%__zoxide_cd%: USERPROFILE is not defined) ^>^&2 ^& %$false%^ + )^ + ) else if "%$p%~i"=="-" (^ + if defined OLDPWD (^ + {% call cd("%$p%OLDPWD%$p%", 4) %}^ + ) else (^ + (echo(%__zoxide_cd%: OLDPWD is not defined) ^>^&2 ^& %$false%^ + )^ + ) else (^ + (^ + {% call cd("%$p%~fi", 4) %}^ + )^ + )^ + )^ +) ^&^& %$true% -doskey pwd = (%__ZOXIDE_PWD%) - -{{ section }} -@rem Hook configuration for zoxide. -@rem - -if not defined __ZOXIDE_HOOKED ( - set __ZOXIDE_HOOKED=1 -{% if hook == InitHook::None -%} - @rem {{ not_configured }} - set __ZOXIDE_HOOK= -{%- else -%} - @rem Initialize hook to add new entries to the database. - set __ZOXIDE_HOOK=for /f "delims=" %%z in ('%__ZOXIDE_PWD%') do (zoxide add -- "%%~fz ") -{%- endif %} -) +@rem pwd based on the value of _ZO_RESOLVE_SYMLINKS. +"%$doskey%" %__zoxide_pwd% = {%~ call pwd(0) %} {{ section }} @rem Commands for zoxide. Disable these using --no-cmd. @@ -87,59 +94,45 @@ if not defined __ZOXIDE_HOOKED ( {%- match cmd %} {%- when Some with (cmd) %} +set __zoxide_z_prefix={{cmd}} + @rem Jump to a directory using only keywords. -doskey {{cmd}} = ( ^ - for %%^^^^ in ("") do @for /f "delims=" %%i in (^^""$*%%~^^"^") do @( ^ - if "%%~i"=="" ( ^ - if defined HOME ( ^ - if /i not "%%CD%%"=="%%HOME%%" ( ^ - %__CD% "%%HOME%%" ^&^& ^ -{%- if echo %} - %__ZOXIDE_PWD% ^&^& ^ -{%- endif %} - set "OLDCD=%%CD%%" ^&^& ^ - %__ZOXIDE_HOOK% ^ - ) ^ - ) ^ - ) else if "%%~i"=="-" ( ^ - if defined OLDCD ( ^ - if /i not "%%CD%%"=="%%OLDCD%%" ( ^ - %__CD% "%%OLDCD%%" ^&^& ^ -{%- if echo %} - %__ZOXIDE_PWD% ^&^& ^ -{%- endif %} - set "OLDCD=%%CD%%" ^&^& ^ - %__ZOXIDE_HOOK% ^ - ) ^ - ) ^ - ) else ( ^ - for /f "delims=" %%p in ('zoxide query --exclude "%%CD%%" -- "%%~i"') do @( ^ - if /i not "%%CD%%"=="%%~fp" ( ^ - %__CD% %%~fp ^&^& ^ -{%- if echo %} - %__ZOXIDE_PWD% ^&^& ^ -{%- endif %} - set "OLDCD=%%CD%%" ^&^& ^ - %__ZOXIDE_HOOK% ^ - ) ^ - ) ^ - ) ^ - ) ^ -) +"%$doskey%" %__zoxide_z_prefix% = (^ + {% call batch::for_caret("%$p%", "i") ~%} @(^ + if "%$p%~i"=="" (^ + if defined USERPROFILE (^ + {% call cd("%$p%USERPROFILE%$p%", 4) %}^ + ) else (^ + (echo(%__zoxide_z_prefix%: USERPROFILE is not defined) ^>^&2 ^& %$false%^ + )^ + ) else if "%$p%~i"=="~" (^ + if defined USERPROFILE (^ + {% call cd("%$p%USERPROFILE%$p%", 4) %}^ + ) else (^ + (echo(%__zoxide_z_prefix%: USERPROFILE is not defined) ^>^&2 ^& %$false%^ + )^ + ) else if "%$p%~i"=="-" (^ + if defined OLDPWD (^ + {% call cd("%$p%OLDPWD%$p%", 4) %}^ + ) else (^ + (echo(%__zoxide_z_prefix%: OLDPWD is not defined) ^>^&2 ^& %$false%^ + )^ + ) else (^ + for /f "delims=" %$p%p in ('"zoxide query --exclude "%$p%CD%$p%\." -- %$p%~i"') do @(^ + {% call cd("%$p%~fp", 4) %}^ + )^ + )^ + )^ +) ^&^& %$true% @rem Jump to a directory using interactive search. -doskey {{cmd}}i = ( ^ - for %%^^^^ in ("") do @for /f "delims=" %%i in (^^""$*%%~^^"^") do @( ^ - for /f "delims=" %%q in ('zoxide query --interactive -- "%%~i"') do @( ^ - %__CD% %%~fq ^&^& ^ -{%- if echo %} - %__ZOXIDE_PWD% ^&^& ^ -{%- endif %} - set "OLDCD=%%CD%%" ^&^& ^ - %__ZOXIDE_HOOK% ^ - ) ^ - ) ^ -) +"%$doskey%" %__zoxide_z_prefix%i = (^ + {% call batch::for_caret("%$p%", "i") ~%} @(^ + for /f "delims=" %$p%p in ('"zoxide query --interactive -- %$p%~i"') do @(^ + {% call cd("%$p%~fp", 3) %}^ + )^ + )^ +) ^&^& %$true% {%- when None %} @@ -147,10 +140,9 @@ doskey {{cmd}}i = ( ^ {%- endmatch %} +@endlocal + {{ section }} -@rem To initialize zoxide, add the contents of the following command to your -@rem configuration: +@rem To initialize zoxide, add this to your configuration or AutoRun command: @rem -@rem zoxide init cmd -@rem -@rem If you don't have one: +@rem zoxide init cmd | cmd /d >nul diff --git a/templates/utils/batch.txt b/templates/utils/batch.txt new file mode 100644 index 0000000..8f48dc7 --- /dev/null +++ b/templates/utils/batch.txt @@ -0,0 +1,9 @@ +{%- macro indent(tabs) %} +{% for tab in 0..tabs %} {% endfor -%} +{%- endmacro indent -%} + +{%- macro for_caret(percent, for_parameter) -%} +{#- `for /f` statement with disappearing carets suitable for use in aliases. -#} +{#- Credits for this go to jeb: https://stackoverflow.com/a/76213522/6724141 -#} +for {{ percent }}^^^^ in ("") do @for /f "delims=" {{ percent }}{{ for_parameter }} in (^^""$*{{ percent }}~^^"^") do +{%- endmacro for_caret -%} From 23e4e78431c63ffa9efc80a2eccb80d2633ab654 Mon Sep 17 00:00:00 2001 From: mataha Date: Tue, 6 Jun 2023 23:51:22 +0200 Subject: [PATCH 09/35] Disable delayed expansion in `cmd init` --- templates/cmd.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/cmd.txt b/templates/cmd.txt index c427913..a5d8acb 100644 --- a/templates/cmd.txt +++ b/templates/cmd.txt @@ -28,7 +28,7 @@ {%- let section = "@rem ==========================================================================\n@rem" -%} {%- let not_configured = "@rem -- not configured --" -%} -@echo off & setlocal EnableDelayedExpansion EnableExtensions +@echo off & setlocal DisableDelayedExpansion EnableExtensions @if "%~f0"=="%~dpnx0" ( set ^"$p=%% Date: Wed, 7 Jun 2023 00:59:49 +0200 Subject: [PATCH 10/35] Fix whitespace suppression in `cmd.exe` template --- templates/cmd.txt | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/templates/cmd.txt b/templates/cmd.txt index a5d8acb..b60d189 100644 --- a/templates/cmd.txt +++ b/templates/cmd.txt @@ -4,7 +4,7 @@ {%- call batch::indent(tabs) %} %__builtin_cd% {{ directory|safe }}^ {%- call batch::indent(tabs) %} ^&^& set "OLDPWD=%$p%CD%$p%"^ {%- if echo -%} -{%- call batch::indent(tabs) %} ^&^& {%~ call pwd(tabs + 1) ~%}^ +{%- call batch::indent(tabs) %} ^&^& {%~ call pwd(tabs + 1) -%}^ {%- endif -%} {%- if hook != InitHook::None -%} {%- call batch::indent(tabs) %} ^&^& (for /f "delims=" %$p%a in ('"%__builtin_pwd%"') do @(zoxide add -- "%$p%~fa\."))^ @@ -60,25 +60,25 @@ set __zoxide_pwd=pwd {% call batch::for_caret("%$p%", "i") ~%} @(^ if "%$p%~i"=="" (^ if defined USERPROFILE (^ - {% call cd("%$p%USERPROFILE%$p%", 4) %}^ + {% call cd("%$p%USERPROFILE%$p%", 4) -%}^ ) else (^ (echo(%__zoxide_cd%: USERPROFILE is not defined) ^>^&2 ^& %$false%^ )^ ) else if "%$p%~i"=="~" (^ if defined USERPROFILE (^ - {% call cd("%$p%USERPROFILE%$p%", 4) %}^ + {% call cd("%$p%USERPROFILE%$p%", 4) -%}^ ) else (^ (echo(%__zoxide_cd%: USERPROFILE is not defined) ^>^&2 ^& %$false%^ )^ ) else if "%$p%~i"=="-" (^ if defined OLDPWD (^ - {% call cd("%$p%OLDPWD%$p%", 4) %}^ + {% call cd("%$p%OLDPWD%$p%", 4) -%}^ ) else (^ (echo(%__zoxide_cd%: OLDPWD is not defined) ^>^&2 ^& %$false%^ )^ ) else (^ (^ - {% call cd("%$p%~fi", 4) %}^ + {% call cd("%$p%~fi", 4) -%}^ )^ )^ )^ @@ -101,25 +101,25 @@ set __zoxide_z_prefix={{cmd}} {% call batch::for_caret("%$p%", "i") ~%} @(^ if "%$p%~i"=="" (^ if defined USERPROFILE (^ - {% call cd("%$p%USERPROFILE%$p%", 4) %}^ + {% call cd("%$p%USERPROFILE%$p%", 4) -%}^ ) else (^ (echo(%__zoxide_z_prefix%: USERPROFILE is not defined) ^>^&2 ^& %$false%^ )^ ) else if "%$p%~i"=="~" (^ if defined USERPROFILE (^ - {% call cd("%$p%USERPROFILE%$p%", 4) %}^ + {% call cd("%$p%USERPROFILE%$p%", 4) -%}^ ) else (^ (echo(%__zoxide_z_prefix%: USERPROFILE is not defined) ^>^&2 ^& %$false%^ )^ ) else if "%$p%~i"=="-" (^ if defined OLDPWD (^ - {% call cd("%$p%OLDPWD%$p%", 4) %}^ + {% call cd("%$p%OLDPWD%$p%", 4) -%}^ ) else (^ (echo(%__zoxide_z_prefix%: OLDPWD is not defined) ^>^&2 ^& %$false%^ )^ ) else (^ for /f "delims=" %$p%p in ('"zoxide query --exclude "%$p%CD%$p%\." -- %$p%~i"') do @(^ - {% call cd("%$p%~fp", 4) %}^ + {% call cd("%$p%~fp", 4) -%}^ )^ )^ )^ @@ -129,7 +129,7 @@ set __zoxide_z_prefix={{cmd}} "%$doskey%" %__zoxide_z_prefix%i = (^ {% call batch::for_caret("%$p%", "i") ~%} @(^ for /f "delims=" %$p%p in ('"zoxide query --interactive -- %$p%~i"') do @(^ - {% call cd("%$p%~fp", 3) %}^ + {% call cd("%$p%~fp", 3) -%}^ )^ )^ ) ^&^& %$true% From ed35b884db1470fda4891d2c479b766590bc859d Mon Sep 17 00:00:00 2001 From: mataha Date: Wed, 7 Jun 2023 02:36:42 +0200 Subject: [PATCH 11/35] Make sure `OLDPWD` is not set --- templates/cmd.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/cmd.txt b/templates/cmd.txt index b60d189..0256e8f 100644 --- a/templates/cmd.txt +++ b/templates/cmd.txt @@ -140,7 +140,7 @@ set __zoxide_z_prefix={{cmd}} {%- endmatch %} -@endlocal +@endlocal & set OLDPWD= {{ section }} @rem To initialize zoxide, add this to your configuration or AutoRun command: From ae74cea6ac07f195032c7e8a18219ed60b83fd82 Mon Sep 17 00:00:00 2001 From: mataha Date: Wed, 7 Jun 2023 04:27:36 +0200 Subject: [PATCH 12/35] Don't run with Command Extensions disabled --- templates/cmd.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/templates/cmd.txt b/templates/cmd.txt index 0256e8f..90ae986 100644 --- a/templates/cmd.txt +++ b/templates/cmd.txt @@ -28,9 +28,10 @@ {%- let section = "@rem ==========================================================================\n@rem" -%} {%- let not_configured = "@rem -- not configured --" -%} -@echo off & setlocal DisableDelayedExpansion EnableExtensions +@echo off & (set ComSpec) >nul 2>nul || exit /b 0 2>nul +setlocal DisableDelayedExpansion EnableExtensions -@if "%~f0"=="%~dpnx0" ( +if /i "%~f0"=="%~dpnx0" ( set ^"$p=%% Date: Sun, 11 Jun 2023 04:23:24 +0200 Subject: [PATCH 13/35] Make the Command Extensions requirement more clear --- README.md | 3 +++ templates/cmd.txt | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c700244..8c4f3cc 100644 --- a/README.md +++ b/README.md @@ -221,6 +221,9 @@ zoxide can be installed in 4 easy steps: > ```batchfile > zoxide init cmd | cmd /d >nul > ``` + > + > **Note** + > zoxide only supports `cmd.exe` with Command Extensions v2 and above.
diff --git a/templates/cmd.txt b/templates/cmd.txt index 90ae986..84ad5d9 100644 --- a/templates/cmd.txt +++ b/templates/cmd.txt @@ -28,8 +28,7 @@ {%- let section = "@rem ==========================================================================\n@rem" -%} {%- let not_configured = "@rem -- not configured --" -%} -@echo off & (set ComSpec) >nul 2>nul || exit /b 0 2>nul -setlocal DisableDelayedExpansion EnableExtensions +@echo off & setlocal DisableDelayedExpansion EnableExtensions if /i "%~f0"=="%~dpnx0" ( set ^"$p=%%nul +@rem +@rem Note: zoxide only supports `cmd.exe` with Command Extensions v2 and above. From 6f3d0a24b8b348210a1419dbcd9454b5a81f0c35 Mon Sep 17 00:00:00 2001 From: mataha Date: Sun, 11 Jun 2023 04:26:02 +0200 Subject: [PATCH 14/35] Don't hardcode command names --- templates/cmd.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/templates/cmd.txt b/templates/cmd.txt index 84ad5d9..c11ae94 100644 --- a/templates/cmd.txt +++ b/templates/cmd.txt @@ -94,28 +94,28 @@ set __zoxide_pwd=pwd {%- match cmd %} {%- when Some with (cmd) %} -set __zoxide_z_prefix={{cmd}} +set __zoxide_command={{cmd}} @rem Jump to a directory using only keywords. -"%$doskey%" %__zoxide_z_prefix% = (^ +"%$doskey%" %__zoxide_command% = (^ {% call batch::for_caret("%$p%", "i") ~%} @(^ if "%$p%~i"=="" (^ if defined USERPROFILE (^ {% call cd("%$p%USERPROFILE%$p%", 4) -%}^ ) else (^ - (echo(%__zoxide_z_prefix%: USERPROFILE is not defined) ^>^&2 ^& %$false%^ + (echo(%__zoxide_command%: USERPROFILE is not defined) ^>^&2 ^& %$false%^ )^ ) else if "%$p%~i"=="~" (^ if defined USERPROFILE (^ {% call cd("%$p%USERPROFILE%$p%", 4) -%}^ ) else (^ - (echo(%__zoxide_z_prefix%: USERPROFILE is not defined) ^>^&2 ^& %$false%^ + (echo(%__zoxide_command%: USERPROFILE is not defined) ^>^&2 ^& %$false%^ )^ ) else if "%$p%~i"=="-" (^ if defined OLDPWD (^ {% call cd("%$p%OLDPWD%$p%", 4) -%}^ ) else (^ - (echo(%__zoxide_z_prefix%: OLDPWD is not defined) ^>^&2 ^& %$false%^ + (echo(%__zoxide_command%: OLDPWD is not defined) ^>^&2 ^& %$false%^ )^ ) else (^ for /f "delims=" %$p%p in ('"zoxide query --exclude "%$p%CD%$p%\." -- %$p%~i"') do @(^ @@ -126,7 +126,7 @@ set __zoxide_z_prefix={{cmd}} ) ^&^& %$true% @rem Jump to a directory using interactive search. -"%$doskey%" %__zoxide_z_prefix%i = (^ +"%$doskey%" %__zoxide_command%i = (^ {% call batch::for_caret("%$p%", "i") ~%} @(^ for /f "delims=" %$p%p in ('"zoxide query --interactive -- %$p%~i"') do @(^ {% call cd("%$p%~fp", 3) -%}^ From 3f2283c5026d16b594c24be99fe68c245ac163f7 Mon Sep 17 00:00:00 2001 From: mataha Date: Sun, 11 Jun 2023 04:31:16 +0200 Subject: [PATCH 15/35] Fall back to being `cd` if directory exists --- templates/cmd.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/templates/cmd.txt b/templates/cmd.txt index c11ae94..57cc823 100644 --- a/templates/cmd.txt +++ b/templates/cmd.txt @@ -117,9 +117,11 @@ set __zoxide_command={{cmd}} ) else (^ (echo(%__zoxide_command%: OLDPWD is not defined) ^>^&2 ^& %$false%^ )^ - ) else (^ - for /f "delims=" %$p%p in ('"zoxide query --exclude "%$p%CD%$p%\." -- %$p%~i"') do @(^ - {% call cd("%$p%~fp", 4) -%}^ + ) else for /f "tokens=1,* delims=d" %$p%a in ("-%$p%~ai") do @(^ + if not "%$p%b"=="" (^ + {% call cd("%$p%~fi", 4) -%}^ + ) else for /f "delims=" %$p%q in ('"zoxide query --exclude "%$p%CD%$p%" -- %$p%~i"') do @(^ + {% call cd("%$p%~fq", 4) -%}^ )^ )^ )^ From e7dba81869e0b5ef3853218d3210e6223d0381a1 Mon Sep 17 00:00:00 2001 From: mataha Date: Sun, 11 Jun 2023 04:41:14 +0200 Subject: [PATCH 16/35] Quote external command macros directly --- templates/cmd.txt | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/templates/cmd.txt b/templates/cmd.txt index 57cc823..348270f 100644 --- a/templates/cmd.txt +++ b/templates/cmd.txt @@ -15,7 +15,7 @@ {%- macro pwd(tabs) -%} (^ {%- if resolve_symlinks -%} {%- call batch::indent(tabs) %} (^ -{%- call batch::indent(tabs) %} for /f "skip=9 tokens=1,2,*" %$p%j in ('""%$fsutil%" reparsepoint query ."') do @(^ +{%- call batch::indent(tabs) %} for /f "skip=9 tokens=1,2,*" %$p%j in ('"%$fsutil% reparsepoint query ."') do @(^ {%- call batch::indent(tabs) %} if "%$p%~j"=="Print" if "%$p%~k"=="Name:" if not "%$p%~l"=="" (echo(%$p%~l)^ {%- call batch::indent(tabs) %} )^ {%- call batch::indent(tabs) %} ) ^|^| %__builtin_pwd%^ @@ -39,10 +39,9 @@ if /i "%~f0"=="%~dpnx0" ( set ^"$true=(call )" set ^"$false=(call)" -set root=%SystemRoot%\System32 -set ^"$doskey=%root%\doskey.exe" +set ^"$doskey="%SystemRoot%\System32\doskey.exe"" {%- if resolve_symlinks %} -set ^"$fsutil=%root%\fsutil.exe" +set ^"$fsutil="%SystemRoot%\System32\fsutil.exe"" {%- endif %} {{ section }} @@ -56,7 +55,7 @@ set __zoxide_cd=cd set __zoxide_pwd=pwd @rem cd + custom logic based on the value of _ZO_ECHO. -"%$doskey%" %__zoxide_cd% = (^ +%$doskey% %__zoxide_cd% = (^ {% call batch::for_caret("%$p%", "i") ~%} @(^ if "%$p%~i"=="" (^ if defined USERPROFILE (^ @@ -85,7 +84,7 @@ set __zoxide_pwd=pwd ) ^&^& %$true% @rem pwd based on the value of _ZO_RESOLVE_SYMLINKS. -"%$doskey%" %__zoxide_pwd% = {%~ call pwd(0) %} +%$doskey% %__zoxide_pwd% = {%~ call pwd(0) %} {{ section }} @rem Commands for zoxide. Disable these using --no-cmd. @@ -97,7 +96,7 @@ set __zoxide_pwd=pwd set __zoxide_command={{cmd}} @rem Jump to a directory using only keywords. -"%$doskey%" %__zoxide_command% = (^ +%$doskey% %__zoxide_command% = (^ {% call batch::for_caret("%$p%", "i") ~%} @(^ if "%$p%~i"=="" (^ if defined USERPROFILE (^ @@ -128,7 +127,7 @@ set __zoxide_command={{cmd}} ) ^&^& %$true% @rem Jump to a directory using interactive search. -"%$doskey%" %__zoxide_command%i = (^ +%$doskey% %__zoxide_command%i = (^ {% call batch::for_caret("%$p%", "i") ~%} @(^ for /f "delims=" %$p%p in ('"zoxide query --interactive -- %$p%~i"') do @(^ {% call cd("%$p%~fp", 3) -%}^ From 1ee0195a0dc88c1830a94425c23c928e962a40a0 Mon Sep 17 00:00:00 2001 From: mataha Date: Sun, 11 Jun 2023 04:46:01 +0200 Subject: [PATCH 17/35] Sanitize trailing backslash when in root directory --- templates/cmd.txt | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/templates/cmd.txt b/templates/cmd.txt index 348270f..d25132d 100644 --- a/templates/cmd.txt +++ b/templates/cmd.txt @@ -7,7 +7,11 @@ {%- call batch::indent(tabs) %} ^&^& {%~ call pwd(tabs + 1) -%}^ {%- endif -%} {%- if hook != InitHook::None -%} -{%- call batch::indent(tabs) %} ^&^& (for /f "delims=" %$p%a in ('"%__builtin_pwd%"') do @(zoxide add -- "%$p%~fa\."))^ +{%- call batch::indent(tabs) %} ^&^& for /f "delims=" %$p%a in ('"%__builtin_pwd%"') do @if /i not "%$p%~dpa"=="%$p%~fa" (^ +{%- call batch::indent(tabs) %} zoxide add -- "%$p%~fa"^ +{%- call batch::indent(tabs) %} ) else (^ +{%- call batch::indent(tabs) %} zoxide add -- "%$p%~fa\"^ +{%- call batch::indent(tabs) %} )^ {%- endif -%} {%- call batch::indent(tabs) %}) {%- endmacro cd -%} @@ -119,8 +123,14 @@ set __zoxide_command={{cmd}} ) else for /f "tokens=1,* delims=d" %$p%a in ("-%$p%~ai") do @(^ if not "%$p%b"=="" (^ {% call cd("%$p%~fi", 4) -%}^ - ) else for /f "delims=" %$p%q in ('"zoxide query --exclude "%$p%CD%$p%" -- %$p%~i"') do @(^ - {% call cd("%$p%~fq", 4) -%}^ + ) else if /i not "%$p%CD%$p%"=="%$p%__CD__%$p%" (^ + for /f "delims=" %$p%q in ('"zoxide query --exclude "%$p%CD%$p%" -- %$p%~i"') do @(^ + {% call cd("%$p%~fq", 5) -%}^ + )^ + ) else (^ + for /f "delims=" %$p%q in ('"zoxide query --exclude "%$p%CD%$p%\" -- %$p%~i"') do @(^ + {% call cd("%$p%~fq", 5) -%}^ + )^ )^ )^ )^ From 8d61617c6a7705fe6f953b657fc0f5484c18472a Mon Sep 17 00:00:00 2001 From: mataha Date: Mon, 12 Jun 2023 01:19:24 +0200 Subject: [PATCH 18/35] Quit if Command Extensions are disabled --- README.md | 5 +---- src/shell.rs | 16 +++++++++++++++- templates/cmd.txt | 10 ++++++---- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 8c4f3cc..bac7a87 100644 --- a/README.md +++ b/README.md @@ -219,11 +219,8 @@ zoxide can be installed in 4 easy steps: > Add this to the **end** of your config file or AutoRun command: > > ```batchfile - > zoxide init cmd | cmd /d >nul + > zoxide init cmd | cmd /d /k >nul > ``` - > - > **Note** - > zoxide only supports `cmd.exe` with Command Extensions v2 and above. diff --git a/src/shell.rs b/src/shell.rs index 01de293..042335d 100644 --- a/src/shell.rs +++ b/src/shell.rs @@ -105,13 +105,27 @@ mod tests { let source = Cmd(&opts).render().unwrap(); Command::new("cmd.exe") - .args(["/a", "/d", "/e:on", "/q", "/v:off", "/k", "@doskey", "/macros:all"]) + .args(["/a", "/d", "/e:on", "/q", "/v:off", "/k", "@doskey /macros:cmd.exe"]) .write_stdin(source) .assert() .success() .stderr(""); } + #[apply(opts)] + #[cfg(windows)] + fn cmd_dos(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) { + let opts = Opts { cmd, hook, echo, resolve_symlinks }; + let source = Cmd(&opts).render().unwrap(); + + Command::new("cmd.exe") + .args(["/a", "/d", "/e:off", "/q", "/v:off", "/k", "@doskey /macros:cmd.exe"]) + .write_stdin(source) + .assert() + .failure() + .stderr("zoxide: unable to init with Command Extensions disabled (see `help cmd` for details)"); + } + #[apply(opts)] #[cfg(unix)] fn elvish_elvish(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) { diff --git a/templates/cmd.txt b/templates/cmd.txt index d25132d..90653d0 100644 --- a/templates/cmd.txt +++ b/templates/cmd.txt @@ -32,7 +32,11 @@ {%- let section = "@rem ==========================================================================\n@rem" -%} {%- let not_configured = "@rem -- not configured --" -%} -@echo off & setlocal DisableDelayedExpansion EnableExtensions +@(set ^"^") >nul 2>nul && (echo off) || ( + echo zoxide: unable to init with Command Extensions disabled ^(see `help cmd` for details^) +) >&2 && exit /b 1 "Command Extensions are disabled" 2>nul + +setlocal DisableDelayedExpansion EnableExtensions if /i "%~f0"=="%~dpnx0" ( set ^"$p=%%nul -@rem -@rem Note: zoxide only supports `cmd.exe` with Command Extensions v2 and above. +@rem zoxide init cmd | cmd /d /k >nul From 435a62266af71d5a260142249d39f998bff833db Mon Sep 17 00:00:00 2001 From: mataha Date: Sat, 17 Jun 2023 02:11:06 +0200 Subject: [PATCH 19/35] Tighten the check for command-line context --- templates/cmd.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/cmd.txt b/templates/cmd.txt index 90653d0..9a07fc9 100644 --- a/templates/cmd.txt +++ b/templates/cmd.txt @@ -38,7 +38,7 @@ setlocal DisableDelayedExpansion EnableExtensions -if /i "%~f0"=="%~dpnx0" ( +if "%=^%="=="%=%=" ( set ^"$p=%% Date: Sat, 17 Jun 2023 02:12:29 +0200 Subject: [PATCH 20/35] Initialize hook only if it's a `pwd` hook --- templates/cmd.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/cmd.txt b/templates/cmd.txt index 9a07fc9..f033226 100644 --- a/templates/cmd.txt +++ b/templates/cmd.txt @@ -6,7 +6,7 @@ {%- if echo -%} {%- call batch::indent(tabs) %} ^&^& {%~ call pwd(tabs + 1) -%}^ {%- endif -%} -{%- if hook != InitHook::None -%} +{%- if hook == InitHook::Pwd -%} {%- call batch::indent(tabs) %} ^&^& for /f "delims=" %$p%a in ('"%__builtin_pwd%"') do @if /i not "%$p%~dpa"=="%$p%~fa" (^ {%- call batch::indent(tabs) %} zoxide add -- "%$p%~fa"^ {%- call batch::indent(tabs) %} ) else (^ From acb9e95e7e51674daf59819a292f1a4e7720acde Mon Sep 17 00:00:00 2001 From: mataha Date: Sat, 17 Jun 2023 02:33:01 +0200 Subject: [PATCH 21/35] Add common shorthands as command aliases --- templates/cmd.txt | 48 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/templates/cmd.txt b/templates/cmd.txt index f033226..29797a7 100644 --- a/templates/cmd.txt +++ b/templates/cmd.txt @@ -91,6 +91,30 @@ set __zoxide_pwd=pwd )^ ) ^&^& %$true% +%$doskey% %__zoxide_cd%~ = (^ + if defined USERPROFILE (^ + {% call cd("%$p%USERPROFILE%$p%", 2) -%}^ + ) else (^ + (echo(%__zoxide_cd%: USERPROFILE is not defined) ^>^&2 ^& %$false%^ + )^ +) + +%$doskey% %__zoxide_cd%- = (^ + if defined OLDPWD (^ + {% call cd("%$p%OLDPWD%$p%", 2) -%}^ + ) else (^ + (echo(%__zoxide_cd%: OLDPWD is not defined) ^>^&2 ^& %$false%^ + )^ +) + +%$doskey% %__zoxide_cd%\ = {%~ call cd("\\", 0) %} + +%$doskey% %__zoxide_cd%/ = {%~ call cd("/", 0) %} + +%$doskey% %__zoxide_cd%. = (%__builtin_cd%.) + +%$doskey% %__zoxide_cd%.. = {%~ call cd("..", 0) %} + @rem pwd based on the value of _ZO_RESOLVE_SYMLINKS. %$doskey% %__zoxide_pwd% = {%~ call pwd(0) %} @@ -140,6 +164,30 @@ set __zoxide_command={{cmd}} )^ ) ^&^& %$true% +%$doskey% %__zoxide_command%~ = (^ + if defined USERPROFILE (^ + {% call cd("%$p%USERPROFILE%$p%", 2) -%}^ + ) else (^ + (echo(%__zoxide_command%: USERPROFILE is not defined) ^>^&2 ^& %$false%^ + )^ +) + +%$doskey% %__zoxide_command%- = (^ + if defined OLDPWD (^ + {% call cd("%$p%OLDPWD%$p%", 2) -%}^ + ) else (^ + (echo(%__zoxide_command%: OLDPWD is not defined) ^>^&2 ^& %$false%^ + )^ +) + +%$doskey% %__zoxide_command%\ = {%~ call cd("\\", 0) %} + +%$doskey% %__zoxide_command%/ = {%~ call cd("/", 0) %} + +%$doskey% %__zoxide_command%. = (%__builtin_cd%.) + +%$doskey% %__zoxide_command%.. = {%~ call cd("..", 0) %} + @rem Jump to a directory using interactive search. %$doskey% %__zoxide_command%i = (^ {% call batch::for_caret("%$p%", "i") ~%} @(^ From 864f8cad91efad7026a9e2025ddb6ed05b823a68 Mon Sep 17 00:00:00 2001 From: mataha Date: Mon, 10 Jun 2024 03:12:46 +0200 Subject: [PATCH 22/35] WIP --- .editorconfig | 16 +++ README.md | 2 +- man/man1/zoxide-init.1 | 7 ++ src/shell.rs | 28 +++-- src/util.rs | 35 ------ templates/cmd.txt | 220 ++++++-------------------------------- templates/posix.txt | 3 +- templates/utils/batch.txt | 9 -- 8 files changed, 79 insertions(+), 241 deletions(-) create mode 100644 .editorconfig delete mode 100644 templates/utils/batch.txt diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..aa6d76d --- /dev/null +++ b/.editorconfig @@ -0,0 +1,16 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true + +[*.(md,txt}] +indent_size = unset +trim_trailing_whitespace = false + +[*.{nix,ts,yml,zsh}] +indent_size = 2 diff --git a/README.md b/README.md index bac7a87..1448383 100644 --- a/README.md +++ b/README.md @@ -219,7 +219,7 @@ zoxide can be installed in 4 easy steps: > Add this to the **end** of your config file or AutoRun command: > > ```batchfile - > zoxide init cmd | cmd /d /k >nul + > zoxide init cmd --hook none | cmd /d/q/k >nul > ``` diff --git a/man/man1/zoxide-init.1 b/man/man1/zoxide-init.1 index ebf1ed1..3eb172c 100644 --- a/man/man1/zoxide-init.1 +++ b/man/man1/zoxide-init.1 @@ -13,6 +13,13 @@ Add this to the \fBend\fR of your config file (usually \fB~/.bashrc\fR): \fBeval "$(zoxide init bash)"\fR .fi .TP +.B cmd +Add this to the \fBend\fR of your config file or AutoRun command: +.sp +.nf + \fBzoxide init cmd --hook none | cmd /d/q/k >nul\fR +.fi +.TP .B elvish Add this to the \fBend\fR of your config file (usually \fB~/.elvish/rc.elv\fR): .sp diff --git a/src/shell.rs b/src/shell.rs index 042335d..0c4568b 100644 --- a/src/shell.rs +++ b/src/shell.rs @@ -11,7 +11,7 @@ pub struct Opts<'a> { macro_rules! make_template { ($name:ident, $path:expr) => { #[derive(::std::fmt::Debug, ::askama::Template)] - #[template(path = $path)] + #[template(path = $path, escape = "none")] pub struct $name<'a>(pub &'a self::Opts<'a>); impl<'a> ::std::ops::Deref for $name<'a> { @@ -104,12 +104,17 @@ mod tests { let opts = Opts { cmd, hook, echo, resolve_symlinks }; let source = Cmd(&opts).render().unwrap(); - Command::new("cmd.exe") - .args(["/a", "/d", "/e:on", "/q", "/v:off", "/k", "@doskey /macros:cmd.exe"]) + let assert = Command::new(which::which("cmd.exe").unwrap()) + .args(["/d", "/x", "/k"]) .write_stdin(source) .assert() - .success() - .stderr(""); + .success(); + + if opts.hook != InitHook::None { + assert.stderr("zoxide: hooks are not supported on cmd shell.\r\n"); + } else { + assert.stderr(""); + } } #[apply(opts)] @@ -118,12 +123,17 @@ mod tests { let opts = Opts { cmd, hook, echo, resolve_symlinks }; let source = Cmd(&opts).render().unwrap(); - Command::new("cmd.exe") - .args(["/a", "/d", "/e:off", "/q", "/v:off", "/k", "@doskey /macros:cmd.exe"]) + let assert = Command::new(which::which("cmd.exe").unwrap()) + .args(["/d", "/y", "/k"]) .write_stdin(source) .assert() - .failure() - .stderr("zoxide: unable to init with Command Extensions disabled (see `help cmd` for details)"); + .success(); + + if opts.hook != InitHook::None { + assert.stderr("zoxide: hooks are not supported on cmd shell.\r\n"); + } else { + assert.stderr(""); + } } #[apply(opts)] diff --git a/src/util.rs b/src/util.rs index d9bedc3..18d1c75 100644 --- a/src/util.rs +++ b/src/util.rs @@ -415,38 +415,3 @@ pub fn to_lowercase(s: impl AsRef) -> String { let s = s.as_ref(); if s.is_ascii() { s.to_ascii_lowercase() } else { s.to_lowercase() } } - -#[cfg(test)] -#[cfg(windows)] -mod tests_win { - use std::path::PathBuf; - - use rstest::rstest; - - #[rstest] - #[case(r"c:\", r"C:\")] - #[case(r"C:\", r"C:\")] - #[case(r"c:\\.", r"C:\")] - #[case(r"c:\..", r"C:\")] - #[case(r"C:\.\.", r"C:\")] - #[case(r"\\?\C:\", r"C:\")] - #[case(r"\\?\c:\", r"C:\")] - #[case(r"\\?\C:\\\", r"C:\")] - #[case(r"\\?\c:\\.\", r"C:\")] - #[case(r"c:\Windows", r"C:\Windows")] - #[case(r"C:\WINDOWS", r"C:\WINDOWS")] - #[case(r"c:\\\Windows\.", r"C:\Windows")] - #[case(r"C:\$WinREAgent", r"C:\$WinREAgent")] - #[case(r"\\?\c:\\Windows\\.", r"C:\Windows")] - #[case(r"\\?\c:\..\.\windows", r"C:\windows")] - #[case(r"c:\Windows\System32\.", r"C:\Windows\System32")] - #[case(r"c:\WINDOWS\..\..\Windows", r"C:\Windows")] - #[case(r"c:\Windows\..\.\.\..\Temp\..\tmp", r"C:\tmp")] - #[case(r"c:\.\Windows\..\..\Program Files", r"C:\Program Files")] - #[case(r"\\?\C:\\$WinREAgent\\..\Program Files\.", r"C:\Program Files")] - fn resolve_path(#[case] absolute_path: &str, #[case] normalized_form: &str) { - let path = PathBuf::from(absolute_path); - let resolved_path = super::resolve_path(path).unwrap(); - assert_eq!(resolved_path.to_str().unwrap(), normalized_form); - } -} diff --git a/templates/cmd.txt b/templates/cmd.txt index 29797a7..cd68a73 100644 --- a/templates/cmd.txt +++ b/templates/cmd.txt @@ -1,201 +1,53 @@ -{%- import "utils/batch.txt" as batch -%} +{%- let section = "rem ===========================================================================\nrem" -%} +{%- let not_configured = "rem -- not configured --" -%} -{%- macro cd(directory, tabs) -%} if /i not "%$p%CD%$p%"=="{{ directory }}" (^ -{%- call batch::indent(tabs) %} %__builtin_cd% {{ directory|safe }}^ -{%- call batch::indent(tabs) %} ^&^& set "OLDPWD=%$p%CD%$p%"^ -{%- if echo -%} -{%- call batch::indent(tabs) %} ^&^& {%~ call pwd(tabs + 1) -%}^ -{%- endif -%} -{%- if hook == InitHook::Pwd -%} -{%- call batch::indent(tabs) %} ^&^& for /f "delims=" %$p%a in ('"%__builtin_pwd%"') do @if /i not "%$p%~dpa"=="%$p%~fa" (^ -{%- call batch::indent(tabs) %} zoxide add -- "%$p%~fa"^ -{%- call batch::indent(tabs) %} ) else (^ -{%- call batch::indent(tabs) %} zoxide add -- "%$p%~fa\"^ -{%- call batch::indent(tabs) %} )^ -{%- endif -%} -{%- call batch::indent(tabs) %}) -{%- endmacro cd -%} +rem Code generated by zoxide. DO NOT EDIT. -{%- macro pwd(tabs) -%} (^ -{%- if resolve_symlinks -%} -{%- call batch::indent(tabs) %} (^ -{%- call batch::indent(tabs) %} for /f "skip=9 tokens=1,2,*" %$p%j in ('"%$fsutil% reparsepoint query ."') do @(^ -{%- call batch::indent(tabs) %} if "%$p%~j"=="Print" if "%$p%~k"=="Name:" if not "%$p%~l"=="" (echo(%$p%~l)^ -{%- call batch::indent(tabs) %} )^ -{%- call batch::indent(tabs) %} ) ^|^| %__builtin_pwd%^ -{%- else -%} -{%- call batch::indent(tabs) %} %__builtin_pwd%^ -{%- endif -%} -{%- call batch::indent(tabs) %}) -{%- endmacro pwd -%} - -{%- let section = "@rem ==========================================================================\n@rem" -%} -{%- let not_configured = "@rem -- not configured --" -%} - -@(set ^"^") >nul 2>nul && (echo off) || ( - echo zoxide: unable to init with Command Extensions disabled ^(see `help cmd` for details^) -) >&2 && exit /b 1 "Command Extensions are disabled" 2>nul - -setlocal DisableDelayedExpansion EnableExtensions - -if "%=^%="=="%=%=" ( - set ^"$p=%%&2 echo zoxide: hooks are not supported on cmd shell. -set ^"$doskey="%SystemRoot%\System32\doskey.exe"" -{%- if resolve_symlinks %} -set ^"$fsutil="%SystemRoot%\System32\fsutil.exe"" {%- endif %} {{ section }} -@rem Utility functions for zoxide. -@rem +rem Utility functions for zoxide. +rem -set __builtin_cd=chdir /d -set __builtin_pwd=chdir +rem pwd based on the value of _ZO_RESOLVE_SYMLINKS. +set __zoxide_pwd={%- if resolve_symlinks -%} (for /f "skip=9 tokens=1,2,*" %\p%j in ('"%SystemRoot%\system32\fsutil.exe" reparsepoint query .') do @(if "%\p%~j" equ "Print" if "%\p%~k" equ "Name:" if "%\p%~l" neq "" (echo(%%~l))) ^^^^^^^|^^^^^^^| {%~ endif -%} %__builtin_pwd% -set __zoxide_cd=cd -set __zoxide_pwd=pwd - -@rem cd + custom logic based on the value of _ZO_ECHO. -%$doskey% %__zoxide_cd% = (^ - {% call batch::for_caret("%$p%", "i") ~%} @(^ - if "%$p%~i"=="" (^ - if defined USERPROFILE (^ - {% call cd("%$p%USERPROFILE%$p%", 4) -%}^ - ) else (^ - (echo(%__zoxide_cd%: USERPROFILE is not defined) ^>^&2 ^& %$false%^ - )^ - ) else if "%$p%~i"=="~" (^ - if defined USERPROFILE (^ - {% call cd("%$p%USERPROFILE%$p%", 4) -%}^ - ) else (^ - (echo(%__zoxide_cd%: USERPROFILE is not defined) ^>^&2 ^& %$false%^ - )^ - ) else if "%$p%~i"=="-" (^ - if defined OLDPWD (^ - {% call cd("%$p%OLDPWD%$p%", 4) -%}^ - ) else (^ - (echo(%__zoxide_cd%: OLDPWD is not defined) ^>^&2 ^& %$false%^ - )^ - ) else (^ - (^ - {% call cd("%$p%~fi", 4) -%}^ - )^ - )^ - )^ -) ^&^& %$true% - -%$doskey% %__zoxide_cd%~ = (^ - if defined USERPROFILE (^ - {% call cd("%$p%USERPROFILE%$p%", 2) -%}^ - ) else (^ - (echo(%__zoxide_cd%: USERPROFILE is not defined) ^>^&2 ^& %$false%^ - )^ -) - -%$doskey% %__zoxide_cd%- = (^ - if defined OLDPWD (^ - {% call cd("%$p%OLDPWD%$p%", 2) -%}^ - ) else (^ - (echo(%__zoxide_cd%: OLDPWD is not defined) ^>^&2 ^& %$false%^ - )^ -) - -%$doskey% %__zoxide_cd%\ = {%~ call cd("\\", 0) %} - -%$doskey% %__zoxide_cd%/ = {%~ call cd("/", 0) %} - -%$doskey% %__zoxide_cd%. = (%__builtin_cd%.) - -%$doskey% %__zoxide_cd%.. = {%~ call cd("..", 0) %} - -@rem pwd based on the value of _ZO_RESOLVE_SYMLINKS. -%$doskey% %__zoxide_pwd% = {%~ call pwd(0) %} +rem cd + custom logic based on the value of _ZO_ECHO. +set __zoxide_cd=if /i "%\p%CD%\p%" neq "%\p%~fc" (%__builtin_cd% "%\p%~fc" ^^^&^^^& set "OLDPWD=%\p%CD%\p%" ^^^&^^^& (for /f "delims=" %\p%l in ('"%__builtin_pwd%"') do @if /i "%\p%~dpl" neq "%\p%~fl" (zoxide add -- "%\p%~fl") else (zoxide add -- "%\p%~fl\")) {%- if echo ~%} ^^^&^^^& %__zoxide_pwd% {%- endif ~%} ^^^&^^^& if defined CDCMD (call %\p%CDCMD%\p%)) {{ section }} -@rem Commands for zoxide. Disable these using --no-cmd. -@rem +rem Commands for zoxide. Disable these using --no-cmd. +rem {%- match cmd %} {%- when Some with (cmd) %} -set __zoxide_command={{cmd}} +set __zoxide_command={{ cmd }} -@rem Jump to a directory using only keywords. -%$doskey% %__zoxide_command% = (^ - {% call batch::for_caret("%$p%", "i") ~%} @(^ - if "%$p%~i"=="" (^ - if defined USERPROFILE (^ - {% call cd("%$p%USERPROFILE%$p%", 4) -%}^ - ) else (^ - (echo(%__zoxide_command%: USERPROFILE is not defined) ^>^&2 ^& %$false%^ - )^ - ) else if "%$p%~i"=="~" (^ - if defined USERPROFILE (^ - {% call cd("%$p%USERPROFILE%$p%", 4) -%}^ - ) else (^ - (echo(%__zoxide_command%: USERPROFILE is not defined) ^>^&2 ^& %$false%^ - )^ - ) else if "%$p%~i"=="-" (^ - if defined OLDPWD (^ - {% call cd("%$p%OLDPWD%$p%", 4) -%}^ - ) else (^ - (echo(%__zoxide_command%: OLDPWD is not defined) ^>^&2 ^& %$false%^ - )^ - ) else for /f "tokens=1,* delims=d" %$p%a in ("-%$p%~ai") do @(^ - if not "%$p%b"=="" (^ - {% call cd("%$p%~fi", 4) -%}^ - ) else if /i not "%$p%CD%$p%"=="%$p%__CD__%$p%" (^ - for /f "delims=" %$p%q in ('"zoxide query --exclude "%$p%CD%$p%" -- %$p%~i"') do @(^ - {% call cd("%$p%~fq", 5) -%}^ - )^ - ) else (^ - for /f "delims=" %$p%q in ('"zoxide query --exclude "%$p%CD%$p%\" -- %$p%~i"') do @(^ - {% call cd("%$p%~fq", 5) -%}^ - )^ - )^ - )^ - )^ -) ^&^& %$true% +rem Jump to a directory using only keywords. +"%SystemRoot%\system32\doskey.exe" %__zoxide_command% = (for %\p%^^^^ in ("") do @for /f "delims=" %\p%i in (^^""$*%\p%~^^"^") do @if "%\p%~i" == "" (if defined HOME (for /f "delims=" %\p%c in (^^""%\p%HOME%\p%"^") do @%__zoxide_cd%) else ^>^&2 (echo(zoxide: HOME not set) ^& call) else if "%\p%~i" == "~" (if defined HOME (for /f "delims=" %\p%c in (^^""%\p%HOME%\p%"^") do @%__zoxide_cd%) else ^>^&2 (echo(zoxide: HOME not set) ^& call) else if "%\p%~i" == "-" (if defined OLDPWD (for /f "delims=" %\p%c in (^^""%\p%OLDPWD%\p%"^") do @%__zoxide_cd%) else ^>^&2 (echo(zoxide: OLDPWD not set) ^& call) else for /f "delims=" %\p%~ in (^^"%\p%~i^") do @for /f "tokens=1,* delims=d" %\p%a in ("-%\p%~a~") do @if "%\p%b" neq "" (for /f "delims=" %\p%c in (^^""%\p%~f~"^") do @%__zoxide_cd%) else if /i "%\p%CD%\p%" neq "%\p%__CD__%\p%" (for /f "delims=" %\p%q in ('zoxide query --exclude "%\p%CD%\p%" -- %\p%~i') do @(for /f "delims=" %\p%c in (^^""%\p%~fq"^") do @%__zoxide_cd%)) else (for /f "delims=" %\p%q in ('zoxide query --exclude "%\p%__CD__%\p%\" -- %\p%~i') do @(for /f "delims=" %\p%c in (^^""%\p%~fq"^") do @%__zoxide_cd%))) ^&^& (call ) -%$doskey% %__zoxide_command%~ = (^ - if defined USERPROFILE (^ - {% call cd("%$p%USERPROFILE%$p%", 2) -%}^ - ) else (^ - (echo(%__zoxide_command%: USERPROFILE is not defined) ^>^&2 ^& %$false%^ - )^ -) - -%$doskey% %__zoxide_command%- = (^ - if defined OLDPWD (^ - {% call cd("%$p%OLDPWD%$p%", 2) -%}^ - ) else (^ - (echo(%__zoxide_command%: OLDPWD is not defined) ^>^&2 ^& %$false%^ - )^ -) - -%$doskey% %__zoxide_command%\ = {%~ call cd("\\", 0) %} - -%$doskey% %__zoxide_command%/ = {%~ call cd("/", 0) %} - -%$doskey% %__zoxide_command%. = (%__builtin_cd%.) - -%$doskey% %__zoxide_command%.. = {%~ call cd("..", 0) %} - -@rem Jump to a directory using interactive search. -%$doskey% %__zoxide_command%i = (^ - {% call batch::for_caret("%$p%", "i") ~%} @(^ - for /f "delims=" %$p%p in ('"zoxide query --interactive -- %$p%~i"') do @(^ - {% call cd("%$p%~fp", 3) -%}^ - )^ - )^ -) ^&^& %$true% +rem Jump to a directory using interactive search. +"%SystemRoot%\system32\doskey.exe" %__zoxide_command%i = (for %\p%^^^^ in ("") do @for /f "delims=" %\p%i in (^^""$*%\p%~^^"^") do @for /f "delims=" %\p%p in ('zoxide query --interactive -- %\p%~i') do @for /f "delims=" %\p%c in (^^""%\p%~fp"^") do @%__zoxide_cd%) ^&^& (call ) {%- when None %} @@ -203,9 +55,7 @@ set __zoxide_command={{cmd}} {%- endmatch %} -endlocal & set OLDPWD= - {{ section }} -@rem To initialize zoxide, add this to your configuration or AutoRun command: -@rem -@rem zoxide init cmd | cmd /d /k >nul +rem To initialize zoxide, add this to your configuration or AutoRun command: +rem +rem zoxide init cmd --hook none | cmd /d/q/k >nul diff --git a/templates/posix.txt b/templates/posix.txt index b3f660c..0775e59 100644 --- a/templates/posix.txt +++ b/templates/posix.txt @@ -101,8 +101,7 @@ __zoxide_z() { if [ -n "${OLDPWD}" ]; then __zoxide_cd "${OLDPWD}" else - # shellcheck disable=SC2016 - \command printf 'zoxide: $OLDPWD is not set' + \command printf 'zoxide: OLDPWD not set' return 1 fi elif [ "$#" -eq 1 ] && [ -d "$1" ]; then diff --git a/templates/utils/batch.txt b/templates/utils/batch.txt deleted file mode 100644 index 8f48dc7..0000000 --- a/templates/utils/batch.txt +++ /dev/null @@ -1,9 +0,0 @@ -{%- macro indent(tabs) %} -{% for tab in 0..tabs %} {% endfor -%} -{%- endmacro indent -%} - -{%- macro for_caret(percent, for_parameter) -%} -{#- `for /f` statement with disappearing carets suitable for use in aliases. -#} -{#- Credits for this go to jeb: https://stackoverflow.com/a/76213522/6724141 -#} -for {{ percent }}^^^^ in ("") do @for /f "delims=" {{ percent }}{{ for_parameter }} in (^^""$*{{ percent }}~^^"^") do -{%- endmacro for_caret -%} From bb75058ce64d0cfb49b717d032b7a64f873ecd03 Mon Sep 17 00:00:00 2001 From: mataha Date: Mon, 10 Jun 2024 03:39:18 +0200 Subject: [PATCH 23/35] Be consistent when comparing comptime strings --- templates/cmd.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/cmd.txt b/templates/cmd.txt index cd68a73..4b02a01 100644 --- a/templates/cmd.txt +++ b/templates/cmd.txt @@ -29,7 +29,7 @@ rem Utility functions for zoxide. rem rem pwd based on the value of _ZO_RESOLVE_SYMLINKS. -set __zoxide_pwd={%- if resolve_symlinks -%} (for /f "skip=9 tokens=1,2,*" %\p%j in ('"%SystemRoot%\system32\fsutil.exe" reparsepoint query .') do @(if "%\p%~j" equ "Print" if "%\p%~k" equ "Name:" if "%\p%~l" neq "" (echo(%%~l))) ^^^^^^^|^^^^^^^| {%~ endif -%} %__builtin_pwd% +set __zoxide_pwd={%- if resolve_symlinks -%} (for /f "skip=9 tokens=1,2,*" %\p%j in ('"%SystemRoot%\system32\fsutil.exe" reparsepoint query .') do @if "%\p%~j" == "Print" if "%\p%~k" == "Name:" if not "%\p%~l" == "" (echo(%%~l)) ^^^^^^^|^^^^^^^| {%~ endif -%} %__builtin_pwd% rem cd + custom logic based on the value of _ZO_ECHO. set __zoxide_cd=if /i "%\p%CD%\p%" neq "%\p%~fc" (%__builtin_cd% "%\p%~fc" ^^^&^^^& set "OLDPWD=%\p%CD%\p%" ^^^&^^^& (for /f "delims=" %\p%l in ('"%__builtin_pwd%"') do @if /i "%\p%~dpl" neq "%\p%~fl" (zoxide add -- "%\p%~fl") else (zoxide add -- "%\p%~fl\")) {%- if echo ~%} ^^^&^^^& %__zoxide_pwd% {%- endif ~%} ^^^&^^^& if defined CDCMD (call %\p%CDCMD%\p%)) @@ -44,7 +44,7 @@ rem set __zoxide_command={{ cmd }} rem Jump to a directory using only keywords. -"%SystemRoot%\system32\doskey.exe" %__zoxide_command% = (for %\p%^^^^ in ("") do @for /f "delims=" %\p%i in (^^""$*%\p%~^^"^") do @if "%\p%~i" == "" (if defined HOME (for /f "delims=" %\p%c in (^^""%\p%HOME%\p%"^") do @%__zoxide_cd%) else ^>^&2 (echo(zoxide: HOME not set) ^& call) else if "%\p%~i" == "~" (if defined HOME (for /f "delims=" %\p%c in (^^""%\p%HOME%\p%"^") do @%__zoxide_cd%) else ^>^&2 (echo(zoxide: HOME not set) ^& call) else if "%\p%~i" == "-" (if defined OLDPWD (for /f "delims=" %\p%c in (^^""%\p%OLDPWD%\p%"^") do @%__zoxide_cd%) else ^>^&2 (echo(zoxide: OLDPWD not set) ^& call) else for /f "delims=" %\p%~ in (^^"%\p%~i^") do @for /f "tokens=1,* delims=d" %\p%a in ("-%\p%~a~") do @if "%\p%b" neq "" (for /f "delims=" %\p%c in (^^""%\p%~f~"^") do @%__zoxide_cd%) else if /i "%\p%CD%\p%" neq "%\p%__CD__%\p%" (for /f "delims=" %\p%q in ('zoxide query --exclude "%\p%CD%\p%" -- %\p%~i') do @(for /f "delims=" %\p%c in (^^""%\p%~fq"^") do @%__zoxide_cd%)) else (for /f "delims=" %\p%q in ('zoxide query --exclude "%\p%__CD__%\p%\" -- %\p%~i') do @(for /f "delims=" %\p%c in (^^""%\p%~fq"^") do @%__zoxide_cd%))) ^&^& (call ) +"%SystemRoot%\system32\doskey.exe" %__zoxide_command% = (for %\p%^^^^ in ("") do @for /f "delims=" %\p%i in (^^""$*%\p%~^^"^") do @if "%\p%~i" == "" (if defined HOME (for /f "delims=" %\p%c in (^^""%\p%HOME%\p%"^") do @%__zoxide_cd%) else ^>^&2 (echo(zoxide: HOME not set) ^& call) else if "%\p%~i" == "~" (if defined HOME (for /f "delims=" %\p%c in (^^""%\p%HOME%\p%"^") do @%__zoxide_cd%) else ^>^&2 (echo(zoxide: HOME not set) ^& call) else if "%\p%~i" == "-" (if defined OLDPWD (for /f "delims=" %\p%c in (^^""%\p%OLDPWD%\p%"^") do @%__zoxide_cd%) else ^>^&2 (echo(zoxide: OLDPWD not set) ^& call) else for /f "delims=" %\p%~ in (^^"%\p%~i^") do @for /f "tokens=1,* delims=d" %\p%a in ("-%\p%~a~") do @if not "%\p%b" == "" (for /f "delims=" %\p%c in (^^""%\p%~f~"^") do @%__zoxide_cd%) else if /i "%\p%CD%\p%" neq "%\p%__CD__%\p%" (for /f "delims=" %\p%q in ('zoxide query --exclude "%\p%CD%\p%" -- %\p%~i') do @(for /f "delims=" %\p%c in (^^""%\p%~fq"^") do @%__zoxide_cd%)) else (for /f "delims=" %\p%q in ('zoxide query --exclude "%\p%__CD__%\p%\" -- %\p%~i') do @(for /f "delims=" %\p%c in (^^""%\p%~fq"^") do @%__zoxide_cd%))) ^&^& (call ) rem Jump to a directory using interactive search. "%SystemRoot%\system32\doskey.exe" %__zoxide_command%i = (for %\p%^^^^ in ("") do @for /f "delims=" %\p%i in (^^""$*%\p%~^^"^") do @for /f "delims=" %\p%p in ('zoxide query --interactive -- %\p%~i') do @for /f "delims=" %\p%c in (^^""%\p%~fp"^") do @%__zoxide_cd%) ^&^& (call ) From cca937c9079ebf097ff0bf44da38f8dcc1e52ffb Mon Sep 17 00:00:00 2001 From: mataha Date: Mon, 10 Jun 2024 16:33:39 +0200 Subject: [PATCH 24/35] WIP --- .editorconfig | 2 +- man/man1/zoxide-init.1 | 2 +- src/shell.rs | 4 +-- src/util.rs | 63 ++++++++++-------------------------------- templates/cmd.txt | 18 ++++++------ 5 files changed, 29 insertions(+), 60 deletions(-) diff --git a/.editorconfig b/.editorconfig index aa6d76d..fba80de 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,7 +8,7 @@ indent_style = space insert_final_newline = true trim_trailing_whitespace = true -[*.(md,txt}] +[*.(md,rst,txt}] indent_size = unset trim_trailing_whitespace = false diff --git a/man/man1/zoxide-init.1 b/man/man1/zoxide-init.1 index 3eb172c..9ea1361 100644 --- a/man/man1/zoxide-init.1 +++ b/man/man1/zoxide-init.1 @@ -13,7 +13,7 @@ Add this to the \fBend\fR of your config file (usually \fB~/.bashrc\fR): \fBeval "$(zoxide init bash)"\fR .fi .TP -.B cmd +.B cmd.exe Add this to the \fBend\fR of your config file or AutoRun command: .sp .nf diff --git a/src/shell.rs b/src/shell.rs index 0c4568b..5ab873c 100644 --- a/src/shell.rs +++ b/src/shell.rs @@ -111,7 +111,7 @@ mod tests { .success(); if opts.hook != InitHook::None { - assert.stderr("zoxide: hooks are not supported on cmd shell.\r\n"); + assert.stderr("zoxide: hooks are not supported on cmd.exe shell.\r\n"); } else { assert.stderr(""); } @@ -130,7 +130,7 @@ mod tests { .success(); if opts.hook != InitHook::None { - assert.stderr("zoxide: hooks are not supported on cmd shell.\r\n"); + assert.stderr("zoxide: hooks are not supported on cmd.exe shell.\r\n"); } else { assert.stderr(""); } diff --git a/src/util.rs b/src/util.rs index 18d1c75..996f61d 100644 --- a/src/util.rs +++ b/src/util.rs @@ -296,77 +296,44 @@ pub fn resolve_path(path: impl AsRef) -> Result { } } - fn get_drive_prefix_path(drive_letter: u8) -> PathBuf { - format!(r"{}:\", patch_drive_letter(drive_letter)).into() + fn get_drive_path(drive_letter: u8) -> PathBuf { + format!(r"{}:\", drive_letter as char).into() } - fn get_drive_relative_path(drive_letter: u8) -> Result { + fn get_drive_relative(drive_letter: u8) -> Result { let path = current_dir()?; if Some(drive_letter) == get_drive_letter(&path) { - return Ok(patch_drive_prefix(path)); + return Ok(path); } - if let Some(path) = env::var_os(format!("={}:", patch_drive_letter(drive_letter))) { - return Ok(patch_drive_prefix(path.into())); + if let Some(path) = env::var_os(format!("={}:", drive_letter as char)) { + return Ok(path.into()); } - let path = get_drive_prefix_path(drive_letter); + let path = get_drive_path(drive_letter); Ok(path) } - #[inline(always)] - fn patch_drive_letter(drive_letter: u8) -> char { - drive_letter.to_ascii_uppercase() as char - } - - // https://github.com/rust-lang/rust-analyzer/pull/14689 - fn patch_drive_prefix(path: PathBuf) -> PathBuf { - let mut components = path.components(); - - match components.next() { - Some(Component::Prefix(prefix)) => { - let prefix = match prefix.kind() { - Prefix::Disk(drive_letter) => { - format!(r"{}:", patch_drive_letter(drive_letter)) - } - Prefix::VerbatimDisk(drive_letter) => { - format!(r"\\?\{}:", patch_drive_letter(drive_letter)) - } - _ => return path, - }; - - let mut path = PathBuf::default(); - path.push(prefix); - path.extend(components); - path - } - _ => path, - } - } - match components.peek() { Some(Component::Prefix(prefix)) => match prefix.kind() { Prefix::Disk(drive_letter) => { - components.next(); + let disk = components.next().unwrap(); if components.peek() == Some(&Component::RootDir) { - components.next(); - base_path = get_drive_prefix_path(drive_letter); + let root = components.next().unwrap(); + stack.push(disk); + stack.push(root); } else { - base_path = get_drive_relative_path(drive_letter)?; + base_path = get_drive_relative(drive_letter)?; + stack.extend(base_path.components()); } - - stack.extend(base_path.components()); } Prefix::VerbatimDisk(drive_letter) => { components.next(); if components.peek() == Some(&Component::RootDir) { components.next(); - base_path = get_drive_prefix_path(drive_letter); - } else { - // Verbatim prefix without a root component? Likely not a legal path - bail!("illegal path: {}", path.display()); } + base_path = get_drive_path(drive_letter); stack.extend(base_path.components()); } _ => bail!("invalid path: {}", path.display()), @@ -378,7 +345,7 @@ pub fn resolve_path(path: impl AsRef) -> Result { let drive_letter = get_drive_letter(¤t_dir).with_context(|| { format!("could not get drive letter: {}", current_dir.display()) })?; - base_path = get_drive_prefix_path(drive_letter); + base_path = get_drive_path(drive_letter); stack.extend(base_path.components()); } _ => { diff --git a/templates/cmd.txt b/templates/cmd.txt index 4b02a01..065a81d 100644 --- a/templates/cmd.txt +++ b/templates/cmd.txt @@ -5,10 +5,12 @@ rem Code generated by zoxide. DO NOT EDIT. @if "%=^%=" == "%=%=" ( set \p=%%&2 echo %__program%: hooks are not supported on cmd.exe shell. {%- else -%} ->&2 echo zoxide: hooks are not supported on cmd shell. +{{ not_configured }} {%- endif %} @@ -29,10 +31,10 @@ rem Utility functions for zoxide. rem rem pwd based on the value of _ZO_RESOLVE_SYMLINKS. -set __zoxide_pwd={%- if resolve_symlinks -%} (for /f "skip=9 tokens=1,2,*" %\p%j in ('"%SystemRoot%\system32\fsutil.exe" reparsepoint query .') do @if "%\p%~j" == "Print" if "%\p%~k" == "Name:" if not "%\p%~l" == "" (echo(%%~l)) ^^^^^^^|^^^^^^^| {%~ endif -%} %__builtin_pwd% +set __zoxide_pwd= {%- if resolve_symlinks -%} (for /f "skip=9 tokens=1,2,*" %\p%j in ('^^^^^^^^""%SystemRoot%\system32\fsutil.exe" reparsepoint query .^"') do @if "%\p%~j" == "Print" if "%\p%~k" == "Name:" if not "%\p%~l" == "" (echo(%%~l)) ^^^^^^^|^^^^^^^| {%~ endif -%} %__builtin_pwd% rem cd + custom logic based on the value of _ZO_ECHO. -set __zoxide_cd=if /i "%\p%CD%\p%" neq "%\p%~fc" (%__builtin_cd% "%\p%~fc" ^^^&^^^& set "OLDPWD=%\p%CD%\p%" ^^^&^^^& (for /f "delims=" %\p%l in ('"%__builtin_pwd%"') do @if /i "%\p%~dpl" neq "%\p%~fl" (zoxide add -- "%\p%~fl") else (zoxide add -- "%\p%~fl\")) {%- if echo ~%} ^^^&^^^& %__zoxide_pwd% {%- endif ~%} ^^^&^^^& if defined CDCMD (call %\p%CDCMD%\p%)) +set __zoxide_cd=if /i "%\p%CD%\p%" neq "%\p%~fc" (%__builtin_cd% "%\p%~fc" ^^^&^^^& set "OLDPWD=%\p%CD%\p%" ^^^&^^^& (for /f "delims=" %\p%l in ('"%__builtin_pwd%"') do @if /i "%\p%~fl" neq "%\p%~dpl" (%__program% add -- "%\p%~fl") else (%__program% add -- "%\p%~dpl\")) {%- if echo ~%} ^^^&^^^& %__zoxide_pwd% {%- endif ~%} ^^^&^^^& if defined CDCMD (call %\p%CDCMD%\p%)) {{ section }} rem Commands for zoxide. Disable these using --no-cmd. @@ -44,10 +46,10 @@ rem set __zoxide_command={{ cmd }} rem Jump to a directory using only keywords. -"%SystemRoot%\system32\doskey.exe" %__zoxide_command% = (for %\p%^^^^ in ("") do @for /f "delims=" %\p%i in (^^""$*%\p%~^^"^") do @if "%\p%~i" == "" (if defined HOME (for /f "delims=" %\p%c in (^^""%\p%HOME%\p%"^") do @%__zoxide_cd%) else ^>^&2 (echo(zoxide: HOME not set) ^& call) else if "%\p%~i" == "~" (if defined HOME (for /f "delims=" %\p%c in (^^""%\p%HOME%\p%"^") do @%__zoxide_cd%) else ^>^&2 (echo(zoxide: HOME not set) ^& call) else if "%\p%~i" == "-" (if defined OLDPWD (for /f "delims=" %\p%c in (^^""%\p%OLDPWD%\p%"^") do @%__zoxide_cd%) else ^>^&2 (echo(zoxide: OLDPWD not set) ^& call) else for /f "delims=" %\p%~ in (^^"%\p%~i^") do @for /f "tokens=1,* delims=d" %\p%a in ("-%\p%~a~") do @if not "%\p%b" == "" (for /f "delims=" %\p%c in (^^""%\p%~f~"^") do @%__zoxide_cd%) else if /i "%\p%CD%\p%" neq "%\p%__CD__%\p%" (for /f "delims=" %\p%q in ('zoxide query --exclude "%\p%CD%\p%" -- %\p%~i') do @(for /f "delims=" %\p%c in (^^""%\p%~fq"^") do @%__zoxide_cd%)) else (for /f "delims=" %\p%q in ('zoxide query --exclude "%\p%__CD__%\p%\" -- %\p%~i') do @(for /f "delims=" %\p%c in (^^""%\p%~fq"^") do @%__zoxide_cd%))) ^&^& (call ) +"%SystemRoot%\system32\doskey.exe" %__zoxide_command% = @(for %\p%^^^^ in ("") do @for /f "delims=" %\p%i in (^^""$*%\p%~^^"^") do @if "%\p%~i" == "" (if "%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%" == "" (for /f "delims=" %\p%c in (^^""%\p%USERPROFILE%\p%"^") do @%__zoxide_cd%) else for /f "delims=" %\p%c in (^^""%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%"^") do @%__zoxide_cd%) else if "%\p%~i" == "~" (if "%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%" == "" (for /f "delims=" %\p%c in (^^""%\p%USERPROFILE%\p%"^") do @%__zoxide_cd%) else for /f "delims=" %\p%c in (^^""%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%"^") do @%__zoxide_cd%) else if "%\p%~i" == "-" (if defined OLDPWD (for /f "delims=" %\p%c in (^^""%\p%OLDPWD%\p%"^") do @%__zoxide_cd%) else ^>^&2 (echo(%__program%: OLDPWD not set) ^& (call)) else for /f "delims=" %\p%~ in (^^"%\p%~i^") do @for /f "tokens=1,* delims=d" %\p%a in ("-%\p%~a~") do @if not "%\p%b" == "" (for /f "delims=" %\p%c in (^^""%\p%~f~"^") do @%__zoxide_cd%) else if /i "%\p%CD%\p%" neq "%\p%__CD__%\p%" (for /f "delims=" %\p%q in ('^^"%__program% query --exclude "%\p%CD%\p%" -- %\p%~i^"') do @(for /f "delims=" %\p%c in (^^""%\p%~fq"^") do @%__zoxide_cd%)) else (for /f "delims=" %\p%q in ('^^"%__program% query --exclude "%\p%__CD__%\p%\" -- %\p%~i^"') do @(for /f "delims=" %\p%c in (^^""%\p%~fq"^") do @%__zoxide_cd%))) ^&^& call ; rem Jump to a directory using interactive search. -"%SystemRoot%\system32\doskey.exe" %__zoxide_command%i = (for %\p%^^^^ in ("") do @for /f "delims=" %\p%i in (^^""$*%\p%~^^"^") do @for /f "delims=" %\p%p in ('zoxide query --interactive -- %\p%~i') do @for /f "delims=" %\p%c in (^^""%\p%~fp"^") do @%__zoxide_cd%) ^&^& (call ) +"%SystemRoot%\system32\doskey.exe" %__zoxide_command%i = @(for %\p%^^^^ in ("") do @for /f "delims=" %\p%i in (^^""$*%\p%~^^"^") do @for /f "delims=" %\p%p in ('^^"%__program% query --interactive -- %\p%~i^"') do @for /f "delims=" %\p%c in (^^""%\p%~fp"^") do @%__zoxide_cd%) ^&^& call ; {%- when None %} From 9d9d605d50e53d51079a34ba8558a77c26eb0ee4 Mon Sep 17 00:00:00 2001 From: mataha Date: Tue, 11 Jun 2024 00:25:55 +0200 Subject: [PATCH 25/35] Make clippy and rustfmt happy --- .editorconfig | 2 +- templates/cmd.txt | 4 ++-- zoxide.plugin.zsh | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.editorconfig b/.editorconfig index fba80de..b4d1b33 100644 --- a/.editorconfig +++ b/.editorconfig @@ -12,5 +12,5 @@ trim_trailing_whitespace = true indent_size = unset trim_trailing_whitespace = false -[*.{nix,ts,yml,zsh}] +[*.{nix,ts,yml}] indent_size = 2 diff --git a/templates/cmd.txt b/templates/cmd.txt index 065a81d..eae30ec 100644 --- a/templates/cmd.txt +++ b/templates/cmd.txt @@ -31,7 +31,7 @@ rem Utility functions for zoxide. rem rem pwd based on the value of _ZO_RESOLVE_SYMLINKS. -set __zoxide_pwd= {%- if resolve_symlinks -%} (for /f "skip=9 tokens=1,2,*" %\p%j in ('^^^^^^^^""%SystemRoot%\system32\fsutil.exe" reparsepoint query .^"') do @if "%\p%~j" == "Print" if "%\p%~k" == "Name:" if not "%\p%~l" == "" (echo(%%~l)) ^^^^^^^|^^^^^^^| {%~ endif -%} %__builtin_pwd% +set __zoxide_pwd= {%- if resolve_symlinks -%} (for /f "skip=9 tokens=1,2,*" %\p%j in ('^^^^^^^^""%SystemRoot%\system32\fsutil.exe" reparsepoint query .^"') do @if "%\p%~j" equ "Print" if "%\p%~k" equ "Name:" if "%\p%~l" neq "" (echo(%\p%~l)) ^^^^^^^|^^^^^^^| {%~ endif -%} %__builtin_pwd% rem cd + custom logic based on the value of _ZO_ECHO. set __zoxide_cd=if /i "%\p%CD%\p%" neq "%\p%~fc" (%__builtin_cd% "%\p%~fc" ^^^&^^^& set "OLDPWD=%\p%CD%\p%" ^^^&^^^& (for /f "delims=" %\p%l in ('"%__builtin_pwd%"') do @if /i "%\p%~fl" neq "%\p%~dpl" (%__program% add -- "%\p%~fl") else (%__program% add -- "%\p%~dpl\")) {%- if echo ~%} ^^^&^^^& %__zoxide_pwd% {%- endif ~%} ^^^&^^^& if defined CDCMD (call %\p%CDCMD%\p%)) @@ -46,7 +46,7 @@ rem set __zoxide_command={{ cmd }} rem Jump to a directory using only keywords. -"%SystemRoot%\system32\doskey.exe" %__zoxide_command% = @(for %\p%^^^^ in ("") do @for /f "delims=" %\p%i in (^^""$*%\p%~^^"^") do @if "%\p%~i" == "" (if "%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%" == "" (for /f "delims=" %\p%c in (^^""%\p%USERPROFILE%\p%"^") do @%__zoxide_cd%) else for /f "delims=" %\p%c in (^^""%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%"^") do @%__zoxide_cd%) else if "%\p%~i" == "~" (if "%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%" == "" (for /f "delims=" %\p%c in (^^""%\p%USERPROFILE%\p%"^") do @%__zoxide_cd%) else for /f "delims=" %\p%c in (^^""%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%"^") do @%__zoxide_cd%) else if "%\p%~i" == "-" (if defined OLDPWD (for /f "delims=" %\p%c in (^^""%\p%OLDPWD%\p%"^") do @%__zoxide_cd%) else ^>^&2 (echo(%__program%: OLDPWD not set) ^& (call)) else for /f "delims=" %\p%~ in (^^"%\p%~i^") do @for /f "tokens=1,* delims=d" %\p%a in ("-%\p%~a~") do @if not "%\p%b" == "" (for /f "delims=" %\p%c in (^^""%\p%~f~"^") do @%__zoxide_cd%) else if /i "%\p%CD%\p%" neq "%\p%__CD__%\p%" (for /f "delims=" %\p%q in ('^^"%__program% query --exclude "%\p%CD%\p%" -- %\p%~i^"') do @(for /f "delims=" %\p%c in (^^""%\p%~fq"^") do @%__zoxide_cd%)) else (for /f "delims=" %\p%q in ('^^"%__program% query --exclude "%\p%__CD__%\p%\" -- %\p%~i^"') do @(for /f "delims=" %\p%c in (^^""%\p%~fq"^") do @%__zoxide_cd%))) ^&^& call ; +"%SystemRoot%\system32\doskey.exe" %__zoxide_command% = @(for %\p%^^^^ in ("") do @for /f "delims=" %\p%i in (^^""$*%\p%~^^"^") do @if "%\p%~i" equ "" (if "%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%" equ "" (for /f "delims=" %\p%c in (^^""%\p%USERPROFILE%\p%"^") do @%__zoxide_cd%) else for /f "delims=" %\p%c in (^^""%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%"^") do @%__zoxide_cd%) else if "%\p%~i" equ "~" (if "%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%" equ "" (for /f "delims=" %\p%c in (^^""%\p%USERPROFILE%\p%"^") do @%__zoxide_cd%) else for /f "delims=" %\p%c in (^^""%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%"^") do @%__zoxide_cd%) else if "%\p%~i" equ "-" (if defined OLDPWD (for /f "delims=" %\p%c in (^^""%\p%OLDPWD%\p%"^") do @%__zoxide_cd%) else ^>^&2 (echo(%__program%: OLDPWD not set) ^& call) else for /f "delims=" %\p%~ in (^^"%\p%~i^") do @for /f "tokens=1,* delims=d" %\p%a in ("-%\p%~a~") do @if "%\p%b" neq "" (for /f "delims=" %\p%c in (^^""%\p%~f~"^") do @%__zoxide_cd%) else if /i "%\p%CD%\p%" neq "%\p%__CD__%\p%" (for /f "delims=" %\p%q in ('^^"%__program% query --exclude "%\p%CD%\p%" -- %\p%~i^"') do @(for /f "delims=" %\p%c in (^^""%\p%~fq"^") do @%__zoxide_cd%)) else (for /f "delims=" %\p%q in ('^^"%__program% query --exclude "%\p%__CD__%\p%\" -- %\p%~i^"') do @(for /f "delims=" %\p%c in (^^""%\p%~fq"^") do @%__zoxide_cd%))) ^&^& call ; rem Jump to a directory using interactive search. "%SystemRoot%\system32\doskey.exe" %__zoxide_command%i = @(for %\p%^^^^ in ("") do @for /f "delims=" %\p%i in (^^""$*%\p%~^^"^") do @for /f "delims=" %\p%p in ('^^"%__program% query --interactive -- %\p%~i^"') do @for /f "delims=" %\p%c in (^^""%\p%~fp"^") do @%__zoxide_cd%) ^&^& call ; diff --git a/zoxide.plugin.zsh b/zoxide.plugin.zsh index aa89a44..cba04b2 100644 --- a/zoxide.plugin.zsh +++ b/zoxide.plugin.zsh @@ -1,5 +1,5 @@ if (( $+commands[zoxide] )); then - eval "$(zoxide init zsh)" + eval "$(zoxide init zsh)" else - echo 'zoxide: command not found, please install it from https://github.com/ajeetdsouza/zoxide' + echo 'zoxide: command not found, please install it from https://github.com/ajeetdsouza/zoxide' fi From 3cc6de20ac2473c1d79fd8bbeca3fd0986abb6fd Mon Sep 17 00:00:00 2001 From: mataha Date: Tue, 11 Jun 2024 01:01:56 +0200 Subject: [PATCH 26/35] Update documentation --- README.md | 20 ++++++++------------ man/man1/zoxide-init.1 | 8 ++++---- man/man1/zoxide.1 | 4 ++-- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 1448383..c30c802 100644 --- a/README.md +++ b/README.md @@ -135,9 +135,6 @@ zoxide can be installed in 4 easy steps:
Windows - > zoxide works with PowerShell, as well as shells running in Cygwin, Git - > Bash, and MSYS2. - > > The recommended way to install zoxide is via `winget`: > > ```sh @@ -409,7 +406,7 @@ When calling `zoxide init`, the following flags are available: - `--cmd` - Changes the prefix of the `z` and `zi` commands. - `--cmd j` would change the commands to (`j`, `ji`). - - `--cmd cd` would replace the `cd` command. + - `--cmd cd` would replace the `cd` command (highly recommended on `cmd.exe`). - `--hook ` - Changes how often zoxide increments a directory's score: @@ -421,8 +418,8 @@ When calling `zoxide init`, the following flags are available: - `--no-cmd` - Prevents zoxide from defining the `z` and `zi` commands. - - These functions will still be available in your shell as `__zoxide_z` and - `__zoxide_zi`, should you choose to redefine them. + - These functions will still be available in your shell (not on `cmd.exe`) + as `__zoxide_z` and `__zoxide_zi`, should you choose to redefine them. ### Environment variables @@ -440,17 +437,16 @@ Environment variables[^2] can be used for configuration. They must be set before | Windows | `%LOCALAPPDATA%` | `C:\Users\Alice\AppData\Local` | - `_ZO_ECHO` - - When set to 1, `z` will print the matched directory before navigating to - it. + - When set to 1, `z` will print the matched directory after navigating to it. - `_ZO_EXCLUDE_DIRS` - Excludes the specified directories from the database. - This is provided as a list of [globs][glob], separated by OS-specific characters: - | OS | Separator | Example | - | ------------------- | --------- | ----------------------- | - | Linux / macOS / BSD | `:` | `$HOME:$HOME/private/*` | - | Windows | `;` | `$HOME;$HOME/private/*` | + | OS | Separator | Example | + | ------------------- | --------- | ------------------------- | + | Linux / macOS / BSD | `:` | `$HOME:$HOME/private/*` | + | Windows | `;` | `%HOME%;%HOME%/private/*` | - By default, this is set to `"$HOME"`. - `_ZO_FZF_OPTS` diff --git a/man/man1/zoxide-init.1 b/man/man1/zoxide-init.1 index 9ea1361..6a2e706 100644 --- a/man/man1/zoxide-init.1 +++ b/man/man1/zoxide-init.1 @@ -98,8 +98,8 @@ Changes the prefix of the \fBz\fR and \fBzi\fR commands. .br \fB--cmd j\fR would change the commands to (\fBj\fR, \fBji\fR). .br -\fB--cmd cd\fR would replace the \fBcd\fR command (doesn't work on Nushell / -POSIX shells). +\fB--cmd cd\fR would replace the \fBcd\fR command (highly recommended on +\fBcmd.exe\fR). .TP .B -h, --help Print help information. @@ -116,8 +116,8 @@ l l. .TP .B --no-cmd Prevents zoxide from defining the \fBz\fR and \fBzi\fR commands. These functions -will still be available in your shell as \fB__zoxide_z\fR and \fB__zoxide_zi\fR, -should you choose to redefine them. +will still be available in your shell (not on \fBcmd.exe\fR) as \fB__zoxide_z\fR +and \fB__zoxide_zi\fR, should you choose to redefine them. .SH REPORTING BUGS For any issues, feature requests, or questions, please visit: .sp diff --git a/man/man1/zoxide.1 b/man/man1/zoxide.1 index ef1792b..5ee7c0c 100644 --- a/man/man1/zoxide.1 +++ b/man/man1/zoxide.1 @@ -70,7 +70,7 @@ T} .TE .TP .B _ZO_ECHO -When set to 1, \fBz\fR will print the matched directory before navigating to it. +When set to 1, \fBz\fR will print the matched directory after navigating to it. .TP .B _ZO_EXCLUDE_DIRS Prevents the specified directories from being added to the database. This is @@ -82,7 +82,7 @@ l l. \fBLinux/macOS/BSD\fR|T{ \fB:\fR, eg. \fB$HOME:$HOME/private/*\fR T} - \fBWindows\fR|\fB;\fR, eg. \fB$HOME;$HOME/private/*\fR + \fBWindows\fR|\fB;\fR, eg. \fB%HOME%;%HOME%/private/*\fR .TE .sp By default, this is set to \fB$HOME\fR. After setting this up, you might need From 699126567f40f24734f7cd50520eae5fda7b29f5 Mon Sep 17 00:00:00 2001 From: mataha Date: Tue, 11 Jun 2024 01:26:11 +0200 Subject: [PATCH 27/35] Code cleanup --- src/main.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index d4ddd6e..2d76539 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,3 @@ -#![allow(clippy::single_component_path_imports)] - mod cmd; mod config; mod db; From 5b2eca1cf8aaebe976ceb5815251f5cf7bee3041 Mon Sep 17 00:00:00 2001 From: mataha Date: Fri, 14 Jun 2024 16:14:34 +0200 Subject: [PATCH 28/35] Fix newlines --- .cargo/config.toml | 3 --- .gitattributes | 9 ++++----- rustfmt.toml | 2 +- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 4b40e31..626e366 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,6 +1,3 @@ -[alias] -xtask = "run --package xtask --" - # On Windows MSVC, statically link the C runtime so that the resulting EXE does # not depend on the vcruntime DLL. [target.'cfg(all(windows, target_env = "msvc"))'] diff --git a/.gitattributes b/.gitattributes index a9a91a2..eeb6151 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,4 @@ -/contrib/completions/* eol=lf linguist-generated=true text -/contrib/completions/README.md -eol -linguist-generated -text -/init.fish eol=lf text -/templates/*.txt eol=lf text -/zoxide.plugin.zsh eol=lf text +* text=auto eol=lf + +/contrib/completions/** linguist-generated +/contrib/completions/README.md -linguist-generated diff --git a/rustfmt.toml b/rustfmt.toml index 72efef7..c216cd1 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,6 +1,6 @@ group_imports = "StdExternalCrate" imports_granularity = "Module" -newline_style = "Native" +newline_style = "Unix" use_field_init_shorthand = true use_small_heuristics = "Max" use_try_shorthand = true From e79df688eedba43ac57bf1c65e19574a679478e0 Mon Sep 17 00:00:00 2001 From: mataha Date: Sat, 15 Jun 2024 01:29:09 +0200 Subject: [PATCH 29/35] Fix stdin end of input --- .editorconfig | 2 +- README.md | 2 +- man/man1/zoxide-init.1 | 2 +- src/shell.rs | 24 ++++++++++++------------ templates/cmd.txt | 16 +++++++++------- 5 files changed, 24 insertions(+), 22 deletions(-) diff --git a/.editorconfig b/.editorconfig index b4d1b33..b18438d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,7 +8,7 @@ indent_style = space insert_final_newline = true trim_trailing_whitespace = true -[*.(md,rst,txt}] +[*.{md,rst,txt}] indent_size = unset trim_trailing_whitespace = false diff --git a/README.md b/README.md index c30c802..445248a 100644 --- a/README.md +++ b/README.md @@ -216,7 +216,7 @@ zoxide can be installed in 4 easy steps: > Add this to the **end** of your config file or AutoRun command: > > ```batchfile - > zoxide init cmd --hook none | cmd /d/q/k >nul + > zoxide init cmd | cmd /d/q/k echo off > ```
diff --git a/man/man1/zoxide-init.1 b/man/man1/zoxide-init.1 index 6a2e706..afe04db 100644 --- a/man/man1/zoxide-init.1 +++ b/man/man1/zoxide-init.1 @@ -17,7 +17,7 @@ Add this to the \fBend\fR of your config file (usually \fB~/.bashrc\fR): Add this to the \fBend\fR of your config file or AutoRun command: .sp .nf - \fBzoxide init cmd --hook none | cmd /d/q/k >nul\fR + \fBzoxide init cmd | cmd /d/q/k echo off\fR .fi .TP .B elvish diff --git a/src/shell.rs b/src/shell.rs index 5ab873c..d4c2fd1 100644 --- a/src/shell.rs +++ b/src/shell.rs @@ -105,15 +105,15 @@ mod tests { let source = Cmd(&opts).render().unwrap(); let assert = Command::new(which::which("cmd.exe").unwrap()) - .args(["/d", "/x", "/k"]) + .args(["/x", "/d", "/q", "/k", "echo off"]) + .env("PROMPT", "") .write_stdin(source) .assert() - .success(); + .success() + .stderr(""); - if opts.hook != InitHook::None { - assert.stderr("zoxide: hooks are not supported on cmd.exe shell.\r\n"); - } else { - assert.stderr(""); + if opts.hook == InitHook::None { + assert.stdout(""); } } @@ -124,15 +124,15 @@ mod tests { let source = Cmd(&opts).render().unwrap(); let assert = Command::new(which::which("cmd.exe").unwrap()) - .args(["/d", "/y", "/k"]) + .args(["/y", "/d", "/q", "/k", "echo off"]) + .env("PROMPT", "") .write_stdin(source) .assert() - .success(); + .success() + .stderr(""); - if opts.hook != InitHook::None { - assert.stderr("zoxide: hooks are not supported on cmd.exe shell.\r\n"); - } else { - assert.stderr(""); + if opts.hook == InitHook::None { + assert.stdout(""); } } diff --git a/templates/cmd.txt b/templates/cmd.txt index eae30ec..802b16c 100644 --- a/templates/cmd.txt +++ b/templates/cmd.txt @@ -3,11 +3,7 @@ rem Code generated by zoxide. DO NOT EDIT. -@if "%=^%=" == "%=%=" ( - set \p=%%&2 echo %__program%: hooks are not supported on cmd.exe shell. +echo %__program%: hooks are not supported on cmd.exe shell. +echo Use '%__program% init cmd --hook none' instead. {%- else -%} {{ not_configured }} @@ -60,4 +57,9 @@ rem Jump to a directory using interactive search. {{ section }} rem To initialize zoxide, add this to your configuration or AutoRun command: rem -rem zoxide init cmd --hook none | cmd /d/q/k >nul +rem zoxide init cmd | cmd /d/q/k echo off + +{#~ + Content piped to `cmd.exe` needs to end with an empty line to indicate end of + input. Removing this will cause extra "More? " to be written to stdout. +#} From d838651f51999fa39386aff4261683e8e574b699 Mon Sep 17 00:00:00 2001 From: mataha Date: Sat, 15 Jun 2024 17:11:45 +0200 Subject: [PATCH 30/35] Fix formatting --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 445248a..363b34f 100644 --- a/README.md +++ b/README.md @@ -211,9 +211,9 @@ zoxide can be installed in 4 easy steps:
- `cmd.exe` + cmd.exe - > Add this to the **end** of your config file or AutoRun command: + > Add this to the **end** of your config file or AutoRun command: > > ```batchfile > zoxide init cmd | cmd /d/q/k echo off From 862bdf16e471c821a153f3dd9b79abd3409e8638 Mon Sep 17 00:00:00 2001 From: mataha Date: Mon, 17 Jun 2024 00:41:02 +0200 Subject: [PATCH 31/35] Consider PATHEXT when searching for fzf binary --- src/util.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util.rs b/src/util.rs index 996f61d..8deb0b5 100644 --- a/src/util.rs +++ b/src/util.rs @@ -31,7 +31,7 @@ impl Fzf { // Instead, we resolve the path to the executable and then pass it to // CreateProcess. #[cfg(windows)] - let program = which::which("fzf.exe").map_err(|_| anyhow!(Self::ERR_FZF_NOT_FOUND))?; + let program = which::which("fzf").map_err(|_| anyhow!(Self::ERR_FZF_NOT_FOUND))?; #[cfg(not(windows))] let program = "fzf"; From 28bddb93898d28b8dad3c0219cca1b77b24812a0 Mon Sep 17 00:00:00 2001 From: mataha Date: Fri, 5 Jul 2024 01:15:44 +0200 Subject: [PATCH 32/35] Switch to labeled comments --- templates/cmd.txt | 59 +++++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/templates/cmd.txt b/templates/cmd.txt index 802b16c..d3e334b 100644 --- a/templates/cmd.txt +++ b/templates/cmd.txt @@ -1,22 +1,26 @@ -{%- let section = "rem ===========================================================================\nrem" -%} -{%- let not_configured = "rem -- not configured --" -%} - -rem Code generated by zoxide. DO NOT EDIT. +{%- let section = "::: ===========================================================================\n:::" -%} +{%- let not_configured = "::: -- not configured --" -%} @if "%=^%=" == "%=%=" (set \p=%%^&2 (echo(%program%: OLDPWD not set) ^& %builtin_false%) else for /f "delims=" %\p%~ in (^^"%\p%~i^") do @for /f "tokens=1,* delims=d" %\p%a in ("-%\p%~a~") do @if "%\p%b" neq "" (for /f "delims=" %\p%c in (^^""%\p%~f~"^") do @%__zoxide_cd%) else if /i "%\p%CD%\p%" neq "%\p%__CD__%\p%" (for /f "delims=" %\p%q in ('^^"%program% query --exclude "%\p%CD%\p%" -- %\p%~i^"') do @(for /f "delims=" %\p%c in (^^""%\p%~fq"^") do @%__zoxide_cd%)) else (for /f "delims=" %\p%q in ('^^"%program% query --exclude "%\p%__CD__%\p%\" -- %\p%~i^"') do @(for /f "delims=" %\p%c in (^^""%\p%~fq"^") do @%__zoxide_cd%))) ^&^& %builtin_true% -rem Jump to a directory using only keywords. -"%SystemRoot%\system32\doskey.exe" %__zoxide_command% = @(for %\p%^^^^ in ("") do @for /f "delims=" %\p%i in (^^""$*%\p%~^^"^") do @if "%\p%~i" equ "" (if "%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%" equ "" (for /f "delims=" %\p%c in (^^""%\p%USERPROFILE%\p%"^") do @%__zoxide_cd%) else for /f "delims=" %\p%c in (^^""%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%"^") do @%__zoxide_cd%) else if "%\p%~i" equ "~" (if "%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%" equ "" (for /f "delims=" %\p%c in (^^""%\p%USERPROFILE%\p%"^") do @%__zoxide_cd%) else for /f "delims=" %\p%c in (^^""%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%"^") do @%__zoxide_cd%) else if "%\p%~i" equ "-" (if defined OLDPWD (for /f "delims=" %\p%c in (^^""%\p%OLDPWD%\p%"^") do @%__zoxide_cd%) else ^>^&2 (echo(%__program%: OLDPWD not set) ^& call) else for /f "delims=" %\p%~ in (^^"%\p%~i^") do @for /f "tokens=1,* delims=d" %\p%a in ("-%\p%~a~") do @if "%\p%b" neq "" (for /f "delims=" %\p%c in (^^""%\p%~f~"^") do @%__zoxide_cd%) else if /i "%\p%CD%\p%" neq "%\p%__CD__%\p%" (for /f "delims=" %\p%q in ('^^"%__program% query --exclude "%\p%CD%\p%" -- %\p%~i^"') do @(for /f "delims=" %\p%c in (^^""%\p%~fq"^") do @%__zoxide_cd%)) else (for /f "delims=" %\p%q in ('^^"%__program% query --exclude "%\p%__CD__%\p%\" -- %\p%~i^"') do @(for /f "delims=" %\p%c in (^^""%\p%~fq"^") do @%__zoxide_cd%))) ^&^& call ; - -rem Jump to a directory using interactive search. -"%SystemRoot%\system32\doskey.exe" %__zoxide_command%i = @(for %\p%^^^^ in ("") do @for /f "delims=" %\p%i in (^^""$*%\p%~^^"^") do @for /f "delims=" %\p%p in ('^^"%__program% query --interactive -- %\p%~i^"') do @for /f "delims=" %\p%c in (^^""%\p%~fp"^") do @%__zoxide_cd%) ^&^& call ; +::: Jump to a directory using interactive search. +%sysdir%doskey.exe {{ cmd }}i = @(for %\p%^^^^ in ("") do @for /f "delims=" %\p%i in (^^""$*%\p%~^^"^") do @for /f "delims=" %\p%p in ('^^"%program% query --interactive -- %\p%~i^"') do @for /f "delims=" %\p%c in (^^""%\p%~fp"^") do @%__zoxide_cd%) ^&^& %builtin_true% {%- when None %} @@ -55,9 +58,9 @@ rem Jump to a directory using interactive search. {%- endmatch %} {{ section }} -rem To initialize zoxide, add this to your configuration or AutoRun command: -rem -rem zoxide init cmd | cmd /d/q/k echo off +::: To initialize zoxide, add this to your configuration or AutoRun command: +::: +::: zoxide init cmd | cmd /d/q/k echo off {#~ Content piped to `cmd.exe` needs to end with an empty line to indicate end of From e7ff4382b7c993544c76deaf32c8d469c4d81b61 Mon Sep 17 00:00:00 2001 From: mataha Date: Wed, 28 Jan 2026 15:22:09 +0100 Subject: [PATCH 33/35] Handle UTF-8 output correctly in `cmd.exe` --- templates/cmd.txt | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/templates/cmd.txt b/templates/cmd.txt index d3e334b..22e00bb 100644 --- a/templates/cmd.txt +++ b/templates/cmd.txt @@ -8,9 +8,6 @@ set program=zoxide set builtin_cd=chdir /d set builtin_pwd=(chdir) -set builtin_true=call; -set builtin_false=call - ::: Get Windows' system directory, like GetSystemDirectoryW. @if "" == "%SystemRoot%" (set sysdir="%__APPDIR__%") else (set sysdir="%SystemRoot%\system32\") @@ -35,7 +32,7 @@ echo Use '%program% init cmd --hook none' instead. set __zoxide_pwd= {%- if resolve_symlinks -%} (for /f "skip=9 tokens=1,2,*" %\p%j in ('^^^^^^^^"%sysdir%fsutil.exe reparsepoint query .^"') do @if "%\p%~j" equ "Print" if "%\p%~k" equ "Name:" if "%\p%~l" neq "" (echo(%\p%~l)) ^^^^^^^|^^^^^^^| {%~ endif -%} %builtin_pwd% ::: cd + custom logic based on the value of _ZO_ECHO. -set __zoxide_cd=if /i "%\p%CD%\p%" neq "%\p%~fc" (%builtin_cd% "%\p%~fc" ^^^&^^^& set "OLDPWD=%\p%CD%\p%" ^^^&^^^& (for /f "delims=" %\p%l in ('"%builtin_pwd%"') do @if /i "%\p%~fl" neq "%\p%~dpl" (%program% add -- "%\p%~fl") else (%program% add -- "%\p%~dpl\")) {%- if echo ~%} ^^^&^^^& %__zoxide_pwd% {%- endif ~%} ^^^&^^^& if defined CDCMD (call %\p%CDCMD%\p%)) +set __zoxide_cd=if /i "%\p%CD%\p%" neq "%\p%~fd" (%builtin_cd% "%\p%~fd" ^^^&^^^& set "OLDPWD=%\p%CD%\p%" ^^^&^^^& (for /f "delims=" %\p%l in ('"%builtin_pwd%"') do @if /i "%\p%~fl" neq "%\p%~dpl" (%program% add -- "%\p%~fl") else (%program% add -- "%\p%~dpl\")) {%- if echo ~%} ^^^&^^^& %__zoxide_pwd% {%- endif ~%} ^^^&^^^& if defined CDCMD (call %\p%CDCMD%\p%)) {{ section }} ::: Commands for zoxide. Disable these using --no-cmd. @@ -44,12 +41,12 @@ set __zoxide_cd=if /i "%\p%CD%\p%" neq "%\p%~fc" (%builtin_cd% "%\p%~fc" ^^^&^^^ {%- match cmd %} {%- when Some with (cmd) %} -::: @TODO for args %* %1 etc., boundary checking +::: @TODO for args %* %1 etc., boundary checking ::: Jump to a directory using only keywords. -%sysdir%doskey.exe {{ cmd }} = @(for %\p%^^^^ in ("") do @for /f "delims=" %\p%i in (^^""$*%\p%~^^"^") do @if "%\p%~i" equ "" (if "%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%" equ "" (for /f "delims=" %\p%c in (^^""%\p%USERPROFILE%\p%"^") do @%__zoxide_cd%) else for /f "delims=" %\p%c in (^^""%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%"^") do @%__zoxide_cd%) else if "%\p%~i" equ "~" (if "%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%" equ "" (for /f "delims=" %\p%c in (^^""%\p%USERPROFILE%\p%"^") do @%__zoxide_cd%) else for /f "delims=" %\p%c in (^^""%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%"^") do @%__zoxide_cd%) else if "%\p%~i" equ "-" (if defined OLDPWD (for /f "delims=" %\p%c in (^^""%\p%OLDPWD%\p%"^") do @%__zoxide_cd%) else ^>^&2 (echo(%program%: OLDPWD not set) ^& %builtin_false%) else for /f "delims=" %\p%~ in (^^"%\p%~i^") do @for /f "tokens=1,* delims=d" %\p%a in ("-%\p%~a~") do @if "%\p%b" neq "" (for /f "delims=" %\p%c in (^^""%\p%~f~"^") do @%__zoxide_cd%) else if /i "%\p%CD%\p%" neq "%\p%__CD__%\p%" (for /f "delims=" %\p%q in ('^^"%program% query --exclude "%\p%CD%\p%" -- %\p%~i^"') do @(for /f "delims=" %\p%c in (^^""%\p%~fq"^") do @%__zoxide_cd%)) else (for /f "delims=" %\p%q in ('^^"%program% query --exclude "%\p%__CD__%\p%\" -- %\p%~i^"') do @(for /f "delims=" %\p%c in (^^""%\p%~fq"^") do @%__zoxide_cd%))) ^&^& %builtin_true% +%sysdir%doskey.exe {{ cmd }} = @for /f "delims=" %\p%s in ('"%sysdir%chcp.com 2>nul"') do @for %\p%c in (%\p%~s) do @%sysdir%chcp.com %\p%~nc ^>nul 2^>^&1 ^&^& %sysdir%chcp.com 65001 ^>nul 2^>^&1 ^&^& @(for %\p%^^^^ in ("") do @for /f "delims=" %\p%i in (^^""$*%\p%~^^"^") do @if "%\p%~i" equ "" (if "%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%" equ "" (for /f "delims=" %\p%d in (^^""%\p%USERPROFILE%\p%"^") do @%__zoxide_cd%) else for /f "delims=" %\p%d in (^^""%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%"^") do @%__zoxide_cd%) else if "%\p%~i" equ "~" (if "%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%" equ "" (for /f "delims=" %\p%d in (^^""%\p%USERPROFILE%\p%"^") do @%__zoxide_cd%) else for /f "delims=" %\p%d in (^^""%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%"^") do @%__zoxide_cd%) else if "%\p%~i" equ "-" (if defined OLDPWD (for /f "delims=" %\p%d in (^^""%\p%OLDPWD%\p%"^") do @%__zoxide_cd%) else ^>^&2 (echo(%program%: OLDPWD not set) ^& call) else for /f "delims=" %\p%~ in (^^"%\p%~i^") do @for /f "tokens=1,* delims=d" %\p%a in ("-%\p%~a~") do @if "%\p%b" neq "" (for /f "delims=" %\p%d in (^^""%\p%~f~"^") do @%__zoxide_cd%) else if /i "%\p%CD%\p%" neq "%\p%__CD__%\p%" (for /f "delims=" %\p%q in ('^^"%program% query --exclude "%\p%CD%\p%" -- %\p%~i^"') do @(for /f "delims=" %\p%d in (^^""%\p%~fq"^") do @%__zoxide_cd%)) else (for /f "delims=" %\p%q in ('^^"%program% query --exclude "%\p%__CD__%\p%\" -- %\p%~i^"') do @(for /f "delims=" %\p%d in (^^""%\p%~fq"^") do @%__zoxide_cd%))) ^&^& %sysdir%chcp.com %\p%~nc ^>nul 2^>^&1 ^|^| %sysdir%chcp.com %\p%~nc ^>nul 2^>^&1 ^&^& call ::: Jump to a directory using interactive search. -%sysdir%doskey.exe {{ cmd }}i = @(for %\p%^^^^ in ("") do @for /f "delims=" %\p%i in (^^""$*%\p%~^^"^") do @for /f "delims=" %\p%p in ('^^"%program% query --interactive -- %\p%~i^"') do @for /f "delims=" %\p%c in (^^""%\p%~fp"^") do @%__zoxide_cd%) ^&^& %builtin_true% +%sysdir%doskey.exe {{ cmd }}i = @for /f "delims=" %\p%s in ('"%sysdir%chcp.com 2>nul"') do @for %\p%c in (%\p%~s) do @%sysdir%chcp.com %\p%~nc ^>nul 2^>^&1 ^&^& %sysdir%chcp.com 65001 ^>nul 2^>^&1 ^&^& @(for %\p%^^^^ in ("") do @for /f "delims=" %\p%i in (^^""$*%\p%~^^"^") do @for /f "delims=" %\p%p in ('^^"%program% query --interactive -- %\p%~i^"') do @for /f "delims=" %\p%d in (^^""%\p%~fp"^") do @%__zoxide_cd%) ^&^& %sysdir%chcp.com %\p%~nc ^>nul 2^>^&1 ^|^| %sysdir%chcp.com %\p%~nc ^>nul 2^>^&1 ^&^& call {%- when None %} From 31f6595f54011fe7f22acc6096f8b52bb807ff2c Mon Sep 17 00:00:00 2001 From: mataha Date: Wed, 28 Jan 2026 15:48:40 +0100 Subject: [PATCH 34/35] Point `cmd.exe` users to the registry key --- README.md | 3 ++- man/man1/zoxide-init.1 | 3 ++- templates/cmd.txt | 23 ++++++++--------------- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 363b34f..41dc83a 100644 --- a/README.md +++ b/README.md @@ -213,7 +213,8 @@ zoxide can be installed in 4 easy steps:
cmd.exe - > Add this to the **end** of your config file or AutoRun command: + > Add this to the **end** of your config file or AutoRun command + > (usually `HKEY_CURRENT_USER\Software\Microsoft\Command Processor\AutoRun`): > > ```batchfile > zoxide init cmd | cmd /d/q/k echo off diff --git a/man/man1/zoxide-init.1 b/man/man1/zoxide-init.1 index afe04db..7050be0 100644 --- a/man/man1/zoxide-init.1 +++ b/man/man1/zoxide-init.1 @@ -14,7 +14,8 @@ Add this to the \fBend\fR of your config file (usually \fB~/.bashrc\fR): .fi .TP .B cmd.exe -Add this to the \fBend\fR of your config file or AutoRun command: +Add this to the \fBend\fR of your config file or AutoRun command (usually +\fBHKEY_CURRENT_USER\\Software\\Microsoft\\Command Processor\\AutoRun\fR): .sp .nf \fBzoxide init cmd | cmd /d/q/k echo off\fR diff --git a/templates/cmd.txt b/templates/cmd.txt index 22e00bb..e1d31da 100644 --- a/templates/cmd.txt +++ b/templates/cmd.txt @@ -1,6 +1,12 @@ {%- let section = "::: ===========================================================================\n:::" -%} {%- let not_configured = "::: -- not configured --" -%} +{%- if hook != InitHook::None -%} +echo zoxide: hooks are not supported on cmd.exe shell. +echo Use '%program% init cmd --hook none' instead. + +{% endif -%} + @if "%=^%=" == "%=%=" (set \p=%%nul"') do @for %\p%c in (%\p%~s) do @%sysdir%chcp.com %\p%~nc ^>nul 2^>^&1 ^&^& %sysdir%chcp.com 65001 ^>nul 2^>^&1 ^&^& @(for %\p%^^^^ in ("") do @for /f "delims=" %\p%i in (^^""$*%\p%~^^"^") do @if "%\p%~i" equ "" (if "%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%" equ "" (for /f "delims=" %\p%d in (^^""%\p%USERPROFILE%\p%"^") do @%__zoxide_cd%) else for /f "delims=" %\p%d in (^^""%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%"^") do @%__zoxide_cd%) else if "%\p%~i" equ "~" (if "%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%" equ "" (for /f "delims=" %\p%d in (^^""%\p%USERPROFILE%\p%"^") do @%__zoxide_cd%) else for /f "delims=" %\p%d in (^^""%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%"^") do @%__zoxide_cd%) else if "%\p%~i" equ "-" (if defined OLDPWD (for /f "delims=" %\p%d in (^^""%\p%OLDPWD%\p%"^") do @%__zoxide_cd%) else ^>^&2 (echo(%program%: OLDPWD not set) ^& call) else for /f "delims=" %\p%~ in (^^"%\p%~i^") do @for /f "tokens=1,* delims=d" %\p%a in ("-%\p%~a~") do @if "%\p%b" neq "" (for /f "delims=" %\p%d in (^^""%\p%~f~"^") do @%__zoxide_cd%) else if /i "%\p%CD%\p%" neq "%\p%__CD__%\p%" (for /f "delims=" %\p%q in ('^^"%program% query --exclude "%\p%CD%\p%" -- %\p%~i^"') do @(for /f "delims=" %\p%d in (^^""%\p%~fq"^") do @%__zoxide_cd%)) else (for /f "delims=" %\p%q in ('^^"%program% query --exclude "%\p%__CD__%\p%\" -- %\p%~i^"') do @(for /f "delims=" %\p%d in (^^""%\p%~fq"^") do @%__zoxide_cd%))) ^&^& %sysdir%chcp.com %\p%~nc ^>nul 2^>^&1 ^|^| %sysdir%chcp.com %\p%~nc ^>nul 2^>^&1 ^&^& call @@ -55,7 +47,8 @@ set __zoxide_cd=if /i "%\p%CD%\p%" neq "%\p%~fd" (%builtin_cd% "%\p%~fd" ^^^&^^^ {%- endmatch %} {{ section }} -::: To initialize zoxide, add this to your configuration or AutoRun command: +::: To initialize zoxide, add this to your configuration or AutoRun command +::: (usually HKEY_CURRENT_USER\Software\Microsoft\Command Processor\AutoRun): ::: ::: zoxide init cmd | cmd /d/q/k echo off From 227997e51693ec43c619f99431585c5e7b5f2221 Mon Sep 17 00:00:00 2001 From: mataha Date: Thu, 29 Jan 2026 19:07:38 +0100 Subject: [PATCH 35/35] Switch code page to UTF-8 in a separate command --- templates/cmd.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/templates/cmd.txt b/templates/cmd.txt index e1d31da..5a5b0f9 100644 --- a/templates/cmd.txt +++ b/templates/cmd.txt @@ -22,10 +22,10 @@ set builtin_pwd=(chdir) ::: ::: pwd based on the value of _ZO_RESOLVE_SYMLINKS. -set __zoxide_pwd= {%- if resolve_symlinks -%} (for /f "skip=9 tokens=1,2,*" %\p%j in ('^^^^^^^^"%sysdir%fsutil.exe reparsepoint query .^"') do @if "%\p%~j" equ "Print" if "%\p%~k" equ "Name:" if "%\p%~l" neq "" (echo(%\p%~l)) ^^^^^^^|^^^^^^^| {%~ endif -%} %builtin_pwd% +set __zoxide_pwd= {%- if resolve_symlinks -%} (for /f "skip=9 tokens=1,2,*" %\p%j in ('^^^^^^^^"%sysdir%fsutil.exe reparsepoint query .^"') do if "%\p%~j" equ "Print" if "%\p%~k" equ "Name:" if "%\p%~l" neq "" (echo(%\p%~l)) ^^^^^^^|^^^^^^^| {%~ endif -%} %builtin_pwd% ::: cd + custom logic based on the value of _ZO_ECHO. -set __zoxide_cd=if /i "%\p%CD%\p%" neq "%\p%~fd" (%builtin_cd% "%\p%~fd" ^^^&^^^& set "OLDPWD=%\p%CD%\p%" ^^^&^^^& (for /f "delims=" %\p%l in ('"%builtin_pwd%"') do @if /i "%\p%~fl" neq "%\p%~dpl" (%program% add -- "%\p%~fl") else (%program% add -- "%\p%~dpl\")) {%- if echo ~%} ^^^&^^^& %__zoxide_pwd% {%- endif ~%} ^^^&^^^& if defined CDCMD (call %\p%CDCMD%\p%)) +set __zoxide_cd=if /i "%\p%CD%\p%" neq "%\p%~fd" (%builtin_cd% "%\p%~fd" ^^^&^^^& set "OLDPWD=%\p%CD%\p%" ^^^&^^^& (for /f "delims=" %\p%l in ('"%builtin_pwd%"') do if /i "%\p%~fl" neq "%\p%~dpl" (%program% add -- "%\p%~fl") else (%program% add -- "%\p%~dpl\")) {%- if echo ~%} ^^^&^^^& %__zoxide_pwd% {%- endif ~%} ^^^&^^^& if defined CDCMD (call %\p%CDCMD%\p%)) {{ section }} ::: Commands for zoxide. Disable these using --no-cmd. @@ -35,10 +35,10 @@ set __zoxide_cd=if /i "%\p%CD%\p%" neq "%\p%~fd" (%builtin_cd% "%\p%~fd" ^^^&^^^ {%- when Some with (cmd) %} ::: Jump to a directory using only keywords. -%sysdir%doskey.exe {{ cmd }} = @for /f "delims=" %\p%s in ('"%sysdir%chcp.com 2>nul"') do @for %\p%c in (%\p%~s) do @%sysdir%chcp.com %\p%~nc ^>nul 2^>^&1 ^&^& %sysdir%chcp.com 65001 ^>nul 2^>^&1 ^&^& @(for %\p%^^^^ in ("") do @for /f "delims=" %\p%i in (^^""$*%\p%~^^"^") do @if "%\p%~i" equ "" (if "%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%" equ "" (for /f "delims=" %\p%d in (^^""%\p%USERPROFILE%\p%"^") do @%__zoxide_cd%) else for /f "delims=" %\p%d in (^^""%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%"^") do @%__zoxide_cd%) else if "%\p%~i" equ "~" (if "%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%" equ "" (for /f "delims=" %\p%d in (^^""%\p%USERPROFILE%\p%"^") do @%__zoxide_cd%) else for /f "delims=" %\p%d in (^^""%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%"^") do @%__zoxide_cd%) else if "%\p%~i" equ "-" (if defined OLDPWD (for /f "delims=" %\p%d in (^^""%\p%OLDPWD%\p%"^") do @%__zoxide_cd%) else ^>^&2 (echo(%program%: OLDPWD not set) ^& call) else for /f "delims=" %\p%~ in (^^"%\p%~i^") do @for /f "tokens=1,* delims=d" %\p%a in ("-%\p%~a~") do @if "%\p%b" neq "" (for /f "delims=" %\p%d in (^^""%\p%~f~"^") do @%__zoxide_cd%) else if /i "%\p%CD%\p%" neq "%\p%__CD__%\p%" (for /f "delims=" %\p%q in ('^^"%program% query --exclude "%\p%CD%\p%" -- %\p%~i^"') do @(for /f "delims=" %\p%d in (^^""%\p%~fq"^") do @%__zoxide_cd%)) else (for /f "delims=" %\p%q in ('^^"%program% query --exclude "%\p%__CD__%\p%\" -- %\p%~i^"') do @(for /f "delims=" %\p%d in (^^""%\p%~fq"^") do @%__zoxide_cd%))) ^&^& %sysdir%chcp.com %\p%~nc ^>nul 2^>^&1 ^|^| %sysdir%chcp.com %\p%~nc ^>nul 2^>^&1 ^&^& call +%sysdir%doskey.exe {{ cmd }} = @if not defined _ZO_DOCTOR (echo off) $T for /f "delims=" %\p%s in ('"%sysdir%chcp.com 2>nul"') do for %\p%c in (%\p%~s) do set "_ZO_CODEPAGE=%\p%~nc" $T %sysdir%mode.com con:cp select=65001 ^>nul $T (for %\p%^^^^ in ("") do for /f "delims=" %\p%i in (^^""$*%\p%~^^"^") do if "%\p%~i" equ "" (if "%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%" equ "" (for /f "delims=" %\p%d in (^^""%\p%USERPROFILE%\p%"^") do %__zoxide_cd%) else for /f "delims=" %\p%d in (^^""%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%"^") do %__zoxide_cd%) else if "%\p%~i" equ "~" (if "%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%" equ "" (for /f "delims=" %\p%d in (^^""%\p%USERPROFILE%\p%"^") do %__zoxide_cd%) else for /f "delims=" %\p%d in (^^""%\p%HOMEDRIVE%\p%%\p%HOMEPATH%\p%"^") do %__zoxide_cd%) else if "%\p%~i" equ "-" (if defined OLDPWD (for /f "delims=" %\p%d in (^^""%\p%OLDPWD%\p%"^") do %__zoxide_cd%) else ^>^&2 (echo(%program%: OLDPWD not set) ^& call) else for /f "delims=" %\p%~ in (^^"%\p%~i^") do for /f "tokens=1,* delims=d" %\p%a in ("-%\p%~a~") do if "%\p%b" neq "" (for /f "delims=" %\p%d in (^^""%\p%~f~"^") do %__zoxide_cd%) else if /i "%\p%CD%\p%" neq "%\p%__CD__%\p%" (for /f "delims=" %\p%q in ('^^"%program% query --exclude "%\p%CD%\p%" -- %\p%~i^"') do (for /f "delims=" %\p%d in (^^""%\p%~fq"^") do %__zoxide_cd%)) else (for /f "delims=" %\p%q in ('^^"%program% query --exclude "%\p%__CD__%\p%\" -- %\p%~i^"') do (for /f "delims=" %\p%d in (^^""%\p%~fq"^") do %__zoxide_cd%))) ^&^& (for /f "delims=" %\p%v in ('"set /a _ZO_CODEPAGE"') do %sysdir%mode.com con:cp select=%\p%~v ^>nul) ^|^| (for /f "delims=" %\p%v in ('"set /a _ZO_CODEPAGE"') do %sysdir%mode.com con:cp select=%\p%~v ^>nul ^& call) $T set "_ZO_CODEPAGE=" ^& echo on ::: Jump to a directory using interactive search. -%sysdir%doskey.exe {{ cmd }}i = @for /f "delims=" %\p%s in ('"%sysdir%chcp.com 2>nul"') do @for %\p%c in (%\p%~s) do @%sysdir%chcp.com %\p%~nc ^>nul 2^>^&1 ^&^& %sysdir%chcp.com 65001 ^>nul 2^>^&1 ^&^& @(for %\p%^^^^ in ("") do @for /f "delims=" %\p%i in (^^""$*%\p%~^^"^") do @for /f "delims=" %\p%p in ('^^"%program% query --interactive -- %\p%~i^"') do @for /f "delims=" %\p%d in (^^""%\p%~fp"^") do @%__zoxide_cd%) ^&^& %sysdir%chcp.com %\p%~nc ^>nul 2^>^&1 ^|^| %sysdir%chcp.com %\p%~nc ^>nul 2^>^&1 ^&^& call +%sysdir%doskey.exe {{ cmd }}i = @if not defined _ZO_DOCTOR (echo off) $T for /f "delims=" %\p%s in ('"%sysdir%chcp.com 2>nul"') do for %\p%c in (%\p%~s) do set "_ZO_CODEPAGE=%\p%~nc" $T %sysdir%mode.com con:cp select=65001 ^>nul $T (for %\p%^^^^ in ("") do for /f "delims=" %\p%i in (^^""$*%\p%~^^"^") do for /f "delims=" %\p%p in ('^^"%program% query --interactive -- %\p%~i^"') do for /f "delims=" %\p%d in (^^""%\p%~fp"^") do %__zoxide_cd%) ^&^& (for /f "delims=" %\p%v in ('"set /a _ZO_CODEPAGE"') do %sysdir%mode.com con:cp select=%\p%~v ^>nul) ^|^| (for /f "delims=" %\p%v in ('"set /a _ZO_CODEPAGE"') do %sysdir%mode.com con:cp select=%\p%~v ^>nul ^& call) $T set "_ZO_CODEPAGE=" ^& echo on {%- when None %}