Compare commits

...

4 Commits

@ -319,9 +319,9 @@ func TestUnixCommands(t *testing.T) {
// purpose of this test is to demonstrate some shortcomings of fzf's templating system on Windows // purpose of this test is to demonstrate some shortcomings of fzf's templating system on Windows
func TestWindowsCommands(t *testing.T) { func TestWindowsCommands(t *testing.T) {
if !util.IsWindows() { // XXX Deprecated
t.SkipNow() t.SkipNow()
}
tests := []testCase{ tests := []testCase{
// reference: give{template, query, items}, want{output OR match} // reference: give{template, query, items}, want{output OR match}

@ -6,14 +6,23 @@ import (
"fmt" "fmt"
"os" "os"
"os/exec" "os/exec"
"regexp" "path/filepath"
"strings" "strings"
"sync/atomic" "sync/atomic"
"syscall" "syscall"
) )
type shellType int
const (
shellTypeUnknown shellType = iota
shellTypeCmd
shellTypePowerShell
)
type Executor struct { type Executor struct {
shell string shell string
shellType shellType
args []string args []string
shellPath atomic.Value shellPath atomic.Value
} }
@ -27,16 +36,20 @@ func NewExecutor(withShell string) *Executor {
shell = "cmd" shell = "cmd"
} }
shellType := shellTypeUnknown
basename := filepath.Base(shell)
if len(args) > 0 { if len(args) > 0 {
args = args[1:] args = args[1:]
} else if strings.Contains(shell, "cmd") { } else if strings.HasPrefix(basename, "cmd") {
shellType = shellTypeCmd
args = []string{"/v:on/s/c"} args = []string{"/v:on/s/c"}
} else if strings.Contains(shell, "pwsh") || strings.Contains(shell, "powershell") { } else if strings.HasPrefix(basename, "pwsh") || strings.HasPrefix(basename, "powershell") {
shellType = shellTypePowerShell
args = []string{"-NoProfile", "-Command"} args = []string{"-NoProfile", "-Command"}
} else { } else {
args = []string{"-c"} args = []string{"-c"}
} }
return &Executor{shell: shell, args: args} return &Executor{shell: shell, shellType: shellType, args: args}
} }
// ExecCommand executes the given command with $SHELL // ExecCommand executes the given command with $SHELL
@ -57,10 +70,20 @@ func (x *Executor) ExecCommand(command string, setpgid bool) *exec.Cmd {
} }
x.shellPath.Store(shell) x.shellPath.Store(shell)
} }
cmd := exec.Command(shell, append(x.args, command)...) var cmd *exec.Cmd
cmd.SysProcAttr = &syscall.SysProcAttr{ if x.shellType == shellTypeCmd {
HideWindow: false, cmd = exec.Command(shell)
CreationFlags: 0, cmd.SysProcAttr = &syscall.SysProcAttr{
HideWindow: false,
CmdLine: fmt.Sprintf(`%s "%s"`, strings.Join(x.args, " "), command),
CreationFlags: 0,
}
} else {
cmd = exec.Command(shell, append(x.args, command)...)
cmd.SysProcAttr = &syscall.SysProcAttr{
HideWindow: false,
CreationFlags: 0,
}
} }
return cmd return cmd
} }
@ -85,21 +108,55 @@ func (x *Executor) Become(stdin *os.File, environ []string, command string) {
Exit(0) Exit(0)
} }
func escapeArg(s string) string {
b := make([]byte, 0, len(s)+2)
b = append(b, '"')
slashes := 0
for i := 0; i < len(s); i++ {
c := s[i]
switch c {
default:
slashes = 0
case '\\':
slashes++
case '&', '|', '<', '>', '(', ')', '@', '^', '%', '!':
b = append(b, '^')
case '"':
for ; slashes > 0; slashes-- {
b = append(b, '\\')
}
b = append(b, '\\')
}
b = append(b, c)
}
for ; slashes > 0; slashes-- {
b = append(b, '\\')
}
b = append(b, '"')
return string(b)
}
func (x *Executor) QuoteEntry(entry string) string { func (x *Executor) QuoteEntry(entry string) string {
if strings.Contains(x.shell, "cmd") { switch x.shellType {
// backslash escaping is done here for applications case shellTypeCmd:
// (see ripgrep test case in terminal_test.go#TestWindowsCommands) /* Manually tested with the following commands:
escaped := strings.Replace(entry, `\`, `\\`, -1) fzf --preview "echo {}"
escaped = `"` + strings.Replace(escaped, `"`, `\"`, -1) + `"` fzf --preview "type {}"
// caret is the escape character for cmd shell echo .git\refs\| fzf --preview "dir {}"
r, _ := regexp.Compile(`[&|<>()@^%!"]`) echo .git\refs\\| fzf --preview "dir {}"
return r.ReplaceAllStringFunc(escaped, func(match string) string { echo .git\refs\\\| fzf --preview "dir {}"
return "^" + match reg query HKCU | fzf --reverse --bind "enter:reload(reg query {})"
}) fzf --disabled --preview "echo {q} {n} {}" --query "&|<>()@^%!"
} else if strings.Contains(x.shell, "pwsh") || strings.Contains(x.shell, "powershell") { fd -H --no-ignore -td -d 4 | fzf --preview "dir {}"
fd -H --no-ignore -td -d 4 | fzf --preview "eza {}" --preview-window up
fd -H --no-ignore -td -d 4 | fzf --preview "eza --color=always --tree --level=3 --icons=always {}"
fd -H --no-ignore -td -d 4 | fzf --preview ".\eza.exe --color=always --tree --level=3 --icons=always {}" --with-shell "powershell -NoProfile -Command"
*/
return escapeArg(entry)
case shellTypePowerShell:
escaped := strings.Replace(entry, `"`, `\"`, -1) escaped := strings.Replace(entry, `"`, `\"`, -1)
return "'" + strings.Replace(escaped, "'", "''", -1) + "'" return "'" + strings.Replace(escaped, "'", "''", -1) + "'"
} else { default:
return "'" + strings.Replace(entry, "'", "'\\''", -1) + "'" return "'" + strings.Replace(entry, "'", "'\\''", -1) + "'"
} }
} }

Loading…
Cancel
Save