archymedes-cli 3.0.0 → 3.2.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.
@@ -1,1250 +0,0 @@
1
- // packages/archymedes-cli/src/theme/theme.ts
2
- var BLUEPRINT = `
3
- /* Blueprint navy, chalk-white ink and an amber pencil — the original drafting table. */
4
- @theme blueprint {
5
- --primary: #7cc5ff;
6
- --secondary: #9fb4e8;
7
- --accent: #ffcf6b;
8
- --bg: #0a1524;
9
- --surface: #122135;
10
- --text: #e8eefb;
11
- --text-muted: #6f89b0;
12
- --success: #79dfa6;
13
- --warning: #ffcf6b;
14
- --error: #ff8f7a;
15
- --border: round;
16
- --border-color: #24406a;
17
- --border-focus: #7cc5ff;
18
- }
19
- `;
20
- var PARCHMENT = `
21
- /* The same drawing inked on paper, for a light terminal. */
22
- @theme parchment {
23
- --primary: #2f5fbf;
24
- --secondary: #5a4a86;
25
- --accent: #9a6a00;
26
- --bg: #faf6ec;
27
- --surface: #f1eadd;
28
- --text: #1b1a16;
29
- --text-muted: #6a6252;
30
- --success: #196a44;
31
- --warning: #8a5300;
32
- --error: #b3243b;
33
- --border: round;
34
- --border-color: #d8cfb8;
35
- --border-focus: #2f5fbf;
36
- }
37
- `;
38
- var CHALKBOARD = `
39
- /* A slate: near-black green, chalk white, chalk yellow — for terminals with contrast to spare. */
40
- @theme chalkboard {
41
- --primary: #9fe8d8;
42
- --secondary: #d8d0b0;
43
- --accent: #ffe066;
44
- --bg: #0d1a15;
45
- --surface: #16271f;
46
- --text: #f2efe4;
47
- --text-muted: #86987f;
48
- --success: #7ef2b0;
49
- --warning: #ffd166;
50
- --error: #ff7a7a;
51
- --border: single;
52
- --border-color: #2c443a;
53
- --border-focus: #ffe066;
54
- }
55
- `;
56
- var HIGH_CONTRAST = `
57
- /* Maximum separation, named colours only — for low vision and for terminals with a fixed palette. */
58
- @theme high-contrast {
59
- --primary: brightCyan;
60
- --secondary: brightMagenta;
61
- --accent: brightYellow;
62
- --bg: black;
63
- --surface: black;
64
- --text: brightWhite;
65
- --text-muted: white;
66
- --success: brightGreen;
67
- --warning: brightYellow;
68
- --error: brightRed;
69
- --border: single;
70
- --border-color: white;
71
- --border-focus: brightCyan;
72
- }
73
- `;
74
- var ARCHYMEDES = `
75
- /* Bronze instruments, limestone ink and olive accents on charcoal — Archymedes's own. */
76
- @theme archymedes {
77
- --primary: #e7bb78;
78
- --secondary: #b9c59a;
79
- --accent: #e5a58c;
80
- --bg: #191815;
81
- --surface: #25231e;
82
- --text: #f2ecdf;
83
- --text-muted: #aaa18f;
84
- --success: #b5cc96;
85
- --warning: #efc778;
86
- --error: #f29686;
87
- --border: single;
88
- --border-color: #736956;
89
- --border-focus: #e7bb78;
90
- }
91
- `;
92
- var ARCHYMEDES_BLUE = `
93
- /* Solarized Dark with an Archymedes-blue line — calm, high-contrast hues; the default. */
94
- @theme archymedes-blue {
95
- --primary: #268bd2;
96
- --secondary: #2aa198;
97
- --accent: #b58900;
98
- --bg: #002b36;
99
- --surface: #073642;
100
- --text: #93a1a1;
101
- --text-muted: #657b83;
102
- --success: #859900;
103
- --warning: #cb4b16;
104
- --error: #dc322f;
105
- --border: round;
106
- --border-color: #586e75;
107
- --border-focus: #268bd2;
108
- }
109
- `;
110
- var RAINBOW = `
111
- /* Every hue at once — the opening art and the thinking spinner sweep the full spectrum. */
112
- @theme rainbow {
113
- --primary: #ff5f5f;
114
- --secondary: #5fd7ff;
115
- --accent: #ffd75f;
116
- --bg: #0c0c0c;
117
- --surface: #161616;
118
- --text: #f2f2f2;
119
- --text-muted: #9a9a9a;
120
- --success: #5fff87;
121
- --warning: #ffaf5f;
122
- --error: #ff3b3b;
123
- --border: double;
124
- --border-color: #8a8a8a;
125
- --border-focus: #d75fff;
126
- }
127
- `;
128
- var BUILTIN_THEME_SOURCES = {
129
- "archymedes-blue": ARCHYMEDES_BLUE,
130
- archymedes: ARCHYMEDES,
131
- blueprint: BLUEPRINT,
132
- parchment: PARCHMENT,
133
- chalkboard: CHALKBOARD,
134
- "high-contrast": HIGH_CONTRAST,
135
- rainbow: RAINBOW
136
- };
137
- var DEFAULT_THEME_NAME = "archymedes-blue";
138
- var NAMED_COLORS = {
139
- black: 0,
140
- red: 1,
141
- green: 2,
142
- yellow: 3,
143
- blue: 4,
144
- magenta: 5,
145
- cyan: 6,
146
- white: 7,
147
- brightblack: 8,
148
- brightred: 9,
149
- brightgreen: 10,
150
- brightyellow: 11,
151
- brightblue: 12,
152
- brightmagenta: 13,
153
- brightcyan: 14,
154
- brightwhite: 15,
155
- gray: 8,
156
- grey: 8
157
- };
158
- function parseColor(value) {
159
- const text = value.trim();
160
- const named = NAMED_COLORS[text.toLowerCase().replace(/[\s_-]/g, "")];
161
- if (named !== undefined)
162
- return named;
163
- const hex = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(text);
164
- if (!hex)
165
- return;
166
- const digits = hex[1];
167
- const full = digits.length === 3 ? digits.split("").map((digit) => digit + digit).join("") : digits;
168
- return {
169
- r: Number.parseInt(full.slice(0, 2), 16),
170
- g: Number.parseInt(full.slice(2, 4), 16),
171
- b: Number.parseInt(full.slice(4, 6), 16)
172
- };
173
- }
174
- function rgbTo256({ r, g, b }) {
175
- const level = (value) => {
176
- if (value < 48)
177
- return 0;
178
- if (value < 115)
179
- return 1;
180
- return Math.min(5, Math.round((value - 35) / 40));
181
- };
182
- const cubeIndex = 16 + 36 * level(r) + 6 * level(g) + level(b);
183
- const cubeValue = (step) => step === 0 ? 0 : 55 + step * 40;
184
- const cube = { r: cubeValue(level(r)), g: cubeValue(level(g)), b: cubeValue(level(b)) };
185
- const greyAverage = (r + g + b) / 3;
186
- const greyStep = Math.max(0, Math.min(23, Math.round((greyAverage - 8) / 10)));
187
- const greyValue = 8 + greyStep * 10;
188
- const grey = { r: greyValue, g: greyValue, b: greyValue };
189
- return distance({ r, g, b }, grey) < distance({ r, g, b }, cube) ? 232 + greyStep : cubeIndex;
190
- }
191
- function distance(a, b) {
192
- return (a.r - b.r) ** 2 + (a.g - b.g) ** 2 + (a.b - b.b) ** 2;
193
- }
194
- function colorCode(value, depth) {
195
- if (depth === "none")
196
- return "";
197
- const parsed = parseColor(value);
198
- if (parsed === undefined)
199
- return "";
200
- if (typeof parsed === "number")
201
- return parsed < 8 ? `\x1B[${30 + parsed}m` : `\x1B[${90 + parsed - 8}m`;
202
- return depth === "truecolor" ? `\x1B[38;2;${parsed.r};${parsed.g};${parsed.b}m` : `\x1B[38;5;${rgbTo256(parsed)}m`;
203
- }
204
- function rainbowHex(t) {
205
- const hue = (t % 1 + 1) % 1 * 360;
206
- const c = 0.5;
207
- const x = c * (1 - Math.abs(hue / 60 % 2 - 1));
208
- const m = 0.6 - c / 2;
209
- const [r1, g1, b1] = hue < 60 ? [c, x, 0] : hue < 120 ? [x, c, 0] : hue < 180 ? [0, c, x] : hue < 240 ? [0, x, c] : hue < 300 ? [x, 0, c] : [c, 0, x];
210
- const channel = (value) => Math.round((value + m) * 255).toString(16).padStart(2, "0");
211
- return `#${channel(r1)}${channel(g1)}${channel(b1)}`;
212
- }
213
- function rainbowText(text, depth, phase = 0) {
214
- if (depth === "none")
215
- return text;
216
- const characters = [...text];
217
- let out = "";
218
- let open;
219
- characters.forEach((character, index) => {
220
- if (character === " ") {
221
- if (open !== undefined) {
222
- out += "\x1B[0m";
223
- open = undefined;
224
- }
225
- out += character;
226
- return;
227
- }
228
- const code = colorCode(rainbowHex(phase + index / 12), depth);
229
- if (code !== open) {
230
- out += code;
231
- open = code;
232
- }
233
- out += character;
234
- });
235
- return open === undefined ? out : `${out}\x1B[0m`;
236
- }
237
- var DEFAULT_TOKENS = {
238
- primary: "cyan",
239
- secondary: "blue",
240
- accent: "yellow",
241
- bg: "black",
242
- surface: "black",
243
- text: "white",
244
- textMuted: "brightBlack",
245
- success: "green",
246
- warning: "yellow",
247
- error: "red",
248
- border: "round",
249
- borderColor: "brightBlack",
250
- borderFocus: "cyan"
251
- };
252
- var TOKEN_NAMES = {
253
- primary: "primary",
254
- secondary: "secondary",
255
- accent: "accent",
256
- bg: "bg",
257
- background: "bg",
258
- surface: "surface",
259
- text: "text",
260
- fg: "text",
261
- "text-muted": "textMuted",
262
- muted: "textMuted",
263
- success: "success",
264
- warning: "warning",
265
- error: "error",
266
- border: "border",
267
- "border-color": "borderColor",
268
- "border-focus": "borderFocus",
269
- highlight: "secondary"
270
- };
271
- function parseThemeSource(source) {
272
- const themes = [];
273
- const withoutLineComments = source.replace(/(^|\s)\/\/[^\n]*/g, "$1");
274
- const blockPattern = /(?:\/\*([\s\S]*?)\*\/\s*)?@theme\s+([A-Za-z0-9_-]+)\s*\{([^}]*)\}/g;
275
- for (const match of withoutLineComments.matchAll(blockPattern)) {
276
- const description = (match[1] ?? "").replace(/\s+/g, " ").trim();
277
- const tokens = { ...DEFAULT_TOKENS };
278
- for (const declaration of match[3].matchAll(/(?:--|\$)([a-z0-9-]+)\s*:\s*([^;}]+)[;]?/gi)) {
279
- const key = TOKEN_NAMES[declaration[1].toLowerCase()];
280
- if (key)
281
- tokens[key] = declaration[2].trim();
282
- }
283
- themes.push({ name: match[2], description, tokens });
284
- }
285
- return themes;
286
- }
287
- function builtinThemes() {
288
- return Object.values(BUILTIN_THEME_SOURCES).flatMap((source) => parseThemeSource(source));
289
- }
290
- function findBuiltinTheme(name) {
291
- return builtinThemes().find((theme) => theme.name.toLowerCase() === name.trim().toLowerCase());
292
- }
293
- function borderStyleOf(value) {
294
- const text = value.trim().toLowerCase();
295
- return text === "single" || text === "double" || text === "none" ? text : "round";
296
- }
297
- function buildPalette(theme, depth) {
298
- const code = (value) => colorCode(value, depth);
299
- return {
300
- theme: theme.name,
301
- depth,
302
- primary: code(theme.tokens.primary),
303
- secondary: code(theme.tokens.secondary),
304
- accent: code(theme.tokens.accent),
305
- text: code(theme.tokens.text),
306
- muted: code(theme.tokens.textMuted),
307
- success: code(theme.tokens.success),
308
- warning: code(theme.tokens.warning),
309
- error: code(theme.tokens.error),
310
- border: code(theme.tokens.borderColor),
311
- borderFocus: code(theme.tokens.borderFocus),
312
- borderStyle: borderStyleOf(theme.tokens.border),
313
- bg: theme.tokens.bg,
314
- surface: theme.tokens.surface,
315
- tokens: theme.tokens
316
- };
317
- }
318
- var EXTERNAL_MARK = "\x1B[35m";
319
- var ANSI_PALETTE = buildPalette({ name: "ansi", description: "", tokens: DEFAULT_TOKENS }, "ansi256");
320
- function roleCode(role, palette, depth) {
321
- if (depth === "none")
322
- return "";
323
- return palette?.[role] || ANSI_PALETTE[role];
324
- }
325
- var NO_COLOR_PALETTE = buildPalette(findBuiltinTheme(DEFAULT_THEME_NAME) ?? { name: DEFAULT_THEME_NAME, description: "", tokens: DEFAULT_TOKENS }, "none");
326
- function parseThemeCommand(input) {
327
- const match = /^\/theme(?:\s+([\s\S]*))?$/.exec(input.trim());
328
- if (!match)
329
- return null;
330
- const rest = (match[1] ?? "").trim().replace(/\s+/g, " ");
331
- if (!rest)
332
- return { kind: "show" };
333
- const [verb, ...words] = rest.split(" ");
334
- switch (verb.toLowerCase()) {
335
- case "list":
336
- return { kind: "list" };
337
- case "show":
338
- return { kind: "show" };
339
- case "where":
340
- return { kind: "where" };
341
- default:
342
- return words.length === 0 ? { kind: "set", name: verb } : { kind: "invalid", reason: `Theme names have no spaces — did you mean /theme ${verb}?` };
343
- }
344
- }
345
-
346
- // packages/archymedes-cli/src/terminal/screen-host.ts
347
- function staticScreenReason(environment) {
348
- if (environment.CI)
349
- return "CI is set";
350
- if (environment.TERM === "dumb")
351
- return "TERM is dumb";
352
- return;
353
- }
354
- function currentScreenCapabilities(interactive, stdout, environment) {
355
- return {
356
- interactive: interactive && Boolean(stdout.isTTY),
357
- columns: stdout.columns ?? 80,
358
- rows: stdout.rows ?? 24,
359
- staticOnly: staticScreenReason(environment)
360
- };
361
- }
362
- var MINIMUM_SCREEN = { columns: 40, rows: 8 };
363
- function canDrawScreen(capabilities) {
364
- if (!capabilities.interactive)
365
- return { ok: false, reason: "not-interactive" };
366
- if (capabilities.staticOnly)
367
- return { ok: false, reason: "static-terminal", detail: capabilities.staticOnly };
368
- if (capabilities.columns < MINIMUM_SCREEN.columns || capabilities.rows < MINIMUM_SCREEN.rows) {
369
- return {
370
- ok: false,
371
- reason: "too-small",
372
- detail: `needs at least ${MINIMUM_SCREEN.columns}×${MINIMUM_SCREEN.rows}, this terminal is ${capabilities.columns}×${capabilities.rows}`
373
- };
374
- }
375
- return { ok: true };
376
- }
377
- function explainScreenRefusal(outcome) {
378
- switch (outcome.reason) {
379
- case "not-interactive":
380
- return "This needs an interactive terminal.";
381
- case "too-small":
382
- return `This needs a bigger window — ${outcome.detail}.`;
383
- case "static-terminal":
384
- return `Full-screen views are off because ${outcome.detail ?? "this terminal cannot run them"}; unset it to use them.`;
385
- case "framework-missing":
386
- return `The screen could not be loaded${outcome.detail ? `: ${outcome.detail}` : ""}.`;
387
- }
388
- }
389
- function exitTopTermUIApp() {
390
- globalThis.__termuijs_apps?.at(-1)?.exit(0);
391
- }
392
- async function withFullScreen(capabilities, controls, open) {
393
- const allowed = canDrawScreen(capabilities);
394
- if (!allowed.ok)
395
- return allowed;
396
- controls.clearStatus();
397
- controls.releaseScreen();
398
- controls.uninstallShortcuts();
399
- controls.pauseInput();
400
- try {
401
- await open();
402
- return { ok: true };
403
- } catch (error) {
404
- return { ok: false, reason: "framework-missing", detail: error instanceof Error ? error.message : String(error) };
405
- } finally {
406
- controls.resumeInput();
407
- controls.installShortcuts();
408
- controls.restoreScreen();
409
- controls.restoreInput?.();
410
- }
411
- }
412
-
413
- // packages/archymedes-cli/src/text/ansi.ts
414
- var RESET = "\x1B[0m";
415
- var BOLD = "\x1B[1m";
416
- var DIM = "\x1B[2m";
417
- var ITALIC = "\x1B[3m";
418
- var STRIKE = "\x1B[9m";
419
- var REVERSE = "\x1B[7m";
420
- function paint(text, code, depth) {
421
- return depth === "none" || code === "" ? text : `${code}${text}${RESET}`;
422
- }
423
- function paintAll(text, codes, depth) {
424
- return depth === "none" || codes.length === 0 ? text : `${codes.join("")}${text}${RESET}`;
425
- }
426
-
427
- // packages/archymedes-cli/src/text/glyphs.ts
428
- var UNICODE_GLYPHS = {
429
- starGlyphs: [".", "·", "✧", "✦", "✶"],
430
- spinnerFrames: [" ◜ ", " ◠ ", " ◝ ", " ◞ ", " ◡ ", " ◟ "],
431
- star: "✦",
432
- starDim: "✧",
433
- check: "✓",
434
- cross: "✗",
435
- pending: "⋯",
436
- prompt: "❯",
437
- caret: "›",
438
- bullet: "•",
439
- ellipsis: "…",
440
- middot: "·",
441
- elbow: "⎿",
442
- boxTopLeft: "╭",
443
- boxTopRight: "╮",
444
- boxBottomLeft: "╰",
445
- boxBottomRight: "╯",
446
- boxHorizontal: "─",
447
- boxVertical: "│",
448
- boxTeeLeft: "├",
449
- boxTeeRight: "┤",
450
- boxCross: "┼",
451
- circleEmpty: "○",
452
- circleHalf: "◐",
453
- circleFull: "●",
454
- checkbox: "☐",
455
- checkboxDone: "☑",
456
- paused: "⏸",
457
- cancelled: "⊘",
458
- treeBranch: "├─",
459
- treeLast: "╰─",
460
- treeTrunk: "│ ",
461
- collapsed: "▸",
462
- expanded: "▾",
463
- arrowUp: "↑",
464
- arrowLeft: "←",
465
- arrowRight: "→",
466
- arrowDown: "↓",
467
- plus: "+",
468
- minus: "-",
469
- warning: "!",
470
- effectWorkspace: "✎",
471
- effectExternal: "◎",
472
- sparkLevels: ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"]
473
- };
474
- var ASCII_GLYPHS = {
475
- starGlyphs: [".", ".", "+", "*", "*"],
476
- spinnerFrames: ["-", "\\", "|", "/"],
477
- star: "*",
478
- starDim: "+",
479
- check: "+",
480
- cross: "x",
481
- pending: "~",
482
- prompt: ">",
483
- caret: ">",
484
- bullet: "-",
485
- ellipsis: "...",
486
- middot: "-",
487
- elbow: "\\",
488
- boxTopLeft: "+",
489
- boxTopRight: "+",
490
- boxBottomLeft: "+",
491
- boxBottomRight: "+",
492
- boxHorizontal: "-",
493
- boxVertical: "|",
494
- boxTeeLeft: "+",
495
- boxTeeRight: "+",
496
- boxCross: "+",
497
- circleEmpty: "o",
498
- circleHalf: "*",
499
- circleFull: "*",
500
- checkbox: "[ ]",
501
- checkboxDone: "[x]",
502
- paused: "=",
503
- cancelled: "x",
504
- treeBranch: "|-",
505
- treeLast: "`-",
506
- treeTrunk: "| ",
507
- collapsed: ">",
508
- expanded: "v",
509
- arrowUp: "^",
510
- arrowLeft: "<-",
511
- arrowRight: "->",
512
- arrowDown: "v",
513
- plus: "+",
514
- minus: "-",
515
- warning: "!",
516
- effectWorkspace: "w",
517
- effectExternal: "e",
518
- sparkLevels: [" ", ".", ":", "-", "=", "+", "*", "#"]
519
- };
520
- var ROUND_BORDER = { topLeft: "╭", topRight: "╮", bottomLeft: "╰", bottomRight: "╯", horizontal: "─", vertical: "│", teeLeft: "├", teeRight: "┤", cross: "┼" };
521
- var SINGLE_BORDER = { topLeft: "┌", topRight: "┐", bottomLeft: "└", bottomRight: "┘", horizontal: "─", vertical: "│", teeLeft: "├", teeRight: "┤", cross: "┼" };
522
- var DOUBLE_BORDER = { topLeft: "╔", topRight: "╗", bottomLeft: "╚", bottomRight: "╝", horizontal: "═", vertical: "║", teeLeft: "╠", teeRight: "╣", cross: "╬" };
523
- var ASCII_BORDER = { topLeft: "+", topRight: "+", bottomLeft: "+", bottomRight: "+", horizontal: "-", vertical: "|", teeLeft: "+", teeRight: "+", cross: "+" };
524
- function borderGlyphsFor(style, glyphs) {
525
- if (glyphs === ASCII_GLYPHS)
526
- return ASCII_BORDER;
527
- if (style === "single")
528
- return SINGLE_BORDER;
529
- if (style === "double")
530
- return DOUBLE_BORDER;
531
- return ROUND_BORDER;
532
- }
533
- function detectGlyphMode(environment, platform = process.platform) {
534
- const forced = environment.ARCHYMEDES_GLYPHS?.trim().toLowerCase();
535
- if (forced === "ascii" || forced === "unicode")
536
- return forced;
537
- if (environment.ARCHYMEDES_ASCII?.trim() && environment.ARCHYMEDES_ASCII !== "0")
538
- return "ascii";
539
- const term = environment.TERM?.trim().toLowerCase();
540
- if (term === "linux" || term === "dumb")
541
- return "ascii";
542
- if (platform === "win32") {
543
- return environment.WT_SESSION || environment.TERMINUS_SUBLIME || environment.ConEmuTask === "{cmd::Cmder}" || environment.TERM_PROGRAM === "vscode" || environment.TERM_PROGRAM === "Terminus-Sublime" || term === "xterm-256color" || term === "alacritty" ? "unicode" : "ascii";
544
- }
545
- const locale = environment.LC_ALL || environment.LC_CTYPE || environment.LANG;
546
- if (!locale?.trim())
547
- return "unicode";
548
- return /utf-?8/i.test(locale) ? "unicode" : "ascii";
549
- }
550
- function glyphsFor(mode) {
551
- return mode === "ascii" ? ASCII_GLYPHS : UNICODE_GLYPHS;
552
- }
553
- function resolveGlyphs(environment, platform = process.platform) {
554
- return glyphsFor(detectGlyphMode(environment, platform));
555
- }
556
-
557
- // packages/archymedes-cli/src/text/text-width.ts
558
- var ANSI = /\x1b\[[0-9;]*m/g;
559
- var PRINTABLE_ASCII = /^[\x20-\x7e]*$/;
560
- function visibleWidth(text) {
561
- if (PRINTABLE_ASCII.test(text))
562
- return text.length;
563
- let width = 0;
564
- for (const character of text.includes("\x1B") ? text.replace(ANSI, "") : text) {
565
- const code = character.codePointAt(0) ?? 0;
566
- if (code >= 768 && code <= 879)
567
- continue;
568
- width += isWide(code) ? 2 : 1;
569
- }
570
- return width;
571
- }
572
- function isWide(code) {
573
- return code >= 4352 && code <= 4447 || code >= 11904 && code <= 42191 || code >= 44032 && code <= 55203 || code >= 63744 && code <= 64255 || code >= 65072 && code <= 65135 || code >= 65280 && code <= 65376 || code >= 127744 && code <= 129535;
574
- }
575
- function clipTo(text, width, glyphs = UNICODE_GLYPHS) {
576
- if (width <= 0)
577
- return "";
578
- if (visibleWidth(text) <= width)
579
- return text;
580
- const mark = visibleWidth(glyphs.ellipsis) < width ? glyphs.ellipsis : "";
581
- const budget = width - visibleWidth(mark);
582
- let out = "";
583
- const segments = typeof Intl.Segmenter === "function" ? [...new Intl.Segmenter(undefined, { granularity: "grapheme" }).segment(text)].map((entry) => entry.segment) : [...text];
584
- for (const segment of segments) {
585
- if (visibleWidth(out + segment) > budget)
586
- break;
587
- out += segment;
588
- }
589
- return `${out}${mark}`;
590
- }
591
-
592
- // packages/archymedes-cli/src/render/syntax.ts
593
- function newSyntaxState() {
594
- return {};
595
- }
596
- var SYNTAX_COLORS = {
597
- dark: {
598
- control: "#C586C0",
599
- declaration: "#569CD6",
600
- string: "#CE9178",
601
- number: "#B5CEA8",
602
- comment: "#6A9955",
603
- function: "#DCDCAA",
604
- type: "#4EC9B0",
605
- property: "#9CDCFE",
606
- decorator: "#DCDCAA",
607
- punctuation: "#808080",
608
- variable: "#9CDCFE",
609
- tag: "#569CD6",
610
- attribute: "#9CDCFE",
611
- inserted: "#81B88B",
612
- deleted: "#E06C75",
613
- meta: "#C586C0"
614
- },
615
- light: {
616
- control: "#AF00DB",
617
- declaration: "#0000FF",
618
- string: "#A31515",
619
- number: "#098658",
620
- comment: "#008000",
621
- function: "#795E26",
622
- type: "#267F99",
623
- property: "#001080",
624
- decorator: "#795E26",
625
- punctuation: "#6E6E6E",
626
- variable: "#001080",
627
- tag: "#800000",
628
- attribute: "#E50000",
629
- inserted: "#587C0C",
630
- deleted: "#AD0707",
631
- meta: "#AF00DB"
632
- }
633
- };
634
- var DIFF_BACKGROUNDS = {
635
- dark: { add: "#1E3A26", addStrong: "#2E6B3E", remove: "#4B1D1D", removeStrong: "#7A2B2B" },
636
- light: { add: "#E6FFEC", addStrong: "#ABF2BC", remove: "#FFEBE9", removeStrong: "#FFC1BD" }
637
- };
638
- function schemeFor(palette) {
639
- const background = palette?.tokens?.bg ?? palette?.bg;
640
- if (!background)
641
- return "dark";
642
- const parsed = parseColor(background);
643
- if (parsed === undefined)
644
- return "dark";
645
- if (typeof parsed === "number")
646
- return parsed === 7 || parsed === 15 ? "light" : "dark";
647
- const channel = (value) => {
648
- const scaled = value / 255;
649
- return scaled <= 0.03928 ? scaled / 12.92 : ((scaled + 0.055) / 1.055) ** 2.4;
650
- };
651
- const luminance = 0.2126 * channel(parsed.r) + 0.7152 * channel(parsed.g) + 0.0722 * channel(parsed.b);
652
- return luminance > 0.4 ? "light" : "dark";
653
- }
654
- function backgroundCode(value, depth) {
655
- if (depth === "none")
656
- return "";
657
- const parsed = parseColor(value);
658
- if (parsed === undefined)
659
- return "";
660
- if (typeof parsed === "number")
661
- return parsed < 8 ? `\x1B[${40 + parsed}m` : `\x1B[${100 + parsed - 8}m`;
662
- return depth === "truecolor" ? `\x1B[48;2;${parsed.r};${parsed.g};${parsed.b}m` : `\x1B[48;5;${rgbTo256(parsed)}m`;
663
- }
664
- var DEFAULT_CODE_STYLE = { colors: "vscode", lineNumbers: true };
665
- var currentCodeStyle = { ...DEFAULT_CODE_STYLE };
666
- function codeStyleFromEnvironment(environment) {
667
- const colors = environment.ARCHYMEDES_CODE_COLORS?.trim().toLowerCase();
668
- const numbers = environment.ARCHYMEDES_CODE_LINE_NUMBERS?.trim().toLowerCase();
669
- return {
670
- colors: colors === "theme" ? "theme" : "vscode",
671
- lineNumbers: !(numbers === "off" || numbers === "false" || numbers === "0" || numbers === "no")
672
- };
673
- }
674
- function setCodeStyle(style) {
675
- currentCodeStyle = { ...currentCodeStyle, ...style };
676
- }
677
- function codeStyle() {
678
- return currentCodeStyle;
679
- }
680
- var words = (text) => new Set(text.split(/\s+/).filter(Boolean));
681
- var JS_CONTROL = words("if else for while do switch case default break continue return throw try catch finally await yield import export from as of with debugger");
682
- var JS_DECLARATION = words("const let var function class interface type enum extends implements new this super true false null undefined async static public private protected readonly abstract declare namespace module typeof instanceof in void delete keyof get set is satisfies infer override accessor");
683
- var JS_TYPES = words("string number boolean any unknown never object symbol bigint Array Promise Record Partial Readonly Map Set Date Error RegExp");
684
- var PY_CONTROL = words("if elif else for while break continue return try except finally raise with import from pass yield await assert del match case");
685
- var PY_DECLARATION = words("def class lambda global nonlocal async None True False self cls and or not in is as");
686
- var PY_TYPES = words("int str float bool list dict tuple set frozenset bytes bytearray object type Exception ValueError TypeError KeyError Optional List Dict Any");
687
- var RUST_CONTROL = words("if else match for while loop break continue return use mod in as await");
688
- var RUST_DECLARATION = words("fn let mut const static struct enum trait impl pub crate self Self super where type ref move unsafe async dyn true false extern");
689
- var RUST_TYPES = words("i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize f32 f64 bool char str String Vec Option Result Box Rc Arc HashMap HashSet");
690
- var GO_CONTROL = words("if else for range switch case default break continue return go defer select fallthrough goto import package");
691
- var GO_DECLARATION = words("func var const type struct interface map chan true false nil iota");
692
- var GO_TYPES = words("int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 uintptr float32 float64 complex64 complex128 string bool byte rune error any");
693
- var C_CONTROL = words("if else for foreach while do switch case default break continue return throw try catch finally goto using import package include when yield await");
694
- var C_DECLARATION = words("class struct interface enum record public private protected internal static final const readonly virtual override abstract sealed new this base super true false null nullptr void var val fun func let typedef template typename auto extern inline volatile unsigned signed operator namespace sizeof async in out ref is as object companion data open lateinit suspend");
695
- var C_TYPES = words("int long short char float double bool boolean byte string String Object decimal uint ulong size_t Integer Boolean List Map Set Task");
696
- var SHELL_CONTROL = words("if then else elif fi for in do done while until case esac function return exit break continue select");
697
- var SHELL_DECLARATION = words("export local readonly declare alias unset source set true false");
698
- var PS_CONTROL = words("if elseif else foreach for while do until switch break continue return try catch finally throw trap exit param begin process end filter in");
699
- var PS_DECLARATION = words("function class enum $true $false $null");
700
- var SQL_DECLARATION = words("select from where insert into values update set delete create table alter drop index join inner left right outer full cross on group by order having limit offset as and or not null is in like between distinct union all primary key foreign references default case when then else end begin commit rollback with returning exists view if replace asc desc unique check constraint transaction");
701
- var SQL_TYPES = words("int integer smallint bigint varchar char text boolean bool date time timestamp timestamptz serial bigserial numeric decimal real double float json jsonb uuid blob");
702
- var YAML_DECLARATION = words("true false null yes no on off True False Null");
703
- var EMPTY = new Set;
704
- var GRAMMARS = {
705
- javascript: { lineComments: ["//"], block: ["/*", "*/"], quotes: "\"'`", control: JS_CONTROL, declaration: JS_DECLARATION, types: JS_TYPES, decorators: true, wordExtra: "$" },
706
- python: { lineComments: ["#"], quotes: `"'`, triple: true, control: PY_CONTROL, declaration: PY_DECLARATION, types: PY_TYPES, decorators: true },
707
- rust: { lineComments: ["//"], block: ["/*", "*/"], quotes: `"'`, control: RUST_CONTROL, declaration: RUST_DECLARATION, types: RUST_TYPES, lifetimes: true, decorators: false },
708
- go: { lineComments: ["//"], block: ["/*", "*/"], quotes: "\"'`", control: GO_CONTROL, declaration: GO_DECLARATION, types: GO_TYPES },
709
- c: { lineComments: ["//"], block: ["/*", "*/"], quotes: `"'`, control: C_CONTROL, declaration: C_DECLARATION, types: C_TYPES, decorators: true },
710
- shell: { lineComments: ["#"], quotes: `"'`, control: SHELL_CONTROL, declaration: SHELL_DECLARATION, dollarVariables: true, commandFirst: true, hashNeedsSpace: true },
711
- powershell: { lineComments: ["#"], block: ["<#", "#>"], quotes: `"'`, control: PS_CONTROL, declaration: PS_DECLARATION, dollarVariables: true, caseInsensitive: true, wordExtra: "-" },
712
- sql: { lineComments: ["--"], block: ["/*", "*/"], quotes: `'"`, control: EMPTY, declaration: SQL_DECLARATION, types: SQL_TYPES, caseInsensitive: true },
713
- json: { lineComments: ["//"], block: ["/*", "*/"], quotes: '"', control: EMPTY, declaration: words("true false null") },
714
- yaml: { lineComments: ["#"], quotes: `"'`, control: EMPTY, declaration: YAML_DECLARATION, hashNeedsSpace: true },
715
- toml: { lineComments: ["#", ";"], quotes: `"'`, control: EMPTY, declaration: words("true false"), hashNeedsSpace: true },
716
- ruby: { lineComments: ["#"], quotes: `"'`, control: words("if elsif else unless case when while until for in do end begin rescue ensure return break next redo retry yield then require require_relative"), declaration: words("def class module self nil true false and or not attr_accessor attr_reader private public protected"), dollarVariables: false },
717
- lua: { lineComments: ["--"], quotes: `"'`, control: words("if then else elseif end for while do repeat until return break goto in"), declaration: words("function local nil true false and or not self") },
718
- dockerfile: { lineComments: ["#"], quotes: `"'`, control: words("FROM RUN CMD LABEL EXPOSE ENV ADD COPY ENTRYPOINT VOLUME USER WORKDIR ARG ONBUILD STOPSIGNAL HEALTHCHECK SHELL AS"), declaration: EMPTY, dollarVariables: true },
719
- makefile: { lineComments: ["#"], quotes: `"'`, control: words("ifeq ifneq ifdef ifndef else endif include define endef export"), declaration: EMPTY, dollarVariables: true },
720
- generic: { lineComments: ["//", "#"], block: ["/*", "*/"], quotes: "\"'`", control: words("if else elif for while do switch case break continue return throw try catch finally import from export yield await match raise"), declaration: words("const let var function def fn func class struct enum interface type impl trait pub public private static new this self true false null nil None True False undefined async"), types: EMPTY }
721
- };
722
- var LANGUAGE_ALIASES = {
723
- js: "javascript",
724
- javascript: "javascript",
725
- jsx: "javascript",
726
- mjs: "javascript",
727
- cjs: "javascript",
728
- ts: "javascript",
729
- typescript: "javascript",
730
- tsx: "javascript",
731
- mts: "javascript",
732
- cts: "javascript",
733
- node: "javascript",
734
- py: "python",
735
- python: "python",
736
- python3: "python",
737
- py3: "python",
738
- rs: "rust",
739
- rust: "rust",
740
- go: "go",
741
- golang: "go",
742
- java: "c",
743
- kotlin: "c",
744
- kt: "c",
745
- kts: "c",
746
- c: "c",
747
- h: "c",
748
- cpp: "c",
749
- "c++": "c",
750
- cc: "c",
751
- cxx: "c",
752
- hpp: "c",
753
- cs: "c",
754
- csharp: "c",
755
- "c#": "c",
756
- swift: "c",
757
- scala: "c",
758
- dart: "c",
759
- php: "c",
760
- groovy: "c",
761
- objc: "c",
762
- "objective-c": "c",
763
- sh: "shell",
764
- bash: "shell",
765
- zsh: "shell",
766
- fish: "shell",
767
- shell: "shell",
768
- console: "shell",
769
- shellsession: "shell",
770
- terminal: "shell",
771
- ps: "powershell",
772
- ps1: "powershell",
773
- psm1: "powershell",
774
- powershell: "powershell",
775
- pwsh: "powershell",
776
- sql: "sql",
777
- psql: "sql",
778
- mysql: "sql",
779
- sqlite: "sql",
780
- postgres: "sql",
781
- postgresql: "sql",
782
- json: "json",
783
- jsonc: "json",
784
- json5: "json",
785
- jsonl: "json",
786
- yaml: "yaml",
787
- yml: "yaml",
788
- toml: "toml",
789
- ini: "toml",
790
- cfg: "toml",
791
- conf: "toml",
792
- properties: "toml",
793
- env: "toml",
794
- dotenv: "toml",
795
- rb: "ruby",
796
- ruby: "ruby",
797
- lua: "lua",
798
- dockerfile: "dockerfile",
799
- docker: "dockerfile",
800
- makefile: "makefile",
801
- make: "makefile",
802
- mk: "makefile",
803
- html: "markup",
804
- htm: "markup",
805
- xml: "markup",
806
- svg: "markup",
807
- xhtml: "markup",
808
- vue: "markup",
809
- svelte: "markup",
810
- css: "css",
811
- scss: "css",
812
- sass: "css",
813
- less: "css",
814
- diff: "diff",
815
- patch: "diff",
816
- udiff: "diff"
817
- };
818
- function grammarName(language) {
819
- const key = (language ?? "").trim().toLowerCase().split(/[\s{,]/)[0] ?? "";
820
- return LANGUAGE_ALIASES[key] ?? "generic";
821
- }
822
- var PUNCTUATION = new Set([..."{}[]()<>;,.:=+-*/%!&|^~?\\"]);
823
- function push(tokens, text, kind) {
824
- if (!text)
825
- return;
826
- const last = tokens[tokens.length - 1];
827
- if (last && last.kind === kind)
828
- last.text += text;
829
- else
830
- tokens.push({ text, kind });
831
- }
832
- function nextNonSpace(line, from) {
833
- for (let index = from;index < line.length; index += 1)
834
- if (line[index] !== " " && line[index] !== "\t")
835
- return line[index];
836
- return "";
837
- }
838
- function previousNonSpace(line, from) {
839
- for (let index = from;index >= 0; index -= 1)
840
- if (line[index] !== " " && line[index] !== "\t")
841
- return line[index];
842
- return "";
843
- }
844
- function tokenizeLine(line, language, state = {}) {
845
- const family = grammarName(language);
846
- if (family === "markup")
847
- return tokenizeMarkup(line, state);
848
- if (family === "css")
849
- return tokenizeCss(line, state);
850
- if (family === "diff")
851
- return tokenizeDiff(line);
852
- return tokenizeCode(line, GRAMMARS[family] ?? GRAMMARS.generic, family, state);
853
- }
854
- function tokenizeDiff(line) {
855
- if (line.startsWith("+++") || line.startsWith("---") || line.startsWith("diff ") || line.startsWith("index "))
856
- return [{ text: line, kind: "meta" }];
857
- if (line.startsWith("@@"))
858
- return [{ text: line, kind: "type" }];
859
- if (line.startsWith("+"))
860
- return [{ text: line, kind: "inserted" }];
861
- if (line.startsWith("-"))
862
- return [{ text: line, kind: "deleted" }];
863
- return line ? [{ text: line, kind: "plain" }] : [];
864
- }
865
- function tokenizeCode(line, grammar, family, state) {
866
- const tokens = [];
867
- let index = 0;
868
- if (state.blockEnd) {
869
- const end = line.indexOf(state.blockEnd);
870
- const kind = state.blockKind === "string" ? "string" : "comment";
871
- if (end === -1) {
872
- push(tokens, line, kind);
873
- return tokens;
874
- }
875
- push(tokens, line.slice(0, end + state.blockEnd.length), kind);
876
- index = end + state.blockEnd.length;
877
- state.blockEnd = undefined;
878
- state.blockKind = undefined;
879
- } else if (grammar.block?.[0] === "/*" && /^\s*\*(?:\s|\/|$)/.test(line)) {
880
- push(tokens, line, "comment");
881
- return tokens;
882
- }
883
- const isWordStart = (character) => /[A-Za-z_]/.test(character) || grammar.wordExtra?.includes("$") === true && character === "$";
884
- const isWordPart = (character) => /[\w]/.test(character) || grammar.wordExtra !== undefined && grammar.wordExtra.includes(character);
885
- let firstWord = true;
886
- while (index < line.length) {
887
- const character = line[index];
888
- const rest = line.slice(index);
889
- if (character === " " || character === "\t") {
890
- let end = index;
891
- while (end < line.length && (line[end] === " " || line[end] === "\t"))
892
- end += 1;
893
- push(tokens, line.slice(index, end), "plain");
894
- index = end;
895
- continue;
896
- }
897
- if (grammar.block && rest.startsWith(grammar.block[0])) {
898
- const end = line.indexOf(grammar.block[1], index + grammar.block[0].length);
899
- if (end === -1) {
900
- push(tokens, rest, "comment");
901
- state.blockEnd = grammar.block[1];
902
- state.blockKind = "comment";
903
- return tokens;
904
- }
905
- push(tokens, line.slice(index, end + grammar.block[1].length), "comment");
906
- index = end + grammar.block[1].length;
907
- continue;
908
- }
909
- const lineComment = grammar.lineComments.find((marker) => rest.startsWith(marker));
910
- if (lineComment) {
911
- const atWordStart = index === 0 || /\s/.test(line[index - 1]);
912
- const shebang = family === "shell" && index === 0 && rest.startsWith("#!");
913
- if (shebang || !grammar.hashNeedsSpace || lineComment !== "#" || atWordStart) {
914
- push(tokens, rest, "comment");
915
- return tokens;
916
- }
917
- }
918
- if (grammar.triple && (rest.startsWith('"""') || rest.startsWith("'''"))) {
919
- const fence = rest.slice(0, 3);
920
- const end = line.indexOf(fence, index + 3);
921
- if (end === -1) {
922
- push(tokens, rest, "string");
923
- state.blockEnd = fence;
924
- state.blockKind = "string";
925
- return tokens;
926
- }
927
- push(tokens, line.slice(index, end + 3), "string");
928
- index = end + 3;
929
- continue;
930
- }
931
- if (grammar.lifetimes && character === "'") {
932
- const charLiteral = /^'(?:\\.|[^\\'])'/.exec(rest);
933
- if (!charLiteral) {
934
- const lifetime = /^'[A-Za-z_]\w*/.exec(rest);
935
- if (lifetime) {
936
- push(tokens, lifetime[0], "declaration");
937
- index += lifetime[0].length;
938
- continue;
939
- }
940
- }
941
- }
942
- if (grammar.quotes.includes(character)) {
943
- let end = index + 1;
944
- while (end < line.length) {
945
- if (line[end] === "\\") {
946
- end += 2;
947
- continue;
948
- }
949
- if (line[end] === character) {
950
- end += 1;
951
- break;
952
- }
953
- end += 1;
954
- }
955
- const text = line.slice(index, Math.min(end, line.length));
956
- const isKey = (family === "json" || family === "yaml") && nextNonSpace(line, index + text.length) === ":";
957
- push(tokens, text, isKey ? "property" : "string");
958
- index += text.length;
959
- firstWord = false;
960
- continue;
961
- }
962
- if (grammar.decorators && character === "@" && /[A-Za-z_]/.test(line[index + 1] ?? "")) {
963
- const match = /^@[\w.]+/.exec(rest);
964
- push(tokens, match[0], "decorator");
965
- index += match[0].length;
966
- continue;
967
- }
968
- if (grammar.dollarVariables && character === "$") {
969
- const match = /^\$(?:\{[^}]*\}|[A-Za-z_][\w:]*|[0-9#?@*!$-])/.exec(rest);
970
- if (match) {
971
- const text = match[0];
972
- const lowered = text.toLowerCase();
973
- push(tokens, text, grammar.declaration.has(lowered) ? "declaration" : "variable");
974
- index += text.length;
975
- firstWord = false;
976
- continue;
977
- }
978
- }
979
- if (/[0-9]/.test(character) || character === "." && /[0-9]/.test(line[index + 1] ?? "") && !/[\w)]/.test(line[index - 1] ?? "")) {
980
- const match = /^(?:0[xX][\da-fA-F_]+|0[bB][01_]+|0[oO][0-7_]+|(?:\d[\d_]*)?\.?\d[\d_]*(?:[eE][+-]?\d+)?)[a-zA-Z%]*/.exec(rest);
981
- if (match && match[0]) {
982
- push(tokens, match[0], "number");
983
- index += match[0].length;
984
- firstWord = false;
985
- continue;
986
- }
987
- }
988
- if (isWordStart(character) || grammar.wordExtra?.includes("-") && character === "-" && /[A-Za-z]/.test(line[index + 1] ?? "") && !isWordPart(line[index - 1] ?? " ")) {
989
- let end = index + 1;
990
- while (end < line.length && isWordPart(line[end]))
991
- end += 1;
992
- const word = line.slice(index, end);
993
- push(tokens, word, classifyWord(word, line, index, end, grammar, family, firstWord));
994
- index = end;
995
- firstWord = false;
996
- continue;
997
- }
998
- if (PUNCTUATION.has(character)) {
999
- push(tokens, character, "punctuation");
1000
- if (character === "|" || character === ";" || character === "&" || character === "(")
1001
- firstWord = true;
1002
- index += 1;
1003
- continue;
1004
- }
1005
- push(tokens, character, "plain");
1006
- index += 1;
1007
- }
1008
- return tokens;
1009
- }
1010
- function classifyWord(word, line, start, end, grammar, family, firstWord) {
1011
- const lookup = grammar.caseInsensitive ? word.toLowerCase() : word;
1012
- const after = nextNonSpace(line, end);
1013
- const before = previousNonSpace(line, start - 1);
1014
- if (family === "yaml" && after === ":" && /^\s*(?:-\s+)?$/.test(line.slice(0, start)) || family === "toml" && after === "=" && /^\s*$/.test(line.slice(0, start)))
1015
- return "property";
1016
- if (family === "toml" && /^\s*\[/.test(line))
1017
- return "type";
1018
- if (family === "powershell") {
1019
- if (word.startsWith("-"))
1020
- return "declaration";
1021
- if (/^[A-Za-z]+-[A-Za-z]+$/.test(word))
1022
- return "function";
1023
- }
1024
- if (grammar.control.has(lookup))
1025
- return "control";
1026
- if (grammar.declaration.has(lookup))
1027
- return "declaration";
1028
- if (grammar.types?.has(lookup))
1029
- return "type";
1030
- if (family === "rust" && line[end] === "!")
1031
- return "function";
1032
- if (before === "." && after !== "(")
1033
- return "property";
1034
- if (after === "(")
1035
- return "function";
1036
- if (family === "shell" && firstWord)
1037
- return "function";
1038
- if (family === "makefile" && after === ":" && start === 0)
1039
- return "function";
1040
- if (/^[A-Z][a-z0-9]/.test(word) && family !== "sql" && family !== "yaml")
1041
- return "type";
1042
- return "plain";
1043
- }
1044
- function tokenizeMarkup(line, state) {
1045
- const tokens = [];
1046
- let index = 0;
1047
- if (state.blockEnd === "-->") {
1048
- const end = line.indexOf("-->");
1049
- if (end === -1)
1050
- return [{ text: line, kind: "comment" }];
1051
- push(tokens, line.slice(0, end + 3), "comment");
1052
- index = end + 3;
1053
- state.blockEnd = undefined;
1054
- }
1055
- while (index < line.length) {
1056
- const rest = line.slice(index);
1057
- if (rest.startsWith("<!--")) {
1058
- const end = line.indexOf("-->", index + 4);
1059
- if (end === -1) {
1060
- push(tokens, rest, "comment");
1061
- state.blockEnd = "-->";
1062
- return tokens;
1063
- }
1064
- push(tokens, line.slice(index, end + 3), "comment");
1065
- index = end + 3;
1066
- continue;
1067
- }
1068
- const tag = /^(<\/?)([A-Za-z][\w:.-]*)/.exec(rest);
1069
- if (tag) {
1070
- push(tokens, tag[1], "punctuation");
1071
- push(tokens, tag[2], /^[A-Z]/.test(tag[2]) ? "type" : "tag");
1072
- index += tag[0].length;
1073
- while (index < line.length) {
1074
- const inner = line.slice(index);
1075
- const close = /^\s*\/?>/.exec(inner);
1076
- if (close) {
1077
- push(tokens, close[0], "punctuation");
1078
- index += close[0].length;
1079
- break;
1080
- }
1081
- const attribute = /^(\s+)([^\s=>/]+)/.exec(inner);
1082
- if (attribute) {
1083
- push(tokens, attribute[1], "plain");
1084
- push(tokens, attribute[2], "attribute");
1085
- index += attribute[0].length;
1086
- continue;
1087
- }
1088
- const value = /^(\s*=\s*)("[^"]*"?|'[^']*'?|[^\s>]+)/.exec(inner);
1089
- if (value) {
1090
- push(tokens, value[1], "punctuation");
1091
- push(tokens, value[2], "string");
1092
- index += value[0].length;
1093
- continue;
1094
- }
1095
- push(tokens, inner[0], "plain");
1096
- index += 1;
1097
- }
1098
- continue;
1099
- }
1100
- const entity = /^&[#\w]+;/.exec(rest);
1101
- if (entity) {
1102
- push(tokens, entity[0], "number");
1103
- index += entity[0].length;
1104
- continue;
1105
- }
1106
- const text = /^[^<&]+/.exec(rest);
1107
- if (text) {
1108
- push(tokens, text[0], "plain");
1109
- index += text[0].length;
1110
- continue;
1111
- }
1112
- push(tokens, rest[0], "punctuation");
1113
- index += 1;
1114
- }
1115
- return tokens;
1116
- }
1117
- function tokenizeCss(line, state) {
1118
- const tokens = [];
1119
- let index = 0;
1120
- if (state.blockEnd === "*/") {
1121
- const end = line.indexOf("*/");
1122
- if (end === -1)
1123
- return [{ text: line, kind: "comment" }];
1124
- push(tokens, line.slice(0, end + 2), "comment");
1125
- index = end + 2;
1126
- state.blockEnd = undefined;
1127
- }
1128
- const declaration = /^\s*[-\w]+\s*:(?!:)/.test(line.slice(index)) && !/\{\s*$/.test(line);
1129
- let seenColon = false;
1130
- while (index < line.length) {
1131
- const rest = line.slice(index);
1132
- const character = line[index];
1133
- if (rest.startsWith("/*")) {
1134
- const end = line.indexOf("*/", index + 2);
1135
- if (end === -1) {
1136
- push(tokens, rest, "comment");
1137
- state.blockEnd = "*/";
1138
- return tokens;
1139
- }
1140
- push(tokens, line.slice(index, end + 2), "comment");
1141
- index = end + 2;
1142
- continue;
1143
- }
1144
- if (rest.startsWith("//")) {
1145
- push(tokens, rest, "comment");
1146
- return tokens;
1147
- }
1148
- if (character === '"' || character === "'") {
1149
- const end = line.indexOf(character, index + 1);
1150
- const text = line.slice(index, end === -1 ? line.length : end + 1);
1151
- push(tokens, text, "string");
1152
- index += text.length;
1153
- continue;
1154
- }
1155
- const at = /^@[\w-]+/.exec(rest);
1156
- if (at) {
1157
- push(tokens, at[0], "control");
1158
- index += at[0].length;
1159
- continue;
1160
- }
1161
- const hex = /^#[\da-fA-F]{3,8}\b/.exec(rest);
1162
- if (hex && (declaration && seenColon)) {
1163
- push(tokens, hex[0], "number");
1164
- index += hex[0].length;
1165
- continue;
1166
- }
1167
- const number = /^-?\d*\.?\d+(?:%|[a-zA-Z]+)?/.exec(rest);
1168
- if (number && /[\d.]/.test(rest[0] === "-" ? rest[1] ?? "" : rest[0]) && !/[\w-]/.test(line[index - 1] ?? "")) {
1169
- push(tokens, number[0], "number");
1170
- index += number[0].length;
1171
- continue;
1172
- }
1173
- const word = /^-?-?[A-Za-z_][\w-]*/.exec(rest);
1174
- if (word) {
1175
- let kind;
1176
- if (declaration && !seenColon)
1177
- kind = "property";
1178
- else if (declaration)
1179
- kind = nextNonSpace(line, index + word[0].length) === "(" ? "function" : "plain";
1180
- else
1181
- kind = "tag";
1182
- push(tokens, word[0], kind);
1183
- index += word[0].length;
1184
- continue;
1185
- }
1186
- if (character === ":" && declaration)
1187
- seenColon = true;
1188
- push(tokens, character, PUNCTUATION.has(character) || character === "#" ? "punctuation" : "plain");
1189
- index += 1;
1190
- }
1191
- return tokens;
1192
- }
1193
- function foreground(kind, scheme, depth) {
1194
- if (kind === "plain")
1195
- return "";
1196
- return colorCode(SYNTAX_COLORS[scheme][kind], depth);
1197
- }
1198
- function highlightSyntax(line, options) {
1199
- const { depth } = options;
1200
- const tokens = tokenizeLine(line, options.language, options.state ?? {});
1201
- if (depth === "none")
1202
- return line;
1203
- const scheme = schemeFor(options.palette);
1204
- if (!options.band) {
1205
- return tokens.map((token) => {
1206
- const code = foreground(token.kind, scheme, depth);
1207
- if (token.kind === "comment")
1208
- return paintAll(token.text, [code, ITALIC], depth);
1209
- return paint(token.text, code, depth);
1210
- }).join("");
1211
- }
1212
- const backgrounds = DIFF_BACKGROUNDS[scheme];
1213
- const lineBackground = backgroundCode(options.band === "add" ? backgrounds.add : backgrounds.remove, depth);
1214
- const strongBackground = backgroundCode(options.band === "add" ? backgrounds.addStrong : backgrounds.removeStrong, depth);
1215
- const changedAt = [];
1216
- if (options.segments)
1217
- for (const segment of options.segments)
1218
- for (let count = 0;count < segment.text.length; count += 1)
1219
- changedAt.push(segment.changed);
1220
- let out = lineBackground;
1221
- let offset = 0;
1222
- let activeBackground = lineBackground;
1223
- for (const token of tokens) {
1224
- const code = foreground(token.kind, scheme, depth);
1225
- const italic = token.kind === "comment";
1226
- let runStart = 0;
1227
- while (runStart < token.text.length) {
1228
- const strong = changedAt[offset + runStart] === true;
1229
- let runEnd = runStart + 1;
1230
- while (runEnd < token.text.length && changedAt[offset + runEnd] === true === strong)
1231
- runEnd += 1;
1232
- const background = strong ? strongBackground : lineBackground;
1233
- if (background !== activeBackground) {
1234
- out += background;
1235
- activeBackground = background;
1236
- }
1237
- out += `${code}${italic ? ITALIC : ""}${token.text.slice(runStart, runEnd)}${code ? "\x1B[39m" : ""}${italic ? "\x1B[23m" : ""}`;
1238
- runStart = runEnd;
1239
- }
1240
- offset += token.text.length;
1241
- }
1242
- if (activeBackground !== lineBackground)
1243
- out += lineBackground;
1244
- const width = [...line].length;
1245
- if (options.padTo !== undefined && options.padTo > width)
1246
- out += " ".repeat(options.padTo - width);
1247
- return `${out}${RESET}`;
1248
- }
1249
-
1250
- export { BUILTIN_THEME_SOURCES, parseColor, rgbTo256, colorCode, rainbowHex, rainbowText, parseThemeSource, builtinThemes, EXTERNAL_MARK, ANSI_PALETTE, roleCode, NO_COLOR_PALETTE, parseThemeCommand, RESET, BOLD, DIM, ITALIC, STRIKE, REVERSE, paint, paintAll, UNICODE_GLYPHS, ASCII_GLYPHS, borderGlyphsFor, resolveGlyphs, visibleWidth, clipTo, newSyntaxState, codeStyleFromEnvironment, setCodeStyle, codeStyle, highlightSyntax, currentScreenCapabilities, explainScreenRefusal, exitTopTermUIApp, withFullScreen };