Run bg-transform callbacks while wait/track-blocked

Background transform results are unrelated to the block; dropping them
would silently lose completed work. Applies both the dedicated
bg-transform-* setters and actions parsed from generic bg-transform
output (inBgCallback). Searches initiated by a bg result are not
waited for.
This commit is contained in:
Junegunn Choi
2026-07-03 08:55:16 +09:00
parent 8631595ce0
commit 6ecf96970a
3 changed files with 63 additions and 7 deletions
+22 -7
View File
@@ -1890,10 +1890,10 @@ func (t *Terminal) UpdateList(result MatchResult) {
t.searchInProgress = false
// If waiting, unblock so main loop can execute pending actions.
// Note: any final result unblocks the wait, not just the one for the
// search that armed it. Back-to-back searches (--listen, reload+wait)
// can therefore unblock early and run the pending actions on the
// previous result set. Accepted; a per-search generation token
// through the matcher isn't worth the complexity.
// search that armed it. Back-to-back searches (--listen, bg-transform
// callbacks, reload+wait) can therefore unblock early and run the
// pending actions on the previous result set. Accepted; a per-search
// generation token through the matcher isn't worth the complexity.
if t.waitBlocked {
t.unblockWait()
wakeUp = len(t.pendingActions) > 0
@@ -6523,6 +6523,10 @@ func (t *Terminal) Loop() error {
var newCommand *commandSpec
var reloadSync bool
var denylist []int32
// True while running bg-transform callbacks. Declared outside the loop
// because callbacks invoke the doActions closure of the iteration that
// scheduled them, not the one executing actAsync.
inBgCallback := false
req := func(evts ...util.EventType) {
for _, event := range evts {
events = append(events, event)
@@ -6677,8 +6681,13 @@ func (t *Terminal) Loop() error {
currentIndex := t.currentIndex()
for i, action := range actions {
if action.t == actWait {
// Already waiting; ignore so input can't reset the blocked state
// Already waiting. Actions parsed from a bg-transform
// result join the current wait; user input can't reset
// the blocked state
if t.waitBlocked {
if inBgCallback {
t.pendingActions = append(t.pendingActions, actions[i+1:]...)
}
return true
}
// Block if search is in progress or will be triggered
@@ -6752,8 +6761,12 @@ func (t *Terminal) Loop() error {
callback(a.a)
}
}
// Actions that run even while wait/track-blocked: bg-transform
// callbacks and their parsed actions (results of processes
// started before the block).
passthrough := inBgCallback || a.t == actAsync
// When wait-blocked, only allow abort/cancel
if t.waitBlocked {
if t.waitBlocked && !passthrough {
if a.t == actAbort || a.t == actCancel {
t.unblockWait()
t.pendingActions = nil
@@ -6762,7 +6775,7 @@ func (t *Terminal) Loop() error {
return true
}
// When track-blocked, only allow abort/cancel and track-disabling actions
if t.trackBlocked && a.t != actToggleTrack && a.t != actToggleTrackCurrent && a.t != actUntrackCurrent {
if t.trackBlocked && !passthrough && a.t != actToggleTrack && a.t != actToggleTrackCurrent && a.t != actUntrackCurrent {
if a.t == actAbort || a.t == actCancel {
t.unblockTrack()
req(reqPrompt, reqInfo)
@@ -6773,11 +6786,13 @@ func (t *Terminal) Loop() error {
switch a.t {
case actIgnore, actStart, actClick:
case actAsync:
inBgCallback = true
for _, callback := range callbacks {
if t.bgVersion == callback.version {
callback.callback()
}
}
inBgCallback = false
case actBecome:
valid, list := t.buildPlusList(a.a, false)
if valid {