archymedes-cli 2.2.0 → 2.3.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 +17 -7
- package/dist/{archymedes-wjaqydyg.mjs → archymedes-4kx65anz.mjs} +5 -20
- package/dist/{archymedes-5zn4zp84.mjs → archymedes-a10k8yrk.mjs} +43 -225
- package/dist/{archymedes-76z6n643.mjs → archymedes-aj30app4.mjs} +160 -150
- package/dist/{archymedes-0jxzsh4z.mjs → archymedes-d5wqcmdr.mjs} +97 -97
- package/dist/{archymedes-sc3mwttb.mjs → archymedes-dz59nvw7.mjs} +52 -21
- package/dist/{archymedes-r54qthg5.mjs → archymedes-g8y3rt6t.mjs} +376 -25
- package/dist/{archymedes-1g1y6q74.mjs → archymedes-h13ap0za.mjs} +1 -1
- package/dist/archymedes-main.mjs +17452 -14872
- package/dist/{archymedes-npcrm9a0.mjs → archymedes-sf9t1hz9.mjs} +479 -50
- package/dist/{archymedes-cdgejs3p.mjs → archymedes-tsne2m7p.mjs} +17 -44
- package/dist/{archymedes-pg3pvh9r.mjs → archymedes-twbks7g3.mjs} +5 -5
- package/dist/{editor-screen-1b3z96tn.mjs → editor-screen-g08zzt70.mjs} +20 -19
- package/dist/{factory-96yy6mxr.mjs → factory-7vtm2fed.mjs} +326 -326
- package/dist/{file-screen-m7q1xcer.mjs → file-screen-ma9yxq2b.mjs} +7 -7
- package/dist/guide-screen-gd129txd.mjs +271 -0
- package/dist/{index-teq1cta4.mjs → index-qvgcwsvm.mjs} +1 -1
- package/dist/{node-0fh63p8z.mjs → node-mdgzx68h.mjs} +7 -7
- package/dist/{sandbox-templates-8sd1psez.mjs → sandbox-templates-9jcjws23.mjs} +2 -2
- package/dist/{workspace-screen-w88mcw4w.mjs → workspace-screen-8cwk6jz9.mjs} +7 -7
- package/package.json +2 -2
- package/dist/guide-screen-aj9n9v80.mjs +0 -569
package/README.md
CHANGED
|
@@ -312,13 +312,23 @@ The startup geometry makes a brief rotation on roomy interactive terminals. Set
|
|
|
312
312
|
|
|
313
313
|
## Fixed workspace
|
|
314
314
|
|
|
315
|
-
|
|
316
|
-
that open inside the transcript area. `/layout` switches layouts during a session;
|
|
317
|
-
`ARCHYMEDES_LAYOUT=
|
|
318
|
-
|
|
319
|
-
Use `/mode` to choose plan, build, auto, or defender with the arrow keys.
|
|
320
|
-
|
|
321
|
-
|
|
315
|
+
Interactive sessions open in the fixed workspace: a persistent mode bar, an anchored composer, and
|
|
316
|
+
menus that open inside the transcript area. `/layout` switches layouts during a session;
|
|
317
|
+
`archymedes --layout scrollback` or `ARCHYMEDES_LAYOUT=scrollback` keeps the plain terminal log.
|
|
318
|
+
|
|
319
|
+
Use `/mode` to choose plan, build, auto, or defender with the arrow keys. To read history, use the
|
|
320
|
+
mouse wheel or Page Up / Page Down. Alt+Up / Alt+Down (or Ctrl) move one line, and Ctrl+Home jumps
|
|
321
|
+
to the top. Escape, Ctrl+End, or scrolling back to the bottom returns to live output. History keeps
|
|
322
|
+
its colours, a scrollbar shows your position, and the header counts output that arrived while you
|
|
323
|
+
were reading. Arrow keys, Home and End still edit the composer. Wheel scrolling uses mouse
|
|
324
|
+
reporting, so hold Shift to select text, or set `ARCHYMEDES_MOUSE=0` to keep the terminal's own
|
|
325
|
+
selection. Each tab retains up to 5,000 output lines, and resizing reflows the transcript.
|
|
326
|
+
|
|
327
|
+
`/find <text>` searches the tab's history and jumps to the first match; `/find` again moves to the
|
|
328
|
+
next one, `/find prev` to the previous, and `/find off` or Escape returns to live output. `/pager`
|
|
329
|
+
opens the whole transcript in `$PAGER` (`less -R` by default). `/cat image.png` draws a PNG in the
|
|
330
|
+
transcript with coloured half-blocks; in the scrollback layout, `ARCHYMEDES_IMAGES=kitty` uses Kitty
|
|
331
|
+
graphics for real pixels, and `/clear` removes them.
|
|
322
332
|
|
|
323
333
|
The opening geometry rotates while the workspace is idle and settles as soon as you type.
|
|
324
334
|
`ARCHYMEDES_NO_MOTION=1` disables this motion and menu focus animation. `--ascii`, `NO_COLOR`,
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SpringAnimator,
|
|
3
3
|
paginator
|
|
4
|
-
} from "./archymedes-
|
|
4
|
+
} from "./archymedes-g8y3rt6t.mjs";
|
|
5
5
|
import {
|
|
6
6
|
UNICODE_GLYPHS,
|
|
7
|
+
clipTo,
|
|
7
8
|
visibleWidth
|
|
8
|
-
} from "./archymedes-
|
|
9
|
+
} from "./archymedes-a10k8yrk.mjs";
|
|
9
10
|
|
|
10
|
-
//
|
|
11
|
+
// src/ui/chooser.ts
|
|
11
12
|
var ALL_CHROME = { title: true, status: true, pagination: true, help: true };
|
|
12
13
|
function chromeOf(chrome) {
|
|
13
14
|
return { ...ALL_CHROME, ...chrome };
|
|
@@ -150,22 +151,6 @@ function renderChooser(state, items, options) {
|
|
|
150
151
|
return lines.join(`
|
|
151
152
|
`);
|
|
152
153
|
}
|
|
153
|
-
function clipTo(text, width, glyphs = UNICODE_GLYPHS) {
|
|
154
|
-
if (width <= 0)
|
|
155
|
-
return "";
|
|
156
|
-
if (visibleWidth(text) <= width)
|
|
157
|
-
return text;
|
|
158
|
-
const mark = visibleWidth(glyphs.ellipsis) < width ? glyphs.ellipsis : "";
|
|
159
|
-
const budget = width - visibleWidth(mark);
|
|
160
|
-
let out = "";
|
|
161
|
-
const segments = typeof Intl.Segmenter === "function" ? [...new Intl.Segmenter(undefined, { granularity: "grapheme" }).segment(text)].map((entry) => entry.segment) : [...text];
|
|
162
|
-
for (const segment of segments) {
|
|
163
|
-
if (visibleWidth(out + segment) > budget)
|
|
164
|
-
break;
|
|
165
|
-
out += segment;
|
|
166
|
-
}
|
|
167
|
-
return `${out}${mark}`;
|
|
168
|
-
}
|
|
169
154
|
async function runChooser(keys, items, paint, options) {
|
|
170
155
|
let state = { selected: Math.max(0, Math.min(options.initialIndex ?? 0, Math.max(0, items.length - 1))), query: "" };
|
|
171
156
|
const liveOptions = () => {
|
|
@@ -221,4 +206,4 @@ async function runChooser(keys, items, paint, options) {
|
|
|
221
206
|
return;
|
|
222
207
|
}
|
|
223
208
|
|
|
224
|
-
export { INITIAL_CHOOSER_STATE, windowStart, terminalColumns, renderChooser,
|
|
209
|
+
export { INITIAL_CHOOSER_STATE, filterItems, windowStart, terminalColumns, renderChooser, runChooser };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//
|
|
1
|
+
// src/theme/theme.ts
|
|
2
2
|
var BLUEPRINT = `
|
|
3
3
|
/* Blueprint navy, chalk-white ink and an amber pencil — the original drafting table. */
|
|
4
4
|
@theme blueprint {
|
|
@@ -296,9 +296,30 @@ function buildPalette(theme, depth) {
|
|
|
296
296
|
tokens: theme.tokens
|
|
297
297
|
};
|
|
298
298
|
}
|
|
299
|
+
var EXTERNAL_MARK = "\x1B[35m";
|
|
300
|
+
var ANSI_PALETTE = buildPalette({ name: "ansi", description: "", tokens: DEFAULT_TOKENS }, "ansi256");
|
|
301
|
+
function roleCode(role, palette, depth) {
|
|
302
|
+
if (depth === "none")
|
|
303
|
+
return "";
|
|
304
|
+
return palette?.[role] || ANSI_PALETTE[role];
|
|
305
|
+
}
|
|
299
306
|
var NO_COLOR_PALETTE = buildPalette(findBuiltinTheme(DEFAULT_THEME_NAME) ?? { name: DEFAULT_THEME_NAME, description: "", tokens: DEFAULT_TOKENS }, "none");
|
|
300
307
|
|
|
301
|
-
//
|
|
308
|
+
// src/text/ansi.ts
|
|
309
|
+
var RESET = "\x1B[0m";
|
|
310
|
+
var BOLD = "\x1B[1m";
|
|
311
|
+
var DIM = "\x1B[2m";
|
|
312
|
+
var ITALIC = "\x1B[3m";
|
|
313
|
+
var STRIKE = "\x1B[9m";
|
|
314
|
+
var REVERSE = "\x1B[7m";
|
|
315
|
+
function paint(text, code, depth) {
|
|
316
|
+
return depth === "none" || code === "" ? text : `${code}${text}${RESET}`;
|
|
317
|
+
}
|
|
318
|
+
function paintAll(text, codes, depth) {
|
|
319
|
+
return depth === "none" || codes.length === 0 ? text : `${codes.join("")}${text}${RESET}`;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// src/text/glyphs.ts
|
|
302
323
|
var UNICODE_GLYPHS = {
|
|
303
324
|
starGlyphs: [".", "·", "✧", "✦", "✶"],
|
|
304
325
|
spinnerFrames: [" ◜ ", " ◠ ", " ◝ ", " ◞ ", " ◡ ", " ◟ "],
|
|
@@ -405,20 +426,14 @@ function borderGlyphsFor(style, glyphs) {
|
|
|
405
426
|
return ROUND_BORDER;
|
|
406
427
|
}
|
|
407
428
|
|
|
408
|
-
//
|
|
409
|
-
var RESET = "\x1B[0m";
|
|
410
|
-
var BOLD = "\x1B[1m";
|
|
411
|
-
var DIM = "\x1B[2m";
|
|
412
|
-
var ITALIC = "\x1B[3m";
|
|
413
|
-
var STRIKE = "\x1B[9m";
|
|
414
|
-
var CYAN = "\x1B[36m";
|
|
415
|
-
var BLUE = "\x1B[34m";
|
|
416
|
-
var GREEN = "\x1B[32m";
|
|
417
|
-
var YELLOW = "\x1B[33m";
|
|
429
|
+
// src/text/text-width.ts
|
|
418
430
|
var ANSI = /\x1b\[[0-9;]*m/g;
|
|
431
|
+
var PRINTABLE_ASCII = /^[\x20-\x7e]*$/;
|
|
419
432
|
function visibleWidth(text) {
|
|
433
|
+
if (PRINTABLE_ASCII.test(text))
|
|
434
|
+
return text.length;
|
|
420
435
|
let width = 0;
|
|
421
|
-
for (const character of text.replace(ANSI, "")) {
|
|
436
|
+
for (const character of text.includes("\x1B") ? text.replace(ANSI, "") : text) {
|
|
422
437
|
const code = character.codePointAt(0) ?? 0;
|
|
423
438
|
if (code >= 768 && code <= 879)
|
|
424
439
|
continue;
|
|
@@ -429,218 +444,21 @@ function visibleWidth(text) {
|
|
|
429
444
|
function isWide(code) {
|
|
430
445
|
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;
|
|
431
446
|
}
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
if (
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
tokens.push({ text: boldStars.slice(2, -2), code: BOLD });
|
|
446
|
-
else if (boldUnderscores !== undefined)
|
|
447
|
-
tokens.push({ text: boldUnderscores.slice(2, -2), code: BOLD });
|
|
448
|
-
else if (strike !== undefined)
|
|
449
|
-
tokens.push({ text: strike.slice(2, -2), code: STRIKE });
|
|
450
|
-
else if (italicStars !== undefined)
|
|
451
|
-
tokens.push({ text: italicStars.slice(1, -1), code: ITALIC });
|
|
452
|
-
else if (italicUnderscores !== undefined)
|
|
453
|
-
tokens.push({ text: italicUnderscores.slice(1, -1), code: ITALIC });
|
|
454
|
-
else if (link !== undefined)
|
|
455
|
-
tokens.push({ text: `${link.startsWith("!") ? `image: ${linkLabel}` : linkLabel} (${linkUrl})`, code: CYAN });
|
|
456
|
-
else if (autolink !== undefined)
|
|
457
|
-
tokens.push({ text: autolinkUrl, code: CYAN });
|
|
458
|
-
lastIndex = match.index + whole.length;
|
|
459
|
-
}
|
|
460
|
-
if (lastIndex < line.length)
|
|
461
|
-
tokens.push({ text: unescapeMarkdown(line.slice(lastIndex)), code: "" });
|
|
462
|
-
return tokens.filter((token) => token.text.length > 0);
|
|
463
|
-
}
|
|
464
|
-
function paint(text, code, depth) {
|
|
465
|
-
return depth === "none" || code === "" ? text : `${code}${text}${RESET}`;
|
|
466
|
-
}
|
|
467
|
-
function wrapTokens(tokens, width, options) {
|
|
468
|
-
const firstPrefix = options.firstPrefix ?? "";
|
|
469
|
-
const continuationPrefix = options.continuationPrefix ?? "";
|
|
470
|
-
const lines = [];
|
|
471
|
-
let current = "";
|
|
472
|
-
let currentWidth = 0;
|
|
473
|
-
let prefix = firstPrefix;
|
|
474
|
-
let prefixWidth = visibleWidth(firstPrefix);
|
|
475
|
-
const limit = Math.max(1, width);
|
|
476
|
-
const flush = () => {
|
|
477
|
-
lines.push(`${prefix}${current}`.replace(/[ \t]+$/, ""));
|
|
478
|
-
current = "";
|
|
479
|
-
currentWidth = 0;
|
|
480
|
-
prefix = continuationPrefix;
|
|
481
|
-
prefixWidth = visibleWidth(continuationPrefix);
|
|
482
|
-
};
|
|
483
|
-
for (const token of tokens) {
|
|
484
|
-
for (const word of token.text.split(/(\s+)/)) {
|
|
485
|
-
if (word === "")
|
|
486
|
-
continue;
|
|
487
|
-
const wordWidth = visibleWidth(word);
|
|
488
|
-
if (/^\s+$/.test(word)) {
|
|
489
|
-
if (currentWidth > 0 && prefixWidth + currentWidth + wordWidth <= limit) {
|
|
490
|
-
current += word;
|
|
491
|
-
currentWidth += wordWidth;
|
|
492
|
-
}
|
|
493
|
-
continue;
|
|
494
|
-
}
|
|
495
|
-
if (currentWidth > 0 && prefixWidth + currentWidth + wordWidth > limit)
|
|
496
|
-
flush();
|
|
497
|
-
if (prefixWidth + wordWidth > limit) {
|
|
498
|
-
let remaining = word;
|
|
499
|
-
while (remaining.length > 0) {
|
|
500
|
-
const available = Math.max(1, limit - prefixWidth - currentWidth);
|
|
501
|
-
if (visibleWidth(remaining) <= available)
|
|
502
|
-
break;
|
|
503
|
-
const head = [...remaining].slice(0, available).join("");
|
|
504
|
-
current += paint(head, token.code, options.depth);
|
|
505
|
-
remaining = [...remaining].slice(available).join("");
|
|
506
|
-
flush();
|
|
507
|
-
}
|
|
508
|
-
if (remaining.length > 0) {
|
|
509
|
-
current += paint(remaining, token.code, options.depth);
|
|
510
|
-
currentWidth += visibleWidth(remaining);
|
|
511
|
-
}
|
|
512
|
-
continue;
|
|
513
|
-
}
|
|
514
|
-
current += paint(word, token.code, options.depth);
|
|
515
|
-
currentWidth += wordWidth;
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
if (current !== "" || lines.length === 0)
|
|
519
|
-
lines.push(`${prefix}${current}`.replace(/[ \t]+$/, ""));
|
|
520
|
-
return lines;
|
|
521
|
-
}
|
|
522
|
-
function newMarkdownState() {
|
|
523
|
-
return { inFence: false, fenceLanguage: "" };
|
|
524
|
-
}
|
|
525
|
-
var HEADING = /^(#{1,6})\s+(.*)$/;
|
|
526
|
-
var BULLET = /^(\s*)([-*+])\s+(.*)$/;
|
|
527
|
-
var TASK = /^(\s*)[-*+]\s+\[([ xX])\]\s+(.*)$/;
|
|
528
|
-
var NUMBERED = /^(\s*)(\d+[.)])\s+(.*)$/;
|
|
529
|
-
var BLOCKQUOTE = /^>\s?(.*)$/;
|
|
530
|
-
var RULE = /^\s*([-*_])\s*(?:\1\s*){2,}$/;
|
|
531
|
-
var FENCE = /^\s*```(.*)$/;
|
|
532
|
-
var TABLE_SEPARATOR_CELL = /^:?-{3,}:?$/;
|
|
533
|
-
function tableCells(line) {
|
|
534
|
-
if (!line.includes("|"))
|
|
535
|
-
return null;
|
|
536
|
-
const trimmed = line.trim().replace(/^\|/, "").replace(/\|$/, "");
|
|
537
|
-
const cells = trimmed.split("|").map((cell) => cell.trim());
|
|
538
|
-
return cells.length >= 2 ? cells : null;
|
|
539
|
-
}
|
|
540
|
-
function fitCell(text, width, glyphs = UNICODE_GLYPHS) {
|
|
541
|
-
let result = "";
|
|
542
|
-
for (const character of text) {
|
|
543
|
-
if (visibleWidth(result + character) > width) {
|
|
544
|
-
while (visibleWidth(result) > Math.max(0, width - visibleWidth(glyphs.ellipsis)))
|
|
545
|
-
result = [...result].slice(0, -1).join("");
|
|
546
|
-
result += glyphs.ellipsis;
|
|
547
|
-
return result + " ".repeat(Math.max(0, width - visibleWidth(result)));
|
|
548
|
-
}
|
|
549
|
-
result += character;
|
|
550
|
-
}
|
|
551
|
-
return result + " ".repeat(Math.max(0, width - visibleWidth(result)));
|
|
552
|
-
}
|
|
553
|
-
function renderTableLine(cells, separator, width, depth, glyphs) {
|
|
554
|
-
const cellWidth = Math.max(3, Math.floor((Math.max(width, 12) - cells.length - 1) / cells.length));
|
|
555
|
-
if (separator)
|
|
556
|
-
return paint(`${glyphs.boxTeeLeft}${cells.map(() => glyphs.boxHorizontal.repeat(cellWidth)).join(glyphs.boxCross)}${glyphs.boxTeeRight}`, DIM, depth);
|
|
557
|
-
const contentWidth = Math.max(1, cellWidth - 2);
|
|
558
|
-
const rendered = cells.map((cell) => fitCell(parseInline(cell).map((token) => token.text).join(""), contentWidth, glyphs));
|
|
559
|
-
return `${glyphs.boxVertical}${rendered.map((cell) => ` ${cell} `).join(glyphs.boxVertical)}${glyphs.boxVertical}`;
|
|
560
|
-
}
|
|
561
|
-
function renderMarkdownLine(line, state, options) {
|
|
562
|
-
const { width, depth } = options;
|
|
563
|
-
const glyphs = options.glyphs ?? UNICODE_GLYPHS;
|
|
564
|
-
const fence = FENCE.exec(line);
|
|
565
|
-
if (fence) {
|
|
566
|
-
const ruleWidth = Math.max(4, Math.min(width - 4, 40));
|
|
567
|
-
if (state.inFence) {
|
|
568
|
-
state.inFence = false;
|
|
569
|
-
state.fenceLanguage = "";
|
|
570
|
-
return [paint(` ${glyphs.boxBottomLeft}${glyphs.boxHorizontal.repeat(ruleWidth)}`, DIM, depth)];
|
|
571
|
-
}
|
|
572
|
-
state.inFence = true;
|
|
573
|
-
state.fenceLanguage = fence[1].trim();
|
|
574
|
-
const label = state.fenceLanguage ? ` ${state.fenceLanguage} ` : "";
|
|
575
|
-
const drawn = 1 + visibleWidth(label);
|
|
576
|
-
return [paint(` ${glyphs.boxTopLeft}${glyphs.boxHorizontal}${label}${glyphs.boxHorizontal.repeat(Math.max(0, ruleWidth - drawn))}`, DIM, depth)];
|
|
577
|
-
}
|
|
578
|
-
if (state.inFence) {
|
|
579
|
-
return [`${paint(` ${glyphs.boxVertical} `, DIM, depth)}${paint(line, GREEN, depth)}`];
|
|
580
|
-
}
|
|
581
|
-
const table = tableCells(line);
|
|
582
|
-
if (table) {
|
|
583
|
-
const separator = table.every((cell) => TABLE_SEPARATOR_CELL.test(cell));
|
|
584
|
-
return [renderTableLine(table, separator, width, depth, glyphs)];
|
|
585
|
-
}
|
|
586
|
-
if (RULE.test(line) && line.trim().length > 0) {
|
|
587
|
-
return [paint(" " + glyphs.boxHorizontal.repeat(Math.max(4, Math.min(width - 4, 40))), DIM, depth)];
|
|
588
|
-
}
|
|
589
|
-
const heading = HEADING.exec(line);
|
|
590
|
-
if (heading) {
|
|
591
|
-
const level = heading[1].length;
|
|
592
|
-
const code = level <= 2 ? `${BOLD}${CYAN}` : BOLD;
|
|
593
|
-
const tokens = parseInline(heading[2]).map((token) => ({ text: token.text, code }));
|
|
594
|
-
return wrapTokens(tokens, width, { depth });
|
|
595
|
-
}
|
|
596
|
-
const task = TASK.exec(line);
|
|
597
|
-
if (task) {
|
|
598
|
-
return wrapTokens(parseInline(task[3]), width, {
|
|
599
|
-
firstPrefix: `${task[1]}${paint(task[2].trim() ? glyphs.checkboxDone : glyphs.checkbox, task[2].trim() ? GREEN : BLUE, depth)} `,
|
|
600
|
-
continuationPrefix: `${task[1]} `,
|
|
601
|
-
depth
|
|
602
|
-
});
|
|
603
|
-
}
|
|
604
|
-
const bullet = BULLET.exec(line);
|
|
605
|
-
if (bullet) {
|
|
606
|
-
const indent = bullet[1];
|
|
607
|
-
return wrapTokens(parseInline(bullet[3]), width, {
|
|
608
|
-
firstPrefix: `${indent}${paint(glyphs.bullet, BLUE, depth)} `,
|
|
609
|
-
continuationPrefix: `${indent} `,
|
|
610
|
-
depth
|
|
611
|
-
});
|
|
612
|
-
}
|
|
613
|
-
const numbered = NUMBERED.exec(line);
|
|
614
|
-
if (numbered) {
|
|
615
|
-
const indent = numbered[1];
|
|
616
|
-
const marker = numbered[2];
|
|
617
|
-
return wrapTokens(parseInline(numbered[3]), width, {
|
|
618
|
-
firstPrefix: `${indent}${paint(marker, BLUE, depth)} `,
|
|
619
|
-
continuationPrefix: `${indent}${" ".repeat(marker.length + 1)}`,
|
|
620
|
-
depth
|
|
621
|
-
});
|
|
622
|
-
}
|
|
623
|
-
const quote = BLOCKQUOTE.exec(line);
|
|
624
|
-
if (quote) {
|
|
625
|
-
return wrapTokens([{ text: quote[1], code: DIM }], width, {
|
|
626
|
-
firstPrefix: paint(`${glyphs.boxVertical} `, YELLOW, depth),
|
|
627
|
-
continuationPrefix: paint(`${glyphs.boxVertical} `, YELLOW, depth),
|
|
628
|
-
depth
|
|
629
|
-
});
|
|
447
|
+
function clipTo(text, width, glyphs = UNICODE_GLYPHS) {
|
|
448
|
+
if (width <= 0)
|
|
449
|
+
return "";
|
|
450
|
+
if (visibleWidth(text) <= width)
|
|
451
|
+
return text;
|
|
452
|
+
const mark = visibleWidth(glyphs.ellipsis) < width ? glyphs.ellipsis : "";
|
|
453
|
+
const budget = width - visibleWidth(mark);
|
|
454
|
+
let out = "";
|
|
455
|
+
const segments = typeof Intl.Segmenter === "function" ? [...new Intl.Segmenter(undefined, { granularity: "grapheme" }).segment(text)].map((entry) => entry.segment) : [...text];
|
|
456
|
+
for (const segment of segments) {
|
|
457
|
+
if (visibleWidth(out + segment) > budget)
|
|
458
|
+
break;
|
|
459
|
+
out += segment;
|
|
630
460
|
}
|
|
631
|
-
|
|
632
|
-
return [""];
|
|
633
|
-
return wrapTokens(parseInline(line), width, { depth });
|
|
634
|
-
}
|
|
635
|
-
function renderMarkdown(text, options) {
|
|
636
|
-
const state = newMarkdownState();
|
|
637
|
-
const glyphs = options.glyphs ?? UNICODE_GLYPHS;
|
|
638
|
-
const rendered = text.split(`
|
|
639
|
-
`).flatMap((line) => renderMarkdownLine(line, state, options));
|
|
640
|
-
if (state.inFence)
|
|
641
|
-
rendered.push(paint(` ${glyphs.boxBottomLeft}${glyphs.boxHorizontal.repeat(4)}`, DIM, options.depth));
|
|
642
|
-
return rendered.join(`
|
|
643
|
-
`);
|
|
461
|
+
return `${out}${mark}`;
|
|
644
462
|
}
|
|
645
463
|
|
|
646
|
-
export { UNICODE_GLYPHS, ASCII_GLYPHS, borderGlyphsFor, visibleWidth,
|
|
464
|
+
export { RESET, BOLD, DIM, ITALIC, STRIKE, REVERSE, paint, paintAll, UNICODE_GLYPHS, ASCII_GLYPHS, borderGlyphsFor, visibleWidth, clipTo, BUILTIN_THEME_SOURCES, parseColor, rgbTo256, rainbowText, parseThemeSource, EXTERNAL_MARK, ANSI_PALETTE, roleCode, NO_COLOR_PALETTE };
|