@promptctl/rich-js 0.23.0 → 0.24.1
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/THIRD-PARTY-NOTICES +29 -1
- package/dist/core/animation.d.ts +78 -0
- package/dist/core/animation.js +107 -0
- package/dist/core/cell-widths.d.ts +9 -0
- package/dist/core/cell-widths.js +140 -0
- package/dist/core/cells.d.ts +17 -11
- package/dist/core/cells.js +100 -25
- package/dist/core/clock.d.ts +9 -1
- package/dist/core/clock.js +22 -2
- package/dist/core/color.d.ts +10 -0
- package/dist/core/color.js +36 -1
- package/dist/core/console.js +5 -5
- package/dist/core/easing.d.ts +138 -7
- package/dist/core/easing.js +355 -17
- package/dist/core/json.js +2 -1
- package/dist/core/measure.js +2 -2
- package/dist/core/place.js +2 -1
- package/dist/core/pretty.js +2 -2
- package/dist/core/protocol.d.ts +73 -19
- package/dist/core/protocol.js +56 -15
- package/dist/core/render.js +2 -1
- package/dist/core/segment.d.ts +28 -1
- package/dist/core/segment.js +60 -44
- package/dist/core/strip.d.ts +107 -29
- package/dist/core/strip.js +242 -131
- package/dist/core/style.d.ts +18 -1
- package/dist/core/style.js +49 -9
- package/dist/core/text.js +26 -15
- package/dist/core/timeline.d.ts +84 -0
- package/dist/core/timeline.js +144 -0
- package/dist/core/tween.d.ts +49 -0
- package/dist/core/tween.js +69 -0
- package/dist/host/app.js +4 -6
- package/dist/host/index.d.ts +1 -1
- package/dist/host/input.d.ts +37 -13
- package/dist/host/input.js +146 -56
- package/dist/host/terminal-host.d.ts +16 -0
- package/dist/host/terminal-host.js +1 -0
- package/dist/index.d.ts +16 -11
- package/dist/index.js +15 -5
- package/dist/node/terminal-host.d.ts +8 -1
- package/dist/node/terminal-host.js +2 -0
- package/dist/renderables/align.d.ts +3 -2
- package/dist/renderables/align.js +3 -0
- package/dist/renderables/columns.d.ts +3 -2
- package/dist/renderables/columns.js +7 -2
- package/dist/renderables/constrain.d.ts +3 -2
- package/dist/renderables/constrain.js +5 -1
- package/dist/renderables/effect.d.ts +83 -30
- package/dist/renderables/effect.js +155 -57
- package/dist/renderables/effects.d.ts +88 -39
- package/dist/renderables/effects.js +444 -105
- package/dist/renderables/embed.d.ts +10 -0
- package/dist/renderables/embed.js +18 -9
- package/dist/renderables/flexStrip.d.ts +3 -2
- package/dist/renderables/flexStrip.js +6 -1
- package/dist/renderables/frames.d.ts +116 -0
- package/dist/renderables/frames.js +133 -0
- package/dist/renderables/group.d.ts +3 -2
- package/dist/renderables/group.js +5 -2
- package/dist/renderables/html-entities.d.ts +8 -0
- package/dist/renderables/html-entities.js +386 -0
- package/dist/renderables/layout.d.ts +3 -2
- package/dist/renderables/layout.js +15 -2
- package/dist/renderables/list-view.d.ts +3 -2
- package/dist/renderables/list-view.js +12 -5
- package/dist/renderables/live.d.ts +23 -7
- package/dist/renderables/live.js +69 -35
- package/dist/renderables/markdown-parse.d.ts +109 -0
- package/dist/renderables/markdown-parse.js +1421 -0
- package/dist/renderables/markdown-url.d.ts +19 -0
- package/dist/renderables/markdown-url.js +314 -0
- package/dist/renderables/markdown.d.ts +7 -6
- package/dist/renderables/markdown.js +363 -499
- package/dist/renderables/padding.d.ts +8 -20
- package/dist/renderables/padding.js +32 -50
- package/dist/renderables/panel.d.ts +26 -26
- package/dist/renderables/panel.js +67 -103
- package/dist/renderables/progress.d.ts +5 -3
- package/dist/renderables/progress.js +14 -3
- package/dist/renderables/progressBar.js +4 -4
- package/dist/renderables/python-space.d.ts +13 -0
- package/dist/renderables/python-space.js +24 -0
- package/dist/renderables/spinner.d.ts +73 -27
- package/dist/renderables/spinner.js +110 -51
- package/dist/renderables/status.d.ts +8 -3
- package/dist/renderables/status.js +8 -5
- package/dist/renderables/syntax.js +2 -1
- package/dist/renderables/table.d.ts +19 -11
- package/dist/renderables/table.js +140 -156
- package/dist/renderables/traceback.d.ts +1 -1
- package/dist/renderables/traceback.js +6 -5
- package/dist/renderables/tree.d.ts +6 -5
- package/dist/renderables/tree.js +11 -7
- package/dist/renderables/viewport.d.ts +13 -5
- package/dist/renderables/viewport.js +41 -20
- package/dist/template-bindings/animation-funcs.d.ts +37 -0
- package/dist/template-bindings/animation-funcs.js +83 -0
- package/dist/template-bindings/color-funcs.d.ts +13 -0
- package/dist/template-bindings/color-funcs.js +1 -1
- package/dist/template-bindings/helpers.d.ts +6 -0
- package/dist/template-bindings/helpers.js +12 -3
- package/dist/template-bindings/index.d.ts +6 -2
- package/dist/template-bindings/index.js +8 -3
- package/dist/themes/ramp.d.ts +18 -3
- package/dist/themes/ramp.js +23 -2
- package/dist/widgets/focus-manager.d.ts +21 -14
- package/dist/widgets/focus-manager.js +28 -29
- package/dist/widgets/index.d.ts +1 -1
- package/dist/widgets/static-item.d.ts +4 -3
- package/dist/widgets/static-item.js +9 -7
- package/dist/widgets/text-input.d.ts +28 -18
- package/dist/widgets/text-input.js +144 -101
- package/dist/widgets/widget-app.d.ts +19 -3
- package/dist/widgets/widget-app.js +39 -21
- package/dist/widgets/widget-base.js +0 -3
- package/package.json +2 -5
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whitespace as Python reads it — `str.isspace`, `str.strip`, and `\s` in a
|
|
3
|
+
* `str` pattern of `re`, which are one set. markdown-it-py, the markdown-it
|
|
4
|
+
* Rich runs, reads whitespace through all three, and that set is not
|
|
5
|
+
* JavaScript's: `\s` and `trim` take U+FEFF, which Python does not, and leave
|
|
6
|
+
* U+001C–U+001F and U+0085, which Python takes.
|
|
7
|
+
*/
|
|
8
|
+
/** The set as a regex character class, every member of it a single UTF-16 unit, for composing into a pattern where markdown-it-py's has `\s`. */
|
|
9
|
+
export const PY_WHITESPACE = String.raw `[\t-\r\x1c-\x20\x85\xa0 -
]`;
|
|
10
|
+
const PY_SPACE = new RegExp(`^${PY_WHITESPACE}$`);
|
|
11
|
+
/** Python's `str.strip`, a scan in from each end, so a run of interior whitespace costs one pass, as it does there. */
|
|
12
|
+
export function pyStrip(text) {
|
|
13
|
+
let start = 0;
|
|
14
|
+
while (start < text.length && PY_SPACE.test(text[start]))
|
|
15
|
+
start++;
|
|
16
|
+
return pyRstrip(text.slice(start));
|
|
17
|
+
}
|
|
18
|
+
/** Python's `str.rstrip`, a scan in from the end — not a `+$` pattern, which retries from every cell of an interior run. */
|
|
19
|
+
export function pyRstrip(text) {
|
|
20
|
+
let end = text.length;
|
|
21
|
+
while (end > 0 && PY_SPACE.test(text[end - 1]))
|
|
22
|
+
end--;
|
|
23
|
+
return text.slice(0, end);
|
|
24
|
+
}
|
|
@@ -1,15 +1,61 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Spinner —
|
|
2
|
+
* Spinner — a named spinner, asked for its frame at a time, with an optional
|
|
3
|
+
* label after it.
|
|
4
|
+
*
|
|
5
|
+
* A spinner is a `FrameSequence` (`./frames.ts`) over one entry of the named spinner
|
|
6
|
+
* data (`core/spinnerData.ts`): each frame held for the spinner's interval,
|
|
7
|
+
* looping, the frame in progress at `t` drawn. The data names the frames and
|
|
8
|
+
* the interval; the beat, the width every frame draws at and which frame `t`
|
|
9
|
+
* lands on are the frames primitive's, so a spinner is one more sequence on
|
|
10
|
+
* it and not a second way of turning frames. Custom frames are a `FrameSequence`
|
|
11
|
+
* drawn through `Frames` directly. [LAW:one-source-of-truth]
|
|
12
|
+
*
|
|
13
|
+
* It is built once and asked for each frame, as Rich's `Spinner` is built
|
|
14
|
+
* once and has `render(time)` called on it: the name is parsed and the
|
|
15
|
+
* styled frames are prepared where the spinner is given, and `at(t)` is what
|
|
16
|
+
* draws, so a `Status` or `SpinnerColumn` holding one pays for the name and
|
|
17
|
+
* the styling once, and a bad name fails at the call that gave it.
|
|
18
|
+
* [LAW:parse-dont-validate] What a `FrameSequence` makes of the frames —
|
|
19
|
+
* the beat, the width, each frame padded to it — is made there too, so a
|
|
20
|
+
* drawn frame costs only finding which one `t` lands on.
|
|
21
|
+
*
|
|
22
|
+
* [LAW:no-ambient-temporal-coupling] A Spinner draws nothing on its own:
|
|
23
|
+
* only `at(t)` is a renderable, so a spinner cannot be drawn without being
|
|
24
|
+
* handed its time, and nothing here reads a clock. Whoever draws frames
|
|
25
|
+
* hands each one its time (`core/clock.ts`) — `SpinnerColumn` the task's
|
|
26
|
+
* `time`, a `Live` the frame's time on its clock — as Rich's `Spinner.render`
|
|
27
|
+
* is handed `console.get_time()` or `task.get_time()`. `t` is the clock's
|
|
28
|
+
* time, as `App` and `Task.time` hand it, where Rich's spinner counts from
|
|
29
|
+
* its first draw: here nothing is kept between frames, so the same `t` draws
|
|
30
|
+
* the same bytes at one redraw a second or sixty, two spinners on one clock
|
|
31
|
+
* agree at every `t`, a `Progress` on a hand-moved clock turns its spinners
|
|
32
|
+
* on that clock, and a draw costs the same at `t = 0` and `t = 10⁶`.
|
|
33
|
+
*
|
|
34
|
+
* `speed` is a `Timeline` (`core/timeline.ts`) playing from `t = 0` at
|
|
35
|
+
* that rate, as Rich scales the time, `t × speed` into the beat: the frames
|
|
36
|
+
* are held for the interval the data gives, and the spinner is asked for the
|
|
37
|
+
* frame at the time the timeline maps the host's to. [LAW:one-source-of-truth]
|
|
38
|
+
* When the frame next changes (`Style.nextChange`) is a time on the host's
|
|
39
|
+
* timeline, and the sequence answers on its own, so the timeline carries the
|
|
40
|
+
* answer back and the drawn cells are stamped with that (`frameAt`), where
|
|
41
|
+
* the host's time is known. Backwards, the frames count down from the last at `t = 0`,
|
|
42
|
+
* a negative time landing in the last frame of the pass before, where Rich's
|
|
43
|
+
* `int()` truncation holds frame 0 for a first interval and then counts
|
|
44
|
+
* down: a departure, made so a negative speed is the one timeline run
|
|
45
|
+
* backwards and not a second rule about time. A speed of zero would hold a
|
|
46
|
+
* frame forever, which a paused timeline is and a rate is not, and the
|
|
47
|
+
* timeline refuses it.
|
|
3
48
|
*/
|
|
4
|
-
import {
|
|
49
|
+
import type { Animation } from "../core/animation.js";
|
|
5
50
|
import { Style } from "../core/style.js";
|
|
6
51
|
import { RichText } from "../core/text.js";
|
|
7
|
-
import type { Renderable, Measurable
|
|
52
|
+
import type { Renderable, Measurable } from "../core/protocol.js";
|
|
8
53
|
export interface SpinnerOptions {
|
|
54
|
+
/** Multiplies the spinner's rate; negative runs it backwards; zero is refused. Defaults to 1. */
|
|
9
55
|
speed?: number;
|
|
10
56
|
style?: string | Style;
|
|
11
57
|
}
|
|
12
|
-
export declare class Spinner implements Renderable
|
|
58
|
+
export declare class Spinner implements Animation<Renderable & Measurable> {
|
|
13
59
|
readonly name: string;
|
|
14
60
|
readonly speed: number;
|
|
15
61
|
readonly style: string | Style;
|
|
@@ -22,36 +68,36 @@ export declare class Spinner implements Renderable, Measurable {
|
|
|
22
68
|
*/
|
|
23
69
|
text: string | RichText;
|
|
24
70
|
private readonly _data;
|
|
25
|
-
private
|
|
26
|
-
private
|
|
71
|
+
private readonly _named;
|
|
72
|
+
private readonly _ascii;
|
|
27
73
|
constructor(name?: string, text?: string | RichText, options?: SpinnerOptions);
|
|
28
74
|
get frames(): readonly string[];
|
|
75
|
+
/** Milliseconds each frame is held, as the spinner data gives it. */
|
|
29
76
|
get interval(): number;
|
|
30
|
-
/** Advance the frame count by the time elapsed, and return it. */
|
|
31
|
-
private _advance;
|
|
32
|
-
/** The frames this output can draw: the `line` spinner stands in for any other on an ASCII-only one. */
|
|
33
|
-
private _drawnFrames;
|
|
34
77
|
/**
|
|
35
|
-
* The
|
|
36
|
-
* ended, as the reference's `Text` is —
|
|
37
|
-
* laid out in a `Progress` cell alike.
|
|
78
|
+
* The frame in progress at `t` seconds and the label, as one renderable:
|
|
79
|
+
* the line wrapped to the width and ended, as the reference's `Text` is —
|
|
80
|
+
* printed, stacked in a `Group`, or laid out in a `Progress` cell alike.
|
|
81
|
+
* The frames this output can draw are chosen where the output is known.
|
|
38
82
|
*/
|
|
39
|
-
|
|
40
|
-
private _currentLine;
|
|
83
|
+
at(t: number): Renderable & Measurable;
|
|
41
84
|
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
85
|
+
* When the spinner drawn at `t` next turns, on the host's clock: the
|
|
86
|
+
* sooner of its two sequences' answers, since which one is drawn is the
|
|
87
|
+
* output's to choose and the line spinner that stands in on an ASCII-only
|
|
88
|
+
* output keeps its own interval. An early answer, on the output that draws
|
|
89
|
+
* the other one, which the contract allows; the drawn cells carry the exact one.
|
|
46
90
|
*/
|
|
47
|
-
|
|
91
|
+
nextChange(t: number): number;
|
|
92
|
+
/** When the spinner drawn at `t` began to be drawn: the later of its two sequences' answers, by the same argument. */
|
|
93
|
+
lastChange(t: number): number;
|
|
94
|
+
private _render;
|
|
48
95
|
/**
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
96
|
+
* The frame in progress and the label as one text, as Rich's
|
|
97
|
+
* `Text.assemble(frame, " ", text)`: a long label wraps as one line with its
|
|
98
|
+
* frame. A label that draws nothing — the default `""`, or markup that
|
|
99
|
+
* styles nothing — is no label, not a trailing space, as an empty `Text` is
|
|
100
|
+
* falsy there.
|
|
52
101
|
*/
|
|
53
|
-
|
|
54
|
-
minimum: number;
|
|
55
|
-
maximum: number;
|
|
56
|
-
};
|
|
102
|
+
private _line;
|
|
57
103
|
}
|
|
@@ -1,14 +1,64 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Spinner —
|
|
2
|
+
* Spinner — a named spinner, asked for its frame at a time, with an optional
|
|
3
|
+
* label after it.
|
|
4
|
+
*
|
|
5
|
+
* A spinner is a `FrameSequence` (`./frames.ts`) over one entry of the named spinner
|
|
6
|
+
* data (`core/spinnerData.ts`): each frame held for the spinner's interval,
|
|
7
|
+
* looping, the frame in progress at `t` drawn. The data names the frames and
|
|
8
|
+
* the interval; the beat, the width every frame draws at and which frame `t`
|
|
9
|
+
* lands on are the frames primitive's, so a spinner is one more sequence on
|
|
10
|
+
* it and not a second way of turning frames. Custom frames are a `FrameSequence`
|
|
11
|
+
* drawn through `Frames` directly. [LAW:one-source-of-truth]
|
|
12
|
+
*
|
|
13
|
+
* It is built once and asked for each frame, as Rich's `Spinner` is built
|
|
14
|
+
* once and has `render(time)` called on it: the name is parsed and the
|
|
15
|
+
* styled frames are prepared where the spinner is given, and `at(t)` is what
|
|
16
|
+
* draws, so a `Status` or `SpinnerColumn` holding one pays for the name and
|
|
17
|
+
* the styling once, and a bad name fails at the call that gave it.
|
|
18
|
+
* [LAW:parse-dont-validate] What a `FrameSequence` makes of the frames —
|
|
19
|
+
* the beat, the width, each frame padded to it — is made there too, so a
|
|
20
|
+
* drawn frame costs only finding which one `t` lands on.
|
|
21
|
+
*
|
|
22
|
+
* [LAW:no-ambient-temporal-coupling] A Spinner draws nothing on its own:
|
|
23
|
+
* only `at(t)` is a renderable, so a spinner cannot be drawn without being
|
|
24
|
+
* handed its time, and nothing here reads a clock. Whoever draws frames
|
|
25
|
+
* hands each one its time (`core/clock.ts`) — `SpinnerColumn` the task's
|
|
26
|
+
* `time`, a `Live` the frame's time on its clock — as Rich's `Spinner.render`
|
|
27
|
+
* is handed `console.get_time()` or `task.get_time()`. `t` is the clock's
|
|
28
|
+
* time, as `App` and `Task.time` hand it, where Rich's spinner counts from
|
|
29
|
+
* its first draw: here nothing is kept between frames, so the same `t` draws
|
|
30
|
+
* the same bytes at one redraw a second or sixty, two spinners on one clock
|
|
31
|
+
* agree at every `t`, a `Progress` on a hand-moved clock turns its spinners
|
|
32
|
+
* on that clock, and a draw costs the same at `t = 0` and `t = 10⁶`.
|
|
33
|
+
*
|
|
34
|
+
* `speed` is a `Timeline` (`core/timeline.ts`) playing from `t = 0` at
|
|
35
|
+
* that rate, as Rich scales the time, `t × speed` into the beat: the frames
|
|
36
|
+
* are held for the interval the data gives, and the spinner is asked for the
|
|
37
|
+
* frame at the time the timeline maps the host's to. [LAW:one-source-of-truth]
|
|
38
|
+
* When the frame next changes (`Style.nextChange`) is a time on the host's
|
|
39
|
+
* timeline, and the sequence answers on its own, so the timeline carries the
|
|
40
|
+
* answer back and the drawn cells are stamped with that (`frameAt`), where
|
|
41
|
+
* the host's time is known. Backwards, the frames count down from the last at `t = 0`,
|
|
42
|
+
* a negative time landing in the last frame of the pass before, where Rich's
|
|
43
|
+
* `int()` truncation holds frame 0 for a first interval and then counts
|
|
44
|
+
* down: a departure, made so a negative speed is the one timeline run
|
|
45
|
+
* backwards and not a second rule about time. A speed of zero would hold a
|
|
46
|
+
* frame forever, which a paused timeline is and a rate is not, and the
|
|
47
|
+
* timeline refuses it.
|
|
3
48
|
*/
|
|
4
|
-
import { cellLen } from "../core/cells.js";
|
|
5
49
|
import { Segment } from "../core/segment.js";
|
|
6
50
|
import { NULL_STYLE } from "../core/style.js";
|
|
7
51
|
import { RichText } from "../core/text.js";
|
|
8
52
|
import { SPINNERS, DEFAULT_SPINNER, LINE_SPINNER } from "../core/spinnerData.js";
|
|
9
|
-
import {
|
|
53
|
+
import { Timeline } from "../core/timeline.js";
|
|
54
|
+
import { drawable, render } from "../core/protocol.js";
|
|
10
55
|
import { EmbeddedText } from "./embed.js";
|
|
11
|
-
|
|
56
|
+
import { FrameSequence, frameAt } from "./frames.js";
|
|
57
|
+
const sequence = (data, style, timeline) => {
|
|
58
|
+
const frames = new FrameSequence(data.frames.map((frame) => ({ text: new RichText("", { end: "" }).append(frame, style), seconds: data.interval / 1000 })));
|
|
59
|
+
return { frames, played: Timeline.run(timeline, frames), glyphs: data.frames.join("") };
|
|
60
|
+
};
|
|
61
|
+
const sequenceGlyphs = ({ glyphs }) => glyphs;
|
|
12
62
|
export class Spinner {
|
|
13
63
|
name;
|
|
14
64
|
speed;
|
|
@@ -22,82 +72,91 @@ export class Spinner {
|
|
|
22
72
|
*/
|
|
23
73
|
text;
|
|
24
74
|
_data;
|
|
25
|
-
|
|
26
|
-
|
|
75
|
+
// The named data's frames, and the `line` spinner's that stand in for them
|
|
76
|
+
// on an ASCII-only output: prepared once, which is drawn chosen at `at`.
|
|
77
|
+
_named;
|
|
78
|
+
_ascii;
|
|
27
79
|
constructor(name, text = "", options) {
|
|
28
80
|
const spinnerName = name ?? DEFAULT_SPINNER;
|
|
29
81
|
const data = SPINNERS[spinnerName];
|
|
30
82
|
if (!data) {
|
|
31
83
|
throw new Error(`Unknown spinner: "${spinnerName}"`);
|
|
32
84
|
}
|
|
85
|
+
const speed = options?.speed ?? 1;
|
|
86
|
+
// [LAW:single-enforcer] A rate is finite and not zero, and the timeline
|
|
87
|
+
// refuses one that is not where it is built.
|
|
88
|
+
const timeline = Timeline.play(0, speed);
|
|
33
89
|
this.name = spinnerName;
|
|
34
90
|
this.text = text;
|
|
35
|
-
this.speed =
|
|
91
|
+
this.speed = speed;
|
|
36
92
|
this.style = options?.style ?? NULL_STYLE;
|
|
37
93
|
this._data = data;
|
|
38
|
-
this.
|
|
39
|
-
this.
|
|
94
|
+
this._named = sequence(data, this.style, timeline);
|
|
95
|
+
this._ascii = sequence(LINE_SPINNER, this.style, timeline);
|
|
40
96
|
}
|
|
41
97
|
get frames() {
|
|
42
98
|
return this._data.frames;
|
|
43
99
|
}
|
|
100
|
+
/** Milliseconds each frame is held, as the spinner data gives it. */
|
|
44
101
|
get interval() {
|
|
45
102
|
return this._data.interval;
|
|
46
103
|
}
|
|
47
|
-
/**
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
this._lastUpdate = now;
|
|
104
|
+
/**
|
|
105
|
+
* The frame in progress at `t` seconds and the label, as one renderable:
|
|
106
|
+
* the line wrapped to the width and ended, as the reference's `Text` is —
|
|
107
|
+
* printed, stacked in a `Group`, or laid out in a `Progress` cell alike.
|
|
108
|
+
* The frames this output can draw are chosen where the output is known.
|
|
109
|
+
*/
|
|
110
|
+
at(t) {
|
|
111
|
+
if (!Number.isFinite(t)) {
|
|
112
|
+
throw new RangeError(`Spinner.at needs a finite t, got ${t}`);
|
|
57
113
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
114
|
+
const drawn = (options) => drawable(options, this._named, this._ascii, sequenceGlyphs);
|
|
115
|
+
return {
|
|
116
|
+
render: (options) => this._render(drawn(options), t, options),
|
|
117
|
+
// Measured at the frames' one width, the widest frame's, so a column
|
|
118
|
+
// holding it never narrows as it turns, and never offered less than
|
|
119
|
+
// that frame: a frame is one picture, which the reference's `Text`
|
|
120
|
+
// measure would let wrap apart at its spaces.
|
|
121
|
+
measure: (options) => {
|
|
122
|
+
const { frames, played } = drawn(options);
|
|
123
|
+
const { minimum, maximum } = this._line(played, t, options).measure(options);
|
|
124
|
+
return { minimum: Math.max(minimum, Math.min(frames.width, maximum)), maximum };
|
|
125
|
+
},
|
|
126
|
+
};
|
|
63
127
|
}
|
|
64
128
|
/**
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
129
|
+
* When the spinner drawn at `t` next turns, on the host's clock: the
|
|
130
|
+
* sooner of its two sequences' answers, since which one is drawn is the
|
|
131
|
+
* output's to choose and the line spinner that stands in on an ASCII-only
|
|
132
|
+
* output keeps its own interval. An early answer, on the output that draws
|
|
133
|
+
* the other one, which the contract allows; the drawn cells carry the exact one.
|
|
68
134
|
*/
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
yield Segment.line();
|
|
135
|
+
nextChange(t) {
|
|
136
|
+
return Math.min(this._named.played.nextChange(t), this._ascii.played.nextChange(t));
|
|
72
137
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
return
|
|
138
|
+
/** When the spinner drawn at `t` began to be drawn: the later of its two sequences' answers, by the same argument. */
|
|
139
|
+
lastChange(t) {
|
|
140
|
+
return Math.max(this._named.played.lastChange(t), this._ascii.played.lastChange(t));
|
|
141
|
+
}
|
|
142
|
+
*_render({ played }, t, options) {
|
|
143
|
+
yield* render(this._line(played, t, options), options);
|
|
144
|
+
yield Segment.line();
|
|
76
145
|
}
|
|
77
146
|
/**
|
|
78
|
-
*
|
|
79
|
-
* text)`: a long label wraps as one line with its
|
|
80
|
-
* nothing — the default `""`, or markup that
|
|
81
|
-
* not a trailing space, as an empty `Text` is
|
|
147
|
+
* The frame in progress and the label as one text, as Rich's
|
|
148
|
+
* `Text.assemble(frame, " ", text)`: a long label wraps as one line with its
|
|
149
|
+
* frame. A label that draws nothing — the default `""`, or markup that
|
|
150
|
+
* styles nothing — is no label, not a trailing space, as an empty `Text` is
|
|
151
|
+
* falsy there.
|
|
82
152
|
*/
|
|
83
|
-
_line(
|
|
84
|
-
|
|
153
|
+
_line(played, t, options) {
|
|
154
|
+
// The frame's cells say when it turns on the host's clock, the label's keep their own word.
|
|
155
|
+
const line = new RichText("", { end: "" }).append(frameAt(played, t));
|
|
85
156
|
// Unhighlighted: Rich's label is a `Text` from the moment it is handed over, and a `Text` is never highlighted.
|
|
86
157
|
const label = new EmbeddedText(this.text).text({ ...options, highlight: false });
|
|
87
158
|
if (label.plain !== "")
|
|
88
159
|
line.append(" ").append(label);
|
|
89
160
|
return line;
|
|
90
161
|
}
|
|
91
|
-
/**
|
|
92
|
-
* Measured at its widest frame, so a column holding it never narrows as it
|
|
93
|
-
* turns, and never offered less than that frame: a frame is one picture,
|
|
94
|
-
* which the reference's `Text` measure would let wrap apart at its spaces.
|
|
95
|
-
*/
|
|
96
|
-
measure(options) {
|
|
97
|
-
const frames = this._drawnFrames(options);
|
|
98
|
-
const widths = frames.map((frame) => cellLen(frame));
|
|
99
|
-
const frameWidth = Math.max(...widths);
|
|
100
|
-
const { minimum, maximum } = this._line(frames[widths.indexOf(frameWidth)], options).measure(options);
|
|
101
|
-
return { minimum: Math.max(minimum, Math.min(frameWidth, maximum)), maximum };
|
|
102
|
-
}
|
|
103
162
|
}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Status — displays a spinner animation with a status message.
|
|
3
3
|
*
|
|
4
|
-
* Its
|
|
5
|
-
*
|
|
6
|
-
* under the console that draws it.
|
|
4
|
+
* Its view is a `Spinner` whose label is the message, as Rich's is, so the
|
|
5
|
+
* message is drawn the way the spinner draws its label: a string is markup
|
|
6
|
+
* under the console that draws it. The `Live` hands each frame its time, and
|
|
7
|
+
* the spinner is asked for its frame at it, so the frame is the clock's, not
|
|
8
|
+
* the platform's. [LAW:no-ambient-temporal-coupling]
|
|
7
9
|
*/
|
|
10
|
+
import type { Clock } from "../core/clock.js";
|
|
8
11
|
import type { Style } from "../core/style.js";
|
|
9
12
|
import type { RichText } from "../core/text.js";
|
|
10
13
|
import { Console } from "../core/console.js";
|
|
@@ -14,6 +17,8 @@ export interface StatusOptions {
|
|
|
14
17
|
/** The spinner's frame style; the message styles itself with its markup. */
|
|
15
18
|
spinnerStyle?: string | Style;
|
|
16
19
|
console?: Console;
|
|
20
|
+
/** What the frames are timed and drawn on. The platform's, unless given. */
|
|
21
|
+
clock?: Clock;
|
|
17
22
|
}
|
|
18
23
|
export declare class Status {
|
|
19
24
|
private _live;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Status — displays a spinner animation with a status message.
|
|
3
3
|
*
|
|
4
|
-
* Its
|
|
5
|
-
*
|
|
6
|
-
* under the console that draws it.
|
|
4
|
+
* Its view is a `Spinner` whose label is the message, as Rich's is, so the
|
|
5
|
+
* message is drawn the way the spinner draws its label: a string is markup
|
|
6
|
+
* under the console that draws it. The `Live` hands each frame its time, and
|
|
7
|
+
* the spinner is asked for its frame at it, so the frame is the clock's, not
|
|
8
|
+
* the platform's. [LAW:no-ambient-temporal-coupling]
|
|
7
9
|
*/
|
|
8
10
|
import { Console } from "../core/console.js";
|
|
9
11
|
import { Spinner } from "./spinner.js";
|
|
@@ -18,8 +20,9 @@ export class Status {
|
|
|
18
20
|
speed: options?.speed,
|
|
19
21
|
style: options?.spinnerStyle ?? "status.spinner",
|
|
20
22
|
});
|
|
21
|
-
this._live = new Live(this._spinner, {
|
|
23
|
+
this._live = new Live((t) => this._spinner.at(t), {
|
|
22
24
|
console: this._console,
|
|
25
|
+
clock: options?.clock,
|
|
23
26
|
transient: true,
|
|
24
27
|
refreshPerSecond: 12.5,
|
|
25
28
|
});
|
|
@@ -41,6 +44,6 @@ export class Status {
|
|
|
41
44
|
}
|
|
42
45
|
update(message) {
|
|
43
46
|
this._spinner.text = message;
|
|
44
|
-
this._live.
|
|
47
|
+
this._live.refresh();
|
|
45
48
|
}
|
|
46
49
|
}
|
|
@@ -11,6 +11,7 @@ import { cellLen, expandTabs, parseTabSize } from "../core/cells.js";
|
|
|
11
11
|
import { Segment } from "../core/segment.js";
|
|
12
12
|
import { RichText } from "../core/text.js";
|
|
13
13
|
import { drawable, groundedStyle, getStyle, withBoundedWidth, withCellWidth, } from "../core/protocol.js";
|
|
14
|
+
import { render } from "../core/protocol.js";
|
|
14
15
|
/**
|
|
15
16
|
* One regex per grammar, each token a named alternative. A single left-to-right
|
|
16
17
|
* scan is what keeps a `//` inside a string from starting a comment, and a
|
|
@@ -140,7 +141,7 @@ export class Syntax {
|
|
|
140
141
|
const lineNo = first + i;
|
|
141
142
|
const style = this.highlightLines.has(lineNo) ? highlightStyle : numberStyle;
|
|
142
143
|
// Terminated, so an empty line is one empty row rather than none.
|
|
143
|
-
const rows = Segment.splitLines([...textLines[i]
|
|
144
|
+
const rows = Segment.splitLines([...render(textLines[i], lineOptions), Segment.line()]);
|
|
144
145
|
for (let row = 0; row < rows.length; row++) {
|
|
145
146
|
if (this.lineNumbers) {
|
|
146
147
|
// A wrapped line's continuation rows keep the gutter, unnumbered.
|
|
@@ -6,7 +6,7 @@ import { Style } from "../core/style.js";
|
|
|
6
6
|
import { Box } from "../core/box.js";
|
|
7
7
|
import { RichText } from "../core/text.js";
|
|
8
8
|
import type { PaddingDimensions } from "./padding.js";
|
|
9
|
-
import type { Renderable, Measurable, OverflowMethod, RenderOptions } from "../core/protocol.js";
|
|
9
|
+
import type { Composite, Renderable, Measurable, OverflowMethod, RenderOptions } from "../core/protocol.js";
|
|
10
10
|
export interface ColumnOptions {
|
|
11
11
|
/** Anything a cell can hold, as Rich's `RenderableType` header is. */
|
|
12
12
|
header?: string | RichText | Renderable;
|
|
@@ -98,7 +98,7 @@ export interface TableOptions {
|
|
|
98
98
|
/** The `highlight` every column `addColumn` makes takes unless told otherwise (default: `false`). */
|
|
99
99
|
highlight?: boolean;
|
|
100
100
|
}
|
|
101
|
-
export declare class Table implements Renderable, Measurable {
|
|
101
|
+
export declare class Table implements Renderable, Measurable, Composite {
|
|
102
102
|
private _columns;
|
|
103
103
|
private _rows;
|
|
104
104
|
readonly box: Box | null;
|
|
@@ -183,8 +183,11 @@ export declare class Table implements Renderable, Measurable {
|
|
|
183
183
|
* mode gets its own path through the width division.
|
|
184
184
|
*
|
|
185
185
|
* Cells are measured against the width left once the frame is paid, as the
|
|
186
|
-
* reference's `_measure_column` measures them. Padding
|
|
187
|
-
*
|
|
186
|
+
* reference's `_measure_column` measures them. Padding is part of every
|
|
187
|
+
* width the demand names, because the reference measures a cell wrapped in
|
|
188
|
+
* its `Padding`, and each sizing adds it where the reference does — a
|
|
189
|
+
* rowless column's minimum is the one width it never reaches. The floor is
|
|
190
|
+
* laid over whichever sizing the column has.
|
|
188
191
|
*/
|
|
189
192
|
private _columnDemands;
|
|
190
193
|
private _columnSizing;
|
|
@@ -198,6 +201,8 @@ export declare class Table implements Renderable, Measurable {
|
|
|
198
201
|
*/
|
|
199
202
|
private _columnPadding;
|
|
200
203
|
private _rowPadding;
|
|
204
|
+
contents(): Iterable<Renderable>;
|
|
205
|
+
private _rowCells;
|
|
201
206
|
/**
|
|
202
207
|
* Every cell column `index` draws, in draw order.
|
|
203
208
|
*
|
|
@@ -211,19 +216,22 @@ export declare class Table implements Renderable, Measurable {
|
|
|
211
216
|
*/
|
|
212
217
|
private _columnCells;
|
|
213
218
|
/**
|
|
214
|
-
* The widest any cell in a column draws,
|
|
215
|
-
* without cutting one — the reference's
|
|
216
|
-
* when the column has no cell to measure.
|
|
217
|
-
*
|
|
218
|
-
* same answer.
|
|
219
|
+
* The widest any cell in a column draws, its padding included, and the
|
|
220
|
+
* narrowest the column can be without cutting one — the reference's
|
|
221
|
+
* `_measure_column` — or `undefined` when the column has no cell to measure.
|
|
222
|
+
* A column whose cells draw nothing measures its padding — a gutter asks for
|
|
223
|
+
* that and nothing else — which is not the same answer.
|
|
224
|
+
* [LAW:types-are-the-program]
|
|
219
225
|
*/
|
|
220
226
|
private _cellRange;
|
|
221
227
|
/**
|
|
222
|
-
* A natural width held to the column's own `minWidth`/`maxWidth
|
|
228
|
+
* A natural width held to the column's own `minWidth`/`maxWidth`, each
|
|
229
|
+
* widened by the column's `pad`, as the reference clamps a padded
|
|
230
|
+
* measurement to `min_width + padding_width`.
|
|
223
231
|
*
|
|
224
232
|
* A bound is a count of cells, read by the rule every width is read by: NaN
|
|
225
233
|
* and a negative are zero cells, so a NaN floor bounds nothing and a NaN
|
|
226
|
-
* ceiling
|
|
234
|
+
* ceiling holds the column to its padding alone, as `width: NaN` does. A bare `Math.max` returns
|
|
227
235
|
* NaN instead, and the column vanishes. [LAW:one-source-of-truth]
|
|
228
236
|
*/
|
|
229
237
|
private _bounded;
|