fix(runtime): render linear screen-reader output in the live commit path (Ink parity, G03) (#36)
* fix(runtime): render linear screen-reader output in the live commit path (Ink parity, G03)
commit() previously called paint(tuiRoot) (the 2D grid painter) unconditionally
for both the non-interactive and interactive branches, so an app mounted with
isScreenReaderEnabled emitted the visual frame (box-drawing borders, padded
grid) into the live stream instead of flat linearized text. isScreenReaderEnabled
was only consulted to disable commit throttling.
Add a renderFrame(width) helper that branches on isScreenReaderEnabled: when SR
is enabled it linearizes the tree via renderScreenReaderOutput(tuiRoot,
{ skipStaticElements: true }) and wraps it with wrapAnsi(out, width,
{ trim: false, hard: true }), mirroring Ink's onRender SR branch
(ink.tsx:598-603). Both commit branches now call renderFrame() instead of
paint() directly. The non-SR path is byte-for-byte unchanged (renderFrame
returns paint(tuiRoot)). Static output continues to flush through the existing
paintStaticNode path; full SR-static linearization parity is deferred.
render-to-string.ts already used renderScreenReaderOutput and is unaffected.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* chore(parity): ledger — G03 pr-open, reconcile G02 merged, track G17 (SR edges)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
import { defineComponent, nextTick } from "vue";
|
||||
import { expect, test } from "vite-plus/test";
|
||||
import { Box, createApp, Text } from "@vue-tui/runtime";
|
||||
import {
|
||||
makeFakeStdin,
|
||||
makeFakeWritable,
|
||||
captureWrites,
|
||||
getContentWrites,
|
||||
} from "../lifecycle/test-streams.ts";
|
||||
|
||||
// G03 (Ink parity): the LIVE commit path must branch on isScreenReaderEnabled
|
||||
// and emit the flat, linearized screen-reader text (via renderScreenReaderOutput),
|
||||
// NOT the 2D grid produced by paint() — which would include border glyphs.
|
||||
|
||||
test.sequential("live commit path emits linear screen-reader text (no border glyphs) when SR enabled", async () => {
|
||||
const App = defineComponent(() => {
|
||||
return () => (
|
||||
<Box borderStyle="round">
|
||||
<Text>Hello world</Text>
|
||||
</Box>
|
||||
);
|
||||
});
|
||||
|
||||
const app = createApp(App);
|
||||
const stdout = makeFakeWritable({ columns: 80 });
|
||||
const stderr = makeFakeWritable({ columns: 80 });
|
||||
const { stream: stdin } = makeFakeStdin();
|
||||
const writes = captureWrites(stdout);
|
||||
|
||||
app.mount({
|
||||
stdout,
|
||||
stdin,
|
||||
stderr,
|
||||
exitOnCtrlC: false,
|
||||
isScreenReaderEnabled: true,
|
||||
});
|
||||
|
||||
await nextTick();
|
||||
await nextTick();
|
||||
|
||||
const content = getContentWrites(writes).join("");
|
||||
|
||||
// The flat text content must be present.
|
||||
expect(content).toContain("Hello world");
|
||||
|
||||
// Border / box-drawing glyphs must NOT appear — SR mode linearizes the tree.
|
||||
const borderGlyphs = ["╭", "╮", "╰", "╯", "─", "│"];
|
||||
for (const glyph of borderGlyphs) {
|
||||
expect(content).not.toContain(glyph);
|
||||
}
|
||||
|
||||
app.unmount();
|
||||
});
|
||||
|
||||
test.sequential("live commit path WITHOUT SR still emits 2D grid with border glyphs (contrast)", async () => {
|
||||
const App = defineComponent(() => {
|
||||
return () => (
|
||||
<Box borderStyle="round">
|
||||
<Text>Hello world</Text>
|
||||
</Box>
|
||||
);
|
||||
});
|
||||
|
||||
const app = createApp(App);
|
||||
const stdout = makeFakeWritable({ columns: 80 });
|
||||
const stderr = makeFakeWritable({ columns: 80 });
|
||||
const { stream: stdin } = makeFakeStdin();
|
||||
const writes = captureWrites(stdout);
|
||||
|
||||
app.mount({
|
||||
stdout,
|
||||
stdin,
|
||||
stderr,
|
||||
exitOnCtrlC: false,
|
||||
});
|
||||
|
||||
await nextTick();
|
||||
await nextTick();
|
||||
|
||||
const content = getContentWrites(writes).join("");
|
||||
expect(content).toContain("Hello world");
|
||||
// Non-SR path renders the visual frame, which DOES contain border glyphs.
|
||||
expect(content).toContain("─");
|
||||
|
||||
app.unmount();
|
||||
});
|
||||
Reference in New Issue
Block a user