@promptctl/rich-js 0.26.0 → 0.28.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 +1 -0
- package/THIRD-PARTY-NOTICES +42 -0
- package/dist/core/animation.d.ts +52 -15
- package/dist/core/animation.js +82 -37
- package/dist/core/ansi.d.ts +15 -8
- package/dist/core/ansi.js +106 -28
- 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 +93 -5
- package/dist/core/color.d.ts +26 -18
- package/dist/core/color.js +37 -34
- package/dist/core/console.d.ts +26 -1
- package/dist/core/console.js +26 -6
- package/dist/core/control-codes.d.ts +61 -0
- package/dist/core/control-codes.js +157 -0
- package/dist/core/easing.js +6 -1
- package/dist/core/env.d.ts +6 -0
- package/dist/core/env.js +9 -1
- package/dist/core/export-html.js +4 -3
- package/dist/core/export-lines.d.ts +2 -0
- package/dist/core/export-lines.js +7 -3
- package/dist/core/export-svg.js +6 -5
- package/dist/core/json.js +9 -2
- package/dist/core/markup.js +4 -3
- package/dist/core/oklch.d.ts +2 -0
- package/dist/core/oklch.js +3 -3
- 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/pretty.js +22 -18
- package/dist/core/protocol.d.ts +53 -22
- package/dist/core/protocol.js +14 -6
- package/dist/core/render.d.ts +8 -3
- package/dist/core/render.js +19 -5
- package/dist/core/seal.d.ts +26 -0
- package/dist/core/seal.js +75 -0
- package/dist/core/segment.d.ts +9 -1
- package/dist/core/segment.js +11 -1
- package/dist/core/style.d.ts +29 -1
- package/dist/core/style.js +41 -5
- package/dist/core/text-order.d.ts +51 -0
- package/dist/core/text-order.js +50 -0
- package/dist/core/text.d.ts +10 -0
- package/dist/core/text.js +133 -87
- package/dist/core/timeline.js +6 -6
- package/dist/core/view.d.ts +23 -9
- package/dist/core/view.js +37 -12
- package/dist/core/wrap.d.ts +24 -6
- package/dist/core/wrap.js +82 -16
- package/dist/host/app.d.ts +48 -7
- package/dist/host/app.js +116 -11
- package/dist/host/index.d.ts +3 -2
- package/dist/host/index.js +1 -0
- package/dist/host/input.d.ts +35 -2
- package/dist/host/input.js +88 -4
- package/dist/host/terminal-colors.d.ts +18 -0
- package/dist/host/terminal-colors.js +46 -0
- package/dist/host/terminal-host.d.ts +2 -1
- package/dist/index.d.ts +10 -8
- package/dist/index.js +2 -2
- package/dist/renderables/change.d.ts +1 -3
- package/dist/renderables/change.js +4 -6
- package/dist/renderables/effect.d.ts +61 -60
- package/dist/renderables/effect.js +91 -81
- package/dist/renderables/effects.d.ts +37 -8
- package/dist/renderables/effects.js +193 -55
- package/dist/renderables/frames.d.ts +1 -10
- package/dist/renderables/frames.js +1 -16
- package/dist/renderables/glyph-effect.d.ts +12 -13
- package/dist/renderables/glyph-effect.js +34 -32
- package/dist/renderables/glyph-effects.d.ts +27 -8
- package/dist/renderables/glyph-effects.js +75 -7
- package/dist/renderables/lifecycle.d.ts +40 -32
- package/dist/renderables/lifecycle.js +87 -48
- package/dist/renderables/live.d.ts +3 -3
- package/dist/renderables/live.js +4 -4
- package/dist/renderables/markdown.js +4 -2
- package/dist/renderables/panel.js +6 -4
- package/dist/renderables/progress.d.ts +11 -4
- package/dist/renderables/progress.js +29 -17
- package/dist/renderables/progressBar.d.ts +3 -3
- package/dist/renderables/progressBar.js +16 -13
- package/dist/renderables/syntax.js +7 -2
- package/dist/renderables/table.js +2 -1
- package/dist/template-bindings/animation-funcs.d.ts +49 -18
- package/dist/template-bindings/animation-funcs.js +115 -32
- package/dist/template-bindings/index.d.ts +7 -5
- package/dist/template-bindings/index.js +8 -5
- package/dist/template-bindings/palette-funcs.d.ts +1 -1
- package/dist/template-bindings/palette-funcs.js +1 -1
- package/dist/themes/buildPalette.d.ts +15 -39
- package/dist/themes/buildPalette.js +196 -67
- package/dist/themes/colorMath.d.ts +10 -4
- package/dist/themes/colorMath.js +33 -1
- package/dist/themes/data/index.js +1 -4
- package/dist/themes/data/textual-ansi.js +0 -143
- package/dist/themes/data/types.d.ts +3 -1
- package/dist/themes/palette.d.ts +22 -6
- package/dist/themes/palette.js +13 -21
- package/dist/themes/ramp.d.ts +1 -1
- package/dist/themes/ramp.js +1 -1
- package/dist/themes/registry.d.ts +7 -10
- package/dist/themes/registry.js +9 -30
- package/dist/themes/terminalThemes.d.ts +4 -10
- package/dist/themes/terminalThemes.js +31 -46
- package/dist/themes/transpose.d.ts +5 -10
- package/dist/themes/transpose.js +13 -24
- package/dist/widgets/button.d.ts +1 -1
- package/dist/widgets/button.js +6 -6
- package/dist/widgets/checkbox.js +4 -4
- package/dist/widgets/dropdown.d.ts +1 -1
- package/dist/widgets/dropdown.js +7 -5
- package/dist/widgets/event-router.js +2 -2
- package/dist/widgets/ink.d.ts +5 -4
- package/dist/widgets/ink.js +6 -9
- package/dist/widgets/text-input.d.ts +1 -1
- package/dist/widgets/text-input.js +41 -32
- package/dist/widgets/themed-widget.js +3 -3
- package/dist/widgets/toggle.d.ts +1 -1
- package/dist/widgets/toggle.js +5 -5
- package/dist/widgets/types.d.ts +2 -2
- package/dist/widgets/widget-app.d.ts +3 -3
- package/dist/widgets/widget-app.js +5 -5
- package/package.json +5 -4
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
*/
|
|
27
27
|
import { type Clock } from "../core/clock.js";
|
|
28
28
|
import { Console } from "../core/console.js";
|
|
29
|
-
import { type FrameHost } from "../core/protocol.js";
|
|
29
|
+
import { type HostFrame, type FrameHost } from "../core/protocol.js";
|
|
30
30
|
import { Timeline } from "../core/timeline.js";
|
|
31
31
|
import { type View } from "../core/view.js";
|
|
32
32
|
export interface LiveOptions {
|
|
@@ -79,8 +79,8 @@ export declare class Live implements FrameHost {
|
|
|
79
79
|
get clock(): Clock;
|
|
80
80
|
/** The map from the clock to the time the view is drawn for. */
|
|
81
81
|
get timeline(): Timeline;
|
|
82
|
-
/** The
|
|
83
|
-
|
|
82
|
+
/** The frame this Live draws now (`FrameHost`): the clock's now, through the timeline, on a frame it is the host of. */
|
|
83
|
+
frameNow(): HostFrame;
|
|
84
84
|
private _time;
|
|
85
85
|
/**
|
|
86
86
|
* Replace the timeline and draw the frame for the time it now maps the
|
package/dist/renderables/live.js
CHANGED
|
@@ -30,7 +30,7 @@ import { Segment } from "../core/segment.js";
|
|
|
30
30
|
import { FinalFramePainter, SurfacePainter } from "../core/paint.js";
|
|
31
31
|
import { fitHeight, render } from "../core/protocol.js";
|
|
32
32
|
import { Timeline } from "../core/timeline.js";
|
|
33
|
-
import { drawView,
|
|
33
|
+
import { drawView, frameNow, hostView, undrawn } from "../core/view.js";
|
|
34
34
|
import { State } from "../core/state.js";
|
|
35
35
|
// Nothing: what a Live made with no view draws until `update` gives it one.
|
|
36
36
|
const NOTHING = { render: () => [] };
|
|
@@ -89,9 +89,9 @@ export class Live {
|
|
|
89
89
|
get timeline() {
|
|
90
90
|
return this._timeline.get();
|
|
91
91
|
}
|
|
92
|
-
/** The
|
|
93
|
-
|
|
94
|
-
return
|
|
92
|
+
/** The frame this Live draws now (`FrameHost`): the clock's now, through the timeline, on a frame it is the host of. */
|
|
93
|
+
frameNow() {
|
|
94
|
+
return frameNow(this, this._time());
|
|
95
95
|
}
|
|
96
96
|
_time() {
|
|
97
97
|
return { now: this._clock.now(), epoch: this._epoch, timeline: this._timeline.get() };
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* followed: HTML, a block of it or a tag inline, is drawn as Rich draws it,
|
|
9
9
|
* not at all.
|
|
10
10
|
*/
|
|
11
|
+
import { withoutExplicit } from "../core/bidi.js";
|
|
11
12
|
import { cellCount, cellLen } from "../core/cells.js";
|
|
12
13
|
import { Segment } from "../core/segment.js";
|
|
13
14
|
import { Style } from "../core/style.js";
|
|
@@ -107,7 +108,8 @@ function appendInline(result, inlines, settings, options) {
|
|
|
107
108
|
};
|
|
108
109
|
const write = (text, styles) => {
|
|
109
110
|
const start = result.length;
|
|
110
|
-
|
|
111
|
+
// Each inline node is its own content, so what it holds open ends with it.
|
|
112
|
+
result.append(new RichText(text));
|
|
111
113
|
paint(start, styles);
|
|
112
114
|
};
|
|
113
115
|
const enter = (styles) => {
|
|
@@ -156,7 +158,7 @@ function appendInline(result, inlines, settings, options) {
|
|
|
156
158
|
write("\n");
|
|
157
159
|
break;
|
|
158
160
|
case "code":
|
|
159
|
-
write(inline.code, [groundedStyle(options, resolveStyle(options, settings.inlineCodeStyle))]);
|
|
161
|
+
write(withoutExplicit(inline.code), [groundedStyle(options, resolveStyle(options, settings.inlineCodeStyle))]);
|
|
160
162
|
break;
|
|
161
163
|
case "html":
|
|
162
164
|
kbd(inline.content);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Panel — a bordered box that wraps content, with optional title and subtitle.
|
|
3
3
|
*/
|
|
4
|
+
import { labelled } from "../core/orient.js";
|
|
4
5
|
import { cellLen, setCellSize, asCellCol, cellCount } from "../core/cells.js";
|
|
5
6
|
import { Segment } from "../core/segment.js";
|
|
6
7
|
import { NULL_STYLE } from "../core/style.js";
|
|
@@ -42,10 +43,11 @@ function borderTitle(label, options) {
|
|
|
42
43
|
* its own laid over the border's, the one rule for "what colour is the title
|
|
43
44
|
* text in". Laid over rather than in place of it, as Rich's `stylize_before`
|
|
44
45
|
* does, because the border's style carries the panel's own: a title that
|
|
45
|
-
* replaced it cut a hole in the panel's background on the top row.
|
|
46
|
+
* replaced it cut a hole in the panel's background on the top row. The text
|
|
47
|
+
* is set into the frame and is not of it.
|
|
46
48
|
*/
|
|
47
49
|
function borderTextStyle(border, own) {
|
|
48
|
-
return
|
|
50
|
+
return border.add(own).withBoxFrame(undefined);
|
|
49
51
|
}
|
|
50
52
|
/**
|
|
51
53
|
* A border row: the opening corner, the rule across `span` cells with `label`
|
|
@@ -129,7 +131,7 @@ export class Panel {
|
|
|
129
131
|
// and the content is rendered on top of it. Applied to the padding alone,
|
|
130
132
|
// "white on dark_blue" drew a blue ring with a hole where the text was.
|
|
131
133
|
const borderStyle = getStyle(options, this.style).add(getStyle(options, this.borderStyle));
|
|
132
|
-
const border =
|
|
134
|
+
const border = box.frame(borderStyle);
|
|
133
135
|
const geometry = layoutPanel(this._getPanelWidth(options));
|
|
134
136
|
const bodyLines = this._renderBody(options, geometry.spanWidth);
|
|
135
137
|
yield* this._renderTopBorder(options, box, geometry, border);
|
|
@@ -241,7 +243,7 @@ export class Panel {
|
|
|
241
243
|
const corner = box.bottom.right.repeat(geometry.right);
|
|
242
244
|
const [close, afterAccessory] = accessoryText === "" ? [corner, ""] : ["", corner];
|
|
243
245
|
yield* borderRow(options, box.bottom, geometry, geometry.spanWidth - cellLen(accessoryText), this._subtitleLabel, subtitleStyle, border, close);
|
|
244
|
-
yield
|
|
246
|
+
yield* labelled("", accessoryText, "", borderTextStyle(border, accessoryOwn), options.textOrder);
|
|
245
247
|
yield new Segment(afterAccessory, border);
|
|
246
248
|
yield Segment.line();
|
|
247
249
|
}
|
|
@@ -7,7 +7,7 @@ import { Console } from "../core/console.js";
|
|
|
7
7
|
import type { Style } from "../core/style.js";
|
|
8
8
|
import type { Clock } from "../core/clock.js";
|
|
9
9
|
import { type ColumnOptions } from "./table.js";
|
|
10
|
-
import type { FrameHost, Renderable, RenderOptions } from "../core/protocol.js";
|
|
10
|
+
import type { HostFrame, FrameHost, Renderable, RenderOptions } from "../core/protocol.js";
|
|
11
11
|
import { Animation } from "../core/animation.js";
|
|
12
12
|
import type { Timing } from "../core/easing.js";
|
|
13
13
|
export interface TaskOptions {
|
|
@@ -156,7 +156,7 @@ export declare class MofNCompleteColumn implements ProgressColumn {
|
|
|
156
156
|
}
|
|
157
157
|
/**
|
|
158
158
|
* How a `Progress` is set up. It is drawn by one host, and every time it
|
|
159
|
-
* keeps or draws at is that host's `
|
|
159
|
+
* keeps or draws at is that host's `frameNow()`: by its own `Live`, which the
|
|
160
160
|
* options for that `Live` configure, or, given `drawnBy`, by another host —
|
|
161
161
|
* which then does all the drawing, so none of them apply.
|
|
162
162
|
*/
|
|
@@ -185,7 +185,7 @@ interface OwnLiveOptions {
|
|
|
185
185
|
interface DrawnByOptions {
|
|
186
186
|
/**
|
|
187
187
|
* The host — a `Live`, an `App` — whose frames this `Progress` is drawn in:
|
|
188
|
-
* tasks are timed by its `
|
|
188
|
+
* tasks are timed by its `frameNow()`, so they hold while its timeline is
|
|
189
189
|
* paused and run back while it is reversed. Drawn in any other host's
|
|
190
190
|
* frame, the `Progress` throws.
|
|
191
191
|
*/
|
|
@@ -207,6 +207,13 @@ export declare class Progress implements Renderable {
|
|
|
207
207
|
constructor(...columns: (ProgressColumn | ProgressOptions)[]);
|
|
208
208
|
/** The console its own `Live` prints above the bars through. */
|
|
209
209
|
get console(): Console;
|
|
210
|
+
/**
|
|
211
|
+
* The frame its host draws now (`FrameHost.frameNow`): what a print of
|
|
212
|
+
* this display is drawn in — `console.print(progress, { frame:
|
|
213
|
+
* progress.frameNow() })` — so a still of it is drawn for a moment on the
|
|
214
|
+
* clock its tasks are timed on, the one the program asked at.
|
|
215
|
+
*/
|
|
216
|
+
frameNow(): HostFrame;
|
|
210
217
|
/** Rich's `Progress.finished`: every task finished, and so true with none. */
|
|
211
218
|
get finished(): boolean;
|
|
212
219
|
static getDefaultColumns(): ProgressColumn[];
|
|
@@ -224,7 +231,7 @@ export declare class Progress implements Renderable {
|
|
|
224
231
|
refresh(): void;
|
|
225
232
|
private _ownLive;
|
|
226
233
|
render(options: RenderOptions): Iterable<Segment>;
|
|
227
|
-
private
|
|
234
|
+
private _ownFrame;
|
|
228
235
|
private _table;
|
|
229
236
|
}
|
|
230
237
|
export declare function track<T>(iterable: Iterable<T>, options?: {
|
|
@@ -321,9 +321,20 @@ export class Progress {
|
|
|
321
321
|
get console() {
|
|
322
322
|
return this._ownLive("console").console;
|
|
323
323
|
}
|
|
324
|
+
/**
|
|
325
|
+
* The frame its host draws now (`FrameHost.frameNow`): what a print of
|
|
326
|
+
* this display is drawn in — `console.print(progress, { frame:
|
|
327
|
+
* progress.frameNow() })` — so a still of it is drawn for a moment on the
|
|
328
|
+
* clock its tasks are timed on, the one the program asked at.
|
|
329
|
+
*/
|
|
330
|
+
frameNow() {
|
|
331
|
+
return this._host.frameNow();
|
|
332
|
+
}
|
|
324
333
|
/** Rich's `Progress.finished`: every task finished, and so true with none. */
|
|
325
334
|
get finished() {
|
|
326
|
-
|
|
335
|
+
// [LAW:one-source-of-truth] One moment, so every task is judged at it.
|
|
336
|
+
const now = this._host.frameNow().time;
|
|
337
|
+
return this._tasks.get().every((task) => finished(taskAt(task.get(), now)));
|
|
327
338
|
}
|
|
328
339
|
static getDefaultColumns() {
|
|
329
340
|
return [
|
|
@@ -342,7 +353,7 @@ export class Progress {
|
|
|
342
353
|
completed: 0,
|
|
343
354
|
fill: Animation.constant(0),
|
|
344
355
|
visible: options?.visible !== false,
|
|
345
|
-
startTime: options?.start === false ? undefined : this._host.
|
|
356
|
+
startTime: options?.start === false ? undefined : this._host.frameNow().time,
|
|
346
357
|
finishedAt: undefined,
|
|
347
358
|
samples: [],
|
|
348
359
|
}));
|
|
@@ -364,7 +375,7 @@ export class Progress {
|
|
|
364
375
|
const completed = options.completed === undefined
|
|
365
376
|
? finiteCount("completed + advance", task.completed + advance)
|
|
366
377
|
: finiteCount("completed", options.completed);
|
|
367
|
-
const now = this._host.
|
|
378
|
+
const now = this._host.frameNow().time;
|
|
368
379
|
const reached = task.startTime !== undefined && task.total !== undefined && completed >= task.total;
|
|
369
380
|
held.set({
|
|
370
381
|
...task,
|
|
@@ -385,7 +396,7 @@ export class Progress {
|
|
|
385
396
|
const held = this._task(taskId);
|
|
386
397
|
// Rich's `start_task`: a task already running keeps the time it started.
|
|
387
398
|
if (held)
|
|
388
|
-
held.set({ ...held.get(), startTime: held.get().startTime ?? this._host.
|
|
399
|
+
held.set({ ...held.get(), startTime: held.get().startTime ?? this._host.frameNow().time });
|
|
389
400
|
}
|
|
390
401
|
start() {
|
|
391
402
|
this._ownLive("start").start();
|
|
@@ -410,23 +421,24 @@ export class Progress {
|
|
|
410
421
|
return this._live;
|
|
411
422
|
}
|
|
412
423
|
*render(options) {
|
|
413
|
-
|
|
414
|
-
yield* render(this._table(framed.frame.time), framed);
|
|
424
|
+
yield* render(this._table(this._ownFrame(options).time), options);
|
|
415
425
|
}
|
|
416
|
-
//
|
|
417
|
-
//
|
|
418
|
-
// for
|
|
419
|
-
//
|
|
420
|
-
//
|
|
421
|
-
//
|
|
422
|
-
//
|
|
423
|
-
|
|
424
|
-
_framed(options) {
|
|
426
|
+
// The frame this display is drawn in, which is only ever its host's: the
|
|
427
|
+
// tasks were stamped on that host's time, and a frame of any other host is
|
|
428
|
+
// drawn for a moment on a different clock. A render reads no clock, so a
|
|
429
|
+
// print names its frame (`frameNow`, `PrintOptions.frame`): drawn for no
|
|
430
|
+
// moment — 0, as everything else is — every task would read as not yet
|
|
431
|
+
// started, so that print is refused with the call that draws it right.
|
|
432
|
+
// [LAW:parse-dont-validate] [LAW:no-silent-failure]
|
|
433
|
+
_ownFrame(options) {
|
|
425
434
|
const { frame } = options;
|
|
426
|
-
if (frame
|
|
435
|
+
if (frame === undefined) {
|
|
436
|
+
throw new Error("a Progress is drawn for a moment on its host's clock, and this print named none; print it in its frame: console.print(progress, { frame: progress.frameNow() })");
|
|
437
|
+
}
|
|
438
|
+
if (frame.host !== this._host) {
|
|
427
439
|
throw new Error("a Progress was drawn in a frame of a host other than its own; give it that host as `drawnBy`");
|
|
428
440
|
}
|
|
429
|
-
return
|
|
441
|
+
return frame;
|
|
430
442
|
}
|
|
431
443
|
// Rich's `make_tasks_table`: each column laid out as it says, at `now` on
|
|
432
444
|
// this display's clock.
|
|
@@ -44,9 +44,9 @@ export declare class ProgressBar implements Renderable, Measurable {
|
|
|
44
44
|
set finished(value: boolean | undefined);
|
|
45
45
|
render(options: RenderOptions): Iterable<Segment>;
|
|
46
46
|
/**
|
|
47
|
-
* The shimmer over this bar's back colour as `Effected` sees it drawn
|
|
48
|
-
*
|
|
49
|
-
*
|
|
47
|
+
* The shimmer over this bar's back colour as `Effected` sees it drawn,
|
|
48
|
+
* toward `bar.pulse`. A bar has no words to keep legible, so its back takes
|
|
49
|
+
* the whole of the light.
|
|
50
50
|
*/
|
|
51
51
|
private pulseEffect;
|
|
52
52
|
/** Rich 9d8f9a3 `__rich_console__`: the fill is counted in half cells, and a total of zero is a bar already full. */
|
|
@@ -71,30 +71,33 @@ export class ProgressBar {
|
|
|
71
71
|
}
|
|
72
72
|
const depth = options.colorSystem ?? ColorDepth.TRUECOLOR;
|
|
73
73
|
// Rich's pulse resolves its colours on the terminal a depth assumes, as
|
|
74
|
-
// `get_truecolor` does with no theme; so does this.
|
|
75
|
-
const
|
|
74
|
+
// `get_truecolor` does with no theme; so does this with none named.
|
|
75
|
+
const terminal = resolveTerminal(options.terminal, depth);
|
|
76
76
|
// Rich writes the pulse's back as a colour of its own, black where the
|
|
77
77
|
// back style names none, so the light always has the bar's colour to fall
|
|
78
78
|
// on: one the terminal supplies takes no light.
|
|
79
79
|
const style = getStyle(options, this.style);
|
|
80
|
-
const ink = style.color?.isDefault === false ? style.color : ColorSpec.fromRgba((style.color ?? PULSE_BACK).getTruecolor(
|
|
80
|
+
const ink = style.color?.isDefault === false ? style.color : ColorSpec.fromRgba((style.color ?? PULSE_BACK).getTruecolor(terminal, true));
|
|
81
81
|
const back = style.add(Style.fromColor(ink));
|
|
82
82
|
// [LAW:no-ambient-temporal-coupling] The moment is the frame's; the bar
|
|
83
83
|
// only says what it looks like then. An empty track, lit by the shimmer.
|
|
84
84
|
const track = { render: (o) => this.track(o, width, 0, back) };
|
|
85
|
-
yield* render(new Effected(track, this.pulseEffect(options, back
|
|
85
|
+
yield* render(new Effected(track, this.pulseEffect(options, back), { key: "progress-bar" }), options);
|
|
86
86
|
}
|
|
87
87
|
/**
|
|
88
|
-
* The shimmer over this bar's back colour as `Effected` sees it drawn
|
|
89
|
-
*
|
|
90
|
-
*
|
|
88
|
+
* The shimmer over this bar's back colour as `Effected` sees it drawn,
|
|
89
|
+
* toward `bar.pulse`. A bar has no words to keep legible, so its back takes
|
|
90
|
+
* the whole of the light.
|
|
91
91
|
*/
|
|
92
|
-
pulseEffect(options, back
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
92
|
+
pulseEffect(options, back) {
|
|
93
|
+
return (drawn) => {
|
|
94
|
+
const { depth, terminal } = drawn;
|
|
95
|
+
const ink = back.drawnColors(depth).color ?? ColorSpec.default();
|
|
96
|
+
const glow = getStyle(options, "bar.pulse").drawnColors(depth).color ?? ColorSpec.default();
|
|
97
|
+
const loop = shimmer(PULSE_CURVE, PULSE_REACH, glow.getTruecolor(terminal, true), 0);
|
|
98
|
+
const whole = new Map([[ink.getTruecolor(terminal, true).hex, 1]]);
|
|
99
|
+
return atShares(loop, () => whole)(drawn);
|
|
100
|
+
};
|
|
98
101
|
}
|
|
99
102
|
/** Rich 9d8f9a3 `__rich_console__`: the fill is counted in half cells, and a total of zero is a bar already full. */
|
|
100
103
|
completeHalves(width) {
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
* other renderable here is restyled, and a second styling vocabulary on this
|
|
8
8
|
* one class would be a second answer to "what colour is a keyword".
|
|
9
9
|
*/
|
|
10
|
-
import {
|
|
10
|
+
import { escaped } from "../core/bidi.js";
|
|
11
|
+
import { cellLen, expandTabs, parseTabSize, unicodeEscape } from "../core/cells.js";
|
|
11
12
|
import { Segment } from "../core/segment.js";
|
|
12
13
|
import { RichText } from "../core/text.js";
|
|
13
14
|
import { drawable, groundedStyle, getStyle, withBoundedWidth, withCellWidth, } from "../core/protocol.js";
|
|
@@ -89,7 +90,11 @@ export class Syntax {
|
|
|
89
90
|
this.wordWrap = options?.wordWrap ?? false;
|
|
90
91
|
const tabSize = parseTabSize(options?.tabSize ?? 4);
|
|
91
92
|
this.tabSize = tabSize;
|
|
92
|
-
|
|
93
|
+
// Code on show: what the wire would drop is escaped, and an explicit bidi
|
|
94
|
+
// control with it. That is the Trojan Source attack: the order and the lines on
|
|
95
|
+
// screen differing from what the compiler reads. A joiner stays, since a Persian
|
|
96
|
+
// comment or an emoji string needs it. Only a CRLF's CR goes, with its line ending.
|
|
97
|
+
this._lines = expandTabs(escaped(code.replace(/\r\n/g, "\n"), unicodeEscape), tabSize).text.split("\n");
|
|
93
98
|
}
|
|
94
99
|
/**
|
|
95
100
|
* The lines shown, as a 0-based half-open slice of `_lines`, and the number
|
|
@@ -454,11 +454,12 @@ export class Table {
|
|
|
454
454
|
// that is all it styles: the reference reads it as `table_style` for the
|
|
455
455
|
// frame and nowhere else, so a cell is untouched by it.
|
|
456
456
|
const borderStyle = getStyle(options, this.style).add(getStyle(options, this.borderStyle));
|
|
457
|
-
const border = borderStyle.isNull ? undefined : borderStyle;
|
|
458
457
|
// The one division of the width every row below is measured against.
|
|
459
458
|
const outerWidth = this._outerWidth(options);
|
|
460
459
|
const geometry = this._geometry(options, outerWidth);
|
|
461
460
|
const edge = geometry.edge === 1;
|
|
461
|
+
// Only an edge closes a frame: without one, a table's rules are not a border.
|
|
462
|
+
const border = box && edge ? box.frame(borderStyle) : borderStyle.isNull ? undefined : borderStyle;
|
|
462
463
|
// Title
|
|
463
464
|
if (this._title) {
|
|
464
465
|
yield* this._renderTitle(options, this._title, geometry.totalWidth, this.titleStyle, this.titleJustify);
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* number the time is turned into first: a frame's stamp says when it changes
|
|
21
21
|
* on the host's clock, which only `Timeline.run` can carry it back onto —
|
|
22
22
|
* paused, never; backwards, at the hold it is about to drop under.
|
|
23
|
-
* [LAW:single-enforcer] `
|
|
23
|
+
* [LAW:single-enforcer] `drawn` is the one place the time, the timeline
|
|
24
24
|
* and the reader's preference for motion are read, for every function.
|
|
25
25
|
*
|
|
26
26
|
* `frames <seconds> <frame> <seconds> <frame> …` is a `FrameSequence`
|
|
@@ -57,31 +57,52 @@
|
|
|
57
57
|
* exact arity of typed slots, so a slot of the wrong kind fails at the gate.
|
|
58
58
|
*
|
|
59
59
|
* Every function says when what it drew changes, so a host paints a
|
|
60
|
-
* template while it moves and not after
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
60
|
+
* template while it moves and not after — and says it only for what the
|
|
61
|
+
* output depends on. A number or a colour has no cells to carry a hold, and
|
|
62
|
+
* a fragment's cells lose theirs the moment it is flattened (`printf "%s"`),
|
|
63
|
+
* so no function stamps cells or tells the frame itself. Each marks its
|
|
64
|
+
* return with the hold its value is in (`marked`, the engine's evaluation
|
|
65
|
+
* provenance), and the engine carries the mark beside the value into every
|
|
66
|
+
* variable, dot and function the value passes through, reporting it where
|
|
67
|
+
* the output depends on it. `emitted` is where a template's cells take a
|
|
68
|
+
* hold: every fragment the template emits, stamped with the holds of the
|
|
69
|
+
* marked values its action read. `decided` is the route for a hold no cell
|
|
70
|
+
* can carry, told to the frame (`TemplateFrame.onHold`): a mark an
|
|
71
|
+
* `if`/`with`/`range` consumed, whichever arm it took, because the frame may
|
|
72
|
+
* show cells for it later and must say when without a cell to say it on, as
|
|
73
|
+
* a placed animation of no cells does (`placed`) — and, by the same rule, a
|
|
74
|
+
* mark a writing function or a throwing action read; `EngineConfig.decided`
|
|
75
|
+
* is the authority on when it is called. A mark bound somewhere nobody reads
|
|
76
|
+
* is reported nowhere, so a value a template computes and never draws or
|
|
77
|
+
* decides on tells the frame nothing (rich-animation-27tq.0gd). Early, never
|
|
78
|
+
* late: an emission may carry a hold it did not strictly need, and a hold
|
|
79
|
+
* the output depends on is never dropped. [LAW:single-enforcer]
|
|
80
|
+
*
|
|
81
|
+
* The functions and the two hooks go into the host's engine config together,
|
|
82
|
+
* by `withAnimation`: the functions wired without the hooks would compile,
|
|
83
|
+
* draw and never say they move. [LAW:no-silent-failure]
|
|
66
84
|
*/
|
|
67
|
-
import type
|
|
85
|
+
import { type EngineConfig } from "@promptctl/go-template-js";
|
|
68
86
|
import type { RenderOptions } from "../core/protocol.js";
|
|
87
|
+
import type { RichText } from "../core/text.js";
|
|
69
88
|
import { Timeline } from "../core/timeline.js";
|
|
70
|
-
/** What
|
|
71
|
-
export interface
|
|
89
|
+
/** What the animation functions are drawn on, beside the frame each evaluation is handed. */
|
|
90
|
+
export interface AnimationOptions {
|
|
72
91
|
/** The timeline to draw on, read once per call; the frame's own time when omitted. */
|
|
73
92
|
readonly timeline?: () => Timeline;
|
|
74
93
|
}
|
|
75
94
|
/**
|
|
76
95
|
* The frame a template is evaluated for, in the fields a render's options
|
|
77
|
-
* carry under the same names: `time` in seconds, `onHold`, told
|
|
78
|
-
*
|
|
96
|
+
* carry under the same names: `time` in seconds, `onHold`, told the hold of
|
|
97
|
+
* an animated value the output may depend on with no cell to carry it — one
|
|
98
|
+
* a decision read, whichever arm it took, a writing function's input, a
|
|
99
|
+
* throwing action's (the engine's `decided`) — and the reader's preferences,
|
|
79
100
|
* `reducedMotion`, and `asciiOnly`, which the glyphs an effect picks for
|
|
80
101
|
* itself go through. They arrive with every frame and nowhere else, so a
|
|
81
102
|
* template drawn in an `App` is drawn as the app's preferences say.
|
|
82
103
|
* [LAW:one-source-of-truth]
|
|
83
104
|
*
|
|
84
|
-
* `time` is on the clock `
|
|
105
|
+
* `time` is on the clock `AnimationOptions.timeline` maps from, and
|
|
85
106
|
* `onHold` hears on that clock. A host outside rich-js hands its own clock's
|
|
86
107
|
* time. Inside a rich-js frame the time is the frame's, which its host's
|
|
87
108
|
* timeline has already mapped, so a template drawn there registers no
|
|
@@ -93,14 +114,24 @@ export interface TemplateFrame extends Pick<RenderOptions, "onHold" | "reducedMo
|
|
|
93
114
|
/** The frame a renderable is drawn in, as the frame a template it evaluates there is drawn for. */
|
|
94
115
|
export declare function templateFrame(options: RenderOptions): TemplateFrame;
|
|
95
116
|
/**
|
|
96
|
-
*
|
|
97
|
-
* the frame `frame` reports when
|
|
98
|
-
* seconds, from whatever zero the
|
|
99
|
-
* `options.timeline`, and each
|
|
117
|
+
* `config` with `frames`, `stepped`, `tween`, `loop` and `glyphs` registered
|
|
118
|
+
* beside its own functions, each drawn for the frame `frame` reports when
|
|
119
|
+
* the template is evaluated — its time in seconds, from whatever zero the
|
|
120
|
+
* host counts from — through `options.timeline`, and each marking its
|
|
121
|
+
* return with the hold it is in there; and with the two hooks that carry
|
|
122
|
+
* those holds to the cells (`emitted`) and the frame (`decided`) installed
|
|
123
|
+
* over any `config` already has, which still hear everything they did. One
|
|
124
|
+
* call, so the functions and the hooks that report for them cannot be wired
|
|
125
|
+
* apart: the functions alone would compile, draw, and never say they move.
|
|
126
|
+
* [LAW:types-are-the-program] [LAW:no-silent-failure] [LAW:composability]
|
|
127
|
+
* A `config` that already has one of the five names is refused, which is
|
|
128
|
+
* also what a second `withAnimation` over its own result meets: its template
|
|
129
|
+
* calls would otherwise reach these with no word said.
|
|
130
|
+
*
|
|
100
131
|
* The functions exist whatever `frame` returns, so a template compiles once
|
|
101
132
|
* and is evaluated at every moment the host draws. In a frame that says
|
|
102
133
|
* `reducedMotion` each draws its animation reduced (`Animation.reduced`): a
|
|
103
134
|
* loop at its start, a one-shot cut from where it starts to where it arrives
|
|
104
135
|
* when it starts.
|
|
105
136
|
*/
|
|
106
|
-
export declare function
|
|
137
|
+
export declare function withAnimation(config: EngineConfig<RichText>, frame: () => TemplateFrame, options?: AnimationOptions): EngineConfig<RichText>;
|