summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJunegunn Choi <junegunn.c@gmail.com>2023-01-23 16:22:25 +0900
committerJunegunn Choi <junegunn.c@gmail.com>2023-01-23 16:38:24 +0900
commit284d77fe2e41ec69fcc7ca7162bcf9b65b1641be (patch)
tree0dbac33153f7b7b611bc41451e09fdeeb4af4410
parent826178f1e2927ecef8b7699ef1269ba060a0a029 (diff)
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
-rw-r--r--CHANGELOG.md14
-rw-r--r--man/man1/fzf.120
-rw-r--r--src/options.go2
-rw-r--r--src/terminal.go16
-rw-r--r--src/tui/tui.go1
-rwxr-xr-xtest/test_go.rb9
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