1// Adapting canonical row snapshots into the flat, column-indexed shape the
2// prediction engine reconciles against.
3//
4// This exists because `RowSnapshot.cells` is not column-indexed: spacer tails
5// are omitted, so a wide glyph advances two columns from one array entry, and
6// the canonical default tail is trimmed away entirely. Predictions are stated
7// in columns, so the translation has to happen somewhere — and it belongs here,
8// tested once, rather than inline at the reconciliation site where an off-by-one
9// would silently read the wrong cell and retract a correct prediction.
10
11import type { CellSnapshot } from "../ghostty/terminal.ts";
12
13/**
14 * Column-indexed text for one row. Empty and trimmed columns read as `""`,
15 * which is also what a prediction compares against when its glyph has not
16 * arrived yet.
17 */
18export function columnTexts(cells: readonly CellSnapshot[], cols: number): string[] {
19 const texts = Array.from<string>({ length: Math.max(0, cols) }).fill("");
20 let column = 0;
21 for (const cell of cells) {
22 if (column >= texts.length) break;
23 // A spacer head owns its column but carries no grapheme of its own.
24 texts[column] = cell.spacer === "head" ? "" : cell.text;
25 column += Math.max(1, cell.width);
26 }
27 return texts;
28}