@promptctl/rich-js 0.17.0 → 0.18.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/README.md +13 -26
- package/dist/core/anchor.d.ts +45 -0
- package/dist/core/anchor.js +39 -0
- package/dist/core/ansi.d.ts +65 -0
- package/dist/core/ansi.js +231 -0
- package/dist/core/box.d.ts +0 -1
- package/dist/core/box.js +6 -18
- package/dist/core/cells.d.ts +16 -5
- package/dist/core/cells.js +31 -10
- package/dist/core/color.d.ts +4 -8
- package/dist/core/color.js +28 -19
- package/dist/core/console.d.ts +13 -4
- package/dist/core/console.js +91 -36
- package/dist/core/export-html.d.ts +40 -5
- package/dist/core/export-html.js +111 -17
- package/dist/core/markup.d.ts +27 -5
- package/dist/core/markup.js +282 -170
- package/dist/core/measure.d.ts +1 -1
- package/dist/core/measure.js +2 -1
- package/dist/core/place.d.ts +30 -0
- package/dist/core/place.js +51 -0
- package/dist/core/pretty.d.ts +3 -0
- package/dist/core/pretty.js +5 -1
- package/dist/core/protocol.d.ts +136 -6
- package/dist/core/protocol.js +64 -2
- package/dist/core/render.d.ts +2 -2
- package/dist/core/render.js +2 -2
- package/dist/core/segment.d.ts +23 -4
- package/dist/core/segment.js +75 -16
- package/dist/core/spinnerData.d.ts +2 -0
- package/dist/core/spinnerData.js +3 -1
- package/dist/core/strip.d.ts +3 -7
- package/dist/core/strip.js +32 -35
- package/dist/core/style.d.ts +25 -0
- package/dist/core/style.js +61 -89
- package/dist/core/text.d.ts +16 -15
- package/dist/core/text.js +62 -76
- package/dist/host/app.d.ts +121 -0
- package/dist/host/app.js +255 -0
- package/dist/host/host-environment.d.ts +26 -0
- package/dist/host/host-environment.js +44 -0
- package/dist/host/index.d.ts +4 -2
- package/dist/host/index.js +2 -1
- package/dist/host/terminal-host.d.ts +43 -7
- package/dist/host/terminal-host.js +57 -3
- package/dist/index.d.ts +7 -3
- package/dist/index.js +4 -1
- package/dist/node/terminal-host.d.ts +31 -2
- package/dist/node/terminal-host.js +69 -2
- package/dist/node/traceback.d.ts +16 -6
- package/dist/node/traceback.js +30 -8
- package/dist/renderables/align.d.ts +2 -2
- package/dist/renderables/align.js +6 -19
- package/dist/renderables/columns.js +4 -20
- package/dist/renderables/embed.d.ts +50 -0
- package/dist/renderables/embed.js +71 -0
- package/dist/renderables/group.js +3 -1
- package/dist/renderables/layout.js +31 -34
- package/dist/renderables/live.d.ts +6 -3
- package/dist/renderables/live.js +89 -45
- package/dist/renderables/markdown.d.ts +1 -1
- package/dist/renderables/markdown.js +6 -4
- package/dist/renderables/padding.js +3 -2
- package/dist/renderables/panel.js +26 -41
- package/dist/renderables/progress.js +5 -8
- package/dist/renderables/progressBar.js +6 -5
- package/dist/renderables/rule.d.ts +3 -2
- package/dist/renderables/rule.js +9 -9
- package/dist/renderables/spinner.d.ts +5 -3
- package/dist/renderables/spinner.js +14 -8
- package/dist/renderables/syntax.d.ts +1 -1
- package/dist/renderables/syntax.js +2 -1
- package/dist/renderables/table.d.ts +26 -14
- package/dist/renderables/table.js +239 -141
- package/dist/renderables/traceback.js +8 -9
- package/dist/renderables/tree.d.ts +17 -3
- package/dist/renderables/tree.js +62 -71
- package/dist/renderables/viewport.d.ts +114 -0
- package/dist/renderables/viewport.js +198 -0
- package/dist/template-bindings/color-funcs.js +11 -13
- package/dist/template-bindings/index.js +4 -2
- package/dist/template-bindings/palette-funcs.js +6 -16
- package/dist/template-bindings/style-funcs.js +4 -0
- package/dist/themes/data/ansi-tables.d.ts +14 -0
- package/dist/themes/data/ansi-tables.js +49 -0
- package/dist/themes/data/atom-one-dark.js +19 -0
- package/dist/themes/data/atom-one-light.js +19 -0
- package/dist/themes/data/catppuccin-frappe.js +19 -0
- package/dist/themes/data/catppuccin-latte.js +19 -0
- package/dist/themes/data/catppuccin-macchiato.js +19 -0
- package/dist/themes/data/catppuccin-mocha.js +19 -0
- package/dist/themes/data/cyberpunk.js +2 -0
- package/dist/themes/data/default.js +2 -0
- package/dist/themes/data/dracula.js +19 -0
- package/dist/themes/data/flexoki.js +19 -0
- package/dist/themes/data/gruvbox.js +19 -0
- package/dist/themes/data/monokai.js +19 -0
- package/dist/themes/data/nord.js +19 -0
- package/dist/themes/data/rose-pine-dawn.js +19 -0
- package/dist/themes/data/rose-pine-moon.js +19 -0
- package/dist/themes/data/rose-pine.js +19 -0
- package/dist/themes/data/solarized-dark.js +19 -0
- package/dist/themes/data/solarized-light.js +19 -0
- package/dist/themes/data/svg-export.js +19 -0
- package/dist/themes/data/textual-ansi.js +2 -0
- package/dist/themes/data/textual-dark.js +2 -0
- package/dist/themes/data/textual-light.js +2 -0
- package/dist/themes/data/tokyo-night.js +19 -0
- package/dist/themes/data/types.d.ts +16 -0
- package/dist/themes/data/types.js +10 -1
- package/dist/themes/registry.d.ts +3 -2
- package/dist/themes/registry.js +13 -1
- package/dist/themes/terminalThemes.d.ts +2 -7
- package/dist/themes/terminalThemes.js +4 -9
- package/dist/widgets/button.d.ts +1 -1
- package/dist/widgets/button.js +4 -2
- package/dist/widgets/checkbox.d.ts +2 -2
- package/dist/widgets/checkbox.js +5 -3
- package/dist/widgets/dropdown.d.ts +2 -2
- package/dist/widgets/dropdown.js +13 -16
- package/dist/widgets/event-router.d.ts +21 -28
- package/dist/widgets/event-router.js +80 -73
- package/dist/widgets/focus-manager.d.ts +25 -6
- package/dist/widgets/focus-manager.js +63 -65
- package/dist/widgets/hit.d.ts +64 -0
- package/dist/widgets/hit.js +113 -0
- package/dist/widgets/index.d.ts +5 -7
- package/dist/widgets/index.js +3 -4
- package/dist/widgets/slider.d.ts +2 -2
- package/dist/widgets/slider.js +7 -7
- package/dist/widgets/static-item.d.ts +9 -15
- package/dist/widgets/static-item.js +9 -15
- package/dist/widgets/text-input.d.ts +2 -2
- package/dist/widgets/text-input.js +17 -14
- package/dist/widgets/toggle.d.ts +1 -1
- package/dist/widgets/toggle.js +3 -2
- package/dist/widgets/types.d.ts +14 -35
- package/dist/widgets/types.js +0 -1
- package/dist/widgets/widget-app.d.ts +63 -0
- package/dist/widgets/widget-app.js +199 -0
- package/dist/widgets/widget-base.d.ts +4 -6
- package/dist/widgets/widget-base.js +22 -30
- package/package.json +12 -4
- package/dist/host/host-stream.d.ts +0 -30
- package/dist/host/host-stream.js +0 -35
- package/dist/widgets/screen.d.ts +0 -98
- package/dist/widgets/screen.js +0 -530
|
@@ -7,8 +7,9 @@ import { NULL_STYLE } from "../core/style.js";
|
|
|
7
7
|
import { ROUNDED } from "../core/box.js";
|
|
8
8
|
import { Measurement } from "../core/measure.js";
|
|
9
9
|
import { RichText } from "../core/text.js";
|
|
10
|
+
import { embed, inlineLabel } from "./embed.js";
|
|
10
11
|
import { normalizePadding } from "./padding.js";
|
|
11
|
-
import { getStyle, isMeasurable, withBoundedWidth, withCellWidth } from "../core/protocol.js";
|
|
12
|
+
import { fitHeight, getStyle, insetHeight, isMeasurable, withBoundedWidth, withCellWidth } from "../core/protocol.js";
|
|
12
13
|
function layoutPanel(outerWidth, padding) {
|
|
13
14
|
const [, padRightWanted, , padLeftWanted] = padding;
|
|
14
15
|
// Panel's one division point, and the width reaching it is not always one
|
|
@@ -54,22 +55,6 @@ function frameOverhead(geometry) {
|
|
|
54
55
|
function borderTextStyle(options, own, border) {
|
|
55
56
|
return own === undefined ? border : getStyle(options, own);
|
|
56
57
|
}
|
|
57
|
-
function toRenderable(content) {
|
|
58
|
-
// [LAW:one-type-per-behavior] Content embedded in a panel is a line, not a
|
|
59
|
-
// printed unit — the same reason columns, table cells, tree labels, and
|
|
60
|
-
// every other embedding site build their RichText with `end: ""`. Now that
|
|
61
|
-
// `RichText.render` honors `end` uniformly (rich-text-5ai), leaving this at
|
|
62
|
-
// the default "\n" would draw a trailing blank row whenever content ends
|
|
63
|
-
// with a literal newline.
|
|
64
|
-
if (typeof content === "string")
|
|
65
|
-
return new RichText(content, { end: "" });
|
|
66
|
-
if (content instanceof RichText) {
|
|
67
|
-
const copy = content.copy();
|
|
68
|
-
copy.end = "";
|
|
69
|
-
return copy;
|
|
70
|
-
}
|
|
71
|
-
return content;
|
|
72
|
-
}
|
|
73
58
|
export class Panel {
|
|
74
59
|
renderable;
|
|
75
60
|
box;
|
|
@@ -84,7 +69,7 @@ export class Panel {
|
|
|
84
69
|
width;
|
|
85
70
|
padding;
|
|
86
71
|
constructor(content, options) {
|
|
87
|
-
this.renderable =
|
|
72
|
+
this.renderable = embed(content);
|
|
88
73
|
this.box = options?.box ?? ROUNDED;
|
|
89
74
|
this.title = options?.title;
|
|
90
75
|
this.subtitle = options?.subtitle;
|
|
@@ -99,7 +84,7 @@ export class Panel {
|
|
|
99
84
|
}
|
|
100
85
|
*render(rawOptions) {
|
|
101
86
|
const options = withBoundedWidth(rawOptions, this);
|
|
102
|
-
const box =
|
|
87
|
+
const box = this.box.substitute(options);
|
|
103
88
|
const borderStyle = getStyle(options, this.borderStyle);
|
|
104
89
|
const style = getStyle(options, this.style);
|
|
105
90
|
const border = borderStyle.isNull ? undefined : borderStyle;
|
|
@@ -129,11 +114,13 @@ export class Panel {
|
|
|
129
114
|
* fires at every width and reads state this render populates.
|
|
130
115
|
*/
|
|
131
116
|
_renderContent(options, contentWidth) {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
const
|
|
117
|
+
// Two border rows and the vertical padding are the panel's own. Handed on
|
|
118
|
+
// as a region, the rest is the panel's to shape, which is what stretches
|
|
119
|
+
// its frame down a pane and keeps its bottom border inside one.
|
|
120
|
+
const [padTop, , padBottom] = this.padding;
|
|
121
|
+
const height = insetHeight(options.height, 2 + padTop + padBottom);
|
|
122
|
+
const innerOptions = { ...options, maxWidth: contentWidth, height };
|
|
123
|
+
const lines = fitHeight(Segment.splitLines([...this.renderable.render(innerOptions)]), height);
|
|
137
124
|
return contentWidth === 0 ? [] : lines;
|
|
138
125
|
}
|
|
139
126
|
/**
|
|
@@ -225,23 +212,22 @@ export class Panel {
|
|
|
225
212
|
}
|
|
226
213
|
*_renderTopBorder(options, box, geometry, border) {
|
|
227
214
|
const innerBorderWidth = geometry.spanWidth;
|
|
228
|
-
|
|
215
|
+
const titleSeg = borderTextStyle(options, this.titleStyle, border);
|
|
216
|
+
const title = inlineLabel(this.title, options, titleSeg);
|
|
217
|
+
const titleWidth = Segment.getLineLength(title);
|
|
218
|
+
if (titleWidth === 0) {
|
|
229
219
|
yield new Segment(box.top.left.repeat(geometry.left), border);
|
|
230
220
|
yield new Segment(box.top.horizontal.repeat(innerBorderWidth), border);
|
|
231
221
|
yield new Segment(box.top.right.repeat(geometry.right), border);
|
|
232
222
|
yield Segment.line();
|
|
233
223
|
return;
|
|
234
224
|
}
|
|
235
|
-
const titleText = typeof this.title === "string" ? this.title : this.title.plain;
|
|
236
|
-
const titleDisplay = ` ${titleText} `;
|
|
237
|
-
const titleWidth = cellLen(titleDisplay);
|
|
238
|
-
const titleSeg = borderTextStyle(options, this.titleStyle, border);
|
|
239
225
|
yield new Segment(box.top.left.repeat(geometry.left), border);
|
|
240
226
|
if (titleWidth >= innerBorderWidth) {
|
|
241
|
-
// Title fills the border. [LAW:one-source-of-truth]
|
|
242
|
-
//
|
|
243
|
-
//
|
|
244
|
-
yield
|
|
227
|
+
// Title fills the border. [LAW:one-source-of-truth] adjustLineLength is
|
|
228
|
+
// cell-aware — a plain .slice would miscount wide chars and break border
|
|
229
|
+
// alignment.
|
|
230
|
+
yield* Segment.adjustLineLength(title, innerBorderWidth, titleSeg);
|
|
245
231
|
}
|
|
246
232
|
else {
|
|
247
233
|
// Center the title in the top border
|
|
@@ -249,7 +235,7 @@ export class Panel {
|
|
|
249
235
|
const rightRuleWidth = innerBorderWidth - titleWidth - leftRuleWidth;
|
|
250
236
|
if (leftRuleWidth > 0)
|
|
251
237
|
yield new Segment(box.top.horizontal.repeat(leftRuleWidth), border);
|
|
252
|
-
yield
|
|
238
|
+
yield* title;
|
|
253
239
|
if (rightRuleWidth > 0)
|
|
254
240
|
yield new Segment(box.top.horizontal.repeat(rightRuleWidth), border);
|
|
255
241
|
}
|
|
@@ -275,25 +261,24 @@ export class Panel {
|
|
|
275
261
|
// (if any) hugs the right edge and the subtitle treats the remainder
|
|
276
262
|
// as its centering canvas.
|
|
277
263
|
const centerWidth = Math.max(0, innerBorderWidth - accessoryWidth);
|
|
278
|
-
|
|
264
|
+
const subtitleSeg = borderTextStyle(options, this.subtitleStyle, border);
|
|
265
|
+
const subtitle = inlineLabel(this.subtitle, options, subtitleSeg);
|
|
266
|
+
const subtitleWidth = Segment.getLineLength(subtitle);
|
|
267
|
+
if (subtitleWidth === 0) {
|
|
279
268
|
if (centerWidth > 0)
|
|
280
269
|
yield new Segment(box.bottom.horizontal.repeat(centerWidth), border);
|
|
281
270
|
}
|
|
282
271
|
else {
|
|
283
|
-
const subtitleText = typeof this.subtitle === "string" ? this.subtitle : this.subtitle.plain;
|
|
284
|
-
const subtitleDisplay = ` ${subtitleText} `;
|
|
285
|
-
const subtitleWidth = cellLen(subtitleDisplay);
|
|
286
|
-
const subtitleSeg = borderTextStyle(options, this.subtitleStyle, border);
|
|
287
272
|
if (subtitleWidth >= centerWidth) {
|
|
288
273
|
// Cell-aware clip — see _renderTopBorder.
|
|
289
|
-
yield
|
|
274
|
+
yield* Segment.adjustLineLength(subtitle, centerWidth, subtitleSeg);
|
|
290
275
|
}
|
|
291
276
|
else {
|
|
292
277
|
const leftRuleWidth = Math.floor((centerWidth - subtitleWidth) / 2);
|
|
293
278
|
const rightRuleWidth = centerWidth - subtitleWidth - leftRuleWidth;
|
|
294
279
|
if (leftRuleWidth > 0)
|
|
295
280
|
yield new Segment(box.bottom.horizontal.repeat(leftRuleWidth), border);
|
|
296
|
-
yield
|
|
281
|
+
yield* subtitle;
|
|
297
282
|
if (rightRuleWidth > 0)
|
|
298
283
|
yield new Segment(box.bottom.horizontal.repeat(rightRuleWidth), border);
|
|
299
284
|
}
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
import { Segment } from "../core/segment.js";
|
|
5
5
|
import { RichText } from "../core/text.js";
|
|
6
6
|
import { Console } from "../core/console.js";
|
|
7
|
-
import { escape as escapeMarkup
|
|
7
|
+
import { escape as escapeMarkup } from "../core/markup.js";
|
|
8
|
+
import { embeddedText } from "./embed.js";
|
|
8
9
|
import { ProgressBar } from "./progressBar.js";
|
|
9
10
|
import { Spinner } from "./spinner.js";
|
|
10
11
|
import { Live } from "./live.js";
|
|
@@ -23,13 +24,9 @@ export class TextColumn {
|
|
|
23
24
|
// Use a callback so `$&`/`$1`/`$$` in the task description aren't
|
|
24
25
|
// reinterpreted by String.replace as replacement patterns.
|
|
25
26
|
const formatted = this.format.replace(/\{task\.description\}/g, () => description);
|
|
26
|
-
// [LAW:
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
// mutate directly rather than copy.
|
|
30
|
-
const text = renderMarkup(formatted);
|
|
31
|
-
text.end = "";
|
|
32
|
-
yield* text.render(options);
|
|
27
|
+
// [LAW:single-enforcer] A column is a row fragment, the same as any
|
|
28
|
+
// embedded text.
|
|
29
|
+
yield* embeddedText(formatted).render(options);
|
|
33
30
|
}
|
|
34
31
|
}
|
|
35
32
|
export class BarColumn {
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { Segment } from "../core/segment.js";
|
|
5
5
|
import { NULL_STYLE } from "../core/style.js";
|
|
6
|
-
import { getStyle } from "../core/protocol.js";
|
|
7
|
-
const
|
|
8
|
-
const
|
|
6
|
+
import { drawable, getStyle } from "../core/protocol.js";
|
|
7
|
+
const BAR = "━";
|
|
8
|
+
const ASCII_BAR = "-";
|
|
9
9
|
export class ProgressBar {
|
|
10
10
|
total;
|
|
11
11
|
completed;
|
|
@@ -38,11 +38,12 @@ export class ProgressBar {
|
|
|
38
38
|
const back = getStyle(options, this.style);
|
|
39
39
|
const fillStyle = fill.isNull ? undefined : fill;
|
|
40
40
|
const bgStyle = back.isNull ? undefined : back;
|
|
41
|
+
const bar = drawable(options, BAR, ASCII_BAR);
|
|
41
42
|
if (filledWidth > 0) {
|
|
42
|
-
yield new Segment(
|
|
43
|
+
yield new Segment(bar.repeat(filledWidth), fillStyle);
|
|
43
44
|
}
|
|
44
45
|
if (emptyWidth > 0) {
|
|
45
|
-
yield new Segment(
|
|
46
|
+
yield new Segment(bar.repeat(emptyWidth), bgStyle);
|
|
46
47
|
}
|
|
47
48
|
}
|
|
48
49
|
measure(_options) {
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Rule — a horizontal divider line, optionally with a centered title.
|
|
3
3
|
*/
|
|
4
4
|
import { Segment } from "../core/segment.js";
|
|
5
|
+
import type { RichText } from "../core/text.js";
|
|
5
6
|
import { Style } from "../core/style.js";
|
|
6
7
|
import type { Renderable, Measurable, RenderOptions } from "../core/protocol.js";
|
|
7
8
|
export type RuleAlign = "left" | "center" | "right";
|
|
@@ -11,11 +12,11 @@ export interface RuleOptions {
|
|
|
11
12
|
style?: string | Style;
|
|
12
13
|
}
|
|
13
14
|
export declare class Rule implements Renderable, Measurable {
|
|
14
|
-
readonly title: string | undefined;
|
|
15
|
+
readonly title: string | RichText | undefined;
|
|
15
16
|
readonly characters: string;
|
|
16
17
|
readonly align: RuleAlign;
|
|
17
18
|
readonly style: string | Style;
|
|
18
|
-
constructor(title?: string, options?: RuleOptions);
|
|
19
|
+
constructor(title?: string | RichText, options?: RuleOptions);
|
|
19
20
|
render(options: RenderOptions): Iterable<Segment>;
|
|
20
21
|
measure(_options: RenderOptions): {
|
|
21
22
|
minimum: number;
|
package/dist/renderables/rule.js
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
import { cellLen } from "../core/cells.js";
|
|
5
5
|
import { Segment } from "../core/segment.js";
|
|
6
6
|
import { NULL_STYLE } from "../core/style.js";
|
|
7
|
-
import { getStyle } from "../core/protocol.js";
|
|
7
|
+
import { drawable, getStyle } from "../core/protocol.js";
|
|
8
|
+
import { inlineLabel } from "./embed.js";
|
|
8
9
|
const ASCII_RULE_CHAR = "-";
|
|
9
10
|
const DEFAULT_RULE_CHAR = "\u2500"; // ─
|
|
10
11
|
export class Rule {
|
|
@@ -28,21 +29,20 @@ export class Rule {
|
|
|
28
29
|
}
|
|
29
30
|
*render(options) {
|
|
30
31
|
const maxWidth = options.maxWidth;
|
|
31
|
-
const ruleChar = options
|
|
32
|
+
const ruleChar = drawable(options, this.characters, ASCII_RULE_CHAR);
|
|
32
33
|
const style = getStyle(options, this.style);
|
|
33
34
|
const ruleStyle = style.isNull ? undefined : style;
|
|
34
|
-
|
|
35
|
+
const title = inlineLabel(this.title, options, ruleStyle);
|
|
36
|
+
const titleWidth = Segment.getLineLength(title);
|
|
37
|
+
if (titleWidth === 0) {
|
|
35
38
|
// No title — just a line of repeated characters
|
|
36
39
|
yield new Segment(repeatToWidth(ruleChar, maxWidth), ruleStyle);
|
|
37
40
|
yield Segment.line();
|
|
38
41
|
return;
|
|
39
42
|
}
|
|
40
|
-
// With title
|
|
41
|
-
const titleText = ` ${this.title} `;
|
|
42
|
-
const titleWidth = cellLen(titleText);
|
|
43
43
|
if (titleWidth >= maxWidth) {
|
|
44
|
-
// Title fills the whole width
|
|
45
|
-
yield
|
|
44
|
+
// Title fills the whole width; adjustLineLength cuts by cells, not code units.
|
|
45
|
+
yield* Segment.adjustLineLength(title, maxWidth, ruleStyle);
|
|
46
46
|
yield Segment.line();
|
|
47
47
|
return;
|
|
48
48
|
}
|
|
@@ -57,7 +57,7 @@ export class Rule {
|
|
|
57
57
|
if (leftWidth > 0) {
|
|
58
58
|
yield new Segment(repeatToWidth(ruleChar, leftWidth), ruleStyle);
|
|
59
59
|
}
|
|
60
|
-
yield
|
|
60
|
+
yield* title;
|
|
61
61
|
if (rightWidth > 0) {
|
|
62
62
|
yield new Segment(repeatToWidth(ruleChar, rightWidth), ruleStyle);
|
|
63
63
|
}
|
|
@@ -19,10 +19,12 @@ export declare class Spinner implements Renderable, Measurable {
|
|
|
19
19
|
constructor(name?: string, text?: string, options?: SpinnerOptions);
|
|
20
20
|
get frames(): readonly string[];
|
|
21
21
|
get interval(): number;
|
|
22
|
-
/** Advance frame
|
|
23
|
-
private
|
|
22
|
+
/** Advance the frame count by the time elapsed, and return it. */
|
|
23
|
+
private _advance;
|
|
24
|
+
/** The frames this output can draw: the `line` spinner stands in for any other on an ASCII-only one. */
|
|
25
|
+
private _drawnFrames;
|
|
24
26
|
render(options: RenderOptions): Iterable<Segment>;
|
|
25
|
-
measure(
|
|
27
|
+
measure(options: RenderOptions): {
|
|
26
28
|
minimum: number;
|
|
27
29
|
maximum: number;
|
|
28
30
|
};
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
import { cellLen } from "../core/cells.js";
|
|
5
5
|
import { Segment } from "../core/segment.js";
|
|
6
6
|
import { NULL_STYLE } from "../core/style.js";
|
|
7
|
-
import { SPINNERS, DEFAULT_SPINNER } from "../core/spinnerData.js";
|
|
8
|
-
import { getStyle } from "../core/protocol.js";
|
|
7
|
+
import { SPINNERS, DEFAULT_SPINNER, LINE_SPINNER } from "../core/spinnerData.js";
|
|
8
|
+
import { drawable, getStyle } from "../core/protocol.js";
|
|
9
|
+
const spinnerGlyphs = ({ frames }) => frames.join("");
|
|
9
10
|
export class Spinner {
|
|
10
11
|
name;
|
|
11
12
|
text;
|
|
@@ -34,8 +35,8 @@ export class Spinner {
|
|
|
34
35
|
get interval() {
|
|
35
36
|
return this._data.interval;
|
|
36
37
|
}
|
|
37
|
-
/** Advance frame
|
|
38
|
-
|
|
38
|
+
/** Advance the frame count by the time elapsed, and return it. */
|
|
39
|
+
_advance() {
|
|
39
40
|
const now = Date.now();
|
|
40
41
|
const elapsed = now - this._lastUpdate;
|
|
41
42
|
const effectiveInterval = this.interval / this.speed;
|
|
@@ -44,10 +45,15 @@ export class Spinner {
|
|
|
44
45
|
this._frameIndex = (this._frameIndex + steps) % this._data.frames.length;
|
|
45
46
|
this._lastUpdate = now;
|
|
46
47
|
}
|
|
47
|
-
return this.
|
|
48
|
+
return this._frameIndex;
|
|
49
|
+
}
|
|
50
|
+
/** The frames this output can draw: the `line` spinner stands in for any other on an ASCII-only one. */
|
|
51
|
+
_drawnFrames(options) {
|
|
52
|
+
return drawable(options, this._data, LINE_SPINNER, spinnerGlyphs).frames;
|
|
48
53
|
}
|
|
49
54
|
*render(options) {
|
|
50
|
-
const
|
|
55
|
+
const frames = this._drawnFrames(options);
|
|
56
|
+
const frame = frames[this._advance() % frames.length];
|
|
51
57
|
const style = getStyle(options, this.style);
|
|
52
58
|
const spinStyle = style.isNull ? undefined : style;
|
|
53
59
|
yield new Segment(frame, spinStyle);
|
|
@@ -55,8 +61,8 @@ export class Spinner {
|
|
|
55
61
|
yield new Segment(` ${this.text}`);
|
|
56
62
|
}
|
|
57
63
|
}
|
|
58
|
-
measure(
|
|
59
|
-
const frameWidth = Math.max(...this.
|
|
64
|
+
measure(options) {
|
|
65
|
+
const frameWidth = Math.max(...this._drawnFrames(options).map((f) => cellLen(f)));
|
|
60
66
|
const textWidth = this.text ? cellLen(this.text) + 1 : 0;
|
|
61
67
|
const total = frameWidth + textWidth;
|
|
62
68
|
return { minimum: frameWidth, maximum: total };
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { Segment } from "../core/segment.js";
|
|
6
6
|
import type { PaddingDimensions } from "./padding.js";
|
|
7
|
-
import type
|
|
7
|
+
import { type Measurable, type Renderable, type RenderOptions } from "../core/protocol.js";
|
|
8
8
|
export interface SyntaxOptions {
|
|
9
9
|
lineNumbers?: boolean;
|
|
10
10
|
theme?: string;
|
|
@@ -6,6 +6,7 @@ import { cellLen } from "../core/cells.js";
|
|
|
6
6
|
import { Segment } from "../core/segment.js";
|
|
7
7
|
import { Style } from "../core/style.js";
|
|
8
8
|
import { RichText } from "../core/text.js";
|
|
9
|
+
import { drawable } from "../core/protocol.js";
|
|
9
10
|
// Built-in token patterns for common languages
|
|
10
11
|
const TOKEN_PATTERNS = {
|
|
11
12
|
_default: [
|
|
@@ -72,7 +73,7 @@ export class Syntax {
|
|
|
72
73
|
? Style.parse("bold on grey27")
|
|
73
74
|
: Style.parse("dim");
|
|
74
75
|
yield new Segment(numStr, numStyle);
|
|
75
|
-
yield new Segment("│ ", Style.parse("dim"));
|
|
76
|
+
yield new Segment(drawable(options, "│ ", "| "), Style.parse("dim"));
|
|
76
77
|
}
|
|
77
78
|
const line = textLines[i];
|
|
78
79
|
const segs = [...line.render({ ...options, maxWidth: options.maxWidth - lineNumWidth - 2 })];
|
|
@@ -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, RenderOptions } from "../core/protocol.js";
|
|
9
|
+
import type { Renderable, Measurable, OverflowMethod, RenderOptions } from "../core/protocol.js";
|
|
10
10
|
export interface ColumnOptions {
|
|
11
11
|
header?: string | RichText;
|
|
12
12
|
footer?: string | RichText;
|
|
@@ -19,7 +19,7 @@ export interface ColumnOptions {
|
|
|
19
19
|
maxWidth?: number;
|
|
20
20
|
ratio?: number;
|
|
21
21
|
noWrap?: boolean;
|
|
22
|
-
overflow?:
|
|
22
|
+
overflow?: OverflowMethod;
|
|
23
23
|
}
|
|
24
24
|
export declare class Column {
|
|
25
25
|
private _header;
|
|
@@ -33,7 +33,7 @@ export declare class Column {
|
|
|
33
33
|
maxWidth: number | undefined;
|
|
34
34
|
ratio: number | undefined;
|
|
35
35
|
noWrap: boolean;
|
|
36
|
-
overflow:
|
|
36
|
+
overflow: OverflowMethod;
|
|
37
37
|
private _cells;
|
|
38
38
|
constructor(options?: ColumnOptions);
|
|
39
39
|
/**
|
|
@@ -42,7 +42,7 @@ export declare class Column {
|
|
|
42
42
|
* constructor-only stamp held only until the first `columns[0].footer = mine`
|
|
43
43
|
* — which installed content that had parsed no markup, still carried its
|
|
44
44
|
* `end`, and was still owned by the caller, into a slot every reader below
|
|
45
|
-
* assumes `
|
|
45
|
+
* assumes `embeddedText` has been through. [LAW:parse-dont-validate] The setter
|
|
46
46
|
* is the border, so the guarantee holds for the object's whole lifetime and
|
|
47
47
|
* the constructor is one caller of it rather than the one place it is true.
|
|
48
48
|
*
|
|
@@ -51,7 +51,7 @@ export declare class Column {
|
|
|
51
51
|
* a column always has one and `show_footer` alone decides whether it is
|
|
52
52
|
* drawn. Modelling the absence as `undefined` instead made "no column has a
|
|
53
53
|
* footer" a state the render path could ask about — and it did, skipping the
|
|
54
|
-
* row a caller had asked for. `
|
|
54
|
+
* row a caller had asked for. `embeddedText` already maps nothing onto empty,
|
|
55
55
|
* which is why the setters take `undefined` rather than defaulting around it.
|
|
56
56
|
*/
|
|
57
57
|
get header(): RichText;
|
|
@@ -121,11 +121,13 @@ export declare class Table implements Renderable, Measurable {
|
|
|
121
121
|
* [LAW:one-source-of-truth] Both ends of the range are widths the geometry
|
|
122
122
|
* actually produced — the maximum from the demands as they stand, the
|
|
123
123
|
* minimum from the same layout with every column asking for a single cell.
|
|
124
|
-
* Neither end stretches:
|
|
125
|
-
* leave over, and a renderable reports the width its content
|
|
126
|
-
* than the width it was offered.
|
|
127
|
-
*
|
|
128
|
-
*
|
|
124
|
+
* Neither end stretches or fills into an offer: both only spend cells an
|
|
125
|
+
* offer happens to leave over, and a renderable reports the width its content
|
|
126
|
+
* wants rather than the width it was offered. A declared `width` is not an
|
|
127
|
+
* offer, and the maximum reports it. Letting either in made the table measure
|
|
128
|
+
* `Infinity` against an unbounded offer, where `withBoundedWidth` needs a
|
|
129
|
+
* natural width to fall back on — an expanding table, and an empty
|
|
130
|
+
* `Table.grid()`.
|
|
129
131
|
* Neither can exceed the width offered and the tighter request cannot exceed
|
|
130
132
|
* the looser one, so the range cannot invert. Deriving the minimum from raw
|
|
131
133
|
* column and padding counts instead is what used to return
|
|
@@ -172,11 +174,21 @@ export declare class Table implements Renderable, Measurable {
|
|
|
172
174
|
*/
|
|
173
175
|
private _columnCells;
|
|
174
176
|
/**
|
|
175
|
-
* The widest cell in a column,
|
|
176
|
-
* Zero
|
|
177
|
-
* nothing else.
|
|
177
|
+
* The widest cell in a column, or `undefined` when the column has no cell to
|
|
178
|
+
* measure. Zero is a column whose cells draw nothing — a gutter asks for its
|
|
179
|
+
* padding and nothing else — and is not the same answer.
|
|
180
|
+
* [LAW:types-are-the-program]
|
|
178
181
|
*/
|
|
179
|
-
private
|
|
182
|
+
private _widestCell;
|
|
183
|
+
/**
|
|
184
|
+
* A natural width held to the column's own `minWidth`/`maxWidth`.
|
|
185
|
+
*
|
|
186
|
+
* A bound is a count of cells, read by the rule every width is read by: NaN
|
|
187
|
+
* and a negative are zero cells, so a NaN floor bounds nothing and a NaN
|
|
188
|
+
* ceiling is a ceiling of zero, as `width: NaN` is. A bare `Math.max` returns
|
|
189
|
+
* NaN instead, and the column vanishes. [LAW:one-source-of-truth]
|
|
190
|
+
*/
|
|
191
|
+
private _bounded;
|
|
180
192
|
private _renderRow;
|
|
181
193
|
private _renderTitle;
|
|
182
194
|
}
|