@promptctl/rich-js 0.18.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/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 +143 -0
- package/dist/core/box.js +379 -0
- package/dist/core/cells.d.ts +159 -0
- package/dist/core/cells.js +287 -0
- package/dist/core/color.d.ts +246 -0
- package/dist/core/color.js +1038 -0
- package/dist/core/console.d.ts +165 -0
- package/dist/core/console.js +527 -0
- package/dist/core/emoji.d.ts +24 -0
- package/dist/core/emoji.js +391 -0
- package/dist/core/export-html.d.ts +59 -0
- package/dist/core/export-html.js +200 -0
- package/dist/core/export-lines.d.ts +121 -0
- package/dist/core/export-lines.js +141 -0
- package/dist/core/highlighter.d.ts +33 -0
- package/dist/core/highlighter.js +124 -0
- package/dist/core/json.d.ts +27 -0
- package/dist/core/json.js +53 -0
- package/dist/core/markup.d.ts +119 -0
- package/dist/core/markup.js +731 -0
- package/dist/core/measure.d.ts +27 -0
- package/dist/core/measure.js +62 -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 +90 -0
- package/dist/core/place.d.ts +30 -0
- package/dist/core/place.js +51 -0
- package/dist/core/pretty.d.ts +144 -0
- package/dist/core/pretty.js +476 -0
- package/dist/core/protocol.d.ts +267 -0
- package/dist/core/protocol.js +163 -0
- package/dist/core/render.d.ts +84 -0
- package/dist/core/render.js +145 -0
- package/dist/core/segment.d.ts +161 -0
- package/dist/core/segment.js +492 -0
- package/dist/core/spinnerData.d.ts +12 -0
- package/dist/core/spinnerData.js +117 -0
- package/dist/core/strip.d.ts +141 -0
- package/dist/core/strip.js +305 -0
- package/dist/core/style.d.ts +169 -0
- package/dist/core/style.js +695 -0
- package/dist/core/subscription.d.ts +12 -0
- package/dist/core/subscription.js +12 -0
- package/dist/core/text.d.ts +256 -0
- package/dist/core/text.js +976 -0
- package/dist/core/wrap.d.ts +41 -0
- package/dist/core/wrap.js +127 -0
- 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 +5 -0
- package/dist/host/index.js +3 -0
- package/dist/host/terminal-host.d.ts +179 -0
- package/dist/host/terminal-host.js +186 -0
- package/dist/index.d.ts +91 -0
- package/dist/index.js +107 -0
- package/dist/node/prompt.d.ts +21 -0
- package/dist/node/prompt.js +30 -0
- package/dist/node/save.d.ts +17 -0
- package/dist/node/save.js +21 -0
- package/dist/node/terminal-host.d.ts +113 -0
- package/dist/node/terminal-host.js +227 -0
- package/dist/node/traceback.d.ts +37 -0
- package/dist/node/traceback.js +134 -0
- package/dist/renderables/align.d.ts +16 -0
- package/dist/renderables/align.js +33 -0
- package/dist/renderables/columns.d.ts +61 -0
- package/dist/renderables/columns.js +152 -0
- package/dist/renderables/constrain.d.ts +15 -0
- package/dist/renderables/constrain.js +37 -0
- package/dist/renderables/embed.d.ts +50 -0
- package/dist/renderables/embed.js +71 -0
- package/dist/renderables/flexStrip.d.ts +41 -0
- package/dist/renderables/flexStrip.js +200 -0
- package/dist/renderables/group.d.ts +11 -0
- package/dist/renderables/group.js +17 -0
- package/dist/renderables/layout.d.ts +92 -0
- package/dist/renderables/layout.js +312 -0
- package/dist/renderables/live.d.ts +50 -0
- package/dist/renderables/live.js +175 -0
- package/dist/renderables/markdown.d.ts +24 -0
- package/dist/renderables/markdown.js +184 -0
- package/dist/renderables/padding.d.ts +38 -0
- package/dist/renderables/padding.js +141 -0
- package/dist/renderables/panel.d.ts +116 -0
- package/dist/renderables/panel.js +307 -0
- package/dist/renderables/progress.d.ts +90 -0
- package/dist/renderables/progress.js +238 -0
- package/dist/renderables/progressBar.d.ts +31 -0
- package/dist/renderables/progressBar.js +53 -0
- package/dist/renderables/prompt.d.ts +49 -0
- package/dist/renderables/prompt.js +125 -0
- package/dist/renderables/rule.d.ts +25 -0
- package/dist/renderables/rule.js +90 -0
- package/dist/renderables/spinner.d.ts +31 -0
- package/dist/renderables/spinner.js +70 -0
- package/dist/renderables/status.d.ts +23 -0
- package/dist/renderables/status.js +60 -0
- package/dist/renderables/syntax.d.ts +35 -0
- package/dist/renderables/syntax.js +115 -0
- package/dist/renderables/table.d.ts +194 -0
- package/dist/renderables/table.js +795 -0
- package/dist/renderables/traceback.d.ts +31 -0
- package/dist/renderables/traceback.js +108 -0
- package/dist/renderables/tree.d.ts +68 -0
- package/dist/renderables/tree.js +150 -0
- package/dist/renderables/viewport.d.ts +114 -0
- package/dist/renderables/viewport.js +198 -0
- package/dist/template-bindings/color-funcs.d.ts +87 -0
- package/dist/template-bindings/color-funcs.js +217 -0
- package/dist/template-bindings/helpers.d.ts +24 -0
- package/dist/template-bindings/helpers.js +48 -0
- package/dist/template-bindings/index.d.ts +107 -0
- package/dist/template-bindings/index.js +146 -0
- package/dist/template-bindings/palette-funcs.d.ts +94 -0
- package/dist/template-bindings/palette-funcs.js +141 -0
- package/dist/template-bindings/style-funcs.d.ts +28 -0
- package/dist/template-bindings/style-funcs.js +155 -0
- package/dist/themes/buildPalette.d.ts +36 -0
- package/dist/themes/buildPalette.js +56 -0
- package/dist/themes/colorMath.d.ts +82 -0
- package/dist/themes/colorMath.js +254 -0
- package/dist/themes/colorRef.d.ts +51 -0
- package/dist/themes/colorRef.js +96 -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 +21 -0
- package/dist/themes/palette.js +28 -0
- package/dist/themes/ramp.d.ts +83 -0
- package/dist/themes/ramp.js +122 -0
- package/dist/themes/registry.d.ts +44 -0
- package/dist/themes/registry.js +94 -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 +49 -0
- package/dist/widgets/button.js +208 -0
- package/dist/widgets/checkbox.d.ts +41 -0
- package/dist/widgets/checkbox.js +157 -0
- package/dist/widgets/dropdown.d.ts +67 -0
- package/dist/widgets/dropdown.js +450 -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/slider.d.ts +57 -0
- package/dist/widgets/slider.js +270 -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 +274 -0
- package/dist/widgets/text-input.js +1165 -0
- package/dist/widgets/toggle.d.ts +44 -0
- package/dist/widgets/toggle.js +180 -0
- package/dist/widgets/types.d.ts +87 -0
- package/dist/widgets/types.js +30 -0
- package/dist/widgets/widget-app.d.ts +63 -0
- package/dist/widgets/widget-app.js +199 -0
- package/dist/widgets/widget-base.d.ts +40 -0
- package/dist/widgets/widget-base.js +165 -0
- package/package.json +6 -2
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in spinner frame data.
|
|
3
|
+
* [LAW:one-type-per-behavior] All spinners are instances of SpinnerData — differ only by frame data.
|
|
4
|
+
*/
|
|
5
|
+
/** The spinner an ASCII-only output draws in place of any other. */
|
|
6
|
+
export const LINE_SPINNER = { frames: ["-", "\\", "|", "/"], interval: 130 };
|
|
7
|
+
// [LAW:one-source-of-truth] Single authoritative collection of spinner definitions
|
|
8
|
+
export const SPINNERS = {
|
|
9
|
+
dots: { frames: ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"], interval: 80 },
|
|
10
|
+
dots2: { frames: ["⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷"], interval: 80 },
|
|
11
|
+
dots3: { frames: ["⠋", "⠙", "⠚", "⠞", "⠖", "⠦", "⠴", "⠲", "⠳", "⠓"], interval: 80 },
|
|
12
|
+
line: LINE_SPINNER,
|
|
13
|
+
line2: { frames: ["⠂", "-", "–", "—", "–", "-"], interval: 100 },
|
|
14
|
+
pipe: { frames: ["┤", "┘", "┴", "└", "├", "┌", "┬", "┐"], interval: 100 },
|
|
15
|
+
simpleDots: { frames: [". ", ".. ", "...", " "], interval: 400 },
|
|
16
|
+
simpleDotsScrolling: { frames: [". ", ".. ", "...", " ..", " .", " "], interval: 200 },
|
|
17
|
+
star: { frames: ["✶", "✸", "✹", "✺", "✹", "✷"], interval: 70 },
|
|
18
|
+
star2: { frames: ["+", "x", "*"], interval: 80 },
|
|
19
|
+
flip: { frames: ["_", "_", "_", "-", "`", "`", "'", "´", "-", "_", "_", "_"], interval: 70 },
|
|
20
|
+
hamburger: { frames: ["☱", "☲", "☴"], interval: 100 },
|
|
21
|
+
growVertical: { frames: ["▁", "▃", "▄", "▅", "▆", "▇", "▆", "▅", "▄", "▃"], interval: 120 },
|
|
22
|
+
growHorizontal: { frames: ["▏", "▎", "▍", "▌", "▋", "▊", "▉", "▊", "▋", "▌", "▍", "▎"], interval: 120 },
|
|
23
|
+
balloon: { frames: [" ", ".", "o", "O", "@", "*", " "], interval: 140 },
|
|
24
|
+
balloon2: { frames: [".", "o", "O", "°", "O", "o", "."], interval: 120 },
|
|
25
|
+
noise: { frames: ["▓", "▒", "░"], interval: 100 },
|
|
26
|
+
bounce: { frames: ["⠁", "⠂", "⠄", "⠂"], interval: 120 },
|
|
27
|
+
boxBounce: { frames: ["▖", "▘", "▝", "▗"], interval: 120 },
|
|
28
|
+
boxBounce2: { frames: ["▌", "▀", "▐", "▄"], interval: 100 },
|
|
29
|
+
triangle: { frames: ["◢", "◣", "◤", "◥"], interval: 50 },
|
|
30
|
+
arc: { frames: ["◜", "◠", "◝", "◞", "◡", "◟"], interval: 100 },
|
|
31
|
+
circle: { frames: ["◡", "⊙", "◠"], interval: 120 },
|
|
32
|
+
squareCorners: { frames: ["◰", "◳", "◲", "◱"], interval: 180 },
|
|
33
|
+
circleQuarters: { frames: ["◴", "◷", "◶", "◵"], interval: 120 },
|
|
34
|
+
circleHalves: { frames: ["◐", "◓", "◑", "◒"], interval: 50 },
|
|
35
|
+
squish: { frames: ["╫", "╪"], interval: 100 },
|
|
36
|
+
toggle: { frames: ["⊶", "⊷"], interval: 250 },
|
|
37
|
+
toggle2: { frames: ["▫", "▪"], interval: 80 },
|
|
38
|
+
toggle3: { frames: ["□", "■"], interval: 120 },
|
|
39
|
+
toggle4: { frames: ["■", "□", "▪", "▫"], interval: 100 },
|
|
40
|
+
toggle5: { frames: ["▮", "▯"], interval: 100 },
|
|
41
|
+
toggle6: { frames: ["ဝ", "၀"], interval: 300 },
|
|
42
|
+
toggle7: { frames: ["⦾", "⦿"], interval: 80 },
|
|
43
|
+
toggle8: { frames: ["◍", "◌"], interval: 100 },
|
|
44
|
+
toggle9: { frames: ["◉", "◎"], interval: 100 },
|
|
45
|
+
toggle10: { frames: ["㊂", "㊀", "㊁"], interval: 100 },
|
|
46
|
+
toggle11: { frames: ["⧇", "⧆"], interval: 50 },
|
|
47
|
+
toggle12: { frames: ["☗", "☖"], interval: 120 },
|
|
48
|
+
toggle13: { frames: ["=", "*", "-"], interval: 80 },
|
|
49
|
+
arrow: { frames: ["←", "↖", "↑", "↗", "→", "↘", "↓", "↙"], interval: 100 },
|
|
50
|
+
arrow2: { frames: ["⬆️ ", "↗️ ", "➡️ ", "↘️ ", "⬇️ ", "↙️ ", "⬅️ ", "↖️ "], interval: 80 },
|
|
51
|
+
arrow3: { frames: ["▹▹▹▹▹", "▸▹▹▹▹", "▹▸▹▹▹", "▹▹▸▹▹", "▹▹▹▸▹", "▹▹▹▹▸"], interval: 120 },
|
|
52
|
+
bouncingBar: { frames: [
|
|
53
|
+
"[ ]", "[= ]", "[== ]", "[=== ]", "[ ===]", "[ ==]", "[ =]", "[ ]",
|
|
54
|
+
"[ =]", "[ ==]", "[ ===]", "[====]", "[=== ]", "[== ]", "[= ]",
|
|
55
|
+
], interval: 80 },
|
|
56
|
+
bouncingBall: { frames: [
|
|
57
|
+
"( ● )", "( ● )", "( ● )", "( ● )", "( ●)", "( ● )",
|
|
58
|
+
"( ● )", "( ● )", "( ● )", "(● )",
|
|
59
|
+
], interval: 80 },
|
|
60
|
+
smiley: { frames: ["😄 ", "😝 "], interval: 200 },
|
|
61
|
+
monkey: { frames: ["🙈 ", "🙈 ", "🙉 ", "🙊 "], interval: 300 },
|
|
62
|
+
hearts: { frames: ["💛 ", "💙 ", "💜 ", "💚 ", "❤️ "], interval: 100 },
|
|
63
|
+
clock: { frames: ["🕛 ", "🕐 ", "🕑 ", "🕒 ", "🕓 ", "🕔 ", "🕕 ", "🕖 ", "🕗 ", "🕘 ", "🕙 ", "🕚 "], interval: 100 },
|
|
64
|
+
earth: { frames: ["🌍 ", "🌎 ", "🌏 "], interval: 180 },
|
|
65
|
+
moon: { frames: ["🌑 ", "🌒 ", "🌓 ", "🌔 ", "🌕 ", "🌖 ", "🌗 ", "🌘 "], interval: 80 },
|
|
66
|
+
runner: { frames: ["🚶 ", "🏃 "], interval: 140 },
|
|
67
|
+
pong: { frames: [
|
|
68
|
+
"▐⠂ ▌", "▐⠈ ▌", "▐ ⠂ ▌", "▐ ⠠ ▌", "▐ ⡀ ▌",
|
|
69
|
+
"▐ ⠠ ▌", "▐ ⠂ ▌", "▐ ⠈ ▌", "▐ ⠂ ▌", "▐ ⠠ ▌",
|
|
70
|
+
"▐ ⡀ ▌", "▐ ⠠ ▌", "▐ ⠂ ▌", "▐ ⠈ ▌", "▐ ⠂▌",
|
|
71
|
+
"▐ ⠠▌", "▐ ⡀▌", "▐ ⠠ ▌", "▐ ⠂ ▌", "▐ ⠈ ▌",
|
|
72
|
+
"▐ ⠂ ▌", "▐ ⠠ ▌", "▐ ⡀ ▌", "▐ ⠠ ▌", "▐ ⠂ ▌",
|
|
73
|
+
"▐ ⠈ ▌", "▐ ⠂ ▌", "▐ ⠠ ▌", "▐ ⡀ ▌", "▐⠠ ▌",
|
|
74
|
+
], interval: 80 },
|
|
75
|
+
material: { frames: [
|
|
76
|
+
"█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", "██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
|
|
77
|
+
"███▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", "████▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
|
|
78
|
+
"██████▁▁▁▁▁▁▁▁▁▁▁▁▁▁", "██████▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
|
|
79
|
+
"███████▁▁▁▁▁▁▁▁▁▁▁▁▁", "████████▁▁▁▁▁▁▁▁▁▁▁▁",
|
|
80
|
+
"█████████▁▁▁▁▁▁▁▁▁▁▁", "█████████▁▁▁▁▁▁▁▁▁▁▁",
|
|
81
|
+
"██████████▁▁▁▁▁▁▁▁▁▁", "███████████▁▁▁▁▁▁▁▁▁",
|
|
82
|
+
"█████████████▁▁▁▁▁▁▁", "██████████████▁▁▁▁▁▁",
|
|
83
|
+
"██████████████▁▁▁▁▁▁", "▁██████████████▁▁▁▁▁",
|
|
84
|
+
"▁██████████████▁▁▁▁▁", "▁██████████████▁▁▁▁▁",
|
|
85
|
+
"▁▁██████████████▁▁▁▁", "▁▁▁██████████████▁▁▁",
|
|
86
|
+
"▁▁▁▁█████████████▁▁▁", "▁▁▁▁██████████████▁▁",
|
|
87
|
+
"▁▁▁▁██████████████▁▁", "▁▁▁▁▁██████████████▁",
|
|
88
|
+
"▁▁▁▁▁██████████████▁", "▁▁▁▁▁██████████████▁",
|
|
89
|
+
"▁▁▁▁▁▁██████████████", "▁▁▁▁▁▁██████████████",
|
|
90
|
+
"▁▁▁▁▁▁▁█████████████", "▁▁▁▁▁▁▁█████████████",
|
|
91
|
+
"▁▁▁▁▁▁▁▁████████████", "▁▁▁▁▁▁▁▁████████████",
|
|
92
|
+
"▁▁▁▁▁▁▁▁▁███████████", "▁▁▁▁▁▁▁▁▁███████████",
|
|
93
|
+
"▁▁▁▁▁▁▁▁▁▁██████████", "▁▁▁▁▁▁▁▁▁▁██████████",
|
|
94
|
+
"▁▁▁▁▁▁▁▁▁▁▁▁████████", "▁▁▁▁▁▁▁▁▁▁▁▁▁███████",
|
|
95
|
+
"▁▁▁▁▁▁▁▁▁▁▁▁▁▁██████", "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████",
|
|
96
|
+
"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████", "█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████",
|
|
97
|
+
"██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███", "██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███",
|
|
98
|
+
"███▁▁▁▁▁▁▁▁▁▁▁▁▁▁███", "████▁▁▁▁▁▁▁▁▁▁▁▁▁▁██",
|
|
99
|
+
"█████▁▁▁▁▁▁▁▁▁▁▁▁▁▁█", "█████▁▁▁▁▁▁▁▁▁▁▁▁▁▁█",
|
|
100
|
+
"██████▁▁▁▁▁▁▁▁▁▁▁▁▁█", "████████▁▁▁▁▁▁▁▁▁▁▁▁",
|
|
101
|
+
"█████████▁▁▁▁▁▁▁▁▁▁▁", "█████████▁▁▁▁▁▁▁▁▁▁▁",
|
|
102
|
+
"█████████▁▁▁▁▁▁▁▁▁▁▁", "█████████▁▁▁▁▁▁▁▁▁▁▁",
|
|
103
|
+
"███████████▁▁▁▁▁▁▁▁▁", "████████████▁▁▁▁▁▁▁▁",
|
|
104
|
+
"████████████▁▁▁▁▁▁▁▁", "██████████████▁▁▁▁▁▁",
|
|
105
|
+
"██████████████▁▁▁▁▁▁", "▁██████████████▁▁▁▁▁",
|
|
106
|
+
"▁██████████████▁▁▁▁▁", "▁▁▁██████████████▁▁▁",
|
|
107
|
+
"▁▁▁▁▁████████████▁▁▁", "▁▁▁▁▁████████████▁▁▁",
|
|
108
|
+
"▁▁▁▁▁▁███████████▁▁▁", "▁▁▁▁▁▁▁▁█████████▁▁▁",
|
|
109
|
+
"▁▁▁▁▁▁▁▁█████████▁▁▁", "▁▁▁▁▁▁▁▁▁█████████▁▁",
|
|
110
|
+
"▁▁▁▁▁▁▁▁▁█████████▁▁", "▁▁▁▁▁▁▁▁▁▁█████████▁",
|
|
111
|
+
], interval: 17 },
|
|
112
|
+
aesthetic: { frames: [
|
|
113
|
+
"▰▱▱▱▱▱▱", "▰▰▱▱▱▱▱", "▰▰▰▱▱▱▱", "▰▰▰▰▱▱▱",
|
|
114
|
+
"▰▰▰▰▰▱▱", "▰▰▰▰▰▰▱", "▰▰▰▰▰▰▰", "▰▱▱▱▱▱▱",
|
|
115
|
+
], interval: 80 },
|
|
116
|
+
};
|
|
117
|
+
export const DEFAULT_SPINNER = "dots";
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strip + Joiner — edge-aware horizontal layout primitive.
|
|
3
|
+
*
|
|
4
|
+
* A `Strip` renders a horizontal sequence of styled items with a `Joiner`
|
|
5
|
+
* deciding how each transition between adjacent items looks. The joiner is
|
|
6
|
+
* a pure function of `(leftItem | null, rightItem | null) -> Renderable`,
|
|
7
|
+
* so endpoint joins (the start and end of the strip) are explicit positions
|
|
8
|
+
* in the protocol — the joiner names what an endpoint looks like rather than
|
|
9
|
+
* the strip guessing.
|
|
10
|
+
*
|
|
11
|
+
* [LAW:one-source-of-truth] The render walk
|
|
12
|
+
* joiner(null, items[0]), items[0],
|
|
13
|
+
* joiner(items[0], items[1]), items[1], ...,
|
|
14
|
+
* joiner(items[N-1], null)
|
|
15
|
+
* is the single authority for how strips lay out. Every joiner participates
|
|
16
|
+
* in the same protocol; "look up the previous segment's bg" is no longer a
|
|
17
|
+
* powerline-specific hack but the contract every joiner shares.
|
|
18
|
+
*
|
|
19
|
+
* [LAW:locality-or-seam] The joiner protocol asks each item only for its
|
|
20
|
+
* *edge* style — the column adjacent to the joiner — not for a single
|
|
21
|
+
* whole-item style. This pushes the bg-uniformity requirement out of the
|
|
22
|
+
* cell type and into the narrowest place that actually needs it: the column
|
|
23
|
+
* boundary. Items with uniform styling report the same style at both edges;
|
|
24
|
+
* items with varying styling report the actual boundary column. There is no
|
|
25
|
+
* single-style invariant on the cell type — the terminal supports per-column
|
|
26
|
+
* styling, so the cell type does too.
|
|
27
|
+
*/
|
|
28
|
+
import { Segment } from "./segment.js";
|
|
29
|
+
import { Style } from "./style.js";
|
|
30
|
+
import { type Renderable, type RenderOptions } from "./protocol.js";
|
|
31
|
+
/**
|
|
32
|
+
* Items in a `Strip` expose their per-edge style so joiners can paint the
|
|
33
|
+
* transition glyph at each boundary.
|
|
34
|
+
*
|
|
35
|
+
* `edgeStyle("left", options)` reports the style of the item's leftmost cell
|
|
36
|
+
* column; `edgeStyle("right", options)` reports the rightmost. Joiners read
|
|
37
|
+
* only these — the item's interior may carry any per-column variation without
|
|
38
|
+
* breaking the join.
|
|
39
|
+
*
|
|
40
|
+
* The edge is asked in a render, with that render's options, because a style
|
|
41
|
+
* name only becomes a colour against the render's theme. A joiner therefore
|
|
42
|
+
* reads edges inside the `render` of what it returns, never in `join`.
|
|
43
|
+
*/
|
|
44
|
+
export interface StyledRenderable extends Renderable {
|
|
45
|
+
edgeStyle(side: "left" | "right", options: RenderOptions): Style;
|
|
46
|
+
}
|
|
47
|
+
export interface Joiner<T extends StyledRenderable = StyledRenderable> {
|
|
48
|
+
/**
|
|
49
|
+
* `left === null` marks the start endpoint; `right === null` marks the end
|
|
50
|
+
* endpoint. The joiner decides what an endpoint looks like — typically
|
|
51
|
+
* fg-only with no bg so the strip blends into the terminal background.
|
|
52
|
+
*/
|
|
53
|
+
join(left: T | null, right: T | null): Renderable;
|
|
54
|
+
}
|
|
55
|
+
export declare class Strip<T extends StyledRenderable = StyledRenderable> implements Renderable {
|
|
56
|
+
readonly items: readonly T[];
|
|
57
|
+
readonly joiner: Joiner<T>;
|
|
58
|
+
constructor(items: readonly T[], joiner: Joiner<T>);
|
|
59
|
+
render(options: RenderOptions): Iterable<Segment>;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The least ΔE_OK two neighbouring backgrounds must differ by for the powerline
|
|
63
|
+
* arrow between them to be seen. Below it the arrow is drawn in a colour the
|
|
64
|
+
* eye cannot tell from its own background, so the joiner draws the divider
|
|
65
|
+
* instead. Twice the ~.02 threshold of a visible difference, because a seam is
|
|
66
|
+
* one cell wide.
|
|
67
|
+
*/
|
|
68
|
+
export declare const SEAM_MIN_DELTA_E = 0.04;
|
|
69
|
+
export interface PowerlineJoinerOptions {
|
|
70
|
+
/** Glyph for every join between two coloured items. */
|
|
71
|
+
glyph: string;
|
|
72
|
+
/**
|
|
73
|
+
* Glyph drawn between neighbours whose backgrounds the eye cannot tell apart,
|
|
74
|
+
* in the left item's text colour — the arrow itself would vanish into the
|
|
75
|
+
* shared background.
|
|
76
|
+
*/
|
|
77
|
+
divider: string;
|
|
78
|
+
/**
|
|
79
|
+
* Glyph for every join a coloured item is entered from nothing — the strip's
|
|
80
|
+
* start, or a colourless left neighbour — painted in the right item's
|
|
81
|
+
* background. `""` begins a coloured run flat.
|
|
82
|
+
*/
|
|
83
|
+
lead: string;
|
|
84
|
+
/**
|
|
85
|
+
* Glyph for every join a coloured item leaves into nothing — the strip's end,
|
|
86
|
+
* or a colourless right neighbour — painted in the left item's background.
|
|
87
|
+
* `""` ends a coloured run flat.
|
|
88
|
+
*/
|
|
89
|
+
tail: string;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* The powerline set: U+E0B0 (right-arrow) divided by U+E0B1 (thin right-arrow),
|
|
93
|
+
* led by U+E0D7 (Nerd Fonts ple-left_hard_divider_inverse, the right-arrow's
|
|
94
|
+
* inverse) and tailed by the arrow itself. The lead leaves empty a triangle
|
|
95
|
+
* whose base is its cell's left edge and whose point touches the first item, so
|
|
96
|
+
* the run opens notched — as if an arrow before it pointed in — rather than
|
|
97
|
+
* with a shape pointing out. The notch is the terminal's own background showing
|
|
98
|
+
* through, never a colour painted to imitate it, so it matches under a
|
|
99
|
+
* translucent terminal background too. The lead is a Powerline Extra glyph: a
|
|
100
|
+
* classic powerline font lacks it.
|
|
101
|
+
*/
|
|
102
|
+
export declare const POWERLINE_JOINER_GLYPHS: Readonly<PowerlineJoinerOptions>;
|
|
103
|
+
export declare class PowerlineJoiner<T extends StyledRenderable = StyledRenderable> implements Joiner<T> {
|
|
104
|
+
private readonly _glyphs;
|
|
105
|
+
constructor(options?: PowerlineJoinerOptions);
|
|
106
|
+
join(left: T | null, right: T | null): Renderable;
|
|
107
|
+
}
|
|
108
|
+
export interface CapsuleJoinerOptions {
|
|
109
|
+
/** Left-cap glyph (default: U+E0B6, powerline rounded left). */
|
|
110
|
+
left?: string;
|
|
111
|
+
/** Right-cap glyph (default: U+E0B4, powerline rounded right). */
|
|
112
|
+
right?: string;
|
|
113
|
+
/** Separator inserted between adjacent capsules in the middle position. */
|
|
114
|
+
separator?: string;
|
|
115
|
+
}
|
|
116
|
+
export declare class CapsuleJoiner<T extends StyledRenderable = StyledRenderable> implements Joiner<T> {
|
|
117
|
+
private readonly _caps;
|
|
118
|
+
private readonly _separator;
|
|
119
|
+
constructor(options?: CapsuleJoinerOptions);
|
|
120
|
+
_emit(left: T | null, right: T | null, options: RenderOptions): Iterable<Segment>;
|
|
121
|
+
join(left: T | null, right: T | null): Renderable;
|
|
122
|
+
}
|
|
123
|
+
export interface PlainJoinerOptions {
|
|
124
|
+
separator?: string;
|
|
125
|
+
style?: Style;
|
|
126
|
+
}
|
|
127
|
+
export declare class PlainJoiner<T extends StyledRenderable = StyledRenderable> implements Joiner<T> {
|
|
128
|
+
private readonly _separator;
|
|
129
|
+
private readonly _style;
|
|
130
|
+
constructor(options?: PlainJoinerOptions);
|
|
131
|
+
join(left: T | null, right: T | null): Renderable;
|
|
132
|
+
}
|
|
133
|
+
export interface GradientJoinerOptions {
|
|
134
|
+
/** Number of cells between adjacent items (default: 4). */
|
|
135
|
+
steps?: number;
|
|
136
|
+
}
|
|
137
|
+
export declare class GradientJoiner<T extends StyledRenderable = StyledRenderable> implements Joiner<T> {
|
|
138
|
+
private readonly _steps;
|
|
139
|
+
constructor(options?: GradientJoinerOptions);
|
|
140
|
+
join(left: T | null, right: T | null): Renderable;
|
|
141
|
+
}
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strip + Joiner — edge-aware horizontal layout primitive.
|
|
3
|
+
*
|
|
4
|
+
* A `Strip` renders a horizontal sequence of styled items with a `Joiner`
|
|
5
|
+
* deciding how each transition between adjacent items looks. The joiner is
|
|
6
|
+
* a pure function of `(leftItem | null, rightItem | null) -> Renderable`,
|
|
7
|
+
* so endpoint joins (the start and end of the strip) are explicit positions
|
|
8
|
+
* in the protocol — the joiner names what an endpoint looks like rather than
|
|
9
|
+
* the strip guessing.
|
|
10
|
+
*
|
|
11
|
+
* [LAW:one-source-of-truth] The render walk
|
|
12
|
+
* joiner(null, items[0]), items[0],
|
|
13
|
+
* joiner(items[0], items[1]), items[1], ...,
|
|
14
|
+
* joiner(items[N-1], null)
|
|
15
|
+
* is the single authority for how strips lay out. Every joiner participates
|
|
16
|
+
* in the same protocol; "look up the previous segment's bg" is no longer a
|
|
17
|
+
* powerline-specific hack but the contract every joiner shares.
|
|
18
|
+
*
|
|
19
|
+
* [LAW:locality-or-seam] The joiner protocol asks each item only for its
|
|
20
|
+
* *edge* style — the column adjacent to the joiner — not for a single
|
|
21
|
+
* whole-item style. This pushes the bg-uniformity requirement out of the
|
|
22
|
+
* cell type and into the narrowest place that actually needs it: the column
|
|
23
|
+
* boundary. Items with uniform styling report the same style at both edges;
|
|
24
|
+
* items with varying styling report the actual boundary column. There is no
|
|
25
|
+
* single-style invariant on the cell type — the terminal supports per-column
|
|
26
|
+
* styling, so the cell type does too.
|
|
27
|
+
*/
|
|
28
|
+
import { Segment } from "./segment.js";
|
|
29
|
+
import { Style } from "./style.js";
|
|
30
|
+
import { ColorDepth, ColorSpec, blendRgb } from "./color.js";
|
|
31
|
+
import { Oklch } from "./oklch.js";
|
|
32
|
+
import { drawable } from "./protocol.js";
|
|
33
|
+
// --- Strip ---
|
|
34
|
+
export class Strip {
|
|
35
|
+
items;
|
|
36
|
+
joiner;
|
|
37
|
+
constructor(items, joiner) {
|
|
38
|
+
this.items = items;
|
|
39
|
+
this.joiner = joiner;
|
|
40
|
+
}
|
|
41
|
+
*render(options) {
|
|
42
|
+
const items = this.items;
|
|
43
|
+
if (items.length === 0)
|
|
44
|
+
return;
|
|
45
|
+
// [LAW:dataflow-not-control-flow] The walk is the same shape every render:
|
|
46
|
+
// start-cap, item, mid-join, item, ..., item, end-cap. Variability lives
|
|
47
|
+
// in `items` and in what the joiner emits at each position — never in
|
|
48
|
+
// whether a join runs.
|
|
49
|
+
yield* this.joiner.join(null, items[0]).render(options);
|
|
50
|
+
for (let i = 0; i < items.length; i++) {
|
|
51
|
+
const item = items[i];
|
|
52
|
+
yield* item.render(options);
|
|
53
|
+
const next = i + 1 < items.length ? items[i + 1] : null;
|
|
54
|
+
yield* this.joiner.join(item, next).render(options);
|
|
55
|
+
}
|
|
56
|
+
// [LAW:one-source-of-truth] `Strip`'s sibling `FlexStrip` ends every line
|
|
57
|
+
// it emits, including the last, and the other block-level renderables
|
|
58
|
+
// (`Panel`/`Rule`/`Table` structurally, `RichText` via `end`) do too — so
|
|
59
|
+
// `Group` can emit children back to back with nothing in between
|
|
60
|
+
// (docs/group.md). A `Strip` that left its last line open broke only
|
|
61
|
+
// under composition: printed alone, Console's own "close whatever the
|
|
62
|
+
// renderable left open" step (console.ts) papered over it, and a `Group`
|
|
63
|
+
// of a Strip and a RichText ran the RichText onto the Strip's line
|
|
64
|
+
// instead of below it. (Not every renderable follows this — a `Spinner`
|
|
65
|
+
// or `ProgressBar` is a line *fragment*, not a block; see
|
|
66
|
+
// rich-flexstrip-5kf.4cq for the open question of formalizing that split.)
|
|
67
|
+
yield Segment.line();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// --- Helpers ---
|
|
71
|
+
const EMPTY = {
|
|
72
|
+
*render(_options) {
|
|
73
|
+
// intentionally empty
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
/** A renderable whose segments are computed from the options it is rendered with. */
|
|
77
|
+
function deferred(emit) {
|
|
78
|
+
return { render: emit };
|
|
79
|
+
}
|
|
80
|
+
// Endpoint and powerline join glyphs paint the adjacent item's edge bg
|
|
81
|
+
// *as* their fg. If the edge has no bgcolor, the glyph degrades to the
|
|
82
|
+
// default fg — which renders as nothing visible against the terminal
|
|
83
|
+
// background, the right outcome for an unstyled edge.
|
|
84
|
+
function bgAsFg(edge) {
|
|
85
|
+
return new Style({ color: edge.bgcolor });
|
|
86
|
+
}
|
|
87
|
+
// A bg with a real colour to paint. `undefined` (no bg) and the terminal
|
|
88
|
+
// DEFAULT colour (transparent — identical to the terminal background) are the
|
|
89
|
+
// two representations of "nothing to paint"; the powerline separator treats
|
|
90
|
+
// them the same, so the gate cannot be fooled by an explicit `… on default`.
|
|
91
|
+
function paintableBg(bg) {
|
|
92
|
+
return bg !== undefined && !bg.isDefault ? bg : undefined;
|
|
93
|
+
}
|
|
94
|
+
// A cap or arrow is its cell continuing: that cell's ground as the writer draws
|
|
95
|
+
// it, so a translucent ground is not composited a second time over whatever it
|
|
96
|
+
// enters.
|
|
97
|
+
function drawnGround(bg) {
|
|
98
|
+
return new Style({ bgcolor: bg }).drawnColors().bgcolor;
|
|
99
|
+
}
|
|
100
|
+
// A cap is its glyph in its cell's ground, and "" is a flat end: no glyph, so
|
|
101
|
+
// no segment — the same output as a join with nothing to paint.
|
|
102
|
+
function* cap(glyph, bg) {
|
|
103
|
+
if (glyph !== "")
|
|
104
|
+
yield new Segment(glyph, new Style({ color: drawnGround(bg) }));
|
|
105
|
+
}
|
|
106
|
+
// --- PowerlineJoiner ---
|
|
107
|
+
/**
|
|
108
|
+
* The least ΔE_OK two neighbouring backgrounds must differ by for the powerline
|
|
109
|
+
* arrow between them to be seen. Below it the arrow is drawn in a colour the
|
|
110
|
+
* eye cannot tell from its own background, so the joiner draws the divider
|
|
111
|
+
* instead. Twice the ~.02 threshold of a visible difference, because a seam is
|
|
112
|
+
* one cell wide.
|
|
113
|
+
*/
|
|
114
|
+
export const SEAM_MIN_DELTA_E = 0.04;
|
|
115
|
+
// An arrow the eye cannot tell from the ground it is drawn on. What is
|
|
116
|
+
// measured is what is drawn — `Style.drawnColors`, the colours the writer
|
|
117
|
+
// encodes: the arrow's colour flattened onto its ground and the ground onto
|
|
118
|
+
// the terminal's black, both downgraded to the depth the render encodes at,
|
|
119
|
+
// so two grounds 256 colours round to one cube entry are the one entry they
|
|
120
|
+
// render as. A colour whose RGB is the terminal theme's own (ANSI 0–15) has no
|
|
121
|
+
// value here, so two of them are the same only when they are the same palette
|
|
122
|
+
// slot — its `number`, never the name or the depth that spells it ("red",
|
|
123
|
+
// "color(1)", an EIGHT_BIT spec on 0–15 are one slot).
|
|
124
|
+
function vanishes(arrow, colorSystem) {
|
|
125
|
+
// No colour emitted draws nothing to tell apart; measure what was handed.
|
|
126
|
+
const { color, bgcolor } = arrow.drawnColors(colorSystem ?? ColorDepth.TRUECOLOR);
|
|
127
|
+
if (color === undefined || bgcolor === undefined)
|
|
128
|
+
return false;
|
|
129
|
+
const av = color.fixedValue;
|
|
130
|
+
const bv = bgcolor.fixedValue;
|
|
131
|
+
return av !== undefined && bv !== undefined
|
|
132
|
+
? Oklch.fromRgba(av).deltaE(Oklch.fromRgba(bv)) < SEAM_MIN_DELTA_E
|
|
133
|
+
: color.number === bgcolor.number;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* The powerline set: U+E0B0 (right-arrow) divided by U+E0B1 (thin right-arrow),
|
|
137
|
+
* led by U+E0D7 (Nerd Fonts ple-left_hard_divider_inverse, the right-arrow's
|
|
138
|
+
* inverse) and tailed by the arrow itself. The lead leaves empty a triangle
|
|
139
|
+
* whose base is its cell's left edge and whose point touches the first item, so
|
|
140
|
+
* the run opens notched — as if an arrow before it pointed in — rather than
|
|
141
|
+
* with a shape pointing out. The notch is the terminal's own background showing
|
|
142
|
+
* through, never a colour painted to imitate it, so it matches under a
|
|
143
|
+
* translucent terminal background too. The lead is a Powerline Extra glyph: a
|
|
144
|
+
* classic powerline font lacks it.
|
|
145
|
+
*/
|
|
146
|
+
export const POWERLINE_JOINER_GLYPHS = Object.freeze({
|
|
147
|
+
glyph: "\ue0b0",
|
|
148
|
+
divider: "\ue0b1",
|
|
149
|
+
lead: "\ue0d7",
|
|
150
|
+
tail: "\ue0b0",
|
|
151
|
+
});
|
|
152
|
+
/** The powerline set in ASCII: an arrow for every join, runs begun flat. */
|
|
153
|
+
const ASCII_POWERLINE_GLYPHS = Object.freeze({
|
|
154
|
+
glyph: ">",
|
|
155
|
+
divider: ">",
|
|
156
|
+
lead: "",
|
|
157
|
+
tail: ">",
|
|
158
|
+
});
|
|
159
|
+
const powerlineGlyphs = ({ glyph, divider, lead, tail }) => glyph + divider + lead + tail;
|
|
160
|
+
export class PowerlineJoiner {
|
|
161
|
+
_glyphs;
|
|
162
|
+
constructor(options = POWERLINE_JOINER_GLYPHS) {
|
|
163
|
+
this._glyphs = options;
|
|
164
|
+
}
|
|
165
|
+
join(left, right) {
|
|
166
|
+
// [LAW:dataflow-not-control-flow] One table for all three positions (start
|
|
167
|
+
// cap, mid-join, end cap), read off which side has a colour to paint. The
|
|
168
|
+
// endpoints are not control-flow special cases; they are the DATA cases
|
|
169
|
+
// where a neighbour (hence its bg) is absent:
|
|
170
|
+
// • both bgs — the arrow in the LEFT bg (the colour bleeding rightward)
|
|
171
|
+
// over the RIGHT bg.
|
|
172
|
+
// • left bg only — the end cap, OR a coloured item before a colourless
|
|
173
|
+
// one — the tail bleeds the left colour out over the terminal
|
|
174
|
+
// background (fg = left bg, no bg).
|
|
175
|
+
// • right bg only — the start cap, OR a colourless item before a coloured
|
|
176
|
+
// one — the lead: the right colour painted over the terminal
|
|
177
|
+
// background in the lead's shape (fg = right bg, no bg).
|
|
178
|
+
// • neither — nothing to paint, so the join yields nothing.
|
|
179
|
+
// Equal REAL bgs still emit: a same-bg seam between two distinct items is a
|
|
180
|
+
// structural boundary, never suppressed. The arrow would be drawn in its own
|
|
181
|
+
// background colour there and vanish, so the seam is the DIVIDER instead, in
|
|
182
|
+
// the left item's text colour — the vim-airline convention for neighbours
|
|
183
|
+
// that share a background. "Equal" is perceptual (SEAM_MIN_DELTA_E) and
|
|
184
|
+
// measured on the colours the terminal draws at `options.colorSystem`: an
|
|
185
|
+
// arrow a hair off its background is as invisible as one exactly on it,
|
|
186
|
+
// and two backgrounds 256 colours round to one entry are one background.
|
|
187
|
+
// Background colour is paint, not structure; its ABSENCE (nothing to paint)
|
|
188
|
+
// is the only thing that elides the separator, and that is paint logic.
|
|
189
|
+
// "Absent" = no bg OR the terminal default (transparent) — paintableBg folds
|
|
190
|
+
// both to undefined so an explicit `… on default` cannot smuggle a separator.
|
|
191
|
+
const glyphs = this._glyphs;
|
|
192
|
+
return deferred(function* (options) {
|
|
193
|
+
const { glyph, divider, lead, tail } = drawable(options, glyphs, ASCII_POWERLINE_GLYPHS, powerlineGlyphs);
|
|
194
|
+
const leftEdge = left?.edgeStyle("right", options);
|
|
195
|
+
const leftBg = paintableBg(leftEdge?.bgcolor);
|
|
196
|
+
const rightBg = paintableBg(right?.edgeStyle("left", options).bgcolor);
|
|
197
|
+
if (leftBg === undefined) {
|
|
198
|
+
if (rightBg !== undefined)
|
|
199
|
+
yield* cap(lead, rightBg);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
if (rightBg === undefined) {
|
|
203
|
+
yield* cap(tail, leftBg);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
const arrow = new Style({ color: drawnGround(leftBg), bgcolor: rightBg });
|
|
207
|
+
// The divider is the left item's text on the left item's own ground,
|
|
208
|
+
// so it reads exactly as well as that item's text does, at any depth.
|
|
209
|
+
yield vanishes(arrow, options.colorSystem)
|
|
210
|
+
? new Segment(divider, new Style({ color: leftEdge?.color, bgcolor: leftBg }))
|
|
211
|
+
: new Segment(glyph, arrow);
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
const ASCII_CAPS = { left: "(", right: ")" };
|
|
216
|
+
const capGlyphs = ({ left, right }) => left + right;
|
|
217
|
+
export class CapsuleJoiner {
|
|
218
|
+
_caps;
|
|
219
|
+
_separator;
|
|
220
|
+
constructor(options) {
|
|
221
|
+
this._caps = { left: options?.left ?? "", right: options?.right ?? "" };
|
|
222
|
+
this._separator = options?.separator ?? " ";
|
|
223
|
+
}
|
|
224
|
+
*_emit(left, right, options) {
|
|
225
|
+
const caps = drawable(options, this._caps, ASCII_CAPS, capGlyphs);
|
|
226
|
+
const separator = drawable(options, this._separator, " ");
|
|
227
|
+
if (left === null && right === null)
|
|
228
|
+
return;
|
|
229
|
+
if (left === null) {
|
|
230
|
+
yield new Segment(caps.left, bgAsFg(right.edgeStyle("left", options)));
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
if (right === null) {
|
|
234
|
+
yield new Segment(caps.right, bgAsFg(left.edgeStyle("right", options)));
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
// Middle: close the left capsule, separator (unstyled), open the right.
|
|
238
|
+
yield new Segment(caps.right, bgAsFg(left.edgeStyle("right", options)));
|
|
239
|
+
if (separator.length > 0)
|
|
240
|
+
yield new Segment(separator);
|
|
241
|
+
yield new Segment(caps.left, bgAsFg(right.edgeStyle("left", options)));
|
|
242
|
+
}
|
|
243
|
+
join(left, right) {
|
|
244
|
+
return deferred((options) => this._emit(left, right, options));
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
export class PlainJoiner {
|
|
248
|
+
_separator;
|
|
249
|
+
_style;
|
|
250
|
+
constructor(options) {
|
|
251
|
+
this._separator = options?.separator ?? " | ";
|
|
252
|
+
this._style = options?.style ?? Style.parse("dim");
|
|
253
|
+
}
|
|
254
|
+
join(left, right) {
|
|
255
|
+
// Endpoints are empty — a fixed separator has no natural cap.
|
|
256
|
+
if (left === null || right === null)
|
|
257
|
+
return EMPTY;
|
|
258
|
+
const separator = this._separator;
|
|
259
|
+
const style = this._style;
|
|
260
|
+
return deferred((options) => [new Segment(drawable(options, separator, " | "), style)]);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Half-block dithering glyph: paints the cell's left half with the foreground
|
|
265
|
+
* colour and the right half with the background colour. Lets each cell carry
|
|
266
|
+
* two colour samples — `2 * steps` samples in `steps` cells — so the gradient
|
|
267
|
+
* looks twice as smooth as one-colour-per-cell at the same width.
|
|
268
|
+
*/
|
|
269
|
+
const HALF_BLOCK = "▌"; // ▌
|
|
270
|
+
export class GradientJoiner {
|
|
271
|
+
_steps;
|
|
272
|
+
constructor(options) {
|
|
273
|
+
this._steps = options?.steps ?? 4;
|
|
274
|
+
}
|
|
275
|
+
join(left, right) {
|
|
276
|
+
// [LAW:dataflow-not-control-flow] Endpoints have no opposite anchor to
|
|
277
|
+
// interpolate toward — the data (a missing neighbor) makes the gradient
|
|
278
|
+
// empty. Same for edges lacking a bgcolor: nothing to blend between.
|
|
279
|
+
if (left === null || right === null)
|
|
280
|
+
return EMPTY;
|
|
281
|
+
const steps = this._steps;
|
|
282
|
+
return deferred(function* (options) {
|
|
283
|
+
const lbg = left.edgeStyle("right", options).bgcolor;
|
|
284
|
+
const rbg = right.edgeStyle("left", options).bgcolor;
|
|
285
|
+
if (!lbg || !rbg)
|
|
286
|
+
return;
|
|
287
|
+
const lTrip = lbg.getTruecolor();
|
|
288
|
+
const rTrip = rbg.getTruecolor();
|
|
289
|
+
// An ASCII cell carries one sample, the background: the gradient keeps
|
|
290
|
+
// its colours at half the resolution.
|
|
291
|
+
const half = drawable(options, HALF_BLOCK, " ");
|
|
292
|
+
const samples = 2 * steps;
|
|
293
|
+
// Midpoint sampling across `2 * steps` half-cell positions: sample j has
|
|
294
|
+
// t = (j + 0.5) / samples. Cell i takes samples 2i (left half) and 2i+1
|
|
295
|
+
// (right half). No sample ever equals either anchor.
|
|
296
|
+
for (let i = 0; i < steps; i++) {
|
|
297
|
+
const tLeft = (2 * i + 0.5) / samples;
|
|
298
|
+
const tRight = (2 * i + 1.5) / samples;
|
|
299
|
+
const fg = ColorSpec.fromRgba(blendRgb(lTrip, rTrip, tLeft));
|
|
300
|
+
const bg = ColorSpec.fromRgba(blendRgb(lTrip, rTrip, tRight));
|
|
301
|
+
yield new Segment(half, new Style({ color: fg, bgcolor: bg }));
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
}
|