Mercurial > vim
changeset 25698:000b37efd5fa v8.2.3385
patch 8.2.3385: escaping for fish shell does not work properly
Commit: https://github.com/vim/vim/commit/6e82351130ddb8d13cf3748b47f07cae77886fc7
Author: Jason Cox <dev@jasoncarloscox.com>
Date: Sun Aug 29 12:36:49 2021 +0200
patch 8.2.3385: escaping for fish shell does not work properly
Problem: Escaping for fish shell does not work properly.
Solution: Insert a backslash before a backslash. (Jason Cox, closes https://github.com/vim/vim/issues/8810)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sun, 29 Aug 2021 12:45:05 +0200 |
parents | c7845af77c65 |
children | 8088e687c3d7 |
files | runtime/doc/eval.txt src/strings.c src/testdir/test_shell.vim src/version.c |
diffstat | 4 files changed, 38 insertions(+), 8 deletions(-) [+] |
line wrap: on
line diff
--- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -10111,6 +10111,10 @@ shellescape({string} [, {special}]) *s escaped. When 'shell' containing "csh" in the tail it's escaped a second time. + The "\" character will be escaped when 'shell' contains "fish" + in the tail. That is because for fish "\" is used as an escape + character inside single quotes. + Example of use with a |:!| command: > :exe '!dir ' . shellescape(expand('<cfile>'), 1) < This results in a directory listing for the file under the
--- a/src/strings.c +++ b/src/strings.c @@ -125,6 +125,15 @@ csh_like_shell(void) } /* + * Return TRUE when 'shell' has "fish" in the tail. + */ + int +fish_like_shell(void) +{ + return (strstr((char *)gettail(p_sh), "fish") != NULL); +} + +/* * Escape "string" for use as a shell argument with system(). * This uses single quotes, except when we know we need to use double quotes * (MS-DOS and MS-Windows not using PowerShell and without 'shellslash' set). @@ -145,6 +154,7 @@ vim_strsave_shellescape(char_u *string, char_u *escaped_string; int l; int csh_like; + int fish_like; char_u *shname; int powershell; # ifdef MSWIN @@ -157,6 +167,10 @@ vim_strsave_shellescape(char_u *string, // Csh also needs to have "\n" escaped twice when do_special is set. csh_like = csh_like_shell(); + // Fish shell uses '\' as an escape character within single quotes, so '\' + // itself must be escaped to get a literal '\'. + fish_like = fish_like_shell(); + // PowerShell uses it's own version for quoting single quotes shname = gettail(p_sh); powershell = strstr((char *)shname, "pwsh") != NULL; @@ -197,6 +211,8 @@ vim_strsave_shellescape(char_u *string, ++length; // insert backslash p += l - 1; } + if (*p == '\\' && fish_like) + ++length; // insert backslash } // Allocate memory for the result and fill it. @@ -261,6 +277,11 @@ vim_strsave_shellescape(char_u *string, *d++ = *p++; continue; } + if (*p == '\\' && fish_like) + { + *d++ = '\\'; + *d++ = *p++; + } MB_COPY_CHAR(p, d); }
--- a/src/testdir/test_shell.vim +++ b/src/testdir/test_shell.vim @@ -61,18 +61,21 @@ func Test_shell_options() for e in shells exe 'set shell=' .. e[0] if e[0] =~# '.*csh$' || e[0] =~# '.*csh.exe$' - let str1 = "'cmd \"arg1\" '\\''arg2'\\'' \\!%#'" - let str2 = "'cmd \"arg1\" '\\''arg2'\\'' \\\\!\\%\\#'" + let str1 = "'cmd \"arg1\" '\\''arg2'\\'' \\!%# \\'" + let str2 = "'cmd \"arg1\" '\\''arg2'\\'' \\\\!\\%\\# \\'" elseif e[0] =~# '.*powershell$' || e[0] =~# '.*powershell.exe$' \ || e[0] =~# '.*pwsh$' || e[0] =~# '.*pwsh.exe$' - let str1 = "'cmd \"arg1\" ''arg2'' !%#'" - let str2 = "'cmd \"arg1\" ''arg2'' \\!\\%\\#'" + let str1 = "'cmd \"arg1\" ''arg2'' !%# \\'" + let str2 = "'cmd \"arg1\" ''arg2'' \\!\\%\\# \\'" + elseif e[0] =~# '.*fish$' || e[0] =~# '.*fish.exe$' + let str1 = "'cmd \"arg1\" '\\''arg2'\\'' !%# \\\\'" + let str2 = "'cmd \"arg1\" '\\''arg2'\\'' \\!\\%\\# \\\\'" else - let str1 = "'cmd \"arg1\" '\\''arg2'\\'' !%#'" - let str2 = "'cmd \"arg1\" '\\''arg2'\\'' \\!\\%\\#'" + let str1 = "'cmd \"arg1\" '\\''arg2'\\'' !%# \\'" + let str2 = "'cmd \"arg1\" '\\''arg2'\\'' \\!\\%\\# \\'" endif - call assert_equal(str1, shellescape("cmd \"arg1\" 'arg2' !%#"), e[0]) - call assert_equal(str2, shellescape("cmd \"arg1\" 'arg2' !%#", 1), e[0]) + call assert_equal(str1, shellescape("cmd \"arg1\" 'arg2' !%# \\"), e[0]) + call assert_equal(str2, shellescape("cmd \"arg1\" 'arg2' !%# \\", 1), e[0]) " Try running an external command with the shell. if executable(e[0])