Public: anyone can read this; the crew can change it.

A test pins the terminal's aligned columns: `drawRows` lines up, drops and never shrinks below `min` #6773

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

scout/forge:scout/6752-a-test-pins-the-terminal-s-aligned-colum → main 2 commits fork 1 thread · 1 unresolved

  • Merged. scout/6752-a-test-pins-the-terminal-s-aligned-colum was merged into main as 65a4adf.

Review

Sign in to review this change.
1 file changed +102 −0
test/tui-rows.test.ts added +102
@@ -0,0 +1,102 @@
1 import { describe, expect, test } from "bun:test";
2 import { Screen } from "../src/tui/term/screen.ts";
3 import { BOLD } from "../src/tui/term/style.ts";
4 import { ListState } from "../src/tui/screens/common.ts";
5 import { theme } from "../src/tui/ui/theme.ts";
6 import { cell, drawRows, type Column } from "../src/tui/local/rows.ts";
7
8 const c = theme("dark").c;
9
10 function draw(
11 w: number,
12 columns: readonly Column[],
13 rows: string[][],
14 index = 0,
15 ): Screen {
16 const s = new Screen(w, rows.length);
17 const list = new ListState();
18 list.index = index;
19 drawRows(
20 s,
21 { x: 0, y: 0, w, h: rows.length },
22 c,
23 list,
24 columns,
25 rows.map((r) => r.map((t) => cell(t))),
26 );
27 return s;
28 }
29
30 const line = (s: Screen, y: number): string =>
31 Array.from({ length: s.cols }, (_, x) => s.textAt(x, y)).join("");
32
33 describe("drawRows", () => {
34 test("columns start at the same x, two spaces apart, none before the first", () => {
35 const s = draw(40, [{}, {}, {}], [
36 ["alpha", "one", "x"],
37 ["be", "three", "yy"],
38 ["gamma-ray", "t", "zzz"],
39 ]);
40 // gutter of two, then widths 9, 5, 3 with two spaces between
41 const starts = [2, 2 + 9 + 2, 2 + 9 + 2 + 5 + 2];
42 const expected = [
43 ["alpha", "one", "x"],
44 ["be", "three", "yy"],
45 ["gamma-ray", "t", "zzz"],
46 ];
47 expected.forEach((fields, y) => {
48 const text = line(s, y);
49 fields.forEach((f, j) => {
50 expect(text.slice(starts[j]!, starts[j]! + f.length)).toBe(f);
51 });
52 expect(text.slice(0, 2)).toBe(y === 0 ? "▸ " : " ");
53 // exactly two spaces between the columns, even after the widest cell
54 expect(text.slice(2 + 9, 2 + 9 + 2)).toBe(" ");
55 });
56 });
57
58 test("a narrow pane drops columns in `drop` order, lowest first", () => {
59 const columns: Column[] = [{}, { drop: 2 }, { drop: 1 }];
60 const rows = [["name-here", "second", "third!"]];
61 // natural: 9 + 2 + 6 + 2 + 6 = 25 > 22; losing rank 1 leaves 17 <= 22
62 const some = line(draw(25, columns, rows), 0);
63 expect(some).toContain("name-here second");
64 expect(some).not.toContain("third!");
65 // at 15 the pane (12 after gutter and scrollbar) loses rank 2 as well
66 const few = line(draw(15, columns, rows), 0);
67 expect(few).toContain("name-here");
68 expect(few).not.toContain("second");
69 expect(few).not.toContain("third!");
70 // wide enough and nothing is dropped
71 expect(line(draw(40, columns, rows), 0)).toContain("third!");
72 });
73
74 test("a column never draws narrower than its min", () => {
75 const columns: Column[] = [{ min: 4 }, { min: 5 }];
76 const rows = [["abcdefghij", "klmnopqr"]];
77 // 10 leaves 7 cells for minimums that need 4+2+5: they hold, and the
outdated

Here the space left is 14 − 1 − 2 = 11 = 4 + 2 + 5, so it is an exact fit, not narrower than the minimums. With the min floor removed from fitColumns, the loop still lands on widths 4/5 and this test passes. Use a pane under 11 (e.g. draw(10, …)) so the assertions only hold if min actually stops the shrinking.

78 // second column still starts at 2+4+2 (clipped by the pane's edge)
79 const s = draw(10, columns, rows);
80 const text = line(s, 0);
81 expect(text.slice(6, 8)).toBe(" ");
82 expect(text[8]).toBe("k");
83 // the first column shows exactly 4 cells: three letters and an ellipsis
84 expect(text.slice(2, 5)).toBe("abc");
85 expect(text[5]).toBe("…");
86 });
87
88 test("the selected row's emphasis column is bold, others are not", () => {
89 const columns: Column[] = [{}, { emphasis: true }];
90 const rows = [
91 ["aa", "bb"],
92 ["cc", "dd"],
93 ];
94 const s = draw(20, columns, rows, 0);
95 const bold = (x: number, y: number): boolean =>
96 (s.styleAt(x, y).attr & BOLD) !== 0;
97 expect(bold(2, 0)).toBe(false); // plain column, selected row
98 expect(bold(6, 0)).toBe(true); // emphasis column, selected row
99 expect(bold(2, 1)).toBe(false);
100 expect(bold(6, 1)).toBe(false); // emphasis column, other row
101 });
102 });

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs