diff --git a/src/terminal.go b/src/terminal.go index 517deee9..99482eeb 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -6747,8 +6747,11 @@ func (t *Terminal) Loop() error { callback(a.a) } } - // When wait-blocked, only allow abort/cancel - if t.waitBlocked { + // When wait-blocked, only allow abort/cancel. Background transform + // callbacks (actAsync) are let through since they're unrelated to the + // wait; blocking them would silently drop bg-transform results that + // complete while waiting. + if t.waitBlocked && a.t != actAsync { if a.t == actAbort || a.t == actCancel { t.unblockWait() t.pendingActions = nil diff --git a/test/test_core.rb b/test/test_core.rb index 9d55ca59..c1da6345 100644 --- a/test/test_core.rb +++ b/test/test_core.rb @@ -1185,6 +1185,15 @@ class TestCore < TestInteractive tmux.until { |lines| assert_equal 1, lines.match_count } end + def test_wait_action_bg_transform + # A bg-transform result is unrelated to the wait, so it's applied while the + # wait is still blocking rather than dropped. The long read keeps the wait + # blocked so the (instant) bg-transform completes during the block; the + # header must show while '(..)' is still displayed. + tmux.send_keys %((seq 100; sleep 2) | #{FZF} --bind 'start:bg-transform-header(echo hello)+search(5)+wait'), :Enter + tmux.until { |lines| assert(lines.any_include?('(..)') && lines.any_include?('hello')) } + end + def test_clear_selection tmux.send_keys %(seq 100 | #{FZF} --multi --bind space:clear-selection), :Enter tmux.until { |lines| assert_equal 100, lines.match_count }