@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,24 +0,0 @@
1
- /**
2
- * Shared internal helpers for the rich-js template binding layer.
3
- *
4
- * [LAW:one-source-of-truth] `applyStyleToFragment` is the single implementation
5
- * of "apply a Style to an existing RichText fragment." Both the style-function
6
- * registrations and the palette-function registrations use this same operation;
7
- * keeping one copy prevents the two from drifting.
8
- */
9
- import { Style } from "../core/style.js";
10
- import { RichText } from "../core/text.js";
11
- /**
12
- * Apply a style on top of an already-styled RichText fragment.
13
- *
14
- * [LAW:single-enforcer] Type validation lives here; callers trust the result.
15
- * The `"liftable"` arg type lifts string literals to `RichText` via the
16
- * engine's `fromString` before the body runs, so `child` is always a
17
- * `RichText` by the time this runs. The instanceof check exists because
18
- * `"liftable"` admits any non-primitive — the engine cannot prove the object
19
- * is the binding's own `T`. Misuse (`{{ red someMap }}`) fails loudly here
20
- * rather than producing a malformed fragment.
21
- *
22
- * Conflict resolution: `Style.add` — the outer (newly applied) style wins.
23
- */
24
- export declare function applyStyleToFragment(child: unknown, style: Style): RichText;
@@ -1,48 +0,0 @@
1
- /**
2
- * Shared internal helpers for the rich-js template binding layer.
3
- *
4
- * [LAW:one-source-of-truth] `applyStyleToFragment` is the single implementation
5
- * of "apply a Style to an existing RichText fragment." Both the style-function
6
- * registrations and the palette-function registrations use this same operation;
7
- * keeping one copy prevents the two from drifting.
8
- */
9
- import { Style, StyleSyntaxError } from "../core/style.js";
10
- import { RichText } from "../core/text.js";
11
- /**
12
- * Apply a style on top of an already-styled RichText fragment.
13
- *
14
- * [LAW:single-enforcer] Type validation lives here; callers trust the result.
15
- * The `"liftable"` arg type lifts string literals to `RichText` via the
16
- * engine's `fromString` before the body runs, so `child` is always a
17
- * `RichText` by the time this runs. The instanceof check exists because
18
- * `"liftable"` admits any non-primitive — the engine cannot prove the object
19
- * is the binding's own `T`. Misuse (`{{ red someMap }}`) fails loudly here
20
- * rather than producing a malformed fragment.
21
- *
22
- * Conflict resolution: `Style.add` — the outer (newly applied) style wins.
23
- */
24
- export function applyStyleToFragment(child, style) {
25
- if (!(child instanceof RichText)) {
26
- throw new TypeError(`template function expected a RichText fragment, got ${typeof child === "object" ? Object.prototype.toString.call(child) : typeof child}`);
27
- }
28
- const result = child.copy();
29
- result.style = baseStyleOf(child.style).add(style);
30
- return result;
31
- }
32
- /**
33
- * A fragment's base style as a `Style`. A string must parse as a definition: a
34
- * name resolves only against the theme of the render that draws it, and a
35
- * template runs before any render exists.
36
- */
37
- function baseStyleOf(style) {
38
- if (style instanceof Style)
39
- return style;
40
- try {
41
- return Style.parse(style);
42
- }
43
- catch (err) {
44
- if (!(err instanceof StyleSyntaxError))
45
- throw err;
46
- throw new TypeError(`template function cannot style a fragment whose base style "${style}" is not a style definition: a style name resolves only against the theme of a render`, { cause: err });
47
- }
48
- }
@@ -1,107 +0,0 @@
1
- /**
2
- * rich-js template bindings — public entry point.
3
- *
4
- * [LAW:one-source-of-truth] This module is the public entry point for
5
- * rich-js's styling vocabulary as `@promptctl/go-template-js` template
6
- * functions. The split between the two exported registrations is exactly the
7
- * split between what needs a theme and what does not:
8
- *
9
- * - `richTextFuncs()` — the colour sinks (`fg`/`bg`), the palette-free colour
10
- * math (`darken`, `mix`, `contrastOn`, the OKLCH axes …), text attributes,
11
- * and `link`. Needs no configuration; safe to register unconditionally. A
12
- * consumer with no theme system still gets the complete colour vocabulary by
13
- * feeding it hex literals.
14
- * - `paletteFuncs(getPalette)` — `color` and `ramp`, the two functions that
15
- * resolve a palette name. This is the *only* registration that knows a
16
- * palette exists, which is why it is the only one that takes an argument.
17
- * [LAW:one-way-deps]
18
- *
19
- * `createRichTextEngine()` wires up `richTextFuncs()` only — it cannot supply a
20
- * palette. Consumers that name theme colours call `paletteFuncs(getPalette)`
21
- * and merge it into their own engine config.
22
- *
23
- * Colours compose by nesting, like every other function:
24
- * `{{ fg (darken (color "primary") 2) (bold "x") }}`. There is no second
25
- * markup grammar and no colour-spec mini-language — the template *is* the
26
- * composition mechanism.
27
- *
28
- * Fragment type: `RichText`. Chosen because it is the library's primary
29
- * text type (implements `Renderable` + `Measurable`), composes via
30
- * `append`, and flows directly into the existing render pipeline with no
31
- * adapter. Top-level template expressions emit as `RichText[]` — natural
32
- * for cases where a single template produces multiple independently
33
- * addressable fragments (e.g. multiple top-level `link` calls, each
34
- * carrying its own URL).
35
- */
36
- import { type Engine, type FuncMap } from "@promptctl/go-template-js";
37
- import { RichText } from "../core/text.js";
38
- import { Segment } from "../core/segment.js";
39
- import { ColorDepth } from "../core/color.js";
40
- export { paletteFuncs } from "./palette-funcs.js";
41
- export { colorFuncs, readableOnFunc } from "./color-funcs.js";
42
- /**
43
- * Funcs registered by the rich-js binding — the colour sinks, the palette-free
44
- * colour math, text attributes, and the `link` cell-splitter. Nothing here
45
- * needs a theme; the two that do (`color`, `ramp`) ship separately via
46
- * `paletteFuncs(getPalette)`, merged consumer-side. `drawnAt` is forwarded to
47
- * `colorFuncs` — the depth `readableOn` measures at, truecolor when omitted.
48
- *
49
- * `FuncMap` is not parameterised over `T` in `@promptctl/go-template-js` — the engine's
50
- * `T` lives on the `Engine`/`EngineConfig`, and per-function input/output
51
- * types are carried as runtime `argTypes` on each `TemplateFunc`. The map
52
- * therefore *type-checks* against any `EngineConfig<T>.funcs`, but the
53
- * functions returned here are only *runtime-compatible* with
54
- * `Engine<RichText>`: each style function returns a `RichText` and
55
- * requires its lifted child to be a `RichText` (enforced by an
56
- * `instanceof` check that throws on misuse). Consumers merging this map
57
- * into a wider engine must keep `T = RichText`; merging into an engine
58
- * whose `T` is something else will compile but fail at evaluation time.
59
- */
60
- export declare function richTextFuncs(drawnAt?: () => ColorDepth): FuncMap;
61
- /**
62
- * Construct an `Engine<RichText>` with the rich-js style-function set
63
- * registered. Consumers that already manage their own engine should call
64
- * `richTextFuncs()` and merge the result into their own `createEngine`
65
- * configuration; consumers that just want rich-js styling can use this
66
- * factory directly.
67
- *
68
- * `fromString` lifts text literals into `RichText`. `toString` flattens a
69
- * `RichText` to its plain text — the engine's no-silent-flatten guard uses
70
- * this only for `printf "%s"` / `"%q"` and `print*` slots, where ANSI is
71
- * not desired anyway.
72
- */
73
- export declare function createRichTextEngine(): Engine<RichText>;
74
- /**
75
- * Compile a template source against `engine` and render the result to a
76
- * flat `Segment[]`. The 90%-case convenience over chaining `engine.compile`,
77
- * `RichText.fromFragments`, and `.render` by hand:
78
- *
79
- * - Runs `engine.compile(source)(scope)` to get the engine's `RichText[]`.
80
- * - Flattens that fragment list into a single styled `RichText` via
81
- * `RichText.fromFragments` so every fragment's wrapping style survives.
82
- * - Renders to a `Segment[]` at the requested `maxWidth`.
83
- * - Wraps the whole flow in a try/catch — on parse/evaluate failure,
84
- * emits a single dim styled `[error: <message>]` segment the caller can
85
- * drop into their layout. No bespoke fallback wiring required at every
86
- * call site.
87
- *
88
- * [LAW:single-enforcer] One place owns "render a template to segments,
89
- * degrade gracefully on errors" — every consumer that wants this exact
90
- * shape reads from here rather than re-implementing the same try/catch +
91
- * error-formatting glue.
92
- *
93
- * For the 10% — custom error UX, intermediate access to the `RichText`,
94
- * pre-compiled templates re-used many times — call the engine directly
95
- * and use `RichText.fromFragments` to flatten. This helper is sugar for
96
- * the live-render case (e.g. a preview pane), not a replacement for the
97
- * compile-once-evaluate-many pattern.
98
- *
99
- * @param maxWidth defaults to 400 — large enough that downstream `splitLines`
100
- * / `adjustLineLength` clipping decides actual width, matching the typical
101
- * "render wide, fit on output" pipeline.
102
- * @param errorStyle is a `Style.parse` spec (default `"red dim"`).
103
- */
104
- export declare function renderTemplate(engine: Engine<RichText>, source: string, scope?: unknown, options?: {
105
- maxWidth?: number;
106
- errorStyle?: string;
107
- }): Segment[];
@@ -1,144 +0,0 @@
1
- /**
2
- * rich-js template bindings — public entry point.
3
- *
4
- * [LAW:one-source-of-truth] This module is the public entry point for
5
- * rich-js's styling vocabulary as `@promptctl/go-template-js` template
6
- * functions. The split between the two exported registrations is exactly the
7
- * split between what needs a theme and what does not:
8
- *
9
- * - `richTextFuncs()` — the colour sinks (`fg`/`bg`), the palette-free colour
10
- * math (`darken`, `mix`, `contrastOn`, the OKLCH axes …), text attributes,
11
- * and `link`. Needs no configuration; safe to register unconditionally. A
12
- * consumer with no theme system still gets the complete colour vocabulary by
13
- * feeding it hex literals.
14
- * - `paletteFuncs(getPalette)` — `color` and `ramp`, the two functions that
15
- * resolve a palette name. This is the *only* registration that knows a
16
- * palette exists, which is why it is the only one that takes an argument.
17
- * [LAW:one-way-deps]
18
- *
19
- * `createRichTextEngine()` wires up `richTextFuncs()` only — it cannot supply a
20
- * palette. Consumers that name theme colours call `paletteFuncs(getPalette)`
21
- * and merge it into their own engine config.
22
- *
23
- * Colours compose by nesting, like every other function:
24
- * `{{ fg (darken (color "primary") 2) (bold "x") }}`. There is no second
25
- * markup grammar and no colour-spec mini-language — the template *is* the
26
- * composition mechanism.
27
- *
28
- * Fragment type: `RichText`. Chosen because it is the library's primary
29
- * text type (implements `Renderable` + `Measurable`), composes via
30
- * `append`, and flows directly into the existing render pipeline with no
31
- * adapter. Top-level template expressions emit as `RichText[]` — natural
32
- * for cases where a single template produces multiple independently
33
- * addressable fragments (e.g. multiple top-level `link` calls, each
34
- * carrying its own URL).
35
- */
36
- import { createEngine } from "@promptctl/go-template-js";
37
- import { RichText } from "../core/text.js";
38
- import { Style } from "../core/style.js";
39
- import { Segment } from "../core/segment.js";
40
- import { richTextStyleFuncs } from "./style-funcs.js";
41
- import { colorFuncs } from "./color-funcs.js";
42
- export { paletteFuncs } from "./palette-funcs.js";
43
- export { colorFuncs, readableOnFunc } from "./color-funcs.js";
44
- /**
45
- * Funcs registered by the rich-js binding — the colour sinks, the palette-free
46
- * colour math, text attributes, and the `link` cell-splitter. Nothing here
47
- * needs a theme; the two that do (`color`, `ramp`) ship separately via
48
- * `paletteFuncs(getPalette)`, merged consumer-side. `drawnAt` is forwarded to
49
- * `colorFuncs` — the depth `readableOn` measures at, truecolor when omitted.
50
- *
51
- * `FuncMap` is not parameterised over `T` in `@promptctl/go-template-js` — the engine's
52
- * `T` lives on the `Engine`/`EngineConfig`, and per-function input/output
53
- * types are carried as runtime `argTypes` on each `TemplateFunc`. The map
54
- * therefore *type-checks* against any `EngineConfig<T>.funcs`, but the
55
- * functions returned here are only *runtime-compatible* with
56
- * `Engine<RichText>`: each style function returns a `RichText` and
57
- * requires its lifted child to be a `RichText` (enforced by an
58
- * `instanceof` check that throws on misuse). Consumers merging this map
59
- * into a wider engine must keep `T = RichText`; merging into an engine
60
- * whose `T` is something else will compile but fail at evaluation time.
61
- */
62
- // [LAW:one-source-of-truth] The truecolor default lives on `colorFuncs` alone;
63
- // an omitted `drawnAt` is forwarded as omitted.
64
- export function richTextFuncs(drawnAt) {
65
- return { ...richTextStyleFuncs(), ...colorFuncs(drawnAt) };
66
- }
67
- /**
68
- * Construct an `Engine<RichText>` with the rich-js style-function set
69
- * registered. Consumers that already manage their own engine should call
70
- * `richTextFuncs()` and merge the result into their own `createEngine`
71
- * configuration; consumers that just want rich-js styling can use this
72
- * factory directly.
73
- *
74
- * `fromString` lifts text literals into `RichText`. `toString` flattens a
75
- * `RichText` to its plain text — the engine's no-silent-flatten guard uses
76
- * this only for `printf "%s"` / `"%q"` and `print*` slots, where ANSI is
77
- * not desired anyway.
78
- */
79
- export function createRichTextEngine() {
80
- return createEngine({
81
- fromString: (s) => new RichText(s),
82
- toString: (rt) => rt.plain,
83
- funcs: richTextFuncs(),
84
- });
85
- }
86
- /**
87
- * Compile a template source against `engine` and render the result to a
88
- * flat `Segment[]`. The 90%-case convenience over chaining `engine.compile`,
89
- * `RichText.fromFragments`, and `.render` by hand:
90
- *
91
- * - Runs `engine.compile(source)(scope)` to get the engine's `RichText[]`.
92
- * - Flattens that fragment list into a single styled `RichText` via
93
- * `RichText.fromFragments` so every fragment's wrapping style survives.
94
- * - Renders to a `Segment[]` at the requested `maxWidth`.
95
- * - Wraps the whole flow in a try/catch — on parse/evaluate failure,
96
- * emits a single dim styled `[error: <message>]` segment the caller can
97
- * drop into their layout. No bespoke fallback wiring required at every
98
- * call site.
99
- *
100
- * [LAW:single-enforcer] One place owns "render a template to segments,
101
- * degrade gracefully on errors" — every consumer that wants this exact
102
- * shape reads from here rather than re-implementing the same try/catch +
103
- * error-formatting glue.
104
- *
105
- * For the 10% — custom error UX, intermediate access to the `RichText`,
106
- * pre-compiled templates re-used many times — call the engine directly
107
- * and use `RichText.fromFragments` to flatten. This helper is sugar for
108
- * the live-render case (e.g. a preview pane), not a replacement for the
109
- * compile-once-evaluate-many pattern.
110
- *
111
- * @param maxWidth defaults to 400 — large enough that downstream `splitLines`
112
- * / `adjustLineLength` clipping decides actual width, matching the typical
113
- * "render wide, fit on output" pipeline.
114
- * @param errorStyle is a `Style.parse` spec (default `"red dim"`).
115
- */
116
- export function renderTemplate(engine, source, scope = {}, options) {
117
- try {
118
- const frags = engine.compile(source)(scope);
119
- const rt = RichText.fromFragments(frags);
120
- return Array.from(rt.render({
121
- maxWidth: options?.maxWidth ?? 400,
122
- isTerminal: true,
123
- encoding: "utf-8",
124
- }));
125
- }
126
- catch (e) {
127
- return [new Segment(`[error: ${String(e).slice(0, 80)}]`, safeErrorStyle(options?.errorStyle))];
128
- }
129
- }
130
- // [LAW:single-enforcer] The error-path Style must not itself throw, or
131
- // the whole "degrade gracefully" promise of renderTemplate is broken. A
132
- // bogus user-supplied `errorStyle` spec falls back to a hard-coded safe
133
- // Style — never propagates the parse failure to the caller.
134
- const FALLBACK_ERROR_STYLE = new Style({ color: "red", dim: true });
135
- function safeErrorStyle(spec) {
136
- if (spec === undefined)
137
- return FALLBACK_ERROR_STYLE;
138
- try {
139
- return Style.parse(spec);
140
- }
141
- catch {
142
- return FALLBACK_ERROR_STYLE;
143
- }
144
- }
@@ -1,94 +0,0 @@
1
- /**
2
- * The palette-dependent template functions: `color`, and `ramp` whose stops
3
- * are color references.
4
- *
5
- * ### Why `color` is the one name resolver
6
- *
7
- * This module used to register four kinds of thing: one function per
8
- * identifier-safe palette variable (`{{ primary child }}`, `{{ accent child }}`,
9
- * …), a general `palette "spec" child`, a `paletteOver "spec" "#bg" child` for
10
- * specs needing a background, and an `auto "#bg" child` sugar. That surface had
11
- * two defects worth recording, because both are easy to reintroduce.
12
- *
13
- * **The name family could not cover its own domain.** A themed palette carries
14
- * ~150 variables; roughly 14 of them are legal Go-template identifiers. So the
15
- * generated functions reached under a tenth of the palette, and the other nine
16
- * tenths needed `palette "text-primary" child` — a *different expression shape*
17
- * for the same intent. An author who learned `{{ primary x }}` and reasonably
18
- * tried `{{ text_primary x }}` got a FuncNotFound. [LAW:composability] — the
19
- * `filterByStatus`/`filterByOwner` shape: names cannot enumerate a domain, and
20
- * the N+1 case always needs a form you have to learn separately.
21
- *
22
- * **Resolution and application were fused.** Every one of those functions
23
- * consumed its color instantly into a styled fragment, so a color could never
24
- * be held or passed. Composition therefore had to happen inside the spec
25
- * *string* — hence the old `name-darken-N alpha%` grammar. See
26
- * `color-funcs.ts` for the full argument; the short version is that a string
27
- * grammar is function application with the function calls spelled as
28
- * punctuation, and it grows a new production for every operation.
29
- *
30
- * What replaces all of it: `color "name-or-hex"` produces a color value, the
31
- * functions in `color-funcs.ts` transform colors, and `fg`/`bg` in
32
- * `style-funcs.ts` paint them. One shape, total over the palette, open to
33
- * arbitrary composition. [LAW:one-type-per-behavior]
34
- *
35
- * ### Why `ramp` lives here and not with the color math
36
- *
37
- * `ramp` is the one function whose input is a *number*, and its stops are
38
- * spelled as color references — `ramp .pct "step" 0 "panel" 50 "warning" 80
39
- * "error"` — resolved through the same `resolveColorRef` that `color` crosses.
40
- * Requiring `(color "panel")` around every stop would put the boilerplate
41
- * back that this binding exists to remove, and an author who writes a hex
42
- * literal loses nothing: the resolver is idempotent on hex. The arithmetic
43
- * itself is `ColorRamp` in `themes/ramp.ts`, palette-free; only the
44
- * reference resolution is here. [LAW:one-way-deps]
45
- *
46
- * ### Why a getter, not a palette
47
- *
48
- * `paletteFuncs` takes `() => Palette` rather than a `Palette`. A consumer
49
- * whose theme can change at runtime (a live preview, a theme picker, a
50
- * status-line that recolors on click) would otherwise be frozen to whichever
51
- * palette happened to be current when the engine was constructed — and since
52
- * templates are parsed once and evaluated many times, that freeze outlives
53
- * every subsequent theme change while the *rest* of the consumer's colors move
54
- * on. Two palettes, one render: [LAW:one-source-of-truth] violated by a
55
- * captured reference.
56
- *
57
- * The getter costs nothing structurally. `FuncMap` entries are data in the
58
- * engine and their bodies run at *evaluate* time, so reading the palette
59
- * through a getter leaves parse-once/evaluate-many completely intact. What the
60
- * getter must not change is *which functions exist* — and it cannot, because
61
- * the two names here do not depend on the palette's contents. That was not
62
- * true of the generated per-variable functions, which is the second reason
63
- * they are gone.
64
- */
65
- import type { FuncMap } from "@promptctl/go-template-js";
66
- import type { Palette } from "../themes/palette.js";
67
- /**
68
- * Register `color "name-or-hex"` against a live palette.
69
- *
70
- * `color` resolves a palette variable name to a `#RRGGBB` string, and passes
71
- * an already-literal color through unchanged. That second half is not a
72
- * convenience — it makes `color` **idempotent**, which is what lets consumers
73
- * apply it unconditionally to any author-written color string without first
74
- * asking whether it is a name or already a color. [LAW:dataflow-not-control-flow]
75
- *
76
- * An unknown name throws, carrying near-miss suggestions from the live
77
- * palette. In a template that surfaces as an evaluation error at the exact
78
- * call site, which is the signal an author (or an agent editing a config) needs
79
- * to fix it. [LAW:no-silent-failure]
80
- *
81
- * @example
82
- * ```ts
83
- * const engine = createEngine({
84
- * fromString: (s) => new RichText(s),
85
- * toString: (rt) => rt.plain,
86
- * funcs: {
87
- * ...richTextFuncs(),
88
- * ...colorFuncs(),
89
- * ...paletteFuncs(() => currentTheme.palette),
90
- * },
91
- * });
92
- * ```
93
- */
94
- export declare function paletteFuncs(getPalette: () => Palette): FuncMap;
@@ -1,151 +0,0 @@
1
- /**
2
- * The palette-dependent template functions: `color`, and `ramp` whose stops
3
- * are color references.
4
- *
5
- * ### Why `color` is the one name resolver
6
- *
7
- * This module used to register four kinds of thing: one function per
8
- * identifier-safe palette variable (`{{ primary child }}`, `{{ accent child }}`,
9
- * …), a general `palette "spec" child`, a `paletteOver "spec" "#bg" child` for
10
- * specs needing a background, and an `auto "#bg" child` sugar. That surface had
11
- * two defects worth recording, because both are easy to reintroduce.
12
- *
13
- * **The name family could not cover its own domain.** A themed palette carries
14
- * ~150 variables; roughly 14 of them are legal Go-template identifiers. So the
15
- * generated functions reached under a tenth of the palette, and the other nine
16
- * tenths needed `palette "text-primary" child` — a *different expression shape*
17
- * for the same intent. An author who learned `{{ primary x }}` and reasonably
18
- * tried `{{ text_primary x }}` got a FuncNotFound. [LAW:composability] — the
19
- * `filterByStatus`/`filterByOwner` shape: names cannot enumerate a domain, and
20
- * the N+1 case always needs a form you have to learn separately.
21
- *
22
- * **Resolution and application were fused.** Every one of those functions
23
- * consumed its color instantly into a styled fragment, so a color could never
24
- * be held or passed. Composition therefore had to happen inside the spec
25
- * *string* — hence the old `name-darken-N alpha%` grammar. See
26
- * `color-funcs.ts` for the full argument; the short version is that a string
27
- * grammar is function application with the function calls spelled as
28
- * punctuation, and it grows a new production for every operation.
29
- *
30
- * What replaces all of it: `color "name-or-hex"` produces a color value, the
31
- * functions in `color-funcs.ts` transform colors, and `fg`/`bg` in
32
- * `style-funcs.ts` paint them. One shape, total over the palette, open to
33
- * arbitrary composition. [LAW:one-type-per-behavior]
34
- *
35
- * ### Why `ramp` lives here and not with the color math
36
- *
37
- * `ramp` is the one function whose input is a *number*, and its stops are
38
- * spelled as color references — `ramp .pct "step" 0 "panel" 50 "warning" 80
39
- * "error"` — resolved through the same `resolveColorRef` that `color` crosses.
40
- * Requiring `(color "panel")` around every stop would put the boilerplate
41
- * back that this binding exists to remove, and an author who writes a hex
42
- * literal loses nothing: the resolver is idempotent on hex. The arithmetic
43
- * itself is `ColorRamp` in `themes/ramp.ts`, palette-free; only the
44
- * reference resolution is here. [LAW:one-way-deps]
45
- *
46
- * ### Why a getter, not a palette
47
- *
48
- * `paletteFuncs` takes `() => Palette` rather than a `Palette`. A consumer
49
- * whose theme can change at runtime (a live preview, a theme picker, a
50
- * status-line that recolors on click) would otherwise be frozen to whichever
51
- * palette happened to be current when the engine was constructed — and since
52
- * templates are parsed once and evaluated many times, that freeze outlives
53
- * every subsequent theme change while the *rest* of the consumer's colors move
54
- * on. Two palettes, one render: [LAW:one-source-of-truth] violated by a
55
- * captured reference.
56
- *
57
- * The getter costs nothing structurally. `FuncMap` entries are data in the
58
- * engine and their bodies run at *evaluate* time, so reading the palette
59
- * through a getter leaves parse-once/evaluate-many completely intact. What the
60
- * getter must not change is *which functions exist* — and it cannot, because
61
- * the two names here do not depend on the palette's contents. That was not
62
- * true of the generated per-variable functions, which is the second reason
63
- * they are gone.
64
- */
65
- import { resolveColorRef } from "../themes/colorRef.js";
66
- import { ColorRamp, parseRampEasing } from "../themes/ramp.js";
67
- /**
68
- * The `(position, color-ref)` pairs a `ramp` call's tail spells, as stops.
69
- *
70
- * The engine's `alternating` gate has already typed every even slot as a
71
- * float and every odd slot as a string; what it cannot see is the *pairing*
72
- * — a trailing position with no color — nor that the string is a color
73
- * reference. Both are settled here, once, and `ColorRamp` receives resolved
74
- * stops it never re-checks. [LAW:parse-dont-validate]
75
- *
76
- * Each reference resolves against the palette of *this* evaluation, so a
77
- * ramp over palette names follows the theme exactly as `color` does.
78
- */
79
- function colorStops(tail, palette) {
80
- if (tail.length === 0) {
81
- throw new RangeError(`ramp needs at least one stop after the easing: ramp <value> <easing> <position> <color> …`);
82
- }
83
- if (tail.length % 2 !== 0) {
84
- throw new RangeError(`ramp's last stop (position ${String(tail[tail.length - 1])}) has no color — ` +
85
- `stops are <position> <color> pairs`);
86
- }
87
- const stops = [];
88
- for (let i = 0; i < tail.length; i += 2) {
89
- stops.push({
90
- at: tail[i],
91
- color: resolveColorRef(palette, tail[i + 1]),
92
- });
93
- }
94
- return stops;
95
- }
96
- /**
97
- * Register `color "name-or-hex"` against a live palette.
98
- *
99
- * `color` resolves a palette variable name to a `#RRGGBB` string, and passes
100
- * an already-literal color through unchanged. That second half is not a
101
- * convenience — it makes `color` **idempotent**, which is what lets consumers
102
- * apply it unconditionally to any author-written color string without first
103
- * asking whether it is a name or already a color. [LAW:dataflow-not-control-flow]
104
- *
105
- * An unknown name throws, carrying near-miss suggestions from the live
106
- * palette. In a template that surfaces as an evaluation error at the exact
107
- * call site, which is the signal an author (or an agent editing a config) needs
108
- * to fix it. [LAW:no-silent-failure]
109
- *
110
- * @example
111
- * ```ts
112
- * const engine = createEngine({
113
- * fromString: (s) => new RichText(s),
114
- * toString: (rt) => rt.plain,
115
- * funcs: {
116
- * ...richTextFuncs(),
117
- * ...colorFuncs(),
118
- * ...paletteFuncs(() => currentTheme.palette),
119
- * },
120
- * });
121
- * ```
122
- */
123
- export function paletteFuncs(getPalette) {
124
- const colorFunc = {
125
- fn: ((ref) => resolveColorRef(getPalette(), ref).hex),
126
- argTypes: ["string"],
127
- returnType: "string",
128
- };
129
- // `ramp <value> <easing> <position> <color> …` — the argument list is one
130
- // float/string cycle end to end (value, easing, then each stop's position
131
- // and color), so the engine's `alternating` gate types every slot; the
132
- // pairing and the references are parsed in `colorStops`.
133
- // [LAW:types-are-the-program]
134
- const rampFunc = {
135
- fn: ((...args) => {
136
- // The engine's `alternating` gate types each slot but sets no minimum
137
- // count, so `{{ ramp }}` and `{{ ramp 65 }}` both reach here: one
138
- // check over the whole list, naming what is missing. [LAW:no-silent-failure]
139
- if (args.length < 2) {
140
- throw new RangeError(`ramp needs a value and an easing before its stops (got ${args.length}): ` +
141
- `ramp <value> "linear"|"step" <position> <color> …`);
142
- }
143
- const [value, easing, ...tail] = args;
144
- return new ColorRamp(parseRampEasing(easing), colorStops(tail, getPalette())).at(value).hex;
145
- }),
146
- argTypes: ["float", "string"],
147
- argTypePattern: "alternating",
148
- returnType: "string",
149
- };
150
- return { color: colorFunc, ramp: rampFunc };
151
- }
@@ -1,28 +0,0 @@
1
- /**
2
- * Style-function registrations for the rich-js template binding.
3
- *
4
- * [LAW:one-source-of-truth] The function inventory below mirrors the
5
- * string-syntax style vocabulary documented in `docs/style.md` — the two
6
- * colour slots (`fg`/`bg`), text attributes (positive + negated), short
7
- * aliases, and the hyperlink. Each registration is a templating-time analogue
8
- * of a piece of `Style.parse`, so a template fragment composed by these
9
- * functions round-trips through `Style` without semantic drift.
10
- *
11
- * [LAW:dataflow-not-control-flow] Every function follows the same
12
- * shape: child `RichText` in, `RichText` out. The styling difference
13
- * lives in a captured `Style` value (or constructor closure), not in
14
- * branches inside a single dispatch. That is why this file is mostly
15
- * factories — the data (the colour, the attribute name) is the
16
- * variability; the operation is fixed.
17
- */
18
- import type { FuncMap } from "@promptctl/go-template-js";
19
- /**
20
- * Text-styling registrations: the two colour sinks (`fg`, `bg`), text
21
- * attributes (canonical names, short aliases, and `not_*` negations), the
22
- * hyperlink cell-splitter (`link`), and the multi-attribute `style` spec.
23
- *
24
- * Colours themselves come from elsewhere: `colorFuncs()` for the palette-free
25
- * math, `paletteFuncs()` for naming a theme colour. This module only paints.
26
- * [LAW:one-way-deps] — nothing here imports a palette.
27
- */
28
- export declare function richTextStyleFuncs(): FuncMap;