@promptctl/rich-js 0.24.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.
Files changed (95) hide show
  1. package/THIRD-PARTY-NOTICES +29 -1
  2. package/dist/core/animation.d.ts +78 -0
  3. package/dist/core/animation.js +107 -0
  4. package/dist/core/cell-widths.d.ts +9 -0
  5. package/dist/core/cell-widths.js +140 -0
  6. package/dist/core/cells.d.ts +17 -11
  7. package/dist/core/cells.js +100 -25
  8. package/dist/core/console.js +5 -5
  9. package/dist/core/easing.d.ts +110 -10
  10. package/dist/core/easing.js +269 -36
  11. package/dist/core/json.js +2 -1
  12. package/dist/core/measure.js +2 -2
  13. package/dist/core/place.js +2 -1
  14. package/dist/core/pretty.js +2 -2
  15. package/dist/core/protocol.d.ts +73 -19
  16. package/dist/core/protocol.js +56 -15
  17. package/dist/core/render.js +2 -1
  18. package/dist/core/segment.d.ts +18 -1
  19. package/dist/core/segment.js +45 -44
  20. package/dist/core/strip.d.ts +3 -2
  21. package/dist/core/strip.js +11 -7
  22. package/dist/core/style.js +17 -6
  23. package/dist/core/text.js +22 -14
  24. package/dist/core/timeline.d.ts +84 -0
  25. package/dist/core/timeline.js +144 -0
  26. package/dist/core/tween.d.ts +49 -0
  27. package/dist/core/tween.js +69 -0
  28. package/dist/host/app.js +2 -2
  29. package/dist/index.d.ts +10 -7
  30. package/dist/index.js +13 -4
  31. package/dist/renderables/align.d.ts +3 -2
  32. package/dist/renderables/align.js +3 -0
  33. package/dist/renderables/columns.d.ts +3 -2
  34. package/dist/renderables/columns.js +7 -2
  35. package/dist/renderables/constrain.d.ts +3 -2
  36. package/dist/renderables/constrain.js +5 -1
  37. package/dist/renderables/effect.d.ts +43 -58
  38. package/dist/renderables/effect.js +58 -64
  39. package/dist/renderables/effects.d.ts +16 -14
  40. package/dist/renderables/effects.js +64 -45
  41. package/dist/renderables/embed.js +3 -2
  42. package/dist/renderables/flexStrip.d.ts +3 -2
  43. package/dist/renderables/flexStrip.js +6 -1
  44. package/dist/renderables/frames.d.ts +40 -19
  45. package/dist/renderables/frames.js +48 -21
  46. package/dist/renderables/group.d.ts +3 -2
  47. package/dist/renderables/group.js +5 -2
  48. package/dist/renderables/html-entities.d.ts +8 -0
  49. package/dist/renderables/html-entities.js +386 -0
  50. package/dist/renderables/layout.d.ts +3 -2
  51. package/dist/renderables/layout.js +15 -2
  52. package/dist/renderables/list-view.d.ts +3 -2
  53. package/dist/renderables/list-view.js +12 -5
  54. package/dist/renderables/live.js +2 -2
  55. package/dist/renderables/markdown-parse.d.ts +109 -0
  56. package/dist/renderables/markdown-parse.js +1421 -0
  57. package/dist/renderables/markdown-url.d.ts +19 -0
  58. package/dist/renderables/markdown-url.js +314 -0
  59. package/dist/renderables/markdown.d.ts +5 -7
  60. package/dist/renderables/markdown.js +356 -683
  61. package/dist/renderables/padding.d.ts +8 -20
  62. package/dist/renderables/padding.js +32 -50
  63. package/dist/renderables/panel.d.ts +26 -26
  64. package/dist/renderables/panel.js +67 -103
  65. package/dist/renderables/progress.d.ts +4 -2
  66. package/dist/renderables/progress.js +11 -2
  67. package/dist/renderables/progressBar.js +2 -2
  68. package/dist/renderables/python-space.d.ts +13 -0
  69. package/dist/renderables/python-space.js +24 -0
  70. package/dist/renderables/spinner.d.ts +26 -14
  71. package/dist/renderables/spinner.js +49 -37
  72. package/dist/renderables/syntax.js +2 -1
  73. package/dist/renderables/table.d.ts +19 -11
  74. package/dist/renderables/table.js +140 -156
  75. package/dist/renderables/traceback.d.ts +1 -1
  76. package/dist/renderables/traceback.js +6 -5
  77. package/dist/renderables/tree.d.ts +6 -5
  78. package/dist/renderables/tree.js +11 -7
  79. package/dist/renderables/viewport.d.ts +13 -5
  80. package/dist/renderables/viewport.js +41 -20
  81. package/dist/template-bindings/animation-funcs.js +2 -2
  82. package/dist/template-bindings/index.js +2 -1
  83. package/dist/themes/ramp.d.ts +18 -3
  84. package/dist/themes/ramp.js +23 -2
  85. package/dist/widgets/focus-manager.d.ts +21 -14
  86. package/dist/widgets/focus-manager.js +28 -29
  87. package/dist/widgets/index.d.ts +1 -1
  88. package/dist/widgets/static-item.d.ts +4 -3
  89. package/dist/widgets/static-item.js +9 -7
  90. package/dist/widgets/text-input.d.ts +28 -18
  91. package/dist/widgets/text-input.js +144 -101
  92. package/dist/widgets/widget-app.d.ts +19 -3
  93. package/dist/widgets/widget-app.js +39 -21
  94. package/dist/widgets/widget-base.js +0 -3
  95. package/package.json +2 -5
@@ -31,20 +31,22 @@
31
31
  * agree at every `t`, a `Progress` on a hand-moved clock turns its spinners
32
32
  * on that clock, and a draw costs the same at `t = 0` and `t = 10⁶`.
33
33
  *
34
- * `speed` scales the holds, not the time: at speed 2 each frame is held half
35
- * the interval, and a negative speed is the frames in reverse order, each held
36
- * the interval over the speed's size. [LAW:one-source-of-truth] Rich scales
37
- * the time instead, `t × speed` into the beat. At a positive speed the frame
38
- * drawn is the same; but when the frame next changes (`Style.nextChange`) is
39
- * a time on the host's timeline, and a beat over scaled time answers on the
40
- * scaled one — so the sequence is scaled where it is built, and the
41
- * `FrameSequence` stamps host time with nothing to map back. Backwards, this is the plain
42
- * reversed sequence from `t = 0`, where Rich's `int()` truncation holds
43
- * frame 0 for a first interval and then counts down: a departure, made so a
44
- * negative speed is one more sequence on the beat and not a second rule
45
- * about time. A speed of zero would hold a frame forever, which is not a
46
- * beat, and is refused where it is given.
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.
47
48
  */
49
+ import type { Animation } from "../core/animation.js";
48
50
  import { Style } from "../core/style.js";
49
51
  import { RichText } from "../core/text.js";
50
52
  import type { Renderable, Measurable } from "../core/protocol.js";
@@ -53,7 +55,7 @@ export interface SpinnerOptions {
53
55
  speed?: number;
54
56
  style?: string | Style;
55
57
  }
56
- export declare class Spinner {
58
+ export declare class Spinner implements Animation<Renderable & Measurable> {
57
59
  readonly name: string;
58
60
  readonly speed: number;
59
61
  readonly style: string | Style;
@@ -79,6 +81,16 @@ export declare class Spinner {
79
81
  * The frames this output can draw are chosen where the output is known.
80
82
  */
81
83
  at(t: number): Renderable & Measurable;
84
+ /**
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.
90
+ */
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;
82
94
  private _render;
83
95
  /**
84
96
  * The frame in progress and the label as one text, as Rich's
@@ -31,33 +31,32 @@
31
31
  * agree at every `t`, a `Progress` on a hand-moved clock turns its spinners
32
32
  * on that clock, and a draw costs the same at `t = 0` and `t = 10⁶`.
33
33
  *
34
- * `speed` scales the holds, not the time: at speed 2 each frame is held half
35
- * the interval, and a negative speed is the frames in reverse order, each held
36
- * the interval over the speed's size. [LAW:one-source-of-truth] Rich scales
37
- * the time instead, `t × speed` into the beat. At a positive speed the frame
38
- * drawn is the same; but when the frame next changes (`Style.nextChange`) is
39
- * a time on the host's timeline, and a beat over scaled time answers on the
40
- * scaled one — so the sequence is scaled where it is built, and the
41
- * `FrameSequence` stamps host time with nothing to map back. Backwards, this is the plain
42
- * reversed sequence from `t = 0`, where Rich's `int()` truncation holds
43
- * frame 0 for a first interval and then counts down: a departure, made so a
44
- * negative speed is one more sequence on the beat and not a second rule
45
- * about time. A speed of zero would hold a frame forever, which is not a
46
- * beat, and is refused where it is given.
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.
47
48
  */
48
49
  import { Segment } from "../core/segment.js";
49
50
  import { NULL_STYLE } from "../core/style.js";
50
51
  import { RichText } from "../core/text.js";
51
52
  import { SPINNERS, DEFAULT_SPINNER, LINE_SPINNER } from "../core/spinnerData.js";
52
- import { drawable } from "../core/protocol.js";
53
+ import { Timeline } from "../core/timeline.js";
54
+ import { drawable, render } from "../core/protocol.js";
53
55
  import { EmbeddedText } from "./embed.js";
54
- import { FrameSequence } from "./frames.js";
55
- const sequence = (data, style, speed) => {
56
- const frames = data.frames.map((frame) => ({
57
- text: new RichText("", { end: "" }).append(frame, style),
58
- seconds: data.interval / 1000 / Math.abs(speed),
59
- }));
60
- return { frames: new FrameSequence(speed < 0 ? frames.reverse() : frames), glyphs: data.frames.join("") };
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("") };
61
60
  };
62
61
  const sequenceGlyphs = ({ glyphs }) => glyphs;
63
62
  export class Spinner {
@@ -84,18 +83,16 @@ export class Spinner {
84
83
  throw new Error(`Unknown spinner: "${spinnerName}"`);
85
84
  }
86
85
  const speed = options?.speed ?? 1;
87
- // [LAW:parse-dont-validate] A hold is a positive number of seconds, so the
88
- // speed it is divided by is finite and not zero, settled here.
89
- if (!Number.isFinite(speed) || speed === 0) {
90
- throw new RangeError(`Spinner speed must be finite and not zero, got ${speed}`);
91
- }
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);
92
89
  this.name = spinnerName;
93
90
  this.text = text;
94
91
  this.speed = speed;
95
92
  this.style = options?.style ?? NULL_STYLE;
96
93
  this._data = data;
97
- this._named = sequence(data, this.style, speed);
98
- this._ascii = sequence(LINE_SPINNER, this.style, speed);
94
+ this._named = sequence(data, this.style, timeline);
95
+ this._ascii = sequence(LINE_SPINNER, this.style, timeline);
99
96
  }
100
97
  get frames() {
101
98
  return this._data.frames;
@@ -114,22 +111,36 @@ export class Spinner {
114
111
  if (!Number.isFinite(t)) {
115
112
  throw new RangeError(`Spinner.at needs a finite t, got ${t}`);
116
113
  }
117
- const frames = (options) => drawable(options, this._named, this._ascii, sequenceGlyphs).frames;
114
+ const drawn = (options) => drawable(options, this._named, this._ascii, sequenceGlyphs);
118
115
  return {
119
- render: (options) => this._render(frames(options), t, options),
116
+ render: (options) => this._render(drawn(options), t, options),
120
117
  // Measured at the frames' one width, the widest frame's, so a column
121
118
  // holding it never narrows as it turns, and never offered less than
122
119
  // that frame: a frame is one picture, which the reference's `Text`
123
120
  // measure would let wrap apart at its spaces.
124
121
  measure: (options) => {
125
- const drawn = frames(options);
126
- const { minimum, maximum } = this._line(drawn, t, options).measure(options);
127
- return { minimum: Math.max(minimum, Math.min(drawn.width, maximum)), maximum };
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 };
128
125
  },
129
126
  };
130
127
  }
131
- *_render(frames, t, options) {
132
- yield* this._line(frames, t, options).render(options);
128
+ /**
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.
134
+ */
135
+ nextChange(t) {
136
+ return Math.min(this._named.played.nextChange(t), this._ascii.played.nextChange(t));
137
+ }
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);
133
144
  yield Segment.line();
134
145
  }
135
146
  /**
@@ -139,8 +150,9 @@ export class Spinner {
139
150
  * styles nothing — is no label, not a trailing space, as an empty `Text` is
140
151
  * falsy there.
141
152
  */
142
- _line(frames, t, options) {
143
- const line = new RichText("", { end: "" }).append(frames.text(t));
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));
144
156
  // Unhighlighted: Rich's label is a `Text` from the moment it is handed over, and a `Text` is never highlighted.
145
157
  const label = new EmbeddedText(this.text).text({ ...options, highlight: false });
146
158
  if (label.plain !== "")
@@ -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].render(lineOptions), Segment.line()]);
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 and the floor are laid
187
- * over whichever sizing the column has: they are the same for all three.
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, and the narrowest the column can be
215
- * without cutting one — the reference's `_measure_column` — or `undefined`
216
- * when the column has no cell to measure. Zero is a column whose cells draw
217
- * nothing — a gutter asks for its padding and nothing else — and is not the
218
- * same answer. [LAW:types-are-the-program]
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 is a ceiling of zero, as `width: NaN` is. A bare `Math.max` returns
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;