diff --git a/src/renderer/src/components/terminal-pane/pty-connection/output/replay-data-drain.ts b/src/renderer/src/components/terminal-pane/pty-connection/output/replay-data-drain.ts index 7f3a6e4238c..c5c52a8c589 100644 --- a/src/renderer/src/components/terminal-pane/pty-connection/output/replay-data-drain.ts +++ b/src/renderer/src/components/terminal-pane/pty-connection/output/replay-data-drain.ts @@ -1,5 +1,9 @@ import { RELEASE_SYNCHRONIZED_OUTPUT } from '../../../../../../shared/terminal/protocol/input-modes/terminal-mode-reset-profiles' import { syncTerminalScrollIntentFromViewport } from '@/lib/pane-manager/terminal-scroll-intent' +import { + beginTerminalScrollIntentBufferRebuild, + endTerminalScrollIntentBufferRebuild +} from '@/lib/pane-manager/terminal-scroll-intent-rebuild' import { cancelDeferredScrollRestore, cancelPendingFitScrollRestore @@ -199,18 +203,26 @@ export function bindReplayDataDrain(session: ConnectPanePtySession): void { continue } if (preSleep) { + const terminal = session.pane.terminal await finishWakeScrollbackRestore( preSleep, - session.pane.terminal, - session.writeReplayDataAsync + terminal, + session.writeReplayDataAsync, + (line) => { + // The person's place wins: drop restores captured before it (a remount's first fit, at + // the bottom), scroll with intent enforcement paused (its synchronous "follow output" + // would snap back), then record the place as a pin for the fits still to come. + cancelDeferredScrollRestore(terminal) + cancelPendingFitScrollRestore(terminal) + beginTerminalScrollIntentBufferRebuild(terminal) + try { + terminal.scrollToLine(line) + } finally { + endTerminalScrollIntentBufferRebuild(terminal) + } + syncTerminalScrollIntentFromViewport(terminal, { allowBufferShrink: true }) + } ) - if (preSleep.scrolledTo !== null) { - // The person's place wins: drop restores captured before it (a remount's first fit, at the - // bottom, waiting for a later fit) and record it as a pin for the fits still to come. - cancelDeferredScrollRestore(session.pane.terminal) - cancelPendingFitScrollRestore(session.pane.terminal) - syncTerminalScrollIntentFromViewport(session.pane.terminal, { allowBufferShrink: true }) - } if (!isCurrentPayload()) { continue } diff --git a/src/renderer/src/lib/orca-cloud/cloud-wake-scrollback.ts b/src/renderer/src/lib/orca-cloud/cloud-wake-scrollback.ts index c97c0ff3eb9..d00ac2784d7 100644 --- a/src/renderer/src/lib/orca-cloud/cloud-wake-scrollback.ts +++ b/src/renderer/src/lib/orca-cloud/cloud-wake-scrollback.ts @@ -319,7 +319,9 @@ export function composeWakeRestore(block: string, terminal: WokenTerminal): stri export async function finishWakeScrollbackRestore( restore: WakeScrollbackRestore, terminal: WokenTerminal, - write: (data: string) => Promise + write: (data: string) => Promise, + /** Puts the person back on their line; the pane may pass one that keeps its scroll intent in step. */ + scrollTo: (line: number) => void = (line) => terminal.scrollToLine(line) ): Promise { const data = composeWakeRestore(restore.block, terminal) if (data !== null) { @@ -333,7 +335,7 @@ export async function finishWakeScrollbackRestore( return false } if (restore.scrolledTo !== null) { - terminal.scrollToLine(restore.scrolledTo) + scrollTo(restore.scrolledTo) } return true }