From 250496c953f8e36cb70ca99d58034bd79a1d0670 Mon Sep 17 00:00:00 2001 From: Junegunn Choi Date: Sun, 7 Jan 2024 17:44:49 +0900 Subject: [PATCH] Add 'result' event that is triggered when the result list is ready Close #3560 --- CHANGELOG.md | 5 +++++ man/man1/fzf.1 | 9 +++++++++ src/options.go | 2 ++ src/terminal.go | 10 ++++++++-- src/tui/tui.go | 1 + test/test_go.rb | 10 ++++++++++ 6 files changed, 35 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 30bca8c..c7e5434 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +0.46.0 (WIP) +------ +- Added `result` event that is triggered when the filtering for the current query is complete and the result list is ready. +- Bug fixes + 0.45.0 ------ - Added `transform` action to conditionally perform a series of actions diff --git a/man/man1/fzf.1 b/man/man1/fzf.1 index e39f6dd..905f677 100644 --- a/man/man1/fzf.1 +++ b/man/man1/fzf.1 @@ -1075,6 +1075,15 @@ e.g. \fB# Change the prompt to "loaded" when the input stream is complete (seq 10; sleep 1; seq 11 20) | fzf --prompt 'Loading> ' --bind 'load:change-prompt:Loaded> '\fR .RE +\fIresult\fR +.RS +Triggered when the filtering for the current query is complete and the result list is ready. + +e.g. + \fB# Put the cursor on the second item when the query string is empty + # * Note that you can't use 'change' event in this case because the second position may not be available + fzf --sync --bind 'result:transform:[[ -z {fzf:query} ]] && echo "pos(2)"'\fR +.RE \fIchange\fR .RS Triggered whenever the query string is changed diff --git a/src/options.go b/src/options.go index e18bdd1..2962f4b 100644 --- a/src/options.go +++ b/src/options.go @@ -650,6 +650,8 @@ func parseKeyChordsImpl(str string, message string, exit func(string)) map[tui.E add(tui.Load) case "focus": add(tui.Focus) + case "result": + add(tui.Result) case "one": add(tui.One) case "zero": diff --git a/src/terminal.go b/src/terminal.go index 295886d..67f5ced 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -251,6 +251,7 @@ type Terminal struct { borderWidth int count int progress int + hasResultActions bool hasFocusActions bool hasLoadActions bool triggerLoad bool @@ -731,6 +732,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal { ellipsis: opts.Ellipsis, ansi: opts.Ansi, tabstop: opts.Tabstop, + hasResultActions: false, hasFocusActions: false, hasLoadActions: false, triggerLoad: false, @@ -759,7 +761,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal { killChan: make(chan int), serverInputChan: make(chan []*action, 10), serverOutputChan: make(chan string), - eventChan: make(chan tui.Event, 4), // (load + zero|one) | (focus) | (GetChar) + eventChan: make(chan tui.Event, 5), // (load + result + zero|one) | (focus) | (GetChar) tui: renderer, initFunc: func() { renderer.Init() }, executing: util.NewAtomicBool(false), @@ -803,6 +805,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal { } } + _, t.hasResultActions = t.keymap[tui.Result.AsEvent()] _, t.hasFocusActions = t.keymap[tui.Focus.AsEvent()] _, t.hasLoadActions = t.keymap[tui.Load.AsEvent()] @@ -1076,6 +1079,9 @@ func (t *Terminal) UpdateList(merger *Merger) { t.eventChan <- one } } + if t.hasResultActions { + t.eventChan <- tui.Result.AsEvent() + } } t.mutex.Unlock() t.reqBox.Set(reqInfo, nil) @@ -3189,7 +3195,7 @@ func (t *Terminal) Loop() { } select { case event = <-t.eventChan: - needBarrier = !event.Is(tui.Load, tui.Focus, tui.One, tui.Zero) + needBarrier = !event.Is(tui.Load, tui.Result, tui.Focus, tui.One, tui.Zero) case serverActions := <-t.serverInputChan: event = tui.Invalid.AsEvent() if t.listenAddr == nil || t.listenAddr.IsLocal() || t.listenUnsafe { diff --git a/src/tui/tui.go b/src/tui/tui.go index 5a5e18d..74129c1 100644 --- a/src/tui/tui.go +++ b/src/tui/tui.go @@ -105,6 +105,7 @@ const ( Focus One Zero + Result AltBS diff --git a/test/test_go.rb b/test/test_go.rb index aa4dfd4..b69daa3 100755 --- a/test/test_go.rb +++ b/test/test_go.rb @@ -2721,6 +2721,16 @@ class TestGoFZF < TestBase tmux.until { |lines| refute_includes(lines[-1], '[[1]]') } end + def test_result_event + tmux.send_keys '(echo 0; seq 10) | fzf --bind "result:pos(2)"', :Enter + tmux.until { |lines| assert_equal 11, lines.item_count } + tmux.until { |lines| assert_includes lines, '> 1' } + tmux.send_keys '9' + tmux.until { |lines| assert_includes lines, '> 9' } + tmux.send_keys :BSpace + 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