-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Shell parsing for preview command in Windows is incompatible with fzf#shellescape and cmd.exe #1018
Comments
Escaping the preview command with ie. if shellquoting is disabled in Vim execute ':!fzf --preview' s:escape(fzf#shellescape(fzf#shellescape('C:\path\to\preview.rb {}'))) |
Workaround from fzf.vim for escaping filenames correctly if not using a batchfile for the preview command let path = 'C:\path\to\preview_script.sh'
if has('win32')
if has('nvim')
let path = split(system('for %A in ("'.path.'") do echo %~sA'), "\n")[1]
else
let path = fnamemodify(path, ':8')
endif
" Required only for shell parser in fzf
let path = escape(path, '\')
endif Leaving this ticket open in case comes up with a better idea or makes the fzf's command parser more convenient for cmd.exe |
Neovim support for DOS shortname is removed in neovim/neovim#635. This hack is here to stay in fzf.vim 😢 and |
@junegunn Do you know why a single double-quote is converted to a double backslash? |
Not quite sure if I follow you. Can you provide the exact steps to reproduce the problem you described? |
In Vim/Neovim, run call fzf#vim#ag('', fzf#vim#with_preview()) Query for a double quote plugin\fzf.vim:2:1:"
Ag> " In the preview window, the preview script outputs |
I haven't tried it on Windows yet but it works on *nix. On *nix, starting a command with Lines 20 to 23 in 077ae51
On Windows, it's a little more complicated. I don't fully remember, but I noticed the same approach didn't work with Lines 18 to 26 in 077ae51
Do you have experience with Go? You can test the code like follows: package main
import (
"fmt"
"os/exec"
"github.com/mattn/go-shellwords"
)
func main() {
command := "echo 'foo\\bar:1:2:\"'"
args, _ := shellwords.Parse(command)
allArgs := make([]string, len(args)+1)
allArgs[0] = "/c"
copy(allArgs[1:], args)
fmt.Printf("%#v\n", allArgs)
out, err := exec.Command("cmd", allArgs...).Output()
fmt.Println(out, err)
} go get github.com/mattn/go-shellwords
go run shellesacpe.go and it gives:
Do you see anything strange about this? |
Which cmd.exe echo > echo foo\bar:1:2:"
foo\bar:1:2:"
> echo 'foo\bar:1:2:"'
'foo\bar:1:2:"' cygwin echo.exe > "echo" foo\bar:1:2:
foo\bar:1:2:
> "echo" foo\bar:1:2:"
foobar:1:2:"
> "echo" 'foo\bar:1:2:"'
foo\bar:1:2:" |
Windows ruby passes it as is so it handles the single double-quote case. For the bash script, I think cygwin bash itself is the issue because it requires double escaping, one for cmd.exe and another for bash.exe. > ruby .\preview.rb foo\bar:1:2:"
File not found: foo\bar |
I tested it on macOS where
Yeah, agreed. |
Pointless because of cmd.exe parsing and the incorrect escaping in exec_windows.go which does not consider the command name if using I prefer to run the command as is in a batchfile (no escaping) so cmd can determine whether the internal |
If the double quotes are not escaped somehow such that it is executed as is but previewCmd is wrapped in double quotes when it is run, then cmd := exec.Command("cmd", "/s", "/c", previewCmd).Output() should work. :: internal echo
>cmd /s /c " echo foo\bar" "
foo\:bar"
:: cygwin echo.exe
> cmd /s /c " "echo" foo\bar" "
foo:bar Imo, Vim and Neovim should use |
Reference: junegunn/fzf#1018 (comment) The command passed to cmd.exe is run as if the user typed it all in an interactive prompt. This is convenient for testing and reduces the burden to shellescape each token. This is enough for basic commands. For non-trivial commands, use a batchfile.
Have to explicity set golang/go#15566 (comment) |
Reference: https://play.golang.org/p/aU1PlbNTqM @junegunn package main
import (
"fmt"
"os/exec"
"syscall"
)
func main() {
cmd := exec.Command("cmd")
command := `"echo" foo\:bar"`
cmd.SysProcAttr = &syscall.SysProcAttr{
HideWindow: false,
CmdLine: fmt.Sprintf(` /s /c "%s"`, command),
CreationFlags: 0,
}
fmt.Println(cmd.SysProcAttr.CmdLine)
out, err := cmd.Output()
fmt.Printf("%s\n", out)
fmt.Println(out, err)
} |
Close junegunn#1018 Run the command as is in cmd.exe with no parsing and escaping. Explicity set cmd.SysProcAttr so execCommand does not escape the command. Technically, the command should be escaped with ^ for special characters, including ". This allows cmd.exe commands to be chained together. See neovim/neovim#7343 (comment) However, this requires a new shellescape function that is specific to one of the following: - interactive prompt - batchfile - command name fzf#shellescape in the Vim plugin can handle only the batchfile.
I still have this issue. Have fzf preview support Window yet? |
Backslashes in the filepath of the preview command are escaped so they don't run in Windows.
The preview script itself (ruby or bash) has no issues with filepaths with backslashes.
junegunn/fzf.vim#418 (comment) is caused by the network drive conflicting with the colon delimiter. I'll open a separate issue/PR for that.
The text was updated successfully, but these errors were encountered: