nolo-cli 0.33.0-alpha.20 → 0.33.0-alpha.22
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.
|
@@ -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-AEYCNMJI.js";
|
|
74
77
|
import "./chunk-ZHYK3N56.js";
|
|
75
78
|
import {
|
|
76
79
|
getReadableCliDb
|
|
@@ -1754,197 +1757,179 @@ 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
|
-
|
|
1769
|
-
const
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
const sourceOffset = mapRowColToSourceOffset(
|
|
1793
|
-
turn.content,
|
|
1794
|
-
turn.role,
|
|
1795
|
-
contentWidth,
|
|
1796
|
-
rowInTurn,
|
|
1797
|
-
screenCol,
|
|
1798
|
-
turn.command
|
|
1799
|
-
);
|
|
1800
|
-
return { turnIndex: i, sourceOffset };
|
|
1768
|
+
return a.globalRow === b.globalRow && a.col === b.col;
|
|
1769
|
+
}
|
|
1770
|
+
function highlightLineByColumns(line, selStartCol, selEndCol, prefixWidth = 0) {
|
|
1771
|
+
const tokens = tokenizeAnsiLine(line);
|
|
1772
|
+
const range = resolveSelectableColumnRange(
|
|
1773
|
+
tokens,
|
|
1774
|
+
selStartCol,
|
|
1775
|
+
selEndCol,
|
|
1776
|
+
prefixWidth
|
|
1777
|
+
);
|
|
1778
|
+
if (!range) return line;
|
|
1779
|
+
let out = "";
|
|
1780
|
+
let currentCol = 0;
|
|
1781
|
+
let isHighlightActive = false;
|
|
1782
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
1783
|
+
const token = tokens[i];
|
|
1784
|
+
if (token.kind === "sgr") {
|
|
1785
|
+
if (isHighlightActive) {
|
|
1786
|
+
if (/^\x1b\[0?m$/.test(token.value)) {
|
|
1787
|
+
out += `${token.value}\x1B[7m`;
|
|
1788
|
+
} else {
|
|
1789
|
+
out += token.value;
|
|
1790
|
+
}
|
|
1791
|
+
} else {
|
|
1792
|
+
out += token.value;
|
|
1793
|
+
}
|
|
1794
|
+
continue;
|
|
1801
1795
|
}
|
|
1796
|
+
const charStartCol = currentCol;
|
|
1797
|
+
const charEndCol = currentCol + token.width;
|
|
1798
|
+
const isSelected = charStartCol >= range.start && charStartCol < range.end;
|
|
1799
|
+
if (isSelected && !isHighlightActive) {
|
|
1800
|
+
out += "\x1B[7m";
|
|
1801
|
+
isHighlightActive = true;
|
|
1802
|
+
} else if (!isSelected && isHighlightActive) {
|
|
1803
|
+
out += "\x1B[27m";
|
|
1804
|
+
isHighlightActive = false;
|
|
1805
|
+
}
|
|
1806
|
+
out += token.value;
|
|
1807
|
+
currentCol = charEndCol;
|
|
1802
1808
|
}
|
|
1803
|
-
|
|
1809
|
+
if (isHighlightActive) {
|
|
1810
|
+
out += "\x1B[27m";
|
|
1811
|
+
}
|
|
1812
|
+
return out;
|
|
1804
1813
|
}
|
|
1805
|
-
function
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
let
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
if (
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
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;
|
|
1862
|
-
}
|
|
1863
|
-
colAccum += w;
|
|
1864
|
-
offsetInLine += char.length;
|
|
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;
|
|
1869
|
-
}
|
|
1870
|
-
return finalOffset;
|
|
1814
|
+
function resolveSelectableColumnRange(tokens, requestedStart, requestedEnd, prefixWidth) {
|
|
1815
|
+
if (requestedStart >= requestedEnd) return null;
|
|
1816
|
+
let col = 0;
|
|
1817
|
+
let lastNonSpaceCol = 0;
|
|
1818
|
+
for (const token of tokens) {
|
|
1819
|
+
if (token.kind !== "char") continue;
|
|
1820
|
+
if (token.value.trim().length > 0) {
|
|
1821
|
+
lastNonSpaceCol = col + token.width;
|
|
1822
|
+
}
|
|
1823
|
+
col += token.width;
|
|
1824
|
+
}
|
|
1825
|
+
const start = Math.max(prefixWidth, requestedStart);
|
|
1826
|
+
const end = Math.min(requestedEnd, lastNonSpaceCol);
|
|
1827
|
+
if (start >= end) return null;
|
|
1828
|
+
let snappedStart = null;
|
|
1829
|
+
let snappedEnd = null;
|
|
1830
|
+
col = 0;
|
|
1831
|
+
for (const token of tokens) {
|
|
1832
|
+
if (token.kind !== "char") continue;
|
|
1833
|
+
const tokenStart = col;
|
|
1834
|
+
const tokenEnd = col + token.width;
|
|
1835
|
+
if (tokenEnd > start && tokenStart < end) {
|
|
1836
|
+
snappedStart ??= tokenStart;
|
|
1837
|
+
snappedEnd = tokenEnd;
|
|
1838
|
+
}
|
|
1839
|
+
col = tokenEnd;
|
|
1840
|
+
}
|
|
1841
|
+
return snappedStart === null || snappedEnd === null ? null : { start: snappedStart, end: snappedEnd };
|
|
1842
|
+
}
|
|
1843
|
+
function hitTestHistory(history, screenRow, screenCol, _contentWidth, scrollTop) {
|
|
1844
|
+
const globalRow = Math.max(0, scrollTop + screenRow);
|
|
1845
|
+
const col = Math.max(0, screenCol);
|
|
1846
|
+
return { globalRow, col };
|
|
1847
|
+
}
|
|
1848
|
+
function extractTextSliceByColumns(line, startCol, endCol, prefixWidth = 0) {
|
|
1849
|
+
const tokens = tokenizeAnsiLine(line);
|
|
1850
|
+
const range = resolveSelectableColumnRange(
|
|
1851
|
+
tokens,
|
|
1852
|
+
startCol,
|
|
1853
|
+
endCol,
|
|
1854
|
+
prefixWidth
|
|
1855
|
+
);
|
|
1856
|
+
if (!range) return "";
|
|
1857
|
+
let col = 0;
|
|
1858
|
+
let text = "";
|
|
1859
|
+
for (const token of tokens) {
|
|
1860
|
+
if (token.kind !== "char") continue;
|
|
1861
|
+
if (col >= range.start && col < range.end) {
|
|
1862
|
+
text += token.value;
|
|
1871
1863
|
}
|
|
1872
|
-
|
|
1873
|
-
charAccumulator += lineLen + 1;
|
|
1864
|
+
col += token.width;
|
|
1874
1865
|
}
|
|
1875
|
-
return
|
|
1866
|
+
return text;
|
|
1876
1867
|
}
|
|
1877
|
-
function extractSelectedText(history, anchor, head) {
|
|
1868
|
+
function extractSelectedText(history, anchor, head, contentWidth) {
|
|
1878
1869
|
if (!anchor || !head) return "";
|
|
1879
1870
|
const cmp = compareSelectionPoints(anchor, head);
|
|
1880
1871
|
if (cmp === 0) return "";
|
|
1881
1872
|
const start = cmp < 0 ? anchor : head;
|
|
1882
1873
|
const end = cmp < 0 ? head : anchor;
|
|
1883
|
-
|
|
1884
|
-
const turn = history.turns[start.turnIndex];
|
|
1885
|
-
if (!turn) return "";
|
|
1886
|
-
const raw = turn.content.slice(start.sourceOffset, end.sourceOffset);
|
|
1887
|
-
return stripAnsi(raw);
|
|
1888
|
-
}
|
|
1874
|
+
const rows = buildHistoryLayoutRows(history, contentWidth);
|
|
1889
1875
|
const pieces = [];
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1876
|
+
for (let r = start.globalRow; r <= end.globalRow; r++) {
|
|
1877
|
+
const row = rows[r];
|
|
1878
|
+
if (!row) continue;
|
|
1879
|
+
let lineStartCol = 0;
|
|
1880
|
+
let lineEndCol = Infinity;
|
|
1881
|
+
if (r === start.globalRow) {
|
|
1882
|
+
lineStartCol = start.col;
|
|
1883
|
+
}
|
|
1884
|
+
if (r === end.globalRow) {
|
|
1885
|
+
lineEndCol = end.col;
|
|
1886
|
+
}
|
|
1887
|
+
pieces.push(
|
|
1888
|
+
extractTextSliceByColumns(
|
|
1889
|
+
row.rendered,
|
|
1890
|
+
lineStartCol,
|
|
1891
|
+
lineEndCol,
|
|
1892
|
+
row.prefixWidth
|
|
1893
|
+
)
|
|
1894
|
+
);
|
|
1895
|
+
if (r < end.globalRow) {
|
|
1896
|
+
pieces.push(row.softWrapped ? row.softWrapJoiner ?? "" : "\n");
|
|
1898
1897
|
}
|
|
1899
1898
|
}
|
|
1900
|
-
|
|
1901
|
-
if (endTurn) {
|
|
1902
|
-
pieces.push(endTurn.content.slice(0, end.sourceOffset));
|
|
1903
|
-
}
|
|
1904
|
-
return stripAnsi(pieces.join("\n\n"));
|
|
1899
|
+
return pieces.join("");
|
|
1905
1900
|
}
|
|
1906
1901
|
function applySelectionOverlay(visibleLines, history, contentWidth, scrollTop, selection) {
|
|
1907
|
-
if (!selection.
|
|
1902
|
+
if (!selection.anchor || !selection.head) {
|
|
1908
1903
|
return visibleLines;
|
|
1909
1904
|
}
|
|
1910
1905
|
const cmp = compareSelectionPoints(selection.anchor, selection.head);
|
|
1911
1906
|
if (cmp === 0) return visibleLines;
|
|
1912
1907
|
const start = cmp < 0 ? selection.anchor : selection.head;
|
|
1913
1908
|
const end = cmp < 0 ? selection.head : selection.anchor;
|
|
1914
|
-
const
|
|
1909
|
+
const layoutRows = buildHistoryLayoutRows(history, contentWidth);
|
|
1915
1910
|
const result = [...visibleLines];
|
|
1916
1911
|
for (let screenRow = 0; screenRow < visibleLines.length; screenRow++) {
|
|
1917
1912
|
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
|
-
}
|
|
1941
|
-
}
|
|
1942
|
-
if (isSelectedRow) {
|
|
1943
|
-
const line = result[screenRow] ?? "";
|
|
1944
|
-
if (line.length > 0) {
|
|
1945
|
-
result[screenRow] = `\x1B[7m${line}\x1B[27m`;
|
|
1946
|
-
}
|
|
1913
|
+
if (globalRow < start.globalRow || globalRow > end.globalRow) {
|
|
1914
|
+
continue;
|
|
1947
1915
|
}
|
|
1916
|
+
const currentLine = result[screenRow] ?? "";
|
|
1917
|
+
if (currentLine.length === 0) continue;
|
|
1918
|
+
const layoutRow = layoutRows[globalRow];
|
|
1919
|
+
let selStartCol = 0;
|
|
1920
|
+
let selEndCol = Infinity;
|
|
1921
|
+
if (globalRow === start.globalRow) {
|
|
1922
|
+
selStartCol = start.col;
|
|
1923
|
+
}
|
|
1924
|
+
if (globalRow === end.globalRow) {
|
|
1925
|
+
selEndCol = end.col;
|
|
1926
|
+
}
|
|
1927
|
+
result[screenRow] = highlightLineByColumns(
|
|
1928
|
+
currentLine,
|
|
1929
|
+
selStartCol,
|
|
1930
|
+
selEndCol,
|
|
1931
|
+
layoutRow?.prefixWidth ?? 0
|
|
1932
|
+
);
|
|
1948
1933
|
}
|
|
1949
1934
|
return result;
|
|
1950
1935
|
}
|
|
@@ -1959,7 +1944,6 @@ function resetHistoryFrameDiffCache(output) {
|
|
|
1959
1944
|
frameBufferByOutput.delete(output);
|
|
1960
1945
|
}
|
|
1961
1946
|
}
|
|
1962
|
-
var renderCacheMissCount = 0;
|
|
1963
1947
|
function createTurnHistory() {
|
|
1964
1948
|
return {
|
|
1965
1949
|
turns: [],
|
|
@@ -1970,11 +1954,8 @@ function createTurnHistory() {
|
|
|
1970
1954
|
};
|
|
1971
1955
|
}
|
|
1972
1956
|
function startTurn(history, role) {
|
|
1973
|
-
if (history.currentRole !== null) {
|
|
1974
|
-
history
|
|
1975
|
-
role: history.currentRole,
|
|
1976
|
-
content: history.currentContent
|
|
1977
|
-
});
|
|
1957
|
+
if (history.currentRole !== null && history.currentContent) {
|
|
1958
|
+
finalizeCurrentTurn(history);
|
|
1978
1959
|
}
|
|
1979
1960
|
history.currentRole = role;
|
|
1980
1961
|
history.currentContent = "";
|
|
@@ -2036,9 +2017,8 @@ function fillUserBubbleRow(row, surfaceSeq, contentWidth) {
|
|
|
2036
2017
|
}
|
|
2037
2018
|
return renderSurfaceLine({ text: row, surface: surfaceSeq, padTo: contentWidth });
|
|
2038
2019
|
}
|
|
2039
|
-
function
|
|
2020
|
+
function layoutTurnRows(role, content, contentWidth, colorEnabled, command) {
|
|
2040
2021
|
content = content.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
2041
|
-
const lines = [];
|
|
2042
2022
|
if (role === "user") {
|
|
2043
2023
|
const logicalLines = content.split("\n");
|
|
2044
2024
|
const accentSeq = colorEnabled ? themeColorSequence("accent") : "";
|
|
@@ -2046,37 +2026,144 @@ function renderTurnBlock(role, content, contentWidth, colorEnabled, command) {
|
|
|
2046
2026
|
const multilinePrefix = colorEnabled ? `${accentSeq}\x1B[1m\u2503 ` : "\u2503 ";
|
|
2047
2027
|
const hangingIndent = colorEnabled ? `${accentSeq}\x1B[1m\u2503 ` : "\u2503 ";
|
|
2048
2028
|
const surfaceSeq = colorEnabled ? userSurfaceBackgroundSequence() : "";
|
|
2029
|
+
const prefixWidth = 3;
|
|
2030
|
+
let lineSourceStart = 0;
|
|
2031
|
+
const rows2 = [];
|
|
2049
2032
|
for (let i = 0; i < logicalLines.length; i++) {
|
|
2050
2033
|
const line = logicalLines[i];
|
|
2051
2034
|
const prefix = i === 0 ? firstPrefix : multilinePrefix;
|
|
2052
2035
|
const styledLine = `${prefix}${line}`;
|
|
2053
|
-
const
|
|
2054
|
-
|
|
2055
|
-
|
|
2036
|
+
const prefixCharCount = prefix.length;
|
|
2037
|
+
const wrappedRows = wrapTranscriptLineWithLayout(
|
|
2038
|
+
styledLine,
|
|
2039
|
+
contentWidth,
|
|
2040
|
+
hangingIndent,
|
|
2041
|
+
lineSourceStart,
|
|
2042
|
+
prefixWidth,
|
|
2043
|
+
prefixCharCount
|
|
2056
2044
|
);
|
|
2045
|
+
for (const r of wrappedRows) {
|
|
2046
|
+
const rendered = surfaceSeq ? fillUserBubbleRow(r.rendered, surfaceSeq, contentWidth) : r.rendered;
|
|
2047
|
+
rows2.push({
|
|
2048
|
+
rendered,
|
|
2049
|
+
sourceStart: r.sourceStart,
|
|
2050
|
+
sourceEnd: r.sourceEnd,
|
|
2051
|
+
prefixWidth: r.prefixWidth,
|
|
2052
|
+
sourceMapping: r.sourceMapping,
|
|
2053
|
+
softWrapped: r.softWrapped,
|
|
2054
|
+
softWrapJoiner: r.softWrapJoiner
|
|
2055
|
+
});
|
|
2056
|
+
}
|
|
2057
|
+
lineSourceStart += line.length + 1;
|
|
2057
2058
|
}
|
|
2058
|
-
|
|
2059
|
+
return rows2.length > 0 ? rows2 : [{ rendered: surfaceSeq ? fillUserBubbleRow(firstPrefix, surfaceSeq, contentWidth) : firstPrefix, sourceStart: 0, sourceEnd: 0, prefixWidth: 3 }];
|
|
2060
|
+
}
|
|
2061
|
+
if (role === "local") {
|
|
2059
2062
|
const dimSeq = colorEnabled ? "\x1B[2m" : "";
|
|
2060
2063
|
const resetSeq = colorEnabled ? "\x1B[0m" : "";
|
|
2064
|
+
const rows2 = [];
|
|
2061
2065
|
if (command) {
|
|
2062
|
-
|
|
2063
|
-
|
|
2066
|
+
const cmdPrefix = `${dimSeq}\u203A `;
|
|
2067
|
+
const cmdLine = `${cmdPrefix}${command}${resetSeq}`;
|
|
2068
|
+
const cmdRows = wrapTranscriptLineWithLayout(
|
|
2069
|
+
cmdLine,
|
|
2070
|
+
contentWidth,
|
|
2071
|
+
"",
|
|
2072
|
+
0,
|
|
2073
|
+
2,
|
|
2074
|
+
cmdPrefix.length
|
|
2064
2075
|
);
|
|
2076
|
+
for (const r of cmdRows) {
|
|
2077
|
+
rows2.push({
|
|
2078
|
+
rendered: r.rendered,
|
|
2079
|
+
sourceStart: 0,
|
|
2080
|
+
sourceEnd: 0,
|
|
2081
|
+
prefixWidth: 2,
|
|
2082
|
+
sourceMapping: void 0,
|
|
2083
|
+
softWrapped: r.softWrapped,
|
|
2084
|
+
softWrapJoiner: r.softWrapJoiner
|
|
2085
|
+
});
|
|
2086
|
+
}
|
|
2065
2087
|
}
|
|
2088
|
+
let lineSourceStart = 0;
|
|
2066
2089
|
if (content) {
|
|
2067
2090
|
for (const line of content.split("\n")) {
|
|
2068
|
-
|
|
2069
|
-
|
|
2091
|
+
const prefix = `${dimSeq} `;
|
|
2092
|
+
const styledLine = `${prefix}${line}${resetSeq}`;
|
|
2093
|
+
const prefixCharCount = prefix.length;
|
|
2094
|
+
const wrappedRows = wrapTranscriptLineWithLayout(
|
|
2095
|
+
styledLine,
|
|
2096
|
+
contentWidth,
|
|
2097
|
+
" ",
|
|
2098
|
+
lineSourceStart,
|
|
2099
|
+
2,
|
|
2100
|
+
prefixCharCount
|
|
2070
2101
|
);
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2102
|
+
rows2.push(...wrappedRows);
|
|
2103
|
+
lineSourceStart += line.length + 1;
|
|
2104
|
+
}
|
|
2105
|
+
}
|
|
2106
|
+
return rows2.length > 0 ? rows2 : [{ rendered: "", sourceStart: 0, sourceEnd: 0, prefixWidth: 2 }];
|
|
2107
|
+
}
|
|
2108
|
+
const styledEntry = styleAssistantTurn(content, colorEnabled);
|
|
2109
|
+
const styledLines = styledEntry.split("\n");
|
|
2110
|
+
const rawLines = content.split("\n");
|
|
2111
|
+
let rawIdx = 0;
|
|
2112
|
+
let rawOffset = 0;
|
|
2113
|
+
const rows = [];
|
|
2114
|
+
for (let i = 0; i < styledLines.length; i++) {
|
|
2115
|
+
const styledLine = styledLines[i];
|
|
2116
|
+
const isFirstLine = i === 0 && !styledLine.startsWith("[nolo]");
|
|
2117
|
+
const anchorPrefix = isFirstLine ? colorEnabled ? `${themeColorSequence("chrome")}\u25C8\x1B[39m ` : "\u25C8 " : "";
|
|
2118
|
+
const prefixWidth = isFirstLine ? 2 : 0;
|
|
2119
|
+
const prefixCharCount = anchorPrefix.length;
|
|
2120
|
+
if (styledLine === "" && rawIdx < rawLines.length && rawLines[rawIdx] !== "") {
|
|
2121
|
+
rows.push({
|
|
2122
|
+
rendered: "",
|
|
2123
|
+
sourceStart: rawOffset,
|
|
2124
|
+
sourceEnd: rawOffset,
|
|
2125
|
+
prefixWidth: 0
|
|
2126
|
+
});
|
|
2127
|
+
continue;
|
|
2077
2128
|
}
|
|
2078
|
-
|
|
2079
|
-
|
|
2129
|
+
const rawLine = rawIdx < rawLines.length ? rawLines[rawIdx] : "";
|
|
2130
|
+
const rawLineLen = rawLine.length;
|
|
2131
|
+
const sourceMapping = buildSourceMapping(rawLine, styledLine, prefixCharCount);
|
|
2132
|
+
const lineRows = wrapTranscriptLineWithLayout(
|
|
2133
|
+
styledLine,
|
|
2134
|
+
contentWidth,
|
|
2135
|
+
"",
|
|
2136
|
+
rawOffset,
|
|
2137
|
+
prefixWidth,
|
|
2138
|
+
prefixCharCount,
|
|
2139
|
+
sourceMapping,
|
|
2140
|
+
rawLineLen
|
|
2141
|
+
);
|
|
2142
|
+
rows.push(...lineRows);
|
|
2143
|
+
rawIdx += 1;
|
|
2144
|
+
rawOffset += rawLineLen + 1;
|
|
2145
|
+
}
|
|
2146
|
+
return rows.length > 0 ? rows : [{ rendered: "", sourceStart: 0, sourceEnd: 0, prefixWidth: 0 }];
|
|
2147
|
+
}
|
|
2148
|
+
function getTurnLayoutRows(turn, contentWidth, colorEnabled, density, surface) {
|
|
2149
|
+
const cached = turnLineCache.get(turn);
|
|
2150
|
+
if (cached && cached.width === contentWidth && cached.color === colorEnabled && cached.density === density && cached.surface === surface) {
|
|
2151
|
+
return cached.layoutRows;
|
|
2152
|
+
}
|
|
2153
|
+
const layoutRows = layoutTurnRows(turn.role, turn.content, contentWidth, colorEnabled, turn.command);
|
|
2154
|
+
const lines = layoutRows.map((r) => r.rendered);
|
|
2155
|
+
turnLineCache.set(turn, {
|
|
2156
|
+
width: contentWidth,
|
|
2157
|
+
color: colorEnabled,
|
|
2158
|
+
density,
|
|
2159
|
+
surface,
|
|
2160
|
+
lines,
|
|
2161
|
+
layoutRows
|
|
2162
|
+
});
|
|
2163
|
+
return layoutRows;
|
|
2164
|
+
}
|
|
2165
|
+
function renderTurnBlock(role, content, contentWidth, colorEnabled, command) {
|
|
2166
|
+
return layoutTurnRows(role, content, contentWidth, colorEnabled, command).map((r) => r.rendered);
|
|
2080
2167
|
}
|
|
2081
2168
|
var streamingTurnCache = null;
|
|
2082
2169
|
function resetStreamingTurnCache() {
|
|
@@ -2104,12 +2191,12 @@ function renderPrefixTurnBlock(role, content, contentWidth, colorEnabled) {
|
|
|
2104
2191
|
}
|
|
2105
2192
|
function renderTailTurnBlock(role, content, contentWidth, colorEnabled) {
|
|
2106
2193
|
content = content.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
2107
|
-
const lines = [];
|
|
2108
2194
|
if (role === "user") {
|
|
2109
2195
|
const surfaceSeq = colorEnabled ? userSurfaceBackgroundSequence() : "";
|
|
2110
2196
|
const accentSeq = colorEnabled ? themeColorSequence("accent") : "";
|
|
2111
2197
|
const multilinePrefix = colorEnabled ? `${accentSeq}\x1B[1m\u2503 ` : "\u2503 ";
|
|
2112
2198
|
const hangingIndent = colorEnabled ? `${accentSeq}\x1B[1m\u2503 ` : "\u2503 ";
|
|
2199
|
+
const lines = [];
|
|
2113
2200
|
for (const rawLine of content.split("\n")) {
|
|
2114
2201
|
const styledLine = `${multilinePrefix}${rawLine}`;
|
|
2115
2202
|
const rows = wrapTranscriptLine(styledLine, contentWidth, hangingIndent);
|
|
@@ -2117,17 +2204,19 @@ function renderTailTurnBlock(role, content, contentWidth, colorEnabled) {
|
|
|
2117
2204
|
...surfaceSeq ? rows.map((row) => fillUserBubbleRow(row, surfaceSeq, contentWidth)) : rows
|
|
2118
2205
|
);
|
|
2119
2206
|
}
|
|
2207
|
+
return lines;
|
|
2120
2208
|
} else {
|
|
2121
|
-
const highlighted = colorEnabled ? formatAssistantDisplay(content) : stripAnsi(formatAssistantDisplay(content));
|
|
2209
|
+
const highlighted = colorEnabled ? formatAssistantDisplay(content, { trimEdges: false }) : stripAnsi(formatAssistantDisplay(content, { trimEdges: false }));
|
|
2122
2210
|
const rawLines = highlighted.split("\n");
|
|
2123
2211
|
const styledLines = rawLines.map((line) => {
|
|
2124
2212
|
return line.startsWith("[nolo]") && colorEnabled ? themeText(line, "chrome", true) : line;
|
|
2125
2213
|
});
|
|
2214
|
+
const lines = [];
|
|
2126
2215
|
for (const logicalLine of styledLines) {
|
|
2127
2216
|
lines.push(...wrapTranscriptLine(logicalLine, contentWidth));
|
|
2128
2217
|
}
|
|
2218
|
+
return lines;
|
|
2129
2219
|
}
|
|
2130
|
-
return lines;
|
|
2131
2220
|
}
|
|
2132
2221
|
function getStreamingTurnLines(role, content, contentWidth, colorEnabled, density, surface) {
|
|
2133
2222
|
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 +2274,10 @@ function getStreamingTurnLines(role, content, contentWidth, colorEnabled, densit
|
|
|
2185
2274
|
const tailLines = renderTailTurnBlock(role, tailContent, contentWidth, colorEnabled);
|
|
2186
2275
|
return [...streamingTurnCache.prefixLines, ...tailLines];
|
|
2187
2276
|
}
|
|
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
2277
|
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;
|
|
2278
|
+
return layoutTurnRows(role, content, contentWidth, false, command).length;
|
|
2231
2279
|
}
|
|
2232
|
-
function
|
|
2280
|
+
function buildTurnOffsets(history, contentWidth) {
|
|
2233
2281
|
const density = getActiveDensity();
|
|
2234
2282
|
const entries = [];
|
|
2235
2283
|
let offset = 0;
|
|
@@ -2250,6 +2298,36 @@ function buildTurnOffsets2(history, contentWidth) {
|
|
|
2250
2298
|
}
|
|
2251
2299
|
return { entries, totalLines: offset };
|
|
2252
2300
|
}
|
|
2301
|
+
function getAllTurnEntries(history, contentWidth) {
|
|
2302
|
+
const { entries, totalLines: finalizedLines } = buildTurnOffsets(history, contentWidth);
|
|
2303
|
+
const turns = [...history.turns];
|
|
2304
|
+
if (history.currentRole !== null && history.currentContent) {
|
|
2305
|
+
const density = getActiveDensity();
|
|
2306
|
+
const colorEnabled = resolveCliColorEnabled();
|
|
2307
|
+
const surface = colorEnabled ? userSurfaceBackgroundSequence() : "";
|
|
2308
|
+
const streamingLines = getStreamingTurnLines(
|
|
2309
|
+
history.currentRole,
|
|
2310
|
+
history.currentContent,
|
|
2311
|
+
contentWidth,
|
|
2312
|
+
colorEnabled,
|
|
2313
|
+
density,
|
|
2314
|
+
surface
|
|
2315
|
+
);
|
|
2316
|
+
const sep = currentTurnSeparator(history, density);
|
|
2317
|
+
const startRow = finalizedLines + sep;
|
|
2318
|
+
entries.push({
|
|
2319
|
+
startRow,
|
|
2320
|
+
lineCount: streamingLines.length,
|
|
2321
|
+
separatorAbove: sep
|
|
2322
|
+
});
|
|
2323
|
+
turns.push({
|
|
2324
|
+
role: history.currentRole,
|
|
2325
|
+
content: history.currentContent
|
|
2326
|
+
});
|
|
2327
|
+
return { entries, totalLines: startRow + streamingLines.length, turns };
|
|
2328
|
+
}
|
|
2329
|
+
return { entries, totalLines: finalizedLines, turns };
|
|
2330
|
+
}
|
|
2253
2331
|
function currentTurnSeparator(history, density) {
|
|
2254
2332
|
return density === "spacious" && (history.turns.length > 0 || history.currentRole === "user") ? 1 : 0;
|
|
2255
2333
|
}
|
|
@@ -2273,6 +2351,41 @@ function buildCopyViewLines(history) {
|
|
|
2273
2351
|
}
|
|
2274
2352
|
return lines;
|
|
2275
2353
|
}
|
|
2354
|
+
function buildHistoryLayoutRows(history, contentWidth) {
|
|
2355
|
+
const colorEnabled = resolveCliColorEnabled();
|
|
2356
|
+
const density = getActiveDensity();
|
|
2357
|
+
const surface = colorEnabled ? userSurfaceBackgroundSequence() : "";
|
|
2358
|
+
const rows = [];
|
|
2359
|
+
const separatorRow = () => ({
|
|
2360
|
+
rendered: "",
|
|
2361
|
+
sourceStart: 0,
|
|
2362
|
+
sourceEnd: 0,
|
|
2363
|
+
prefixWidth: 0
|
|
2364
|
+
});
|
|
2365
|
+
for (let i = 0; i < history.turns.length; i++) {
|
|
2366
|
+
const turn = history.turns[i];
|
|
2367
|
+
if (density === "spacious" && (i > 0 || turn.role === "user")) {
|
|
2368
|
+
rows.push(separatorRow());
|
|
2369
|
+
}
|
|
2370
|
+
rows.push(...getTurnLayoutRows(turn, contentWidth, colorEnabled, density, surface));
|
|
2371
|
+
}
|
|
2372
|
+
if (history.currentRole !== null && history.currentContent) {
|
|
2373
|
+
const i = history.turns.length;
|
|
2374
|
+
if (density === "spacious" && (i > 0 || history.currentRole === "user")) {
|
|
2375
|
+
rows.push(separatorRow());
|
|
2376
|
+
}
|
|
2377
|
+
rows.push(
|
|
2378
|
+
...layoutTurnRows(
|
|
2379
|
+
history.currentRole,
|
|
2380
|
+
history.currentContent,
|
|
2381
|
+
contentWidth,
|
|
2382
|
+
colorEnabled
|
|
2383
|
+
)
|
|
2384
|
+
);
|
|
2385
|
+
}
|
|
2386
|
+
return rows;
|
|
2387
|
+
}
|
|
2388
|
+
var renderCacheMissCount = 0;
|
|
2276
2389
|
function renderHistory(output, history, inputLines, selection) {
|
|
2277
2390
|
const tty = output;
|
|
2278
2391
|
if (!tty.isTTY) return;
|
|
@@ -2283,13 +2396,9 @@ function renderHistory(output, history, inputLines, selection) {
|
|
|
2283
2396
|
const colorEnabled = resolveCliColorEnabled();
|
|
2284
2397
|
const density = getActiveDensity();
|
|
2285
2398
|
const surface = colorEnabled ? userSurfaceBackgroundSequence() : "";
|
|
2286
|
-
const { entries, totalLines: finalizedLines } =
|
|
2287
|
-
history,
|
|
2288
|
-
contentWidth
|
|
2289
|
-
);
|
|
2290
|
-
let totalLines = finalizedLines;
|
|
2291
|
-
let currentStart = -1;
|
|
2399
|
+
const { entries, totalLines: finalizedLines } = buildTurnOffsets(history, contentWidth);
|
|
2292
2400
|
let currentLines = [];
|
|
2401
|
+
let currentStart = -1;
|
|
2293
2402
|
if (history.currentRole !== null && history.currentContent) {
|
|
2294
2403
|
currentLines = getStreamingTurnLines(
|
|
2295
2404
|
history.currentRole,
|
|
@@ -2299,16 +2408,17 @@ function renderHistory(output, history, inputLines, selection) {
|
|
|
2299
2408
|
density,
|
|
2300
2409
|
surface
|
|
2301
2410
|
);
|
|
2302
|
-
|
|
2303
|
-
|
|
2411
|
+
const sep = currentTurnSeparator(history, density);
|
|
2412
|
+
currentStart = finalizedLines + sep;
|
|
2304
2413
|
}
|
|
2414
|
+
const totalLines = currentStart >= 0 ? currentStart + currentLines.length : finalizedLines;
|
|
2305
2415
|
if (history.followBottom) {
|
|
2306
2416
|
history.scrollTop = Math.max(0, totalLines - visibleHeight);
|
|
2307
2417
|
} else {
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2418
|
+
const maxScroll = Math.max(0, totalLines - visibleHeight);
|
|
2419
|
+
if (history.scrollTop > maxScroll) {
|
|
2420
|
+
history.scrollTop = maxScroll;
|
|
2421
|
+
}
|
|
2312
2422
|
}
|
|
2313
2423
|
history.hasMoreAbove = history.scrollTop > 0;
|
|
2314
2424
|
history.hasMoreBelow = history.scrollTop + visibleHeight < totalLines;
|
|
@@ -2328,20 +2438,14 @@ function renderHistory(output, history, inputLines, selection) {
|
|
|
2328
2438
|
if (turnEnd <= winStart || turnStart >= winEnd) continue;
|
|
2329
2439
|
const turn = history.turns[i];
|
|
2330
2440
|
const cached = turnLineCache.get(turn);
|
|
2331
|
-
let
|
|
2441
|
+
let layoutRows;
|
|
2332
2442
|
if (cached && cached.width === contentWidth && cached.color === colorEnabled && cached.density === density && cached.surface === surface) {
|
|
2333
|
-
|
|
2443
|
+
layoutRows = cached.layoutRows;
|
|
2334
2444
|
} else {
|
|
2335
2445
|
renderCacheMissCount += 1;
|
|
2336
|
-
|
|
2337
|
-
turnLineCache.set(turn, {
|
|
2338
|
-
width: contentWidth,
|
|
2339
|
-
color: colorEnabled,
|
|
2340
|
-
density,
|
|
2341
|
-
surface,
|
|
2342
|
-
lines
|
|
2343
|
-
});
|
|
2446
|
+
layoutRows = getTurnLayoutRows(turn, contentWidth, colorEnabled, density, surface);
|
|
2344
2447
|
}
|
|
2448
|
+
const lines = layoutRows.map((r) => r.rendered);
|
|
2345
2449
|
const interStart = Math.max(turnStart, winStart);
|
|
2346
2450
|
const interEnd = Math.min(turnEnd, winEnd);
|
|
2347
2451
|
for (let r = interStart; r < interEnd; r++) {
|
|
@@ -2365,7 +2469,7 @@ function renderHistory(output, history, inputLines, selection) {
|
|
|
2365
2469
|
}
|
|
2366
2470
|
}
|
|
2367
2471
|
}
|
|
2368
|
-
if (selection && selection.
|
|
2472
|
+
if (selection && selection.anchor && selection.head) {
|
|
2369
2473
|
visibleLines = applySelectionOverlay(
|
|
2370
2474
|
visibleLines,
|
|
2371
2475
|
history,
|
|
@@ -2377,11 +2481,11 @@ function renderHistory(output, history, inputLines, selection) {
|
|
|
2377
2481
|
const prevBuffer = typeof output === "object" && output !== null ? frameBufferByOutput.get(output) : void 0;
|
|
2378
2482
|
const isGeometryCompatible = prevBuffer !== void 0 && prevBuffer.rows === rows && prevBuffer.columns === columns && prevBuffer.inputLines === inputLines && prevBuffer.lines.length === visibleHeight;
|
|
2379
2483
|
const prevLines = isGeometryCompatible ? prevBuffer.lines : void 0;
|
|
2380
|
-
const nextLines = new Array(visibleHeight);
|
|
2381
2484
|
let frame = "";
|
|
2485
|
+
const nextLines = new Array(visibleHeight);
|
|
2382
2486
|
for (let i = 0; i < visibleHeight; i++) {
|
|
2383
|
-
const
|
|
2384
|
-
const padded = padOrTruncateToWidth(
|
|
2487
|
+
const content = visibleLines[i] ?? "";
|
|
2488
|
+
const padded = padOrTruncateToWidth(content, contentWidth);
|
|
2385
2489
|
const thumb = renderScrollbarRow(i, visibleHeight, totalLines, history.scrollTop);
|
|
2386
2490
|
const scrollbarPrefix = colorEnabled ? themeColorSequence("chrome") : "";
|
|
2387
2491
|
const scrollbarSuffix = colorEnabled ? "\x1B[39m" : "";
|
|
@@ -2407,9 +2511,6 @@ function renderHistory(output, history, inputLines, selection) {
|
|
|
2407
2511
|
}
|
|
2408
2512
|
function createHistoryOutputStream(history, onUpdate) {
|
|
2409
2513
|
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
2514
|
isTTY: true,
|
|
2414
2515
|
write(chunk) {
|
|
2415
2516
|
const text = typeof chunk === "string" ? chunk : chunk.toString();
|
|
@@ -2426,7 +2527,7 @@ function applyScrollAction(history, action, output, inputLines) {
|
|
|
2426
2527
|
const columns = tty.columns ?? 80;
|
|
2427
2528
|
const visibleHeight = Math.max(1, rows - inputLines);
|
|
2428
2529
|
const contentWidth = Math.max(1, columns - 1);
|
|
2429
|
-
const { totalLines: finalizedLines } =
|
|
2530
|
+
const { totalLines: finalizedLines } = buildTurnOffsets(history, contentWidth);
|
|
2430
2531
|
let totalLines = finalizedLines;
|
|
2431
2532
|
if (history.currentRole !== null && history.currentContent) {
|
|
2432
2533
|
totalLines += currentTurnSeparator(history, getActiveDensity()) + countTurnLines(history.currentRole, history.currentContent, contentWidth);
|
|
@@ -6317,6 +6418,10 @@ async function startTuiWorkspace(options) {
|
|
|
6317
6418
|
const output = options.output ?? defaultOutput;
|
|
6318
6419
|
const fetchImpl = options.fetchImpl ?? fetch;
|
|
6319
6420
|
const spawnRunner = options.spawnRunner ?? spawnProcess;
|
|
6421
|
+
const writeClipboard = options.clipboardWriter ?? (async (text) => {
|
|
6422
|
+
const { default: clipboard } = await import("./clipboardy-MMBYVRLF.js");
|
|
6423
|
+
await clipboard.write(text);
|
|
6424
|
+
});
|
|
6320
6425
|
const selfUpdater = options.selfUpdater ?? ((target) => runSelfUpdate({ output: target }));
|
|
6321
6426
|
if (output.isTTY) {
|
|
6322
6427
|
enterAltScreen(output);
|
|
@@ -7053,8 +7158,7 @@ async function startTuiWorkspace(options) {
|
|
|
7053
7158
|
emitCommandOutput(t("copyNothing"));
|
|
7054
7159
|
} else {
|
|
7055
7160
|
try {
|
|
7056
|
-
|
|
7057
|
-
await clipboard.write(text);
|
|
7161
|
+
await writeClipboard(text);
|
|
7058
7162
|
emitCommandOutput(t("copiedLastReply"));
|
|
7059
7163
|
} catch (error) {
|
|
7060
7164
|
const message = toErrorMessage(error);
|
|
@@ -7406,7 +7510,7 @@ ${err.message}` : ""}`
|
|
|
7406
7510
|
stopAutoScroll();
|
|
7407
7511
|
}
|
|
7408
7512
|
} else {
|
|
7409
|
-
const { totalLines } =
|
|
7513
|
+
const { totalLines } = getAllTurnEntries(history, contentWidth);
|
|
7410
7514
|
const maxScroll = Math.max(0, totalLines - visibleHeight);
|
|
7411
7515
|
if (history.scrollTop < maxScroll) {
|
|
7412
7516
|
history.scrollTop = Math.min(maxScroll, history.scrollTop + 1);
|
|
@@ -7567,19 +7671,28 @@ ${merged}` : merged;
|
|
|
7567
7671
|
const textToCopy = extractSelectedText(
|
|
7568
7672
|
history,
|
|
7569
7673
|
selectionState.anchor,
|
|
7570
|
-
selectionState.head
|
|
7674
|
+
selectionState.head,
|
|
7675
|
+
contentWidth
|
|
7571
7676
|
);
|
|
7572
7677
|
if (textToCopy.length > 0) {
|
|
7573
|
-
|
|
7678
|
+
writeClipboard(textToCopy).catch((error) => {
|
|
7679
|
+
emitCommandOutput(
|
|
7680
|
+
`[nolo] ${t("copyFailed")}: ${toErrorMessage(error)}`
|
|
7681
|
+
);
|
|
7574
7682
|
});
|
|
7575
7683
|
}
|
|
7684
|
+
selectionState.dragging = false;
|
|
7685
|
+
} else {
|
|
7686
|
+
clearSelection();
|
|
7576
7687
|
}
|
|
7577
|
-
clearSelection();
|
|
7578
7688
|
paintFrame(buffer);
|
|
7579
7689
|
return;
|
|
7580
7690
|
}
|
|
7581
7691
|
return;
|
|
7582
7692
|
}
|
|
7693
|
+
if (selectionState.anchor) {
|
|
7694
|
+
clearSelection();
|
|
7695
|
+
}
|
|
7583
7696
|
const scrollAction = parseScrollAction(sequence);
|
|
7584
7697
|
if (scrollAction) {
|
|
7585
7698
|
if (fixedInput.isPaused()) return;
|