@ 261102.1

260705.3 · 978ded5cd0d4f1e2ee4d37b01f477bf01a7b9d7a

Pass bracketed paste actions through wait/track block

A pasted character firing a wait-arming binding swallowed the subsequent bracketed-paste-end, leaving t.pasting set forever and suppressing queryChanged for all later input. Let paste begin/end through the block so pasting state is maintained and the search for the edited query is dispatched.

reading declarations

src/terminal.go

@@ -5838,7 +5838,8 @@ func (t *Terminal) unblockTrack() { // The wait state machine. Invariant: arming captures every action after // 'wait' at any nesting level into wait.pending; while blocked, actions are // dropped unless they are results of work started before the block-// (bg-transform callbacks); abort/cancel discards everything.+// (bg-transform callbacks, bracketed paste bookkeeping); abort/cancel+// discards everything.  // blockWait blocks action execution and defers the given actions until the // current search completes (see UpdateList)@@ -6804,8 +6805,10 @@ func (t *Terminal) Loop() error { 			} 			// 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+			// started before the block), and bracketed paste bookkeeping (a+			// swallowed paste-end would leave t.pasting set forever).+			passthrough := inBgCallback || a.t == actAsync ||+				a.t == actBracketedPasteBegin || a.t == actBracketedPasteEnd 			// When wait-blocked, only allow abort/cancel 			if t.wait.blocked && !passthrough { 				if a.t == actAbort || a.t == actCancel {

test/lib/common.rb

@@ -177,6 +177,12 @@ class Tmux     system('tmux', 'setb', str, ';', 'pasteb', '-t', win, ';', 'send-keys', '-t', win, 'Enter')   end +  # Paste with bracketed paste control codes so fzf sees+  # bracketed-paste-begin/end around the content+  def paste_bracketed(str)+    system('tmux', 'setb', str, ';', 'pasteb', '-p', '-t', win)+  end+   def capture     go(%W[capture-pane -p -J -t #{win}]).map(&:rstrip).reverse.drop_while(&:empty?).reverse   end

test/test_core.rb

@@ -1251,6 +1251,20 @@ class TestCore < TestInteractive     tmux.until { |lines| assert_equal '> 5', lines[-3] }   end +  def test_wait_action_bracketed_paste+    # A wait armed by a binding fired from a pasted character must not break+    # bracketed paste handling: paste-end passes through the block so+    # t.pasting is cleared and the pending search is dispatched+    tmux.send_keys %(seq 100 | #{FZF} --bind 'a:put(a)+wait+first'), :Enter+    tmux.until { |lines| assert_equal 100, lines.match_count }+    tmux.paste_bracketed('1a2')+    # Search for the edited query must run; blocked forever before the fix+    tmux.until { |lines| assert_equal 0, lines.match_count }+    # Filtering must still work afterwards+    tmux.send_keys 'C-u', '55'+    tmux.until { |lines| assert_equal 1, lines.match_count }+  end+   def test_wait_action_expect     # --expect keys are ignored while wait-blocked, like the rest of the input     tmux.send_keys %((seq 100; sleep 2) | #{fzf('--expect ctrl-t --bind start:wait')}), :Enter