@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
|
@@ -0,0 +1,758 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Immutable style descriptors — colors, text attributes, links, metadata.
|
|
3
|
+
*/
|
|
4
|
+
import { COLOR_NAMES, ColorSpec, SURFACE_BLACK, } from "./color.js";
|
|
5
|
+
import { shiftAnchor } from "./anchor.js";
|
|
6
|
+
import { Memo } from "./memo.js";
|
|
7
|
+
// [LAW:one-way-deps] `core/style` depends only on `core/color`. The substrate
|
|
8
|
+
// a translucent colour is flattened over is `SURFACE_BLACK`, defined beside
|
|
9
|
+
// `compositeOver`.
|
|
10
|
+
// --- Attribute definitions ---
|
|
11
|
+
/**
|
|
12
|
+
* Canonical text-attribute inventory. Single source of truth consumed by
|
|
13
|
+
* `Style.parse` / `Style.toString` and the template bindings — adding an
|
|
14
|
+
* attribute here propagates to every styling surface without a second
|
|
15
|
+
* list to keep in sync. [LAW:one-source-of-truth]
|
|
16
|
+
*/
|
|
17
|
+
export const ATTRIBUTE_NAMES = [
|
|
18
|
+
"bold",
|
|
19
|
+
"dim",
|
|
20
|
+
"italic",
|
|
21
|
+
"underline",
|
|
22
|
+
"blink",
|
|
23
|
+
"blink2",
|
|
24
|
+
"reverse",
|
|
25
|
+
"conceal",
|
|
26
|
+
"strike",
|
|
27
|
+
"underline2",
|
|
28
|
+
"frame",
|
|
29
|
+
"encircle",
|
|
30
|
+
"overline",
|
|
31
|
+
];
|
|
32
|
+
// The SGR parameter that turns each attribute on. `ansi.ts` reads it back.
|
|
33
|
+
export const ATTRIBUTE_SGR = {
|
|
34
|
+
bold: 1,
|
|
35
|
+
dim: 2,
|
|
36
|
+
italic: 3,
|
|
37
|
+
underline: 4,
|
|
38
|
+
blink: 5,
|
|
39
|
+
blink2: 6,
|
|
40
|
+
reverse: 7,
|
|
41
|
+
conceal: 8,
|
|
42
|
+
strike: 9,
|
|
43
|
+
underline2: 21,
|
|
44
|
+
frame: 51,
|
|
45
|
+
encircle: 52,
|
|
46
|
+
overline: 53,
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Canonical short-attribute aliases (`b` → `bold`, `i` → `italic`, …).
|
|
50
|
+
* Single source of truth consumed by `Style.parse` and the template
|
|
51
|
+
* bindings — adding an alias here makes it available everywhere.
|
|
52
|
+
* [LAW:one-source-of-truth]
|
|
53
|
+
*/
|
|
54
|
+
export const ATTRIBUTE_SHORT_ALIASES = {
|
|
55
|
+
b: "bold",
|
|
56
|
+
d: "dim",
|
|
57
|
+
i: "italic",
|
|
58
|
+
u: "underline",
|
|
59
|
+
s: "strike",
|
|
60
|
+
r: "reverse",
|
|
61
|
+
o: "overline",
|
|
62
|
+
uu: "underline2",
|
|
63
|
+
};
|
|
64
|
+
export class StyleSyntaxError extends Error {
|
|
65
|
+
constructor(message, options) {
|
|
66
|
+
super(message, options);
|
|
67
|
+
this.name = "StyleSyntaxError";
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// [LAW:one-source-of-truth] The single source for parsed Style instances.
|
|
71
|
+
const styleParseMemo = new Memo();
|
|
72
|
+
// --- Style ---
|
|
73
|
+
export class Style {
|
|
74
|
+
color;
|
|
75
|
+
bgcolor;
|
|
76
|
+
bold;
|
|
77
|
+
dim;
|
|
78
|
+
italic;
|
|
79
|
+
underline;
|
|
80
|
+
blink;
|
|
81
|
+
blink2;
|
|
82
|
+
reverse;
|
|
83
|
+
conceal;
|
|
84
|
+
strike;
|
|
85
|
+
underline2;
|
|
86
|
+
frame;
|
|
87
|
+
encircle;
|
|
88
|
+
overline;
|
|
89
|
+
link;
|
|
90
|
+
meta;
|
|
91
|
+
/**
|
|
92
|
+
* Where this style's cells sat in the output of whatever drew them; see
|
|
93
|
+
* `./anchor.ts`. It draws nothing, and it makes two styles that draw alike
|
|
94
|
+
* unequal, because they came from different places.
|
|
95
|
+
*/
|
|
96
|
+
anchor;
|
|
97
|
+
constructor(options = {}) {
|
|
98
|
+
this.color = resolveColor(options.color);
|
|
99
|
+
this.bgcolor = resolveBackground(options.bgcolor);
|
|
100
|
+
this.bold = options.bold;
|
|
101
|
+
this.dim = options.dim;
|
|
102
|
+
this.italic = options.italic;
|
|
103
|
+
this.underline = options.underline;
|
|
104
|
+
this.blink = options.blink;
|
|
105
|
+
this.blink2 = options.blink2;
|
|
106
|
+
this.reverse = options.reverse;
|
|
107
|
+
this.conceal = options.conceal;
|
|
108
|
+
this.strike = options.strike;
|
|
109
|
+
this.underline2 = options.underline2;
|
|
110
|
+
this.frame = options.frame;
|
|
111
|
+
this.encircle = options.encircle;
|
|
112
|
+
this.overline = options.overline;
|
|
113
|
+
this.link = options.link;
|
|
114
|
+
this.meta = options.meta;
|
|
115
|
+
this.anchor = options.anchor;
|
|
116
|
+
}
|
|
117
|
+
get isNull() {
|
|
118
|
+
return (this.color === undefined &&
|
|
119
|
+
this.bgcolor === undefined &&
|
|
120
|
+
this.bold === undefined &&
|
|
121
|
+
this.dim === undefined &&
|
|
122
|
+
this.italic === undefined &&
|
|
123
|
+
this.underline === undefined &&
|
|
124
|
+
this.blink === undefined &&
|
|
125
|
+
this.blink2 === undefined &&
|
|
126
|
+
this.reverse === undefined &&
|
|
127
|
+
this.conceal === undefined &&
|
|
128
|
+
this.strike === undefined &&
|
|
129
|
+
this.underline2 === undefined &&
|
|
130
|
+
this.frame === undefined &&
|
|
131
|
+
this.encircle === undefined &&
|
|
132
|
+
this.overline === undefined &&
|
|
133
|
+
this.link === undefined &&
|
|
134
|
+
this.meta === undefined &&
|
|
135
|
+
this.anchor === undefined);
|
|
136
|
+
}
|
|
137
|
+
get transparentBackground() {
|
|
138
|
+
return this.bgcolor === undefined || this.bgcolor.isDefault;
|
|
139
|
+
}
|
|
140
|
+
get backgroundStyle() {
|
|
141
|
+
return new Style({ bgcolor: this.bgcolor });
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* This style with `overrides` in place of its own fields.
|
|
145
|
+
*
|
|
146
|
+
* [LAW:one-source-of-truth] The field list is the class's own fields, so a
|
|
147
|
+
* field added to `Style` is carried by every copy without being named here.
|
|
148
|
+
*/
|
|
149
|
+
with(overrides) {
|
|
150
|
+
return new Style({ ...this, ...overrides });
|
|
151
|
+
}
|
|
152
|
+
get withoutColor() {
|
|
153
|
+
return this.with({ color: undefined, bgcolor: undefined });
|
|
154
|
+
}
|
|
155
|
+
// [LAW:types-are-the-program] Structural clone helper — pure rearrangement
|
|
156
|
+
// of fields, no policy. Sanitization of the URL is the trust boundary's
|
|
157
|
+
// job (see RichText in text.ts); Style stays a faithful container so
|
|
158
|
+
// callers that have already sanitized are not silently re-mutated.
|
|
159
|
+
withLink(link) {
|
|
160
|
+
return this.with({ link });
|
|
161
|
+
}
|
|
162
|
+
clearMetaAndLinks() {
|
|
163
|
+
return this.with({ link: undefined, meta: undefined });
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* The same look, drawn from the place `anchor` names, or from nowhere.
|
|
167
|
+
*/
|
|
168
|
+
withAnchor(anchor) {
|
|
169
|
+
return this.with({ anchor });
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* This style on the cell `cells` to the right: its anchor shifted along its
|
|
173
|
+
* row, or the style itself when it has no anchor.
|
|
174
|
+
*/
|
|
175
|
+
shiftedBy(cells) {
|
|
176
|
+
return this.anchor ? this.withAnchor(shiftAnchor(this.anchor, cells)) : this;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Merges two styles. `other`'s values take priority.
|
|
180
|
+
*/
|
|
181
|
+
add(other) {
|
|
182
|
+
if (!other || other.isNull)
|
|
183
|
+
return this;
|
|
184
|
+
if (this.isNull)
|
|
185
|
+
return other;
|
|
186
|
+
return new Style({
|
|
187
|
+
color: other.color ?? this.color,
|
|
188
|
+
bgcolor: other.bgcolor ?? this.bgcolor,
|
|
189
|
+
bold: other.bold ?? this.bold,
|
|
190
|
+
dim: other.dim ?? this.dim,
|
|
191
|
+
italic: other.italic ?? this.italic,
|
|
192
|
+
underline: other.underline ?? this.underline,
|
|
193
|
+
blink: other.blink ?? this.blink,
|
|
194
|
+
blink2: other.blink2 ?? this.blink2,
|
|
195
|
+
reverse: other.reverse ?? this.reverse,
|
|
196
|
+
conceal: other.conceal ?? this.conceal,
|
|
197
|
+
strike: other.strike ?? this.strike,
|
|
198
|
+
underline2: other.underline2 ?? this.underline2,
|
|
199
|
+
frame: other.frame ?? this.frame,
|
|
200
|
+
encircle: other.encircle ?? this.encircle,
|
|
201
|
+
overline: other.overline ?? this.overline,
|
|
202
|
+
link: other.link ?? this.link,
|
|
203
|
+
meta: other.meta && this.meta
|
|
204
|
+
? { ...this.meta, ...other.meta }
|
|
205
|
+
: other.meta ?? this.meta,
|
|
206
|
+
anchor: other.anchor ?? this.anchor,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
equals(other) {
|
|
210
|
+
if (this === other)
|
|
211
|
+
return true;
|
|
212
|
+
return (this.color?.name === other.color?.name &&
|
|
213
|
+
this.bgcolor?.name === other.bgcolor?.name &&
|
|
214
|
+
this.bold === other.bold &&
|
|
215
|
+
this.dim === other.dim &&
|
|
216
|
+
this.italic === other.italic &&
|
|
217
|
+
this.underline === other.underline &&
|
|
218
|
+
this.blink === other.blink &&
|
|
219
|
+
this.blink2 === other.blink2 &&
|
|
220
|
+
this.reverse === other.reverse &&
|
|
221
|
+
this.conceal === other.conceal &&
|
|
222
|
+
this.strike === other.strike &&
|
|
223
|
+
this.underline2 === other.underline2 &&
|
|
224
|
+
this.frame === other.frame &&
|
|
225
|
+
this.encircle === other.encircle &&
|
|
226
|
+
this.overline === other.overline &&
|
|
227
|
+
this.link === other.link &&
|
|
228
|
+
anchorsEqual(this.anchor, other.anchor));
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* The colours this style puts on screen at `colorSystem`: each flattened
|
|
232
|
+
* onto what lies beneath it — the background onto the terminal's black, the
|
|
233
|
+
* foreground onto that background — then downgraded to the depth. The one
|
|
234
|
+
* account of what a style draws: `toSgrCodes` encodes exactly these, and a
|
|
235
|
+
* renderable choosing between two ways of drawing measures them.
|
|
236
|
+
*/
|
|
237
|
+
drawnColors(colorSystem) {
|
|
238
|
+
// [LAW:dataflow-not-control-flow] Always resolve a substrate and flatten
|
|
239
|
+
// alpha before downgrade. Opaque colors short-circuit inside compositeOver,
|
|
240
|
+
// so the same code path runs every render — the alpha value is the data,
|
|
241
|
+
// not a branch.
|
|
242
|
+
const surface = SURFACE_BLACK;
|
|
243
|
+
const bgFlat = this.bgcolor?.flattenAlpha(surface);
|
|
244
|
+
const fgSubstrate = bgFlat?.getTruecolor(undefined, false) ?? surface;
|
|
245
|
+
const fgFlat = this.color?.flattenAlpha(fgSubstrate);
|
|
246
|
+
const at = (c) => colorSystem !== undefined ? c.downgrade(colorSystem) : c;
|
|
247
|
+
return {
|
|
248
|
+
color: fgFlat === undefined ? undefined : at(fgFlat),
|
|
249
|
+
bgcolor: bgFlat === undefined ? undefined : at(bgFlat),
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Returns the SGR parameter list this style emits (e.g. `"1;31;48;2;0;0;255"`),
|
|
254
|
+
* or `""` when the style has no SGR contribution. Excludes OSC 8 link bytes —
|
|
255
|
+
* links are not SGR. The segment encoder (`segmentToString`) wraps it in
|
|
256
|
+
* `\x1b[...m`; styled text reaches the wire only through that encoder.
|
|
257
|
+
*
|
|
258
|
+
* [LAW:one-source-of-truth] One computation of SGR codes.
|
|
259
|
+
*/
|
|
260
|
+
toSgrCodes(colorSystem) {
|
|
261
|
+
if (this.isNull)
|
|
262
|
+
return "";
|
|
263
|
+
// Attributes, then foreground, then background: Python Rich 9d8f9a3's
|
|
264
|
+
// `_make_ansi_codes` order, so a byte pinned against the reference holds.
|
|
265
|
+
// An attribute set false writes nothing, as there. It overrides an
|
|
266
|
+
// inherited attribute when styles combine, and every styled run is written
|
|
267
|
+
// after a reset, so no off code is ever needed.
|
|
268
|
+
const drawn = this.drawnColors(colorSystem);
|
|
269
|
+
return [
|
|
270
|
+
...ATTRIBUTE_NAMES.filter((name) => this[name] === true).map((name) => `${ATTRIBUTE_SGR[name]}`),
|
|
271
|
+
...(drawn.color?.getAnsiCodes(true) ?? []),
|
|
272
|
+
...(drawn.bgcolor?.getAnsiCodes(false) ?? []),
|
|
273
|
+
].join(";");
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Serializes to a canonical string that round-trips through `Style.parse()`.
|
|
277
|
+
*/
|
|
278
|
+
toString() {
|
|
279
|
+
if (this.isNull)
|
|
280
|
+
return "none";
|
|
281
|
+
const parts = [];
|
|
282
|
+
// Negated attributes first
|
|
283
|
+
for (const name of ATTRIBUTE_NAMES) {
|
|
284
|
+
if (this[name] === false)
|
|
285
|
+
parts.push(`not ${name}`);
|
|
286
|
+
}
|
|
287
|
+
// Positive attributes
|
|
288
|
+
for (const name of ATTRIBUTE_NAMES) {
|
|
289
|
+
if (this[name] === true)
|
|
290
|
+
parts.push(name);
|
|
291
|
+
}
|
|
292
|
+
if (this.color)
|
|
293
|
+
parts.push(this.color.name);
|
|
294
|
+
if (this.bgcolor)
|
|
295
|
+
parts.push(`on ${this.bgcolor.name}`);
|
|
296
|
+
if (this.link)
|
|
297
|
+
parts.push(`link ${this.link}`);
|
|
298
|
+
return parts.join(" ") || "none";
|
|
299
|
+
}
|
|
300
|
+
// --- Static methods ---
|
|
301
|
+
static null() {
|
|
302
|
+
return NULL_STYLE;
|
|
303
|
+
}
|
|
304
|
+
static fromColor(color, bgcolor) {
|
|
305
|
+
return new Style({ color, bgcolor });
|
|
306
|
+
}
|
|
307
|
+
static fromMeta(meta) {
|
|
308
|
+
return new Style({ meta });
|
|
309
|
+
}
|
|
310
|
+
static pickFirst(...args) {
|
|
311
|
+
for (const a of args) {
|
|
312
|
+
if (a !== undefined)
|
|
313
|
+
return a;
|
|
314
|
+
}
|
|
315
|
+
throw new Error("All arguments are undefined");
|
|
316
|
+
}
|
|
317
|
+
static combine(styles) {
|
|
318
|
+
let result = NULL_STYLE;
|
|
319
|
+
for (const s of styles) {
|
|
320
|
+
if (s)
|
|
321
|
+
result = result.add(s);
|
|
322
|
+
}
|
|
323
|
+
return result;
|
|
324
|
+
}
|
|
325
|
+
static chain(...styles) {
|
|
326
|
+
return Style.combine(styles);
|
|
327
|
+
}
|
|
328
|
+
static normalize(definition) {
|
|
329
|
+
return definition.trim().replace(/\s+/g, " ");
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Parse a space-separated style definition. Memoized (`Memo`).
|
|
333
|
+
*
|
|
334
|
+
* A definition only: `"bold red"` parses, `"repr.number"` does not. Names
|
|
335
|
+
* belong to a `Theme`, and `Theme.resolve` is where one is looked up.
|
|
336
|
+
*/
|
|
337
|
+
static parse(definition) {
|
|
338
|
+
const normalized = Style.normalize(definition);
|
|
339
|
+
if (normalized === "" || normalized === "none")
|
|
340
|
+
return NULL_STYLE;
|
|
341
|
+
return styleParseMemo.get(normalized, parseStyleDefinition);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
export const NULL_STYLE = new Style();
|
|
345
|
+
// --- StyleStack ---
|
|
346
|
+
export class StyleStack {
|
|
347
|
+
stack;
|
|
348
|
+
constructor(base = NULL_STYLE) {
|
|
349
|
+
this.stack = [base];
|
|
350
|
+
}
|
|
351
|
+
get current() {
|
|
352
|
+
return this.stack[this.stack.length - 1];
|
|
353
|
+
}
|
|
354
|
+
push(style) {
|
|
355
|
+
this.stack.push(this.current.add(style));
|
|
356
|
+
}
|
|
357
|
+
pop() {
|
|
358
|
+
if (this.stack.length <= 1) {
|
|
359
|
+
throw new Error("Cannot pop the base style from StyleStack");
|
|
360
|
+
}
|
|
361
|
+
return this.stack.pop();
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
// --- Theme ---
|
|
365
|
+
const STYLE_NAME_RE = /^[a-z][a-z0-9._-]*$/;
|
|
366
|
+
/**
|
|
367
|
+
* `over` added to `base`, the outer style winning as `Style.add` has it. A
|
|
368
|
+
* `Style` base takes the addition now, and so does `""`, the definition that
|
|
369
|
+
* adds nothing; any other string keeps it as a `LayeredStyle` for the render
|
|
370
|
+
* that resolves the string.
|
|
371
|
+
*/
|
|
372
|
+
export function layerStyle(base, over) {
|
|
373
|
+
if (base instanceof Style)
|
|
374
|
+
return base.add(over);
|
|
375
|
+
if (base === "")
|
|
376
|
+
return over;
|
|
377
|
+
if (typeof base === "string")
|
|
378
|
+
return { under: base, over };
|
|
379
|
+
return { under: base.under, over: base.over.add(over) };
|
|
380
|
+
}
|
|
381
|
+
export class Theme {
|
|
382
|
+
styles;
|
|
383
|
+
constructor(definitions = {}, options) {
|
|
384
|
+
this.styles = new Map();
|
|
385
|
+
const inherit = options?.inherit !== false;
|
|
386
|
+
if (inherit) {
|
|
387
|
+
for (const [name, style] of Object.entries(DEFAULT_STYLES)) {
|
|
388
|
+
this.styles.set(name, style);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
for (const [name, def] of Object.entries(definitions)) {
|
|
392
|
+
if (!STYLE_NAME_RE.test(name)) {
|
|
393
|
+
throw new Error(`Invalid style name: "${name}" (must be lowercase, start with letter, contain only letters, digits, ".", "-", "_")`);
|
|
394
|
+
}
|
|
395
|
+
this.styles.set(name, Style.parse(def));
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
get(name) {
|
|
399
|
+
return this.styles.get(name);
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* The style a `TextStyle` stands for under this theme: a name this theme
|
|
403
|
+
* defines, otherwise a definition for `Style.parse`, which throws
|
|
404
|
+
* `StyleSyntaxError` when the string is neither. A `LayeredStyle` is its
|
|
405
|
+
* `under` resolved here with its `over` added on top.
|
|
406
|
+
*
|
|
407
|
+
* [LAW:one-source-of-truth] The theme is the one map from names to styles.
|
|
408
|
+
* The lookup stays outside `Style.parse`'s process-wide cache on purpose:
|
|
409
|
+
* cached there, the first console to resolve `repr.number` would decide it
|
|
410
|
+
* for every console after it, whatever theme each was given.
|
|
411
|
+
*/
|
|
412
|
+
resolve(style) {
|
|
413
|
+
if (style instanceof Style)
|
|
414
|
+
return style;
|
|
415
|
+
if (typeof style !== "string")
|
|
416
|
+
return this.resolve(style.under).add(style.over);
|
|
417
|
+
return this.styles.get(style) ?? Style.parse(style);
|
|
418
|
+
}
|
|
419
|
+
has(name) {
|
|
420
|
+
return this.styles.has(name);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
// --- Parse helpers ---
|
|
424
|
+
const ATTRIBUTE_SET = new Set(ATTRIBUTE_NAMES);
|
|
425
|
+
// The words each position of a definition can hold: a bare token is a keyword,
|
|
426
|
+
// an attribute or a colour name; `on` takes a colour name; `not` an attribute.
|
|
427
|
+
// The short aliases are left out, since `b` is no help to someone who typed
|
|
428
|
+
// `bolt` and a one-letter name sits one edit from every other short word.
|
|
429
|
+
// [LAW:one-source-of-truth] Derived from the lists the parser accepts from; the
|
|
430
|
+
// keywords are the three `parseStyleDefinition` reads before anything else.
|
|
431
|
+
const FOREGROUND_WORDS = ["not", "on", "link", ...ATTRIBUTE_NAMES, ...COLOR_NAMES];
|
|
432
|
+
/**
|
|
433
|
+
* Optimal string alignment distance: insertions, deletions, substitutions, and
|
|
434
|
+
* swaps of two neighbouring letters each cost one edit, so `cyna` is as near
|
|
435
|
+
* `cyan` as `rd` is to `red`. Kept to three rows, since only the two before the
|
|
436
|
+
* current one are ever read.
|
|
437
|
+
*/
|
|
438
|
+
function editDistance(a, b) {
|
|
439
|
+
let before = [];
|
|
440
|
+
let previous = Array.from({ length: b.length + 1 }, (_, j) => j);
|
|
441
|
+
for (let i = 1; i <= a.length; i++) {
|
|
442
|
+
const current = [i];
|
|
443
|
+
for (let j = 1; j <= b.length; j++) {
|
|
444
|
+
const swap = i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1];
|
|
445
|
+
current[j] = Math.min(previous[j] + 1, current[j - 1] + 1, previous[j - 1] + Number(a[i - 1] !== b[j - 1]), swap ? before[j - 2] + 1 : Infinity);
|
|
446
|
+
}
|
|
447
|
+
[before, previous] = [previous, current];
|
|
448
|
+
}
|
|
449
|
+
return previous[b.length];
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* The ` (did you mean …?)` clause for a word no position accepted, or `""`
|
|
453
|
+
* when nothing in `words` is a plausible typo of it.
|
|
454
|
+
*
|
|
455
|
+
* Plausible means within one edit per three letters, at least one, which lets
|
|
456
|
+
* `rd` reach `red` and keeps `hello` from reaching `yellow`. Every name tied
|
|
457
|
+
* for nearest is offered: `gold` is one edit from `bold` and from three
|
|
458
|
+
* `goldN` colours, and choosing among them would be a guess the reader cannot
|
|
459
|
+
* tell from a finding. Case is not an edit, because the colour parser ignores
|
|
460
|
+
* it: `Cyna` is as near `cyan` as `cyna` is.
|
|
461
|
+
*
|
|
462
|
+
* This runs on every render that meets the bad style, since only successful
|
|
463
|
+
* parses are cached. Two words differ by at least their difference in length,
|
|
464
|
+
* so a name outside the budget on length alone is never measured — which is
|
|
465
|
+
* also what keeps a long garbage token from costing length × length per name.
|
|
466
|
+
*/
|
|
467
|
+
function nearMiss(word, words) {
|
|
468
|
+
const typed = word.toLowerCase();
|
|
469
|
+
const budget = Math.max(1, Math.floor(typed.length / 3));
|
|
470
|
+
const scored = words
|
|
471
|
+
.filter((name) => Math.abs(name.length - typed.length) <= budget)
|
|
472
|
+
.map((name) => ({ name, distance: editDistance(typed, name) }));
|
|
473
|
+
const nearest = Math.min(budget, ...scored.map((s) => s.distance));
|
|
474
|
+
const names = scored
|
|
475
|
+
.filter((s) => s.distance === nearest)
|
|
476
|
+
.map((s) => `"${s.name}"`)
|
|
477
|
+
.sort();
|
|
478
|
+
return names.length === 0 ? "" : ` (did you mean ${names.join(" or ")}?)`;
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* A style token read as a colour. The colour parser's own error is the reason
|
|
482
|
+
* the token failed, so it rides along twice: in the message, for a reader with
|
|
483
|
+
* only the text, and as `cause`, for code that wants the original error.
|
|
484
|
+
*
|
|
485
|
+
* [LAW:single-enforcer] Both colour positions in a definition rewrap here, and
|
|
486
|
+
* the near miss is named here rather than by the colour parser: only a
|
|
487
|
+
* definition knows whether the token could also have been an attribute.
|
|
488
|
+
*/
|
|
489
|
+
function parseStyleColor(token, failure, words) {
|
|
490
|
+
try {
|
|
491
|
+
return ColorSpec.parse(token);
|
|
492
|
+
}
|
|
493
|
+
catch (cause) {
|
|
494
|
+
throw new StyleSyntaxError(`${failure} "${token}"${nearMiss(token, words)}: ${String(cause)}`, {
|
|
495
|
+
cause,
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
function parseStyleDefinition(definition) {
|
|
500
|
+
const tokens = definition.split(/\s+/);
|
|
501
|
+
const opts = {};
|
|
502
|
+
let i = 0;
|
|
503
|
+
while (i < tokens.length) {
|
|
504
|
+
const token = tokens[i];
|
|
505
|
+
// "not <attr>"
|
|
506
|
+
if (token === "not") {
|
|
507
|
+
i++;
|
|
508
|
+
const next = tokens[i];
|
|
509
|
+
if (!next) {
|
|
510
|
+
throw new StyleSyntaxError(`Expected attribute after "not" in style definition`);
|
|
511
|
+
}
|
|
512
|
+
const attrName = ATTRIBUTE_SHORT_ALIASES[next] ?? next;
|
|
513
|
+
if (!ATTRIBUTE_SET.has(attrName)) {
|
|
514
|
+
throw new StyleSyntaxError(`Invalid attribute: "${next}"${nearMiss(next, ATTRIBUTE_NAMES)}`);
|
|
515
|
+
}
|
|
516
|
+
opts[attrName] = false;
|
|
517
|
+
i++;
|
|
518
|
+
continue;
|
|
519
|
+
}
|
|
520
|
+
// "on <color>"
|
|
521
|
+
if (token === "on") {
|
|
522
|
+
i++;
|
|
523
|
+
const next = tokens[i];
|
|
524
|
+
if (!next) {
|
|
525
|
+
throw new StyleSyntaxError(`Expected color after "on" in style definition`);
|
|
526
|
+
}
|
|
527
|
+
opts.bgcolor = parseStyleColor(next, "Invalid background color", COLOR_NAMES);
|
|
528
|
+
i++;
|
|
529
|
+
continue;
|
|
530
|
+
}
|
|
531
|
+
// "link <url>"
|
|
532
|
+
if (token === "link") {
|
|
533
|
+
i++;
|
|
534
|
+
const url = tokens[i];
|
|
535
|
+
if (url) {
|
|
536
|
+
opts.link = url;
|
|
537
|
+
}
|
|
538
|
+
i++;
|
|
539
|
+
continue;
|
|
540
|
+
}
|
|
541
|
+
// Attribute (full name)
|
|
542
|
+
const resolvedAttr = ATTRIBUTE_SHORT_ALIASES[token] ?? token;
|
|
543
|
+
if (ATTRIBUTE_SET.has(resolvedAttr)) {
|
|
544
|
+
opts[resolvedAttr] = true;
|
|
545
|
+
i++;
|
|
546
|
+
continue;
|
|
547
|
+
}
|
|
548
|
+
// Must be a color
|
|
549
|
+
opts.color = parseStyleColor(token, "Invalid style definition", FOREGROUND_WORDS);
|
|
550
|
+
i++;
|
|
551
|
+
}
|
|
552
|
+
return new Style(opts);
|
|
553
|
+
}
|
|
554
|
+
function resolveColor(c) {
|
|
555
|
+
if (c === undefined)
|
|
556
|
+
return undefined;
|
|
557
|
+
if (c instanceof ColorSpec)
|
|
558
|
+
return c;
|
|
559
|
+
return ColorSpec.parse(c);
|
|
560
|
+
}
|
|
561
|
+
// A fully transparent background draws nothing over whatever lies beneath it,
|
|
562
|
+
// so it is no background: a style added on top of another keeps that one's,
|
|
563
|
+
// which is what Textual's `#00000000` means. A transparent foreground is not
|
|
564
|
+
// the same, it draws its glyph in whatever lies beneath it — the background,
|
|
565
|
+
// or `SURFACE_BLACK` when there is none — so it stays a colour.
|
|
566
|
+
function resolveBackground(c) {
|
|
567
|
+
const spec = resolveColor(c);
|
|
568
|
+
return spec?.value?.alpha === 0 ? undefined : spec;
|
|
569
|
+
}
|
|
570
|
+
// --- DEFAULT_STYLES ---
|
|
571
|
+
// [LAW:one-source-of-truth] Single canonical mapping of semantic names to styles
|
|
572
|
+
export const DEFAULT_STYLES = {
|
|
573
|
+
none: NULL_STYLE,
|
|
574
|
+
reset: new Style({
|
|
575
|
+
color: ColorSpec.default(),
|
|
576
|
+
bgcolor: ColorSpec.default(),
|
|
577
|
+
bold: false,
|
|
578
|
+
dim: false,
|
|
579
|
+
italic: false,
|
|
580
|
+
underline: false,
|
|
581
|
+
blink: false,
|
|
582
|
+
blink2: false,
|
|
583
|
+
reverse: false,
|
|
584
|
+
conceal: false,
|
|
585
|
+
strike: false,
|
|
586
|
+
underline2: false,
|
|
587
|
+
frame: false,
|
|
588
|
+
encircle: false,
|
|
589
|
+
overline: false,
|
|
590
|
+
}),
|
|
591
|
+
bold: new Style({ bold: true }),
|
|
592
|
+
dim: new Style({ dim: true }),
|
|
593
|
+
italic: new Style({ italic: true }),
|
|
594
|
+
underline: new Style({ underline: true }),
|
|
595
|
+
blink: new Style({ blink: true }),
|
|
596
|
+
blink2: new Style({ blink2: true }),
|
|
597
|
+
reverse: new Style({ reverse: true }),
|
|
598
|
+
conceal: new Style({ conceal: true }),
|
|
599
|
+
strike: new Style({ strike: true }),
|
|
600
|
+
underline2: new Style({ underline2: true }),
|
|
601
|
+
frame: new Style({ frame: true }),
|
|
602
|
+
encircle: new Style({ encircle: true }),
|
|
603
|
+
overline: new Style({ overline: true }),
|
|
604
|
+
// Table
|
|
605
|
+
"table.header": new Style({ bold: true }),
|
|
606
|
+
"table.footer": new Style({ bold: true }),
|
|
607
|
+
"table.cell": NULL_STYLE,
|
|
608
|
+
"table.title": new Style({ italic: true }),
|
|
609
|
+
"table.caption": new Style({ italic: true, dim: true }),
|
|
610
|
+
// Repr/highlighting — Rich 15.0.0's `rich.default_styles`, in its order
|
|
611
|
+
"repr.ellipsis": Style.parse("yellow"),
|
|
612
|
+
"repr.indent": Style.parse("dim green"),
|
|
613
|
+
"repr.error": Style.parse("bold red"),
|
|
614
|
+
"repr.str": Style.parse("not bold not italic green"),
|
|
615
|
+
"repr.brace": Style.parse("bold"),
|
|
616
|
+
"repr.comma": Style.parse("bold"),
|
|
617
|
+
"repr.ipv4": Style.parse("bold bright_green"),
|
|
618
|
+
"repr.ipv6": Style.parse("bold bright_green"),
|
|
619
|
+
"repr.eui48": Style.parse("bold bright_green"),
|
|
620
|
+
"repr.eui64": Style.parse("bold bright_green"),
|
|
621
|
+
"repr.tag_start": Style.parse("bold"),
|
|
622
|
+
"repr.tag_name": Style.parse("bold bright_magenta"),
|
|
623
|
+
"repr.tag_contents": Style.parse("default"),
|
|
624
|
+
"repr.tag_end": Style.parse("bold"),
|
|
625
|
+
"repr.attrib_name": Style.parse("not italic yellow"),
|
|
626
|
+
"repr.attrib_equal": Style.parse("bold"),
|
|
627
|
+
"repr.attrib_value": Style.parse("not italic magenta"),
|
|
628
|
+
"repr.number": Style.parse("bold not italic cyan"),
|
|
629
|
+
"repr.number_complex": Style.parse("bold not italic cyan"),
|
|
630
|
+
"repr.bool_true": Style.parse("italic bright_green"),
|
|
631
|
+
"repr.bool_false": Style.parse("italic bright_red"),
|
|
632
|
+
"repr.none": Style.parse("italic magenta"),
|
|
633
|
+
"repr.url": Style.parse("not bold not italic underline bright_blue"),
|
|
634
|
+
"repr.uuid": Style.parse("not bold bright_yellow"),
|
|
635
|
+
"repr.call": Style.parse("bold magenta"),
|
|
636
|
+
"repr.path": Style.parse("magenta"),
|
|
637
|
+
"repr.filename": Style.parse("bright_magenta"),
|
|
638
|
+
// Log
|
|
639
|
+
"log.time": Style.parse("cyan dim"),
|
|
640
|
+
"log.message": NULL_STYLE,
|
|
641
|
+
"log.path": Style.parse("dim"),
|
|
642
|
+
"log.line_no": Style.parse("cyan"),
|
|
643
|
+
"log.level": NULL_STYLE,
|
|
644
|
+
// Rule
|
|
645
|
+
"rule.line": Style.parse("green"),
|
|
646
|
+
"rule.text": Style.parse("bold"),
|
|
647
|
+
// JSON
|
|
648
|
+
"json.brace": Style.parse("bold"),
|
|
649
|
+
"json.bool_true": Style.parse("italic bright_green"),
|
|
650
|
+
"json.bool_false": Style.parse("italic bright_red"),
|
|
651
|
+
"json.key": Style.parse("bold blue"),
|
|
652
|
+
"json.null": Style.parse("italic magenta"),
|
|
653
|
+
"json.number": Style.parse("bold not italic cyan"),
|
|
654
|
+
"json.str": Style.parse("not bold not italic green"),
|
|
655
|
+
// Syntax
|
|
656
|
+
"syntax.keyword": Style.parse("bold magenta"),
|
|
657
|
+
"syntax.constant": Style.parse("italic bright_magenta"),
|
|
658
|
+
"syntax.string": Style.parse("green"),
|
|
659
|
+
"syntax.number": Style.parse("cyan"),
|
|
660
|
+
"syntax.comment": Style.parse("dim italic"),
|
|
661
|
+
"syntax.line_number": Style.parse("dim"),
|
|
662
|
+
// Ink and ground both from the fixed 256-colour greys: the terminal theme's
|
|
663
|
+
// own foreground is dark on a light theme and would vanish on grey27. At 16
|
|
664
|
+
// colours `Syntax` draws it without the pair (`groundedStyle`).
|
|
665
|
+
"syntax.line_number.highlight": Style.parse("bold grey93 on grey27"),
|
|
666
|
+
// Markdown
|
|
667
|
+
"markdown.h1": Style.parse("bold underline"),
|
|
668
|
+
"markdown.h2": Style.parse("bold"),
|
|
669
|
+
"markdown.h3": Style.parse("bold dim"),
|
|
670
|
+
"markdown.h4": Style.parse("bold dim italic"),
|
|
671
|
+
// A fixed cyan, not the theme's: `cyan` is dark enough on some themes to
|
|
672
|
+
// sink into grey11. Bold, as Rich's is: at 16 colours a renderable draws it
|
|
673
|
+
// without its pair (`groundedStyle`), and bold is what still marks code.
|
|
674
|
+
"markdown.code": Style.parse("bold dark_turquoise on grey11"),
|
|
675
|
+
"markdown.hr": Style.parse("yellow"),
|
|
676
|
+
"markdown.link": Style.parse("bright_blue"),
|
|
677
|
+
"markdown.link_url": Style.parse("blue"),
|
|
678
|
+
// Progress
|
|
679
|
+
"progress.description": NULL_STYLE,
|
|
680
|
+
"progress.percentage": Style.parse("cyan"),
|
|
681
|
+
"progress.remaining": Style.parse("cyan"),
|
|
682
|
+
"progress.elapsed": Style.parse("cyan"),
|
|
683
|
+
"progress.spinner": Style.parse("green"),
|
|
684
|
+
"progress.download": Style.parse("green"),
|
|
685
|
+
"progress.filesize": Style.parse("green"),
|
|
686
|
+
"progress.filesize.total": Style.parse("green"),
|
|
687
|
+
"progress.data.speed": Style.parse("red"),
|
|
688
|
+
// Bar
|
|
689
|
+
"bar.back": Style.parse("grey23"),
|
|
690
|
+
"bar.complete": Style.parse("magenta"),
|
|
691
|
+
"bar.finished": Style.parse("green"),
|
|
692
|
+
"bar.pulse": Style.parse("magenta"),
|
|
693
|
+
// Scrollbar
|
|
694
|
+
"scrollbar.thumb": NULL_STYLE,
|
|
695
|
+
"scrollbar.track": Style.parse("grey37"),
|
|
696
|
+
// Tree
|
|
697
|
+
"tree": NULL_STYLE,
|
|
698
|
+
"tree.guide": NULL_STYLE,
|
|
699
|
+
// Status
|
|
700
|
+
"status.spinner": Style.parse("green"),
|
|
701
|
+
"status.message": NULL_STYLE,
|
|
702
|
+
// Prompt
|
|
703
|
+
"prompt": NULL_STYLE,
|
|
704
|
+
"prompt.choices": Style.parse("bold magenta"),
|
|
705
|
+
"prompt.default": Style.parse("bold cyan"),
|
|
706
|
+
"prompt.invalid": Style.parse("red"),
|
|
707
|
+
"prompt.invalid.choice": Style.parse("red"),
|
|
708
|
+
// Inspect
|
|
709
|
+
"inspect.attr": Style.parse("yellow italic"),
|
|
710
|
+
"inspect.attr.dunder": Style.parse("yellow italic dim"),
|
|
711
|
+
"inspect.callable": Style.parse("bold magenta"),
|
|
712
|
+
"inspect.error": Style.parse("bold red"),
|
|
713
|
+
"inspect.help": Style.parse("cyan"),
|
|
714
|
+
"inspect.doc": Style.parse("dim"),
|
|
715
|
+
"inspect.value.border": Style.parse("green"),
|
|
716
|
+
// Traceback
|
|
717
|
+
"traceback.border": Style.parse("red"),
|
|
718
|
+
"traceback.text": Style.parse("red"),
|
|
719
|
+
"traceback.title": Style.parse("bold red"),
|
|
720
|
+
"traceback.exc_type": Style.parse("bold bright_red"),
|
|
721
|
+
"traceback.exc_value": NULL_STYLE,
|
|
722
|
+
"traceback.offset": Style.parse("bold bright_red"),
|
|
723
|
+
// Scope
|
|
724
|
+
"scope.border": Style.parse("blue"),
|
|
725
|
+
"scope.key": Style.parse("italic"),
|
|
726
|
+
"scope.key.special": Style.parse("dim italic"),
|
|
727
|
+
// Pretty
|
|
728
|
+
"pretty": NULL_STYLE,
|
|
729
|
+
// ISO8601
|
|
730
|
+
"iso8601.date": Style.parse("blue"),
|
|
731
|
+
"iso8601.time": Style.parse("magenta"),
|
|
732
|
+
"iso8601.timezone": Style.parse("yellow"),
|
|
733
|
+
// The parts ISO8601Highlighter lays inside a date or time. Rich's theme names
|
|
734
|
+
// none of them, so they draw nothing; they are here so a theme can set them
|
|
735
|
+
// and so none reaches `onStyleError` as an unknown name.
|
|
736
|
+
"iso8601.year": NULL_STYLE,
|
|
737
|
+
"iso8601.month": NULL_STYLE,
|
|
738
|
+
"iso8601.day": NULL_STYLE,
|
|
739
|
+
"iso8601.week": NULL_STYLE,
|
|
740
|
+
"iso8601.hour": NULL_STYLE,
|
|
741
|
+
"iso8601.minute": NULL_STYLE,
|
|
742
|
+
"iso8601.second": NULL_STYLE,
|
|
743
|
+
"iso8601.frac": NULL_STYLE,
|
|
744
|
+
"iso8601.ms": NULL_STYLE,
|
|
745
|
+
"iso8601.hyphen": NULL_STYLE,
|
|
746
|
+
};
|
|
747
|
+
/**
|
|
748
|
+
* The theme a render resolves names against when nothing supplied one — what
|
|
749
|
+
* a renderable sees outside a `Console`, as in `renderToString`.
|
|
750
|
+
*/
|
|
751
|
+
export const DEFAULT_THEME = new Theme();
|
|
752
|
+
function anchorsEqual(a, b) {
|
|
753
|
+
if (a === b)
|
|
754
|
+
return true;
|
|
755
|
+
if (!a || !b)
|
|
756
|
+
return false;
|
|
757
|
+
return a.owner === b.owner && a.row === b.row && a.col === b.col && anchorsEqual(a.inner, b.inner);
|
|
758
|
+
}
|