summaryrefslogtreecommitdiffstats
path: root/src/util/util_unix.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/util_unix.go')
-rw-r--r--src/util/util_unix.go56
1 files changed, 48 insertions, 8 deletions
diff --git a/src/util/util_unix.go b/src/util/util_unix.go
index 2991fd2c..5a67066b 100644
--- a/src/util/util_unix.go
+++ b/src/util/util_unix.go
@@ -3,31 +3,71 @@
package util
import (
+ "fmt"
"os"
"os/exec"
+ "strings"
"syscall"
"golang.org/x/sys/unix"
)
-// ExecCommand executes the given command with $SHELL
-func ExecCommand(command string, setpgid bool) *exec.Cmd {
+type Executor struct {
+ shell string
+ args []string
+ escaper *strings.Replacer
+}
+
+func NewExecutor(withShell string) *Executor {
shell := os.Getenv("SHELL")
- if len(shell) == 0 {
- shell = "sh"
+ args := strings.Fields(withShell)
+ if len(args) > 0 {
+ shell = args[0]
+ args = args[1:]
+ } else {
+ if len(shell) == 0 {
+ shell = "sh"
+ }
+ args = []string{"-c"}
}
- return ExecCommandWith(shell, command, setpgid)
+
+ var escaper *strings.Replacer
+ tokens := strings.Split(shell, "/")
+ if tokens[len(tokens)-1] == "fish" {
+ // https://fishshell.com/docs/current/language.html#quotes
+ // > The only meaningful escape sequences in single quotes are \', which
+ // > escapes a single quote and \\, which escapes the backslash symbol.
+ escaper = strings.NewReplacer("\\", "\\\\", "'", "\\'")
+ } else {
+ escaper = strings.NewReplacer("'", "'\\''")
+ }
+ return &Executor{shell, args, escaper}
}
-// ExecCommandWith executes the given command with the specified shell
-func ExecCommandWith(shell string, command string, setpgid bool) *exec.Cmd {
- cmd := exec.Command(shell, "-c", command)
+// ExecCommand executes the given command with $SHELL
+func (x *Executor) ExecCommand(command string, setpgid bool) *exec.Cmd {
+ cmd := exec.Command(x.shell, append(x.args, command)...)
if setpgid {
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
}
return cmd
}
+func (x *Executor) QuoteEntry(entry string) string {
+ return "'" + x.escaper.Replace(entry) + "'"
+}
+
+func (x *Executor) Become(stdin *os.File, environ []string, command string) {
+ shellPath, err := exec.LookPath(x.shell)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "fzf (become): %s\n", err.Error())
+ os.Exit(127)
+ }
+ args := append([]string{shellPath}, append(x.args, command)...)
+ SetStdin(stdin)
+ syscall.Exec(shellPath, args, environ)
+}
+
// KillCommand kills the process for the given command
func KillCommand(cmd *exec.Cmd) error {
return syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)