From a5bdd1be7ea71f063808bf75e007ff0181f7d771 Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Wed, 17 Jun 2026 02:03:06 -0700 Subject: [PATCH] Fix hidden synchronized split-boundary replay --- .../terminal-pane/pty-connection.ts | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/renderer/src/components/terminal-pane/pty-connection.ts b/src/renderer/src/components/terminal-pane/pty-connection.ts index e976913becd..731f01cf2c0 100644 --- a/src/renderer/src/components/terminal-pane/pty-connection.ts +++ b/src/renderer/src/components/terminal-pane/pty-connection.ts @@ -734,17 +734,21 @@ function updateSynchronizedOutputScanTail(data: string): string { return data.slice(-SYNCHRONIZED_OUTPUT_SCAN_TAIL_CHARS) } -function containsSequenceAcrossBoundary(tail: string, data: string, sequence: string): boolean { +function getSequenceAcrossBoundaryPrefix( + tail: string, + data: string, + sequence: string +): string | null { const maxPrefixLength = Math.min(sequence.length - 1, tail.length, data.length) for (let prefixLength = 1; prefixLength <= maxPrefixLength; prefixLength++) { if ( tail.endsWith(sequence.slice(0, prefixLength)) && data.startsWith(sequence.slice(prefixLength)) ) { - return true + return tail.slice(-prefixLength) } } - return false + return null } function containsCursorPositionSequence(data: string): boolean { @@ -3407,18 +3411,19 @@ export function connectPanePty( const synchronizedOutputEnded = containsSynchronizedOutputEnd(hiddenSynchronizedScanData) // Why: if a DEC 2026 marker spans chunks, xterm may already hold the // first bytes of that escape. Complete that boundary live, then skip. - const splitSynchronizedBoundary = - !foreground && - (containsSequenceAcrossBoundary( - synchronizedHiddenOutputScanTail, - data, - SYNCHRONIZED_OUTPUT_START_SEQUENCE - ) || - containsSequenceAcrossBoundary( + const splitSynchronizedBoundaryPrefix = !foreground + ? (getSequenceAcrossBoundaryPrefix( + synchronizedHiddenOutputScanTail, + data, + SYNCHRONIZED_OUTPUT_START_SEQUENCE + ) ?? + getSequenceAcrossBoundaryPrefix( synchronizedHiddenOutputScanTail, data, SYNCHRONIZED_OUTPUT_END_SEQUENCE )) + : null + const splitSynchronizedBoundary = splitSynchronizedBoundaryPrefix !== null const synchronizedHiddenOutput = !foreground && (synchronizedHiddenOutputActive || synchronizedOutputStarted || synchronizedOutputEnded) @@ -3456,7 +3461,10 @@ export function connectPanePty( : 'synchronized' ) } - writePtyOutputToXterm(data, foreground) + writePtyOutputToXterm( + splitSynchronizedBoundary ? `${splitSynchronizedBoundaryPrefix}${data}` : data, + foreground + ) } else if ( (hiddenOutputRestoreNeeded || hiddenOutputRestoreInFlight) && restoreAppliesToCurrentPty