@vincemakes/kiso-tui-cells 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/render.d.ts CHANGED
@@ -34,7 +34,25 @@ export interface Palette {
34
34
  readonly dim: string;
35
35
  readonly red: string;
36
36
  readonly green: string;
37
+ /** TUI2-R2 ①: the third functional exception, finally spelled. The
38
+ * mono-discipline ruling above names "green ✓, yellow warn and red
39
+ * error" as the ONLY functional colours; warn had no entry because
40
+ * nothing had needed it yet. The uncertain badge needs exactly it —
41
+ * a state that is neither success nor failure but a question
42
+ * addressed to the human. This is the ruling's own set gaining its
43
+ * missing member, not a fourth colour. */
44
+ readonly warn: string;
37
45
  readonly code: string;
46
+ /** TUI2-MD (MD-1, the owner's circle) — the markdown round's ONE new
47
+ * member. `*italic*` needs a rendering, and under the mono discipline
48
+ * the answer cannot be a colour: SGR 3 is an ATTRIBUTE, it costs the
49
+ * alphabet nothing chromatic, and a terminal without italics simply
50
+ * draws the text — a harmless degradation rather than a lie.
51
+ * It ships with its own close (23) for the same reason `rv` does: an
52
+ * italic span inside a bold heading must be able to end WITHOUT the
53
+ * SGR-0 that would strand the heading's own style. */
54
+ readonly italic: string;
55
+ readonly italicEnd: string;
38
56
  readonly rv: string;
39
57
  readonly rvEnd: string;
40
58
  readonly reset: string;
package/dist/render.js CHANGED
@@ -6,8 +6,8 @@
6
6
  * dependencies (the tui-cells package has none).
7
7
  */
8
8
  import { charWidth, displayWidth } from "./width.js";
9
- export const COLOR_ON = { bold: "\x1b[1m", dim: "\x1b[2m", red: "\x1b[31m", green: "\x1b[32m", code: "\x1b[38;5;252m", rv: "\x1b[7m", rvEnd: "\x1b[27m", reset: "\x1b[0m" };
10
- export const COLOR_OFF = { bold: "", dim: "", red: "", green: "", code: "", rv: "", rvEnd: "", reset: "" };
9
+ export const COLOR_ON = { bold: "\x1b[1m", dim: "\x1b[2m", red: "\x1b[31m", green: "\x1b[32m", warn: "\x1b[33m", code: "\x1b[38;5;252m", italic: "\x1b[3m", italicEnd: "\x1b[23m", rv: "\x1b[7m", rvEnd: "\x1b[27m", reset: "\x1b[0m" };
10
+ export const COLOR_OFF = { bold: "", dim: "", red: "", green: "", warn: "", code: "", italic: "", italicEnd: "", rv: "", rvEnd: "", reset: "" };
11
11
  export function palette() {
12
12
  return process.env.NO_COLOR === undefined && process.stdout.isTTY ? COLOR_ON : COLOR_OFF;
13
13
  }
package/dist/strings.d.ts CHANGED
@@ -111,6 +111,10 @@ export interface KeyBinding {
111
111
  * then the completions.
112
112
  */
113
113
  export declare const KEY_BINDINGS: readonly KeyBinding[];
114
+ /** A tool's name as the SCREEN says it. Display-only: the raw name stays
115
+ * on the cell, and dispatch, the mode gate, the policy keys, the /last
116
+ * RAW block and every model-facing byte keep reading that. */
117
+ export declare function displayVerb(name: string): string;
114
118
  /** The panel keys, which belong to a panel rather than the composer —
115
119
  * one dim line rather than four table rows, because they apply only
116
120
  * while a panel is up. */
package/dist/strings.js CHANGED
@@ -155,6 +155,40 @@ export const KEY_BINDINGS = [
155
155
  { keys: "tab", what: "complete (menu / @)" },
156
156
  { keys: "?", what: "this sheet" },
157
157
  ];
158
+ /**
159
+ * TUI2-R2pre ④ — THE display-verb table (the integrator's ruling).
160
+ *
161
+ * The screen names the ACT; the tool table names the CALL. Two
162
+ * audiences, two vocabularies, and only the human's one lives here: the
163
+ * API names DO NOT change, because the model-request surface is frozen
164
+ * rent and every byte of it is paid for on every turn. The
165
+ * rename-the-tools path is REJECTED by ruling.
166
+ *
167
+ * One table, for the same reason KEY_BINDINGS above is one table. The
168
+ * mapping used to exist three and a half times — a `.replace("_file",
169
+ * "")` in components.ts, another in render.ts, two more in the
170
+ * compositor, and a private three-tool table for the rollup's expanded
171
+ * list — and the drift was visible on a single screen: a card head
172
+ * reading `read` directly above one reading `list_dir`.
173
+ *
174
+ * An unmapped tool (an extension's, an MCP server's) renders its own
175
+ * name. Inventing a verb for a tool this package has never heard of
176
+ * would be a worse lie than printing what the model actually calls.
177
+ */
178
+ const DISPLAY_VERB = {
179
+ read_file: "read",
180
+ list_dir: "list",
181
+ search_text: "search",
182
+ write_file: "write",
183
+ edit_file: "edit",
184
+ shell: "shell",
185
+ };
186
+ /** A tool's name as the SCREEN says it. Display-only: the raw name stays
187
+ * on the cell, and dispatch, the mode gate, the policy keys, the /last
188
+ * RAW block and every model-facing byte keep reading that. */
189
+ export function displayVerb(name) {
190
+ return DISPLAY_VERB[name] ?? name;
191
+ }
158
192
  /** The panel keys, which belong to a panel rather than the composer —
159
193
  * one dim line rather than four table rows, because they apply only
160
194
  * while a panel is up. */
package/dist/width.d.ts CHANGED
@@ -1,18 +1,42 @@
1
1
  /**
2
2
  * The display-width primitives — the SINGLE width authority (TUI v5
3
- * #16e: "charWidth is the width authority"). The eastAsianWidth table
4
- * is a ~40-line subset (CJK ideographs/kana/hangul/fullwidth/common
5
- * wide symbols = 2, everything else = 1 — the box-drawing/brick glyphs
6
- * █▀▄▞▸ are narrow). Known limitation, documented in the README: emoji
7
- * ZWJ clusters are not guaranteed perfect — each code point counts as
8
- * its width. Zero dependencies (importable from any module).
3
+ * #16e: "charWidth is the width authority"). The table covers the East
4
+ * Asian Wide/Fullwidth ranges and Emoji_Presentation=Yes; everything
5
+ * else is one column, the box-drawing/brick glyphs █▀▄▞▸ and the text-
6
+ * presentation marks ✓ ✗ ⚠ ⏸ included.
7
+ *
8
+ * This is the compositor's FLOOR, not a cosmetic detail: a glyph scored
9
+ * one column that a terminal draws in two makes a line whose measured
10
+ * width is <= W really need W+1, the terminal soft-wraps the tail onto
11
+ * the row below, and the live region silently eats a row it never
12
+ * budgeted (TUI2-R2pre ① — the composer clobber).
13
+ *
14
+ * Known limitation, documented in the README: emoji ZWJ clusters and
15
+ * variation-selector sequences are not guaranteed perfect — each code
16
+ * point counts as its own width (U+26A0 + FE0F sums to 2, which is what
17
+ * a terminal draws, but that is arithmetic luck, not a model).
18
+ * Zero dependencies (importable from any module).
9
19
  */
10
20
  /** A code point's display width: 2 for the wide ranges, 1 otherwise. */
11
21
  export declare function charWidth(cp: number): number;
22
+ /** TUI2-MD ③ — may a row break immediately before/after this code
23
+ * point? True for the CJK scripts (they break between any two
24
+ * characters), false for everything else INCLUDING the wide
25
+ * pictographs. The wrapper asks this; the width table answers it. */
26
+ export declare function breakable(cp: number): boolean;
12
27
  /** Display width of a code-point array (cursor math, scrolling). */
13
28
  export declare function widthOf(chars: readonly number[]): number;
14
29
  /** Display width of a string. */
15
30
  export declare function displayWidth(text: string): number;
31
+ /** The visible width of a RENDERED line — the same table, asked with
32
+ * the SGR/CSI sequences skipped. The compositor's invariant ① measures
33
+ * with this, so every producer of a screen row must measure with it
34
+ * too. TUI2-MD ⑤: moved here verbatim from components.ts, where it had
35
+ * lived since the extraction. The markdown renderer needs it and
36
+ * components.ts needs the markdown renderer — and a width question
37
+ * belongs to the width authority anyway. components.ts re-exports it,
38
+ * so every existing importer and the barrel are untouched. */
39
+ export declare function visibleWidth(line: string): number;
16
40
  /** A LEAD's display width — the prompt / the panel's phase lead,
17
41
  * ANSI-stripped. W23: the ONE width authority shared by the editor
18
42
  * (selfRender, #reflow), the compositor's #inputRow, and editCol — a
package/dist/width.js CHANGED
@@ -1,47 +1,141 @@
1
1
  /**
2
2
  * The display-width primitives — the SINGLE width authority (TUI v5
3
- * #16e: "charWidth is the width authority"). The eastAsianWidth table
4
- * is a ~40-line subset (CJK ideographs/kana/hangul/fullwidth/common
5
- * wide symbols = 2, everything else = 1 — the box-drawing/brick glyphs
6
- * █▀▄▞▸ are narrow). Known limitation, documented in the README: emoji
7
- * ZWJ clusters are not guaranteed perfect — each code point counts as
8
- * its width. Zero dependencies (importable from any module).
3
+ * #16e: "charWidth is the width authority"). The table covers the East
4
+ * Asian Wide/Fullwidth ranges and Emoji_Presentation=Yes; everything
5
+ * else is one column, the box-drawing/brick glyphs █▀▄▞▸ and the text-
6
+ * presentation marks ✓ ✗ ⚠ ⏸ included.
7
+ *
8
+ * This is the compositor's FLOOR, not a cosmetic detail: a glyph scored
9
+ * one column that a terminal draws in two makes a line whose measured
10
+ * width is <= W really need W+1, the terminal soft-wraps the tail onto
11
+ * the row below, and the live region silently eats a row it never
12
+ * budgeted (TUI2-R2pre ① — the composer clobber).
13
+ *
14
+ * Known limitation, documented in the README: emoji ZWJ clusters and
15
+ * variation-selector sequences are not guaranteed perfect — each code
16
+ * point counts as its own width (U+26A0 + FE0F sums to 2, which is what
17
+ * a terminal draws, but that is arithmetic luck, not a model).
18
+ * Zero dependencies (importable from any module).
9
19
  */
10
- /** A code point's display width: 2 for the wide ranges, 1 otherwise. */
11
- export function charWidth(cp) {
20
+ /** TUI2-R2pre ① — the Emoji_Presentation=Yes code points inside
21
+ * U+2000..U+2BFF. The rest of that span is TEXT presentation and stays
22
+ * one column: ✓ ✗ ⚠ ⏸ ▞ ▸ and the box-drawing rails are all narrow, and
23
+ * widening any of them would move every card head on the screen. Listed
24
+ * as ranges because that is what the property is — the singles are
25
+ * singles in Unicode too. */
26
+ const EMOJI_PRESENTATION = [
27
+ [0x231a, 0x231b],
28
+ [0x23e9, 0x23ec],
29
+ [0x23f0, 0x23f0],
30
+ [0x23f3, 0x23f3],
31
+ [0x25fd, 0x25fe],
32
+ [0x2614, 0x2615],
33
+ [0x2648, 0x2653],
34
+ [0x267f, 0x267f],
35
+ [0x2693, 0x2693],
36
+ [0x26a1, 0x26a1],
37
+ [0x26aa, 0x26ab],
38
+ [0x26bd, 0x26be],
39
+ [0x26c4, 0x26c5],
40
+ [0x26ce, 0x26ce],
41
+ [0x26d4, 0x26d4],
42
+ [0x26ea, 0x26ea],
43
+ [0x26f2, 0x26f3],
44
+ [0x26f5, 0x26f5],
45
+ [0x26fa, 0x26fa],
46
+ [0x26fd, 0x26fd],
47
+ [0x2705, 0x2705],
48
+ [0x270a, 0x270b],
49
+ [0x2728, 0x2728],
50
+ [0x274c, 0x274c],
51
+ [0x274e, 0x274e],
52
+ [0x2753, 0x2755],
53
+ [0x2757, 0x2757],
54
+ [0x2795, 0x2797],
55
+ [0x27b0, 0x27b0],
56
+ [0x27bf, 0x27bf],
57
+ [0x2b1b, 0x2b1c],
58
+ [0x2b50, 0x2b50],
59
+ [0x2b55, 0x2b55],
60
+ ];
61
+ /** TUI2-MD ③ — the CJK half of the wide table, split out so the SAME
62
+ * ranges answer a SECOND question: may a line break here? The width
63
+ * authority stays one table; the break class is a view of it, never a
64
+ * fork (a second copy would drift, and a drifted width table is the
65
+ * composer clobber all over again).
66
+ *
67
+ * These scripts break between any two characters, which is why a
68
+ * space-free CJK run must not be treated as one unbreakable word: a
69
+ * whitespace-only wrapper cannot place it at all. */
70
+ function cjkWide(cp) {
12
71
  if (cp >= 0x1100 && cp <= 0x115f)
13
- return 2; // hangul jamo
72
+ return true; // hangul jamo
14
73
  if (cp >= 0x2e80 && cp <= 0x303e)
15
- return 2; // radicals .. CJK punctuation
74
+ return true; // radicals .. CJK punctuation
16
75
  if (cp >= 0x3041 && cp <= 0x33ff)
17
- return 2; // kana, CJK compat
76
+ return true; // kana, CJK compat
18
77
  if (cp >= 0x3400 && cp <= 0x4dbf)
19
- return 2; // CJK ext A
78
+ return true; // CJK ext A
20
79
  if (cp >= 0x4e00 && cp <= 0x9fff)
21
- return 2; // CJK unified
80
+ return true; // CJK unified
22
81
  if (cp >= 0xa000 && cp <= 0xa4cf)
23
- return 2; // yi
82
+ return true; // yi
24
83
  if (cp >= 0xa960 && cp <= 0xa97f)
25
- return 2; // hangul jamo ext
84
+ return true; // hangul jamo ext
26
85
  if (cp >= 0xac00 && cp <= 0xd7a3)
27
- return 2; // hangul syllables
86
+ return true; // hangul syllables
28
87
  if (cp >= 0xf900 && cp <= 0xfaff)
29
- return 2; // CJK compat ideographs
88
+ return true; // CJK compat ideographs
30
89
  if (cp >= 0xfe10 && cp <= 0xfe19)
31
- return 2; // vertical forms
90
+ return true; // vertical forms
32
91
  if (cp >= 0xfe30 && cp <= 0xfe6f)
33
- return 2; // CJK compat forms
92
+ return true; // CJK compat forms
34
93
  if (cp >= 0xff00 && cp <= 0xff60)
35
- return 2; // fullwidth forms
94
+ return true; // fullwidth forms
36
95
  if (cp >= 0xffe0 && cp <= 0xffe6)
37
- return 2; // fullwidth signs
96
+ return true; // fullwidth signs
97
+ return cp >= 0x20000 && cp <= 0x3fffd; // CJK ext B..G
98
+ }
99
+ /** The PICTOGRAPHIC half: wide, and deliberately NOT breakable — a
100
+ * ZWJ/variation sequence must survive a line break whole. */
101
+ function emojiWide(cp) {
102
+ // TUI2-R1.5 shipped only two of the pictographic ranges; the holes
103
+ // (transport, mahjong/cards, enclosed, colored shapes, the extended
104
+ // block) were scored ONE column while every terminal draws them in
105
+ // two — the composer clobber of the owner's field report (①).
106
+ if (cp === 0x1f004 || cp === 0x1f0cf)
107
+ return true; // mahjong red dragon, joker
108
+ if (cp >= 0x1f18e && cp <= 0x1f19a)
109
+ return true; // enclosed alphanumerics
110
+ if (cp >= 0x1f200 && cp <= 0x1f251)
111
+ return true; // enclosed ideographic
38
112
  if (cp >= 0x1f300 && cp <= 0x1f64f)
39
- return 2; // emoji (misc + emoticons)
113
+ return true; // emoji (misc + emoticons)
114
+ if (cp >= 0x1f680 && cp <= 0x1f6ff)
115
+ return true; // transport + map
116
+ if (cp >= 0x1f7e0 && cp <= 0x1f7eb)
117
+ return true; // colored circles + squares
40
118
  if (cp >= 0x1f900 && cp <= 0x1f9ff)
41
- return 2; // supplemental emoji
42
- if (cp >= 0x20000 && cp <= 0x3fffd)
43
- return 2; // CJK ext B..G
44
- return 1;
119
+ return true; // supplemental emoji
120
+ if (cp >= 0x1fa70 && cp <= 0x1faff)
121
+ return true; // symbols + pictographs ext-A
122
+ if (cp >= 0x231a && cp <= 0x2b55) {
123
+ for (const [lo, hi] of EMOJI_PRESENTATION)
124
+ if (cp >= lo && cp <= hi)
125
+ return true;
126
+ }
127
+ return false;
128
+ }
129
+ /** A code point's display width: 2 for the wide ranges, 1 otherwise. */
130
+ export function charWidth(cp) {
131
+ return cjkWide(cp) || emojiWide(cp) ? 2 : 1;
132
+ }
133
+ /** TUI2-MD ③ — may a row break immediately before/after this code
134
+ * point? True for the CJK scripts (they break between any two
135
+ * characters), false for everything else INCLUDING the wide
136
+ * pictographs. The wrapper asks this; the width table answers it. */
137
+ export function breakable(cp) {
138
+ return cjkWide(cp);
45
139
  }
46
140
  /** Display width of a code-point array (cursor math, scrolling). */
47
141
  export function widthOf(chars) {
@@ -57,6 +151,31 @@ export function displayWidth(text) {
57
151
  w += charWidth(ch.codePointAt(0));
58
152
  return w;
59
153
  }
154
+ /** The visible width of a RENDERED line — the same table, asked with
155
+ * the SGR/CSI sequences skipped. The compositor's invariant ① measures
156
+ * with this, so every producer of a screen row must measure with it
157
+ * too. TUI2-MD ⑤: moved here verbatim from components.ts, where it had
158
+ * lived since the extraction. The markdown renderer needs it and
159
+ * components.ts needs the markdown renderer — and a width question
160
+ * belongs to the width authority anyway. components.ts re-exports it,
161
+ * so every existing importer and the barrel are untouched. */
162
+ export function visibleWidth(line) {
163
+ let w = 0;
164
+ for (let i = 0; i < line.length;) {
165
+ if (line[i] === "\x1b") {
166
+ const m = /^\x1b\[[0-9;?]*[A-Za-z]/.exec(line.slice(i));
167
+ if (m !== null) {
168
+ i += m[0].length;
169
+ continue;
170
+ }
171
+ i += 1;
172
+ continue;
173
+ }
174
+ w += displayWidth(line[i]);
175
+ i += 1;
176
+ }
177
+ return w;
178
+ }
60
179
  /** A LEAD's display width — the prompt / the panel's phase lead,
61
180
  * ANSI-stripped. W23: the ONE width authority shared by the editor
62
181
  * (selfRender, #reflow), the compositor's #inputRow, and editCol — a
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vincemakes/kiso-tui-cells",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "description": "kiso tui-cells — the components cell renderer (components, diff, width, the render slice). Zero runtime dependencies: input is data, output is bytes.",
5
5
  "type": "module",
6
6
  "license": "MIT",