@promptctl/rich-js 0.18.0 → 0.19.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 (244) hide show
  1. package/README.md +9 -7
  2. package/dist/core/anchor.d.ts +45 -0
  3. package/dist/core/anchor.js +39 -0
  4. package/dist/core/ansi.d.ts +65 -0
  5. package/dist/core/ansi.js +231 -0
  6. package/dist/core/box.d.ts +145 -0
  7. package/dist/core/box.js +372 -0
  8. package/dist/core/cells.d.ts +192 -0
  9. package/dist/core/cells.js +334 -0
  10. package/dist/core/clock.d.ts +48 -0
  11. package/dist/core/clock.js +42 -0
  12. package/dist/core/color.d.ts +326 -0
  13. package/dist/core/color.js +1225 -0
  14. package/dist/core/console.d.ts +196 -0
  15. package/dist/core/console.js +596 -0
  16. package/dist/core/easing.d.ts +86 -0
  17. package/dist/core/easing.js +171 -0
  18. package/dist/core/emoji.d.ts +24 -0
  19. package/dist/core/emoji.js +391 -0
  20. package/dist/core/env.d.ts +16 -0
  21. package/dist/core/env.js +16 -0
  22. package/dist/core/export-html.d.ts +59 -0
  23. package/dist/core/export-html.js +197 -0
  24. package/dist/core/export-lines.d.ts +130 -0
  25. package/dist/core/export-lines.js +159 -0
  26. package/dist/core/export-svg.d.ts +49 -0
  27. package/dist/core/export-svg.js +213 -0
  28. package/dist/core/fnv1a.d.ts +10 -0
  29. package/dist/core/fnv1a.js +17 -0
  30. package/dist/core/highlighter.d.ts +33 -0
  31. package/dist/core/highlighter.js +190 -0
  32. package/dist/core/json.d.ts +27 -0
  33. package/dist/core/json.js +53 -0
  34. package/dist/core/markup.d.ts +140 -0
  35. package/dist/core/markup.js +654 -0
  36. package/dist/core/measure.d.ts +27 -0
  37. package/dist/core/measure.js +67 -0
  38. package/dist/core/memo.d.ts +19 -0
  39. package/dist/core/memo.js +34 -0
  40. package/dist/core/oklch.d.ts +161 -0
  41. package/dist/core/oklch.js +312 -0
  42. package/dist/core/osc8.d.ts +68 -0
  43. package/dist/core/osc8.js +78 -0
  44. package/dist/core/paint.d.ts +107 -0
  45. package/dist/core/paint.js +150 -0
  46. package/dist/core/place.d.ts +30 -0
  47. package/dist/core/place.js +49 -0
  48. package/dist/core/pretty.d.ts +247 -0
  49. package/dist/core/pretty.js +906 -0
  50. package/dist/core/protocol.d.ts +305 -0
  51. package/dist/core/protocol.js +183 -0
  52. package/dist/core/render.d.ts +87 -0
  53. package/dist/core/render.js +105 -0
  54. package/dist/core/segment.d.ts +162 -0
  55. package/dist/core/segment.js +488 -0
  56. package/dist/core/spinnerData.d.ts +12 -0
  57. package/dist/core/spinnerData.js +117 -0
  58. package/dist/core/strip.d.ts +152 -0
  59. package/dist/core/strip.js +326 -0
  60. package/dist/core/style.d.ts +189 -0
  61. package/dist/core/style.js +758 -0
  62. package/dist/core/subscription.d.ts +12 -0
  63. package/dist/core/subscription.js +12 -0
  64. package/dist/core/text.d.ts +283 -0
  65. package/dist/core/text.js +1097 -0
  66. package/dist/core/wrap.d.ts +46 -0
  67. package/dist/core/wrap.js +140 -0
  68. package/dist/host/app.d.ts +133 -0
  69. package/dist/host/app.js +285 -0
  70. package/dist/host/host-environment.d.ts +26 -0
  71. package/dist/host/host-environment.js +44 -0
  72. package/dist/host/index.d.ts +6 -0
  73. package/dist/host/index.js +3 -0
  74. package/dist/host/terminal-host.d.ts +180 -0
  75. package/dist/host/terminal-host.js +186 -0
  76. package/dist/index.d.ts +98 -0
  77. package/dist/index.js +114 -0
  78. package/dist/node/prompt.d.ts +34 -0
  79. package/dist/node/prompt.js +51 -0
  80. package/dist/node/save.d.ts +18 -0
  81. package/dist/node/save.js +24 -0
  82. package/dist/node/terminal-host.d.ts +114 -0
  83. package/dist/node/terminal-host.js +227 -0
  84. package/dist/node/traceback.d.ts +38 -0
  85. package/dist/node/traceback.js +98 -0
  86. package/dist/renderables/align.d.ts +16 -0
  87. package/dist/renderables/align.js +26 -0
  88. package/dist/renderables/columns.d.ts +77 -0
  89. package/dist/renderables/columns.js +191 -0
  90. package/dist/renderables/constrain.d.ts +15 -0
  91. package/dist/renderables/constrain.js +31 -0
  92. package/dist/renderables/effect.d.ts +98 -0
  93. package/dist/renderables/effect.js +160 -0
  94. package/dist/renderables/embed.d.ts +107 -0
  95. package/dist/renderables/embed.js +160 -0
  96. package/dist/renderables/flexStrip.d.ts +41 -0
  97. package/dist/renderables/flexStrip.js +200 -0
  98. package/dist/renderables/group.d.ts +14 -0
  99. package/dist/renderables/group.js +22 -0
  100. package/dist/renderables/layout.d.ts +75 -0
  101. package/dist/renderables/layout.js +223 -0
  102. package/dist/renderables/live.d.ts +74 -0
  103. package/dist/renderables/live.js +188 -0
  104. package/dist/renderables/markdown.d.ts +38 -0
  105. package/dist/renderables/markdown.js +587 -0
  106. package/dist/renderables/padding.d.ts +59 -0
  107. package/dist/renderables/padding.js +147 -0
  108. package/dist/renderables/panel.d.ts +114 -0
  109. package/dist/renderables/panel.js +303 -0
  110. package/dist/renderables/progress.d.ts +178 -0
  111. package/dist/renderables/progress.js +362 -0
  112. package/dist/renderables/progressBar.d.ts +31 -0
  113. package/dist/renderables/progressBar.js +64 -0
  114. package/dist/renderables/prompt.d.ts +71 -0
  115. package/dist/renderables/prompt.js +165 -0
  116. package/dist/renderables/ratio.d.ts +123 -0
  117. package/dist/renderables/ratio.js +213 -0
  118. package/dist/renderables/rule.d.ts +26 -0
  119. package/dist/renderables/rule.js +86 -0
  120. package/dist/renderables/spinner.d.ts +57 -0
  121. package/dist/renderables/spinner.js +103 -0
  122. package/dist/renderables/status.d.ts +29 -0
  123. package/dist/renderables/status.js +46 -0
  124. package/dist/renderables/syntax.d.ts +65 -0
  125. package/dist/renderables/syntax.js +166 -0
  126. package/dist/renderables/table.d.ts +232 -0
  127. package/dist/renderables/table.js +973 -0
  128. package/dist/renderables/traceback.d.ts +32 -0
  129. package/dist/renderables/traceback.js +279 -0
  130. package/dist/renderables/tree.d.ts +76 -0
  131. package/dist/renderables/tree.js +177 -0
  132. package/dist/renderables/viewport.d.ts +114 -0
  133. package/dist/renderables/viewport.js +196 -0
  134. package/dist/template-bindings/color-funcs.d.ts +109 -0
  135. package/dist/template-bindings/color-funcs.js +243 -0
  136. package/dist/template-bindings/helpers.d.ts +26 -0
  137. package/dist/template-bindings/helpers.js +33 -0
  138. package/dist/template-bindings/index.d.ts +119 -0
  139. package/dist/template-bindings/index.js +162 -0
  140. package/dist/template-bindings/palette-funcs.d.ts +96 -0
  141. package/dist/template-bindings/palette-funcs.js +145 -0
  142. package/dist/template-bindings/style-funcs.d.ts +28 -0
  143. package/dist/template-bindings/style-funcs.js +157 -0
  144. package/dist/themes/buildPalette.d.ts +57 -0
  145. package/dist/themes/buildPalette.js +100 -0
  146. package/dist/themes/colorMath.d.ts +94 -0
  147. package/dist/themes/colorMath.js +280 -0
  148. package/dist/themes/colorRef.d.ts +36 -0
  149. package/dist/themes/colorRef.js +78 -0
  150. package/dist/themes/data/ansi-tables.d.ts +14 -0
  151. package/dist/themes/data/ansi-tables.js +49 -0
  152. package/dist/themes/data/atom-one-dark.d.ts +3 -0
  153. package/dist/themes/data/atom-one-dark.js +177 -0
  154. package/dist/themes/data/atom-one-light.d.ts +3 -0
  155. package/dist/themes/data/atom-one-light.js +177 -0
  156. package/dist/themes/data/catppuccin-frappe.d.ts +3 -0
  157. package/dist/themes/data/catppuccin-frappe.js +177 -0
  158. package/dist/themes/data/catppuccin-latte.d.ts +3 -0
  159. package/dist/themes/data/catppuccin-latte.js +177 -0
  160. package/dist/themes/data/catppuccin-macchiato.d.ts +3 -0
  161. package/dist/themes/data/catppuccin-macchiato.js +177 -0
  162. package/dist/themes/data/catppuccin-mocha.d.ts +3 -0
  163. package/dist/themes/data/catppuccin-mocha.js +177 -0
  164. package/dist/themes/data/cyberpunk.d.ts +17 -0
  165. package/dist/themes/data/cyberpunk.js +193 -0
  166. package/dist/themes/data/default.d.ts +3 -0
  167. package/dist/themes/data/default.js +160 -0
  168. package/dist/themes/data/dracula.d.ts +3 -0
  169. package/dist/themes/data/dracula.js +177 -0
  170. package/dist/themes/data/flexoki.d.ts +3 -0
  171. package/dist/themes/data/flexoki.js +177 -0
  172. package/dist/themes/data/gruvbox.d.ts +3 -0
  173. package/dist/themes/data/gruvbox.js +177 -0
  174. package/dist/themes/data/index.d.ts +35 -0
  175. package/dist/themes/data/index.js +64 -0
  176. package/dist/themes/data/monokai.d.ts +3 -0
  177. package/dist/themes/data/monokai.js +177 -0
  178. package/dist/themes/data/nord.d.ts +3 -0
  179. package/dist/themes/data/nord.js +177 -0
  180. package/dist/themes/data/rose-pine-dawn.d.ts +3 -0
  181. package/dist/themes/data/rose-pine-dawn.js +177 -0
  182. package/dist/themes/data/rose-pine-moon.d.ts +3 -0
  183. package/dist/themes/data/rose-pine-moon.js +177 -0
  184. package/dist/themes/data/rose-pine.d.ts +3 -0
  185. package/dist/themes/data/rose-pine.js +177 -0
  186. package/dist/themes/data/solarized-dark.d.ts +3 -0
  187. package/dist/themes/data/solarized-dark.js +177 -0
  188. package/dist/themes/data/solarized-light.d.ts +3 -0
  189. package/dist/themes/data/solarized-light.js +177 -0
  190. package/dist/themes/data/svg-export.d.ts +3 -0
  191. package/dist/themes/data/svg-export.js +177 -0
  192. package/dist/themes/data/textual-ansi.d.ts +3 -0
  193. package/dist/themes/data/textual-ansi.js +160 -0
  194. package/dist/themes/data/textual-dark.d.ts +3 -0
  195. package/dist/themes/data/textual-dark.js +160 -0
  196. package/dist/themes/data/textual-light.d.ts +3 -0
  197. package/dist/themes/data/textual-light.js +160 -0
  198. package/dist/themes/data/tokyo-night.d.ts +3 -0
  199. package/dist/themes/data/tokyo-night.js +177 -0
  200. package/dist/themes/data/types.d.ts +31 -0
  201. package/dist/themes/data/types.js +10 -0
  202. package/dist/themes/palette.d.ts +45 -0
  203. package/dist/themes/palette.js +71 -0
  204. package/dist/themes/ramp.d.ts +70 -0
  205. package/dist/themes/ramp.js +103 -0
  206. package/dist/themes/registry.d.ts +44 -0
  207. package/dist/themes/registry.js +105 -0
  208. package/dist/themes/terminalThemes.d.ts +49 -0
  209. package/dist/themes/terminalThemes.js +63 -0
  210. package/dist/themes/transpose.d.ts +87 -0
  211. package/dist/themes/transpose.js +138 -0
  212. package/dist/widgets/button.d.ts +45 -0
  213. package/dist/widgets/button.js +177 -0
  214. package/dist/widgets/checkbox.d.ts +38 -0
  215. package/dist/widgets/checkbox.js +135 -0
  216. package/dist/widgets/dropdown.d.ts +64 -0
  217. package/dist/widgets/dropdown.js +416 -0
  218. package/dist/widgets/event-router.d.ts +71 -0
  219. package/dist/widgets/event-router.js +629 -0
  220. package/dist/widgets/focus-manager.d.ts +45 -0
  221. package/dist/widgets/focus-manager.js +191 -0
  222. package/dist/widgets/hit.d.ts +64 -0
  223. package/dist/widgets/hit.js +113 -0
  224. package/dist/widgets/index.d.ts +20 -0
  225. package/dist/widgets/index.js +14 -0
  226. package/dist/widgets/ink.d.ts +22 -0
  227. package/dist/widgets/ink.js +31 -0
  228. package/dist/widgets/slider.d.ts +54 -0
  229. package/dist/widgets/slider.js +247 -0
  230. package/dist/widgets/static-item.d.ts +34 -0
  231. package/dist/widgets/static-item.js +54 -0
  232. package/dist/widgets/text-input.d.ts +283 -0
  233. package/dist/widgets/text-input.js +1174 -0
  234. package/dist/widgets/themed-widget.d.ts +20 -0
  235. package/dist/widgets/themed-widget.js +89 -0
  236. package/dist/widgets/toggle.d.ts +41 -0
  237. package/dist/widgets/toggle.js +157 -0
  238. package/dist/widgets/types.d.ts +87 -0
  239. package/dist/widgets/types.js +30 -0
  240. package/dist/widgets/widget-app.d.ts +65 -0
  241. package/dist/widgets/widget-app.js +206 -0
  242. package/dist/widgets/widget-base.d.ts +42 -0
  243. package/dist/widgets/widget-base.js +172 -0
  244. package/package.json +16 -2
@@ -0,0 +1,305 @@
1
+ /**
2
+ * Rendering protocol interfaces — Renderable, Measurable, RenderOptions.
3
+ * [LAW:one-source-of-truth] These interfaces are the single authority for the rendering contract.
4
+ */
5
+ import type { Segment } from "./segment.js";
6
+ import { type Style, type StyleSyntaxError, type Theme } from "./style.js";
7
+ import { ColorDepth } from "./color.js";
8
+ import type { Highlighter } from "./highlighter.js";
9
+ /**
10
+ * What becomes of a line still wider than its width once wrapping is done.
11
+ * `"fold"` breaks it across lines, `"crop"` cuts it at the edge, `"ellipsis"`
12
+ * cuts it and marks the cut. `"ignore"` is not a way of cutting: the line has
13
+ * no edge, so nothing wraps it and nothing cuts it, and it leaves at its
14
+ * natural width for whatever drew it to crop or not.
15
+ *
16
+ * `noWrap` is the other half of Rich's pair and is not `"ignore"`: it stops the
17
+ * wrapping and leaves the edge, so a line too wide is cut by the method here.
18
+ */
19
+ export type OverflowMethod = "fold" | "crop" | "ellipsis" | "ignore";
20
+ export interface RenderOptions {
21
+ /**
22
+ * The cells this renderable may occupy. A count of cells, so a non-negative
23
+ * integer — but the field is a plain `number` because it is public API and a
24
+ * caller can write anything into it. `withCellWidth` is where that becomes
25
+ * true rather than assumed; see its comment for why every renderable must
26
+ * call it rather than trusting this declaration.
27
+ */
28
+ maxWidth: number;
29
+ minWidth?: number;
30
+ /**
31
+ * The rows this renderable may occupy. Absent, nothing limits them.
32
+ */
33
+ height?: Height;
34
+ isTerminal?: boolean;
35
+ /**
36
+ * The output can draw only ASCII. Every glyph a renderable chooses — box
37
+ * lines, tree guides, a check mark — is resolved through `drawable`. Text
38
+ * the caller hands in is drawn as given. Absent means the output draws any
39
+ * glyph.
40
+ */
41
+ asciiOnly?: boolean;
42
+ justify?: "left" | "center" | "right" | "full";
43
+ overflow?: OverflowMethod;
44
+ noWrap?: boolean;
45
+ /**
46
+ * Whether a string handed to a renderable — a cell, a label, a pane — is
47
+ * read as markup when it is drawn. Absent, it is, as a `Console`'s is unless
48
+ * told otherwise. A `Console` passes its own setting, and `print`'s.
49
+ */
50
+ markup?: boolean;
51
+ /**
52
+ * Whether a string handed to a renderable is highlighted when it is drawn,
53
+ * by `highlighter`. Absent, it is, as a `Console`'s is unless told
54
+ * otherwise. A `Console` passes its own setting, and `print`'s; a renderable
55
+ * that draws its strings plain, as Rich's `Panel`, `Table` and `Tree` do by
56
+ * default, sets it false for what it renders — Rich's
57
+ * `options.update(highlight=False)` — and a table column's `highlight` sets
58
+ * it either way. `activeHighlighter` is the one reading of the pair.
59
+ */
60
+ highlight?: boolean;
61
+ /**
62
+ * What highlights a string handed to a renderable, while `highlight` says
63
+ * to. A `Console` passes its highlighter whether or not its own `highlight`
64
+ * is on, as Rich's `render_str` reaches `console.highlighter`, so content
65
+ * that turns highlighting on finds the console's highlighter there. Absent,
66
+ * nothing highlights.
67
+ */
68
+ highlighter?: Highlighter;
69
+ /**
70
+ * The depth the output will be encoded at, `null` when it carries no colour.
71
+ * A renderable choosing between two ways of drawing something — the strip's
72
+ * arrow or its divider — decides on the colours the terminal will draw at
73
+ * this depth, which at 256 colours or fewer are not the colours it was
74
+ * handed. Absent means truecolor.
75
+ */
76
+ colorSystem?: ColorDepth | null;
77
+ /**
78
+ * The names a style string may use. A `Console` passes its own; absent, the
79
+ * built-in defaults apply. Read it through `getStyle` rather than directly.
80
+ */
81
+ theme?: Theme;
82
+ /**
83
+ * Called each time a render degrades a style string it cannot parse to
84
+ * unstyled, once per resolution — a style the render reads twice is reported
85
+ * twice. Absent, the failure passes silently. A handler that throws makes
86
+ * the render strict: the error leaves `render`.
87
+ */
88
+ onStyleError?: StyleErrorHandler;
89
+ /**
90
+ * Told of each owner that stamps its output (`core/anchor`) as it starts to
91
+ * render, so the calls arrive in document order: a container's children in
92
+ * the order it renders them, an owner before the owners nested in it. A
93
+ * container forwards it by passing its options on, which every container
94
+ * does. An owner rendered twice is told twice. A render made to measure is
95
+ * not drawing and is not told (`measuring`).
96
+ */
97
+ onDraw?: (owner: object) => void;
98
+ }
99
+ /**
100
+ * `chosen` as this output can draw it: `ascii` in its place when the output is
101
+ * ASCII-only and `chosen` spends a glyph outside ASCII, otherwise `chosen`
102
+ * itself. Choosing a glyph that is already ASCII (a rule of `=`, a MARKDOWN box)
103
+ * picks a frame the terminal can draw, so it is kept. A set of glyphs that must
104
+ * change together — a box grid, a spinner's frames, a scrollbar — passes
105
+ * `glyphs` to say which characters it spends, and is replaced whole.
106
+ *
107
+ * [LAW:single-enforcer] The one place that decides what `asciiOnly` replaces.
108
+ * `test/renderables/ascii-only.test.ts` renders every exported renderable to
109
+ * hold each of them to it.
110
+ */
111
+ export declare function drawable(options: {
112
+ readonly asciiOnly?: boolean;
113
+ }, chosen: string, ascii: string): string;
114
+ export declare function drawable<T>(options: {
115
+ readonly asciiOnly?: boolean;
116
+ }, chosen: T, ascii: T, glyphs: (value: T) => string): T;
117
+ /**
118
+ * A vertical budget: a count of rows, and whether they are a region the
119
+ * renderable stands in or a ceiling it stays under.
120
+ *
121
+ * `exact: true` is a region — a `Layout` pane, a full-screen frame. The output
122
+ * is exactly `rows` tall. A renderable may fill the region — a layout divides
123
+ * it, a frame can stretch to its last row — or ignore it and emit its natural
124
+ * height; either way, whoever set the region shapes what comes back to it
125
+ * (`fitHeight`). Setting a region is a promise to shape, so no renderable pads
126
+ * or crops itself to one.
127
+ *
128
+ * `exact: false` is a ceiling — the terminal an inline print lands on. Content
129
+ * keeps its natural height beneath it, and nothing pads up to the ceiling.
130
+ * Output taller than the ceiling is its setter's to handle: an inline `Live`
131
+ * applies its `verticalOverflow`, and a print lets the terminal scroll it.
132
+ *
133
+ * A renderable passing its whole space to one child must forward the budget
134
+ * less the rows it draws itself, and of the same kind (`insetHeight`). One
135
+ * stacking several children must hand each the rows as a ceiling
136
+ * (`stackedHeight`): any one of them may use all of it, and none may claim it
137
+ * as its region. Forwarded unchanged, a layout nested in a panel fills the
138
+ * panel's whole region and the region's crop takes the panel's bottom border.
139
+ *
140
+ * [LAW:types-are-the-program] One field, because the fact is one count and one
141
+ * bit about it. As two numbers, `height` and `maxHeight`, it admitted a region
142
+ * taller than its ceiling and a region with no ceiling at all, and the one
143
+ * reader in the library resolved them `maxHeight ?? height` — the ceiling ahead
144
+ * of the region it contains.
145
+ *
146
+ * There is no vertical `Measurable`. A parent chooses widths from its
147
+ * children's measurements before any of them renders; nothing chooses rows
148
+ * that way, because a renderable's height is a consequence of the width it
149
+ * renders at. Rendering and counting the lines is the measurement.
150
+ */
151
+ export interface Height {
152
+ readonly rows: number;
153
+ readonly exact: boolean;
154
+ }
155
+ /**
156
+ * The budget a renderable hands the one child filling its space: its own, less
157
+ * the `rows` it draws itself, and of the same kind.
158
+ */
159
+ export declare function insetHeight(height: Height | undefined, rows: number): Height | undefined;
160
+ /**
161
+ * The budget a renderable hands each of several children it stacks: its rows,
162
+ * as a ceiling.
163
+ */
164
+ export declare function stackedHeight(height: Height | undefined): Height | undefined;
165
+ /**
166
+ * The rows a region holds, parsed as a cell count, or `undefined` when there
167
+ * is no region to fill: a ceiling, no budget, or a region of `Infinity` rows,
168
+ * which names no count — as an unbounded width resolves to a natural one in
169
+ * `withBoundedWidth`.
170
+ */
171
+ export declare function regionRows(height: Height | undefined): number | undefined;
172
+ /**
173
+ * What came back from a child, held to the region `height` names — blank rows
174
+ * padded below, overflow cropped from the bottom — or left at its own height
175
+ * when `height` is no region. This is the shaping a region's setter owes.
176
+ */
177
+ export declare function fitHeight(lines: Segment[][], height: Height | undefined): Segment[][];
178
+ /**
179
+ * Receives a style error a render would otherwise absorb: the parse failure,
180
+ * and the whole style string it came from — the error names only the token
181
+ * that failed, and `"bold rd"` loses its `bold` too.
182
+ *
183
+ * [LAW:no-mode-explosion] Strict mode is not a second option beside this one.
184
+ * It is a handler that throws, so there is no "strict and a callback" state
185
+ * whose order anyone has to define.
186
+ */
187
+ export type StyleErrorHandler = (error: StyleSyntaxError, style: string) => void;
188
+ /**
189
+ * The style a `string | Style` stands for in this render: a name from the
190
+ * theme of whatever is drawing, otherwise a style definition. A string that is
191
+ * neither throws `StyleSyntaxError`. This is how a renderable that yields its
192
+ * own `Segment`s draws with a theme name, since a `Segment` takes a resolved
193
+ * `Style`. It is Rich's `console.get_style`, asked of the options because the
194
+ * options are where the theme travels.
195
+ *
196
+ * [LAW:single-enforcer] Every renderable resolves a style name here, at render
197
+ * time, because only the render knows whose theme it is drawing for. Resolved
198
+ * when a renderable was built instead, a name was fixed to the built-in
199
+ * defaults before any `Console` could offer its theme, and `new Console({
200
+ * theme })` changed nothing.
201
+ */
202
+ export declare function getStyle(options: RenderOptions, style: string | Style): Style;
203
+ /**
204
+ * `style` as the depth the render is encoded at can draw it. A style that
205
+ * paints its own ground in fixed colours chose its ink and ground as a pair;
206
+ * at sixteen colours the writer rounds a fixed colour to an ANSI slot, which
207
+ * the terminal paints in its own theme's colour, and no pair of slots reads in
208
+ * every bundled theme. So where the depth would turn a fixed colour of the
209
+ * pair into a slot, the pair is dropped and the run is drawn on the
210
+ * terminal's own foreground and background, which its theme does make
211
+ * readable; its attributes still set it apart. A style whose colours are
212
+ * slots already (`white on blue`), or that paints no ground (`bold magenta`),
213
+ * was written for the terminal's own colours and is drawn as written. Rich
214
+ * draws a highlighted line number the same way below 256 colours
215
+ * (`Syntax._get_number_styles`).
216
+ */
217
+ export declare function groundedStyle(options: RenderOptions, style: Style): Style;
218
+ /**
219
+ * The options a renderable should work from: the caller's, with `maxWidth`
220
+ * parsed into an actual count of cells.
221
+ *
222
+ * [LAW:parse-dont-validate] The stamp has to travel, which is the whole reason
223
+ * this returns options rather than a number. Parsing `options.maxWidth` into a
224
+ * local leaves the caller's raw value sitting in `options` for whatever the
225
+ * renderable forwards it to — and every renderable forwards it, to a child's
226
+ * `render`, to `Measurement.get`, to a nested layout. `Columns` was fixed that
227
+ * way first and still threw `Invalid array length` on a NaN width, because it
228
+ * handed the unparsed original to `Measurement.get` and got a NaN column count
229
+ * back. Replace the field, and nothing downstream can see the number the
230
+ * caller actually wrote.
231
+ *
232
+ * [LAW:single-enforcer] This is the width checkpoint for the render contract.
233
+ * There is no second one: a renderable that re-derives its own answer is how
234
+ * `Panel`, `Table`, `Tree`, `Columns` and `Layout` came to disagree about what
235
+ * a NaN width means — one collapsed to a cell of garbage, two threw, one
236
+ * ignored the request and emitted its full natural width.
237
+ */
238
+ export declare function withCellWidth(options: RenderOptions): RenderOptions;
239
+ /**
240
+ * The options a renderable should *lay out against*: `withCellWidth`, with an
241
+ * unbounded offer resolved to the renderable's own natural width.
242
+ *
243
+ * [LAW:parse-dont-validate] `cellCount` cannot finish the job alone. It floors
244
+ * a negative width and NaN to zero from the number alone, but `Infinity` is not
245
+ * a quantity it can floor — the only finite answer is "as wide as this
246
+ * renderable's content wants", which is a question about the renderable and not
247
+ * about the number. So the parse is completed here, where the renderable is in
248
+ * hand, and the stamped options travel exactly as `withCellWidth`'s do.
249
+ *
250
+ * [LAW:single-enforcer] One checkpoint for the whole rule, not one per
251
+ * renderable. `Panel`, `Padding`, `Columns` and `Layout` each expand into the
252
+ * width they are offered, and each independently reached `" ".repeat(Infinity)`
253
+ * — Columns twice over, since its column *count* is derived from the width too
254
+ * and `new Array(Infinity)` throws a different error again.
255
+ *
256
+ * The natural width comes from `measure`, which every one of them already
257
+ * implements, and the recursion terminates because `measure` reports content
258
+ * rather than the offer: `Panel.measure({maxWidth: Infinity})` is `{9, 9}` for
259
+ * nine cells of content and frame, not `{9, Infinity}`.
260
+ *
261
+ * So this belongs at the top of `render` and never at the top of `measure`:
262
+ * `measure` is the method being asked, and asking it through here would ask it
263
+ * with itself. `measure` parses with `withCellWidth` and reports a natural
264
+ * width of its own — that is the half of the contract that makes this half work.
265
+ *
266
+ * A `maximum` of `Infinity` means the renderable genuinely cannot answer. Two
267
+ * ways in: it wraps a `Renderable` with no `measure`, so nothing in the tree
268
+ * knows how wide the content wants to be; or something inside it asked for an
269
+ * unbounded width of its own, as a `Table` column declared
270
+ * `{ ratio: Infinity }` does. [LAW:no-silent-failure] Both are unanswerable
271
+ * rather than zero, and saying so names the cause — where `String.repeat` and
272
+ * `new Array` only ever name their own argument.
273
+ */
274
+ /**
275
+ * `options` as a measurement is asked with. A `measure` that renders to learn
276
+ * its shape draws nothing on the frame, so it reports no owner to `onDraw` —
277
+ * one that did would put a widget in document order at the moment a
278
+ * container measured it, and keep one the frame then cropped away.
279
+ *
280
+ * [LAW:single-enforcer] Every measurement starts here: `Measurement.get` and
281
+ * `withBoundedWidth` ask through it, and each `measure` passes it on.
282
+ */
283
+ export declare function measuring(options: RenderOptions): RenderOptions;
284
+ export declare function withBoundedWidth(options: RenderOptions, self: Measurable): RenderOptions;
285
+ export interface Renderable {
286
+ render(options: RenderOptions): Iterable<Segment>;
287
+ }
288
+ export interface Measurable {
289
+ measure(options: RenderOptions): {
290
+ minimum: number;
291
+ maximum: number;
292
+ };
293
+ }
294
+ /**
295
+ * What the wheel scrolls: an owner of anchors on the frame (`./anchor.ts`)
296
+ * that moves by lines. `canScrollBy` says whether `scrollBy` with the same
297
+ * `lines` would move it; one that would not passes the wheel outward.
298
+ */
299
+ export interface Scrollable {
300
+ canScrollBy(lines: number): boolean;
301
+ scrollBy(lines: number): void;
302
+ }
303
+ export declare function isRenderable(obj: unknown): obj is Renderable;
304
+ export declare function isMeasurable(obj: unknown): obj is Measurable;
305
+ export declare function isScrollable(obj: object): obj is Scrollable;
@@ -0,0 +1,183 @@
1
+ /**
2
+ * Rendering protocol interfaces — Renderable, Measurable, RenderOptions.
3
+ * [LAW:one-source-of-truth] These interfaces are the single authority for the rendering contract.
4
+ */
5
+ import { cellCount } from "./cells.js";
6
+ import { DEFAULT_THEME } from "./style.js";
7
+ const ASCII_TEXT = /^[\x00-\x7F]*$/;
8
+ export function drawable(options, chosen, ascii, glyphs = String) {
9
+ return options.asciiOnly === true && !ASCII_TEXT.test(glyphs(chosen)) ? ascii : chosen;
10
+ }
11
+ /**
12
+ * The budget a renderable hands the one child filling its space: its own, less
13
+ * the `rows` it draws itself, and of the same kind.
14
+ */
15
+ export function insetHeight(height, rows) {
16
+ return height && { rows: cellCount(height.rows - rows), exact: height.exact };
17
+ }
18
+ /**
19
+ * The budget a renderable hands each of several children it stacks: its rows,
20
+ * as a ceiling.
21
+ */
22
+ export function stackedHeight(height) {
23
+ return height && { rows: cellCount(height.rows), exact: false };
24
+ }
25
+ /**
26
+ * The rows a region holds, parsed as a cell count, or `undefined` when there
27
+ * is no region to fill: a ceiling, no budget, or a region of `Infinity` rows,
28
+ * which names no count — as an unbounded width resolves to a natural one in
29
+ * `withBoundedWidth`.
30
+ */
31
+ export function regionRows(height) {
32
+ return height?.exact && height.rows !== Infinity ? cellCount(height.rows) : undefined;
33
+ }
34
+ /**
35
+ * What came back from a child, held to the region `height` names — blank rows
36
+ * padded below, overflow cropped from the bottom — or left at its own height
37
+ * when `height` is no region. This is the shaping a region's setter owes.
38
+ */
39
+ export function fitHeight(lines, height) {
40
+ const rows = regionRows(height) ?? lines.length;
41
+ const fitted = lines.slice(0, rows);
42
+ while (fitted.length < rows)
43
+ fitted.push([]);
44
+ return fitted;
45
+ }
46
+ /**
47
+ * The style a `string | Style` stands for in this render: a name from the
48
+ * theme of whatever is drawing, otherwise a style definition. A string that is
49
+ * neither throws `StyleSyntaxError`. This is how a renderable that yields its
50
+ * own `Segment`s draws with a theme name, since a `Segment` takes a resolved
51
+ * `Style`. It is Rich's `console.get_style`, asked of the options because the
52
+ * options are where the theme travels.
53
+ *
54
+ * [LAW:single-enforcer] Every renderable resolves a style name here, at render
55
+ * time, because only the render knows whose theme it is drawing for. Resolved
56
+ * when a renderable was built instead, a name was fixed to the built-in
57
+ * defaults before any `Console` could offer its theme, and `new Console({
58
+ * theme })` changed nothing.
59
+ */
60
+ export function getStyle(options, style) {
61
+ return (options.theme ?? DEFAULT_THEME).resolve(style);
62
+ }
63
+ /**
64
+ * `style` as the depth the render is encoded at can draw it. A style that
65
+ * paints its own ground in fixed colours chose its ink and ground as a pair;
66
+ * at sixteen colours the writer rounds a fixed colour to an ANSI slot, which
67
+ * the terminal paints in its own theme's colour, and no pair of slots reads in
68
+ * every bundled theme. So where the depth would turn a fixed colour of the
69
+ * pair into a slot, the pair is dropped and the run is drawn on the
70
+ * terminal's own foreground and background, which its theme does make
71
+ * readable; its attributes still set it apart. A style whose colours are
72
+ * slots already (`white on blue`), or that paints no ground (`bold magenta`),
73
+ * was written for the terminal's own colours and is drawn as written. Rich
74
+ * draws a highlighted line number the same way below 256 colours
75
+ * (`Syntax._get_number_styles`).
76
+ */
77
+ export function groundedStyle(options, style) {
78
+ const drawn = style.drawnColors(options.colorSystem ?? undefined);
79
+ const lost = (written, shown) => written?.fixedValue !== undefined && shown?.fixedValue === undefined;
80
+ const pairLost = style.bgcolor !== undefined && (lost(style.color, drawn.color) || lost(style.bgcolor, drawn.bgcolor));
81
+ return pairLost ? style.withoutColor : style;
82
+ }
83
+ /**
84
+ * The options a renderable should work from: the caller's, with `maxWidth`
85
+ * parsed into an actual count of cells.
86
+ *
87
+ * [LAW:parse-dont-validate] The stamp has to travel, which is the whole reason
88
+ * this returns options rather than a number. Parsing `options.maxWidth` into a
89
+ * local leaves the caller's raw value sitting in `options` for whatever the
90
+ * renderable forwards it to — and every renderable forwards it, to a child's
91
+ * `render`, to `Measurement.get`, to a nested layout. `Columns` was fixed that
92
+ * way first and still threw `Invalid array length` on a NaN width, because it
93
+ * handed the unparsed original to `Measurement.get` and got a NaN column count
94
+ * back. Replace the field, and nothing downstream can see the number the
95
+ * caller actually wrote.
96
+ *
97
+ * [LAW:single-enforcer] This is the width checkpoint for the render contract.
98
+ * There is no second one: a renderable that re-derives its own answer is how
99
+ * `Panel`, `Table`, `Tree`, `Columns` and `Layout` came to disagree about what
100
+ * a NaN width means — one collapsed to a cell of garbage, two threw, one
101
+ * ignored the request and emitted its full natural width.
102
+ */
103
+ export function withCellWidth(options) {
104
+ return { ...options, maxWidth: cellCount(options.maxWidth) };
105
+ }
106
+ /**
107
+ * The options a renderable should *lay out against*: `withCellWidth`, with an
108
+ * unbounded offer resolved to the renderable's own natural width.
109
+ *
110
+ * [LAW:parse-dont-validate] `cellCount` cannot finish the job alone. It floors
111
+ * a negative width and NaN to zero from the number alone, but `Infinity` is not
112
+ * a quantity it can floor — the only finite answer is "as wide as this
113
+ * renderable's content wants", which is a question about the renderable and not
114
+ * about the number. So the parse is completed here, where the renderable is in
115
+ * hand, and the stamped options travel exactly as `withCellWidth`'s do.
116
+ *
117
+ * [LAW:single-enforcer] One checkpoint for the whole rule, not one per
118
+ * renderable. `Panel`, `Padding`, `Columns` and `Layout` each expand into the
119
+ * width they are offered, and each independently reached `" ".repeat(Infinity)`
120
+ * — Columns twice over, since its column *count* is derived from the width too
121
+ * and `new Array(Infinity)` throws a different error again.
122
+ *
123
+ * The natural width comes from `measure`, which every one of them already
124
+ * implements, and the recursion terminates because `measure` reports content
125
+ * rather than the offer: `Panel.measure({maxWidth: Infinity})` is `{9, 9}` for
126
+ * nine cells of content and frame, not `{9, Infinity}`.
127
+ *
128
+ * So this belongs at the top of `render` and never at the top of `measure`:
129
+ * `measure` is the method being asked, and asking it through here would ask it
130
+ * with itself. `measure` parses with `withCellWidth` and reports a natural
131
+ * width of its own — that is the half of the contract that makes this half work.
132
+ *
133
+ * A `maximum` of `Infinity` means the renderable genuinely cannot answer. Two
134
+ * ways in: it wraps a `Renderable` with no `measure`, so nothing in the tree
135
+ * knows how wide the content wants to be; or something inside it asked for an
136
+ * unbounded width of its own, as a `Table` column declared
137
+ * `{ ratio: Infinity }` does. [LAW:no-silent-failure] Both are unanswerable
138
+ * rather than zero, and saying so names the cause — where `String.repeat` and
139
+ * `new Array` only ever name their own argument.
140
+ */
141
+ /**
142
+ * `options` as a measurement is asked with. A `measure` that renders to learn
143
+ * its shape draws nothing on the frame, so it reports no owner to `onDraw` —
144
+ * one that did would put a widget in document order at the moment a
145
+ * container measured it, and keep one the frame then cropped away.
146
+ *
147
+ * [LAW:single-enforcer] Every measurement starts here: `Measurement.get` and
148
+ * `withBoundedWidth` ask through it, and each `measure` passes it on.
149
+ */
150
+ export function measuring(options) {
151
+ return { ...options, onDraw: undefined };
152
+ }
153
+ export function withBoundedWidth(options, self) {
154
+ const parsed = withCellWidth(options);
155
+ if (Number.isFinite(parsed.maxWidth))
156
+ return parsed;
157
+ const natural = self.measure(measuring(parsed)).maximum;
158
+ if (!Number.isFinite(natural)) {
159
+ throw new RangeError("maxWidth is unbounded and this renderable has no natural width to fall " +
160
+ "back on: its content does not implement measure(), or something inside " +
161
+ "it asked for an unbounded width of its own. Render it at a finite " +
162
+ "width, or give the content a measure() that reports a finite maximum.");
163
+ }
164
+ return { ...parsed, maxWidth: cellCount(natural) };
165
+ }
166
+ export function isRenderable(obj) {
167
+ return (typeof obj === "object" &&
168
+ obj !== null &&
169
+ "render" in obj &&
170
+ typeof obj.render === "function");
171
+ }
172
+ export function isMeasurable(obj) {
173
+ return (typeof obj === "object" &&
174
+ obj !== null &&
175
+ "measure" in obj &&
176
+ typeof obj.measure === "function");
177
+ }
178
+ export function isScrollable(obj) {
179
+ return ("canScrollBy" in obj &&
180
+ typeof obj.canScrollBy === "function" &&
181
+ "scrollBy" in obj &&
182
+ typeof obj.scrollBy === "function");
183
+ }
@@ -0,0 +1,87 @@
1
+ /**
2
+ * `renderToString` — stateless one-shot emission of a `Renderable` to a string
3
+ * of ANSI-encoded text. Pure function: same inputs produce byte-identical
4
+ * output. Does not write to `process.stdout` and does not require a `Console`
5
+ * instance.
6
+ *
7
+ * Note on `colorSystem: "auto"`: the `"auto"` spec resolves via
8
+ * `detectColorSystem`, which reads `process.env` and `process.stdout?.isTTY`
9
+ * by default. Callers that want a fully deterministic render must either pass
10
+ * an explicit `ColorDepth` enum / non-`"auto"` spec, or supply `env` and
11
+ * `isTTY` in the options so detection does not consult ambient process state.
12
+ *
13
+ * [LAW:single-enforcer] The Segment-to-ANSI conversion lives in `segmentToString`
14
+ * and is the single way a segment becomes wire bytes. `segmentsToString` is
15
+ * that encoding joined, and `Console._writeSegments`, `Painter` (every `Live`
16
+ * and `App` frame) and `renderToString` all go through it, so terminal output,
17
+ * live and app frames and string export agree by construction.
18
+ *
19
+ * [LAW:one-source-of-truth] What the encoding needs from where it writes
20
+ * arrives as one `Destination` value. Each caller resolves its destination
21
+ * once — spec, detection, and its own overrides — and hands it through whole,
22
+ * so a depth is never paired with a link setting taken from somewhere else.
23
+ *
24
+ * Every segment is written alone, exactly as Python Rich 9d8f9a3 writes it
25
+ * (`Console._render_buffer` calls `Style.render` per segment): its SGR codes
26
+ * open, its text, a reset, and an OSC 8 pair around all three when it carries
27
+ * a link. Two adjacent segments with equal codes are two runs, not one. That
28
+ * costs a reset and a reopen the terminal draws identically, and it is what
29
+ * lets a fixture generated from the reference hold any sequence of segments,
30
+ * rather than only those in which no two neighbours happen to share a style
31
+ * (rich-render-g5g8). The price of that is that where a renderable cuts its
32
+ * segments is now in the bytes, so a renderable pinned against the reference
33
+ * has to cut where the reference cuts, as `Box`'s rules and `Table`'s blank
34
+ * cell lines do. A link split across segments still hovers as one link,
35
+ * because every pair it becomes carries the id `osc8Open` derives from the URL.
36
+ *
37
+ * Colour and hyperlinks are two facts about the destination:
38
+ * `colorSystem === null` empties every segment's SGR codes, and
39
+ * `hyperlinks === false` drops every segment's link. A colour depth never
40
+ * removes a link — a hyperlink is not a colour, and a NO_COLOR terminal still
41
+ * follows OSC 8. This is where the port departs from the reference, whose
42
+ * `Style.render` returns bare text for a null colour system.
43
+ */
44
+ import { ColorDepth } from "./color.js";
45
+ import type { ColorSystemName, Destination } from "./color.js";
46
+ import type { Env } from "./env.js";
47
+ import type { Segment } from "./segment.js";
48
+ import type { Renderable, RenderOptions } from "./protocol.js";
49
+ export interface RenderToStringOptions extends Pick<RenderOptions, "asciiOnly" | "theme" | "onStyleError" | "highlight" | "highlighter"> {
50
+ /** Cell width to render into. Default 80. */
51
+ width?: number;
52
+ /**
53
+ * Color encoding to emit. Accepts a `ColorSystemName` (`"auto"`,
54
+ * `"truecolor"`, `"256"`, `"ansi"`, `"none"`), a `ColorDepth` enum value, or `null` to
55
+ * strip SGR colors/attributes. Hyperlinks are `hyperlinks`' concern. Default
56
+ * truecolor.
57
+ */
58
+ colorSystem?: ColorSystemName | ColorDepth | null;
59
+ /**
60
+ * Environment to consult when `colorSystem` is `"auto"`. Defaults to
61
+ * `process.env`. Pass an explicit value to keep rendering deterministic.
62
+ */
63
+ env?: Env;
64
+ /**
65
+ * Whether output is going to a TTY when `colorSystem` is `"auto"`. Defaults
66
+ * to `process.stdout?.isTTY`. Pass an explicit value to keep rendering
67
+ * deterministic.
68
+ */
69
+ isTTY?: boolean;
70
+ /** When true, forces `colorSystem` to `null` regardless of the explicit value. */
71
+ noColor?: boolean;
72
+ /**
73
+ * Whether OSC 8 hyperlinks are emitted. Independent of `colorSystem`: a
74
+ * null colour system strips SGR and keeps links. Default: what the
75
+ * destination takes — true for an explicit depth, detected under `"auto"`
76
+ * (no TTY or TERM=dumb: false). `false` with `colorSystem: null` is plain text.
77
+ */
78
+ hyperlinks?: boolean;
79
+ }
80
+ /**
81
+ * Encodes one segment as ANSI bytes for `destination`: the reference's
82
+ * `Style.render` for that segment, and nothing for a control segment.
83
+ */
84
+ export declare function segmentToString(segment: Segment, destination: Destination): string;
85
+ /** Encodes a sequence of segments as ANSI bytes for `destination`, one segment at a time. */
86
+ export declare function segmentsToString(segments: Iterable<Segment>, destination: Destination): string;
87
+ export declare function renderToString(renderable: Renderable, options?: RenderToStringOptions): string;