fix(runtime): restoreLastOutput falls back on an empty frame, matching Ink (#100)

The frame-restore after an external stdout write (console.log / useStdout().write)
used `lastOutputToRender ?? lastOutput + "\n"`. `??` only falls back for
null/undefined, so an empty-string lastOutputToRender (the initial value, and the
value left by the screen-reader empty-frame path) restored "" — nothing — where Ink
restores lastOutput + "\n". Ink uses `||` (ink.tsx:507) and so does vue's own
mountedClear (render.ts:668); :518 was the lone inconsistent site. Changed `??` to
`||`. Locked by an SR-empty-frame + external-write test that re-emits "\n".

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Yunfei He
2026-05-31 22:04:06 +08:00
committed by GitHub
parent 8841350491
commit f99f23e346
2 changed files with 118 additions and 1 deletions
+7 -1
View File
@@ -515,7 +515,13 @@ export function createApp(root: Component, rootProps?: RootProps | null): TuiApp
// Clear() resets log-update's cursor state, so replay the latest cursor
// intent before restoring output after external stdout/stderr writes.
writer.setCursorPosition(cursorPosition);
writer.write(frameState.lastOutputToRender ?? frameState.lastOutput + "\n");
// Use `||` (not `??`): an EMPTY lastOutputToRender — its initial value before
// the first content commit, the value the narrowing-resize path assigns
// (render.ts:1043), and what an empty screen-reader frame leaves — must fall
// back to `lastOutput + "\n"`, matching Ink (ink.tsx:507) and vue's own
// mountedClear (render.ts:668). `??` only falls back for null/undefined, so an
// empty string would pass through and restore nothing after an external write.
writer.write(frameState.lastOutputToRender || frameState.lastOutput + "\n");
}
function writeToStdout(data: string) {