From 284d77fe2e41ec69fcc7ca7162bcf9b65b1641be Mon Sep 17 00:00:00 2001 From: Junegunn Choi Date: Mon, 23 Jan 2023 16:22:25 +0900 Subject: [PATCH] Add 'focus' event Can we find a better name? I have considered the followings. * 'point', because "the pointer" points to the current item. * 'shift', 'switch', 'move', etc. These are not technically correct because the current item can change without cursor movement (--tac, reload, search update) * 'change' is already taken. 'change-current' feels a bit wordy and sounds wrong, 'current-changed' is wordy and doesn't go well with the other event names * 'target', not straightforward Close #3053 --- CHANGELOG.md | 14 ++++++++++++++ man/man1/fzf.1 | 20 ++++++++++++++++++-- src/options.go | 2 ++ src/terminal.go | 16 ++++++++++++++-- src/tui/tui.go | 1 + test/test_go.rb | 9 +++++++++ 6 files changed, 58 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 08da4026..6233f194 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,20 @@ CHANGELOG 0.37.0 ------ +- New event + - `focus` - Triggered when the focus changes due to a vertical cursor + movement or a search result update + ```sh + fzf --bind 'focus:transform-preview-label:echo [ {} ]' --border --preview 'cat {}' + + # Any action bound to the event runs synchronously and thus can make the interface sluggish + # e.g. lolcat isn't one of the fastest programs, and every cursor movement in + # fzf will be noticeably affected by its execution time + fzf --bind 'focus:transform-preview-label:echo [ {} ] | lolcat -f' --border --preview 'cat {}' + + # Beware not to introduce an infinite loop + seq 10 | fzf --bind 'focus:up' --cycle + ``` - New actions - `change-border-label` - `change-preview-label` diff --git a/man/man1/fzf.1 b/man/man1/fzf.1 index 70faf8a3..a2e8c41f 100644 --- a/man/man1/fzf.1 +++ b/man/man1/fzf.1 @@ -959,6 +959,22 @@ e.g. \fB# Move cursor to the first entry whenever the query is changed fzf --bind change:first\fR .RE +\fIfocus\fR +.RS +Triggered when the focus changes due to a vertical cursor movement or a search +result update. + +e.g. + \fBfzf --bind 'focus:transform-preview-label:echo [ {} ]' --border --preview 'cat {}' + + # Any action bound to the event runs synchronously and thus can make the interface sluggish + # e.g. lolcat isn't one of the fastest programs, and every cursor movement in + # fzf will be noticeably affected by its execution time + fzf --bind 'focus:transform-preview-label:echo [ {} ] | lolcat -f' --border --preview 'cat {}' + + # Beware not to introduce an infinite loop + seq 10 | fzf --bind 'focus:up' --cycle\fR +.RE \fIbackward-eof\fR .RS @@ -983,11 +999,11 @@ A key or an event can be bound to one or more of the following actions. \fBbackward-word\fR \fIalt-b shift-left\fR \fBbeginning-of-line\fR \fIctrl-a home\fR \fBcancel\fR (clear query string if not empty, abort fzf otherwise) + \fBchange-border-label(...)\fR (change \fB--border-label\fR to the given string) \fBchange-preview(...)\fR (change \fB--preview\fR option) - \fBchange-preview-window(...)\fR (change \fB--preview-window\fR option; rotate through the multiple option sets separated by '|') \fBchange-preview-label(...)\fR (change \fB--preview-label\fR to the given string) + \fBchange-preview-window(...)\fR (change \fB--preview-window\fR option; rotate through the multiple option sets separated by '|') \fBchange-prompt(...)\fR (change prompt to the given string) - \fBchange-border-label(...)\fR (change \fB--border-label\fR to the given string) \fBchange-query(...)\fR (change query string to the given string) \fBclear-screen\fR \fIctrl-l\fR \fBclear-selection\fR (clear multi-selection) diff --git a/src/options.go b/src/options.go index fa238d7e..393f5804 100644 --- a/src/options.go +++ b/src/options.go @@ -609,6 +609,8 @@ func parseKeyChordsImpl(str string, message string, exit func(string)) map[tui.E add(tui.Start) case "load": add(tui.Load) + case "focus": + add(tui.Focus) case "alt-enter", "alt-return": chords[tui.CtrlAltKey('m')] = key case "alt-space": diff --git a/src/terminal.go b/src/terminal.go index a9565c86..62e80431 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -1265,7 +1265,7 @@ func (t *Terminal) resizeWindows(forcePreview bool) { } func (t *Terminal) printLabel(window tui.Window, render labelPrinter, opts labelOpts, length int, borderShape tui.BorderShape, redrawBorder bool) { - if window == nil || render == nil { + if window == nil { return } @@ -1274,6 +1274,9 @@ func (t *Terminal) printLabel(window tui.Window, render labelPrinter, opts label if redrawBorder { window.DrawHBorder() } + if render == nil { + return + } var col int if opts.column == 0 { col = util.Max(0, (window.Width()-length)/2) @@ -2616,6 +2619,11 @@ func (t *Terminal) Loop() { } } + var onFocus []*action + if actions, prs := t.keymap[tui.Focus.AsEvent()]; prs { + onFocus = actions + } + go func() { var focusedIndex int32 = minItem.Index() var version int64 = -1 @@ -2651,7 +2659,11 @@ func (t *Terminal) Loop() { if currentItem != nil { currentIndex = currentItem.Index() } - if focusedIndex != currentIndex || version != t.version { + focusChanged := focusedIndex != currentIndex + if onFocus != nil && focusChanged { + t.serverChan <- onFocus + } + if focusChanged || version != t.version { version = t.version focusedIndex = currentIndex refreshPreview(t.previewOpts.command) diff --git a/src/tui/tui.go b/src/tui/tui.go index 203da76c..a51627fd 100644 --- a/src/tui/tui.go +++ b/src/tui/tui.go @@ -92,6 +92,7 @@ const ( BackwardEOF Start Load + Focus AltBS diff --git a/test/test_go.rb b/test/test_go.rb index 5bf5ab58..67207fb4 100755 --- a/test/test_go.rb +++ b/test/test_go.rb @@ -2473,6 +2473,15 @@ class TestGoFZF < TestBase end end + def test_focus_event + tmux.send_keys 'seq 100 | fzf --bind "focus:transform-prompt(echo [[{}]])"', :Enter + tmux.until { |lines| assert_includes(lines[-1], '[[1]]') } + tmux.send_keys :Up + tmux.until { |lines| assert_includes(lines[-1], '[[2]]') } + tmux.send_keys :X + tmux.until { |lines| assert_includes(lines[-1], '[[]]') } + end + def test_labels_center tmux.send_keys 'echo x | fzf --border --border-label foobar --preview : --preview-label barfoo --bind "space:change-border-label(foobarfoo)+change-preview-label(barfoobar),enter:transform-border-label(echo foo{}foo)+transform-preview-label(echo bar{}bar)"', :Enter tmux.until do