To: vim_dev@googlegroups.com Subject: Patch 8.2.3385 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.3385 Problem: Escaping for fish shell does not work properly. Solution: Insert a backslash before a backslash. (Jason Cox, closes #8810) Files: runtime/doc/eval.txt, src/strings.c, src/testdir/test_shell.vim *** ../vim-8.2.3384/runtime/doc/eval.txt 2021-08-16 21:38:38.127122597 +0200 --- runtime/doc/eval.txt 2021-08-29 12:29:23.666462297 +0200 *************** *** 10016,10021 **** --- 10111,10120 ---- 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(''), 1) < This results in a directory listing for the file under the *** ../vim-8.2.3384/src/strings.c 2021-08-09 19:59:01.446811234 +0200 --- src/strings.c 2021-08-29 12:33:09.886138250 +0200 *************** *** 125,130 **** --- 125,139 ---- } /* + * 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,150 **** --- 154,160 ---- char_u *escaped_string; int l; int csh_like; + int fish_like; char_u *shname; int powershell; # ifdef MSWIN *************** *** 157,162 **** --- 167,176 ---- // 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,202 **** --- 211,218 ---- ++length; // insert backslash p += l - 1; } + if (*p == '\\' && fish_like) + ++length; // insert backslash } // Allocate memory for the result and fill it. *************** *** 261,266 **** --- 277,287 ---- *d++ = *p++; continue; } + if (*p == '\\' && fish_like) + { + *d++ = '\\'; + *d++ = *p++; + } MB_COPY_CHAR(p, d); } *** ../vim-8.2.3384/src/testdir/test_shell.vim 2021-08-06 21:34:34.626972208 +0200 --- src/testdir/test_shell.vim 2021-08-29 12:29:23.666462297 +0200 *************** *** 61,78 **** 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'\\'' \\\\!\\%\\#'" 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'' \\!\\%\\#'" else ! 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]) " Try running an external command with the shell. if executable(e[0]) --- 61,81 ---- 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'\\'' \\\\!\\%\\# \\'" 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'' \\!\\%\\# \\'" ! 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'\\'' \\!\\%\\# \\'" endif ! 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]) *** ../vim-8.2.3384/src/version.c 2021-08-28 20:42:43.636422753 +0200 --- src/version.c 2021-08-29 12:36:20.149901341 +0200 *************** *** 757,758 **** --- 757,760 ---- { /* Add new patch number below this line */ + /**/ + 3385, /**/ -- Hanson's Treatment of Time: There are never enough hours in a day, but always too many days before Saturday. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///