Fix bg-transform reload/exclude

Async callbacks fire a later iteration than the one that scheduled
them, so newCommand/reloadSync/denylist must persist across iterations.

  fzf --bind 'space:bg-transform:echo reload:date'
This commit is contained in:
Junegunn Choi
2026-05-18 18:48:00 +09:00
parent fcc3c6acce
commit 5819e5ff2f
2 changed files with 28 additions and 4 deletions
+10 -4
View File
@@ -6366,12 +6366,18 @@ func (t *Terminal) Loop() error {
needBarrier = false needBarrier = false
} }
// These variables are defined outside the loop to be accessible from closures // These variables are defined outside the loop to be accessible from closures.
// In particular, async bg-transform callbacks run in a later iteration than
// the one that scheduled them, but still need to mutate state that the
// loop-end reload/event dispatch reads.
events := []util.EventType{} events := []util.EventType{}
changed := false changed := false
var newNth *[]Range var newNth *[]Range
var newWithNth *withNthSpec var newWithNth *withNthSpec
var newHeaderLines *int var newHeaderLines *int
var newCommand *commandSpec
var reloadSync bool
var denylist []int32
req := func(evts ...util.EventType) { req := func(evts ...util.EventType) {
for _, event := range evts { for _, event := range evts {
events = append(events, event) events = append(events, event)
@@ -6383,16 +6389,16 @@ func (t *Terminal) Loop() error {
// The main event loop // The main event loop
for loopIndex := int64(0); looping; loopIndex++ { for loopIndex := int64(0); looping; loopIndex++ {
var newCommand *commandSpec
var reloadSync bool
events = []util.EventType{} events = []util.EventType{}
changed = false changed = false
newNth = nil newNth = nil
newWithNth = nil newWithNth = nil
newHeaderLines = nil newHeaderLines = nil
newCommand = nil
reloadSync = false
denylist = nil
beof := false beof := false
queryChanged := false queryChanged := false
denylist := []int32{}
// Special handling of --sync. Activate the interface on the second tick. // Special handling of --sync. Activate the interface on the second tick.
if loopIndex == 1 && t.deferActivation() { if loopIndex == 1 && t.deferActivation() {
+18
View File
@@ -2153,6 +2153,24 @@ class TestCore < TestInteractive
tmux.until { |lines| assert lines.any_include?('a b c') || lines.any_include?('d e f') } tmux.until { |lines| assert lines.any_include?('a b c') || lines.any_include?('d e f') }
end end
# Regression: actions emitted by bg-transform must affect the iteration that
# processes the async result, not the (no-longer-active) iteration that
# scheduled the transform. Covers reload (newCommand) and exclude (denylist).
def test_bg_transform_action_output
tmux.send_keys %(seq 5 | #{FZF} --bind 'a:bg-transform(echo reload:seq 10 20),b:bg-transform(echo exclude)'), :Enter
tmux.until { |lines| assert_equal 5, lines.item_count }
tmux.send_keys :a
tmux.until do |lines|
assert_equal 11, lines.match_count
assert_includes lines, '> 10'
end
tmux.send_keys :b
tmux.until do |lines|
assert_equal 10, lines.match_count
assert_includes lines, '> 11'
end
end
def test_change_with_nth_search def test_change_with_nth_search
input = [ input = [
'alpha bravo charlie', 'alpha bravo charlie',