diff --git a/src/terminal.go b/src/terminal.go index 7813680..98d837c 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -1103,9 +1103,18 @@ func keyMatch(key int, event tui.Event) bool { 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 { if util.IsWindows() { - return strconv.Quote(strings.Replace(entry, "\"", "\\\"", -1)) + return quoteEntryCmd(entry) } return "'" + strings.Replace(entry, "'", "'\\''", -1) + "'" } diff --git a/src/terminal_test.go b/src/terminal_test.go index d42d2b8..60f2b1a 100644 --- a/src/terminal_test.go +++ b/src/terminal_test.go @@ -91,3 +91,22 @@ func TestReplacePlaceholder(t *testing.T) { result = replacePlaceholder("echo {}/{1}/{3}/{2..3}", true, Delimiter{regex: regex}, false, "query", items1) 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) + } + } +} diff --git a/src/util/util_windows.go b/src/util/util_windows.go index 493f4d7..86409fd 100644 --- a/src/util/util_windows.go +++ b/src/util/util_windows.go @@ -6,8 +6,6 @@ import ( "os" "os/exec" "syscall" - - "github.com/mattn/go-shellwords" ) // 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 // ignored on Windows. func ExecCommandWith(_shell string, command string) *exec.Cmd { - args, _ := shellwords.Parse(command) - allArgs := make([]string, len(args)+1) - allArgs[0] = "/c" - copy(allArgs[1:], args) - return exec.Command("cmd", allArgs...) + cmd := exec.Command("cmd") + cmd.SysProcAttr = &syscall.SysProcAttr{ + HideWindow: false, + CmdLine: fmt.Sprintf(` /s /c "%s"`, command), + CreationFlags: 0, + } + return cmd } // IsWindows returns true on Windows