mirror of
https://github.com/junegunn/fzf.git
synced 2025-08-27 18:33:49 -07:00
Add --with-shell for shelling out with different command and flags (#3746)
Close #3732
This commit is contained in:
@@ -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)
|
||||
|
Reference in New Issue
Block a user