nolo-cli 0.33.0-alpha.20 → 0.33.0-alpha.21
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.
|
@@ -388,6 +388,9 @@ function displayWidth(str) {
|
|
|
388
388
|
for (const char of str) {
|
|
389
389
|
const code = char.codePointAt(0) ?? 0;
|
|
390
390
|
if (code < 32 || code === 127) continue;
|
|
391
|
+
if (code >= 768 && code <= 879 || code >= 6832 && code <= 6911 || code >= 7616 && code <= 7679 || code >= 8203 && code <= 8207 || code >= 8234 && code <= 8238 || code >= 8288 && code <= 8303 || code >= 8400 && code <= 8447 || code >= 65024 && code <= 65039 || code >= 65056 && code <= 65071 || code >= 917760 && code <= 917999) {
|
|
392
|
+
continue;
|
|
393
|
+
}
|
|
391
394
|
if (code >= 4352 && code <= 4447 || // 0x2768-0x2775 (ornamental brackets, incl. the ❯ prompt at U+276F)
|
|
392
395
|
// render narrow in terminals; counting them wide drifts the cursor.
|
|
393
396
|
code >= 9728 && code <= 10175 && !(code >= 10088 && code <= 10101) || // 0x2B00-0x2BFF (Misc Symbols and Arrows, incl. ⬢ U+2B22 used as the
|
|
@@ -474,6 +477,7 @@ function padOrTruncateToWidth(text, width) {
|
|
|
474
477
|
return `${text}${" ".repeat(width - textWidth)}`;
|
|
475
478
|
}
|
|
476
479
|
var SGR_RESET_REGEX = /^\x1b\[0?m$/;
|
|
480
|
+
var graphemeSegmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
477
481
|
function tokenizeAnsiLine(line) {
|
|
478
482
|
const tokens = [];
|
|
479
483
|
let index = 0;
|
|
@@ -481,28 +485,119 @@ function tokenizeAnsiLine(line) {
|
|
|
481
485
|
if (line[index] === "\x1B") {
|
|
482
486
|
const osc = line.slice(index).match(/^\x1b\]8;;[^\x07\x1b]*(?:\x07|\x1b\\)/);
|
|
483
487
|
if (osc) {
|
|
484
|
-
tokens.push({ kind: "sgr", value: osc[0], width: 0 });
|
|
488
|
+
tokens.push({ kind: "sgr", value: osc[0], width: 0, charIndex: index });
|
|
485
489
|
index += osc[0].length;
|
|
486
490
|
continue;
|
|
487
491
|
}
|
|
488
492
|
const sgr = SGR_SEQUENCE_REGEX.exec(line.slice(index));
|
|
489
493
|
if (sgr) {
|
|
490
|
-
tokens.push({ kind: "sgr", value: sgr[0], width: 0 });
|
|
494
|
+
tokens.push({ kind: "sgr", value: sgr[0], width: 0, charIndex: index });
|
|
491
495
|
index += sgr[0].length;
|
|
492
496
|
continue;
|
|
493
497
|
}
|
|
498
|
+
const csi = line.slice(index).match(/^\x1b\[[\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e]/);
|
|
499
|
+
if (csi) {
|
|
500
|
+
tokens.push({ kind: "sgr", value: csi[0], width: 0, charIndex: index });
|
|
501
|
+
index += csi[0].length;
|
|
502
|
+
continue;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
let nextEsc = line.indexOf("\x1B", index);
|
|
506
|
+
if (nextEsc === -1) nextEsc = line.length;
|
|
507
|
+
const chunk = line.slice(index, nextEsc);
|
|
508
|
+
for (const item of graphemeSegmenter.segment(chunk)) {
|
|
509
|
+
tokens.push({
|
|
510
|
+
kind: "char",
|
|
511
|
+
value: item.segment,
|
|
512
|
+
width: displayWidth(item.segment),
|
|
513
|
+
charIndex: index + item.index
|
|
514
|
+
});
|
|
494
515
|
}
|
|
495
|
-
|
|
496
|
-
const value = String.fromCodePoint(codePoint);
|
|
497
|
-
tokens.push({ kind: "char", value, width: displayWidth(value) });
|
|
498
|
-
index += value.length;
|
|
516
|
+
index = nextEsc;
|
|
499
517
|
}
|
|
500
518
|
return tokens;
|
|
501
519
|
}
|
|
502
|
-
function
|
|
503
|
-
|
|
520
|
+
function buildSourceMapping(rawLine, styledLine, prefixCharCount) {
|
|
521
|
+
let contentStart = 0;
|
|
522
|
+
const headingMatch = rawLine.match(/^(#{1,3})\s+(.+)$/);
|
|
523
|
+
let lineToParse = rawLine;
|
|
524
|
+
if (headingMatch) {
|
|
525
|
+
contentStart = headingMatch[1].length + 1;
|
|
526
|
+
while (contentStart < rawLine.length && rawLine[contentStart] === " ") contentStart++;
|
|
527
|
+
lineToParse = rawLine.slice(contentStart);
|
|
528
|
+
}
|
|
529
|
+
const INLINE_RE = /(\[([^\]]+)\]\(([^)\s]+)\)|`([^`]+)`|\*\*(.+?)\*\*|(?<!\*)\*([^*]+?)\*(?!\*)|~~([^~]+?)~~)/g;
|
|
530
|
+
const mapping = [];
|
|
531
|
+
let lastIdx = 0;
|
|
532
|
+
let match;
|
|
533
|
+
while ((match = INLINE_RE.exec(lineToParse)) !== null) {
|
|
534
|
+
const plainBefore = lineToParse.slice(lastIdx, match.index);
|
|
535
|
+
for (let c = 0; c < plainBefore.length; c++) {
|
|
536
|
+
mapping.push(contentStart + lastIdx + c);
|
|
537
|
+
}
|
|
538
|
+
const fullMatch = match[0];
|
|
539
|
+
if (match[2] !== void 0 && match[3] !== void 0) {
|
|
540
|
+
const linkText = match[2];
|
|
541
|
+
const linkUrl = match[3];
|
|
542
|
+
const textOffset = contentStart + match.index + 1;
|
|
543
|
+
for (let c = 0; c < linkText.length; c++) {
|
|
544
|
+
mapping.push(textOffset + c);
|
|
545
|
+
}
|
|
546
|
+
const parenOffset = textOffset + linkText.length;
|
|
547
|
+
mapping.push(parenOffset);
|
|
548
|
+
mapping.push(parenOffset + 1);
|
|
549
|
+
const urlOffset = parenOffset + 2;
|
|
550
|
+
for (let c = 0; c < linkUrl.length; c++) {
|
|
551
|
+
mapping.push(urlOffset + c);
|
|
552
|
+
}
|
|
553
|
+
mapping.push(urlOffset + linkUrl.length);
|
|
554
|
+
} else if (match[4] !== void 0) {
|
|
555
|
+
const codeText = match[4];
|
|
556
|
+
const codeOffset = contentStart + match.index + 1;
|
|
557
|
+
for (let c = 0; c < codeText.length; c++) {
|
|
558
|
+
mapping.push(codeOffset + c);
|
|
559
|
+
}
|
|
560
|
+
} else if (match[5] !== void 0) {
|
|
561
|
+
const boldText = match[5];
|
|
562
|
+
const boldOffset = contentStart + match.index + 2;
|
|
563
|
+
for (let c = 0; c < boldText.length; c++) {
|
|
564
|
+
mapping.push(boldOffset + c);
|
|
565
|
+
}
|
|
566
|
+
} else if (match[6] !== void 0) {
|
|
567
|
+
const italicText = match[6];
|
|
568
|
+
const italicOffset = contentStart + match.index + 1;
|
|
569
|
+
for (let c = 0; c < italicText.length; c++) {
|
|
570
|
+
mapping.push(italicOffset + c);
|
|
571
|
+
}
|
|
572
|
+
} else if (match[7] !== void 0) {
|
|
573
|
+
const strikeText = match[7];
|
|
574
|
+
const strikeOffset = contentStart + match.index + 2;
|
|
575
|
+
for (let c = 0; c < strikeText.length; c++) {
|
|
576
|
+
mapping.push(strikeOffset + c);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
lastIdx = match.index + fullMatch.length;
|
|
580
|
+
}
|
|
581
|
+
const plainRest = lineToParse.slice(lastIdx);
|
|
582
|
+
for (let c = 0; c < plainRest.length; c++) {
|
|
583
|
+
mapping.push(contentStart + lastIdx + c);
|
|
584
|
+
}
|
|
585
|
+
return mapping;
|
|
586
|
+
}
|
|
587
|
+
function wrapTranscriptLineWithLayout(line, columns, hangingIndent = "", lineSourceStart = 0, prefixWidth = 0, prefixCharCount = 0, sourceMapping, rawLineLength) {
|
|
588
|
+
if (line === "") {
|
|
589
|
+
const rawLen = rawLineLength ?? 0;
|
|
590
|
+
return [
|
|
591
|
+
{
|
|
592
|
+
rendered: "",
|
|
593
|
+
sourceStart: lineSourceStart,
|
|
594
|
+
sourceEnd: lineSourceStart + rawLen,
|
|
595
|
+
prefixWidth
|
|
596
|
+
}
|
|
597
|
+
];
|
|
598
|
+
}
|
|
504
599
|
const tokens = tokenizeAnsiLine(line);
|
|
505
|
-
const
|
|
600
|
+
const rows = [];
|
|
506
601
|
let activeStyles = [];
|
|
507
602
|
const applyStyleToken = (value) => {
|
|
508
603
|
if (SGR_RESET_REGEX.test(value)) {
|
|
@@ -514,10 +609,11 @@ function wrapTranscriptLine(line, columns, hangingIndent = "") {
|
|
|
514
609
|
let start = 0;
|
|
515
610
|
while (start < tokens.length) {
|
|
516
611
|
if (tokens.slice(start).every((token) => token.kind === "sgr")) {
|
|
517
|
-
if (
|
|
612
|
+
if (rows.length > 0) break;
|
|
518
613
|
}
|
|
519
614
|
const openingStyles = [...activeStyles];
|
|
520
|
-
const isContinuation =
|
|
615
|
+
const isContinuation = rows.length > 0;
|
|
616
|
+
const currentPrefixWidth = isContinuation ? visibleWidth(hangingIndent) : prefixWidth;
|
|
521
617
|
const indentWidth = isContinuation ? visibleWidth(hangingIndent) : 0;
|
|
522
618
|
const maxSegmentWidth = Math.max(1, columns - indentWidth);
|
|
523
619
|
let width = 0;
|
|
@@ -532,7 +628,7 @@ function wrapTranscriptLine(line, columns, hangingIndent = "") {
|
|
|
532
628
|
if (width + token.width > maxSegmentWidth && width > 0) break;
|
|
533
629
|
width += token.width;
|
|
534
630
|
end += 1;
|
|
535
|
-
if (token.value === " " || token.value === " ") {
|
|
631
|
+
if ((token.value === " " || token.value === " ") && token.charIndex >= prefixCharCount) {
|
|
536
632
|
lastBreak = end;
|
|
537
633
|
}
|
|
538
634
|
}
|
|
@@ -557,18 +653,71 @@ function wrapTranscriptLine(line, columns, hangingIndent = "") {
|
|
|
557
653
|
const prefix = openingStyles.join("");
|
|
558
654
|
const needsReset = (sawStyle || activeStyles.length > 0) && !segment.endsWith("\x1B[0m");
|
|
559
655
|
const lineContent = `${prefix}${segment}${needsReset ? "\x1B[0m" : ""}`;
|
|
560
|
-
|
|
656
|
+
const rowRendered = isContinuation && hangingIndent.length > 0 ? `${hangingIndent}${lineContent}` : lineContent;
|
|
657
|
+
let segSourceStart = lineSourceStart;
|
|
658
|
+
let segSourceEnd = lineSourceStart;
|
|
659
|
+
let foundFirst = false;
|
|
660
|
+
const rowMapping = [];
|
|
661
|
+
let plainCharIndex = 0;
|
|
662
|
+
for (let i = 0; i < start; i++) {
|
|
663
|
+
const tok = tokens[i];
|
|
664
|
+
if (tok.kind === "char" && tok.charIndex >= prefixCharCount) {
|
|
665
|
+
plainCharIndex += tok.value.length;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
for (let i = start; i < segmentEnd; i++) {
|
|
669
|
+
const tok = tokens[i];
|
|
670
|
+
if (tok.kind === "char" && tok.charIndex >= prefixCharCount) {
|
|
671
|
+
const mappedOffset = sourceMapping && sourceMapping[plainCharIndex] !== void 0 ? sourceMapping[plainCharIndex] : plainCharIndex;
|
|
672
|
+
if (!foundFirst) {
|
|
673
|
+
segSourceStart = lineSourceStart + mappedOffset;
|
|
674
|
+
foundFirst = true;
|
|
675
|
+
}
|
|
676
|
+
for (let c = 0; c < tok.value.length; c++) {
|
|
677
|
+
const idx = plainCharIndex + c;
|
|
678
|
+
const mapped = sourceMapping && sourceMapping[idx] !== void 0 ? sourceMapping[idx] : idx;
|
|
679
|
+
rowMapping.push(lineSourceStart + mapped);
|
|
680
|
+
}
|
|
681
|
+
const lastCharIdx = plainCharIndex + tok.value.length - 1;
|
|
682
|
+
const mappedEndOffset = sourceMapping && sourceMapping[lastCharIdx] !== void 0 ? sourceMapping[lastCharIdx] + 1 : plainCharIndex + tok.value.length;
|
|
683
|
+
segSourceEnd = lineSourceStart + mappedEndOffset;
|
|
684
|
+
plainCharIndex += tok.value.length;
|
|
685
|
+
}
|
|
686
|
+
}
|
|
561
687
|
start = segmentEnd;
|
|
562
688
|
while (start < tokens.length) {
|
|
563
689
|
const token = tokens[start];
|
|
564
|
-
if (token.kind === "char" && token.value === " ") {
|
|
690
|
+
if (token.kind === "char" && token.value === " " && token.charIndex >= prefixCharCount) {
|
|
691
|
+
const mappedOffset = sourceMapping && sourceMapping[plainCharIndex] !== void 0 ? sourceMapping[plainCharIndex] + 1 : plainCharIndex + 1;
|
|
692
|
+
segSourceEnd = lineSourceStart + mappedOffset;
|
|
693
|
+
plainCharIndex += token.value.length;
|
|
565
694
|
start += 1;
|
|
566
695
|
continue;
|
|
567
696
|
}
|
|
568
697
|
break;
|
|
569
698
|
}
|
|
699
|
+
if (start >= tokens.length && rawLineLength !== void 0) {
|
|
700
|
+
segSourceEnd = lineSourceStart + rawLineLength;
|
|
701
|
+
}
|
|
702
|
+
rows.push({
|
|
703
|
+
rendered: rowRendered,
|
|
704
|
+
sourceStart: segSourceStart,
|
|
705
|
+
sourceEnd: segSourceEnd,
|
|
706
|
+
prefixWidth: currentPrefixWidth,
|
|
707
|
+
sourceMapping: rowMapping.length > 0 ? rowMapping : void 0
|
|
708
|
+
});
|
|
570
709
|
}
|
|
571
|
-
return
|
|
710
|
+
return rows.length > 0 ? rows : [
|
|
711
|
+
{
|
|
712
|
+
rendered: "",
|
|
713
|
+
sourceStart: lineSourceStart,
|
|
714
|
+
sourceEnd: lineSourceStart + (rawLineLength ?? 0),
|
|
715
|
+
prefixWidth
|
|
716
|
+
}
|
|
717
|
+
];
|
|
718
|
+
}
|
|
719
|
+
function wrapTranscriptLine(line, columns, hangingIndent = "") {
|
|
720
|
+
return wrapTranscriptLineWithLayout(line, columns, hangingIndent).map((r) => r.rendered);
|
|
572
721
|
}
|
|
573
722
|
function buildWindowTitle(title) {
|
|
574
723
|
const plain = stripAnsi(title).replace(/[\x00-\x1f\x7f]+/g, " ");
|
|
@@ -5371,6 +5520,9 @@ export {
|
|
|
5371
5520
|
countPhysicalLines,
|
|
5372
5521
|
takeDisplayWidth,
|
|
5373
5522
|
padOrTruncateToWidth,
|
|
5523
|
+
tokenizeAnsiLine,
|
|
5524
|
+
buildSourceMapping,
|
|
5525
|
+
wrapTranscriptLineWithLayout,
|
|
5374
5526
|
wrapTranscriptLine,
|
|
5375
5527
|
buildWindowTitle,
|
|
5376
5528
|
wrapTextToLines,
|
package/index.js
CHANGED
|
@@ -126,7 +126,7 @@ function createDaemonShortcutCommand(path, description, command2) {
|
|
|
126
126
|
// packages/cli/agentInternalCommandEntries.ts
|
|
127
127
|
function getAgentInternalCommandEntries() {
|
|
128
128
|
const createAgentRunCommand = (path, description) => createContextCommand(path, description, async (args2, ctx) => {
|
|
129
|
-
const { runAgentRunCommand } = await import("./agentRunCommand-
|
|
129
|
+
const { runAgentRunCommand } = await import("./agentRunCommand-OJX27NII.js");
|
|
130
130
|
return runAgentRunCommand(args2, {
|
|
131
131
|
env: ctx.env,
|
|
132
132
|
scriptDir: ctx.scriptDir,
|
|
@@ -796,7 +796,7 @@ async function runScript(script, forwardedArgs, env) {
|
|
|
796
796
|
return proc.exited;
|
|
797
797
|
}
|
|
798
798
|
async function launchTuiWorkspace(args2) {
|
|
799
|
-
const { startTuiWorkspace } = await import("./readlineWorkspace-
|
|
799
|
+
const { startTuiWorkspace } = await import("./readlineWorkspace-J2ARMEUC.js");
|
|
800
800
|
const { createTuiSummaryLlmCaller } = await import("./tuiSummaryLlmCaller-WUVAOIYU.js");
|
|
801
801
|
return startTuiWorkspace({
|
|
802
802
|
...args2,
|
package/package.json
CHANGED
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
applyDetectedBackground,
|
|
25
25
|
applyTerminalOutputToText,
|
|
26
26
|
buildSkillContextBlocks,
|
|
27
|
+
buildSourceMapping,
|
|
27
28
|
buildWindowTitle,
|
|
28
29
|
clearCollapsedPasteStore,
|
|
29
30
|
countPhysicalLines,
|
|
@@ -65,12 +66,14 @@ import {
|
|
|
65
66
|
takeDisplayWidth,
|
|
66
67
|
themeColorSequence,
|
|
67
68
|
themeText,
|
|
69
|
+
tokenizeAnsiLine,
|
|
68
70
|
truncateAnsi,
|
|
69
71
|
userSurfaceBackgroundSequence,
|
|
70
72
|
visibleWidth,
|
|
71
73
|
wrapTextToLines,
|
|
72
|
-
wrapTranscriptLine
|
|
73
|
-
|
|
74
|
+
wrapTranscriptLine,
|
|
75
|
+
wrapTranscriptLineWithLayout
|
|
76
|
+
} from "./chunk-46JSKTPF.js";
|
|
74
77
|
import "./chunk-ZHYK3N56.js";
|
|
75
78
|
import {
|
|
76
79
|
getReadableCliDb
|
|
@@ -1754,197 +1757,161 @@ function createSelectionState() {
|
|
|
1754
1757
|
};
|
|
1755
1758
|
}
|
|
1756
1759
|
function compareSelectionPoints(a, b) {
|
|
1757
|
-
if (a.
|
|
1758
|
-
return a.
|
|
1760
|
+
if (a.globalRow !== b.globalRow) {
|
|
1761
|
+
return a.globalRow - b.globalRow;
|
|
1759
1762
|
}
|
|
1760
|
-
return a.
|
|
1763
|
+
return a.col - b.col;
|
|
1761
1764
|
}
|
|
1762
1765
|
function areSelectionPointsEqual(a, b) {
|
|
1763
1766
|
if (a === null && b === null) return true;
|
|
1764
1767
|
if (a === null || b === null) return false;
|
|
1765
|
-
return a.
|
|
1766
|
-
}
|
|
1767
|
-
function
|
|
1768
|
-
if (
|
|
1769
|
-
const
|
|
1770
|
-
if (
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
turn.role,
|
|
1795
|
-
contentWidth,
|
|
1796
|
-
rowInTurn,
|
|
1797
|
-
screenCol,
|
|
1798
|
-
turn.command
|
|
1799
|
-
);
|
|
1800
|
-
return { turnIndex: i, sourceOffset };
|
|
1801
|
-
}
|
|
1802
|
-
}
|
|
1803
|
-
return null;
|
|
1804
|
-
}
|
|
1805
|
-
function mapRowColToSourceOffset(content, role, contentWidth, targetRow, targetCol, command) {
|
|
1806
|
-
const normalized = content.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
1807
|
-
const logicalLines = normalized.split("\n");
|
|
1808
|
-
let currentRow = 0;
|
|
1809
|
-
let charAccumulator = 0;
|
|
1810
|
-
if (role === "local" && command) {
|
|
1811
|
-
const cmdWrapped = wrapTranscriptLine(`\u203A ${command}`, contentWidth);
|
|
1812
|
-
if (targetRow < cmdWrapped.length) {
|
|
1813
|
-
return 0;
|
|
1814
|
-
}
|
|
1815
|
-
currentRow += cmdWrapped.length;
|
|
1816
|
-
}
|
|
1817
|
-
for (let l = 0; l < logicalLines.length; l++) {
|
|
1818
|
-
const lineText = logicalLines[l];
|
|
1819
|
-
const lineLen = lineText.length;
|
|
1820
|
-
let wrappedRows;
|
|
1821
|
-
let prefixFirst = 0;
|
|
1822
|
-
let prefixCont = 0;
|
|
1823
|
-
if (role === "user") {
|
|
1824
|
-
wrappedRows = wrapTranscriptLine(`\u2503 ${lineText}`, contentWidth, "\u2503 ");
|
|
1825
|
-
prefixFirst = 3;
|
|
1826
|
-
prefixCont = 3;
|
|
1827
|
-
} else if (role === "local") {
|
|
1828
|
-
wrappedRows = wrapTranscriptLine(` ${lineText}`, contentWidth, " ");
|
|
1829
|
-
prefixFirst = 2;
|
|
1830
|
-
prefixCont = 2;
|
|
1831
|
-
} else {
|
|
1832
|
-
if (l === 0 && !lineText.startsWith("[nolo]")) {
|
|
1833
|
-
wrappedRows = wrapTranscriptLine(`\u25C8 ${lineText}`, contentWidth);
|
|
1834
|
-
prefixFirst = 2;
|
|
1835
|
-
prefixCont = 0;
|
|
1836
|
-
} else {
|
|
1837
|
-
wrappedRows = wrapTranscriptLine(lineText, contentWidth);
|
|
1838
|
-
prefixFirst = 0;
|
|
1839
|
-
prefixCont = 0;
|
|
1840
|
-
}
|
|
1841
|
-
}
|
|
1842
|
-
const rowCount = Math.max(1, wrappedRows.length);
|
|
1843
|
-
if (targetRow >= currentRow && targetRow < currentRow + rowCount) {
|
|
1844
|
-
const subRow = targetRow - currentRow;
|
|
1845
|
-
let offsetInLine = 0;
|
|
1846
|
-
for (let s = 0; s < subRow; s++) {
|
|
1847
|
-
const rowStr = stripAnsi(wrappedRows[s] ?? "");
|
|
1848
|
-
const pLen2 = s === 0 ? prefixFirst : prefixCont;
|
|
1849
|
-
const pureText = rowStr.slice(pLen2);
|
|
1850
|
-
offsetInLine += pureText.length;
|
|
1851
|
-
}
|
|
1852
|
-
const targetRowStr = stripAnsi(wrappedRows[subRow] ?? "");
|
|
1853
|
-
const pLen = subRow === 0 ? prefixFirst : prefixCont;
|
|
1854
|
-
const pureTargetText = targetRowStr.slice(pLen);
|
|
1855
|
-
const effectiveCol = Math.max(0, targetCol - pLen);
|
|
1856
|
-
let colAccum = 0;
|
|
1857
|
-
for (let c = 0; c < pureTargetText.length; c++) {
|
|
1858
|
-
const char = pureTargetText[c];
|
|
1859
|
-
const w = displayWidth(char);
|
|
1860
|
-
if (colAccum + w > effectiveCol) {
|
|
1861
|
-
break;
|
|
1768
|
+
return a.globalRow === b.globalRow && a.col === b.col;
|
|
1769
|
+
}
|
|
1770
|
+
function highlightLineByColumns(line, selStartCol, selEndCol) {
|
|
1771
|
+
if (selStartCol >= selEndCol) return line;
|
|
1772
|
+
const tokens = tokenizeAnsiLine(line);
|
|
1773
|
+
if (tokens.length === 0) return line;
|
|
1774
|
+
let lastNonSpaceCol = 0;
|
|
1775
|
+
let colScan = 0;
|
|
1776
|
+
for (const tok of tokens) {
|
|
1777
|
+
if (tok.kind === "char") {
|
|
1778
|
+
if (tok.value.trim().length > 0) {
|
|
1779
|
+
lastNonSpaceCol = colScan + tok.width;
|
|
1780
|
+
}
|
|
1781
|
+
colScan += tok.width;
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1784
|
+
const effectiveEndCol = Math.min(selEndCol, lastNonSpaceCol);
|
|
1785
|
+
if (selStartCol >= effectiveEndCol) return line;
|
|
1786
|
+
let out = "";
|
|
1787
|
+
let currentCol = 0;
|
|
1788
|
+
let isHighlightActive = false;
|
|
1789
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
1790
|
+
const token = tokens[i];
|
|
1791
|
+
if (token.kind === "sgr") {
|
|
1792
|
+
if (isHighlightActive) {
|
|
1793
|
+
if (/^\x1b\[0?m$/.test(token.value)) {
|
|
1794
|
+
out += `${token.value}\x1B[7m`;
|
|
1795
|
+
} else {
|
|
1796
|
+
out += token.value;
|
|
1862
1797
|
}
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
}
|
|
1866
|
-
let finalOffset = Math.min(normalized.length, charAccumulator + Math.min(lineLen, offsetInLine));
|
|
1867
|
-
if (finalOffset > 0 && finalOffset < normalized.length && normalized.charCodeAt(finalOffset - 1) >= 55296 && normalized.charCodeAt(finalOffset - 1) <= 56319) {
|
|
1868
|
-
finalOffset += 1;
|
|
1798
|
+
} else {
|
|
1799
|
+
out += token.value;
|
|
1869
1800
|
}
|
|
1870
|
-
|
|
1801
|
+
continue;
|
|
1871
1802
|
}
|
|
1872
|
-
|
|
1873
|
-
|
|
1803
|
+
const charStartCol = currentCol;
|
|
1804
|
+
const charEndCol = currentCol + token.width;
|
|
1805
|
+
const isSelected = charStartCol >= selStartCol && charStartCol < effectiveEndCol;
|
|
1806
|
+
if (isSelected && !isHighlightActive) {
|
|
1807
|
+
out += "\x1B[7m";
|
|
1808
|
+
isHighlightActive = true;
|
|
1809
|
+
} else if (!isSelected && isHighlightActive) {
|
|
1810
|
+
out += "\x1B[27m";
|
|
1811
|
+
isHighlightActive = false;
|
|
1812
|
+
}
|
|
1813
|
+
out += token.value;
|
|
1814
|
+
currentCol = charEndCol;
|
|
1815
|
+
}
|
|
1816
|
+
if (isHighlightActive) {
|
|
1817
|
+
out += "\x1B[27m";
|
|
1818
|
+
}
|
|
1819
|
+
return out;
|
|
1820
|
+
}
|
|
1821
|
+
function hitTestHistory(history, screenRow, screenCol, _contentWidth, scrollTop) {
|
|
1822
|
+
const globalRow = Math.max(0, scrollTop + screenRow);
|
|
1823
|
+
const col = Math.max(0, screenCol);
|
|
1824
|
+
return { globalRow, col };
|
|
1825
|
+
}
|
|
1826
|
+
function extractTextSliceByColumns(plain, startCol, endCol) {
|
|
1827
|
+
let text = plain;
|
|
1828
|
+
let textStartCol = 0;
|
|
1829
|
+
if (text.startsWith("\u25C8 ")) {
|
|
1830
|
+
text = text.slice(2);
|
|
1831
|
+
textStartCol = 2;
|
|
1832
|
+
} else if (text.startsWith("\u2503 ")) {
|
|
1833
|
+
text = text.slice(3);
|
|
1834
|
+
textStartCol = 3;
|
|
1835
|
+
} else if (text.startsWith("\u203A ")) {
|
|
1836
|
+
text = text.slice(2);
|
|
1837
|
+
textStartCol = 2;
|
|
1838
|
+
}
|
|
1839
|
+
const effectiveStart = Math.max(0, startCol - textStartCol);
|
|
1840
|
+
const effectiveEnd = Math.max(0, endCol - textStartCol);
|
|
1841
|
+
if (effectiveStart >= effectiveEnd) return "";
|
|
1842
|
+
let out = "";
|
|
1843
|
+
let col = 0;
|
|
1844
|
+
for (const char of text) {
|
|
1845
|
+
const w = displayWidth(char);
|
|
1846
|
+
if (col + w > effectiveStart && col < effectiveEnd) {
|
|
1847
|
+
out += char;
|
|
1848
|
+
}
|
|
1849
|
+
col += w;
|
|
1874
1850
|
}
|
|
1875
|
-
return
|
|
1851
|
+
return out;
|
|
1876
1852
|
}
|
|
1877
|
-
function extractSelectedText(history, anchor, head) {
|
|
1853
|
+
function extractSelectedText(history, anchor, head, contentWidth = 80) {
|
|
1878
1854
|
if (!anchor || !head) return "";
|
|
1879
1855
|
const cmp = compareSelectionPoints(anchor, head);
|
|
1880
1856
|
if (cmp === 0) return "";
|
|
1881
1857
|
const start = cmp < 0 ? anchor : head;
|
|
1882
1858
|
const end = cmp < 0 ? head : anchor;
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
const
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1859
|
+
const lines = buildHistoryLines(history, contentWidth);
|
|
1860
|
+
const selectedLines = [];
|
|
1861
|
+
for (let r = start.globalRow; r <= end.globalRow; r++) {
|
|
1862
|
+
const rawLine = lines[r];
|
|
1863
|
+
if (rawLine === void 0) continue;
|
|
1864
|
+
const plain = stripAnsi(rawLine);
|
|
1865
|
+
if (plain.trim().length === 0) {
|
|
1866
|
+
if (selectedLines.length > 0 && selectedLines[selectedLines.length - 1] !== "") {
|
|
1867
|
+
selectedLines.push("");
|
|
1868
|
+
}
|
|
1869
|
+
continue;
|
|
1870
|
+
}
|
|
1871
|
+
let lineStartCol = 0;
|
|
1872
|
+
let lineEndCol = Infinity;
|
|
1873
|
+
if (r === start.globalRow) {
|
|
1874
|
+
lineStartCol = start.col;
|
|
1875
|
+
}
|
|
1876
|
+
if (r === end.globalRow) {
|
|
1877
|
+
lineEndCol = end.col;
|
|
1878
|
+
}
|
|
1879
|
+
const extracted = extractTextSliceByColumns(plain, lineStartCol, lineEndCol);
|
|
1880
|
+
if (extracted.length > 0) {
|
|
1881
|
+
selectedLines.push(extracted);
|
|
1898
1882
|
}
|
|
1899
1883
|
}
|
|
1900
|
-
|
|
1901
|
-
if (endTurn) {
|
|
1902
|
-
pieces.push(endTurn.content.slice(0, end.sourceOffset));
|
|
1903
|
-
}
|
|
1904
|
-
return stripAnsi(pieces.join("\n\n"));
|
|
1884
|
+
return selectedLines.join("\n");
|
|
1905
1885
|
}
|
|
1906
|
-
function applySelectionOverlay(visibleLines,
|
|
1907
|
-
if (!selection.
|
|
1886
|
+
function applySelectionOverlay(visibleLines, _history, _contentWidth, scrollTop, selection) {
|
|
1887
|
+
if (!selection.anchor || !selection.head) {
|
|
1908
1888
|
return visibleLines;
|
|
1909
1889
|
}
|
|
1910
1890
|
const cmp = compareSelectionPoints(selection.anchor, selection.head);
|
|
1911
1891
|
if (cmp === 0) return visibleLines;
|
|
1912
1892
|
const start = cmp < 0 ? selection.anchor : selection.head;
|
|
1913
1893
|
const end = cmp < 0 ? selection.head : selection.anchor;
|
|
1914
|
-
const { entries } = buildTurnOffsets2(history, contentWidth);
|
|
1915
1894
|
const result = [...visibleLines];
|
|
1916
1895
|
for (let screenRow = 0; screenRow < visibleLines.length; screenRow++) {
|
|
1917
1896
|
const globalRow = scrollTop + screenRow;
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
const entry = entries[i];
|
|
1921
|
-
if (!entry) continue;
|
|
1922
|
-
const turnStart = entry.startRow;
|
|
1923
|
-
const turnEnd = turnStart + entry.lineCount;
|
|
1924
|
-
if (i === start.turnIndex && i === end.turnIndex) {
|
|
1925
|
-
if (globalRow >= turnStart && globalRow < turnEnd) {
|
|
1926
|
-
isSelectedRow = true;
|
|
1927
|
-
}
|
|
1928
|
-
} else if (i === start.turnIndex) {
|
|
1929
|
-
if (globalRow >= turnStart) {
|
|
1930
|
-
isSelectedRow = true;
|
|
1931
|
-
}
|
|
1932
|
-
} else if (i === end.turnIndex) {
|
|
1933
|
-
if (globalRow < turnEnd) {
|
|
1934
|
-
isSelectedRow = true;
|
|
1935
|
-
}
|
|
1936
|
-
} else {
|
|
1937
|
-
if (globalRow >= turnStart && globalRow < turnEnd) {
|
|
1938
|
-
isSelectedRow = true;
|
|
1939
|
-
}
|
|
1940
|
-
}
|
|
1897
|
+
if (globalRow < start.globalRow || globalRow > end.globalRow) {
|
|
1898
|
+
continue;
|
|
1941
1899
|
}
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1900
|
+
const currentLine = result[screenRow] ?? "";
|
|
1901
|
+
if (currentLine.length === 0) continue;
|
|
1902
|
+
let selStartCol = 0;
|
|
1903
|
+
let selEndCol = Infinity;
|
|
1904
|
+
if (globalRow === start.globalRow) {
|
|
1905
|
+
selStartCol = start.col;
|
|
1947
1906
|
}
|
|
1907
|
+
if (globalRow === end.globalRow) {
|
|
1908
|
+
selEndCol = end.col;
|
|
1909
|
+
}
|
|
1910
|
+
result[screenRow] = highlightLineByColumns(
|
|
1911
|
+
currentLine,
|
|
1912
|
+
selStartCol,
|
|
1913
|
+
selEndCol
|
|
1914
|
+
);
|
|
1948
1915
|
}
|
|
1949
1916
|
return result;
|
|
1950
1917
|
}
|
|
@@ -1959,7 +1926,6 @@ function resetHistoryFrameDiffCache(output) {
|
|
|
1959
1926
|
frameBufferByOutput.delete(output);
|
|
1960
1927
|
}
|
|
1961
1928
|
}
|
|
1962
|
-
var renderCacheMissCount = 0;
|
|
1963
1929
|
function createTurnHistory() {
|
|
1964
1930
|
return {
|
|
1965
1931
|
turns: [],
|
|
@@ -1970,11 +1936,8 @@ function createTurnHistory() {
|
|
|
1970
1936
|
};
|
|
1971
1937
|
}
|
|
1972
1938
|
function startTurn(history, role) {
|
|
1973
|
-
if (history.currentRole !== null) {
|
|
1974
|
-
history
|
|
1975
|
-
role: history.currentRole,
|
|
1976
|
-
content: history.currentContent
|
|
1977
|
-
});
|
|
1939
|
+
if (history.currentRole !== null && history.currentContent) {
|
|
1940
|
+
finalizeCurrentTurn(history);
|
|
1978
1941
|
}
|
|
1979
1942
|
history.currentRole = role;
|
|
1980
1943
|
history.currentContent = "";
|
|
@@ -2036,9 +1999,8 @@ function fillUserBubbleRow(row, surfaceSeq, contentWidth) {
|
|
|
2036
1999
|
}
|
|
2037
2000
|
return renderSurfaceLine({ text: row, surface: surfaceSeq, padTo: contentWidth });
|
|
2038
2001
|
}
|
|
2039
|
-
function
|
|
2002
|
+
function layoutTurnRows(role, content, contentWidth, colorEnabled, command) {
|
|
2040
2003
|
content = content.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
2041
|
-
const lines = [];
|
|
2042
2004
|
if (role === "user") {
|
|
2043
2005
|
const logicalLines = content.split("\n");
|
|
2044
2006
|
const accentSeq = colorEnabled ? themeColorSequence("accent") : "";
|
|
@@ -2046,37 +2008,140 @@ function renderTurnBlock(role, content, contentWidth, colorEnabled, command) {
|
|
|
2046
2008
|
const multilinePrefix = colorEnabled ? `${accentSeq}\x1B[1m\u2503 ` : "\u2503 ";
|
|
2047
2009
|
const hangingIndent = colorEnabled ? `${accentSeq}\x1B[1m\u2503 ` : "\u2503 ";
|
|
2048
2010
|
const surfaceSeq = colorEnabled ? userSurfaceBackgroundSequence() : "";
|
|
2011
|
+
const prefixWidth = 3;
|
|
2012
|
+
let lineSourceStart = 0;
|
|
2013
|
+
const rows2 = [];
|
|
2049
2014
|
for (let i = 0; i < logicalLines.length; i++) {
|
|
2050
2015
|
const line = logicalLines[i];
|
|
2051
2016
|
const prefix = i === 0 ? firstPrefix : multilinePrefix;
|
|
2052
2017
|
const styledLine = `${prefix}${line}`;
|
|
2053
|
-
const
|
|
2054
|
-
|
|
2055
|
-
|
|
2018
|
+
const prefixCharCount = prefix.length;
|
|
2019
|
+
const wrappedRows = wrapTranscriptLineWithLayout(
|
|
2020
|
+
styledLine,
|
|
2021
|
+
contentWidth,
|
|
2022
|
+
hangingIndent,
|
|
2023
|
+
lineSourceStart,
|
|
2024
|
+
prefixWidth,
|
|
2025
|
+
prefixCharCount
|
|
2056
2026
|
);
|
|
2027
|
+
for (const r of wrappedRows) {
|
|
2028
|
+
const rendered = surfaceSeq ? fillUserBubbleRow(r.rendered, surfaceSeq, contentWidth) : r.rendered;
|
|
2029
|
+
rows2.push({
|
|
2030
|
+
rendered,
|
|
2031
|
+
sourceStart: r.sourceStart,
|
|
2032
|
+
sourceEnd: r.sourceEnd,
|
|
2033
|
+
prefixWidth: r.prefixWidth,
|
|
2034
|
+
sourceMapping: r.sourceMapping
|
|
2035
|
+
});
|
|
2036
|
+
}
|
|
2037
|
+
lineSourceStart += line.length + 1;
|
|
2057
2038
|
}
|
|
2058
|
-
|
|
2039
|
+
return rows2.length > 0 ? rows2 : [{ rendered: surfaceSeq ? fillUserBubbleRow(firstPrefix, surfaceSeq, contentWidth) : firstPrefix, sourceStart: 0, sourceEnd: 0, prefixWidth: 3 }];
|
|
2040
|
+
}
|
|
2041
|
+
if (role === "local") {
|
|
2059
2042
|
const dimSeq = colorEnabled ? "\x1B[2m" : "";
|
|
2060
2043
|
const resetSeq = colorEnabled ? "\x1B[0m" : "";
|
|
2044
|
+
const rows2 = [];
|
|
2061
2045
|
if (command) {
|
|
2062
|
-
|
|
2063
|
-
|
|
2046
|
+
const cmdPrefix = `${dimSeq}\u203A `;
|
|
2047
|
+
const cmdLine = `${cmdPrefix}${command}${resetSeq}`;
|
|
2048
|
+
const cmdRows = wrapTranscriptLineWithLayout(
|
|
2049
|
+
cmdLine,
|
|
2050
|
+
contentWidth,
|
|
2051
|
+
"",
|
|
2052
|
+
0,
|
|
2053
|
+
2,
|
|
2054
|
+
cmdPrefix.length
|
|
2064
2055
|
);
|
|
2056
|
+
for (const r of cmdRows) {
|
|
2057
|
+
rows2.push({
|
|
2058
|
+
rendered: r.rendered,
|
|
2059
|
+
sourceStart: 0,
|
|
2060
|
+
sourceEnd: 0,
|
|
2061
|
+
prefixWidth: 2,
|
|
2062
|
+
sourceMapping: void 0
|
|
2063
|
+
});
|
|
2064
|
+
}
|
|
2065
2065
|
}
|
|
2066
|
+
let lineSourceStart = 0;
|
|
2066
2067
|
if (content) {
|
|
2067
2068
|
for (const line of content.split("\n")) {
|
|
2068
|
-
|
|
2069
|
-
|
|
2069
|
+
const prefix = `${dimSeq} `;
|
|
2070
|
+
const styledLine = `${prefix}${line}${resetSeq}`;
|
|
2071
|
+
const prefixCharCount = prefix.length;
|
|
2072
|
+
const wrappedRows = wrapTranscriptLineWithLayout(
|
|
2073
|
+
styledLine,
|
|
2074
|
+
contentWidth,
|
|
2075
|
+
" ",
|
|
2076
|
+
lineSourceStart,
|
|
2077
|
+
2,
|
|
2078
|
+
prefixCharCount
|
|
2070
2079
|
);
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2080
|
+
rows2.push(...wrappedRows);
|
|
2081
|
+
lineSourceStart += line.length + 1;
|
|
2082
|
+
}
|
|
2083
|
+
}
|
|
2084
|
+
return rows2.length > 0 ? rows2 : [{ rendered: "", sourceStart: 0, sourceEnd: 0, prefixWidth: 2 }];
|
|
2085
|
+
}
|
|
2086
|
+
const styledEntry = styleAssistantTurn(content, colorEnabled);
|
|
2087
|
+
const styledLines = styledEntry.split("\n");
|
|
2088
|
+
const rawLines = content.split("\n");
|
|
2089
|
+
let rawIdx = 0;
|
|
2090
|
+
let rawOffset = 0;
|
|
2091
|
+
const rows = [];
|
|
2092
|
+
for (let i = 0; i < styledLines.length; i++) {
|
|
2093
|
+
const styledLine = styledLines[i];
|
|
2094
|
+
const isFirstLine = i === 0 && !styledLine.startsWith("[nolo]");
|
|
2095
|
+
const anchorPrefix = isFirstLine ? colorEnabled ? `${themeColorSequence("chrome")}\u25C8\x1B[39m ` : "\u25C8 " : "";
|
|
2096
|
+
const prefixWidth = isFirstLine ? 2 : 0;
|
|
2097
|
+
const prefixCharCount = anchorPrefix.length;
|
|
2098
|
+
if (styledLine === "" && rawIdx < rawLines.length && rawLines[rawIdx] !== "") {
|
|
2099
|
+
rows.push({
|
|
2100
|
+
rendered: "",
|
|
2101
|
+
sourceStart: rawOffset,
|
|
2102
|
+
sourceEnd: rawOffset,
|
|
2103
|
+
prefixWidth: 0
|
|
2104
|
+
});
|
|
2105
|
+
continue;
|
|
2077
2106
|
}
|
|
2078
|
-
|
|
2079
|
-
|
|
2107
|
+
const rawLine = rawIdx < rawLines.length ? rawLines[rawIdx] : "";
|
|
2108
|
+
const rawLineLen = rawLine.length;
|
|
2109
|
+
const sourceMapping = buildSourceMapping(rawLine, styledLine, prefixCharCount);
|
|
2110
|
+
const lineRows = wrapTranscriptLineWithLayout(
|
|
2111
|
+
styledLine,
|
|
2112
|
+
contentWidth,
|
|
2113
|
+
"",
|
|
2114
|
+
rawOffset,
|
|
2115
|
+
prefixWidth,
|
|
2116
|
+
prefixCharCount,
|
|
2117
|
+
sourceMapping,
|
|
2118
|
+
rawLineLen
|
|
2119
|
+
);
|
|
2120
|
+
rows.push(...lineRows);
|
|
2121
|
+
rawIdx += 1;
|
|
2122
|
+
rawOffset += rawLineLen + 1;
|
|
2123
|
+
}
|
|
2124
|
+
return rows.length > 0 ? rows : [{ rendered: "", sourceStart: 0, sourceEnd: 0, prefixWidth: 0 }];
|
|
2125
|
+
}
|
|
2126
|
+
function getTurnLayoutRows(turn, contentWidth, colorEnabled, density, surface) {
|
|
2127
|
+
const cached = turnLineCache.get(turn);
|
|
2128
|
+
if (cached && cached.width === contentWidth && cached.color === colorEnabled && cached.density === density && cached.surface === surface) {
|
|
2129
|
+
return cached.layoutRows;
|
|
2130
|
+
}
|
|
2131
|
+
const layoutRows = layoutTurnRows(turn.role, turn.content, contentWidth, colorEnabled, turn.command);
|
|
2132
|
+
const lines = layoutRows.map((r) => r.rendered);
|
|
2133
|
+
turnLineCache.set(turn, {
|
|
2134
|
+
width: contentWidth,
|
|
2135
|
+
color: colorEnabled,
|
|
2136
|
+
density,
|
|
2137
|
+
surface,
|
|
2138
|
+
lines,
|
|
2139
|
+
layoutRows
|
|
2140
|
+
});
|
|
2141
|
+
return layoutRows;
|
|
2142
|
+
}
|
|
2143
|
+
function renderTurnBlock(role, content, contentWidth, colorEnabled, command) {
|
|
2144
|
+
return layoutTurnRows(role, content, contentWidth, colorEnabled, command).map((r) => r.rendered);
|
|
2080
2145
|
}
|
|
2081
2146
|
var streamingTurnCache = null;
|
|
2082
2147
|
function resetStreamingTurnCache() {
|
|
@@ -2104,12 +2169,12 @@ function renderPrefixTurnBlock(role, content, contentWidth, colorEnabled) {
|
|
|
2104
2169
|
}
|
|
2105
2170
|
function renderTailTurnBlock(role, content, contentWidth, colorEnabled) {
|
|
2106
2171
|
content = content.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
2107
|
-
const lines = [];
|
|
2108
2172
|
if (role === "user") {
|
|
2109
2173
|
const surfaceSeq = colorEnabled ? userSurfaceBackgroundSequence() : "";
|
|
2110
2174
|
const accentSeq = colorEnabled ? themeColorSequence("accent") : "";
|
|
2111
2175
|
const multilinePrefix = colorEnabled ? `${accentSeq}\x1B[1m\u2503 ` : "\u2503 ";
|
|
2112
2176
|
const hangingIndent = colorEnabled ? `${accentSeq}\x1B[1m\u2503 ` : "\u2503 ";
|
|
2177
|
+
const lines = [];
|
|
2113
2178
|
for (const rawLine of content.split("\n")) {
|
|
2114
2179
|
const styledLine = `${multilinePrefix}${rawLine}`;
|
|
2115
2180
|
const rows = wrapTranscriptLine(styledLine, contentWidth, hangingIndent);
|
|
@@ -2117,17 +2182,19 @@ function renderTailTurnBlock(role, content, contentWidth, colorEnabled) {
|
|
|
2117
2182
|
...surfaceSeq ? rows.map((row) => fillUserBubbleRow(row, surfaceSeq, contentWidth)) : rows
|
|
2118
2183
|
);
|
|
2119
2184
|
}
|
|
2185
|
+
return lines;
|
|
2120
2186
|
} else {
|
|
2121
|
-
const highlighted = colorEnabled ? formatAssistantDisplay(content) : stripAnsi(formatAssistantDisplay(content));
|
|
2187
|
+
const highlighted = colorEnabled ? formatAssistantDisplay(content, { trimEdges: false }) : stripAnsi(formatAssistantDisplay(content, { trimEdges: false }));
|
|
2122
2188
|
const rawLines = highlighted.split("\n");
|
|
2123
2189
|
const styledLines = rawLines.map((line) => {
|
|
2124
2190
|
return line.startsWith("[nolo]") && colorEnabled ? themeText(line, "chrome", true) : line;
|
|
2125
2191
|
});
|
|
2192
|
+
const lines = [];
|
|
2126
2193
|
for (const logicalLine of styledLines) {
|
|
2127
2194
|
lines.push(...wrapTranscriptLine(logicalLine, contentWidth));
|
|
2128
2195
|
}
|
|
2196
|
+
return lines;
|
|
2129
2197
|
}
|
|
2130
|
-
return lines;
|
|
2131
2198
|
}
|
|
2132
2199
|
function getStreamingTurnLines(role, content, contentWidth, colorEnabled, density, surface) {
|
|
2133
2200
|
if (streamingTurnCache && (streamingTurnCache.role !== role || streamingTurnCache.contentWidth !== contentWidth || streamingTurnCache.colorEnabled !== colorEnabled || streamingTurnCache.density !== density || streamingTurnCache.surface !== surface || !content.startsWith(streamingTurnCache.fullContent.slice(0, streamingTurnCache.prefixLength)))) {
|
|
@@ -2185,51 +2252,10 @@ function getStreamingTurnLines(role, content, contentWidth, colorEnabled, densit
|
|
|
2185
2252
|
const tailLines = renderTailTurnBlock(role, tailContent, contentWidth, colorEnabled);
|
|
2186
2253
|
return [...streamingTurnCache.prefixLines, ...tailLines];
|
|
2187
2254
|
}
|
|
2188
|
-
var assistantPlainLinesCache = /* @__PURE__ */ new Map();
|
|
2189
|
-
function getAssistantPlainLines(content) {
|
|
2190
|
-
let plainLines = assistantPlainLinesCache.get(content);
|
|
2191
|
-
if (plainLines !== void 0) {
|
|
2192
|
-
return plainLines;
|
|
2193
|
-
}
|
|
2194
|
-
if (!/[\r\x00#|\-*_~`>+\[\]()•☐☑]|\b\d+\./.test(content)) {
|
|
2195
|
-
plainLines = content.trim().split("\n");
|
|
2196
|
-
} else {
|
|
2197
|
-
plainLines = stripAnsi(formatAssistantDisplay(content)).split("\n");
|
|
2198
|
-
}
|
|
2199
|
-
if (assistantPlainLinesCache.size > 2e3) {
|
|
2200
|
-
const firstKey = assistantPlainLinesCache.keys().next().value;
|
|
2201
|
-
if (firstKey !== void 0) assistantPlainLinesCache.delete(firstKey);
|
|
2202
|
-
}
|
|
2203
|
-
assistantPlainLinesCache.set(content, plainLines);
|
|
2204
|
-
return plainLines;
|
|
2205
|
-
}
|
|
2206
2255
|
function countTurnLines(role, content, contentWidth, command) {
|
|
2207
|
-
|
|
2208
|
-
let count = 0;
|
|
2209
|
-
if (role === "user") {
|
|
2210
|
-
for (const line of content.split("\n")) {
|
|
2211
|
-
count += wrapTranscriptLine(`\u2503 ${line}`, contentWidth, "\u2503 ").length;
|
|
2212
|
-
}
|
|
2213
|
-
} else if (role === "local") {
|
|
2214
|
-
if (command) {
|
|
2215
|
-
count += wrapTranscriptLine(`\u203A ${command}`, contentWidth).length;
|
|
2216
|
-
}
|
|
2217
|
-
if (content) {
|
|
2218
|
-
for (const line of content.split("\n")) {
|
|
2219
|
-
count += wrapTranscriptLine(` ${line}`, contentWidth).length;
|
|
2220
|
-
}
|
|
2221
|
-
}
|
|
2222
|
-
} else {
|
|
2223
|
-
const plainLines = getAssistantPlainLines(content);
|
|
2224
|
-
for (let i = 0; i < plainLines.length; i++) {
|
|
2225
|
-
const line = plainLines[i];
|
|
2226
|
-
const wrapped = i === 0 && !line.startsWith("[nolo]") ? wrapTranscriptLine(`\u25C8 ${line}`, contentWidth) : wrapTranscriptLine(line, contentWidth);
|
|
2227
|
-
count += wrapped.length;
|
|
2228
|
-
}
|
|
2229
|
-
}
|
|
2230
|
-
return count;
|
|
2256
|
+
return layoutTurnRows(role, content, contentWidth, false, command).length;
|
|
2231
2257
|
}
|
|
2232
|
-
function
|
|
2258
|
+
function buildTurnOffsets(history, contentWidth) {
|
|
2233
2259
|
const density = getActiveDensity();
|
|
2234
2260
|
const entries = [];
|
|
2235
2261
|
let offset = 0;
|
|
@@ -2250,6 +2276,36 @@ function buildTurnOffsets2(history, contentWidth) {
|
|
|
2250
2276
|
}
|
|
2251
2277
|
return { entries, totalLines: offset };
|
|
2252
2278
|
}
|
|
2279
|
+
function getAllTurnEntries(history, contentWidth) {
|
|
2280
|
+
const { entries, totalLines: finalizedLines } = buildTurnOffsets(history, contentWidth);
|
|
2281
|
+
const turns = [...history.turns];
|
|
2282
|
+
if (history.currentRole !== null && history.currentContent) {
|
|
2283
|
+
const density = getActiveDensity();
|
|
2284
|
+
const colorEnabled = resolveCliColorEnabled();
|
|
2285
|
+
const surface = colorEnabled ? userSurfaceBackgroundSequence() : "";
|
|
2286
|
+
const streamingLines = getStreamingTurnLines(
|
|
2287
|
+
history.currentRole,
|
|
2288
|
+
history.currentContent,
|
|
2289
|
+
contentWidth,
|
|
2290
|
+
colorEnabled,
|
|
2291
|
+
density,
|
|
2292
|
+
surface
|
|
2293
|
+
);
|
|
2294
|
+
const sep = currentTurnSeparator(history, density);
|
|
2295
|
+
const startRow = finalizedLines + sep;
|
|
2296
|
+
entries.push({
|
|
2297
|
+
startRow,
|
|
2298
|
+
lineCount: streamingLines.length,
|
|
2299
|
+
separatorAbove: sep
|
|
2300
|
+
});
|
|
2301
|
+
turns.push({
|
|
2302
|
+
role: history.currentRole,
|
|
2303
|
+
content: history.currentContent
|
|
2304
|
+
});
|
|
2305
|
+
return { entries, totalLines: startRow + streamingLines.length, turns };
|
|
2306
|
+
}
|
|
2307
|
+
return { entries, totalLines: finalizedLines, turns };
|
|
2308
|
+
}
|
|
2253
2309
|
function currentTurnSeparator(history, density) {
|
|
2254
2310
|
return density === "spacious" && (history.turns.length > 0 || history.currentRole === "user") ? 1 : 0;
|
|
2255
2311
|
}
|
|
@@ -2273,6 +2329,37 @@ function buildCopyViewLines(history) {
|
|
|
2273
2329
|
}
|
|
2274
2330
|
return lines;
|
|
2275
2331
|
}
|
|
2332
|
+
function buildHistoryLines(history, contentWidth) {
|
|
2333
|
+
const colorEnabled = resolveCliColorEnabled();
|
|
2334
|
+
const density = getActiveDensity();
|
|
2335
|
+
const surface = colorEnabled ? userSurfaceBackgroundSequence() : "";
|
|
2336
|
+
const wrapped = [];
|
|
2337
|
+
for (let i = 0; i < history.turns.length; i++) {
|
|
2338
|
+
const turn = history.turns[i];
|
|
2339
|
+
if (density === "spacious" && (i > 0 || turn.role === "user")) {
|
|
2340
|
+
wrapped.push("");
|
|
2341
|
+
}
|
|
2342
|
+
const layoutRows = getTurnLayoutRows(turn, contentWidth, colorEnabled, density, surface);
|
|
2343
|
+
wrapped.push(...layoutRows.map((r) => r.rendered));
|
|
2344
|
+
}
|
|
2345
|
+
if (history.currentRole !== null && history.currentContent) {
|
|
2346
|
+
const i = history.turns.length;
|
|
2347
|
+
if (density === "spacious" && (i > 0 || history.currentRole === "user")) {
|
|
2348
|
+
wrapped.push("");
|
|
2349
|
+
}
|
|
2350
|
+
const streamingLines = getStreamingTurnLines(
|
|
2351
|
+
history.currentRole,
|
|
2352
|
+
history.currentContent,
|
|
2353
|
+
contentWidth,
|
|
2354
|
+
colorEnabled,
|
|
2355
|
+
density,
|
|
2356
|
+
surface
|
|
2357
|
+
);
|
|
2358
|
+
wrapped.push(...streamingLines);
|
|
2359
|
+
}
|
|
2360
|
+
return wrapped;
|
|
2361
|
+
}
|
|
2362
|
+
var renderCacheMissCount = 0;
|
|
2276
2363
|
function renderHistory(output, history, inputLines, selection) {
|
|
2277
2364
|
const tty = output;
|
|
2278
2365
|
if (!tty.isTTY) return;
|
|
@@ -2283,13 +2370,9 @@ function renderHistory(output, history, inputLines, selection) {
|
|
|
2283
2370
|
const colorEnabled = resolveCliColorEnabled();
|
|
2284
2371
|
const density = getActiveDensity();
|
|
2285
2372
|
const surface = colorEnabled ? userSurfaceBackgroundSequence() : "";
|
|
2286
|
-
const { entries, totalLines: finalizedLines } =
|
|
2287
|
-
history,
|
|
2288
|
-
contentWidth
|
|
2289
|
-
);
|
|
2290
|
-
let totalLines = finalizedLines;
|
|
2291
|
-
let currentStart = -1;
|
|
2373
|
+
const { entries, totalLines: finalizedLines } = buildTurnOffsets(history, contentWidth);
|
|
2292
2374
|
let currentLines = [];
|
|
2375
|
+
let currentStart = -1;
|
|
2293
2376
|
if (history.currentRole !== null && history.currentContent) {
|
|
2294
2377
|
currentLines = getStreamingTurnLines(
|
|
2295
2378
|
history.currentRole,
|
|
@@ -2299,16 +2382,17 @@ function renderHistory(output, history, inputLines, selection) {
|
|
|
2299
2382
|
density,
|
|
2300
2383
|
surface
|
|
2301
2384
|
);
|
|
2302
|
-
|
|
2303
|
-
|
|
2385
|
+
const sep = currentTurnSeparator(history, density);
|
|
2386
|
+
currentStart = finalizedLines + sep;
|
|
2304
2387
|
}
|
|
2388
|
+
const totalLines = currentStart >= 0 ? currentStart + currentLines.length : finalizedLines;
|
|
2305
2389
|
if (history.followBottom) {
|
|
2306
2390
|
history.scrollTop = Math.max(0, totalLines - visibleHeight);
|
|
2307
2391
|
} else {
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2392
|
+
const maxScroll = Math.max(0, totalLines - visibleHeight);
|
|
2393
|
+
if (history.scrollTop > maxScroll) {
|
|
2394
|
+
history.scrollTop = maxScroll;
|
|
2395
|
+
}
|
|
2312
2396
|
}
|
|
2313
2397
|
history.hasMoreAbove = history.scrollTop > 0;
|
|
2314
2398
|
history.hasMoreBelow = history.scrollTop + visibleHeight < totalLines;
|
|
@@ -2328,20 +2412,14 @@ function renderHistory(output, history, inputLines, selection) {
|
|
|
2328
2412
|
if (turnEnd <= winStart || turnStart >= winEnd) continue;
|
|
2329
2413
|
const turn = history.turns[i];
|
|
2330
2414
|
const cached = turnLineCache.get(turn);
|
|
2331
|
-
let
|
|
2415
|
+
let layoutRows;
|
|
2332
2416
|
if (cached && cached.width === contentWidth && cached.color === colorEnabled && cached.density === density && cached.surface === surface) {
|
|
2333
|
-
|
|
2417
|
+
layoutRows = cached.layoutRows;
|
|
2334
2418
|
} else {
|
|
2335
2419
|
renderCacheMissCount += 1;
|
|
2336
|
-
|
|
2337
|
-
turnLineCache.set(turn, {
|
|
2338
|
-
width: contentWidth,
|
|
2339
|
-
color: colorEnabled,
|
|
2340
|
-
density,
|
|
2341
|
-
surface,
|
|
2342
|
-
lines
|
|
2343
|
-
});
|
|
2420
|
+
layoutRows = getTurnLayoutRows(turn, contentWidth, colorEnabled, density, surface);
|
|
2344
2421
|
}
|
|
2422
|
+
const lines = layoutRows.map((r) => r.rendered);
|
|
2345
2423
|
const interStart = Math.max(turnStart, winStart);
|
|
2346
2424
|
const interEnd = Math.min(turnEnd, winEnd);
|
|
2347
2425
|
for (let r = interStart; r < interEnd; r++) {
|
|
@@ -2365,7 +2443,7 @@ function renderHistory(output, history, inputLines, selection) {
|
|
|
2365
2443
|
}
|
|
2366
2444
|
}
|
|
2367
2445
|
}
|
|
2368
|
-
if (selection && selection.
|
|
2446
|
+
if (selection && selection.anchor && selection.head) {
|
|
2369
2447
|
visibleLines = applySelectionOverlay(
|
|
2370
2448
|
visibleLines,
|
|
2371
2449
|
history,
|
|
@@ -2377,11 +2455,11 @@ function renderHistory(output, history, inputLines, selection) {
|
|
|
2377
2455
|
const prevBuffer = typeof output === "object" && output !== null ? frameBufferByOutput.get(output) : void 0;
|
|
2378
2456
|
const isGeometryCompatible = prevBuffer !== void 0 && prevBuffer.rows === rows && prevBuffer.columns === columns && prevBuffer.inputLines === inputLines && prevBuffer.lines.length === visibleHeight;
|
|
2379
2457
|
const prevLines = isGeometryCompatible ? prevBuffer.lines : void 0;
|
|
2380
|
-
const nextLines = new Array(visibleHeight);
|
|
2381
2458
|
let frame = "";
|
|
2459
|
+
const nextLines = new Array(visibleHeight);
|
|
2382
2460
|
for (let i = 0; i < visibleHeight; i++) {
|
|
2383
|
-
const
|
|
2384
|
-
const padded = padOrTruncateToWidth(
|
|
2461
|
+
const content = visibleLines[i] ?? "";
|
|
2462
|
+
const padded = padOrTruncateToWidth(content, contentWidth);
|
|
2385
2463
|
const thumb = renderScrollbarRow(i, visibleHeight, totalLines, history.scrollTop);
|
|
2386
2464
|
const scrollbarPrefix = colorEnabled ? themeColorSequence("chrome") : "";
|
|
2387
2465
|
const scrollbarSuffix = colorEnabled ? "\x1B[39m" : "";
|
|
@@ -2407,9 +2485,6 @@ function renderHistory(output, history, inputLines, selection) {
|
|
|
2407
2485
|
}
|
|
2408
2486
|
function createHistoryOutputStream(history, onUpdate) {
|
|
2409
2487
|
return {
|
|
2410
|
-
// Virtual TTY: Spinner uses \\r in-place updates. We honor that via
|
|
2411
|
-
// applyTerminalOutputToText so frames collapse to one status line instead
|
|
2412
|
-
// of spamming the transcript. Do not fall through to process.stdout here.
|
|
2413
2488
|
isTTY: true,
|
|
2414
2489
|
write(chunk) {
|
|
2415
2490
|
const text = typeof chunk === "string" ? chunk : chunk.toString();
|
|
@@ -2426,7 +2501,7 @@ function applyScrollAction(history, action, output, inputLines) {
|
|
|
2426
2501
|
const columns = tty.columns ?? 80;
|
|
2427
2502
|
const visibleHeight = Math.max(1, rows - inputLines);
|
|
2428
2503
|
const contentWidth = Math.max(1, columns - 1);
|
|
2429
|
-
const { totalLines: finalizedLines } =
|
|
2504
|
+
const { totalLines: finalizedLines } = buildTurnOffsets(history, contentWidth);
|
|
2430
2505
|
let totalLines = finalizedLines;
|
|
2431
2506
|
if (history.currentRole !== null && history.currentContent) {
|
|
2432
2507
|
totalLines += currentTurnSeparator(history, getActiveDensity()) + countTurnLines(history.currentRole, history.currentContent, contentWidth);
|
|
@@ -7406,7 +7481,7 @@ ${err.message}` : ""}`
|
|
|
7406
7481
|
stopAutoScroll();
|
|
7407
7482
|
}
|
|
7408
7483
|
} else {
|
|
7409
|
-
const { totalLines } =
|
|
7484
|
+
const { totalLines } = getAllTurnEntries(history, contentWidth);
|
|
7410
7485
|
const maxScroll = Math.max(0, totalLines - visibleHeight);
|
|
7411
7486
|
if (history.scrollTop < maxScroll) {
|
|
7412
7487
|
history.scrollTop = Math.min(maxScroll, history.scrollTop + 1);
|
|
@@ -7573,13 +7648,18 @@ ${merged}` : merged;
|
|
|
7573
7648
|
import("./clipboardy-MMBYVRLF.js").then(({ default: clipboard }) => clipboard.write(textToCopy)).catch(() => {
|
|
7574
7649
|
});
|
|
7575
7650
|
}
|
|
7651
|
+
selectionState.dragging = false;
|
|
7652
|
+
} else {
|
|
7653
|
+
clearSelection();
|
|
7576
7654
|
}
|
|
7577
|
-
clearSelection();
|
|
7578
7655
|
paintFrame(buffer);
|
|
7579
7656
|
return;
|
|
7580
7657
|
}
|
|
7581
7658
|
return;
|
|
7582
7659
|
}
|
|
7660
|
+
if (selectionState.anchor) {
|
|
7661
|
+
clearSelection();
|
|
7662
|
+
}
|
|
7583
7663
|
const scrollAction = parseScrollAction(sequence);
|
|
7584
7664
|
if (scrollAction) {
|
|
7585
7665
|
if (fixedInput.isPaused()) return;
|