mirror of
https://github.com/junegunn/fzf.git
synced 2026-06-24 18:03:54 +08:00
Add result-final event
- Fires like result, but only after the input stream closes - Use for one-shot per-query actions that would otherwise re-fire on every intermediate snapshot during loading Close #4835
This commit is contained in:
@@ -1,6 +1,17 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
0.74.0 (WIP)
|
||||
------------
|
||||
- Added `result-final` event, a variant of `result` that is not triggered while the input stream is still open (#4835)
|
||||
- Use it for one-shot, per-query actions that would otherwise re-fire on every intermediate snapshot during loading
|
||||
```sh
|
||||
# 'result' fires per intermediate snapshot (header keeps updating during load);
|
||||
# 'result-final' fires once after the stream closes (footer shows the final count)
|
||||
(seq 100; sleep 1; seq 100) | fzf --query 1 \
|
||||
--bind 'result:transform-header(echo result: $FZF_MATCH_COUNT),result-final:transform-footer(echo final: $FZF_MATCH_COUNT)'
|
||||
```
|
||||
|
||||
0.73.1
|
||||
------
|
||||
- Bug fixes
|
||||
|
||||
+15
-1
@@ -226,7 +226,7 @@ Enable processing of ANSI color codes
|
||||
Synchronous search for multi-staged filtering. If specified, fzf will launch
|
||||
the finder only after the input stream is complete and the initial filtering
|
||||
and the associated actions (bound to any of \fBstart\fR, \fBload\fR,
|
||||
\fBresult\fR, or \fBfocus\fR) are complete.
|
||||
\fBresult\fR, \fBresult\-final\fR, or \fBfocus\fR) are complete.
|
||||
|
||||
.RS
|
||||
e.g. \fB# Avoid rendering both fzf instances at the same time
|
||||
@@ -1855,6 +1855,20 @@ e.g.
|
||||
# * 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 {q} ]] && echo "pos(2)"'\fR
|
||||
.RE
|
||||
|
||||
\fIresult\-final\fR
|
||||
.RS
|
||||
Same as \fIresult\fR, but suppressed while the input stream is still open. Use
|
||||
this when you want a one-shot action per query instead of one per intermediate
|
||||
snapshot during loading.
|
||||
|
||||
e.g.
|
||||
\fB# 'result' fires per intermediate snapshot (header keeps updating during load);
|
||||
# 'result-final' fires once after the stream closes (footer shows the final count)
|
||||
(seq 100; sleep 1; seq 100) | fzf \-\-query 1 \\
|
||||
\-\-bind 'result:transform\-header(echo result: $FZF_MATCH_COUNT),result\-final:transform\-footer(echo final: $FZF_MATCH_COUNT)'\fR
|
||||
.RE
|
||||
|
||||
\fIchange\fR
|
||||
.RS
|
||||
Triggered whenever the query string is changed
|
||||
|
||||
@@ -1063,6 +1063,8 @@ func parseKeyChords(str string, message string) (map[tui.Event]string, []tui.Eve
|
||||
add(tui.Focus)
|
||||
case "result":
|
||||
add(tui.Result)
|
||||
case "result-final":
|
||||
add(tui.ResultFinal)
|
||||
case "resize":
|
||||
add(tui.Resize)
|
||||
case "one":
|
||||
|
||||
+16
-3
@@ -1152,7 +1152,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
|
||||
bgSemaphore: make(chan struct{}, maxBgProcesses),
|
||||
bgSemaphores: make(map[action]chan struct{}),
|
||||
keyChan: make(chan tui.Event),
|
||||
eventChan: make(chan tui.Event, 6), // start | (load + result + zero|one) | (focus) | (resize)
|
||||
eventChan: make(chan tui.Event, 7), // start | (load + result + result-final + zero|one) | (focus) | (resize)
|
||||
timerChan: make(chan tui.Event), // unbuffered: every() ticks coalesce when main loop is busy
|
||||
tui: renderer,
|
||||
ttyDefault: opts.TtyDefault,
|
||||
@@ -1345,6 +1345,9 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
|
||||
}
|
||||
_, t.hasStartActions = t.keymap[tui.Start.AsEvent()]
|
||||
_, t.hasResultActions = t.keymap[tui.Result.AsEvent()]
|
||||
if _, prs := t.keymap[tui.ResultFinal.AsEvent()]; prs {
|
||||
t.hasResultActions = true
|
||||
}
|
||||
_, t.hasFocusActions = t.keymap[tui.Focus.AsEvent()]
|
||||
_, t.hasLoadActions = t.keymap[tui.Load.AsEvent()]
|
||||
|
||||
@@ -2022,8 +2025,18 @@ func (t *Terminal) UpdateList(result MatchResult) {
|
||||
}
|
||||
}
|
||||
if t.hasResultActions {
|
||||
t.pendingReqList = true
|
||||
t.eventChan <- tui.Result.AsEvent()
|
||||
result := tui.Result.AsEvent()
|
||||
if _, prs := t.keymap[result]; prs {
|
||||
t.pendingReqList = true
|
||||
t.eventChan <- result
|
||||
}
|
||||
if !t.reading {
|
||||
resultFinal := tui.ResultFinal.AsEvent()
|
||||
if _, prs := t.keymap[resultFinal]; prs {
|
||||
t.pendingReqList = true
|
||||
t.eventChan <- resultFinal
|
||||
}
|
||||
}
|
||||
}
|
||||
updateList := !t.trackBlocked && !t.pendingReqList
|
||||
updatePrompt := trackWasBlocked && !t.trackBlocked
|
||||
|
||||
@@ -164,11 +164,12 @@ func _() {
|
||||
_ = x[ClickFooter-153]
|
||||
_ = x[Multi-154]
|
||||
_ = x[Every-155]
|
||||
_ = x[ResultFinal-156]
|
||||
}
|
||||
|
||||
const _EventType_name = "RuneCtrlACtrlBCtrlCCtrlDCtrlECtrlFCtrlGCtrlHTabCtrlJCtrlKCtrlLEnterCtrlNCtrlOCtrlPCtrlQCtrlRCtrlSCtrlTCtrlUCtrlVCtrlWCtrlXCtrlYCtrlZEscCtrlSpaceCtrlBackSlashCtrlRightBracketCtrlCaretCtrlSlashShiftTabBackspaceDeletePageUpPageDownUpDownLeftRightHomeEndInsertShiftUpShiftDownShiftLeftShiftRightShiftDeleteShiftHomeShiftEndShiftPageUpShiftPageDownF1F2F3F4F5F6F7F8F9F10F11F12AltBackspaceAltUpAltDownAltLeftAltRightAltDeleteAltHomeAltEndAltPageUpAltPageDownAltShiftUpAltShiftDownAltShiftLeftAltShiftRightAltShiftDeleteAltShiftHomeAltShiftEndAltShiftPageUpAltShiftPageDownCtrlUpCtrlDownCtrlLeftCtrlRightCtrlHomeCtrlEndCtrlBackspaceCtrlDeleteCtrlPageUpCtrlPageDownAltCtrlAltCtrlAltUpCtrlAltDownCtrlAltLeftCtrlAltRightCtrlAltHomeCtrlAltEndCtrlAltBackspaceCtrlAltDeleteCtrlAltPageUpCtrlAltPageDownCtrlShiftUpCtrlShiftDownCtrlShiftLeftCtrlShiftRightCtrlShiftHomeCtrlShiftEndCtrlShiftDeleteCtrlShiftPageUpCtrlShiftPageDownCtrlAltShiftUpCtrlAltShiftDownCtrlAltShiftLeftCtrlAltShiftRightCtrlAltShiftHomeCtrlAltShiftEndCtrlAltShiftDeleteCtrlAltShiftPageUpCtrlAltShiftPageDownMouseDoubleClickLeftClickRightClickSLeftClickSRightClickScrollUpScrollDownSScrollUpSScrollDownPreviewScrollUpPreviewScrollDownInvalidFatalBracketedPasteBeginBracketedPasteEndResizeChangeBackwardEOFStartLoadFocusOneZeroResultJumpJumpCancelClickHeaderClickFooterMultiEvery"
|
||||
const _EventType_name = "RuneCtrlACtrlBCtrlCCtrlDCtrlECtrlFCtrlGCtrlHTabCtrlJCtrlKCtrlLEnterCtrlNCtrlOCtrlPCtrlQCtrlRCtrlSCtrlTCtrlUCtrlVCtrlWCtrlXCtrlYCtrlZEscCtrlSpaceCtrlBackSlashCtrlRightBracketCtrlCaretCtrlSlashShiftTabBackspaceDeletePageUpPageDownUpDownLeftRightHomeEndInsertShiftUpShiftDownShiftLeftShiftRightShiftDeleteShiftHomeShiftEndShiftPageUpShiftPageDownF1F2F3F4F5F6F7F8F9F10F11F12AltBackspaceAltUpAltDownAltLeftAltRightAltDeleteAltHomeAltEndAltPageUpAltPageDownAltShiftUpAltShiftDownAltShiftLeftAltShiftRightAltShiftDeleteAltShiftHomeAltShiftEndAltShiftPageUpAltShiftPageDownCtrlUpCtrlDownCtrlLeftCtrlRightCtrlHomeCtrlEndCtrlBackspaceCtrlDeleteCtrlPageUpCtrlPageDownAltCtrlAltCtrlAltUpCtrlAltDownCtrlAltLeftCtrlAltRightCtrlAltHomeCtrlAltEndCtrlAltBackspaceCtrlAltDeleteCtrlAltPageUpCtrlAltPageDownCtrlShiftUpCtrlShiftDownCtrlShiftLeftCtrlShiftRightCtrlShiftHomeCtrlShiftEndCtrlShiftDeleteCtrlShiftPageUpCtrlShiftPageDownCtrlAltShiftUpCtrlAltShiftDownCtrlAltShiftLeftCtrlAltShiftRightCtrlAltShiftHomeCtrlAltShiftEndCtrlAltShiftDeleteCtrlAltShiftPageUpCtrlAltShiftPageDownMouseDoubleClickLeftClickRightClickSLeftClickSRightClickScrollUpScrollDownSScrollUpSScrollDownPreviewScrollUpPreviewScrollDownInvalidFatalBracketedPasteBeginBracketedPasteEndResizeChangeBackwardEOFStartLoadFocusOneZeroResultJumpJumpCancelClickHeaderClickFooterMultiEveryResultFinal"
|
||||
|
||||
var _EventType_index = [...]uint16{0, 4, 9, 14, 19, 24, 29, 34, 39, 44, 47, 52, 57, 62, 67, 72, 77, 82, 87, 92, 97, 102, 107, 112, 117, 122, 127, 132, 135, 144, 157, 173, 182, 191, 199, 208, 214, 220, 228, 230, 234, 238, 243, 247, 250, 256, 263, 272, 281, 291, 302, 311, 319, 330, 343, 345, 347, 349, 351, 353, 355, 357, 359, 361, 364, 367, 370, 382, 387, 394, 401, 409, 418, 425, 431, 440, 451, 461, 473, 485, 498, 512, 524, 535, 549, 565, 571, 579, 587, 596, 604, 611, 624, 634, 644, 656, 659, 666, 675, 686, 697, 709, 720, 730, 746, 759, 772, 787, 798, 811, 824, 838, 851, 863, 878, 893, 910, 924, 940, 956, 973, 989, 1004, 1022, 1040, 1060, 1065, 1076, 1085, 1095, 1105, 1116, 1124, 1134, 1143, 1154, 1169, 1186, 1193, 1198, 1217, 1234, 1240, 1246, 1257, 1262, 1266, 1271, 1274, 1278, 1284, 1288, 1298, 1309, 1320, 1325, 1330}
|
||||
var _EventType_index = [...]uint16{0, 4, 9, 14, 19, 24, 29, 34, 39, 44, 47, 52, 57, 62, 67, 72, 77, 82, 87, 92, 97, 102, 107, 112, 117, 122, 127, 132, 135, 144, 157, 173, 182, 191, 199, 208, 214, 220, 228, 230, 234, 238, 243, 247, 250, 256, 263, 272, 281, 291, 302, 311, 319, 330, 343, 345, 347, 349, 351, 353, 355, 357, 359, 361, 364, 367, 370, 382, 387, 394, 401, 409, 418, 425, 431, 440, 451, 461, 473, 485, 498, 512, 524, 535, 549, 565, 571, 579, 587, 596, 604, 611, 624, 634, 644, 656, 659, 666, 675, 686, 697, 709, 720, 730, 746, 759, 772, 787, 798, 811, 824, 838, 851, 863, 878, 893, 910, 924, 940, 956, 973, 989, 1004, 1022, 1040, 1060, 1065, 1076, 1085, 1095, 1105, 1116, 1124, 1134, 1143, 1154, 1169, 1186, 1193, 1198, 1217, 1234, 1240, 1246, 1257, 1262, 1266, 1271, 1274, 1278, 1284, 1288, 1298, 1309, 1320, 1325, 1330, 1341}
|
||||
|
||||
func (i EventType) String() string {
|
||||
if i < 0 || i >= EventType(len(_EventType_index)-1) {
|
||||
|
||||
@@ -234,6 +234,7 @@ const (
|
||||
ClickFooter
|
||||
Multi
|
||||
Every
|
||||
ResultFinal
|
||||
)
|
||||
|
||||
func (t EventType) AsEvent() Event {
|
||||
|
||||
@@ -1405,6 +1405,17 @@ class TestCore < TestInteractive
|
||||
tmux.until { |lines| assert_includes lines, '> 1' }
|
||||
end
|
||||
|
||||
def test_result_final_event
|
||||
tmux.send_keys %[(seq 100; sleep 1; seq 100) | #{FZF} \\
|
||||
--query 1 \\
|
||||
--bind 'result:transform-header(echo "R=$FZF_MATCH_COUNT")' \\
|
||||
--bind 'result-final:transform-footer(echo "F=$FZF_MATCH_COUNT")'], :Enter
|
||||
tmux.until { |lines| assert lines.any_include?('R=20') }
|
||||
tmux.until { |lines| refute lines.any_include?('F=20') }
|
||||
tmux.until { |lines| assert lines.any_include?('R=40') }
|
||||
tmux.until { |lines| assert lines.any_include?('F=40') }
|
||||
end
|
||||
|
||||
def test_every_event
|
||||
tmux.send_keys %(seq 100 | fzf --bind 'every(0.2):transform-prompt(cat #{tempname})'), :Enter
|
||||
tmux.until { |lines| assert_equal 100, lines.match_count }
|
||||
|
||||
Reference in New Issue
Block a user