From a4391aeedd4fec1865d2d646711f58d04058531b Mon Sep 17 00:00:00 2001 From: Junegunn Choi Date: Sat, 27 Apr 2024 18:36:37 +0900 Subject: Add --with-shell for shelling out with different command and flags (#3746) Close #3732 --- src/terminal.go | 53 +++++++++++++++++++++++++---------------------------- 1 file changed, 25 insertions(+), 28 deletions(-) (limited to 'src/terminal.go') diff --git a/src/terminal.go b/src/terminal.go index 25f30150..8d114e1b 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -7,7 +7,6 @@ import ( "io" "math" "os" - "os/exec" "os/signal" "regexp" "sort" @@ -245,6 +244,7 @@ type Terminal struct { listenUnsafe bool borderShape tui.BorderShape cleanExit bool + executor *util.Executor paused bool border tui.Window window tui.Window @@ -640,7 +640,7 @@ func evaluateHeight(opts *Options, termHeight int) int { } // NewTerminal returns new Terminal object -func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal { +func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor) *Terminal { input := trimQuery(opts.Query) var delay time.Duration if opts.Tac { @@ -736,6 +736,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal { previewLabel: nil, previewLabelOpts: opts.PreviewLabel, cleanExit: opts.ClearOnExit, + executor: executor, paused: opts.Phony, cycle: opts.Cycle, headerVisible: true, @@ -2522,6 +2523,7 @@ type replacePlaceholderParams struct { allItems []*Item lastAction actionType prompt string + executor *util.Executor } func (t *Terminal) replacePlaceholder(template string, forcePlus bool, input string, list []*Item) string { @@ -2535,6 +2537,7 @@ func (t *Terminal) replacePlaceholder(template string, forcePlus bool, input str allItems: list, lastAction: t.lastAction, prompt: t.promptString, + executor: t.executor, }) } @@ -2595,7 +2598,7 @@ func replacePlaceholder(params replacePlaceholderParams) string { case escaped: return match case match == "{q}" || match == "{fzf:query}": - return quoteEntry(params.query) + return params.executor.QuoteEntry(params.query) case match == "{}": replace = func(item *Item) string { switch { @@ -2608,13 +2611,13 @@ func replacePlaceholder(params replacePlaceholderParams) string { case flags.file: return item.AsString(params.stripAnsi) default: - return quoteEntry(item.AsString(params.stripAnsi)) + return params.executor.QuoteEntry(item.AsString(params.stripAnsi)) } } case match == "{fzf:action}": return params.lastAction.Name() case match == "{fzf:prompt}": - return quoteEntry(params.prompt) + return params.executor.QuoteEntry(params.prompt) default: // token type and also failover (below) rangeExpressions := strings.Split(match[1:len(match)-1], ",") @@ -2648,7 +2651,7 @@ func replacePlaceholder(params replacePlaceholderParams) string { str = strings.TrimSpace(str) } if !flags.file { - str = quoteEntry(str) + str = params.executor.QuoteEntry(str) } return str } @@ -2688,7 +2691,7 @@ func (t *Terminal) executeCommand(template string, forcePlus bool, background bo return line } command := t.replacePlaceholder(template, forcePlus, string(t.input), list) - cmd := util.ExecCommand(command, false) + cmd := t.executor.ExecCommand(command, false) cmd.Env = t.environ() t.executing.Set(true) if !background { @@ -2965,7 +2968,7 @@ func (t *Terminal) Loop() { if items[0] != nil { _, query := t.Input() command := t.replacePlaceholder(commandTemplate, false, string(query), items) - cmd := util.ExecCommand(command, true) + cmd := t.executor.ExecCommand(command, true) env := t.environ() if pwindowSize.Lines > 0 { lines := fmt.Sprintf("LINES=%d", pwindowSize.Lines) @@ -3372,27 +3375,21 @@ func (t *Terminal) Loop() { valid, list := t.buildPlusList(a.a, false) if valid { command := t.replacePlaceholder(a.a, false, string(t.input), list) - shell := os.Getenv("SHELL") - if len(shell) == 0 { - shell = "sh" - } - shellPath, err := exec.LookPath(shell) - if err == nil { - t.tui.Close() - if t.history != nil { - t.history.append(string(t.input)) - } - /* - FIXME: It is not at all clear why this is required. - The following command will report 'not a tty', unless we open - /dev/tty *twice* after closing the standard input for 'reload' - in Reader.terminate(). - : | fzf --bind 'start:reload:ls' --bind 'enter:become:tty' - */ - tui.TtyIn() - util.SetStdin(tui.TtyIn()) - syscall.Exec(shellPath, []string{shell, "-c", command}, os.Environ()) + t.tui.Close() + if t.history != nil { + t.history.append(string(t.input)) } + + /* + FIXME: It is not at all clear why this is required. + The following command will report 'not a tty', unless we open + /dev/tty *twice* after closing the standard input for 'reload' + in Reader.terminate(). + + while : | fzf --bind 'start:reload:ls' --bind 'load:become:tty'; do echo; done + */ + tui.TtyIn() + t.executor.Become(tui.TtyIn(), t.environ(), command) } case actExecute, actExecuteSilent: t.executeCommand(a.a, false, a.t == actExecuteSilent, false, false) -- cgit v1.2.3