@promptctl/rich-js 0.27.0 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -6
- package/THIRD-PARTY-NOTICES +42 -0
- package/dist/core/animation.d.ts +65 -46
- package/dist/core/animation.js +91 -67
- package/dist/core/ansi.d.ts +19 -12
- package/dist/core/ansi.js +114 -36
- package/dist/core/bidi-data.d.ts +14 -0
- package/dist/core/bidi-data.js +385 -0
- package/dist/core/bidi.d.ts +89 -0
- package/dist/core/bidi.js +615 -0
- package/dist/core/box.d.ts +9 -1
- package/dist/core/box.js +11 -0
- package/dist/core/cell-widths.d.ts +3 -2
- package/dist/core/cell-widths.js +93 -93
- package/dist/core/cells.d.ts +20 -0
- package/dist/core/cells.js +94 -6
- package/dist/core/clock.d.ts +1 -1
- package/dist/core/color.d.ts +56 -57
- package/dist/core/color.js +79 -81
- package/dist/core/console.d.ts +24 -7
- package/dist/core/console.js +27 -8
- package/dist/core/control-codes.d.ts +61 -0
- package/dist/core/control-codes.js +157 -0
- package/dist/core/easing.d.ts +40 -40
- package/dist/core/easing.js +40 -40
- package/dist/core/env.d.ts +6 -0
- package/dist/core/env.js +9 -1
- package/dist/core/export-html.js +5 -4
- package/dist/core/export-lines.d.ts +13 -11
- package/dist/core/export-lines.js +19 -15
- package/dist/core/export-svg.d.ts +3 -3
- package/dist/core/export-svg.js +10 -9
- package/dist/core/json.js +9 -2
- package/dist/core/markup.js +5 -4
- package/dist/core/memo.d.ts +1 -1
- package/dist/core/memo.js +1 -1
- package/dist/core/oklch.d.ts +14 -14
- package/dist/core/oklch.js +10 -10
- package/dist/core/orient.d.ts +68 -0
- package/dist/core/orient.js +224 -0
- package/dist/core/osc8.d.ts +12 -5
- package/dist/core/osc8.js +14 -7
- package/dist/core/paint.d.ts +9 -9
- package/dist/core/paint.js +3 -3
- package/dist/core/pretty.d.ts +1 -1
- package/dist/core/pretty.js +23 -19
- package/dist/core/protocol.d.ts +47 -26
- package/dist/core/protocol.js +31 -23
- package/dist/core/render.d.ts +19 -14
- package/dist/core/render.js +30 -17
- package/dist/core/seal.d.ts +26 -0
- package/dist/core/seal.js +75 -0
- package/dist/core/segment.d.ts +12 -4
- package/dist/core/segment.js +16 -6
- package/dist/core/strip.d.ts +83 -83
- package/dist/core/strip.js +70 -70
- package/dist/core/style.d.ts +46 -18
- package/dist/core/style.js +92 -56
- package/dist/core/text-order.d.ts +51 -0
- package/dist/core/text-order.js +50 -0
- package/dist/core/text.d.ts +12 -2
- package/dist/core/text.js +136 -90
- package/dist/core/timeline.d.ts +5 -5
- package/dist/core/timeline.js +11 -11
- package/dist/core/tween.d.ts +6 -6
- package/dist/core/tween.js +10 -10
- package/dist/core/view.d.ts +5 -5
- package/dist/core/view.js +15 -14
- package/dist/core/wrap.d.ts +24 -6
- package/dist/core/wrap.js +82 -16
- package/dist/host/app.d.ts +50 -9
- package/dist/host/app.js +120 -15
- package/dist/host/host-environment.d.ts +2 -2
- package/dist/host/host-environment.js +2 -2
- package/dist/host/index.d.ts +3 -2
- package/dist/host/index.js +1 -0
- package/dist/host/input.d.ts +42 -9
- package/dist/host/input.js +91 -7
- package/dist/host/terminal-colors.d.ts +18 -0
- package/dist/host/terminal-colors.js +46 -0
- package/dist/host/terminal-host.d.ts +4 -3
- package/dist/host/terminal-host.js +1 -1
- package/dist/index.d.ts +17 -16
- package/dist/index.js +11 -11
- package/dist/node/prompt.d.ts +1 -1
- package/dist/node/prompt.js +1 -1
- package/dist/node/terminal-host.d.ts +1 -1
- package/dist/node/traceback.js +2 -2
- package/dist/renderables/change.d.ts +1 -3
- package/dist/renderables/change.js +6 -8
- package/dist/renderables/effect.d.ts +88 -87
- package/dist/renderables/effect.js +124 -114
- package/dist/renderables/effects.d.ts +105 -76
- package/dist/renderables/effects.js +309 -176
- package/dist/renderables/embed.d.ts +1 -1
- package/dist/renderables/embed.js +2 -2
- package/dist/renderables/flexStrip.d.ts +7 -7
- package/dist/renderables/flexStrip.js +15 -15
- package/dist/renderables/frames.d.ts +7 -16
- package/dist/renderables/frames.js +12 -27
- package/dist/renderables/glyph-effect.d.ts +22 -23
- package/dist/renderables/glyph-effect.js +43 -41
- package/dist/renderables/glyph-effects.d.ts +33 -14
- package/dist/renderables/glyph-effects.js +90 -22
- package/dist/renderables/html-entities.d.ts +1 -1
- package/dist/renderables/html-entities.js +1 -1
- package/dist/renderables/lifecycle.d.ts +8 -10
- package/dist/renderables/lifecycle.js +17 -18
- package/dist/renderables/live.d.ts +2 -2
- package/dist/renderables/live.js +7 -7
- package/dist/renderables/markdown-parse.js +3 -3
- package/dist/renderables/markdown.js +4 -2
- package/dist/renderables/panel.js +7 -5
- package/dist/renderables/progress.d.ts +1 -1
- package/dist/renderables/progress.js +1 -1
- package/dist/renderables/progressBar.d.ts +3 -3
- package/dist/renderables/progressBar.js +21 -18
- package/dist/renderables/prompt.d.ts +1 -1
- package/dist/renderables/scroll.d.ts +1 -1
- package/dist/renderables/scroll.js +3 -3
- package/dist/renderables/spinner.d.ts +4 -4
- package/dist/renderables/spinner.js +10 -10
- package/dist/renderables/syntax.d.ts +2 -2
- package/dist/renderables/syntax.js +9 -4
- package/dist/renderables/table.js +5 -4
- package/dist/renderables/traceback.d.ts +1 -1
- package/dist/renderables/traceback.js +1 -1
- package/dist/renderables/tree.js +3 -3
- package/dist/template-bindings/animation-funcs.d.ts +60 -29
- package/dist/template-bindings/animation-funcs.js +126 -43
- package/dist/template-bindings/color-funcs.d.ts +14 -14
- package/dist/template-bindings/color-funcs.js +25 -25
- package/dist/template-bindings/index.d.ts +16 -14
- package/dist/template-bindings/index.js +17 -14
- package/dist/template-bindings/palette-funcs.d.ts +2 -2
- package/dist/template-bindings/palette-funcs.js +4 -4
- package/dist/template-bindings/style-funcs.d.ts +5 -5
- package/dist/template-bindings/style-funcs.js +16 -16
- package/dist/themes/{transpose.d.ts → adjust.d.ts} +23 -23
- package/dist/themes/{transpose.js → adjust.js} +28 -28
- package/dist/themes/buildPalette.d.ts +6 -5
- package/dist/themes/buildPalette.js +22 -22
- package/dist/themes/colorMath.d.ts +16 -16
- package/dist/themes/colorMath.js +32 -32
- package/dist/themes/data/ansi-tables.d.ts +2 -2
- package/dist/themes/data/ansi-tables.js +2 -2
- package/dist/themes/data/index.js +1 -4
- package/dist/themes/data/textual-ansi.js +0 -143
- package/dist/themes/data/types.d.ts +4 -4
- package/dist/themes/data/types.js +2 -2
- package/dist/themes/palette.d.ts +12 -12
- package/dist/themes/palette.js +16 -16
- package/dist/themes/ramp.d.ts +17 -17
- package/dist/themes/ramp.js +12 -12
- package/dist/themes/registry.d.ts +6 -8
- package/dist/themes/registry.js +6 -8
- package/dist/themes/terminalThemes.d.ts +4 -11
- package/dist/themes/terminalThemes.js +31 -47
- package/dist/widgets/button.d.ts +3 -3
- package/dist/widgets/button.js +8 -8
- package/dist/widgets/checkbox.d.ts +2 -2
- package/dist/widgets/checkbox.js +4 -4
- package/dist/widgets/dropdown.d.ts +3 -3
- package/dist/widgets/dropdown.js +7 -5
- package/dist/widgets/event-router.d.ts +6 -6
- package/dist/widgets/event-router.js +2 -2
- package/dist/widgets/focus-manager.d.ts +3 -3
- package/dist/widgets/focus-manager.js +3 -3
- package/dist/widgets/index.d.ts +2 -2
- package/dist/widgets/index.js +1 -1
- package/dist/widgets/ink.d.ts +3 -3
- package/dist/widgets/ink.js +4 -4
- package/dist/widgets/slider.d.ts +2 -2
- package/dist/widgets/static-item.d.ts +2 -2
- package/dist/widgets/text-input.d.ts +2 -2
- package/dist/widgets/text-input.js +5 -5
- package/dist/widgets/themed-widget.js +4 -4
- package/dist/widgets/toggle.d.ts +4 -4
- package/dist/widgets/toggle.js +6 -6
- package/dist/widgets/types.d.ts +6 -6
- package/dist/widgets/types.js +2 -2
- package/dist/widgets/widget-app.d.ts +10 -10
- package/dist/widgets/widget-app.js +8 -8
- package/dist/widgets/widget-base.d.ts +2 -2
- package/package.json +5 -4
package/dist/core/protocol.d.ts
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
* [LAW:one-source-of-truth] These interfaces are the single authority for the rendering contract.
|
|
4
4
|
*/
|
|
5
5
|
import type { Segment } from "./segment.js";
|
|
6
|
-
import { Style, type
|
|
7
|
-
import { ColorDepth } from "./color.js";
|
|
6
|
+
import { Style, type ValidityInterval, type StyleSyntaxError, type Theme } from "./style.js";
|
|
7
|
+
import { ColorDepth, type TerminalColors } from "./color.js";
|
|
8
|
+
import type { TextOrder } from "./text-order.js";
|
|
8
9
|
import type { Highlighter } from "./highlighter.js";
|
|
9
10
|
/**
|
|
10
11
|
* What becomes of a line still wider than its width once wrapping is done.
|
|
@@ -19,7 +20,7 @@ import type { Highlighter } from "./highlighter.js";
|
|
|
19
20
|
export type OverflowMethod = "fold" | "crop" | "ellipsis" | "ignore";
|
|
20
21
|
/**
|
|
21
22
|
* The frame being drawn, as a value: `time`, the moment it is drawn for, in
|
|
22
|
-
* seconds, on the clock its cells' `
|
|
23
|
+
* seconds, on the clock its cells' `validUntil` stamps are read on, and
|
|
23
24
|
* `host`, the identity of what drew it — nothing to read, so what draws in
|
|
24
25
|
* the frame has one time, this one, and cannot ask the host for another.
|
|
25
26
|
* [LAW:types-are-the-program] A `Progress` keeps the identity to refuse a
|
|
@@ -90,13 +91,24 @@ export interface RenderOptions {
|
|
|
90
91
|
*/
|
|
91
92
|
highlighter?: Highlighter;
|
|
92
93
|
/**
|
|
93
|
-
* The depth the output will be encoded at, `null` when it carries no
|
|
94
|
+
* The depth the output will be encoded at, `null` when it carries no color.
|
|
94
95
|
* A renderable that measures what it draws — the strip's joiner, holding a
|
|
95
|
-
* seam's ink off its ground — measures the
|
|
96
|
-
* this depth, which at 256
|
|
96
|
+
* seam's ink off its ground — measures the colors the terminal will draw at
|
|
97
|
+
* this depth, which at 256 colors or fewer are not the colors it was
|
|
97
98
|
* handed. Absent means truecolor.
|
|
98
99
|
*/
|
|
99
100
|
colorSystem?: ColorDepth | null;
|
|
101
|
+
/** What the output's destination does with direction. Absent is `"plain"`. */
|
|
102
|
+
textOrder?: TextOrder;
|
|
103
|
+
/**
|
|
104
|
+
* The terminal the output is drawn on: the colors a cell that sets none is
|
|
105
|
+
* drawn in, and the sixteen an ANSI color names. The terminal's own palette
|
|
106
|
+
* is never queried, so the program says what it is, once, where the output
|
|
107
|
+
* is decided; a renderable reads it here (`Effected`, `ProgressBar`) and
|
|
108
|
+
* nothing hands it down to one. Absent is the terminal the depth assumes
|
|
109
|
+
* (`resolveTerminal`).
|
|
110
|
+
*/
|
|
111
|
+
terminal?: TerminalColors;
|
|
100
112
|
/**
|
|
101
113
|
* The names a style string may use. A `Console` passes its own; absent, the
|
|
102
114
|
* built-in defaults apply. Read it through `getStyle` rather than directly.
|
|
@@ -111,11 +123,11 @@ export interface RenderOptions {
|
|
|
111
123
|
onStyleError?: StyleErrorHandler;
|
|
112
124
|
/**
|
|
113
125
|
* The reader asked for reduced motion — CSS's `prefers-reduced-motion`,
|
|
114
|
-
* which a terminal has no way to report, so a host is told.
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
126
|
+
* which a terminal has no way to report, so a host is told. Every placed
|
|
127
|
+
* animation is drawn reduced, its motion taken out and its content kept on
|
|
128
|
+
* time (`shownAt`, `Animation.reduced`, `./animation.ts`), and an `OutputTarget`
|
|
129
|
+
* told the same writes no blink (`shownOn`, `./render.ts`). Absent, everything
|
|
130
|
+
* moves. Nothing here reads it from the environment.
|
|
119
131
|
*/
|
|
120
132
|
reducedMotion?: boolean;
|
|
121
133
|
/**
|
|
@@ -130,13 +142,13 @@ export interface RenderOptions {
|
|
|
130
142
|
/**
|
|
131
143
|
* Told of every renderable `render` is asked for, as it is asked, so the
|
|
132
144
|
* calls arrive in document order: a container before what it holds, what
|
|
133
|
-
* it holds in the order it renders it. `"
|
|
134
|
-
* the width it was handed; `"
|
|
145
|
+
* it holds in the order it renders it. `"visible"` is a renderable drawn at
|
|
146
|
+
* the width it was handed; `"hidden"` is one handed no column, which is still
|
|
135
147
|
* in the view but has nothing drawn for it (`render`). A renderable rendered
|
|
136
148
|
* twice is told twice. A render made to measure is not drawing and is not
|
|
137
149
|
* told (`measuring`).
|
|
138
150
|
*/
|
|
139
|
-
|
|
151
|
+
onVisibility?: (renderable: Renderable, visibility: Visibility) => void;
|
|
140
152
|
/**
|
|
141
153
|
* Told of a hold the frame is in that no cell of it may carry: an animation
|
|
142
154
|
* placed in the view reports its own, whether or not it drew a cell — one
|
|
@@ -147,7 +159,16 @@ export interface RenderOptions {
|
|
|
147
159
|
* (`measuring`) and a held render (`holding`) tell too: what they find
|
|
148
160
|
* decides the frame's layout, so when it changes, the frame may.
|
|
149
161
|
*/
|
|
150
|
-
|
|
162
|
+
onValidity?: (validity: ValidityInterval) => void;
|
|
163
|
+
/**
|
|
164
|
+
* Told of the hold the element `key` names, drawn for a time on its own
|
|
165
|
+
* clock, is in: an effect's frame, which alone knows, since the answer
|
|
166
|
+
* depends on what it drew. `t` is that clock's, not the frame's, so this cannot be `onValidity`:
|
|
167
|
+
* the animation placed around the value carries the answer back through the
|
|
168
|
+
* combinators that remapped the time (`Reads`, `./animation.ts`). It reaches
|
|
169
|
+
* whatever `frame` reaches.
|
|
170
|
+
*/
|
|
171
|
+
onReads?: (t: number, key: string, validity: ValidityInterval) => void;
|
|
151
172
|
}
|
|
152
173
|
/** The one field of the render options that says whether the reader wants motion. */
|
|
153
174
|
export type Motion = Pick<RenderOptions, "reducedMotion">;
|
|
@@ -155,7 +176,7 @@ export type Motion = Pick<RenderOptions, "reducedMotion">;
|
|
|
155
176
|
* Whether a renderable the view holds was drawn, or held: in the view, handed
|
|
156
177
|
* no column, and so not drawn (`render`).
|
|
157
178
|
*/
|
|
158
|
-
export type
|
|
179
|
+
export type Visibility = "visible" | "hidden";
|
|
159
180
|
/** Whether `text` is all ASCII — what an `asciiOnly` output can draw. */
|
|
160
181
|
export declare const isAscii: (text: string) => boolean;
|
|
161
182
|
/**
|
|
@@ -264,19 +285,19 @@ export type StyleErrorHandler = (error: StyleSyntaxError, style: string) => void
|
|
|
264
285
|
export declare function getStyle(options: RenderOptions, style: string | Style): Style;
|
|
265
286
|
/**
|
|
266
287
|
* `style` as the depth the render is encoded at can draw it. A style that
|
|
267
|
-
* paints its own ground in fixed
|
|
268
|
-
* at sixteen
|
|
269
|
-
* the terminal paints in its own theme's
|
|
270
|
-
* every bundled theme. So where the depth would turn a fixed
|
|
288
|
+
* paints its own ground in fixed colors chose its ink and ground as a pair;
|
|
289
|
+
* at sixteen colors the writer rounds a fixed color to an ANSI slot, which
|
|
290
|
+
* the terminal paints in its own theme's color, and no pair of slots reads in
|
|
291
|
+
* every bundled theme. So where the depth would turn a fixed color of the
|
|
271
292
|
* pair into a slot, the pair is dropped and the run is drawn on the
|
|
272
293
|
* terminal's own foreground and background, which its theme does make
|
|
273
294
|
* readable; its attributes still set it apart. Both are named, not left
|
|
274
|
-
* unset, so the
|
|
275
|
-
* not show through: Rich's code keeps its own
|
|
276
|
-
* terminal's are the ones it keeps here. A style whose
|
|
295
|
+
* unset, so the color of whatever the run sits in — a quote, a link — does
|
|
296
|
+
* not show through: Rich's code keeps its own colors inside a quote, and the
|
|
297
|
+
* terminal's are the ones it keeps here. A style whose colors are
|
|
277
298
|
* slots already (`white on blue`), or that paints no ground (`bold magenta`),
|
|
278
|
-
* was written for the terminal's own
|
|
279
|
-
* draws a highlighted line number the same way below 256
|
|
299
|
+
* was written for the terminal's own colors and is drawn as written. Rich
|
|
300
|
+
* draws a highlighted line number the same way below 256 colors
|
|
280
301
|
* (`Syntax._get_number_styles`).
|
|
281
302
|
*/
|
|
282
303
|
export declare function groundedStyle(options: RenderOptions, style: Style): Style;
|
|
@@ -353,7 +374,7 @@ export declare function afterPass(effect: () => void): void;
|
|
|
353
374
|
* write during render is refused at: a `State` set in a pass that did not make
|
|
354
375
|
* it throws (`./state.ts`).
|
|
355
376
|
*
|
|
356
|
-
* It is also the one reporter of what the view holds (`
|
|
377
|
+
* It is also the one reporter of what the view holds (`onVisibility`). Under one
|
|
357
378
|
* column a renderable is held: in the view, with nothing of it on the frame.
|
|
358
379
|
* It is drawn all the same and what it drew dropped (`holding`), so what a held
|
|
359
380
|
* container is reported holding is what it draws, under the options it hands
|
package/dist/core/protocol.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* [LAW:one-source-of-truth] These interfaces are the single authority for the rendering contract.
|
|
4
4
|
*/
|
|
5
5
|
import { cellCount } from "./cells.js";
|
|
6
|
-
import { DEFAULT_THEME, Style } from "./style.js";
|
|
6
|
+
import { DEFAULT_THEME, NEVER_CHANGES, Style } from "./style.js";
|
|
7
7
|
/** Whether `text` is all ASCII — what an `asciiOnly` output can draw. */
|
|
8
8
|
export const isAscii = (text) => /^[\x00-\x7F]*$/.test(text);
|
|
9
9
|
export function drawable(options, chosen, ascii, glyphs = String) {
|
|
@@ -65,19 +65,19 @@ export function getStyle(options, style) {
|
|
|
65
65
|
const TERMINAL_GROUND = Style.parse("default on default");
|
|
66
66
|
/**
|
|
67
67
|
* `style` as the depth the render is encoded at can draw it. A style that
|
|
68
|
-
* paints its own ground in fixed
|
|
69
|
-
* at sixteen
|
|
70
|
-
* the terminal paints in its own theme's
|
|
71
|
-
* every bundled theme. So where the depth would turn a fixed
|
|
68
|
+
* paints its own ground in fixed colors chose its ink and ground as a pair;
|
|
69
|
+
* at sixteen colors the writer rounds a fixed color to an ANSI slot, which
|
|
70
|
+
* the terminal paints in its own theme's color, and no pair of slots reads in
|
|
71
|
+
* every bundled theme. So where the depth would turn a fixed color of the
|
|
72
72
|
* pair into a slot, the pair is dropped and the run is drawn on the
|
|
73
73
|
* terminal's own foreground and background, which its theme does make
|
|
74
74
|
* readable; its attributes still set it apart. Both are named, not left
|
|
75
|
-
* unset, so the
|
|
76
|
-
* not show through: Rich's code keeps its own
|
|
77
|
-
* terminal's are the ones it keeps here. A style whose
|
|
75
|
+
* unset, so the color of whatever the run sits in — a quote, a link — does
|
|
76
|
+
* not show through: Rich's code keeps its own colors inside a quote, and the
|
|
77
|
+
* terminal's are the ones it keeps here. A style whose colors are
|
|
78
78
|
* slots already (`white on blue`), or that paints no ground (`bold magenta`),
|
|
79
|
-
* was written for the terminal's own
|
|
80
|
-
* draws a highlighted line number the same way below 256
|
|
79
|
+
* was written for the terminal's own colors and is drawn as written. Rich
|
|
80
|
+
* draws a highlighted line number the same way below 256 colors
|
|
81
81
|
* (`Syntax._get_number_styles`).
|
|
82
82
|
*/
|
|
83
83
|
export function groundedStyle(options, style) {
|
|
@@ -230,7 +230,7 @@ const ITERATOR_PROTOTYPE = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol
|
|
|
230
230
|
* write during render is refused at: a `State` set in a pass that did not make
|
|
231
231
|
* it throws (`./state.ts`).
|
|
232
232
|
*
|
|
233
|
-
* It is also the one reporter of what the view holds (`
|
|
233
|
+
* It is also the one reporter of what the view holds (`onVisibility`). Under one
|
|
234
234
|
* column a renderable is held: in the view, with nothing of it on the frame.
|
|
235
235
|
* It is drawn all the same and what it drew dropped (`holding`), so what a held
|
|
236
236
|
* container is reported holding is what it draws, under the options it hands
|
|
@@ -239,13 +239,13 @@ const ITERATOR_PROTOTYPE = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol
|
|
|
239
239
|
*/
|
|
240
240
|
export function render(renderable, options) {
|
|
241
241
|
const opens = active === undefined;
|
|
242
|
-
const
|
|
243
|
-
const { phase, drawing } =
|
|
242
|
+
const visibility = drawsNothing(options) ? "hidden" : "visible";
|
|
243
|
+
const { phase, drawing } = visibility === "visible" ? { phase: phaseHere(), drawing: options } : holding(options);
|
|
244
244
|
const drawn = runIn(phase, () => {
|
|
245
|
-
options.
|
|
245
|
+
options.onVisibility?.(renderable, visibility);
|
|
246
246
|
return renderable.render(drawing);
|
|
247
247
|
});
|
|
248
|
-
if (
|
|
248
|
+
if (visibility === "hidden") {
|
|
249
249
|
runIn(phase, () => {
|
|
250
250
|
for (const _ of drawn)
|
|
251
251
|
;
|
|
@@ -257,12 +257,14 @@ export function render(renderable, options) {
|
|
|
257
257
|
/**
|
|
258
258
|
* Where a held renderable is drawn, and the options it is drawn under: what
|
|
259
259
|
* it draws is dropped, and everything it draws is reported held, whatever
|
|
260
|
-
* width it hands it. What it tells of its hold (`
|
|
260
|
+
* width it hands it. What it tells of its hold (`onValidity`) still reaches the
|
|
261
261
|
* frame: an element not yet entered is held at no width, and must say when it
|
|
262
262
|
* enters and takes some. A motion held at no width therefore wakes its host
|
|
263
263
|
* for frames that look the same: when it next takes room is not a moment its
|
|
264
264
|
* hold can name, and an early answer costs a frame where a late one hides the
|
|
265
|
-
* element.
|
|
265
|
+
* element. An effect is not such a motion: it cannot give itself room, so
|
|
266
|
+
* however it moves, a held one reports held for good, and whatever gives it
|
|
267
|
+
* room wakes the host. It commits nothing, as a measurement commits nothing —
|
|
266
268
|
* its effects (`afterPass`) are learned at a width nobody sees, so a
|
|
267
269
|
* `Viewport` it shows content through keeps the scroll the last frame shown
|
|
268
270
|
* left it.
|
|
@@ -273,10 +275,15 @@ export function render(renderable, options) {
|
|
|
273
275
|
* can repeat.
|
|
274
276
|
*/
|
|
275
277
|
function holding(options) {
|
|
276
|
-
const {
|
|
278
|
+
const { onVisibility, onReads } = options;
|
|
277
279
|
return {
|
|
278
280
|
phase: { pass: phaseHere().pass, effects: [] },
|
|
279
|
-
drawing: {
|
|
281
|
+
drawing: {
|
|
282
|
+
...options,
|
|
283
|
+
maxWidth: 0,
|
|
284
|
+
onVisibility: onVisibility && ((content) => onVisibility(content, "hidden")),
|
|
285
|
+
onReads: onReads && ((t, key) => onReads(t, key, NEVER_CHANGES)),
|
|
286
|
+
},
|
|
280
287
|
};
|
|
281
288
|
}
|
|
282
289
|
/**
|
|
@@ -293,15 +300,16 @@ export function measure(measurable, options) {
|
|
|
293
300
|
}
|
|
294
301
|
/**
|
|
295
302
|
* `options` as a measurement is asked with. A `measure` that renders to learn
|
|
296
|
-
* its shape draws nothing on the frame, so it reports nothing to `
|
|
303
|
+
* its shape draws nothing on the frame, so it reports nothing to `onVisibility` —
|
|
297
304
|
* one that did would put a widget in the view at the moment a container
|
|
298
|
-
* measured it, and keep one the frame then cropped away
|
|
299
|
-
*
|
|
305
|
+
* measured it, and keep one the frame then cropped away — and nothing to
|
|
306
|
+
* `onReads`, which speaks only for what the frame shows. It still tells its
|
|
307
|
+
* hold (`onValidity`): a layout decided by a measurement changes when it does.
|
|
300
308
|
*
|
|
301
309
|
* [LAW:single-enforcer] Every measurement starts here: `measure` asks with it.
|
|
302
310
|
*/
|
|
303
311
|
function measuring(options) {
|
|
304
|
-
return { ...options,
|
|
312
|
+
return { ...options, onVisibility: undefined, onReads: undefined };
|
|
305
313
|
}
|
|
306
314
|
/**
|
|
307
315
|
* The options a renderable should *lay out against*: `withCellWidth`, with an
|
package/dist/core/render.d.ts
CHANGED
|
@@ -12,12 +12,12 @@
|
|
|
12
12
|
*
|
|
13
13
|
* [LAW:single-enforcer] The Segment-to-ANSI conversion lives in `segmentToString`
|
|
14
14
|
* and is the single way a segment becomes wire bytes. `segmentsToString` is
|
|
15
|
-
* that encoding joined, and `Console._writeSegments`, `
|
|
15
|
+
* that encoding joined, and `Console._writeSegments`, `Renderer` (every `Live`
|
|
16
16
|
* and `App` frame) and `renderToString` all go through it, so terminal output,
|
|
17
17
|
* live and app frames and string export agree by construction.
|
|
18
18
|
*
|
|
19
19
|
* [LAW:one-source-of-truth] What the encoding needs from where it writes
|
|
20
|
-
* arrives as one `
|
|
20
|
+
* arrives as one `OutputTarget` value. Each caller resolves its destination
|
|
21
21
|
* once — spec, detection, and its own overrides — and hands it through whole,
|
|
22
22
|
* so a depth is never paired with a link setting taken from somewhere else.
|
|
23
23
|
*
|
|
@@ -34,22 +34,22 @@
|
|
|
34
34
|
* cell lines do. A link split across segments still hovers as one link,
|
|
35
35
|
* because every pair it becomes carries the id `osc8Open` derives from the URL.
|
|
36
36
|
*
|
|
37
|
-
*
|
|
37
|
+
* Color and hyperlinks are two facts about the destination:
|
|
38
38
|
* `colorSystem === null` empties every segment's SGR codes, and
|
|
39
|
-
* `hyperlinks === false` drops every segment's link. A
|
|
40
|
-
* removes a link — a hyperlink is not a
|
|
39
|
+
* `hyperlinks === false` drops every segment's link. A color depth never
|
|
40
|
+
* removes a link — a hyperlink is not a color, and a NO_COLOR terminal still
|
|
41
41
|
* follows OSC 8. This is where the port departs from the reference, whose
|
|
42
|
-
* `Style.render` returns bare text for a null
|
|
42
|
+
* `Style.render` returns bare text for a null color system.
|
|
43
43
|
*
|
|
44
44
|
* The third fact, `reducedMotion`, changes the segment rather than its
|
|
45
45
|
* encoding: `shownOn` takes the style's blink out before it is encoded.
|
|
46
46
|
*/
|
|
47
47
|
import { ColorDepth } from "./color.js";
|
|
48
|
-
import type { ColorSystemName,
|
|
48
|
+
import type { ColorSystemName, OutputTarget } from "./color.js";
|
|
49
49
|
import type { Env } from "./env.js";
|
|
50
50
|
import { Segment } from "./segment.js";
|
|
51
51
|
import type { Renderable, RenderOptions } from "./protocol.js";
|
|
52
|
-
export interface RenderToStringOptions extends Pick<RenderOptions, "asciiOnly" | "reducedMotion" | "theme" | "onStyleError" | "highlight" | "highlighter" | "frame"> {
|
|
52
|
+
export interface RenderToStringOptions extends Pick<RenderOptions, "asciiOnly" | "reducedMotion" | "textOrder" | "terminal" | "theme" | "onStyleError" | "highlight" | "highlighter" | "frame"> {
|
|
53
53
|
/** Cell width to render into. Default 80. */
|
|
54
54
|
width?: number;
|
|
55
55
|
/**
|
|
@@ -74,7 +74,7 @@ export interface RenderToStringOptions extends Pick<RenderOptions, "asciiOnly" |
|
|
|
74
74
|
noColor?: boolean;
|
|
75
75
|
/**
|
|
76
76
|
* Whether OSC 8 hyperlinks are emitted. Independent of `colorSystem`: a
|
|
77
|
-
* null
|
|
77
|
+
* null color system strips SGR and keeps links. Default: what the
|
|
78
78
|
* destination takes — true for an explicit depth, detected under `"auto"`
|
|
79
79
|
* (no TTY or TERM=dumb: false). `false` with `colorSystem: null` is plain text.
|
|
80
80
|
*/
|
|
@@ -89,12 +89,17 @@ export interface RenderToStringOptions extends Pick<RenderOptions, "asciiOnly" |
|
|
|
89
89
|
* what was drawn, after `render`. The encoder writes what this returns, and a
|
|
90
90
|
* recording console records it, so every export replays what was written.
|
|
91
91
|
*/
|
|
92
|
-
export declare function shownOn(segment: Segment, destination:
|
|
92
|
+
export declare function shownOn(segment: Segment, destination: OutputTarget): Segment;
|
|
93
93
|
/**
|
|
94
94
|
* Encodes one segment as ANSI bytes for `destination`: the reference's
|
|
95
|
-
* `Style.render` for that segment, and nothing for a control segment.
|
|
95
|
+
* `Style.render` for that segment, and nothing for a control segment. It seals
|
|
96
|
+
* the segment alone, and a `logical` row's isolate spans its segments, so a row
|
|
97
|
+
* goes through `segmentsToString` whole.
|
|
96
98
|
*/
|
|
97
|
-
export declare function segmentToString(segment: Segment, destination:
|
|
98
|
-
/**
|
|
99
|
-
|
|
99
|
+
export declare function segmentToString(segment: Segment, destination: OutputTarget): string;
|
|
100
|
+
/**
|
|
101
|
+
* Encodes a sequence of segments as ANSI bytes for `destination`, one segment
|
|
102
|
+
* at a time, over what `sealed` lets reach the wire.
|
|
103
|
+
*/
|
|
104
|
+
export declare function segmentsToString(segments: Iterable<Segment>, destination: OutputTarget): string;
|
|
100
105
|
export declare function renderToString(renderable: Renderable, options?: RenderToStringOptions): string;
|
package/dist/core/render.js
CHANGED
|
@@ -12,12 +12,12 @@
|
|
|
12
12
|
*
|
|
13
13
|
* [LAW:single-enforcer] The Segment-to-ANSI conversion lives in `segmentToString`
|
|
14
14
|
* and is the single way a segment becomes wire bytes. `segmentsToString` is
|
|
15
|
-
* that encoding joined, and `Console._writeSegments`, `
|
|
15
|
+
* that encoding joined, and `Console._writeSegments`, `Renderer` (every `Live`
|
|
16
16
|
* and `App` frame) and `renderToString` all go through it, so terminal output,
|
|
17
17
|
* live and app frames and string export agree by construction.
|
|
18
18
|
*
|
|
19
19
|
* [LAW:one-source-of-truth] What the encoding needs from where it writes
|
|
20
|
-
* arrives as one `
|
|
20
|
+
* arrives as one `OutputTarget` value. Each caller resolves its destination
|
|
21
21
|
* once — spec, detection, and its own overrides — and hands it through whole,
|
|
22
22
|
* so a depth is never paired with a link setting taken from somewhere else.
|
|
23
23
|
*
|
|
@@ -34,20 +34,21 @@
|
|
|
34
34
|
* cell lines do. A link split across segments still hovers as one link,
|
|
35
35
|
* because every pair it becomes carries the id `osc8Open` derives from the URL.
|
|
36
36
|
*
|
|
37
|
-
*
|
|
37
|
+
* Color and hyperlinks are two facts about the destination:
|
|
38
38
|
* `colorSystem === null` empties every segment's SGR codes, and
|
|
39
|
-
* `hyperlinks === false` drops every segment's link. A
|
|
40
|
-
* removes a link — a hyperlink is not a
|
|
39
|
+
* `hyperlinks === false` drops every segment's link. A color depth never
|
|
40
|
+
* removes a link — a hyperlink is not a color, and a NO_COLOR terminal still
|
|
41
41
|
* follows OSC 8. This is where the port departs from the reference, whose
|
|
42
|
-
* `Style.render` returns bare text for a null
|
|
42
|
+
* `Style.render` returns bare text for a null color system.
|
|
43
43
|
*
|
|
44
44
|
* The third fact, `reducedMotion`, changes the segment rather than its
|
|
45
45
|
* encoding: `shownOn` takes the style's blink out before it is encoded.
|
|
46
46
|
*/
|
|
47
|
-
import { ColorDepth,
|
|
47
|
+
import { ColorDepth, resolveOutputTarget } from "./color.js";
|
|
48
48
|
import { Segment } from "./segment.js";
|
|
49
49
|
import { render } from "./protocol.js";
|
|
50
50
|
import { OSC8_CLOSE, osc8Open } from "./osc8.js";
|
|
51
|
+
import { sealed } from "./seal.js";
|
|
51
52
|
const DEFAULT_WIDTH = 80;
|
|
52
53
|
/**
|
|
53
54
|
* `segment` as `destination` shows it: under reduced motion its style
|
|
@@ -64,44 +65,54 @@ export function shownOn(segment, destination) {
|
|
|
64
65
|
}
|
|
65
66
|
/**
|
|
66
67
|
* Encodes one segment as ANSI bytes for `destination`: the reference's
|
|
67
|
-
* `Style.render` for that segment, and nothing for a control segment.
|
|
68
|
+
* `Style.render` for that segment, and nothing for a control segment. It seals
|
|
69
|
+
* the segment alone, and a `logical` row's isolate spans its segments, so a row
|
|
70
|
+
* goes through `segmentsToString` whole.
|
|
68
71
|
*/
|
|
69
72
|
export function segmentToString(segment, destination) {
|
|
73
|
+
return segmentsToString([segment], destination);
|
|
74
|
+
}
|
|
75
|
+
function encoded(segment, destination) {
|
|
70
76
|
if (segment.isControl)
|
|
71
77
|
return "";
|
|
72
78
|
const { text, style } = shownOn(segment, destination);
|
|
73
79
|
// As the reference's `if not text` and `if style:` — no pair around nothing.
|
|
74
80
|
if (text.length === 0 || style === undefined)
|
|
75
81
|
return text;
|
|
76
|
-
// [LAW:one-type-per-behavior]
|
|
77
|
-
// their own fact. Coupling them let a
|
|
82
|
+
// [LAW:one-type-per-behavior] Color depth governs SGR only; hyperlinks are
|
|
83
|
+
// their own fact. Coupling them let a color setting delete every control.
|
|
78
84
|
const codes = destination.colorSystem === null ? "" : style.toSgrCodes(destination.colorSystem);
|
|
79
85
|
const styled = codes.length > 0 ? `\x1b[${codes}m${text}\x1b[0m` : text;
|
|
80
86
|
const link = destination.hyperlinks ? style.link : undefined;
|
|
81
87
|
return link === undefined ? styled : `${osc8Open(link)}${styled}${OSC8_CLOSE}`;
|
|
82
88
|
}
|
|
83
|
-
/**
|
|
89
|
+
/**
|
|
90
|
+
* Encodes a sequence of segments as ANSI bytes for `destination`, one segment
|
|
91
|
+
* at a time, over what `sealed` lets reach the wire.
|
|
92
|
+
*/
|
|
84
93
|
export function segmentsToString(segments, destination) {
|
|
85
94
|
const parts = [];
|
|
86
|
-
for (const segment of segments)
|
|
87
|
-
parts.push(
|
|
95
|
+
for (const segment of sealed(segments, destination.textOrder))
|
|
96
|
+
parts.push(encoded(segment, destination));
|
|
88
97
|
return parts.join("");
|
|
89
98
|
}
|
|
90
99
|
export function renderToString(renderable, options) {
|
|
91
100
|
const width = options?.width ?? DEFAULT_WIDTH;
|
|
92
101
|
// [LAW:dataflow-not-control-flow] An absent spec is truecolor; an explicit
|
|
93
102
|
// `null` stays null (`??` would collapse it).
|
|
94
|
-
// [LAW:single-enforcer] Specs resolve through `
|
|
95
|
-
|
|
103
|
+
// [LAW:single-enforcer] Specs resolve through `resolveOutputTarget`.
|
|
104
|
+
// Stated, never detected: this call's bytes have no known destination, and
|
|
105
|
+
// its output is deterministic.
|
|
106
|
+
const destinationOptions = { reducedMotion: options?.reducedMotion, textOrder: options?.textOrder ?? "plain" };
|
|
96
107
|
if (options?.env !== undefined)
|
|
97
108
|
destinationOptions.env = options.env;
|
|
98
109
|
if (options?.isTTY !== undefined)
|
|
99
110
|
destinationOptions.isTTY = options.isTTY;
|
|
100
111
|
const rawSpec = options?.colorSystem;
|
|
101
|
-
const resolved =
|
|
112
|
+
const resolved = resolveOutputTarget(rawSpec === undefined ? ColorDepth.TRUECOLOR : rawSpec, destinationOptions);
|
|
102
113
|
// [LAW:single-enforcer] This call's overrides are applied here, once, to
|
|
103
114
|
// make the one destination everything below is drawn for. `noColor` is a
|
|
104
|
-
//
|
|
115
|
+
// color choice, so it overrides the depth and leaves hyperlinks to the
|
|
105
116
|
// destination; an explicit `hyperlinks` overrides what the destination takes.
|
|
106
117
|
const destination = {
|
|
107
118
|
...resolved,
|
|
@@ -114,6 +125,7 @@ export function renderToString(renderable, options) {
|
|
|
114
125
|
asciiOnly: options?.asciiOnly ?? false,
|
|
115
126
|
// [LAW:one-source-of-truth] What is drawn and how it is encoded take one preference.
|
|
116
127
|
reducedMotion: destination.reducedMotion,
|
|
128
|
+
terminal: options?.terminal,
|
|
117
129
|
theme: options?.theme,
|
|
118
130
|
onStyleError: options?.onStyleError,
|
|
119
131
|
highlight: options?.highlight,
|
|
@@ -122,6 +134,7 @@ export function renderToString(renderable, options) {
|
|
|
122
134
|
// [LAW:one-source-of-truth] The depth the segments below are encoded at,
|
|
123
135
|
// so a renderable measures what this very call will draw.
|
|
124
136
|
colorSystem: destination.colorSystem,
|
|
137
|
+
textOrder: destination.textOrder,
|
|
125
138
|
};
|
|
126
139
|
return segmentsToString(render(renderable, renderOptions), destination);
|
|
127
140
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `sealed` — the one total enforcer of what the wire holds.
|
|
3
|
+
*
|
|
4
|
+
* [LAW:single-enforcer] An explicit bidi control reaches the bytes only inside
|
|
5
|
+
* an isolate that accounts for it. The rule has no list of who wrote what: in a
|
|
6
|
+
* segment with no logical stamp every explicit control is deleted, in every
|
|
7
|
+
* order, so a raw `new Segment(text)` is contained and merely shows no effect.
|
|
8
|
+
* What the census withholds goes here too (`wireText`), a segment at a time, on
|
|
9
|
+
* text nothing cuts again, which is why a rule that reads neighbours can live here
|
|
10
|
+
* and not in the sanitizer. A span edge is therefore where that reading stops. A
|
|
11
|
+
* flag cut by one loses its tags and stays a flag; a selector after one is kept;
|
|
12
|
+
* a ZWJ before one is not taken with a deletion past it, so a join can form that
|
|
13
|
+
* `cellLen`, which reads the whole string, did not measure. Segments have always
|
|
14
|
+
* been measured apart and written together, so the same edge in the same text with
|
|
15
|
+
* nothing deleted draws the same row.
|
|
16
|
+
*
|
|
17
|
+
* This runs on the way out, below every cut, because a row is cut after it is
|
|
18
|
+
* drawn: `scroll` divides it, `mergeHorizontal` and a viewport crop it, an
|
|
19
|
+
* overlay splices into it. Controls written at drawing time would be cut with
|
|
20
|
+
* it. `Style.bidi` is a fact on the cells instead, so what survives still names
|
|
21
|
+
* its stamp, and the controls are written around the survivors.
|
|
22
|
+
*/
|
|
23
|
+
import { Segment } from "./segment.js";
|
|
24
|
+
import type { TextOrder } from "./text-order.js";
|
|
25
|
+
/** `segments` as the wire may hold them for `order`. */
|
|
26
|
+
export declare function sealed(segments: Iterable<Segment>, order: TextOrder): Iterable<Segment>;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `sealed` — the one total enforcer of what the wire holds.
|
|
3
|
+
*
|
|
4
|
+
* [LAW:single-enforcer] An explicit bidi control reaches the bytes only inside
|
|
5
|
+
* an isolate that accounts for it. The rule has no list of who wrote what: in a
|
|
6
|
+
* segment with no logical stamp every explicit control is deleted, in every
|
|
7
|
+
* order, so a raw `new Segment(text)` is contained and merely shows no effect.
|
|
8
|
+
* What the census withholds goes here too (`wireText`), a segment at a time, on
|
|
9
|
+
* text nothing cuts again, which is why a rule that reads neighbours can live here
|
|
10
|
+
* and not in the sanitizer. A span edge is therefore where that reading stops. A
|
|
11
|
+
* flag cut by one loses its tags and stays a flag; a selector after one is kept;
|
|
12
|
+
* a ZWJ before one is not taken with a deletion past it, so a join can form that
|
|
13
|
+
* `cellLen`, which reads the whole string, did not measure. Segments have always
|
|
14
|
+
* been measured apart and written together, so the same edge in the same text with
|
|
15
|
+
* nothing deleted draws the same row.
|
|
16
|
+
*
|
|
17
|
+
* This runs on the way out, below every cut, because a row is cut after it is
|
|
18
|
+
* drawn: `scroll` divides it, `mergeHorizontal` and a viewport crop it, an
|
|
19
|
+
* overlay splices into it. Controls written at drawing time would be cut with
|
|
20
|
+
* it. `Style.bidi` is a fact on the cells instead, so what survives still names
|
|
21
|
+
* its stamp, and the controls are written around the survivors.
|
|
22
|
+
*/
|
|
23
|
+
import { advance, closersOf, opened, withoutExplicit } from "./bidi.js";
|
|
24
|
+
import { wireText } from "./cells.js";
|
|
25
|
+
import { Segment } from "./segment.js";
|
|
26
|
+
const LRI = "\u2066";
|
|
27
|
+
const RLI = "\u2067";
|
|
28
|
+
const PDI = "\u2069";
|
|
29
|
+
/** `text` with closers that match nothing in `open` dropped, so content cannot end the isolate around it. */
|
|
30
|
+
function balanced(text, open) {
|
|
31
|
+
return Array.from(text, (character) => (advance(open, character) ? character : "")).join("");
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* One row's run of one stamp in its isolate. The initiator is stated from the
|
|
35
|
+
* whole line's direction rather than FSI, so a wrapped row does not re-detect
|
|
36
|
+
* it. Embeddings close by PDF ahead of the PDI because VTE discards a zero-width
|
|
37
|
+
* character at column 0, initiator included, and a PDI matching nothing there
|
|
38
|
+
* closes nothing.
|
|
39
|
+
*/
|
|
40
|
+
function* isolated(run, { level, opens }) {
|
|
41
|
+
const open = opened(opens);
|
|
42
|
+
yield new Segment((level === 1 ? RLI : LRI) + opens);
|
|
43
|
+
for (const segment of run) {
|
|
44
|
+
const text = balanced(segment.text, open);
|
|
45
|
+
yield text === segment.text ? segment : new Segment(text, segment.style, segment.control);
|
|
46
|
+
}
|
|
47
|
+
yield new Segment(closersOf(open.stack.join("")) + PDI);
|
|
48
|
+
}
|
|
49
|
+
/** `segments` as the wire may hold them for `order`. */
|
|
50
|
+
export function* sealed(segments, order) {
|
|
51
|
+
let run = [];
|
|
52
|
+
let stamp;
|
|
53
|
+
const flush = function* () {
|
|
54
|
+
if (stamp !== undefined)
|
|
55
|
+
yield* isolated(run, stamp);
|
|
56
|
+
run = [];
|
|
57
|
+
stamp = undefined;
|
|
58
|
+
};
|
|
59
|
+
for (const raw of segments) {
|
|
60
|
+
const drawn = wireText(raw.text);
|
|
61
|
+
const segment = drawn === raw.text ? raw : new Segment(drawn, raw.style, raw.control);
|
|
62
|
+
const own = order === "logical" && !segment.isControl ? segment.style?.bidi : undefined;
|
|
63
|
+
if (own?.order === "logical") {
|
|
64
|
+
if (own !== stamp)
|
|
65
|
+
yield* flush();
|
|
66
|
+
stamp = own;
|
|
67
|
+
run.push(segment);
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
yield* flush();
|
|
71
|
+
const text = withoutExplicit(segment.text);
|
|
72
|
+
yield text === segment.text ? segment : new Segment(text, segment.style, segment.control);
|
|
73
|
+
}
|
|
74
|
+
yield* flush();
|
|
75
|
+
}
|
package/dist/core/segment.d.ts
CHANGED
|
@@ -69,15 +69,15 @@ export declare class Segment {
|
|
|
69
69
|
* again: a frame of frames answers the next frame's start, a transition
|
|
70
70
|
* `t` until it is done, still content never.
|
|
71
71
|
*/
|
|
72
|
-
static
|
|
72
|
+
static validUntil(segments: Iterable<Segment>): number;
|
|
73
73
|
/**
|
|
74
74
|
* Since when what `segments` show has been what it is, on the same
|
|
75
75
|
* timeline: the latest `Style.hold` among them, the other end of the
|
|
76
|
-
* hold `
|
|
76
|
+
* hold `validUntil` reads — `t` for a frame something in moves every
|
|
77
77
|
* frame, `-Infinity` for one that always was. What a host running its
|
|
78
78
|
* timeline backwards asks before drawing again.
|
|
79
79
|
*/
|
|
80
|
-
static
|
|
80
|
+
static validFrom(segments: Iterable<Segment>): number;
|
|
81
81
|
/**
|
|
82
82
|
* The anchor of the cell at column `x` of row `y` in a composed frame, or
|
|
83
83
|
* `undefined` when that cell was drawn by no owner or lies outside the frame.
|
|
@@ -130,6 +130,14 @@ export declare class Segment {
|
|
|
130
130
|
* short rows padded with spaces, long ones cut.
|
|
131
131
|
*/
|
|
132
132
|
static splitAndCropLines(segments: Iterable<Segment>, width: number): Segment[][];
|
|
133
|
+
/**
|
|
134
|
+
* The plain text of one line of segments, in the coordinate system
|
|
135
|
+
* `divideLine` and `Segment.divide` share: cell offsets into the styled line
|
|
136
|
+
* are cell offsets into this string. [LAW:one-source-of-truth] for that
|
|
137
|
+
* correspondence — the offsets are found in this text and applied to the
|
|
138
|
+
* segments it came from.
|
|
139
|
+
*/
|
|
140
|
+
static plainOf(line: readonly Segment[]): string;
|
|
133
141
|
/**
|
|
134
142
|
* Returns total cell width of a line. Ignores control segments.
|
|
135
143
|
*/
|
|
@@ -177,7 +185,7 @@ export declare class Segment {
|
|
|
177
185
|
* rest every time, so a long line wrapped into many rows took time quadratic
|
|
178
186
|
* in its length.
|
|
179
187
|
*/
|
|
180
|
-
static divide(segments: Segment[], cuts: number[]): Segment[][];
|
|
188
|
+
static divide(segments: readonly Segment[], cuts: number[]): Segment[][];
|
|
181
189
|
/**
|
|
182
190
|
* Pads below to fill height.
|
|
183
191
|
*/
|