From 835d2fb98cedbb6384dfbeb41e4ba48c3c0a8081 Mon Sep 17 00:00:00 2001 From: Junegunn Choi Date: Wed, 1 May 2024 10:02:26 +0900 Subject: [PATCH] [vim] Fix argument escaping for Windows batch file Fix #3620 --- CHANGELOG.md | 1 + plugin/fzf.vim | 26 +++++++++++++++++++++----- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 911f043a..5e66fb1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ CHANGELOG - `change-multi(0)` - disable multi-select mode - `become` action is now supported on Windows - Unlike in *nix, this does not use `execve(2)`. Instead it spawns a new process and waits for it to finish, so the exact behavior may differ. +- Fixed argument escaping for Windows cmd.exe - Bug fixes and improvements 0.50.0 diff --git a/plugin/fzf.vim b/plugin/fzf.vim index a99dbb2b..4a1ca0e5 100644 --- a/plugin/fzf.vim +++ b/plugin/fzf.vim @@ -83,12 +83,28 @@ else endfunction endif +let s:cmd_control_chars = ['&', '|', '<', '>', '(', ')', '@', '^', '!'] + function! s:shellesc_cmd(arg) - let escaped = substitute(a:arg, '[&|<>()@^]', '^&', 'g') - let escaped = substitute(escaped, '%', '%%', 'g') - let escaped = substitute(escaped, '"', '\\^&', 'g') - let escaped = substitute(escaped, '\(\\\+\)\(\\^\)', '\1\1\2', 'g') - return '^"'.substitute(escaped, '\(\\\+\)$', '\1\1', '').'^"' + let e = '"' + let slashes = 0 + for c in split(a:arg, '\zs') + if c ==# '\' + let slashes += 1 + elseif c ==# '"' + let e .= repeat('\', slashes + 1) + let slashes = 0 + elseif c ==# '%' + let e .= '%' + elseif index(s:cmd_control_chars, c) >= 0 + let e .= '^' + else + let slashes = 0 + endif + let e .= c + endfor + let e .= repeat('\', slashes) .'"' + return e endfunction function! fzf#shellescape(arg, ...)