@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,139 +0,0 @@
1
- /**
2
- * Strip + Joiner — edge-aware horizontal layout primitive.
3
- *
4
- * A `Strip` renders a horizontal sequence of styled items with a `Joiner`
5
- * deciding how each transition between adjacent items looks. The joiner is
6
- * a pure function of `(leftItem | null, rightItem | null) -> Renderable`,
7
- * so endpoint joins (the start and end of the strip) are explicit positions
8
- * in the protocol — the joiner names what an endpoint looks like rather than
9
- * the strip guessing.
10
- *
11
- * [LAW:one-source-of-truth] The render walk
12
- * joiner(null, items[0]), items[0],
13
- * joiner(items[0], items[1]), items[1], ...,
14
- * joiner(items[N-1], null)
15
- * is the single authority for how strips lay out. Every joiner participates
16
- * in the same protocol; "look up the previous segment's bg" is no longer a
17
- * powerline-specific hack but the contract every joiner shares.
18
- *
19
- * [LAW:locality-or-seam] The joiner protocol asks each item only for its
20
- * *edge* style — the column adjacent to the joiner — not for a single
21
- * whole-item style. This pushes the bg-uniformity requirement out of the
22
- * cell type and into the narrowest place that actually needs it: the column
23
- * boundary. Items with uniform styling report the same style at both edges;
24
- * items with varying styling report the actual boundary column. There is no
25
- * single-style invariant on the cell type — the terminal supports per-column
26
- * styling, so the cell type does too.
27
- */
28
- import { Segment } from "./segment.js";
29
- import { Style } from "./style.js";
30
- import type { Renderable, RenderOptions } from "./protocol.js";
31
- /**
32
- * Items in a `Strip` expose their per-edge style so joiners can paint the
33
- * transition glyph at each boundary.
34
- *
35
- * `edgeStyle("left", options)` reports the style of the item's leftmost cell
36
- * column; `edgeStyle("right", options)` reports the rightmost. Joiners read
37
- * only these — the item's interior may carry any per-column variation without
38
- * breaking the join.
39
- *
40
- * The edge is asked in a render, with that render's options, because a style
41
- * name only becomes a colour against the render's theme. A joiner therefore
42
- * reads edges inside the `render` of what it returns, never in `join`.
43
- */
44
- export interface StyledRenderable extends Renderable {
45
- edgeStyle(side: "left" | "right", options: RenderOptions): Style;
46
- }
47
- export interface Joiner<T extends StyledRenderable = StyledRenderable> {
48
- /**
49
- * `left === null` marks the start endpoint; `right === null` marks the end
50
- * endpoint. The joiner decides what an endpoint looks like — typically
51
- * fg-only with no bg so the strip blends into the terminal background.
52
- */
53
- join(left: T | null, right: T | null): Renderable;
54
- }
55
- export declare class Strip<T extends StyledRenderable = StyledRenderable> implements Renderable {
56
- readonly items: readonly T[];
57
- readonly joiner: Joiner<T>;
58
- constructor(items: readonly T[], joiner: Joiner<T>);
59
- render(options: RenderOptions): Iterable<Segment>;
60
- }
61
- /**
62
- * The least ΔE_OK two neighbouring backgrounds must differ by for the powerline
63
- * arrow between them to be seen. Below it the arrow is drawn in a colour the
64
- * eye cannot tell from its own background, so the joiner draws the divider
65
- * instead. Twice the ~.02 threshold of a visible difference, because a seam is
66
- * one cell wide.
67
- */
68
- export declare const SEAM_MIN_DELTA_E = 0.04;
69
- export interface PowerlineJoinerOptions {
70
- /** Glyph for every join between two coloured items. */
71
- glyph: string;
72
- /**
73
- * Glyph drawn between neighbours whose backgrounds the eye cannot tell apart,
74
- * in the left item's text colour — the arrow itself would vanish into the
75
- * shared background.
76
- */
77
- divider: string;
78
- /**
79
- * Glyph for every join a coloured item is entered from nothing — the strip's
80
- * start, or a colourless left neighbour — painted in the right item's
81
- * background. `""` begins a coloured run flat.
82
- */
83
- lead: string;
84
- /**
85
- * Glyph for every join a coloured item leaves into nothing — the strip's end,
86
- * or a colourless right neighbour — painted in the left item's background.
87
- * `""` ends a coloured run flat.
88
- */
89
- tail: string;
90
- }
91
- /**
92
- * The powerline set: U+E0B0 (right-arrow) divided by U+E0B1 (thin right-arrow),
93
- * led by U+E0B2 (left-arrow) and tailed by the arrow itself — so a strip's two
94
- * ends are one shape.
95
- */
96
- export declare const POWERLINE_JOINER_GLYPHS: Readonly<PowerlineJoinerOptions>;
97
- export declare class PowerlineJoiner<T extends StyledRenderable = StyledRenderable> implements Joiner<T> {
98
- private readonly _glyph;
99
- private readonly _divider;
100
- private readonly _lead;
101
- private readonly _tail;
102
- constructor(options?: PowerlineJoinerOptions);
103
- join(left: T | null, right: T | null): Renderable;
104
- }
105
- export interface CapsuleJoinerOptions {
106
- /** Left-cap glyph (default: U+E0B6, powerline rounded left). */
107
- left?: string;
108
- /** Right-cap glyph (default: U+E0B4, powerline rounded right). */
109
- right?: string;
110
- /** Separator inserted between adjacent capsules in the middle position. */
111
- separator?: string;
112
- }
113
- export declare class CapsuleJoiner<T extends StyledRenderable = StyledRenderable> implements Joiner<T> {
114
- private readonly _left;
115
- private readonly _right;
116
- private readonly _separator;
117
- constructor(options?: CapsuleJoinerOptions);
118
- _emit(left: T | null, right: T | null, options: RenderOptions): Iterable<Segment>;
119
- join(left: T | null, right: T | null): Renderable;
120
- }
121
- export interface PlainJoinerOptions {
122
- separator?: string;
123
- style?: Style;
124
- }
125
- export declare class PlainJoiner<T extends StyledRenderable = StyledRenderable> implements Joiner<T> {
126
- private readonly _separator;
127
- private readonly _style;
128
- constructor(options?: PlainJoinerOptions);
129
- join(left: T | null, right: T | null): Renderable;
130
- }
131
- export interface GradientJoinerOptions {
132
- /** Number of cells between adjacent items (default: 4). */
133
- steps?: number;
134
- }
135
- export declare class GradientJoiner<T extends StyledRenderable = StyledRenderable> implements Joiner<T> {
136
- private readonly _steps;
137
- constructor(options?: GradientJoinerOptions);
138
- join(left: T | null, right: T | null): Renderable;
139
- }
@@ -1,302 +0,0 @@
1
- /**
2
- * Strip + Joiner — edge-aware horizontal layout primitive.
3
- *
4
- * A `Strip` renders a horizontal sequence of styled items with a `Joiner`
5
- * deciding how each transition between adjacent items looks. The joiner is
6
- * a pure function of `(leftItem | null, rightItem | null) -> Renderable`,
7
- * so endpoint joins (the start and end of the strip) are explicit positions
8
- * in the protocol — the joiner names what an endpoint looks like rather than
9
- * the strip guessing.
10
- *
11
- * [LAW:one-source-of-truth] The render walk
12
- * joiner(null, items[0]), items[0],
13
- * joiner(items[0], items[1]), items[1], ...,
14
- * joiner(items[N-1], null)
15
- * is the single authority for how strips lay out. Every joiner participates
16
- * in the same protocol; "look up the previous segment's bg" is no longer a
17
- * powerline-specific hack but the contract every joiner shares.
18
- *
19
- * [LAW:locality-or-seam] The joiner protocol asks each item only for its
20
- * *edge* style — the column adjacent to the joiner — not for a single
21
- * whole-item style. This pushes the bg-uniformity requirement out of the
22
- * cell type and into the narrowest place that actually needs it: the column
23
- * boundary. Items with uniform styling report the same style at both edges;
24
- * items with varying styling report the actual boundary column. There is no
25
- * single-style invariant on the cell type — the terminal supports per-column
26
- * styling, so the cell type does too.
27
- */
28
- import { Segment } from "./segment.js";
29
- import { Style } from "./style.js";
30
- import { ColorDepth, ColorSpec, blendRgb } from "./color.js";
31
- import { Oklch } from "./oklch.js";
32
- // --- Strip ---
33
- export class Strip {
34
- items;
35
- joiner;
36
- constructor(items, joiner) {
37
- this.items = items;
38
- this.joiner = joiner;
39
- }
40
- *render(options) {
41
- const items = this.items;
42
- if (items.length === 0)
43
- return;
44
- // [LAW:dataflow-not-control-flow] The walk is the same shape every render:
45
- // start-cap, item, mid-join, item, ..., item, end-cap. Variability lives
46
- // in `items` and in what the joiner emits at each position — never in
47
- // whether a join runs.
48
- yield* this.joiner.join(null, items[0]).render(options);
49
- for (let i = 0; i < items.length; i++) {
50
- const item = items[i];
51
- yield* item.render(options);
52
- const next = i + 1 < items.length ? items[i + 1] : null;
53
- yield* this.joiner.join(item, next).render(options);
54
- }
55
- // [LAW:one-source-of-truth] `Strip`'s sibling `FlexStrip` ends every line
56
- // it emits, including the last, and the other block-level renderables
57
- // (`Panel`/`Rule`/`Table` structurally, `RichText` via `end`) do too — so
58
- // `Group` can emit children back to back with nothing in between
59
- // (docs/group.md). A `Strip` that left its last line open broke only
60
- // under composition: printed alone, Console's own "close whatever the
61
- // renderable left open" step (console.ts) papered over it, and a `Group`
62
- // of a Strip and a RichText ran the RichText onto the Strip's line
63
- // instead of below it. (Not every renderable follows this — a `Spinner`
64
- // or `ProgressBar` is a line *fragment*, not a block; see
65
- // rich-flexstrip-5kf.4cq for the open question of formalizing that split.)
66
- yield Segment.line();
67
- }
68
- }
69
- // --- Helpers ---
70
- const EMPTY = {
71
- *render(_options) {
72
- // intentionally empty
73
- },
74
- };
75
- class FixedSegment {
76
- _text;
77
- _style;
78
- constructor(text, style) {
79
- this._text = text;
80
- this._style = style;
81
- }
82
- *render(_options) {
83
- yield new Segment(this._text, this._style);
84
- }
85
- }
86
- /** A renderable whose segments are computed from the options it is rendered with. */
87
- function deferred(emit) {
88
- return { render: emit };
89
- }
90
- // Endpoint and powerline join glyphs paint the adjacent item's edge bg
91
- // *as* their fg. If the edge has no bgcolor, the glyph degrades to the
92
- // default fg — which renders as nothing visible against the terminal
93
- // background, the right outcome for an unstyled edge.
94
- function bgAsFg(edge) {
95
- return new Style({ color: edge.bgcolor });
96
- }
97
- // A bg with a real colour to paint. `undefined` (no bg) and the terminal
98
- // DEFAULT colour (transparent — identical to the terminal background) are the
99
- // two representations of "nothing to paint"; the powerline separator treats
100
- // them the same, so the gate cannot be fooled by an explicit `… on default`.
101
- function paintableBg(bg) {
102
- return bg !== undefined && !bg.isDefault ? bg : undefined;
103
- }
104
- // A cap or arrow is its cell continuing: that cell's ground as the writer draws
105
- // it, so a translucent ground is not composited a second time over whatever it
106
- // enters.
107
- function drawnGround(bg) {
108
- return new Style({ bgcolor: bg }).drawnColors().bgcolor;
109
- }
110
- // A cap is its glyph in its cell's ground, and "" is a flat end: no glyph, so
111
- // no segment — the same output as a join with nothing to paint.
112
- function* cap(glyph, bg) {
113
- if (glyph !== "")
114
- yield new Segment(glyph, new Style({ color: drawnGround(bg) }));
115
- }
116
- // --- PowerlineJoiner ---
117
- /**
118
- * The least ΔE_OK two neighbouring backgrounds must differ by for the powerline
119
- * arrow between them to be seen. Below it the arrow is drawn in a colour the
120
- * eye cannot tell from its own background, so the joiner draws the divider
121
- * instead. Twice the ~.02 threshold of a visible difference, because a seam is
122
- * one cell wide.
123
- */
124
- export const SEAM_MIN_DELTA_E = 0.04;
125
- // An arrow the eye cannot tell from the ground it is drawn on. What is
126
- // measured is what is drawn — `Style.drawnColors`, the colours the writer
127
- // encodes: the arrow's colour flattened onto its ground and the ground onto
128
- // the terminal's black, both downgraded to the depth the render encodes at,
129
- // so two grounds 256 colours round to one cube entry are the one entry they
130
- // render as. A colour whose RGB is the terminal theme's own (ANSI 0–15) has no
131
- // value here, so two of them are the same only when they are the same palette
132
- // slot — its `number`, never the name or the depth that spells it ("red",
133
- // "color(1)", an EIGHT_BIT spec on 0–15 are one slot).
134
- function vanishes(arrow, colorSystem) {
135
- // No colour emitted draws nothing to tell apart; measure what was handed.
136
- const { color, bgcolor } = arrow.drawnColors(colorSystem ?? ColorDepth.TRUECOLOR);
137
- if (color === undefined || bgcolor === undefined)
138
- return false;
139
- const av = color.fixedValue;
140
- const bv = bgcolor.fixedValue;
141
- return av !== undefined && bv !== undefined
142
- ? Oklch.fromRgba(av).deltaE(Oklch.fromRgba(bv)) < SEAM_MIN_DELTA_E
143
- : color.number === bgcolor.number;
144
- }
145
- /**
146
- * The powerline set: U+E0B0 (right-arrow) divided by U+E0B1 (thin right-arrow),
147
- * led by U+E0B2 (left-arrow) and tailed by the arrow itself — so a strip's two
148
- * ends are one shape.
149
- */
150
- export const POWERLINE_JOINER_GLYPHS = Object.freeze({
151
- glyph: "\ue0b0",
152
- divider: "\ue0b1",
153
- lead: "\ue0b2",
154
- tail: "\ue0b0",
155
- });
156
- export class PowerlineJoiner {
157
- _glyph;
158
- _divider;
159
- _lead;
160
- _tail;
161
- constructor(options = POWERLINE_JOINER_GLYPHS) {
162
- this._glyph = options.glyph;
163
- this._divider = options.divider;
164
- this._lead = options.lead;
165
- this._tail = options.tail;
166
- }
167
- join(left, right) {
168
- // [LAW:dataflow-not-control-flow] One table for all three positions (start
169
- // cap, mid-join, end cap), read off which side has a colour to paint. The
170
- // endpoints are not control-flow special cases; they are the DATA cases
171
- // where a neighbour (hence its bg) is absent:
172
- // • both bgs — the arrow in the LEFT bg (the colour bleeding rightward)
173
- // over the RIGHT bg.
174
- // • left bg only — the end cap, OR a coloured item before a colourless
175
- // one — the tail bleeds the left colour out over the terminal
176
- // background (fg = left bg, no bg).
177
- // • right bg only — the start cap, OR a colourless item before a coloured
178
- // one — the lead: the right colour reaching back over the terminal
179
- // background (fg = right bg, no bg).
180
- // • neither — nothing to paint, so the join yields nothing.
181
- // Equal REAL bgs still emit: a same-bg seam between two distinct items is a
182
- // structural boundary, never suppressed. The arrow would be drawn in its own
183
- // background colour there and vanish, so the seam is the DIVIDER instead, in
184
- // the left item's text colour — the vim-airline convention for neighbours
185
- // that share a background. "Equal" is perceptual (SEAM_MIN_DELTA_E) and
186
- // measured on the colours the terminal draws at `options.colorSystem`: an
187
- // arrow a hair off its background is as invisible as one exactly on it,
188
- // and two backgrounds 256 colours round to one entry are one background.
189
- // Background colour is paint, not structure; its ABSENCE (nothing to paint)
190
- // is the only thing that elides the separator, and that is paint logic.
191
- // "Absent" = no bg OR the terminal default (transparent) — paintableBg folds
192
- // both to undefined so an explicit `… on default` cannot smuggle a separator.
193
- const glyph = this._glyph;
194
- const divider = this._divider;
195
- const lead = this._lead;
196
- const tail = this._tail;
197
- return deferred(function* (options) {
198
- const leftEdge = left?.edgeStyle("right", options);
199
- const leftBg = paintableBg(leftEdge?.bgcolor);
200
- const rightBg = paintableBg(right?.edgeStyle("left", options).bgcolor);
201
- if (leftBg === undefined) {
202
- if (rightBg !== undefined)
203
- yield* cap(lead, rightBg);
204
- return;
205
- }
206
- if (rightBg === undefined) {
207
- yield* cap(tail, leftBg);
208
- return;
209
- }
210
- const arrow = new Style({ color: drawnGround(leftBg), bgcolor: rightBg });
211
- // The divider is the left item's text on the left item's own ground,
212
- // so it reads exactly as well as that item's text does, at any depth.
213
- yield vanishes(arrow, options.colorSystem)
214
- ? new Segment(divider, new Style({ color: leftEdge?.color, bgcolor: leftBg }))
215
- : new Segment(glyph, arrow);
216
- });
217
- }
218
- }
219
- export class CapsuleJoiner {
220
- _left;
221
- _right;
222
- _separator;
223
- constructor(options) {
224
- this._left = options?.left ?? "";
225
- this._right = options?.right ?? "";
226
- this._separator = options?.separator ?? " ";
227
- }
228
- *_emit(left, right, options) {
229
- if (left === null && right === null)
230
- return;
231
- if (left === null) {
232
- yield new Segment(this._left, bgAsFg(right.edgeStyle("left", options)));
233
- return;
234
- }
235
- if (right === null) {
236
- yield new Segment(this._right, bgAsFg(left.edgeStyle("right", options)));
237
- return;
238
- }
239
- // Middle: close the left capsule, separator (unstyled), open the right.
240
- yield new Segment(this._right, bgAsFg(left.edgeStyle("right", options)));
241
- if (this._separator.length > 0)
242
- yield new Segment(this._separator);
243
- yield new Segment(this._left, bgAsFg(right.edgeStyle("left", options)));
244
- }
245
- join(left, right) {
246
- return deferred((options) => this._emit(left, right, options));
247
- }
248
- }
249
- export class PlainJoiner {
250
- _separator;
251
- _style;
252
- constructor(options) {
253
- this._separator = options?.separator ?? " | ";
254
- this._style = options?.style ?? Style.parse("dim");
255
- }
256
- join(left, right) {
257
- // Endpoints are empty — a fixed separator has no natural cap.
258
- if (left === null || right === null)
259
- return EMPTY;
260
- return new FixedSegment(this._separator, this._style);
261
- }
262
- }
263
- /**
264
- * Half-block dithering glyph: paints the cell's left half with the foreground
265
- * colour and the right half with the background colour. Lets each cell carry
266
- * two colour samples — `2 * steps` samples in `steps` cells — so the gradient
267
- * looks twice as smooth as one-colour-per-cell at the same width.
268
- */
269
- const HALF_BLOCK = "▌"; // ▌
270
- export class GradientJoiner {
271
- _steps;
272
- constructor(options) {
273
- this._steps = options?.steps ?? 4;
274
- }
275
- join(left, right) {
276
- // [LAW:dataflow-not-control-flow] Endpoints have no opposite anchor to
277
- // interpolate toward — the data (a missing neighbor) makes the gradient
278
- // empty. Same for edges lacking a bgcolor: nothing to blend between.
279
- if (left === null || right === null)
280
- return EMPTY;
281
- const steps = this._steps;
282
- return deferred(function* (options) {
283
- const lbg = left.edgeStyle("right", options).bgcolor;
284
- const rbg = right.edgeStyle("left", options).bgcolor;
285
- if (!lbg || !rbg)
286
- return;
287
- const lTrip = lbg.getTruecolor();
288
- const rTrip = rbg.getTruecolor();
289
- const samples = 2 * steps;
290
- // Midpoint sampling across `2 * steps` half-cell positions: sample j has
291
- // t = (j + 0.5) / samples. Cell i takes samples 2i (left half) and 2i+1
292
- // (right half). No sample ever equals either anchor.
293
- for (let i = 0; i < steps; i++) {
294
- const tLeft = (2 * i + 0.5) / samples;
295
- const tRight = (2 * i + 1.5) / samples;
296
- const fg = ColorSpec.fromRgba(blendRgb(lTrip, rTrip, tLeft));
297
- const bg = ColorSpec.fromRgba(blendRgb(lTrip, rTrip, tRight));
298
- yield new Segment(HALF_BLOCK, new Style({ color: fg, bgcolor: bg }));
299
- }
300
- });
301
- }
302
- }
@@ -1,149 +0,0 @@
1
- /**
2
- * Immutable style descriptors — colors, text attributes, links, metadata.
3
- */
4
- import { ColorSpec, ColorDepth } from "./color.js";
5
- /**
6
- * Canonical text-attribute inventory. Single source of truth consumed by
7
- * `Style.parse` / `Style.toString` and the template bindings — adding an
8
- * attribute here propagates to every styling surface without a second
9
- * list to keep in sync. [LAW:one-source-of-truth]
10
- */
11
- export declare const ATTRIBUTE_NAMES: readonly ["bold", "dim", "italic", "underline", "blink", "blink2", "reverse", "conceal", "strike", "underline2", "frame", "encircle", "overline"];
12
- export type AttributeName = (typeof ATTRIBUTE_NAMES)[number];
13
- /**
14
- * Canonical short-attribute aliases (`b` → `bold`, `i` → `italic`, …).
15
- * Single source of truth consumed by `Style.parse` and the template
16
- * bindings — adding an alias here makes it available everywhere.
17
- * [LAW:one-source-of-truth]
18
- */
19
- export declare const ATTRIBUTE_SHORT_ALIASES: Record<string, AttributeName>;
20
- export interface StyleOptions {
21
- color?: string | ColorSpec;
22
- bgcolor?: string | ColorSpec;
23
- bold?: boolean;
24
- dim?: boolean;
25
- italic?: boolean;
26
- underline?: boolean;
27
- blink?: boolean;
28
- blink2?: boolean;
29
- reverse?: boolean;
30
- conceal?: boolean;
31
- strike?: boolean;
32
- underline2?: boolean;
33
- frame?: boolean;
34
- encircle?: boolean;
35
- overline?: boolean;
36
- link?: string;
37
- meta?: Record<string, unknown>;
38
- }
39
- export declare class StyleSyntaxError extends Error {
40
- constructor(message: string, options?: ErrorOptions);
41
- }
42
- export declare class Style {
43
- readonly color: ColorSpec | undefined;
44
- readonly bgcolor: ColorSpec | undefined;
45
- readonly bold: boolean | undefined;
46
- readonly dim: boolean | undefined;
47
- readonly italic: boolean | undefined;
48
- readonly underline: boolean | undefined;
49
- readonly blink: boolean | undefined;
50
- readonly blink2: boolean | undefined;
51
- readonly reverse: boolean | undefined;
52
- readonly conceal: boolean | undefined;
53
- readonly strike: boolean | undefined;
54
- readonly underline2: boolean | undefined;
55
- readonly frame: boolean | undefined;
56
- readonly encircle: boolean | undefined;
57
- readonly overline: boolean | undefined;
58
- readonly link: string | undefined;
59
- readonly meta: Record<string, unknown> | undefined;
60
- constructor(options?: StyleOptions);
61
- get isNull(): boolean;
62
- get transparentBackground(): boolean;
63
- get backgroundStyle(): Style;
64
- get withoutColor(): Style;
65
- withLink(link: string | undefined): Style;
66
- clearMetaAndLinks(): Style;
67
- /**
68
- * Merges two styles. `other`'s values take priority.
69
- */
70
- add(other: Style | undefined): Style;
71
- equals(other: Style): boolean;
72
- /**
73
- * The colours this style puts on screen at `colorSystem`: each flattened
74
- * onto what lies beneath it — the background onto the terminal's black, the
75
- * foreground onto that background — then downgraded to the depth. The one
76
- * account of what a style draws: `toSgrCodes` encodes exactly these, and a
77
- * renderable choosing between two ways of drawing measures them.
78
- */
79
- drawnColors(colorSystem?: ColorDepth): {
80
- readonly color: ColorSpec | undefined;
81
- readonly bgcolor: ColorSpec | undefined;
82
- };
83
- /**
84
- * Returns the SGR parameter list this style emits (e.g. `"1;31;48;2;0;0;255"`),
85
- * or `""` when the style has no SGR contribution. Excludes OSC 8 link bytes —
86
- * links are not SGR. The Strip renderer uses this string as the group key for
87
- * adjacent-same-style coalescing; the per-segment `render` path wraps the
88
- * returned codes in `\x1b[...m`.
89
- *
90
- * [LAW:one-source-of-truth] One computation of SGR codes — both `render` and
91
- * the segment coalescer derive from this.
92
- */
93
- toSgrCodes(colorSystem?: ColorDepth): string;
94
- /**
95
- * Render text with this style's ANSI escape codes.
96
- */
97
- render(text: string, colorSystem?: ColorDepth): string;
98
- /**
99
- * Serializes to a canonical string that round-trips through `Style.parse()`.
100
- */
101
- toString(): string;
102
- static null(): Style;
103
- static fromColor(color?: ColorSpec, bgcolor?: ColorSpec): Style;
104
- static fromMeta(meta: Record<string, unknown>): Style;
105
- static pickFirst(...args: (Style | undefined)[]): Style;
106
- static combine(styles: (Style | undefined)[]): Style;
107
- static chain(...styles: (Style | undefined)[]): Style;
108
- static normalize(definition: string): string;
109
- /**
110
- * Parse a space-separated style definition. Cached.
111
- *
112
- * A definition only: `"bold red"` parses, `"repr.number"` does not. Names
113
- * belong to a `Theme`, and `Theme.resolve` is where one is looked up.
114
- */
115
- static parse(definition: string): Style;
116
- }
117
- export declare const NULL_STYLE: Style;
118
- export declare class StyleStack {
119
- private readonly stack;
120
- constructor(base?: Style);
121
- get current(): Style;
122
- push(style: Style): void;
123
- pop(): Style;
124
- }
125
- export declare class Theme {
126
- private readonly styles;
127
- constructor(definitions?: Record<string, string>, options?: {
128
- inherit?: boolean;
129
- });
130
- get(name: string): Style | undefined;
131
- /**
132
- * The style a `string | Style` stands for under this theme: a name this
133
- * theme defines, otherwise a definition for `Style.parse`, which throws
134
- * `StyleSyntaxError` when the string is neither.
135
- *
136
- * [LAW:one-source-of-truth] The theme is the one map from names to styles.
137
- * The lookup stays outside `Style.parse`'s process-wide cache on purpose:
138
- * cached there, the first console to resolve `repr.number` would decide it
139
- * for every console after it, whatever theme each was given.
140
- */
141
- resolve(style: string | Style): Style;
142
- has(name: string): boolean;
143
- }
144
- export declare const DEFAULT_STYLES: Record<string, Style>;
145
- /**
146
- * The theme a render resolves names against when nothing supplied one — what
147
- * a renderable sees outside a `Console`, as in `renderToString`.
148
- */
149
- export declare const DEFAULT_THEME: Theme;