mirror of
https://github.com/Llewellynvdm/fzf.git
synced 2024-12-23 19:39:07 +00:00
Kill running preview process after 500ms when focus has changed
Close #1383 Close #1384
This commit is contained in:
parent
27c40dc6b0
commit
0d748a0699
@ -25,6 +25,7 @@ const (
|
|||||||
initialDelay = 20 * time.Millisecond
|
initialDelay = 20 * time.Millisecond
|
||||||
initialDelayTac = 100 * time.Millisecond
|
initialDelayTac = 100 * time.Millisecond
|
||||||
spinnerDuration = 200 * time.Millisecond
|
spinnerDuration = 200 * time.Millisecond
|
||||||
|
previewCancelWait = 500 * time.Millisecond
|
||||||
maxPatternLength = 300
|
maxPatternLength = 300
|
||||||
|
|
||||||
// Matcher
|
// Matcher
|
||||||
@ -76,6 +77,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
exitCancel = -1
|
||||||
exitOk = 0
|
exitOk = 0
|
||||||
exitNoMatch = 1
|
exitNoMatch = 1
|
||||||
exitError = 2
|
exitError = 2
|
||||||
|
@ -103,7 +103,7 @@ func (r *Reader) readFromStdin() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *Reader) readFromCommand(shell string, cmd string) bool {
|
func (r *Reader) readFromCommand(shell string, cmd string) bool {
|
||||||
listCommand := util.ExecCommandWith(shell, cmd)
|
listCommand := util.ExecCommandWith(shell, cmd, false)
|
||||||
out, err := listCommand.StdoutPipe()
|
out, err := listCommand.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
|
@ -114,6 +114,7 @@ type Terminal struct {
|
|||||||
prevLines []itemLine
|
prevLines []itemLine
|
||||||
suppress bool
|
suppress bool
|
||||||
startChan chan bool
|
startChan chan bool
|
||||||
|
killChan chan int
|
||||||
slab *util.Slab
|
slab *util.Slab
|
||||||
theme *tui.ColorTheme
|
theme *tui.ColorTheme
|
||||||
tui tui.Renderer
|
tui tui.Renderer
|
||||||
@ -414,6 +415,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
|
|||||||
slab: util.MakeSlab(slab16Size, slab32Size),
|
slab: util.MakeSlab(slab16Size, slab32Size),
|
||||||
theme: opts.Theme,
|
theme: opts.Theme,
|
||||||
startChan: make(chan bool, 1),
|
startChan: make(chan bool, 1),
|
||||||
|
killChan: make(chan int),
|
||||||
tui: renderer,
|
tui: renderer,
|
||||||
initFunc: func() { renderer.Init() }}
|
initFunc: func() { renderer.Init() }}
|
||||||
t.prompt, t.promptLen = t.processTabs([]rune(opts.Prompt), 0)
|
t.prompt, t.promptLen = t.processTabs([]rune(opts.Prompt), 0)
|
||||||
@ -1298,7 +1300,7 @@ func (t *Terminal) executeCommand(template string, forcePlus bool, background bo
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
command := replacePlaceholder(template, t.ansi, t.delimiter, forcePlus, string(t.input), list)
|
command := replacePlaceholder(template, t.ansi, t.delimiter, forcePlus, string(t.input), list)
|
||||||
cmd := util.ExecCommand(command)
|
cmd := util.ExecCommand(command, false)
|
||||||
if !background {
|
if !background {
|
||||||
cmd.Stdin = os.Stdin
|
cmd.Stdin = os.Stdin
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
@ -1381,6 +1383,20 @@ func (t *Terminal) toggleItem(item *Item) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Terminal) killPreview(code int) {
|
||||||
|
select {
|
||||||
|
case t.killChan <- code:
|
||||||
|
default:
|
||||||
|
if code != exitCancel {
|
||||||
|
os.Exit(code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Terminal) cancelPreview() {
|
||||||
|
t.killPreview(exitCancel)
|
||||||
|
}
|
||||||
|
|
||||||
// Loop is called to start Terminal I/O
|
// Loop is called to start Terminal I/O
|
||||||
func (t *Terminal) Loop() {
|
func (t *Terminal) Loop() {
|
||||||
// prof := profile.Start(profile.ProfilePath("/tmp/"))
|
// prof := profile.Start(profile.ProfilePath("/tmp/"))
|
||||||
@ -1458,15 +1474,43 @@ func (t *Terminal) Loop() {
|
|||||||
if request[0] != nil {
|
if request[0] != nil {
|
||||||
command := replacePlaceholder(t.preview.command,
|
command := replacePlaceholder(t.preview.command,
|
||||||
t.ansi, t.delimiter, false, string(t.input), request)
|
t.ansi, t.delimiter, false, string(t.input), request)
|
||||||
cmd := util.ExecCommand(command)
|
cmd := util.ExecCommand(command, true)
|
||||||
if t.pwindow != nil {
|
if t.pwindow != nil {
|
||||||
env := os.Environ()
|
env := os.Environ()
|
||||||
env = append(env, fmt.Sprintf("LINES=%d", t.pwindow.Height()))
|
env = append(env, fmt.Sprintf("LINES=%d", t.pwindow.Height()))
|
||||||
env = append(env, fmt.Sprintf("COLUMNS=%d", t.pwindow.Width()))
|
env = append(env, fmt.Sprintf("COLUMNS=%d", t.pwindow.Width()))
|
||||||
cmd.Env = env
|
cmd.Env = env
|
||||||
}
|
}
|
||||||
out, _ := cmd.CombinedOutput()
|
var out bytes.Buffer
|
||||||
t.reqBox.Set(reqPreviewDisplay, string(out))
|
cmd.Stdout = &out
|
||||||
|
cmd.Stderr = &out
|
||||||
|
cmd.Start()
|
||||||
|
finishChan := make(chan bool, 1)
|
||||||
|
updateChan := make(chan bool)
|
||||||
|
go func() {
|
||||||
|
select {
|
||||||
|
case code := <-t.killChan:
|
||||||
|
if code != exitCancel {
|
||||||
|
util.KillCommand(cmd)
|
||||||
|
os.Exit(code)
|
||||||
|
} else {
|
||||||
|
select {
|
||||||
|
case <-time.After(previewCancelWait):
|
||||||
|
util.KillCommand(cmd)
|
||||||
|
updateChan <- true
|
||||||
|
case <-finishChan:
|
||||||
|
updateChan <- false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case <-finishChan:
|
||||||
|
updateChan <- false
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
cmd.Wait()
|
||||||
|
finishChan <- true
|
||||||
|
if out.Len() > 0 || !<-updateChan {
|
||||||
|
t.reqBox.Set(reqPreviewDisplay, string(out.Bytes()))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
t.reqBox.Set(reqPreviewDisplay, "")
|
t.reqBox.Set(reqPreviewDisplay, "")
|
||||||
}
|
}
|
||||||
@ -1484,7 +1528,7 @@ func (t *Terminal) Loop() {
|
|||||||
t.history.append(string(t.input))
|
t.history.append(string(t.input))
|
||||||
}
|
}
|
||||||
// prof.Stop()
|
// prof.Stop()
|
||||||
os.Exit(code)
|
t.killPreview(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
@ -1511,6 +1555,7 @@ func (t *Terminal) Loop() {
|
|||||||
focused = currentFocus
|
focused = currentFocus
|
||||||
if t.isPreviewEnabled() {
|
if t.isPreviewEnabled() {
|
||||||
_, list := t.buildPlusList(t.preview.command, false)
|
_, list := t.buildPlusList(t.preview.command, false)
|
||||||
|
t.cancelPreview()
|
||||||
t.previewBox.Set(reqPreviewEnqueue, list)
|
t.previewBox.Set(reqPreviewEnqueue, list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1620,6 +1665,7 @@ func (t *Terminal) Loop() {
|
|||||||
if t.previewer.enabled {
|
if t.previewer.enabled {
|
||||||
valid, list := t.buildPlusList(t.preview.command, false)
|
valid, list := t.buildPlusList(t.preview.command, false)
|
||||||
if valid {
|
if valid {
|
||||||
|
t.cancelPreview()
|
||||||
t.previewBox.Set(reqPreviewEnqueue, list)
|
t.previewBox.Set(reqPreviewEnqueue, list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,17 +9,26 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// ExecCommand executes the given command with $SHELL
|
// ExecCommand executes the given command with $SHELL
|
||||||
func ExecCommand(command string) *exec.Cmd {
|
func ExecCommand(command string, setpgid bool) *exec.Cmd {
|
||||||
shell := os.Getenv("SHELL")
|
shell := os.Getenv("SHELL")
|
||||||
if len(shell) == 0 {
|
if len(shell) == 0 {
|
||||||
shell = "sh"
|
shell = "sh"
|
||||||
}
|
}
|
||||||
return ExecCommandWith(shell, command)
|
return ExecCommandWith(shell, command, setpgid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecCommandWith executes the given command with the specified shell
|
// ExecCommandWith executes the given command with the specified shell
|
||||||
func ExecCommandWith(shell string, command string) *exec.Cmd {
|
func ExecCommandWith(shell string, command string, setpgid bool) *exec.Cmd {
|
||||||
return exec.Command(shell, "-c", command)
|
cmd := exec.Command(shell, "-c", command)
|
||||||
|
if setpgid {
|
||||||
|
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
|
||||||
|
}
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
// KillCommand kills the process for the given command
|
||||||
|
func KillCommand(cmd *exec.Cmd) error {
|
||||||
|
return syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsWindows returns true on Windows
|
// IsWindows returns true on Windows
|
||||||
@ -27,7 +36,7 @@ func IsWindows() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetNonBlock executes syscall.SetNonblock on file descriptor
|
// SetNonblock executes syscall.SetNonblock on file descriptor
|
||||||
func SetNonblock(file *os.File, nonblock bool) {
|
func SetNonblock(file *os.File, nonblock bool) {
|
||||||
syscall.SetNonblock(int(file.Fd()), nonblock)
|
syscall.SetNonblock(int(file.Fd()), nonblock)
|
||||||
}
|
}
|
||||||
|
@ -10,13 +10,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// ExecCommand executes the given command with cmd
|
// ExecCommand executes the given command with cmd
|
||||||
func ExecCommand(command string) *exec.Cmd {
|
func ExecCommand(command string, setpgid bool) *exec.Cmd {
|
||||||
return ExecCommandWith("cmd", command)
|
return ExecCommandWith("cmd", command)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecCommandWith executes the given command with cmd. _shell parameter is
|
// ExecCommandWith executes the given command with cmd. _shell parameter is
|
||||||
// ignored on Windows.
|
// ignored on Windows.
|
||||||
func ExecCommandWith(_shell string, command string) *exec.Cmd {
|
// FIXME: setpgid is unused. We set it in the Unix implementation so that we
|
||||||
|
// can kill preview process with its child processes at once.
|
||||||
|
func ExecCommandWith(_shell string, command string, setpgid bool) *exec.Cmd {
|
||||||
cmd := exec.Command("cmd")
|
cmd := exec.Command("cmd")
|
||||||
cmd.SysProcAttr = &syscall.SysProcAttr{
|
cmd.SysProcAttr = &syscall.SysProcAttr{
|
||||||
HideWindow: false,
|
HideWindow: false,
|
||||||
@ -26,12 +28,17 @@ func ExecCommandWith(_shell string, command string) *exec.Cmd {
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// KillCommand kills the process for the given command
|
||||||
|
func KillCommand(cmd *exec.Cmd) error {
|
||||||
|
return cmd.Process.Kill()
|
||||||
|
}
|
||||||
|
|
||||||
// IsWindows returns true on Windows
|
// IsWindows returns true on Windows
|
||||||
func IsWindows() bool {
|
func IsWindows() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetNonBlock executes syscall.SetNonblock on file descriptor
|
// SetNonblock executes syscall.SetNonblock on file descriptor
|
||||||
func SetNonblock(file *os.File, nonblock bool) {
|
func SetNonblock(file *os.File, nonblock bool) {
|
||||||
syscall.SetNonblock(syscall.Handle(file.Fd()), nonblock)
|
syscall.SetNonblock(syscall.Handle(file.Fd()), nonblock)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user