From 864f8cad91efad7026a9e2025ddb6ed05b823a68 Mon Sep 17 00:00:00 2001 From: mataha Date: Mon, 10 Jun 2024 03:12:46 +0200 Subject: [PATCH] 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 -%}