From 85b2596b2974274c2a8e0ff96923a829ae2d6eed Mon Sep 17 00:00:00 2001 From: mataha Date: Wed, 10 May 2023 23:40:23 +0200 Subject: [PATCH] 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: