@promptctl/rich-js 0.18.0 → 0.19.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 +9 -7
- 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 +145 -0
- package/dist/core/box.js +372 -0
- package/dist/core/cells.d.ts +192 -0
- package/dist/core/cells.js +334 -0
- package/dist/core/clock.d.ts +48 -0
- package/dist/core/clock.js +42 -0
- package/dist/core/color.d.ts +326 -0
- package/dist/core/color.js +1225 -0
- package/dist/core/console.d.ts +196 -0
- package/dist/core/console.js +596 -0
- package/dist/core/easing.d.ts +86 -0
- package/dist/core/easing.js +171 -0
- package/dist/core/emoji.d.ts +24 -0
- package/dist/core/emoji.js +391 -0
- package/dist/core/env.d.ts +16 -0
- package/dist/core/env.js +16 -0
- package/dist/core/export-html.d.ts +59 -0
- package/dist/core/export-html.js +197 -0
- package/dist/core/export-lines.d.ts +130 -0
- package/dist/core/export-lines.js +159 -0
- package/dist/core/export-svg.d.ts +49 -0
- package/dist/core/export-svg.js +213 -0
- package/dist/core/fnv1a.d.ts +10 -0
- package/dist/core/fnv1a.js +17 -0
- package/dist/core/highlighter.d.ts +33 -0
- package/dist/core/highlighter.js +190 -0
- package/dist/core/json.d.ts +27 -0
- package/dist/core/json.js +53 -0
- package/dist/core/markup.d.ts +140 -0
- package/dist/core/markup.js +654 -0
- package/dist/core/measure.d.ts +27 -0
- package/dist/core/measure.js +67 -0
- package/dist/core/memo.d.ts +19 -0
- package/dist/core/memo.js +34 -0
- package/dist/core/oklch.d.ts +161 -0
- package/dist/core/oklch.js +312 -0
- package/dist/core/osc8.d.ts +68 -0
- package/dist/core/osc8.js +78 -0
- package/dist/core/paint.d.ts +107 -0
- package/dist/core/paint.js +150 -0
- package/dist/core/place.d.ts +30 -0
- package/dist/core/place.js +49 -0
- package/dist/core/pretty.d.ts +247 -0
- package/dist/core/pretty.js +906 -0
- package/dist/core/protocol.d.ts +305 -0
- package/dist/core/protocol.js +183 -0
- package/dist/core/render.d.ts +87 -0
- package/dist/core/render.js +105 -0
- package/dist/core/segment.d.ts +162 -0
- package/dist/core/segment.js +488 -0
- package/dist/core/spinnerData.d.ts +12 -0
- package/dist/core/spinnerData.js +117 -0
- package/dist/core/strip.d.ts +152 -0
- package/dist/core/strip.js +326 -0
- package/dist/core/style.d.ts +189 -0
- package/dist/core/style.js +758 -0
- package/dist/core/subscription.d.ts +12 -0
- package/dist/core/subscription.js +12 -0
- package/dist/core/text.d.ts +283 -0
- package/dist/core/text.js +1097 -0
- package/dist/core/wrap.d.ts +46 -0
- package/dist/core/wrap.js +140 -0
- package/dist/host/app.d.ts +133 -0
- package/dist/host/app.js +285 -0
- package/dist/host/host-environment.d.ts +26 -0
- package/dist/host/host-environment.js +44 -0
- package/dist/host/index.d.ts +6 -0
- package/dist/host/index.js +3 -0
- package/dist/host/terminal-host.d.ts +180 -0
- package/dist/host/terminal-host.js +186 -0
- package/dist/index.d.ts +98 -0
- package/dist/index.js +114 -0
- package/dist/node/prompt.d.ts +34 -0
- package/dist/node/prompt.js +51 -0
- package/dist/node/save.d.ts +18 -0
- package/dist/node/save.js +24 -0
- package/dist/node/terminal-host.d.ts +114 -0
- package/dist/node/terminal-host.js +227 -0
- package/dist/node/traceback.d.ts +38 -0
- package/dist/node/traceback.js +98 -0
- package/dist/renderables/align.d.ts +16 -0
- package/dist/renderables/align.js +26 -0
- package/dist/renderables/columns.d.ts +77 -0
- package/dist/renderables/columns.js +191 -0
- package/dist/renderables/constrain.d.ts +15 -0
- package/dist/renderables/constrain.js +31 -0
- package/dist/renderables/effect.d.ts +98 -0
- package/dist/renderables/effect.js +160 -0
- package/dist/renderables/embed.d.ts +107 -0
- package/dist/renderables/embed.js +160 -0
- package/dist/renderables/flexStrip.d.ts +41 -0
- package/dist/renderables/flexStrip.js +200 -0
- package/dist/renderables/group.d.ts +14 -0
- package/dist/renderables/group.js +22 -0
- package/dist/renderables/layout.d.ts +75 -0
- package/dist/renderables/layout.js +223 -0
- package/dist/renderables/live.d.ts +74 -0
- package/dist/renderables/live.js +188 -0
- package/dist/renderables/markdown.d.ts +38 -0
- package/dist/renderables/markdown.js +587 -0
- package/dist/renderables/padding.d.ts +59 -0
- package/dist/renderables/padding.js +147 -0
- package/dist/renderables/panel.d.ts +114 -0
- package/dist/renderables/panel.js +303 -0
- package/dist/renderables/progress.d.ts +178 -0
- package/dist/renderables/progress.js +362 -0
- package/dist/renderables/progressBar.d.ts +31 -0
- package/dist/renderables/progressBar.js +64 -0
- package/dist/renderables/prompt.d.ts +71 -0
- package/dist/renderables/prompt.js +165 -0
- package/dist/renderables/ratio.d.ts +123 -0
- package/dist/renderables/ratio.js +213 -0
- package/dist/renderables/rule.d.ts +26 -0
- package/dist/renderables/rule.js +86 -0
- package/dist/renderables/spinner.d.ts +57 -0
- package/dist/renderables/spinner.js +103 -0
- package/dist/renderables/status.d.ts +29 -0
- package/dist/renderables/status.js +46 -0
- package/dist/renderables/syntax.d.ts +65 -0
- package/dist/renderables/syntax.js +166 -0
- package/dist/renderables/table.d.ts +232 -0
- package/dist/renderables/table.js +973 -0
- package/dist/renderables/traceback.d.ts +32 -0
- package/dist/renderables/traceback.js +279 -0
- package/dist/renderables/tree.d.ts +76 -0
- package/dist/renderables/tree.js +177 -0
- package/dist/renderables/viewport.d.ts +114 -0
- package/dist/renderables/viewport.js +196 -0
- package/dist/template-bindings/color-funcs.d.ts +109 -0
- package/dist/template-bindings/color-funcs.js +243 -0
- package/dist/template-bindings/helpers.d.ts +26 -0
- package/dist/template-bindings/helpers.js +33 -0
- package/dist/template-bindings/index.d.ts +119 -0
- package/dist/template-bindings/index.js +162 -0
- package/dist/template-bindings/palette-funcs.d.ts +96 -0
- package/dist/template-bindings/palette-funcs.js +145 -0
- package/dist/template-bindings/style-funcs.d.ts +28 -0
- package/dist/template-bindings/style-funcs.js +157 -0
- package/dist/themes/buildPalette.d.ts +57 -0
- package/dist/themes/buildPalette.js +100 -0
- package/dist/themes/colorMath.d.ts +94 -0
- package/dist/themes/colorMath.js +280 -0
- package/dist/themes/colorRef.d.ts +36 -0
- package/dist/themes/colorRef.js +78 -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.d.ts +3 -0
- package/dist/themes/data/atom-one-dark.js +177 -0
- package/dist/themes/data/atom-one-light.d.ts +3 -0
- package/dist/themes/data/atom-one-light.js +177 -0
- package/dist/themes/data/catppuccin-frappe.d.ts +3 -0
- package/dist/themes/data/catppuccin-frappe.js +177 -0
- package/dist/themes/data/catppuccin-latte.d.ts +3 -0
- package/dist/themes/data/catppuccin-latte.js +177 -0
- package/dist/themes/data/catppuccin-macchiato.d.ts +3 -0
- package/dist/themes/data/catppuccin-macchiato.js +177 -0
- package/dist/themes/data/catppuccin-mocha.d.ts +3 -0
- package/dist/themes/data/catppuccin-mocha.js +177 -0
- package/dist/themes/data/cyberpunk.d.ts +17 -0
- package/dist/themes/data/cyberpunk.js +193 -0
- package/dist/themes/data/default.d.ts +3 -0
- package/dist/themes/data/default.js +160 -0
- package/dist/themes/data/dracula.d.ts +3 -0
- package/dist/themes/data/dracula.js +177 -0
- package/dist/themes/data/flexoki.d.ts +3 -0
- package/dist/themes/data/flexoki.js +177 -0
- package/dist/themes/data/gruvbox.d.ts +3 -0
- package/dist/themes/data/gruvbox.js +177 -0
- package/dist/themes/data/index.d.ts +35 -0
- package/dist/themes/data/index.js +64 -0
- package/dist/themes/data/monokai.d.ts +3 -0
- package/dist/themes/data/monokai.js +177 -0
- package/dist/themes/data/nord.d.ts +3 -0
- package/dist/themes/data/nord.js +177 -0
- package/dist/themes/data/rose-pine-dawn.d.ts +3 -0
- package/dist/themes/data/rose-pine-dawn.js +177 -0
- package/dist/themes/data/rose-pine-moon.d.ts +3 -0
- package/dist/themes/data/rose-pine-moon.js +177 -0
- package/dist/themes/data/rose-pine.d.ts +3 -0
- package/dist/themes/data/rose-pine.js +177 -0
- package/dist/themes/data/solarized-dark.d.ts +3 -0
- package/dist/themes/data/solarized-dark.js +177 -0
- package/dist/themes/data/solarized-light.d.ts +3 -0
- package/dist/themes/data/solarized-light.js +177 -0
- package/dist/themes/data/svg-export.d.ts +3 -0
- package/dist/themes/data/svg-export.js +177 -0
- package/dist/themes/data/textual-ansi.d.ts +3 -0
- package/dist/themes/data/textual-ansi.js +160 -0
- package/dist/themes/data/textual-dark.d.ts +3 -0
- package/dist/themes/data/textual-dark.js +160 -0
- package/dist/themes/data/textual-light.d.ts +3 -0
- package/dist/themes/data/textual-light.js +160 -0
- package/dist/themes/data/tokyo-night.d.ts +3 -0
- package/dist/themes/data/tokyo-night.js +177 -0
- package/dist/themes/data/types.d.ts +31 -0
- package/dist/themes/data/types.js +10 -0
- package/dist/themes/palette.d.ts +45 -0
- package/dist/themes/palette.js +71 -0
- package/dist/themes/ramp.d.ts +70 -0
- package/dist/themes/ramp.js +103 -0
- package/dist/themes/registry.d.ts +44 -0
- package/dist/themes/registry.js +105 -0
- package/dist/themes/terminalThemes.d.ts +49 -0
- package/dist/themes/terminalThemes.js +63 -0
- package/dist/themes/transpose.d.ts +87 -0
- package/dist/themes/transpose.js +138 -0
- package/dist/widgets/button.d.ts +45 -0
- package/dist/widgets/button.js +177 -0
- package/dist/widgets/checkbox.d.ts +38 -0
- package/dist/widgets/checkbox.js +135 -0
- package/dist/widgets/dropdown.d.ts +64 -0
- package/dist/widgets/dropdown.js +416 -0
- package/dist/widgets/event-router.d.ts +71 -0
- package/dist/widgets/event-router.js +629 -0
- package/dist/widgets/focus-manager.d.ts +45 -0
- package/dist/widgets/focus-manager.js +191 -0
- package/dist/widgets/hit.d.ts +64 -0
- package/dist/widgets/hit.js +113 -0
- package/dist/widgets/index.d.ts +20 -0
- package/dist/widgets/index.js +14 -0
- package/dist/widgets/ink.d.ts +22 -0
- package/dist/widgets/ink.js +31 -0
- package/dist/widgets/slider.d.ts +54 -0
- package/dist/widgets/slider.js +247 -0
- package/dist/widgets/static-item.d.ts +34 -0
- package/dist/widgets/static-item.js +54 -0
- package/dist/widgets/text-input.d.ts +283 -0
- package/dist/widgets/text-input.js +1174 -0
- package/dist/widgets/themed-widget.d.ts +20 -0
- package/dist/widgets/themed-widget.js +89 -0
- package/dist/widgets/toggle.d.ts +41 -0
- package/dist/widgets/toggle.js +157 -0
- package/dist/widgets/types.d.ts +87 -0
- package/dist/widgets/types.js +30 -0
- package/dist/widgets/widget-app.d.ts +65 -0
- package/dist/widgets/widget-app.js +206 -0
- package/dist/widgets/widget-base.d.ts +42 -0
- package/dist/widgets/widget-base.js +172 -0
- package/package.json +16 -2
package/dist/core/box.js
ADDED
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Box-drawing character sets for borders and table grids.
|
|
3
|
+
*
|
|
4
|
+
* A style is declared as an 8x4 character grid — one line per row a table can
|
|
5
|
+
* draw, one column per position within that row:
|
|
6
|
+
*
|
|
7
|
+
* ┌─┬┐ top border
|
|
8
|
+
* │ ││ header content
|
|
9
|
+
* ├─┼┤ header separator
|
|
10
|
+
* │ ││ body content
|
|
11
|
+
* ├─┼┤ row separator
|
|
12
|
+
* ├─┼┤ footer separator
|
|
13
|
+
* │ ││ footer content
|
|
14
|
+
* └─┴┘ bottom border
|
|
15
|
+
*
|
|
16
|
+
* [LAW:one-source-of-truth] The grid is the shape the reference implementation
|
|
17
|
+
* (Python Rich's `box.py`) publishes these glyphs in, so a constant below can
|
|
18
|
+
* be diffed against it character for character. The eighteen named fields this
|
|
19
|
+
* replaced were a second, differently-shaped map of the same territory, and it
|
|
20
|
+
* had drifted: seven of the nineteen constants carried wrong glyphs, and the
|
|
21
|
+
* field named `mid` held the reference's line 3 while the reference's `mid_*`
|
|
22
|
+
* is line 4 — so reading the reference name-for-name swapped a separator for a
|
|
23
|
+
* content row. Named row fields are gone for that reason; a row is reached by
|
|
24
|
+
* what it is (`getRow`, `getContentChars`), never by a name that can be
|
|
25
|
+
* mismatched to a line.
|
|
26
|
+
*/
|
|
27
|
+
import { cellLen } from "./cells.js";
|
|
28
|
+
import { Segment } from "./segment.js";
|
|
29
|
+
import { drawable } from "./protocol.js";
|
|
30
|
+
const GRID_ROWS = 8;
|
|
31
|
+
const GRID_COLUMNS = 4;
|
|
32
|
+
/** Corners that a legacy Windows terminal cannot draw, and their square kin. */
|
|
33
|
+
const SAFE_SUBSTITUTIONS = {
|
|
34
|
+
"╭": "┌",
|
|
35
|
+
"╮": "┐",
|
|
36
|
+
"╰": "└",
|
|
37
|
+
"╯": "┘",
|
|
38
|
+
};
|
|
39
|
+
const edgeOf = (row) => ({
|
|
40
|
+
left: row[0],
|
|
41
|
+
horizontal: row[1],
|
|
42
|
+
cross: row[2],
|
|
43
|
+
right: row[3],
|
|
44
|
+
});
|
|
45
|
+
const contentOf = (row) => ({
|
|
46
|
+
left: row[0],
|
|
47
|
+
vertical: row[2],
|
|
48
|
+
right: row[3],
|
|
49
|
+
});
|
|
50
|
+
// [LAW:one-type-per-behavior] Box is a single type for all border styles — instances differ by data
|
|
51
|
+
export class Box {
|
|
52
|
+
top;
|
|
53
|
+
bottom;
|
|
54
|
+
grid;
|
|
55
|
+
headContent;
|
|
56
|
+
headSeparator;
|
|
57
|
+
bodyContent;
|
|
58
|
+
rowSeparator;
|
|
59
|
+
footSeparator;
|
|
60
|
+
footContent;
|
|
61
|
+
/**
|
|
62
|
+
* [LAW:parse-dont-validate] The one crossing between a grid string and box
|
|
63
|
+
* glyphs. A `Box` cannot exist without eight rows of four characters, so no
|
|
64
|
+
* consumer below ever re-checks the shape of the data it reads.
|
|
65
|
+
*/
|
|
66
|
+
constructor(grid) {
|
|
67
|
+
const lines = grid.split("\n");
|
|
68
|
+
// A row is four characters because `getEdge` indexes the four positions,
|
|
69
|
+
// and four cells because that is what the terminal draws — a single astral
|
|
70
|
+
// glyph satisfies the first and breaks every frame the box appears in.
|
|
71
|
+
// [LAW:single-enforcer] `cellLen` is the cell-width authority.
|
|
72
|
+
const malformed = lines.length !== GRID_ROWS
|
|
73
|
+
|| lines.some((line) => Array.from(line).length !== GRID_COLUMNS)
|
|
74
|
+
|| lines.some((line) => cellLen(line) !== GRID_COLUMNS);
|
|
75
|
+
if (malformed) {
|
|
76
|
+
throw new Error(`A box grid is ${GRID_ROWS} lines of ${GRID_COLUMNS} single-cell `
|
|
77
|
+
+ `characters; got ${lines.length} line(s) measuring `
|
|
78
|
+
+ lines.map((line) => `${Array.from(line).length}/${cellLen(line)}`).join(", ")
|
|
79
|
+
+ " characters/cells");
|
|
80
|
+
}
|
|
81
|
+
const rows = lines.map((line) => Array.from(line));
|
|
82
|
+
this.grid = grid;
|
|
83
|
+
this.top = edgeOf(rows[0]);
|
|
84
|
+
this.headContent = contentOf(rows[1]);
|
|
85
|
+
this.headSeparator = edgeOf(rows[2]);
|
|
86
|
+
this.bodyContent = contentOf(rows[3]);
|
|
87
|
+
this.rowSeparator = edgeOf(rows[4]);
|
|
88
|
+
this.footSeparator = edgeOf(rows[5]);
|
|
89
|
+
this.footContent = contentOf(rows[6]);
|
|
90
|
+
this.bottom = edgeOf(rows[7]);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Renders the top border row for given column widths.
|
|
94
|
+
*/
|
|
95
|
+
getTop(widths, style, edge = true) {
|
|
96
|
+
return this.getEdge(widths, this.top, style, edge);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Renders the separator drawn *above* a row at `level` — the head separator
|
|
100
|
+
* under the header, the row separator between body rows, the foot separator
|
|
101
|
+
* above the footer.
|
|
102
|
+
*/
|
|
103
|
+
getRow(widths, level, style, edge = true) {
|
|
104
|
+
return this.getEdge(widths, this.getRowChars(level), style, edge);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* The verticals that frame a content row at `level` — the counterpart to
|
|
108
|
+
* `getRow`, which draws the separator between two such rows.
|
|
109
|
+
*/
|
|
110
|
+
getContentChars(level) {
|
|
111
|
+
switch (level) {
|
|
112
|
+
case "head":
|
|
113
|
+
return this.headContent;
|
|
114
|
+
// `mid` is a spacer between body rows, so it is framed as one.
|
|
115
|
+
case "row":
|
|
116
|
+
case "mid":
|
|
117
|
+
return this.bodyContent;
|
|
118
|
+
case "foot":
|
|
119
|
+
return this.footContent;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Renders the bottom border row.
|
|
124
|
+
*/
|
|
125
|
+
getBottom(widths, style, edge = true) {
|
|
126
|
+
return this.getEdge(widths, this.bottom, style, edge);
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* The box to draw with when the platform cannot render this one as written.
|
|
130
|
+
*
|
|
131
|
+
* `asciiOnly` gives up a box that spends non-ASCII glyphs for `ASCII`, and
|
|
132
|
+
* leaves the four already-ASCII styles as they are — a caller that chose
|
|
133
|
+
* MARKDOWN or ASCII_DOUBLE_HEAD asked for that frame and it is already
|
|
134
|
+
* drawable, so answering with `ASCII` would trade a frame the terminal
|
|
135
|
+
* supports for a different one it equally supports. `safe` squares off the
|
|
136
|
+
* rounded corners a legacy Windows terminal draws as blanks.
|
|
137
|
+
*/
|
|
138
|
+
substitute(options = {}) {
|
|
139
|
+
// [LAW:one-source-of-truth] A box is wholly its grid, so the grid is what
|
|
140
|
+
// says whether it is already drawable — for a box built by `safeSubstitute`
|
|
141
|
+
// as much as for a shipped constant.
|
|
142
|
+
const drawn = drawable(options, this, ASCII, (box) => box.grid);
|
|
143
|
+
return drawn === this && options.safe === true ? this.safeSubstitute() : drawn;
|
|
144
|
+
}
|
|
145
|
+
safeSubstitute() {
|
|
146
|
+
return new Box(Array.from(this.grid, (char) => SAFE_SUBSTITUTIONS[char] ?? char).join(""));
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* The nearest box that spends no special glyphs on a header — what a table
|
|
150
|
+
* with `showHeader: false` draws with. A box whose head row already matches
|
|
151
|
+
* its body is its own answer, so this is the identity for fourteen of the
|
|
152
|
+
* nineteen shipped styles.
|
|
153
|
+
*
|
|
154
|
+
* It stands beside `substitute` rather than joining it because the two ask
|
|
155
|
+
* unrelated questions: `substitute` asks what the *platform* can draw, this
|
|
156
|
+
* asks what the *table* contains. Nothing correlates them, so a caller that
|
|
157
|
+
* wants both wants both, and a shared options bag would only multiply the
|
|
158
|
+
* combinations either one has to reason about. [LAW:no-mode-explosion]
|
|
159
|
+
*
|
|
160
|
+
* [LAW:types-are-the-program] The relation is keyed on the grid, not on
|
|
161
|
+
* object identity as the reference's dict is. A `Box` is wholly determined by
|
|
162
|
+
* its grid — that is what the constructor takes and all eight rows derive
|
|
163
|
+
* from — so two boxes with one grid must answer this alike. Identity keying
|
|
164
|
+
* would say otherwise the moment a box arrived by any route but the shipped
|
|
165
|
+
* constant, and `safeSubstitute` above builds exactly such a box: a fresh
|
|
166
|
+
* instance carrying an unchanged grid.
|
|
167
|
+
*/
|
|
168
|
+
plainHeaded() {
|
|
169
|
+
// `private` is scoped to the class, so the pairs below can be read by grid
|
|
170
|
+
// without exposing one.
|
|
171
|
+
return PLAIN_HEADED_SUBSTITUTIONS.find(([headed]) => headed.grid === this.grid)?.[1]
|
|
172
|
+
?? this;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* [LAW:dataflow-not-control-flow] Every full-width rule the box can draw is
|
|
176
|
+
* this one join; which rule it is arrives as four characters, not a branch.
|
|
177
|
+
* The rule is one segment, as the reference's `get_top` is one string, so
|
|
178
|
+
* its bytes are one styled run.
|
|
179
|
+
*/
|
|
180
|
+
getEdge(widths, chars, style, edge) {
|
|
181
|
+
const inner = widths.map((width) => chars.horizontal.repeat(width)).join(chars.cross);
|
|
182
|
+
const rule = edge ? chars.left + inner + chars.right : inner;
|
|
183
|
+
return [new Segment(rule, style), Segment.line()];
|
|
184
|
+
}
|
|
185
|
+
getRowChars(level) {
|
|
186
|
+
switch (level) {
|
|
187
|
+
case "head":
|
|
188
|
+
return this.headSeparator;
|
|
189
|
+
case "row":
|
|
190
|
+
return this.rowSeparator;
|
|
191
|
+
case "foot":
|
|
192
|
+
return this.footSeparator;
|
|
193
|
+
// The reference's spacer row, not a rule: blank fill between the body
|
|
194
|
+
// row's verticals. Nothing draws it yet — rich-table-jx1 has the details.
|
|
195
|
+
case "mid":
|
|
196
|
+
return {
|
|
197
|
+
left: this.bodyContent.left,
|
|
198
|
+
horizontal: " ",
|
|
199
|
+
cross: this.bodyContent.vertical,
|
|
200
|
+
right: this.bodyContent.right,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
// --- Pre-built box styles ---
|
|
206
|
+
// Transcribed from Python Rich's `rich/box.py` and verified grid-for-grid
|
|
207
|
+
// against it; see this module's header for the shape and why it is this shape.
|
|
208
|
+
export const ASCII = new Box("+--+\n" +
|
|
209
|
+
"| ||\n" +
|
|
210
|
+
"|-+|\n" +
|
|
211
|
+
"| ||\n" +
|
|
212
|
+
"|-+|\n" +
|
|
213
|
+
"|-+|\n" +
|
|
214
|
+
"| ||\n" +
|
|
215
|
+
"+--+");
|
|
216
|
+
export const ASCII2 = new Box("+-++\n" +
|
|
217
|
+
"| ||\n" +
|
|
218
|
+
"+-++\n" +
|
|
219
|
+
"| ||\n" +
|
|
220
|
+
"+-++\n" +
|
|
221
|
+
"+-++\n" +
|
|
222
|
+
"| ||\n" +
|
|
223
|
+
"+-++");
|
|
224
|
+
export const ASCII_DOUBLE_HEAD = new Box("+-++\n" +
|
|
225
|
+
"| ||\n" +
|
|
226
|
+
"+=++\n" +
|
|
227
|
+
"| ||\n" +
|
|
228
|
+
"+-++\n" +
|
|
229
|
+
"+-++\n" +
|
|
230
|
+
"| ||\n" +
|
|
231
|
+
"+-++");
|
|
232
|
+
export const SQUARE = new Box("┌─┬┐\n" +
|
|
233
|
+
"│ ││\n" +
|
|
234
|
+
"├─┼┤\n" +
|
|
235
|
+
"│ ││\n" +
|
|
236
|
+
"├─┼┤\n" +
|
|
237
|
+
"├─┼┤\n" +
|
|
238
|
+
"│ ││\n" +
|
|
239
|
+
"└─┴┘");
|
|
240
|
+
export const SQUARE_DOUBLE_HEAD = new Box("┌─┬┐\n" +
|
|
241
|
+
"│ ││\n" +
|
|
242
|
+
"╞═╪╡\n" +
|
|
243
|
+
"│ ││\n" +
|
|
244
|
+
"├─┼┤\n" +
|
|
245
|
+
"├─┼┤\n" +
|
|
246
|
+
"│ ││\n" +
|
|
247
|
+
"└─┴┘");
|
|
248
|
+
export const MINIMAL = new Box(" ╷ \n" +
|
|
249
|
+
" │ \n" +
|
|
250
|
+
"╶─┼╴\n" +
|
|
251
|
+
" │ \n" +
|
|
252
|
+
"╶─┼╴\n" +
|
|
253
|
+
"╶─┼╴\n" +
|
|
254
|
+
" │ \n" +
|
|
255
|
+
" ╵ ");
|
|
256
|
+
export const MINIMAL_HEAVY_HEAD = new Box(" ╷ \n" +
|
|
257
|
+
" │ \n" +
|
|
258
|
+
"╺━┿╸\n" +
|
|
259
|
+
" │ \n" +
|
|
260
|
+
"╶─┼╴\n" +
|
|
261
|
+
"╶─┼╴\n" +
|
|
262
|
+
" │ \n" +
|
|
263
|
+
" ╵ ");
|
|
264
|
+
export const MINIMAL_DOUBLE_HEAD = new Box(" ╷ \n" +
|
|
265
|
+
" │ \n" +
|
|
266
|
+
" ═╪ \n" +
|
|
267
|
+
" │ \n" +
|
|
268
|
+
" ─┼ \n" +
|
|
269
|
+
" ─┼ \n" +
|
|
270
|
+
" │ \n" +
|
|
271
|
+
" ╵ ");
|
|
272
|
+
export const SIMPLE = new Box(" \n" +
|
|
273
|
+
" \n" +
|
|
274
|
+
" ── \n" +
|
|
275
|
+
" \n" +
|
|
276
|
+
" \n" +
|
|
277
|
+
" ── \n" +
|
|
278
|
+
" \n" +
|
|
279
|
+
" ");
|
|
280
|
+
export const SIMPLE_HEAD = new Box(" \n" +
|
|
281
|
+
" \n" +
|
|
282
|
+
" ── \n" +
|
|
283
|
+
" \n" +
|
|
284
|
+
" \n" +
|
|
285
|
+
" \n" +
|
|
286
|
+
" \n" +
|
|
287
|
+
" ");
|
|
288
|
+
export const SIMPLE_HEAVY = new Box(" \n" +
|
|
289
|
+
" \n" +
|
|
290
|
+
" ━━ \n" +
|
|
291
|
+
" \n" +
|
|
292
|
+
" \n" +
|
|
293
|
+
" ━━ \n" +
|
|
294
|
+
" \n" +
|
|
295
|
+
" ");
|
|
296
|
+
export const HORIZONTALS = new Box(" ── \n" +
|
|
297
|
+
" \n" +
|
|
298
|
+
" ── \n" +
|
|
299
|
+
" \n" +
|
|
300
|
+
" ── \n" +
|
|
301
|
+
" ── \n" +
|
|
302
|
+
" \n" +
|
|
303
|
+
" ── ");
|
|
304
|
+
export const ROUNDED = new Box("╭─┬╮\n" +
|
|
305
|
+
"│ ││\n" +
|
|
306
|
+
"├─┼┤\n" +
|
|
307
|
+
"│ ││\n" +
|
|
308
|
+
"├─┼┤\n" +
|
|
309
|
+
"├─┼┤\n" +
|
|
310
|
+
"│ ││\n" +
|
|
311
|
+
"╰─┴╯");
|
|
312
|
+
export const HEAVY = new Box("┏━┳┓\n" +
|
|
313
|
+
"┃ ┃┃\n" +
|
|
314
|
+
"┣━╋┫\n" +
|
|
315
|
+
"┃ ┃┃\n" +
|
|
316
|
+
"┣━╋┫\n" +
|
|
317
|
+
"┣━╋┫\n" +
|
|
318
|
+
"┃ ┃┃\n" +
|
|
319
|
+
"┗━┻┛");
|
|
320
|
+
export const HEAVY_EDGE = new Box("┏━┯┓\n" +
|
|
321
|
+
"┃ │┃\n" +
|
|
322
|
+
"┠─┼┨\n" +
|
|
323
|
+
"┃ │┃\n" +
|
|
324
|
+
"┠─┼┨\n" +
|
|
325
|
+
"┠─┼┨\n" +
|
|
326
|
+
"┃ │┃\n" +
|
|
327
|
+
"┗━┷┛");
|
|
328
|
+
export const HEAVY_HEAD = new Box("┏━┳┓\n" +
|
|
329
|
+
"┃ ┃┃\n" +
|
|
330
|
+
"┡━╇┩\n" +
|
|
331
|
+
"│ ││\n" +
|
|
332
|
+
"├─┼┤\n" +
|
|
333
|
+
"├─┼┤\n" +
|
|
334
|
+
"│ ││\n" +
|
|
335
|
+
"└─┴┘");
|
|
336
|
+
export const DOUBLE = new Box("╔═╦╗\n" +
|
|
337
|
+
"║ ║║\n" +
|
|
338
|
+
"╠═╬╣\n" +
|
|
339
|
+
"║ ║║\n" +
|
|
340
|
+
"╠═╬╣\n" +
|
|
341
|
+
"╠═╬╣\n" +
|
|
342
|
+
"║ ║║\n" +
|
|
343
|
+
"╚═╩╝");
|
|
344
|
+
export const DOUBLE_EDGE = new Box("╔═╤╗\n" +
|
|
345
|
+
"║ │║\n" +
|
|
346
|
+
"╟─┼╢\n" +
|
|
347
|
+
"║ │║\n" +
|
|
348
|
+
"╟─┼╢\n" +
|
|
349
|
+
"╟─┼╢\n" +
|
|
350
|
+
"║ │║\n" +
|
|
351
|
+
"╚═╧╝");
|
|
352
|
+
export const MARKDOWN = new Box(" \n" +
|
|
353
|
+
"| ||\n" +
|
|
354
|
+
"|-||\n" +
|
|
355
|
+
"| ||\n" +
|
|
356
|
+
"|-||\n" +
|
|
357
|
+
"|-||\n" +
|
|
358
|
+
"| ||\n" +
|
|
359
|
+
" ");
|
|
360
|
+
/**
|
|
361
|
+
* Boxes whose header glyphs differ from their body's, paired with the kin that
|
|
362
|
+
* draws the same frame without them. Transcribed from the reference's
|
|
363
|
+
* `PLAIN_HEADED_SUBSTITUTIONS`; the fourteen styles absent here already draw a
|
|
364
|
+
* plain head, and `plainHeaded` returns them unchanged.
|
|
365
|
+
*/
|
|
366
|
+
const PLAIN_HEADED_SUBSTITUTIONS = [
|
|
367
|
+
[HEAVY_HEAD, SQUARE],
|
|
368
|
+
[SQUARE_DOUBLE_HEAD, SQUARE],
|
|
369
|
+
[MINIMAL_HEAVY_HEAD, MINIMAL],
|
|
370
|
+
[MINIMAL_DOUBLE_HEAD, MINIMAL],
|
|
371
|
+
[ASCII_DOUBLE_HEAD, ASCII2],
|
|
372
|
+
];
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal cell width calculation.
|
|
3
|
+
* Handles ASCII, CJK (double-width), and emoji characters.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Returns the terminal cell width of a string.
|
|
7
|
+
*/
|
|
8
|
+
export declare function cellLen(text: string): number;
|
|
9
|
+
declare const _cellCol: unique symbol;
|
|
10
|
+
declare const _codeUnit: unique symbol;
|
|
11
|
+
declare const _codePoint: unique symbol;
|
|
12
|
+
/** Terminal cell-column offset. Never interchangeable with a code-unit index. */
|
|
13
|
+
export type CellCol = number & {
|
|
14
|
+
readonly [_cellCol]: true;
|
|
15
|
+
};
|
|
16
|
+
/** JS string code-unit index. Never interchangeable with a cell-column offset. */
|
|
17
|
+
export type CodeUnit = number & {
|
|
18
|
+
readonly [_codeUnit]: true;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* A `CodeUnit` index that is additionally guaranteed to fall on a Unicode
|
|
22
|
+
* code-point boundary (i.e. never inside a surrogate pair). Assignable to
|
|
23
|
+
* `CodeUnit`; the reverse assignment is forbidden.
|
|
24
|
+
*/
|
|
25
|
+
export type CodePoint = CodeUnit & {
|
|
26
|
+
readonly [_codePoint]: true;
|
|
27
|
+
};
|
|
28
|
+
/** Brand a raw number as a CellCol. Use only at trust boundaries. */
|
|
29
|
+
export declare function asCellCol(n: number): CellCol;
|
|
30
|
+
/** Brand a raw number as a CodeUnit. Use only at trust boundaries. */
|
|
31
|
+
export declare function asCodeUnit(n: number): CodeUnit;
|
|
32
|
+
/** Brand a raw number as a CodePoint. Use only when the value is known to be
|
|
33
|
+
* on a Unicode code-point boundary. */
|
|
34
|
+
export declare function asCodePoint(n: number): CodePoint;
|
|
35
|
+
/**
|
|
36
|
+
* [LAW:parse-dont-validate] A caller's number as a count of cells — the checked
|
|
37
|
+
* counterpart to `asCellCol`'s unchecked brand, and the one place the rule "a
|
|
38
|
+
* cell count is a non-negative integer" is written.
|
|
39
|
+
*
|
|
40
|
+
* [LAW:one-source-of-truth] Every renderable is handed `RenderOptions.maxWidth`
|
|
41
|
+
* as a plain `number`, so every renderable used to answer this for itself and
|
|
42
|
+
* they disagreed: at NaN, `Table` collapsed to one cell of garbage, `Columns`
|
|
43
|
+
* and `Layout` threw `Invalid array length`, and `RichText` ignored the request
|
|
44
|
+
* and emitted its full natural width. Parse at the entry to `render`/`measure`
|
|
45
|
+
* and nothing downstream re-asks.
|
|
46
|
+
*
|
|
47
|
+
* The comparison is the point, not `Math.max(0, n)`: NaN fails every comparison
|
|
48
|
+
* and so floors here, where `Math.max` would return it and let it poison every
|
|
49
|
+
* bounds check downstream. Integral because a cell is not divisible — a
|
|
50
|
+
* fractional budget reaches a largest-remainder division, which grants a whole
|
|
51
|
+
* cell against a fractional residue and hands out more width than it was given.
|
|
52
|
+
*
|
|
53
|
+
* `Infinity` is outside what the comparison floors, so it passes through
|
|
54
|
+
* unchanged, and no clamp belongs here: the finite answer to an unbounded offer
|
|
55
|
+
* is the renderable's own natural width, which this function cannot see from
|
|
56
|
+
* the number alone. `withBoundedWidth` in `protocol.ts` is the second half of
|
|
57
|
+
* the parse and the only place that value is resolved.
|
|
58
|
+
*/
|
|
59
|
+
export declare function cellCount(n: number): CellCol;
|
|
60
|
+
/**
|
|
61
|
+
* Pads or crops a string to exactly `totalWidth` terminal cells.
|
|
62
|
+
* Invariant: cellLen(setCellSize(text, n)) === n (unless n is 0)
|
|
63
|
+
*/
|
|
64
|
+
export declare function setCellSize(text: string, totalWidth: CellCol): string;
|
|
65
|
+
/**
|
|
66
|
+
* Splits text at a cell position. Returns [left, right].
|
|
67
|
+
* When the position falls mid-wide-character, the left side is padded
|
|
68
|
+
* to reach exactly `position` cells. The wide char remains in the right side.
|
|
69
|
+
*
|
|
70
|
+
* [LAW:one-source-of-truth] The left side is `cellFit`'s, so the cut falls
|
|
71
|
+
* between the grapheme clusters `cellLen` measures and never inside one.
|
|
72
|
+
*/
|
|
73
|
+
export declare function splitText(text: string, position: CellCol): [string, string];
|
|
74
|
+
/**
|
|
75
|
+
* Cuts `text` into exactly `position` cells and the rest, as the reference's
|
|
76
|
+
* `Segment.split_cells` does: a wide glyph the cut goes through fits neither
|
|
77
|
+
* side, so it leaves a space in each of its cells, where `splitText` keeps it
|
|
78
|
+
* whole on the right. Every other character lands on exactly one side.
|
|
79
|
+
* `position` must fall inside `text`, between 0 and its width.
|
|
80
|
+
*/
|
|
81
|
+
export declare function cutCells(text: string, position: CellCol): [string, string];
|
|
82
|
+
/**
|
|
83
|
+
* Wraps text into lines of at most `maxWidth` cells, preserving every code
|
|
84
|
+
* point: `chopCells(t, w).join("") === t`. Unlike `splitText` this never pads,
|
|
85
|
+
* so a line ending before a wide glyph is narrower than `maxWidth` rather than
|
|
86
|
+
* padded out to it.
|
|
87
|
+
*
|
|
88
|
+
* A line overflows exactly where the budget cannot be met: a glyph wider than
|
|
89
|
+
* `maxWidth` is force-taken whole rather than dropped, and a `maxWidth` of zero
|
|
90
|
+
* or less is no budget at all, so the text comes back as one line.
|
|
91
|
+
*/
|
|
92
|
+
export declare function chopCells(text: string, maxWidth: CellCol): string[];
|
|
93
|
+
/**
|
|
94
|
+
* `line` split at each of `cuts`, in one walk over it. Converting each cut to a
|
|
95
|
+
* code-unit offset on its own rescans the line from the start every time, which
|
|
96
|
+
* is quadratic in a long enough string.
|
|
97
|
+
*/
|
|
98
|
+
export declare function splitAtCells(line: string, cuts: readonly CellCol[]): string[];
|
|
99
|
+
/**
|
|
100
|
+
* The grapheme clusters of `text`, in order: the unit `string-width` measures,
|
|
101
|
+
* and so the unit `cellLen` of a whole string is the sum of. Summing `cellLen`
|
|
102
|
+
* over code points instead disagrees with it on every glyph built from several:
|
|
103
|
+
* `❤️` is 1 + 0 by code point and 2 as a cluster, `👨👩👧` is 6 and 2, and a cut
|
|
104
|
+
* between two of its code points leaves half a glyph.
|
|
105
|
+
*/
|
|
106
|
+
export declare function graphemes(text: string): string[];
|
|
107
|
+
/**
|
|
108
|
+
* Returns the largest prefix of `text` whose cell width fits within `cap` cells,
|
|
109
|
+
* cut between grapheme clusters. No padding — the returned string may be
|
|
110
|
+
* narrower than `cap` when the next glyph is wide and would overshoot. Never
|
|
111
|
+
* wider than `cap` cells.
|
|
112
|
+
*
|
|
113
|
+
* When the first glyph already exceeds `cap` cells, returns "" (the caller
|
|
114
|
+
* must decide whether to force-take the glyph or skip it).
|
|
115
|
+
*/
|
|
116
|
+
export declare function cellFit(text: string, cap: CellCol): string;
|
|
117
|
+
/** `cellFit` from the other end: the largest suffix of `text` within `cap` cells. */
|
|
118
|
+
export declare function cellFitEnd(text: string, cap: CellCol): string;
|
|
119
|
+
/**
|
|
120
|
+
* Returns the largest code-unit end offset starting from `startCU` whose
|
|
121
|
+
* prefix (from `startCU`) has cell width ≤ `cap`. Iterates from the given
|
|
122
|
+
* offset without slicing the tail, avoiding O(N²) allocation when called
|
|
123
|
+
* repeatedly across a long string.
|
|
124
|
+
*
|
|
125
|
+
* [LAW:types-are-the-program] returns CodePoint because it stops between
|
|
126
|
+
* grapheme clusters, and every cluster boundary is a code-point boundary.
|
|
127
|
+
*/
|
|
128
|
+
export declare function cellFitFrom(text: string, startCU: CodePoint, cap: CellCol): CodePoint;
|
|
129
|
+
/**
|
|
130
|
+
* Like `cellFitFrom`, but for any `startCU` inside `text` the result is
|
|
131
|
+
* strictly past it: a glyph too wide for `cap` is force-taken whole and
|
|
132
|
+
* overflows `cap` by its own width. So a `while (i < text.length)` loop driven
|
|
133
|
+
* by this terminates by construction, and the re-brand is honest — both
|
|
134
|
+
* operands land on code-point boundaries, so their max does too.
|
|
135
|
+
*
|
|
136
|
+
* [LAW:single-enforcer] `cellFit` documents that its caller must choose between
|
|
137
|
+
* force-taking and skipping; this is that choice, made once. It was made twice
|
|
138
|
+
* before and the copies drifted — the textarea's soft wrap force-took,
|
|
139
|
+
* `chopCells` did neither and hung.
|
|
140
|
+
*/
|
|
141
|
+
export declare function cellStepFrom(text: string, startCU: CodePoint, cap: CellCol): CodePoint;
|
|
142
|
+
/**
|
|
143
|
+
* The code-unit offset a visual column falls at: the end of the largest
|
|
144
|
+
* prefix of `content` within `cellCol` cells, so a column inside a wide glyph
|
|
145
|
+
* lands before it. The inverse of `cellLen(content.slice(0, offset))`.
|
|
146
|
+
*/
|
|
147
|
+
export declare function cellColToCodeUnitOffset(content: string, cellCol: CellCol): CodePoint;
|
|
148
|
+
/**
|
|
149
|
+
* The offset just past the grapheme cluster at `cu`: one step of a cursor, a
|
|
150
|
+
* Delete, a transposition, so `👍🏽` or `👨👩👧` moves and goes as the one
|
|
151
|
+
* glyph `cellLen` measures, never a code point at a time. `cu` is a cluster
|
|
152
|
+
* boundary in `s` (see `graphemeBoundary`); `s.length` gives `s.length`.
|
|
153
|
+
*/
|
|
154
|
+
export declare function nextGrapheme(s: string, cu: CodePoint): CodePoint;
|
|
155
|
+
/** `nextGrapheme` backwards: the start of the cluster ending at `cu`; 0 at the start. */
|
|
156
|
+
export declare function prevGrapheme(s: string, cu: CodePoint): CodePoint;
|
|
157
|
+
/**
|
|
158
|
+
* Where an offset into `s` comes to rest as a cursor: itself when it is a
|
|
159
|
+
* cluster boundary, else the end of the cluster it falls inside, and never
|
|
160
|
+
* past `s.length`. The one parse from any number to the boundaries
|
|
161
|
+
* `nextGrapheme` and `prevGrapheme` step between.
|
|
162
|
+
*/
|
|
163
|
+
export declare function graphemeBoundary(s: string, cu: CodeUnit): CodePoint;
|
|
164
|
+
declare const _tabSize: unique symbol;
|
|
165
|
+
/** Cells between tab stops: a positive integer, so every stop is a column. */
|
|
166
|
+
export type TabSize = number & {
|
|
167
|
+
readonly [_tabSize]: true;
|
|
168
|
+
};
|
|
169
|
+
/**
|
|
170
|
+
* `n` as a `TabSize`, or a `RangeError` naming it. Rich divides by the tab
|
|
171
|
+
* size and raises on 0; here the value is refused where it is given, not at
|
|
172
|
+
* the first tab it meets.
|
|
173
|
+
*/
|
|
174
|
+
export declare function parseTabSize(n: number): TabSize;
|
|
175
|
+
/** Text with its tabs expanded, and where each offset into the original went. */
|
|
176
|
+
export interface TabExpansion {
|
|
177
|
+
readonly text: string;
|
|
178
|
+
offsetOf(offset: number): number;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* `text` with each tab widened to the next tab stop — a multiple of `tabSize`
|
|
182
|
+
* cells from the start of its line — as Rich's `Text.expand_tabs` widens it, and
|
|
183
|
+
* `offsetOf`, where each code-unit offset into `text` lands in the result.
|
|
184
|
+
*
|
|
185
|
+
* A tab is a column position, not a run of spaces: one that already sits a
|
|
186
|
+
* cell short of a stop widens to a single space. `offsetOf` is there because a
|
|
187
|
+
* caller that annotates the text by offset — a `RichText`'s spans — has to move
|
|
188
|
+
* its offsets with the characters, or every annotation after a tab lands short
|
|
189
|
+
* of what it styled.
|
|
190
|
+
*/
|
|
191
|
+
export declare function expandTabs(text: string, tabSize: TabSize): TabExpansion;
|
|
192
|
+
export {};
|