Fix ExecCommandWith for cmd.exe in Windows (#1072)
Close #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 https://github.com/neovim/neovim/pull/7343#issuecomment-333350201 This commit also updates quoteEntry to use strings.Replace instead of strconv.Quote which escapes more than \ and ".
This commit is contained in:
parent
0580fe9046
commit
c4185e81e8
@ -1103,9 +1103,18 @@ func keyMatch(key int, event tui.Event) bool {
|
|||||||
event.Type == tui.Mouse && key == tui.DoubleClick && event.MouseEvent.Double
|
event.Type == tui.Mouse && key == tui.DoubleClick && event.MouseEvent.Double
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func quoteEntryCmd(entry string) string {
|
||||||
|
escaped := strings.Replace(entry, `\`, `\\`, -1)
|
||||||
|
escaped = `"` + strings.Replace(escaped, `"`, `\"`, -1) + `"`
|
||||||
|
r, _ := regexp.Compile(`[&|<>()@^%!"]`)
|
||||||
|
return r.ReplaceAllStringFunc(escaped, func(match string) string {
|
||||||
|
return "^" + match
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func quoteEntry(entry string) string {
|
func quoteEntry(entry string) string {
|
||||||
if util.IsWindows() {
|
if util.IsWindows() {
|
||||||
return strconv.Quote(strings.Replace(entry, "\"", "\\\"", -1))
|
return quoteEntryCmd(entry)
|
||||||
}
|
}
|
||||||
return "'" + strings.Replace(entry, "'", "'\\''", -1) + "'"
|
return "'" + strings.Replace(entry, "'", "'\\''", -1) + "'"
|
||||||
}
|
}
|
||||||
|
@ -91,3 +91,22 @@ func TestReplacePlaceholder(t *testing.T) {
|
|||||||
result = replacePlaceholder("echo {}/{1}/{3}/{2..3}", true, Delimiter{regex: regex}, false, "query", items1)
|
result = replacePlaceholder("echo {}/{1}/{3}/{2..3}", true, Delimiter{regex: regex}, false, "query", items1)
|
||||||
check("echo ' foo'\\''bar baz'/'f'/'r b'/''\\''bar b'")
|
check("echo ' foo'\\''bar baz'/'f'/'r b'/''\\''bar b'")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestQuoteEntryCmd(t *testing.T) {
|
||||||
|
tests := map[string]string{
|
||||||
|
`"`: `^"\^"^"`,
|
||||||
|
`\`: `^"\\^"`,
|
||||||
|
`\"`: `^"\\\^"^"`,
|
||||||
|
`"\\\"`: `^"\^"\\\\\\\^"^"`,
|
||||||
|
`&|<>()@^%!`: `^"^&^|^<^>^(^)^@^^^%^!^"`,
|
||||||
|
`%USERPROFILE%`: `^"^%USERPROFILE^%^"`,
|
||||||
|
`C:\Program Files (x86)\`: `^"C:\\Program Files ^(x86^)\\^"`,
|
||||||
|
}
|
||||||
|
|
||||||
|
for input, expected := range tests {
|
||||||
|
escaped := quoteEntryCmd(input)
|
||||||
|
if escaped != expected {
|
||||||
|
t.Errorf("Input: %s, expected: %s, actual %s", input, expected, escaped)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,8 +6,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/mattn/go-shellwords"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ExecCommand executes the given command with cmd
|
// ExecCommand executes the given command with cmd
|
||||||
@ -18,11 +16,13 @@ func ExecCommand(command string) *exec.Cmd {
|
|||||||
// ExecCommandWith executes the given command with cmd. _shell parameter is
|
// ExecCommandWith executes the given command with cmd. _shell parameter is
|
||||||
// ignored on Windows.
|
// ignored on Windows.
|
||||||
func ExecCommandWith(_shell string, command string) *exec.Cmd {
|
func ExecCommandWith(_shell string, command string) *exec.Cmd {
|
||||||
args, _ := shellwords.Parse(command)
|
cmd := exec.Command("cmd")
|
||||||
allArgs := make([]string, len(args)+1)
|
cmd.SysProcAttr = &syscall.SysProcAttr{
|
||||||
allArgs[0] = "/c"
|
HideWindow: false,
|
||||||
copy(allArgs[1:], args)
|
CmdLine: fmt.Sprintf(` /s /c "%s"`, command),
|
||||||
return exec.Command("cmd", allArgs...)
|
CreationFlags: 0,
|
||||||
|
}
|
||||||
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsWindows returns true on Windows
|
// IsWindows returns true on Windows
|
||||||
|
Loading…
Reference in New Issue
Block a user