@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
|
@@ -107,7 +107,7 @@ export declare function cutLabel(text: RichText, width: number, marker: string):
|
|
|
107
107
|
* `Text` are not, and markup that styles nothing is — it reads as empty text,
|
|
108
108
|
* but the string that holds it is not empty.
|
|
109
109
|
*/
|
|
110
|
-
export declare function
|
|
110
|
+
export declare function mounted(content: string | RichText | undefined): content is string | RichText;
|
|
111
111
|
/**
|
|
112
112
|
* A label's text as one line of segments at its natural width, its own styles
|
|
113
113
|
* laid over `base`. The caller has already cut it to its room, so it leaves as
|
|
@@ -159,7 +159,7 @@ export function cutLabel(text, width, marker) {
|
|
|
159
159
|
* `Text` are not, and markup that styles nothing is — it reads as empty text,
|
|
160
160
|
* but the string that holds it is not empty.
|
|
161
161
|
*/
|
|
162
|
-
export function
|
|
162
|
+
export function mounted(content) {
|
|
163
163
|
// Asked of what the content is rather than of what it is not, so a `null`
|
|
164
164
|
// from untyped JS is no content, as Rich's `None` is.
|
|
165
165
|
return typeof content === "string" ? content !== "" : content instanceof RichText && content.plain !== "";
|
|
@@ -180,5 +180,5 @@ export function drawLabel(text, options, base) {
|
|
|
180
180
|
* label, which still opens a gap in the rule, as Rich's does.
|
|
181
181
|
*/
|
|
182
182
|
export function inlineLabel(content) {
|
|
183
|
-
return
|
|
183
|
+
return mounted(content) ? new InlineLabel(content) : undefined;
|
|
184
184
|
}
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
* FlexStrip — wrap-to-width horizontal layout for `StyledRenderable` items.
|
|
3
3
|
*
|
|
4
4
|
* Pack as many items as fit on a line, then break and continue. Each line is
|
|
5
|
-
* an independent sub-strip: optional `
|
|
5
|
+
* an independent sub-strip: optional `Separator` end-caps fire at every line
|
|
6
6
|
* boundary (not just the strip's first/last position), so a line break looks
|
|
7
|
-
* the same as an endpoint to the joiner. Composes with the Strip +
|
|
8
|
-
* primitive in `core/strip` — same `
|
|
7
|
+
* the same as an endpoint to the joiner. Composes with the Strip + Separator
|
|
8
|
+
* primitive in `core/strip` — same `Separator` protocol, no new join semantics.
|
|
9
9
|
*
|
|
10
10
|
* [LAW:dataflow-not-control-flow] The pack walk is the same shape every
|
|
11
11
|
* render: measure each item, render every joiner form (start-cap, end-cap,
|
|
@@ -17,11 +17,11 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import { Segment } from "../core/segment.js";
|
|
19
19
|
import type { Renderable, Measurable, RenderOptions } from "../core/protocol.js";
|
|
20
|
-
import { type
|
|
20
|
+
import { type Separator, type StyledRenderable } from "../core/strip.js";
|
|
21
21
|
export type FlexAlign = "left" | "center" | "right" | "justify";
|
|
22
22
|
export interface FlexStripOptions<T extends StyledRenderable> {
|
|
23
|
-
/**
|
|
24
|
-
|
|
23
|
+
/** Separator used between items within a line, and at line endpoints. */
|
|
24
|
+
separator?: Separator<T>;
|
|
25
25
|
/** Cells of horizontal space inserted on each side of an inter-item joiner (default 0). */
|
|
26
26
|
gap?: number;
|
|
27
27
|
/** Line alignment when packed items don't fill the available width (default "left"). */
|
|
@@ -29,7 +29,7 @@ export interface FlexStripOptions<T extends StyledRenderable> {
|
|
|
29
29
|
}
|
|
30
30
|
export declare class FlexStrip<T extends StyledRenderable = StyledRenderable> implements Renderable, Measurable {
|
|
31
31
|
readonly items: readonly T[];
|
|
32
|
-
readonly
|
|
32
|
+
readonly separator: Separator<T> | undefined;
|
|
33
33
|
readonly gap: number;
|
|
34
34
|
readonly align: FlexAlign;
|
|
35
35
|
constructor(items: readonly T[], options?: FlexStripOptions<T>);
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
* FlexStrip — wrap-to-width horizontal layout for `StyledRenderable` items.
|
|
3
3
|
*
|
|
4
4
|
* Pack as many items as fit on a line, then break and continue. Each line is
|
|
5
|
-
* an independent sub-strip: optional `
|
|
5
|
+
* an independent sub-strip: optional `Separator` end-caps fire at every line
|
|
6
6
|
* boundary (not just the strip's first/last position), so a line break looks
|
|
7
|
-
* the same as an endpoint to the joiner. Composes with the Strip +
|
|
8
|
-
* primitive in `core/strip` — same `
|
|
7
|
+
* the same as an endpoint to the joiner. Composes with the Strip + Separator
|
|
8
|
+
* primitive in `core/strip` — same `Separator` protocol, no new join semantics.
|
|
9
9
|
*
|
|
10
10
|
* [LAW:dataflow-not-control-flow] The pack walk is the same shape every
|
|
11
11
|
* render: measure each item, render every joiner form (start-cap, end-cap,
|
|
@@ -47,12 +47,12 @@ function computeSlotFills(align, isFinalLine, spare, itemCount) {
|
|
|
47
47
|
}
|
|
48
48
|
export class FlexStrip {
|
|
49
49
|
items;
|
|
50
|
-
|
|
50
|
+
separator;
|
|
51
51
|
gap;
|
|
52
52
|
align;
|
|
53
53
|
constructor(items, options) {
|
|
54
54
|
this.items = items;
|
|
55
|
-
this.
|
|
55
|
+
this.separator = options?.separator;
|
|
56
56
|
this.gap = options?.gap ?? 0;
|
|
57
57
|
this.align = options?.align ?? "left";
|
|
58
58
|
}
|
|
@@ -62,7 +62,7 @@ export class FlexStrip {
|
|
|
62
62
|
return;
|
|
63
63
|
const maxWidth = Math.max(1, options.maxWidth);
|
|
64
64
|
const gap = this.gap;
|
|
65
|
-
const joiner = this.
|
|
65
|
+
const joiner = this.separator;
|
|
66
66
|
// Pre-render every item and every joiner form we might need. Doing this
|
|
67
67
|
// up-front turns packing into a pure data computation over widths.
|
|
68
68
|
const itemBlocks = items.map((it) => renderToBlock(drawItem(it), options));
|
|
@@ -178,24 +178,24 @@ export class FlexStrip {
|
|
|
178
178
|
let maximum = 0;
|
|
179
179
|
for (let i = 0; i < items.length; i++) {
|
|
180
180
|
const itemWidth = renderToBlock(items[i], options).width;
|
|
181
|
-
const sc = this.
|
|
182
|
-
? renderToBlock(drawJoin(this.
|
|
181
|
+
const sc = this.separator
|
|
182
|
+
? renderToBlock(drawJoin(this.separator, null, items[i], { index: i }), options).width
|
|
183
183
|
: 0;
|
|
184
|
-
const ec = this.
|
|
185
|
-
? renderToBlock(drawJoin(this.
|
|
184
|
+
const ec = this.separator
|
|
185
|
+
? renderToBlock(drawJoin(this.separator, items[i], null, { index: i + 1 }), options).width
|
|
186
186
|
: 0;
|
|
187
187
|
minimum = Math.max(minimum, itemWidth + sc + ec);
|
|
188
188
|
maximum += itemWidth;
|
|
189
189
|
if (i > 0) {
|
|
190
190
|
maximum += this.gap * 2;
|
|
191
|
-
if (this.
|
|
192
|
-
maximum += renderToBlock(drawJoin(this.
|
|
191
|
+
if (this.separator) {
|
|
192
|
+
maximum += renderToBlock(drawJoin(this.separator, items[i - 1], items[i], { index: i }), options).width;
|
|
193
193
|
}
|
|
194
194
|
}
|
|
195
195
|
}
|
|
196
|
-
if (this.
|
|
197
|
-
maximum += renderToBlock(drawJoin(this.
|
|
198
|
-
maximum += renderToBlock(drawJoin(this.
|
|
196
|
+
if (this.separator) {
|
|
197
|
+
maximum += renderToBlock(drawJoin(this.separator, null, items[0], { index: 0 }), options).width;
|
|
198
|
+
maximum += renderToBlock(drawJoin(this.separator, items[items.length - 1], null, { index: items.length }), options).width;
|
|
199
199
|
}
|
|
200
200
|
return { minimum, maximum };
|
|
201
201
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* for its own seconds and looping, drawn as the one in progress at a time
|
|
4
4
|
* the host hands in.
|
|
5
5
|
*
|
|
6
|
-
* An effect moves a cell's
|
|
6
|
+
* An effect moves a cell's colors and may never change a glyph
|
|
7
7
|
* (`./effect.ts`: "It changes how cells look, never which cells exist or who
|
|
8
8
|
* drew them"). A frame is the other kind of motion — what the element shows
|
|
9
9
|
* changes — so it is its own primitive and not a wider `Effect`, and the two
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
* placed sequence stamps them with its hold (`Style.hold`,
|
|
31
31
|
* `placedRender` in `core/animation.ts`), which rides up
|
|
32
32
|
* through every container to whoever holds the composed frame
|
|
33
|
-
* (`Segment.
|
|
33
|
+
* (`Segment.validUntil`), so a host drawing at `t` knows when to draw again,
|
|
34
34
|
* and one drawing slower than the frames turn can see that it is skipping
|
|
35
35
|
* them. Nothing an animation's `at` returns carries a stamp of its own: the
|
|
36
36
|
* stamp is put on where the frame's time is known.
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
* children do.
|
|
46
46
|
*/
|
|
47
47
|
import { Animation } from "../core/animation.js";
|
|
48
|
-
import { type
|
|
49
|
-
import type {
|
|
48
|
+
import { type StepSequence } from "../core/easing.js";
|
|
49
|
+
import type { RenderOptions } from "../core/protocol.js";
|
|
50
50
|
import type { Segment } from "../core/segment.js";
|
|
51
51
|
import { RichText } from "../core/text.js";
|
|
52
52
|
/** One frame: what it shows, and how long it is held, in seconds. */
|
|
@@ -57,7 +57,7 @@ export interface Frame {
|
|
|
57
57
|
/** A sequence of frames prepared to be drawn: built once, asked for the frame at a time. */
|
|
58
58
|
export declare class FrameSequence implements Animation<RichText> {
|
|
59
59
|
/** Which frame is in progress when: the holds are the frames' seconds, in order. */
|
|
60
|
-
readonly
|
|
60
|
+
readonly stepSequence: StepSequence;
|
|
61
61
|
/** The width every frame draws at: the widest frame's, in cells. */
|
|
62
62
|
readonly width: number;
|
|
63
63
|
private readonly _shown;
|
|
@@ -70,9 +70,9 @@ export declare class FrameSequence implements Animation<RichText> {
|
|
|
70
70
|
*/
|
|
71
71
|
at(t: number): RichText;
|
|
72
72
|
/** When the frame in progress at `t` gives way to the next: the beat's answer, its holds being the frames'. */
|
|
73
|
-
|
|
73
|
+
validUntil(t: number): number;
|
|
74
74
|
/** When the frame in progress at `t` began: the beat's answer. */
|
|
75
|
-
|
|
75
|
+
validFrom(t: number): number;
|
|
76
76
|
/** The frames with their motion taken out: the beat's first frame, held, a copy as `at`'s is. */
|
|
77
77
|
reduced(): Animation<RichText>;
|
|
78
78
|
render(options: RenderOptions): Iterable<Segment>;
|
|
@@ -86,12 +86,3 @@ export declare class FrameSequence implements Animation<RichText> {
|
|
|
86
86
|
maximum: number;
|
|
87
87
|
};
|
|
88
88
|
}
|
|
89
|
-
/**
|
|
90
|
-
* The text frame `animation` shows at host time `t` under `motion`
|
|
91
|
-
* (`shownAt`), copied and stamped with the hold it is in there: what the
|
|
92
|
-
* template `frames` and `glyphs` functions, which know the reader's
|
|
93
|
-
* preference before any render, splice into a line. The stamp is on the
|
|
94
|
-
* base style, which an empty text still draws as its one piece of no width,
|
|
95
|
-
* and on a copy, since an animation may hand back the one `RichText` it holds.
|
|
96
|
-
*/
|
|
97
|
-
export declare function textFrameAt(animation: Animation<RichText>, t: number, motion: Motion): RichText;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* for its own seconds and looping, drawn as the one in progress at a time
|
|
4
4
|
* the host hands in.
|
|
5
5
|
*
|
|
6
|
-
* An effect moves a cell's
|
|
6
|
+
* An effect moves a cell's colors and may never change a glyph
|
|
7
7
|
* (`./effect.ts`: "It changes how cells look, never which cells exist or who
|
|
8
8
|
* drew them"). A frame is the other kind of motion — what the element shows
|
|
9
9
|
* changes — so it is its own primitive and not a wider `Effect`, and the two
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
* placed sequence stamps them with its hold (`Style.hold`,
|
|
31
31
|
* `placedRender` in `core/animation.ts`), which rides up
|
|
32
32
|
* through every container to whoever holds the composed frame
|
|
33
|
-
* (`Segment.
|
|
33
|
+
* (`Segment.validUntil`), so a host drawing at `t` knows when to draw again,
|
|
34
34
|
* and one drawing slower than the frames turn can see that it is skipping
|
|
35
35
|
* them. Nothing an animation's `at` returns carries a stamp of its own: the
|
|
36
36
|
* stamp is put on where the frame's time is known.
|
|
@@ -44,20 +44,19 @@
|
|
|
44
44
|
* binding has no console for, so the frame arrives read, as a `Group`'s
|
|
45
45
|
* children do.
|
|
46
46
|
*/
|
|
47
|
-
import { Animation,
|
|
48
|
-
import {
|
|
49
|
-
import { layerStyle } from "../core/style.js";
|
|
47
|
+
import { Animation, placedRender } from "../core/animation.js";
|
|
48
|
+
import { stepSequence } from "../core/easing.js";
|
|
50
49
|
import { setIntoLine } from "./embed.js";
|
|
51
50
|
/** A sequence of frames prepared to be drawn: built once, asked for the frame at a time. */
|
|
52
51
|
export class FrameSequence {
|
|
53
52
|
/** Which frame is in progress when: the holds are the frames' seconds, in order. */
|
|
54
|
-
|
|
53
|
+
stepSequence;
|
|
55
54
|
/** The width every frame draws at: the widest frame's, in cells. */
|
|
56
55
|
width;
|
|
57
56
|
// Each frame as it draws: a line fragment padded to `width`, made once.
|
|
58
57
|
_shown;
|
|
59
58
|
constructor(frames) {
|
|
60
|
-
this.
|
|
59
|
+
this.stepSequence = stepSequence(frames.map((frame) => frame.seconds));
|
|
61
60
|
const texts = frames.map((frame) => setIntoLine(frame.text.copy()));
|
|
62
61
|
const widths = texts.map((text) => text.cellLength);
|
|
63
62
|
this.width = Math.max(...widths);
|
|
@@ -76,19 +75,19 @@ export class FrameSequence {
|
|
|
76
75
|
* refuses a `t` that is not finite.
|
|
77
76
|
*/
|
|
78
77
|
at(t) {
|
|
79
|
-
return this._shown[this.
|
|
78
|
+
return this._shown[this.stepSequence.at(t)].copy();
|
|
80
79
|
}
|
|
81
80
|
/** When the frame in progress at `t` gives way to the next: the beat's answer, its holds being the frames'. */
|
|
82
|
-
|
|
83
|
-
return this.
|
|
81
|
+
validUntil(t) {
|
|
82
|
+
return this.stepSequence.validUntil(t);
|
|
84
83
|
}
|
|
85
84
|
/** When the frame in progress at `t` began: the beat's answer. */
|
|
86
|
-
|
|
87
|
-
return this.
|
|
85
|
+
validFrom(t) {
|
|
86
|
+
return this.stepSequence.validFrom(t);
|
|
88
87
|
}
|
|
89
88
|
/** The frames with their motion taken out: the beat's first frame, held, a copy as `at`'s is. */
|
|
90
89
|
reduced() {
|
|
91
|
-
return Animation.map(this.
|
|
90
|
+
return Animation.map(this.stepSequence.reduced(), (i) => this._shown[i].copy());
|
|
92
91
|
}
|
|
93
92
|
render(options) {
|
|
94
93
|
return placedRender(this, options);
|
|
@@ -102,17 +101,3 @@ export class FrameSequence {
|
|
|
102
101
|
return { minimum: this.width, maximum: this.width };
|
|
103
102
|
}
|
|
104
103
|
}
|
|
105
|
-
/**
|
|
106
|
-
* The text frame `animation` shows at host time `t` under `motion`
|
|
107
|
-
* (`shownAt`), copied and stamped with the hold it is in there: what the
|
|
108
|
-
* template `frames` and `glyphs` functions, which know the reader's
|
|
109
|
-
* preference before any render, splice into a line. The stamp is on the
|
|
110
|
-
* base style, which an empty text still draws as its one piece of no width,
|
|
111
|
-
* and on a copy, since an animation may hand back the one `RichText` it holds.
|
|
112
|
-
*/
|
|
113
|
-
export function textFrameAt(animation, t, motion) {
|
|
114
|
-
const shown = shownAt(animation, t, motion);
|
|
115
|
-
const stamped = shown.value.copy();
|
|
116
|
-
stamped.style = layerStyle(stamped.style, stamp(holdOf(shown, t)));
|
|
117
|
-
return stamped;
|
|
118
|
-
}
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* glyph effect at a moment `t`: the glyph half of `Effected` (`./effect.ts`),
|
|
4
4
|
* built to its contract.
|
|
5
5
|
*
|
|
6
|
-
* A glyph effect is the
|
|
7
|
-
* the
|
|
6
|
+
* A glyph effect is the color effect's two-stage shape with a glyph where
|
|
7
|
+
* the colors were: for the cells an element draws in a frame, an
|
|
8
8
|
* `Animation` (`../core/animation.ts`) of what is done to them. The first
|
|
9
9
|
* stage is handed every cell once a frame (`GlyphCell`), blanks included —
|
|
10
10
|
* rain and stars live there — and whether the output draws ASCII alone
|
|
@@ -14,15 +14,15 @@
|
|
|
14
14
|
* scramble, a wave of case changes and particles on blank cells are all this
|
|
15
15
|
* one shape (`./glyph-effects.ts`) [LAW:one-type-per-behavior].
|
|
16
16
|
*
|
|
17
|
-
*
|
|
17
|
+
* Color and glyph are not two kinds of animation: each is an `Animation` of
|
|
18
18
|
* a per-cell map, and they differ only in what a cell is mapped to. The
|
|
19
|
-
* wrappers are two because the stages are handed different facts. A
|
|
20
|
-
* effect is settled against the depth, the terminal and the
|
|
21
|
-
* words (`Drawn`), and with no
|
|
19
|
+
* wrappers are two because the stages are handed different facts. A color
|
|
20
|
+
* effect is settled against the depth, the terminal and the colors of the
|
|
21
|
+
* words (`Drawn`), and with no color output there is nothing for it to
|
|
22
22
|
* change. A glyph effect needs none of that, and is written at every depth,
|
|
23
|
-
* with no
|
|
24
|
-
* `new Effected(new GlyphEffected(child, glyphs, …),
|
|
25
|
-
*
|
|
23
|
+
* with no color too. Over one element the two compose by nesting:
|
|
24
|
+
* `new Effected(new GlyphEffected(child, glyphs, …), colors, …)` moves the
|
|
25
|
+
* colors of the glyphs the glyph effect left, since each wrapper measures
|
|
26
26
|
* what its child drew.
|
|
27
27
|
*
|
|
28
28
|
* A `GlyphEffected` is the element under its glyph effect over time, an
|
|
@@ -51,11 +51,11 @@
|
|
|
51
51
|
* Positions are the child's own: row and column count from the top-left of
|
|
52
52
|
* what the child drew.
|
|
53
53
|
*/
|
|
54
|
-
import { Animation } from "../core/animation.js";
|
|
54
|
+
import { Animation, type Reads } from "../core/animation.js";
|
|
55
55
|
import type { Measurable, Renderable, RenderOptions } from "../core/protocol.js";
|
|
56
56
|
import { Segment } from "../core/segment.js";
|
|
57
57
|
import { type RichText } from "../core/text.js";
|
|
58
|
-
import { type
|
|
58
|
+
import { type Placed } from "./effect.js";
|
|
59
59
|
/**
|
|
60
60
|
* A cell of the element a glyph effect wraps: the glyph it shows, where it
|
|
61
61
|
* sits and who drew it, its place in reading order among the cells handed
|
|
@@ -85,7 +85,7 @@ export interface DrawnGlyphs {
|
|
|
85
85
|
}
|
|
86
86
|
/**
|
|
87
87
|
* For an element drawing `drawn`, the animation of what is done to its
|
|
88
|
-
* glyphs. Its `
|
|
88
|
+
* glyphs. Its `validUntil` is when the frame next changes, as an `Effect`'s is.
|
|
89
89
|
*/
|
|
90
90
|
export type GlyphEffect = (drawn: DrawnGlyphs) => Animation<GlyphFrame>;
|
|
91
91
|
export interface GlyphEffectedOptions {
|
|
@@ -95,20 +95,18 @@ export interface GlyphEffectedOptions {
|
|
|
95
95
|
/**
|
|
96
96
|
* A `GlyphEffected` at `t`, or an element through a glyph effect at a time an
|
|
97
97
|
* animation's `at` was handed: `renderable` with its cells' glyphs passed
|
|
98
|
-
* through `effect` at `t`,
|
|
99
|
-
* `
|
|
98
|
+
* through `effect` at `t`, telling the hold it drew in as a `Recolored` does
|
|
99
|
+
* (`RenderOptions.onReads`, `./effect.ts`). [LAW:one-type-per-behavior]
|
|
100
100
|
*/
|
|
101
101
|
export declare class Reglyphed implements Renderable, Measurable {
|
|
102
102
|
readonly renderable: Renderable;
|
|
103
103
|
readonly effect: GlyphEffect;
|
|
104
|
-
readonly
|
|
104
|
+
private readonly _t;
|
|
105
105
|
readonly key: string;
|
|
106
106
|
constructor(renderable: Renderable, effect: GlyphEffect, options: GlyphEffectedOptions & {
|
|
107
107
|
readonly t: number;
|
|
108
108
|
});
|
|
109
109
|
render(options: RenderOptions): Iterable<Segment>;
|
|
110
|
-
/** The frame the effect draws at `t`, and the hold it says that is in. */
|
|
111
|
-
moved(options: RenderOptions): Moved;
|
|
112
110
|
measure(options: RenderOptions): {
|
|
113
111
|
minimum: number;
|
|
114
112
|
maximum: number;
|
|
@@ -116,9 +114,10 @@ export declare class Reglyphed implements Renderable, Measurable {
|
|
|
116
114
|
}
|
|
117
115
|
/**
|
|
118
116
|
* `renderable` under a glyph effect over time, an `Animation<Renderable>`
|
|
119
|
-
* as an `Effected` is (`./effect.ts`): its
|
|
120
|
-
*
|
|
121
|
-
* output's `asciiOnly`,
|
|
117
|
+
* as an `Effected` is (`./effect.ts`): with nothing drawn its answer is `t`,
|
|
118
|
+
* and placed, on its own or as a part of any combinator, it says the glyph
|
|
119
|
+
* effect's exact hold at that time and the output's `asciiOnly`, which the
|
|
120
|
+
* frame's drawing told (`Reads`).
|
|
122
121
|
*/
|
|
123
122
|
export declare class GlyphEffected implements Animation<Renderable> {
|
|
124
123
|
readonly renderable: Renderable;
|
|
@@ -127,8 +126,8 @@ export declare class GlyphEffected implements Animation<Renderable> {
|
|
|
127
126
|
constructor(renderable: Renderable, effect: GlyphEffect, options: GlyphEffectedOptions);
|
|
128
127
|
/** The element through the glyph effect at `t`, unstamped. */
|
|
129
128
|
at(t: number): Reglyphed;
|
|
130
|
-
|
|
131
|
-
|
|
129
|
+
validUntil(t: number, moves?: Reads): number;
|
|
130
|
+
validFrom(t: number, moves?: Reads): number;
|
|
132
131
|
/** The element under the glyph effect with its motion taken out. */
|
|
133
132
|
reduced(): GlyphEffected;
|
|
134
133
|
/** Drawn at the frame's time, its cells stamped with the glyph effect's exact hold there. */
|
|
@@ -150,7 +149,7 @@ export declare class GlyphEffected implements Animation<Renderable> {
|
|
|
150
149
|
* its every style and span, each moved to where its glyphs now sit, and a
|
|
151
150
|
* frame that changes nothing hands the text back as it was. What it says of
|
|
152
151
|
* when it changes is the effect's, unstamped: whoever draws it at a time
|
|
153
|
-
* stamps it (`
|
|
152
|
+
* stamps it (`placed`), or marks it for the engine to (the template `glyphs`).
|
|
154
153
|
*/
|
|
155
154
|
export declare function reglyphText(text: RichText, effect: GlyphEffect, options: {
|
|
156
155
|
readonly key: string;
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* glyph effect at a moment `t`: the glyph half of `Effected` (`./effect.ts`),
|
|
4
4
|
* built to its contract.
|
|
5
5
|
*
|
|
6
|
-
* A glyph effect is the
|
|
7
|
-
* the
|
|
6
|
+
* A glyph effect is the color effect's two-stage shape with a glyph where
|
|
7
|
+
* the colors were: for the cells an element draws in a frame, an
|
|
8
8
|
* `Animation` (`../core/animation.ts`) of what is done to them. The first
|
|
9
9
|
* stage is handed every cell once a frame (`GlyphCell`), blanks included —
|
|
10
10
|
* rain and stars live there — and whether the output draws ASCII alone
|
|
@@ -14,15 +14,15 @@
|
|
|
14
14
|
* scramble, a wave of case changes and particles on blank cells are all this
|
|
15
15
|
* one shape (`./glyph-effects.ts`) [LAW:one-type-per-behavior].
|
|
16
16
|
*
|
|
17
|
-
*
|
|
17
|
+
* Color and glyph are not two kinds of animation: each is an `Animation` of
|
|
18
18
|
* a per-cell map, and they differ only in what a cell is mapped to. The
|
|
19
|
-
* wrappers are two because the stages are handed different facts. A
|
|
20
|
-
* effect is settled against the depth, the terminal and the
|
|
21
|
-
* words (`Drawn`), and with no
|
|
19
|
+
* wrappers are two because the stages are handed different facts. A color
|
|
20
|
+
* effect is settled against the depth, the terminal and the colors of the
|
|
21
|
+
* words (`Drawn`), and with no color output there is nothing for it to
|
|
22
22
|
* change. A glyph effect needs none of that, and is written at every depth,
|
|
23
|
-
* with no
|
|
24
|
-
* `new Effected(new GlyphEffected(child, glyphs, …),
|
|
25
|
-
*
|
|
23
|
+
* with no color too. Over one element the two compose by nesting:
|
|
24
|
+
* `new Effected(new GlyphEffected(child, glyphs, …), colors, …)` moves the
|
|
25
|
+
* colors of the glyphs the glyph effect left, since each wrapper measures
|
|
26
26
|
* what its child drew.
|
|
27
27
|
*
|
|
28
28
|
* A `GlyphEffected` is the element under its glyph effect over time, an
|
|
@@ -51,44 +51,40 @@
|
|
|
51
51
|
* Positions are the child's own: row and column count from the top-left of
|
|
52
52
|
* what the child drew.
|
|
53
53
|
*/
|
|
54
|
-
import { Animation,
|
|
54
|
+
import { Animation, placedRender, shownAt } from "../core/animation.js";
|
|
55
55
|
import { cellLen, graphemes } from "../core/cells.js";
|
|
56
56
|
import { Measurement } from "../core/measure.js";
|
|
57
57
|
import { render } from "../core/protocol.js";
|
|
58
58
|
import { Segment } from "../core/segment.js";
|
|
59
59
|
import { finiteTime } from "../core/easing.js";
|
|
60
|
-
import {
|
|
61
|
-
import { cellSeed, walkGlyphs } from "./effect.js";
|
|
60
|
+
import { sanitized } from "../core/text.js";
|
|
61
|
+
import { cellSeed, validityOver, walkGlyphs } from "./effect.js";
|
|
62
62
|
import { pattern } from "../core/pattern.js";
|
|
63
63
|
/**
|
|
64
64
|
* A `GlyphEffected` at `t`, or an element through a glyph effect at a time an
|
|
65
65
|
* animation's `at` was handed: `renderable` with its cells' glyphs passed
|
|
66
|
-
* through `effect` at `t`,
|
|
67
|
-
* `
|
|
66
|
+
* through `effect` at `t`, telling the hold it drew in as a `Recolored` does
|
|
67
|
+
* (`RenderOptions.onReads`, `./effect.ts`). [LAW:one-type-per-behavior]
|
|
68
68
|
*/
|
|
69
69
|
export class Reglyphed {
|
|
70
70
|
renderable;
|
|
71
71
|
effect;
|
|
72
|
-
|
|
72
|
+
_t;
|
|
73
73
|
key;
|
|
74
74
|
constructor(renderable, effect, options) {
|
|
75
75
|
this.renderable = renderable;
|
|
76
76
|
this.effect = effect;
|
|
77
|
-
this.
|
|
77
|
+
this._t = finiteTime("GlyphEffected", options.t);
|
|
78
78
|
this.key = options.key;
|
|
79
79
|
}
|
|
80
80
|
render(options) {
|
|
81
|
-
return this.moved(options).segments;
|
|
82
|
-
}
|
|
83
|
-
/** The frame the effect draws at `t`, and the hold it says that is in. */
|
|
84
|
-
moved(options) {
|
|
85
81
|
const segments = [...render(this.renderable, options)];
|
|
86
82
|
const { placed, cells } = placeGlyphs(segments, this.key);
|
|
87
83
|
const animation = this.effect({ cells, asciiOnly: options.asciiOnly === true });
|
|
88
|
-
const frame = shownAt(animation, this.
|
|
84
|
+
const frame = shownAt(animation, this._t, options);
|
|
89
85
|
const shown = showGlyphs(placed, frame.value);
|
|
90
|
-
|
|
91
|
-
return
|
|
86
|
+
options.onReads?.(this._t, this.key, validityOver(cells.length > 0, frame, this._t));
|
|
87
|
+
return segments.map((segment, i) => (shown[i].every((text, j) => text === placed[i][j].glyph) ? segment : new Segment(shown[i].join(""), segment.style)));
|
|
92
88
|
}
|
|
93
89
|
measure(options) {
|
|
94
90
|
return Measurement.get(options, this.renderable);
|
|
@@ -96,9 +92,10 @@ export class Reglyphed {
|
|
|
96
92
|
}
|
|
97
93
|
/**
|
|
98
94
|
* `renderable` under a glyph effect over time, an `Animation<Renderable>`
|
|
99
|
-
* as an `Effected` is (`./effect.ts`): its
|
|
100
|
-
*
|
|
101
|
-
* output's `asciiOnly`,
|
|
95
|
+
* as an `Effected` is (`./effect.ts`): with nothing drawn its answer is `t`,
|
|
96
|
+
* and placed, on its own or as a part of any combinator, it says the glyph
|
|
97
|
+
* effect's exact hold at that time and the output's `asciiOnly`, which the
|
|
98
|
+
* frame's drawing told (`Reads`).
|
|
102
99
|
*/
|
|
103
100
|
export class GlyphEffected {
|
|
104
101
|
renderable;
|
|
@@ -113,11 +110,11 @@ export class GlyphEffected {
|
|
|
113
110
|
at(t) {
|
|
114
111
|
return new Reglyphed(this.renderable, this.effect, { t, key: this.key });
|
|
115
112
|
}
|
|
116
|
-
|
|
117
|
-
return t;
|
|
113
|
+
validUntil(t, moves) {
|
|
114
|
+
return moves?.(t, this.key)?.validUntil ?? t;
|
|
118
115
|
}
|
|
119
|
-
|
|
120
|
-
return t;
|
|
116
|
+
validFrom(t, moves) {
|
|
117
|
+
return moves?.(t, this.key)?.validFrom ?? t;
|
|
121
118
|
}
|
|
122
119
|
/** The element under the glyph effect with its motion taken out. */
|
|
123
120
|
reduced() {
|
|
@@ -126,8 +123,7 @@ export class GlyphEffected {
|
|
|
126
123
|
}
|
|
127
124
|
/** Drawn at the frame's time, its cells stamped with the glyph effect's exact hold there. */
|
|
128
125
|
render(options) {
|
|
129
|
-
|
|
130
|
-
return stampFrame(segments, hold);
|
|
126
|
+
return placedRender(this, options);
|
|
131
127
|
}
|
|
132
128
|
measure(options) {
|
|
133
129
|
return Measurement.get(options, this.renderable);
|
|
@@ -161,7 +157,7 @@ function showGlyphs(placed, frame) {
|
|
|
161
157
|
* its every style and span, each moved to where its glyphs now sit, and a
|
|
162
158
|
* frame that changes nothing hands the text back as it was. What it says of
|
|
163
159
|
* when it changes is the effect's, unstamped: whoever draws it at a time
|
|
164
|
-
* stamps it (`
|
|
160
|
+
* stamps it (`placed`), or marks it for the engine to (the template `glyphs`).
|
|
165
161
|
*/
|
|
166
162
|
export function reglyphText(text, effect, options) {
|
|
167
163
|
const { placed, cells } = placeGlyphs([new Segment(text.plain)], options.key);
|
|
@@ -193,7 +189,7 @@ function rewritten(text, glyphs, shown) {
|
|
|
193
189
|
result.stylize(span.style, moved(span.start), moved(span.end));
|
|
194
190
|
return result;
|
|
195
191
|
}
|
|
196
|
-
/** Line breaks and tabs, which `
|
|
192
|
+
/** Line breaks and tabs, which `sanitized` leaves for a text's own lines and which no cell may hold. */
|
|
197
193
|
const BREAKS = pattern(/[\n\t]/);
|
|
198
194
|
/**
|
|
199
195
|
* What `frame` shows in `cell`, held to the contract: as many cells wide as
|
|
@@ -205,7 +201,7 @@ function shows(frame, cell) {
|
|
|
205
201
|
const text = frame(cell);
|
|
206
202
|
if (text === cell.glyph)
|
|
207
203
|
return text;
|
|
208
|
-
if (cellLen(text) !== cellLen(cell.glyph) || BREAKS.test(text) ||
|
|
204
|
+
if (cellLen(text) !== cellLen(cell.glyph) || BREAKS.test(text) || sanitized(text) !== text) {
|
|
209
205
|
throw new RangeError(`a glyph effect turned ${JSON.stringify(cell.glyph)} at row ${cell.row}, column ${cell.col} into ${JSON.stringify(text)}: ` +
|
|
210
206
|
`it must be ${cellLen(cell.glyph)} cell(s) wide, with no line break or control character`);
|
|
211
207
|
}
|
|
@@ -218,18 +214,24 @@ function shows(frame, cell) {
|
|
|
218
214
|
* wide as its glyph is `shows`'s check; this is the half no one cell can
|
|
219
215
|
* see — a trailing zero-width joiner that fuses with the next emoji, or a
|
|
220
216
|
* leading combining mark that draws on the glyph before it, is right alone
|
|
221
|
-
* and wrong beside its neighbour. Only a
|
|
222
|
-
* that splits a cluster across its own segments is drawn
|
|
217
|
+
* and wrong beside its neighbour. Only a join the effect made is asked, seam
|
|
218
|
+
* by seam, so a child that splits a cluster across its own segments is drawn
|
|
219
|
+
* as it drew it, whatever becomes of the glyph its mark sits on.
|
|
223
220
|
*/
|
|
224
221
|
function standsApart(placed, shown) {
|
|
225
|
-
|
|
226
|
-
|
|
222
|
+
const fuse = (left, right) => graphemes(left + right).length < graphemes(left).length + graphemes(right).length;
|
|
223
|
+
// Whether the text at `i` fuses across its left seam and across its right.
|
|
224
|
+
const seams = (texts, i) => {
|
|
225
|
+
// A line break is no cell, and nothing joins across it.
|
|
226
|
+
const beside = (j) => (placed[j]?.cell === undefined ? "" : texts(j));
|
|
227
|
+
const [before, text, after] = [beside(i - 1), texts(i), beside(i + 1)];
|
|
228
|
+
return [fuse(before, text + after), fuse(before + text, after)];
|
|
229
|
+
};
|
|
227
230
|
shown.forEach((text, i) => {
|
|
228
231
|
const { glyph, cell } = placed[i];
|
|
229
232
|
if (cell === undefined || text === glyph)
|
|
230
233
|
return;
|
|
231
|
-
|
|
232
|
-
if (graphemes(before + text + after).length !== graphemes(before).length + graphemes(text).length + graphemes(after).length) {
|
|
234
|
+
if (seams((j) => shown[j], i).some((fused, seam) => fused && !seams((j) => placed[j].glyph, i)[seam])) {
|
|
233
235
|
throw new RangeError(`a glyph effect turned ${JSON.stringify(glyph)} at row ${cell.row}, column ${cell.col} into ${JSON.stringify(text)}, ` +
|
|
234
236
|
`which joins the cell beside it into one character`);
|
|
235
237
|
}
|