@promptctl/rich-js 0.16.0 → 0.18.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.
Files changed (206) hide show
  1. package/README.md +14 -27
  2. package/package.json +7 -3
  3. package/dist/core/box.d.ts +0 -144
  4. package/dist/core/box.js +0 -391
  5. package/dist/core/cells.d.ts +0 -148
  6. package/dist/core/cells.js +0 -266
  7. package/dist/core/color.d.ts +0 -229
  8. package/dist/core/color.js +0 -992
  9. package/dist/core/console.d.ts +0 -142
  10. package/dist/core/console.js +0 -477
  11. package/dist/core/emoji.d.ts +0 -24
  12. package/dist/core/emoji.js +0 -391
  13. package/dist/core/export-html.d.ts +0 -24
  14. package/dist/core/export-html.js +0 -106
  15. package/dist/core/export-lines.d.ts +0 -121
  16. package/dist/core/export-lines.js +0 -141
  17. package/dist/core/highlighter.d.ts +0 -33
  18. package/dist/core/highlighter.js +0 -124
  19. package/dist/core/json.d.ts +0 -27
  20. package/dist/core/json.js +0 -53
  21. package/dist/core/markup.d.ts +0 -97
  22. package/dist/core/markup.js +0 -619
  23. package/dist/core/measure.d.ts +0 -27
  24. package/dist/core/measure.js +0 -61
  25. package/dist/core/oklch.d.ts +0 -161
  26. package/dist/core/oklch.js +0 -312
  27. package/dist/core/osc8.d.ts +0 -68
  28. package/dist/core/osc8.js +0 -90
  29. package/dist/core/pretty.d.ts +0 -141
  30. package/dist/core/pretty.js +0 -472
  31. package/dist/core/protocol.d.ts +0 -137
  32. package/dist/core/protocol.js +0 -101
  33. package/dist/core/render.d.ts +0 -69
  34. package/dist/core/render.js +0 -140
  35. package/dist/core/segment.d.ts +0 -142
  36. package/dist/core/segment.js +0 -433
  37. package/dist/core/spinnerData.d.ts +0 -10
  38. package/dist/core/spinnerData.js +0 -115
  39. package/dist/core/strip.d.ts +0 -139
  40. package/dist/core/strip.js +0 -302
  41. package/dist/core/style.d.ts +0 -149
  42. package/dist/core/style.js +0 -741
  43. package/dist/core/subscription.d.ts +0 -12
  44. package/dist/core/subscription.js +0 -12
  45. package/dist/core/text.d.ts +0 -255
  46. package/dist/core/text.js +0 -990
  47. package/dist/core/wrap.d.ts +0 -41
  48. package/dist/core/wrap.js +0 -127
  49. package/dist/host/host-stream.d.ts +0 -30
  50. package/dist/host/host-stream.js +0 -35
  51. package/dist/host/index.d.ts +0 -3
  52. package/dist/host/index.js +0 -2
  53. package/dist/host/terminal-host.d.ts +0 -143
  54. package/dist/host/terminal-host.js +0 -132
  55. package/dist/index.d.ts +0 -87
  56. package/dist/index.js +0 -104
  57. package/dist/node/prompt.d.ts +0 -21
  58. package/dist/node/prompt.js +0 -30
  59. package/dist/node/save.d.ts +0 -17
  60. package/dist/node/save.js +0 -21
  61. package/dist/node/terminal-host.d.ts +0 -84
  62. package/dist/node/terminal-host.js +0 -160
  63. package/dist/node/traceback.d.ts +0 -27
  64. package/dist/node/traceback.js +0 -112
  65. package/dist/renderables/align.d.ts +0 -16
  66. package/dist/renderables/align.js +0 -46
  67. package/dist/renderables/columns.d.ts +0 -61
  68. package/dist/renderables/columns.js +0 -168
  69. package/dist/renderables/constrain.d.ts +0 -15
  70. package/dist/renderables/constrain.js +0 -37
  71. package/dist/renderables/flexStrip.d.ts +0 -41
  72. package/dist/renderables/flexStrip.js +0 -200
  73. package/dist/renderables/group.d.ts +0 -11
  74. package/dist/renderables/group.js +0 -15
  75. package/dist/renderables/layout.d.ts +0 -92
  76. package/dist/renderables/layout.js +0 -315
  77. package/dist/renderables/live.d.ts +0 -47
  78. package/dist/renderables/live.js +0 -131
  79. package/dist/renderables/markdown.d.ts +0 -24
  80. package/dist/renderables/markdown.js +0 -182
  81. package/dist/renderables/padding.d.ts +0 -38
  82. package/dist/renderables/padding.js +0 -140
  83. package/dist/renderables/panel.d.ts +0 -116
  84. package/dist/renderables/panel.js +0 -322
  85. package/dist/renderables/progress.d.ts +0 -90
  86. package/dist/renderables/progress.js +0 -241
  87. package/dist/renderables/progressBar.d.ts +0 -31
  88. package/dist/renderables/progressBar.js +0 -52
  89. package/dist/renderables/prompt.d.ts +0 -49
  90. package/dist/renderables/prompt.js +0 -125
  91. package/dist/renderables/rule.d.ts +0 -24
  92. package/dist/renderables/rule.js +0 -90
  93. package/dist/renderables/spinner.d.ts +0 -29
  94. package/dist/renderables/spinner.js +0 -64
  95. package/dist/renderables/status.d.ts +0 -23
  96. package/dist/renderables/status.js +0 -60
  97. package/dist/renderables/syntax.d.ts +0 -35
  98. package/dist/renderables/syntax.js +0 -114
  99. package/dist/renderables/table.d.ts +0 -182
  100. package/dist/renderables/table.js +0 -697
  101. package/dist/renderables/traceback.d.ts +0 -31
  102. package/dist/renderables/traceback.js +0 -109
  103. package/dist/renderables/tree.d.ts +0 -54
  104. package/dist/renderables/tree.js +0 -159
  105. package/dist/template-bindings/color-funcs.d.ts +0 -87
  106. package/dist/template-bindings/color-funcs.js +0 -219
  107. package/dist/template-bindings/helpers.d.ts +0 -24
  108. package/dist/template-bindings/helpers.js +0 -48
  109. package/dist/template-bindings/index.d.ts +0 -107
  110. package/dist/template-bindings/index.js +0 -144
  111. package/dist/template-bindings/palette-funcs.d.ts +0 -94
  112. package/dist/template-bindings/palette-funcs.js +0 -151
  113. package/dist/template-bindings/style-funcs.d.ts +0 -28
  114. package/dist/template-bindings/style-funcs.js +0 -151
  115. package/dist/themes/buildPalette.d.ts +0 -36
  116. package/dist/themes/buildPalette.js +0 -56
  117. package/dist/themes/colorMath.d.ts +0 -82
  118. package/dist/themes/colorMath.js +0 -254
  119. package/dist/themes/colorRef.d.ts +0 -51
  120. package/dist/themes/colorRef.js +0 -96
  121. package/dist/themes/data/atom-one-dark.d.ts +0 -3
  122. package/dist/themes/data/atom-one-dark.js +0 -158
  123. package/dist/themes/data/atom-one-light.d.ts +0 -3
  124. package/dist/themes/data/atom-one-light.js +0 -158
  125. package/dist/themes/data/catppuccin-frappe.d.ts +0 -3
  126. package/dist/themes/data/catppuccin-frappe.js +0 -158
  127. package/dist/themes/data/catppuccin-latte.d.ts +0 -3
  128. package/dist/themes/data/catppuccin-latte.js +0 -158
  129. package/dist/themes/data/catppuccin-macchiato.d.ts +0 -3
  130. package/dist/themes/data/catppuccin-macchiato.js +0 -158
  131. package/dist/themes/data/catppuccin-mocha.d.ts +0 -3
  132. package/dist/themes/data/catppuccin-mocha.js +0 -158
  133. package/dist/themes/data/cyberpunk.d.ts +0 -17
  134. package/dist/themes/data/cyberpunk.js +0 -191
  135. package/dist/themes/data/default.d.ts +0 -3
  136. package/dist/themes/data/default.js +0 -158
  137. package/dist/themes/data/dracula.d.ts +0 -3
  138. package/dist/themes/data/dracula.js +0 -158
  139. package/dist/themes/data/flexoki.d.ts +0 -3
  140. package/dist/themes/data/flexoki.js +0 -158
  141. package/dist/themes/data/gruvbox.d.ts +0 -3
  142. package/dist/themes/data/gruvbox.js +0 -158
  143. package/dist/themes/data/index.d.ts +0 -35
  144. package/dist/themes/data/index.js +0 -64
  145. package/dist/themes/data/monokai.d.ts +0 -3
  146. package/dist/themes/data/monokai.js +0 -158
  147. package/dist/themes/data/nord.d.ts +0 -3
  148. package/dist/themes/data/nord.js +0 -158
  149. package/dist/themes/data/rose-pine-dawn.d.ts +0 -3
  150. package/dist/themes/data/rose-pine-dawn.js +0 -158
  151. package/dist/themes/data/rose-pine-moon.d.ts +0 -3
  152. package/dist/themes/data/rose-pine-moon.js +0 -158
  153. package/dist/themes/data/rose-pine.d.ts +0 -3
  154. package/dist/themes/data/rose-pine.js +0 -158
  155. package/dist/themes/data/solarized-dark.d.ts +0 -3
  156. package/dist/themes/data/solarized-dark.js +0 -158
  157. package/dist/themes/data/solarized-light.d.ts +0 -3
  158. package/dist/themes/data/solarized-light.js +0 -158
  159. package/dist/themes/data/svg-export.d.ts +0 -3
  160. package/dist/themes/data/svg-export.js +0 -158
  161. package/dist/themes/data/textual-ansi.d.ts +0 -3
  162. package/dist/themes/data/textual-ansi.js +0 -158
  163. package/dist/themes/data/textual-dark.d.ts +0 -3
  164. package/dist/themes/data/textual-dark.js +0 -158
  165. package/dist/themes/data/textual-light.d.ts +0 -3
  166. package/dist/themes/data/textual-light.js +0 -158
  167. package/dist/themes/data/tokyo-night.d.ts +0 -3
  168. package/dist/themes/data/tokyo-night.js +0 -158
  169. package/dist/themes/data/types.d.ts +0 -15
  170. package/dist/themes/data/types.js +0 -1
  171. package/dist/themes/palette.d.ts +0 -21
  172. package/dist/themes/palette.js +0 -28
  173. package/dist/themes/ramp.d.ts +0 -83
  174. package/dist/themes/ramp.js +0 -122
  175. package/dist/themes/registry.d.ts +0 -43
  176. package/dist/themes/registry.js +0 -82
  177. package/dist/themes/terminalThemes.d.ts +0 -54
  178. package/dist/themes/terminalThemes.js +0 -68
  179. package/dist/themes/transpose.d.ts +0 -87
  180. package/dist/themes/transpose.js +0 -138
  181. package/dist/widgets/button.d.ts +0 -49
  182. package/dist/widgets/button.js +0 -206
  183. package/dist/widgets/checkbox.d.ts +0 -41
  184. package/dist/widgets/checkbox.js +0 -155
  185. package/dist/widgets/dropdown.d.ts +0 -67
  186. package/dist/widgets/dropdown.js +0 -453
  187. package/dist/widgets/event-router.d.ts +0 -78
  188. package/dist/widgets/event-router.js +0 -622
  189. package/dist/widgets/focus-manager.d.ts +0 -26
  190. package/dist/widgets/focus-manager.js +0 -193
  191. package/dist/widgets/index.d.ts +0 -22
  192. package/dist/widgets/index.js +0 -15
  193. package/dist/widgets/screen.d.ts +0 -98
  194. package/dist/widgets/screen.js +0 -542
  195. package/dist/widgets/slider.d.ts +0 -57
  196. package/dist/widgets/slider.js +0 -270
  197. package/dist/widgets/static-item.d.ts +0 -40
  198. package/dist/widgets/static-item.js +0 -60
  199. package/dist/widgets/text-input.d.ts +0 -274
  200. package/dist/widgets/text-input.js +0 -1162
  201. package/dist/widgets/toggle.d.ts +0 -44
  202. package/dist/widgets/toggle.js +0 -179
  203. package/dist/widgets/types.d.ts +0 -108
  204. package/dist/widgets/types.js +0 -31
  205. package/dist/widgets/widget-base.d.ts +0 -42
  206. package/dist/widgets/widget-base.js +0 -173
@@ -1,41 +0,0 @@
1
- /**
2
- * Word wrapping: the offsets one logical line is cut at so its pieces fit a
3
- * cell budget.
4
- *
5
- * This is deliberately not in `cells.ts` next door. That module answers
6
- * geometry — how wide is this, where does cell column N fall — and knows
7
- * nothing about language. This one answers where a line may *break*, which is
8
- * a fact about words, and the only thing it borrows from geometry is how to
9
- * measure one.
10
- *
11
- * It returns offsets rather than pieces because the caller holds styled
12
- * `Segment[]`, not a string: cutting the text here would drop every span
13
- * attached to it. Offsets are the one representation both sides can act on —
14
- * `Segment.divide` cuts the styled line at exactly the places this function
15
- * found in the plain one.
16
- *
17
- * Wrapping is the *first* step, and overflow is the last resort applied to a
18
- * line still too wide once wrapping is done. That order is the whole reason a
19
- * long sentence in a table cell grows the row while an unbreakable word in the
20
- * same cell still ellipsizes.
21
- */
22
- import { type CellCol } from "./cells.js";
23
- /**
24
- * The cell offsets `text` should be cut at to wrap it into lines of at most
25
- * `width` cells, for `Segment.divide` to apply to the styled line.
26
- *
27
- * `fold` decides what happens to a word that fits on no line at all: folded,
28
- * it is chopped across as many lines as it needs; unfolded, it is left whole
29
- * on its own line for the caller's overflow method to cut. Only the `fold`
30
- * overflow method folds — `crop` and `ellipsis` want the word intact so they
31
- * can truncate it, which is what makes an unbreakable word ellipsize while the
32
- * sentence around it merely wraps.
33
- *
34
- * Requires `width >= 1`. A zero-cell canvas gets no cuts, because "no cut
35
- * fits" and "no cell fits" are different facts and only one of them is a list
36
- * of offsets — the caller answers the second one by cropping the single
37
- * uncut piece to nothing, which is what every overflow method does there.
38
- */
39
- export declare function divideLine(text: string, width: CellCol, options: {
40
- fold: boolean;
41
- }): CellCol[];
package/dist/core/wrap.js DELETED
@@ -1,127 +0,0 @@
1
- /**
2
- * Word wrapping: the offsets one logical line is cut at so its pieces fit a
3
- * cell budget.
4
- *
5
- * This is deliberately not in `cells.ts` next door. That module answers
6
- * geometry — how wide is this, where does cell column N fall — and knows
7
- * nothing about language. This one answers where a line may *break*, which is
8
- * a fact about words, and the only thing it borrows from geometry is how to
9
- * measure one.
10
- *
11
- * It returns offsets rather than pieces because the caller holds styled
12
- * `Segment[]`, not a string: cutting the text here would drop every span
13
- * attached to it. Offsets are the one representation both sides can act on —
14
- * `Segment.divide` cuts the styled line at exactly the places this function
15
- * found in the plain one.
16
- *
17
- * Wrapping is the *first* step, and overflow is the last resort applied to a
18
- * line still too wide once wrapping is done. That order is the whole reason a
19
- * long sentence in a table cell grows the row while an unbreakable word in the
20
- * same cell still ellipsizes.
21
- */
22
- import { cellLen, chopCells, asCellCol } from "./cells.js";
23
- /**
24
- * Each word of `text` in order, where a "word" carries its own trailing
25
- * whitespace — the run of spaces that follows it belongs to it, because that
26
- * is the whitespace a break at the *next* word leaves hanging past the edge.
27
- *
28
- * The matches tile the text: each begins exactly where the last ended, so a
29
- * caller can track absolute offsets by accumulating widths alone. Text with no
30
- * non-whitespace character yields nothing, which is the honest answer — there
31
- * is nowhere to break.
32
- */
33
- function* words(text) {
34
- // Constructed per call rather than hoisted: a sticky regex carries its
35
- // `lastIndex` as mutable state, and a shared one would corrupt any two
36
- // interleaved walks. [LAW:no-shared-mutable-globals]
37
- const re = /\s*\S+\s*/y;
38
- for (let match = re.exec(text); match !== null; match = re.exec(text)) {
39
- yield match[0];
40
- }
41
- }
42
- /**
43
- * A word chopped into pieces of at most `width` cells, as the reference chops
44
- * it.
45
- *
46
- * `chopCells` next door and Rich's `chop_cells` disagree in exactly one place.
47
- * Rich opens a new line for any glyph that does not fit and emits whatever line
48
- * it was already on, so a word beginning with a glyph wider than the entire
49
- * canvas folds with an empty piece in front of it — and that piece reaches the
50
- * output as a blank line. `chopCells` force-takes the glyph instead and never
51
- * returns an empty piece.
52
- *
53
- * Restoring the blank is what keeps `test/core/text-wrap.golden.txt`
54
- * regenerable from the reference. A fixture is only an oracle while the command
55
- * in its header reproduces it byte for byte; smoothing away one byte the
56
- * reference emits costs that, everywhere, to tidy a blank line reachable only
57
- * by folding a two-cell glyph onto a one-cell canvas.
58
- */
59
- function foldWord(word, width) {
60
- const pieces = chopCells(word, width);
61
- // `chopCells` overshoots the budget only when it force-takes one glyph, so an
62
- // over-wide first piece is exactly the case Rich opens a blank line for.
63
- return cellLen(pieces[0]) > width ? ["", ...pieces] : pieces;
64
- }
65
- /**
66
- * The cell offsets `text` should be cut at to wrap it into lines of at most
67
- * `width` cells, for `Segment.divide` to apply to the styled line.
68
- *
69
- * `fold` decides what happens to a word that fits on no line at all: folded,
70
- * it is chopped across as many lines as it needs; unfolded, it is left whole
71
- * on its own line for the caller's overflow method to cut. Only the `fold`
72
- * overflow method folds — `crop` and `ellipsis` want the word intact so they
73
- * can truncate it, which is what makes an unbreakable word ellipsize while the
74
- * sentence around it merely wraps.
75
- *
76
- * Requires `width >= 1`. A zero-cell canvas gets no cuts, because "no cut
77
- * fits" and "no cell fits" are different facts and only one of them is a list
78
- * of offsets — the caller answers the second one by cropping the single
79
- * uncut piece to nothing, which is what every overflow method does there.
80
- */
81
- export function divideLine(text, width, options) {
82
- if (width <= 0)
83
- return [];
84
- const cuts = [];
85
- // A cut at the start of the text is not a cut: it would open the line with
86
- // an empty piece. [LAW:single-enforcer] for that rule, so neither arm below
87
- // has to restate it.
88
- const cutAt = (cell) => {
89
- if (cell > 0)
90
- cuts.push(asCellCol(cell));
91
- };
92
- let used = 0; // cells already committed to the line being filled
93
- let wordStart = 0; // absolute cell offset where the current word begins
94
- for (const word of words(text)) {
95
- // Measured without its trailing whitespace: a word is allowed to end the
96
- // line with its spaces hanging past the edge, and the caller crops them.
97
- const wordWidth = cellLen(word.trimEnd());
98
- if (width - used >= wordWidth) {
99
- used += cellLen(word);
100
- }
101
- else if (options.fold && wordWidth > width) {
102
- // No line, however empty, can hold this word whole, and folding is
103
- // allowed — so it is chopped across as many lines as it needs. Unfolded,
104
- // it takes the arm below and is left whole for the overflow method.
105
- const pieces = foldWord(word, width);
106
- let pieceStart = wordStart;
107
- for (let index = 0; index < pieces.length; index += 1) {
108
- cutAt(pieceStart);
109
- const piece = pieces[index];
110
- // The last piece is what the *next* word finds already on the line;
111
- // the rest are whole lines of their own.
112
- if (index === pieces.length - 1)
113
- used = cellLen(piece);
114
- else
115
- pieceStart += cellLen(piece);
116
- }
117
- }
118
- else {
119
- // It does not fit here. Either it fits on a line of its own, or nothing
120
- // can hold it and the caller's overflow method will cut it there.
121
- cutAt(wordStart);
122
- used = cellLen(word);
123
- }
124
- wordStart += cellLen(word);
125
- }
126
- return cuts;
127
- }
@@ -1,30 +0,0 @@
1
- /**
2
- * hostStream — adapt a `TerminalHost` into the narrow Writable surface that
3
- * Console (and Live) actually exercise.
4
- *
5
- * [LAW:types-are-the-program] The return type matches Console's `ConsoleSink`
6
- * exactly: a single `.write(chunk)` method whose return value Console never
7
- * inspects (so the type leaves it as `unknown`; this implementation happens
8
- * to return `true` to mirror Node's stream contract, but callers may not
9
- * rely on that). Anything wider would lie about what this adapter
10
- * implements; anything narrower would force a cast at the call site.
11
- * Calling `.pipe()`, `.cork()`, `.on('error')`, etc. is a programming error
12
- * that TypeScript will reject at compile time.
13
- *
14
- * [LAW:locality-or-seam] Console + Live access their sink only via `.write()`
15
- * — verified in src/core/console.ts (one `_file.write` call) and
16
- * src/renderables/live.ts (every `this._console.file.write(...)` site). So
17
- * this narrow surface is the entire contract they need.
18
- */
19
- import type { ConsoleSink } from "../core/console.js";
20
- import type { TerminalHost } from "./terminal-host.js";
21
- /**
22
- * Wrap a `TerminalHost` so its output can be threaded into `Console` via the
23
- * existing `file:` option. The returned object implements `.write()` only —
24
- * exactly the surface Console + Live touch.
25
- *
26
- * Pair with `forceTerminal: true` on the Console — without it, Console treats
27
- * any non-undefined `file` option as non-TTY and disables color, which
28
- * defeats the point.
29
- */
30
- export declare function hostStream(host: TerminalHost): ConsoleSink;
@@ -1,35 +0,0 @@
1
- /**
2
- * hostStream — adapt a `TerminalHost` into the narrow Writable surface that
3
- * Console (and Live) actually exercise.
4
- *
5
- * [LAW:types-are-the-program] The return type matches Console's `ConsoleSink`
6
- * exactly: a single `.write(chunk)` method whose return value Console never
7
- * inspects (so the type leaves it as `unknown`; this implementation happens
8
- * to return `true` to mirror Node's stream contract, but callers may not
9
- * rely on that). Anything wider would lie about what this adapter
10
- * implements; anything narrower would force a cast at the call site.
11
- * Calling `.pipe()`, `.cork()`, `.on('error')`, etc. is a programming error
12
- * that TypeScript will reject at compile time.
13
- *
14
- * [LAW:locality-or-seam] Console + Live access their sink only via `.write()`
15
- * — verified in src/core/console.ts (one `_file.write` call) and
16
- * src/renderables/live.ts (every `this._console.file.write(...)` site). So
17
- * this narrow surface is the entire contract they need.
18
- */
19
- /**
20
- * Wrap a `TerminalHost` so its output can be threaded into `Console` via the
21
- * existing `file:` option. The returned object implements `.write()` only —
22
- * exactly the surface Console + Live touch.
23
- *
24
- * Pair with `forceTerminal: true` on the Console — without it, Console treats
25
- * any non-undefined `file` option as non-TTY and disables color, which
26
- * defeats the point.
27
- */
28
- export function hostStream(host) {
29
- return {
30
- write(chunk) {
31
- host.write(chunk);
32
- return true;
33
- },
34
- };
35
- }
@@ -1,3 +0,0 @@
1
- export { BrowserTerminalHost } from "./terminal-host.js";
2
- export type { TerminalHost, TerminalSize, DataHandler, ResizeHandler, BrowserTerminalHostOptions, XtermTerminal, XtermDisposable, XtermResizeEvent, } from "./terminal-host.js";
3
- export { hostStream } from "./host-stream.js";
@@ -1,2 +0,0 @@
1
- export { BrowserTerminalHost } from "./terminal-host.js";
2
- export { hostStream } from "./host-stream.js";
@@ -1,143 +0,0 @@
1
- /**
2
- * TerminalHost — the capability seam between the interactive runtime and its
3
- * I/O environment.
4
- *
5
- * [LAW:locality-or-seam] The missing seam *was* the missing type. Before this
6
- * type existed, Screen and EventRouter reached for ambient `process.stdin`/
7
- * `process.stdout`, which crystallised them to node. With a `TerminalHost`
8
- * value flowing across one boundary, the same runtime code runs against any
9
- * implementation — node's TTY (`NodeTerminalHost`, on the `node/terminal-host`
10
- * subpath) or a browser xterm.js terminal (`BrowserTerminalHost`, below).
11
- *
12
- * [LAW:dataflow-not-control-flow] The runtime never branches on "am I in
13
- * node or browser." The host is the value that differs; the code path is
14
- * the same. Variability lives in which host is constructed at the program
15
- * entry, not in any `if` inside the runtime.
16
- *
17
- * [LAW:one-way-deps] The interface and the browser host live here, on the
18
- * `host` subpath; the node host lives in `src/node/terminal-host.ts`, behind
19
- * its own subpath, because it reads `process.stdin` / `process.stdout`. The
20
- * dependency runs one way — the node adapter imports this seam; nothing here
21
- * imports the adapter — so importing a browser-facing entry point cannot
22
- * reach the ambient `process` global by any path, rather than merely not
23
- * reaching it in practice. `test/seam/browser-safe.test.ts` is what holds
24
- * that direction; who reads the host at all is `HOST_ACCESS` in
25
- * `test/seam/ambient-process.ts`, and neither list is repeated here.
26
- *
27
- * [LAW:decomposition] This seam is not part of the interactive layer, which is
28
- * why it is not in it. It sits below `src/widgets/` and imports nothing from
29
- * it, so a program that wants to write bytes through a host — every non-
30
- * interactive consumer — reaches one without loading the widget set or its
31
- * `mobx` dependency.
32
- *
33
- * [boundaries: capabilities over context] A `TerminalHost` grants exactly
34
- * the I/O capabilities the runtime needs: write bytes, read input, query
35
- * size, observe resize, switch raw mode, lifecycle. It is not an
36
- * omniscient handle to "the process."
37
- */
38
- import type { Unsubscribe } from "../core/subscription.js";
39
- export interface TerminalSize {
40
- readonly cols: number;
41
- readonly rows: number;
42
- }
43
- export type DataHandler = (chunk: Uint8Array | string) => void;
44
- export type ResizeHandler = (size: TerminalSize) => void;
45
- export interface TerminalHost {
46
- /**
47
- * Write raw bytes (or UTF-8 text) to the terminal. The byte sequence is
48
- * written verbatim; no escape interpretation, no framing.
49
- */
50
- write(data: Uint8Array | string): void;
51
- /**
52
- * Subscribe to input data. The host emits whatever its underlying
53
- * transport produces (Buffer on node, string on browser xterm.js); the
54
- * runtime's parser accepts either.
55
- */
56
- onData(handler: DataHandler): Unsubscribe;
57
- /**
58
- * Subscribe to terminal resize events. The handler fires with the new
59
- * size after a resize is observed.
60
- */
61
- onResize(handler: ResizeHandler): Unsubscribe;
62
- /** Current terminal size in cells. Always returns a valid size. */
63
- size(): TerminalSize;
64
- /**
65
- * Enable or disable raw mode on the input side. Implementations whose
66
- * transport has no "cooked" mode (xterm.js, non-TTY pipes) silently
67
- * no-op so callers don't need to branch on capability.
68
- */
69
- setRawMode(raw: boolean): void;
70
- /**
71
- * Whether the host is connected to a real interactive terminal. Drives
72
- * default option values (e.g. `manageCursor`, `manageRawMode`) in the
73
- * runtime; non-TTY hosts default those features off.
74
- */
75
- readonly isTTY: boolean;
76
- /**
77
- * Begin the host's lifecycle. Implementations attach whatever resources
78
- * they own — or no-op when there is nothing to attach. Idempotent. See
79
- * the concrete host's own JSDoc for what its `start()` actually does:
80
- * `NodeTerminalHost` and `BrowserTerminalHost` both no-op because their
81
- * underlying transports (process streams; a caller-managed xterm.js
82
- * Terminal) are already live by the time the host is constructed.
83
- */
84
- start(): void;
85
- /**
86
- * Stop the host's lifecycle. Pairs with `start`. Idempotent. After
87
- * `stop()`, the host releases its own subscriptions to the underlying
88
- * transport and clears its handler sets; the transport itself is not
89
- * torn down (that is the caller's concern — process streams persist;
90
- * an xterm.js Terminal is disposed by the caller). Re-subscribing via
91
- * `onData` / `onResize` after `stop()` re-engages the host.
92
- */
93
- stop(): void;
94
- }
95
- /**
96
- * Subset of xterm.js's `Terminal` surface the browser host depends on.
97
- *
98
- * [LAW:locality-or-seam] Declaring the dependency by *shape* — rather than
99
- * importing xterm.js's types — keeps this package free of an xterm.js
100
- * dev-dep at the type level, lets the browser-bundle pipeline (downstream
101
- * ticket) pin whichever xterm.js version it wants, and lets unit tests
102
- * pass a hand-built fake: ask for exactly the capabilities the host uses,
103
- * no more.
104
- */
105
- export interface XtermDisposable {
106
- dispose(): void;
107
- }
108
- export interface XtermResizeEvent {
109
- cols: number;
110
- rows: number;
111
- }
112
- export interface XtermTerminal {
113
- readonly cols: number;
114
- readonly rows: number;
115
- write(data: Uint8Array | string): void;
116
- onData(handler: (data: string) => void): XtermDisposable;
117
- onResize(handler: (size: XtermResizeEvent) => void): XtermDisposable;
118
- }
119
- export interface BrowserTerminalHostOptions {
120
- /**
121
- * The xterm.js `Terminal` instance to wrap. The caller is responsible
122
- * for its DOM lifecycle (`terminal.open(element)`, `terminal.dispose()`)
123
- * — the host only owns its own subscriber lifecycle, exactly mirroring
124
- * `NodeTerminalHost`'s relationship to `process.stdin`/`process.stdout`.
125
- */
126
- terminal: XtermTerminal;
127
- }
128
- export declare class BrowserTerminalHost implements TerminalHost {
129
- private readonly terminal;
130
- private readonly dataHandlers;
131
- private readonly resizeHandlers;
132
- private dataSubscription;
133
- private resizeSubscription;
134
- constructor(options: BrowserTerminalHostOptions);
135
- get isTTY(): boolean;
136
- write(data: Uint8Array | string): void;
137
- size(): TerminalSize;
138
- setRawMode(_raw: boolean): void;
139
- onData(handler: DataHandler): Unsubscribe;
140
- onResize(handler: ResizeHandler): Unsubscribe;
141
- start(): void;
142
- stop(): void;
143
- }
@@ -1,132 +0,0 @@
1
- /**
2
- * TerminalHost — the capability seam between the interactive runtime and its
3
- * I/O environment.
4
- *
5
- * [LAW:locality-or-seam] The missing seam *was* the missing type. Before this
6
- * type existed, Screen and EventRouter reached for ambient `process.stdin`/
7
- * `process.stdout`, which crystallised them to node. With a `TerminalHost`
8
- * value flowing across one boundary, the same runtime code runs against any
9
- * implementation — node's TTY (`NodeTerminalHost`, on the `node/terminal-host`
10
- * subpath) or a browser xterm.js terminal (`BrowserTerminalHost`, below).
11
- *
12
- * [LAW:dataflow-not-control-flow] The runtime never branches on "am I in
13
- * node or browser." The host is the value that differs; the code path is
14
- * the same. Variability lives in which host is constructed at the program
15
- * entry, not in any `if` inside the runtime.
16
- *
17
- * [LAW:one-way-deps] The interface and the browser host live here, on the
18
- * `host` subpath; the node host lives in `src/node/terminal-host.ts`, behind
19
- * its own subpath, because it reads `process.stdin` / `process.stdout`. The
20
- * dependency runs one way — the node adapter imports this seam; nothing here
21
- * imports the adapter — so importing a browser-facing entry point cannot
22
- * reach the ambient `process` global by any path, rather than merely not
23
- * reaching it in practice. `test/seam/browser-safe.test.ts` is what holds
24
- * that direction; who reads the host at all is `HOST_ACCESS` in
25
- * `test/seam/ambient-process.ts`, and neither list is repeated here.
26
- *
27
- * [LAW:decomposition] This seam is not part of the interactive layer, which is
28
- * why it is not in it. It sits below `src/widgets/` and imports nothing from
29
- * it, so a program that wants to write bytes through a host — every non-
30
- * interactive consumer — reaches one without loading the widget set or its
31
- * `mobx` dependency.
32
- *
33
- * [boundaries: capabilities over context] A `TerminalHost` grants exactly
34
- * the I/O capabilities the runtime needs: write bytes, read input, query
35
- * size, observe resize, switch raw mode, lifecycle. It is not an
36
- * omniscient handle to "the process."
37
- */
38
- export class BrowserTerminalHost {
39
- terminal;
40
- dataHandlers = new Set();
41
- resizeHandlers = new Set();
42
- dataSubscription;
43
- resizeSubscription;
44
- constructor(options) {
45
- this.terminal = options.terminal;
46
- }
47
- // [LAW:dataflow-not-control-flow] xterm.js is always an interactive
48
- // terminal — there is no "non-TTY" code path in the browser. The
49
- // runtime never branches on the value; this is the only sensible
50
- // constant for this host.
51
- get isTTY() {
52
- return true;
53
- }
54
- write(data) {
55
- this.terminal.write(data);
56
- }
57
- size() {
58
- return { cols: this.terminal.cols, rows: this.terminal.rows };
59
- }
60
- // [LAW:dataflow-not-control-flow] xterm.js delivers keystrokes raw
61
- // unconditionally — there is no cooked mode to toggle. The no-op
62
- // matches the TerminalHost contract's documented "silently no-op when
63
- // the transport has no cooked mode," so callers stay uniform across
64
- // hosts. (Mirror: NodeTerminalHost on a non-TTY stream takes the same
65
- // no-op path via the optional-chain in `applyRawMode`.)
66
- setRawMode(_raw) { }
67
- // [LAW:single-enforcer] One underlying `terminal.onData` subscription
68
- // fans out to every host-level handler — the same lazy-attach,
69
- // last-unsubscribe-detaches shape as NodeTerminalHost.onData. The
70
- // runtime never sees the underlying subscription; it sees a single
71
- // uniform `(handler) => Unsubscribe` API across hosts.
72
- onData(handler) {
73
- this.dataHandlers.add(handler);
74
- if (!this.dataSubscription) {
75
- this.dataSubscription = this.terminal.onData((chunk) => {
76
- for (const h of this.dataHandlers)
77
- h(chunk);
78
- });
79
- }
80
- return () => {
81
- this.dataHandlers.delete(handler);
82
- if (this.dataHandlers.size === 0 && this.dataSubscription) {
83
- this.dataSubscription.dispose();
84
- this.dataSubscription = undefined;
85
- }
86
- };
87
- }
88
- onResize(handler) {
89
- this.resizeHandlers.add(handler);
90
- if (!this.resizeSubscription) {
91
- this.resizeSubscription = this.terminal.onResize((size) => {
92
- const snapshot = { cols: size.cols, rows: size.rows };
93
- for (const h of this.resizeHandlers)
94
- h(snapshot);
95
- });
96
- }
97
- return () => {
98
- this.resizeHandlers.delete(handler);
99
- if (this.resizeHandlers.size === 0 && this.resizeSubscription) {
100
- this.resizeSubscription.dispose();
101
- this.resizeSubscription = undefined;
102
- }
103
- };
104
- }
105
- start() {
106
- // [LAW:one-source-of-truth] The host does NOT own the terminal's DOM
107
- // lifecycle (`terminal.open` / `terminal.dispose`). That is the
108
- // caller's responsibility, exactly as NodeTerminalHost does not own
109
- // `process.stdin`/`process.stdout`. start() is here so the runtime
110
- // can call it uniformly across hosts; for this host there is
111
- // nothing to do at this seam.
112
- }
113
- stop() {
114
- // [LAW:one-source-of-truth] Symmetric teardown mirroring
115
- // NodeTerminalHost.stop: drop every host-level subscriber and
116
- // dispose the underlying terminal subscriptions. The terminal
117
- // itself stays alive — re-subscribing via onData/onResize after
118
- // stop() works, since the lazy-attach path re-creates the
119
- // subscription on next subscribe. Calling stop() repeatedly is
120
- // safe — the subscription guards make later calls no-ops.
121
- if (this.dataSubscription) {
122
- this.dataSubscription.dispose();
123
- this.dataSubscription = undefined;
124
- }
125
- if (this.resizeSubscription) {
126
- this.resizeSubscription.dispose();
127
- this.resizeSubscription = undefined;
128
- }
129
- this.dataHandlers.clear();
130
- this.resizeHandlers.clear();
131
- }
132
- }
package/dist/index.d.ts DELETED
@@ -1,87 +0,0 @@
1
- export { cellLen, setCellSize, splitText, chopCells, cellFit, asCellCol, asCodePoint, } from "./core/cells.js";
2
- export type { CellCol, CodeUnit, CodePoint } from "./core/cells.js";
3
- export { ColorRgba, ColorTable, ColorDepth, ColorSpec, ColorParseError, TerminalTheme, parseRgbHex, parseRgbaHex, blendRgb, resolveColorSystem, detectColorSystem, STANDARD_TABLE, EIGHT_BIT_TABLE, WINDOWS_TABLE, ANSI_COLOR_NAMES, } from "./core/color.js";
4
- export type { DetectColorOptions } from "./core/color.js";
5
- export { Oklch, IDENTITY, INVERT_LIGHTNESS, isIdentityKey, } from "./core/oklch.js";
6
- export type { ThemeKey, OklchWeights } from "./core/oklch.js";
7
- export { Palette } from "./themes/palette.js";
8
- export { resolveColorRef, parseHexColor, ColorRefError, HEX_COLOR_RE, } from "./themes/colorRef.js";
9
- export { buildPalette } from "./themes/buildPalette.js";
10
- export type { BaseColors } from "./themes/buildPalette.js";
11
- export { DEFAULT_TERMINAL_THEME, MONOKAI, SVG_EXPORT_THEME, NORD, GRUVBOX, DRACULA, TOKYO_NIGHT, FLEXOKI, CYBERPUNK, CATPPUCCIN_MOCHA, CATPPUCCIN_LATTE, CATPPUCCIN_FRAPPE, CATPPUCCIN_MACCHIATO, SOLARIZED_DARK, SOLARIZED_LIGHT, ROSE_PINE, ROSE_PINE_MOON, ROSE_PINE_DAWN, ATOM_ONE_DARK, ATOM_ONE_LIGHT, TEXTUAL_DARK, TEXTUAL_LIGHT, TEXTUAL_ANSI, } from "./themes/terminalThemes.js";
12
- export { getThemePalette, listThemePalettes } from "./themes/registry.js";
13
- export type { ThemeName } from "./themes/registry.js";
14
- export { transposePalette, themeKeyForRoot, isAnchored, ANCHORED_ROOTS, } from "./themes/transpose.js";
15
- export { lighten, darken, relativeLuminance, contrastRatio, contrastFor, ensureContrast, ensureDrawn, drawnColour, } from "./themes/colorMath.js";
16
- export { ColorRamp, RAMP_EASING_NAMES, parseRampEasing } from "./themes/ramp.js";
17
- export type { ColorStop, RampEasing } from "./themes/ramp.js";
18
- export { Style, StyleSyntaxError, StyleStack, Theme, NULL_STYLE, DEFAULT_STYLES, } from "./core/style.js";
19
- export type { StyleOptions } from "./core/style.js";
20
- export { Segment, ControlType, } from "./core/segment.js";
21
- export type { ControlCode } from "./core/segment.js";
22
- export { Box } from "./core/box.js";
23
- export type { EdgeChars, ContentChars, RowLevel, SubstituteOptions } from "./core/box.js";
24
- export { ASCII, ASCII2, ASCII_DOUBLE_HEAD, SQUARE, SQUARE_DOUBLE_HEAD, MINIMAL, MINIMAL_HEAVY_HEAD, MINIMAL_DOUBLE_HEAD, SIMPLE, SIMPLE_HEAD, SIMPLE_HEAVY, HORIZONTALS, ROUNDED, HEAVY, HEAVY_EDGE, HEAVY_HEAD, DOUBLE, DOUBLE_EDGE, MARKDOWN, } from "./core/box.js";
25
- export { isRenderable, isMeasurable, withCellWidth, withBoundedWidth, } from "./core/protocol.js";
26
- export type { RenderOptions, Renderable, Measurable, StyleErrorHandler, } from "./core/protocol.js";
27
- export type { Unsubscribe } from "./core/subscription.js";
28
- export { Measurement, measureRenderables } from "./core/measure.js";
29
- export { Span, RichText } from "./core/text.js";
30
- export type { RichTextOptions } from "./core/text.js";
31
- export { Strip, PowerlineJoiner, SEAM_MIN_DELTA_E, POWERLINE_JOINER_GLYPHS, CapsuleJoiner, PlainJoiner, GradientJoiner, } from "./core/strip.js";
32
- export type { StyledRenderable, Joiner, PowerlineJoinerOptions, CapsuleJoinerOptions, PlainJoinerOptions, GradientJoinerOptions, } from "./core/strip.js";
33
- export { renderToString, segmentToString, segmentsToString, } from "./core/render.js";
34
- export type { RenderToStringOptions } from "./core/render.js";
35
- export { OSC8, osc8Sequences } from "./core/osc8.js";
36
- export type { Osc8Sequence } from "./core/osc8.js";
37
- export { MarkupRegistry, globalMarkupRegistry, renderMarkup, } from "./core/markup.js";
38
- export type { MarkupTagContext, MarkupTagHandler, RenderMarkupOptions, } from "./core/markup.js";
39
- export { EMOJI, emojiReplace, Emoji, NoEmoji } from "./core/emoji.js";
40
- export { MarkupError, MarkupSyntaxError, escape as escapeMarkup } from "./core/markup.js";
41
- export { Highlighter, NullHighlighter, RegexHighlighter, ReprHighlighter, JSONHighlighter, ISO8601Highlighter, } from "./core/highlighter.js";
42
- export { Pretty } from "./core/pretty.js";
43
- export type { PrettyOptions } from "./core/pretty.js";
44
- export { JSONRenderable } from "./core/json.js";
45
- export type { JSONOptions } from "./core/json.js";
46
- export { SPINNERS, DEFAULT_SPINNER } from "./core/spinnerData.js";
47
- export type { SpinnerData } from "./core/spinnerData.js";
48
- export { Console } from "./core/console.js";
49
- export type { ConsoleOptions, ConsoleSink, ConsoleStream, ConsoleEnvironment, PrintOptions, } from "./core/console.js";
50
- export { Constrain } from "./renderables/constrain.js";
51
- export { Align } from "./renderables/align.js";
52
- export type { Alignment } from "./renderables/align.js";
53
- export { Padding } from "./renderables/padding.js";
54
- export type { PaddingDimensions } from "./renderables/padding.js";
55
- export { Rule } from "./renderables/rule.js";
56
- export type { RuleAlign, RuleOptions } from "./renderables/rule.js";
57
- export { Panel } from "./renderables/panel.js";
58
- export type { PanelOptions } from "./renderables/panel.js";
59
- export { Group } from "./renderables/group.js";
60
- export { ProgressBar } from "./renderables/progressBar.js";
61
- export type { ProgressBarOptions } from "./renderables/progressBar.js";
62
- export { Spinner } from "./renderables/spinner.js";
63
- export type { SpinnerOptions } from "./renderables/spinner.js";
64
- export { Table, Column } from "./renderables/table.js";
65
- export type { TableOptions, ColumnOptions } from "./renderables/table.js";
66
- export { Tree } from "./renderables/tree.js";
67
- export type { TreeOptions } from "./renderables/tree.js";
68
- export { Columns } from "./renderables/columns.js";
69
- export type { ColumnsOptions } from "./renderables/columns.js";
70
- export { FlexStrip } from "./renderables/flexStrip.js";
71
- export type { FlexStripOptions, FlexAlign } from "./renderables/flexStrip.js";
72
- export { Live } from "./renderables/live.js";
73
- export type { LiveOptions } from "./renderables/live.js";
74
- export { Status } from "./renderables/status.js";
75
- export type { StatusOptions } from "./renderables/status.js";
76
- export { Progress, TextColumn, BarColumn, TaskProgressColumn, TimeRemainingColumn, TimeElapsedColumn, SpinnerColumn, MofNCompleteColumn, track, } from "./renderables/progress.js";
77
- export type { ProgressOptions, TaskOptions, TaskUpdateOptions } from "./renderables/progress.js";
78
- export { Prompt, IntPrompt, FloatPrompt, Confirm } from "./renderables/prompt.js";
79
- export type { PromptInput, PromptOptions } from "./renderables/prompt.js";
80
- export { Traceback } from "./renderables/traceback.js";
81
- export type { TracebackOptions } from "./renderables/traceback.js";
82
- export { Syntax } from "./renderables/syntax.js";
83
- export type { SyntaxOptions } from "./renderables/syntax.js";
84
- export { Markdown } from "./renderables/markdown.js";
85
- export type { MarkdownOptions } from "./renderables/markdown.js";
86
- export { Layout } from "./renderables/layout.js";
87
- export type { LayoutOptions } from "./renderables/layout.js";