nolo-cli 0.33.0-alpha.19 → 0.33.0-alpha.20
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/index.js
CHANGED
|
@@ -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-EH77JVMA.js");
|
|
800
800
|
const { createTuiSummaryLlmCaller } = await import("./tuiSummaryLlmCaller-WUVAOIYU.js");
|
|
801
801
|
return startTuiWorkspace({
|
|
802
802
|
...args2,
|
package/package.json
CHANGED
|
@@ -675,13 +675,11 @@ function renderDialogCommand(text, colorEnabled = resolveCliColorEnabled()) {
|
|
|
675
675
|
return themeText(` ${text}`, "danger", colorEnabled);
|
|
676
676
|
}
|
|
677
677
|
|
|
678
|
-
// packages/cli/tui/
|
|
679
|
-
var SGR_MOUSE_REGEX = /^\x1b\[<(\d+)
|
|
678
|
+
// packages/cli/tui/tuiMouse.ts
|
|
679
|
+
var SGR_MOUSE_REGEX = /^\x1b\[<(\d+);(\d+);(\d+)([Mm])$/;
|
|
680
680
|
function consumeSgrMouseSequence(buffer) {
|
|
681
681
|
if (!buffer.startsWith("\x1B[")) return null;
|
|
682
|
-
if (!buffer.startsWith("\x1B[<"))
|
|
683
|
-
return null;
|
|
684
|
-
}
|
|
682
|
+
if (!buffer.startsWith("\x1B[<")) return null;
|
|
685
683
|
const body = buffer.slice(3);
|
|
686
684
|
for (let index = 0; index < body.length; index += 1) {
|
|
687
685
|
const character = body[index];
|
|
@@ -695,13 +693,75 @@ function consumeSgrMouseSequence(buffer) {
|
|
|
695
693
|
}
|
|
696
694
|
return void 0;
|
|
697
695
|
}
|
|
696
|
+
function parseSgrMouseEvent(sequence) {
|
|
697
|
+
const match = SGR_MOUSE_REGEX.exec(sequence);
|
|
698
|
+
if (!match) return null;
|
|
699
|
+
const code = Number(match[1]);
|
|
700
|
+
const x = Number(match[2]);
|
|
701
|
+
const y = Number(match[3]);
|
|
702
|
+
const isRelease = match[4] === "m";
|
|
703
|
+
const shift = (code & 4) !== 0;
|
|
704
|
+
const alt = (code & 8) !== 0;
|
|
705
|
+
const ctrl = (code & 16) !== 0;
|
|
706
|
+
if ((code & 64) !== 0) {
|
|
707
|
+
if ((code & 2) !== 0) {
|
|
708
|
+
return null;
|
|
709
|
+
}
|
|
710
|
+
const wheelDirection = (code & 1) !== 0 ? "down" : "up";
|
|
711
|
+
return {
|
|
712
|
+
kind: "wheel",
|
|
713
|
+
button: "none",
|
|
714
|
+
x,
|
|
715
|
+
y,
|
|
716
|
+
shift,
|
|
717
|
+
alt,
|
|
718
|
+
ctrl,
|
|
719
|
+
wheelDirection
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
const rawButton = code & 3;
|
|
723
|
+
let button = "none";
|
|
724
|
+
if (rawButton === 0) button = "left";
|
|
725
|
+
else if (rawButton === 1) button = "middle";
|
|
726
|
+
else if (rawButton === 2) button = "right";
|
|
727
|
+
if (isRelease) {
|
|
728
|
+
return {
|
|
729
|
+
kind: "release",
|
|
730
|
+
button,
|
|
731
|
+
x,
|
|
732
|
+
y,
|
|
733
|
+
shift,
|
|
734
|
+
alt,
|
|
735
|
+
ctrl
|
|
736
|
+
};
|
|
737
|
+
}
|
|
738
|
+
if ((code & 32) !== 0) {
|
|
739
|
+
return {
|
|
740
|
+
kind: "drag",
|
|
741
|
+
button,
|
|
742
|
+
x,
|
|
743
|
+
y,
|
|
744
|
+
shift,
|
|
745
|
+
alt,
|
|
746
|
+
ctrl
|
|
747
|
+
};
|
|
748
|
+
}
|
|
749
|
+
return {
|
|
750
|
+
kind: "press",
|
|
751
|
+
button,
|
|
752
|
+
x,
|
|
753
|
+
y,
|
|
754
|
+
shift,
|
|
755
|
+
alt,
|
|
756
|
+
ctrl
|
|
757
|
+
};
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
// packages/cli/tui/tuiScrollbar.ts
|
|
698
761
|
function parseScrollAction(sequence) {
|
|
699
|
-
const
|
|
700
|
-
if (
|
|
701
|
-
|
|
702
|
-
if ((button & 64) === 0) return null;
|
|
703
|
-
if ((button & 2) !== 0) return null;
|
|
704
|
-
return (button & 1) !== 0 ? "wheel-down" : "wheel-up";
|
|
762
|
+
const mouseEvent = parseSgrMouseEvent(sequence);
|
|
763
|
+
if (mouseEvent && mouseEvent.kind === "wheel") {
|
|
764
|
+
return mouseEvent.wheelDirection === "down" ? "wheel-down" : "wheel-up";
|
|
705
765
|
}
|
|
706
766
|
switch (sequence) {
|
|
707
767
|
case "\x1B[5~":
|
|
@@ -1685,6 +1745,210 @@ async function runAskChoiceDialog(args) {
|
|
|
1685
1745
|
};
|
|
1686
1746
|
}
|
|
1687
1747
|
|
|
1748
|
+
// packages/cli/tui/tuiSelection.ts
|
|
1749
|
+
function createSelectionState() {
|
|
1750
|
+
return {
|
|
1751
|
+
dragging: false,
|
|
1752
|
+
anchor: null,
|
|
1753
|
+
head: null
|
|
1754
|
+
};
|
|
1755
|
+
}
|
|
1756
|
+
function compareSelectionPoints(a, b) {
|
|
1757
|
+
if (a.turnIndex !== b.turnIndex) {
|
|
1758
|
+
return a.turnIndex - b.turnIndex;
|
|
1759
|
+
}
|
|
1760
|
+
return a.sourceOffset - b.sourceOffset;
|
|
1761
|
+
}
|
|
1762
|
+
function areSelectionPointsEqual(a, b) {
|
|
1763
|
+
if (a === null && b === null) return true;
|
|
1764
|
+
if (a === null || b === null) return false;
|
|
1765
|
+
return a.turnIndex === b.turnIndex && a.sourceOffset === b.sourceOffset;
|
|
1766
|
+
}
|
|
1767
|
+
function hitTestHistory(history, screenRow, screenCol, contentWidth, scrollTop) {
|
|
1768
|
+
if (history.turns.length === 0) return null;
|
|
1769
|
+
const { entries } = buildTurnOffsets2(history, contentWidth);
|
|
1770
|
+
if (entries.length === 0) return null;
|
|
1771
|
+
const globalRow = scrollTop + screenRow;
|
|
1772
|
+
const firstEntry = entries[0];
|
|
1773
|
+
if (globalRow < firstEntry.startRow) {
|
|
1774
|
+
return { turnIndex: 0, sourceOffset: 0 };
|
|
1775
|
+
}
|
|
1776
|
+
const lastIdx = entries.length - 1;
|
|
1777
|
+
const lastEntry = entries[lastIdx];
|
|
1778
|
+
const lastTurn = history.turns[lastIdx];
|
|
1779
|
+
if (globalRow >= lastEntry.startRow + lastEntry.lineCount) {
|
|
1780
|
+
return { turnIndex: lastIdx, sourceOffset: lastTurn.content.length };
|
|
1781
|
+
}
|
|
1782
|
+
for (let i = 0; i < entries.length; i++) {
|
|
1783
|
+
const entry = entries[i];
|
|
1784
|
+
const turn = history.turns[i];
|
|
1785
|
+
const turnStart = entry.startRow;
|
|
1786
|
+
const turnEnd = turnStart + entry.lineCount;
|
|
1787
|
+
if (entry.separatorAbove > 0 && globalRow === turnStart - 1) {
|
|
1788
|
+
return { turnIndex: i, sourceOffset: 0 };
|
|
1789
|
+
}
|
|
1790
|
+
if (globalRow >= turnStart && globalRow < turnEnd) {
|
|
1791
|
+
const rowInTurn = globalRow - turnStart;
|
|
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 };
|
|
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;
|
|
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;
|
|
1871
|
+
}
|
|
1872
|
+
currentRow += rowCount;
|
|
1873
|
+
charAccumulator += lineLen + 1;
|
|
1874
|
+
}
|
|
1875
|
+
return normalized.length;
|
|
1876
|
+
}
|
|
1877
|
+
function extractSelectedText(history, anchor, head) {
|
|
1878
|
+
if (!anchor || !head) return "";
|
|
1879
|
+
const cmp = compareSelectionPoints(anchor, head);
|
|
1880
|
+
if (cmp === 0) return "";
|
|
1881
|
+
const start = cmp < 0 ? anchor : head;
|
|
1882
|
+
const end = cmp < 0 ? head : anchor;
|
|
1883
|
+
if (start.turnIndex === end.turnIndex) {
|
|
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
|
+
}
|
|
1889
|
+
const pieces = [];
|
|
1890
|
+
const startTurn2 = history.turns[start.turnIndex];
|
|
1891
|
+
if (startTurn2) {
|
|
1892
|
+
pieces.push(startTurn2.content.slice(start.sourceOffset));
|
|
1893
|
+
}
|
|
1894
|
+
for (let i = start.turnIndex + 1; i < end.turnIndex; i++) {
|
|
1895
|
+
const midTurn = history.turns[i];
|
|
1896
|
+
if (midTurn) {
|
|
1897
|
+
pieces.push(midTurn.content);
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
const endTurn = history.turns[end.turnIndex];
|
|
1901
|
+
if (endTurn) {
|
|
1902
|
+
pieces.push(endTurn.content.slice(0, end.sourceOffset));
|
|
1903
|
+
}
|
|
1904
|
+
return stripAnsi(pieces.join("\n\n"));
|
|
1905
|
+
}
|
|
1906
|
+
function applySelectionOverlay(visibleLines, history, contentWidth, scrollTop, selection) {
|
|
1907
|
+
if (!selection.dragging || !selection.anchor || !selection.head) {
|
|
1908
|
+
return visibleLines;
|
|
1909
|
+
}
|
|
1910
|
+
const cmp = compareSelectionPoints(selection.anchor, selection.head);
|
|
1911
|
+
if (cmp === 0) return visibleLines;
|
|
1912
|
+
const start = cmp < 0 ? selection.anchor : selection.head;
|
|
1913
|
+
const end = cmp < 0 ? selection.head : selection.anchor;
|
|
1914
|
+
const { entries } = buildTurnOffsets2(history, contentWidth);
|
|
1915
|
+
const result = [...visibleLines];
|
|
1916
|
+
for (let screenRow = 0; screenRow < visibleLines.length; screenRow++) {
|
|
1917
|
+
const globalRow = scrollTop + screenRow;
|
|
1918
|
+
let isSelectedRow = false;
|
|
1919
|
+
for (let i = start.turnIndex; i <= end.turnIndex; i++) {
|
|
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
|
+
}
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1949
|
+
return result;
|
|
1950
|
+
}
|
|
1951
|
+
|
|
1688
1952
|
// packages/cli/tui/tuiHistory.ts
|
|
1689
1953
|
var MAX_TUI_HISTORY_TURNS = 500;
|
|
1690
1954
|
var turnLineCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -1965,7 +2229,7 @@ function countTurnLines(role, content, contentWidth, command) {
|
|
|
1965
2229
|
}
|
|
1966
2230
|
return count;
|
|
1967
2231
|
}
|
|
1968
|
-
function
|
|
2232
|
+
function buildTurnOffsets2(history, contentWidth) {
|
|
1969
2233
|
const density = getActiveDensity();
|
|
1970
2234
|
const entries = [];
|
|
1971
2235
|
let offset = 0;
|
|
@@ -2009,7 +2273,7 @@ function buildCopyViewLines(history) {
|
|
|
2009
2273
|
}
|
|
2010
2274
|
return lines;
|
|
2011
2275
|
}
|
|
2012
|
-
function renderHistory(output, history, inputLines) {
|
|
2276
|
+
function renderHistory(output, history, inputLines, selection) {
|
|
2013
2277
|
const tty = output;
|
|
2014
2278
|
if (!tty.isTTY) return;
|
|
2015
2279
|
const rows = tty.rows ?? 24;
|
|
@@ -2019,7 +2283,7 @@ function renderHistory(output, history, inputLines) {
|
|
|
2019
2283
|
const colorEnabled = resolveCliColorEnabled();
|
|
2020
2284
|
const density = getActiveDensity();
|
|
2021
2285
|
const surface = colorEnabled ? userSurfaceBackgroundSequence() : "";
|
|
2022
|
-
const { entries, totalLines: finalizedLines } =
|
|
2286
|
+
const { entries, totalLines: finalizedLines } = buildTurnOffsets2(
|
|
2023
2287
|
history,
|
|
2024
2288
|
contentWidth
|
|
2025
2289
|
);
|
|
@@ -2050,7 +2314,7 @@ function renderHistory(output, history, inputLines) {
|
|
|
2050
2314
|
history.hasMoreBelow = history.scrollTop + visibleHeight < totalLines;
|
|
2051
2315
|
const winStart = history.scrollTop;
|
|
2052
2316
|
const winEnd = Math.min(totalLines, winStart + visibleHeight);
|
|
2053
|
-
|
|
2317
|
+
let visibleLines = new Array(visibleHeight).fill("");
|
|
2054
2318
|
for (let i = 0; i < entries.length; i++) {
|
|
2055
2319
|
const entry = entries[i];
|
|
2056
2320
|
if (entry.separatorAbove > 0) {
|
|
@@ -2101,6 +2365,15 @@ function renderHistory(output, history, inputLines) {
|
|
|
2101
2365
|
}
|
|
2102
2366
|
}
|
|
2103
2367
|
}
|
|
2368
|
+
if (selection && selection.dragging) {
|
|
2369
|
+
visibleLines = applySelectionOverlay(
|
|
2370
|
+
visibleLines,
|
|
2371
|
+
history,
|
|
2372
|
+
contentWidth,
|
|
2373
|
+
winStart,
|
|
2374
|
+
selection
|
|
2375
|
+
);
|
|
2376
|
+
}
|
|
2104
2377
|
const prevBuffer = typeof output === "object" && output !== null ? frameBufferByOutput.get(output) : void 0;
|
|
2105
2378
|
const isGeometryCompatible = prevBuffer !== void 0 && prevBuffer.rows === rows && prevBuffer.columns === columns && prevBuffer.inputLines === inputLines && prevBuffer.lines.length === visibleHeight;
|
|
2106
2379
|
const prevLines = isGeometryCompatible ? prevBuffer.lines : void 0;
|
|
@@ -2153,7 +2426,7 @@ function applyScrollAction(history, action, output, inputLines) {
|
|
|
2153
2426
|
const columns = tty.columns ?? 80;
|
|
2154
2427
|
const visibleHeight = Math.max(1, rows - inputLines);
|
|
2155
2428
|
const contentWidth = Math.max(1, columns - 1);
|
|
2156
|
-
const { totalLines: finalizedLines } =
|
|
2429
|
+
const { totalLines: finalizedLines } = buildTurnOffsets2(history, contentWidth);
|
|
2157
2430
|
let totalLines = finalizedLines;
|
|
2158
2431
|
if (history.currentRole !== null && history.currentContent) {
|
|
2159
2432
|
totalLines += currentTurnSeparator(history, getActiveDensity()) + countTurnLines(history.currentRole, history.currentContent, contentWidth);
|
|
@@ -5157,9 +5430,9 @@ function createFixedInput(output, config) {
|
|
|
5157
5430
|
};
|
|
5158
5431
|
let mouseEnabled = true;
|
|
5159
5432
|
const enableMouse = () => {
|
|
5160
|
-
if (mouseEnabled) write("\x1B[?1006h\x1B[?
|
|
5433
|
+
if (mouseEnabled) write("\x1B[?1006h\x1B[?1002h");
|
|
5161
5434
|
};
|
|
5162
|
-
const disableMouse = () => write("\x1B[?
|
|
5435
|
+
const disableMouse = () => write("\x1B[?1002l\x1B[?1006l");
|
|
5163
5436
|
let lastRenderedText = null;
|
|
5164
5437
|
let lastStartRow = -1;
|
|
5165
5438
|
let lastCursorRow = -1;
|
|
@@ -5334,9 +5607,9 @@ function createFixedInput(output, config) {
|
|
|
5334
5607
|
setMouseEnabled(enabled) {
|
|
5335
5608
|
mouseEnabled = enabled;
|
|
5336
5609
|
if (enabled) {
|
|
5337
|
-
write("\x1B[?1006h\x1B[?
|
|
5610
|
+
write("\x1B[?1006h\x1B[?1002h");
|
|
5338
5611
|
} else {
|
|
5339
|
-
write("\x1B[?
|
|
5612
|
+
write("\x1B[?1002l\x1B[?1006l");
|
|
5340
5613
|
}
|
|
5341
5614
|
},
|
|
5342
5615
|
setAltScreenEnabled(enabled) {
|
|
@@ -6217,12 +6490,32 @@ async function startTuiWorkspace(options) {
|
|
|
6217
6490
|
}
|
|
6218
6491
|
});
|
|
6219
6492
|
let syncingLayout = false;
|
|
6493
|
+
const selectionState = createSelectionState();
|
|
6494
|
+
let autoScrollTimer = null;
|
|
6495
|
+
let lastDragMouseX = 1;
|
|
6496
|
+
const stopAutoScroll = () => {
|
|
6497
|
+
if (autoScrollTimer) {
|
|
6498
|
+
clearInterval(autoScrollTimer);
|
|
6499
|
+
autoScrollTimer = null;
|
|
6500
|
+
}
|
|
6501
|
+
};
|
|
6502
|
+
const clearSelection = () => {
|
|
6503
|
+
stopAutoScroll();
|
|
6504
|
+
selectionState.dragging = false;
|
|
6505
|
+
selectionState.anchor = null;
|
|
6506
|
+
selectionState.head = null;
|
|
6507
|
+
};
|
|
6220
6508
|
const renderHistoryToOutput = () => {
|
|
6221
6509
|
if (fixedInput.isPaused()) return;
|
|
6222
6510
|
if (syncingLayout) return;
|
|
6223
6511
|
syncingLayout = true;
|
|
6224
6512
|
try {
|
|
6225
|
-
renderHistory(
|
|
6513
|
+
renderHistory(
|
|
6514
|
+
output,
|
|
6515
|
+
history,
|
|
6516
|
+
fixedInput.getInputLines(),
|
|
6517
|
+
selectionState
|
|
6518
|
+
);
|
|
6226
6519
|
} finally {
|
|
6227
6520
|
syncingLayout = false;
|
|
6228
6521
|
}
|
|
@@ -6964,6 +7257,10 @@ ${err.message}` : ""}`
|
|
|
6964
7257
|
repaint(draft, cursorPos2) {
|
|
6965
7258
|
syncWindowTitle();
|
|
6966
7259
|
return baseFixedInput.repaint(draft, cursorPos2);
|
|
7260
|
+
},
|
|
7261
|
+
pause() {
|
|
7262
|
+
clearSelection();
|
|
7263
|
+
return baseFixedInput.pause();
|
|
6967
7264
|
}
|
|
6968
7265
|
};
|
|
6969
7266
|
fixedInput.init();
|
|
@@ -6973,6 +7270,7 @@ ${err.message}` : ""}`
|
|
|
6973
7270
|
};
|
|
6974
7271
|
const onResize = () => {
|
|
6975
7272
|
if (done) return;
|
|
7273
|
+
clearSelection();
|
|
6976
7274
|
if (copyViewExitResolver) {
|
|
6977
7275
|
copyViewRender?.();
|
|
6978
7276
|
return;
|
|
@@ -6991,6 +7289,7 @@ ${err.message}` : ""}`
|
|
|
6991
7289
|
if (done) return;
|
|
6992
7290
|
done = true;
|
|
6993
7291
|
sessionEnded = true;
|
|
7292
|
+
clearSelection();
|
|
6994
7293
|
if (autoThemeTimer !== null) {
|
|
6995
7294
|
clearInterval(autoThemeTimer);
|
|
6996
7295
|
autoThemeTimer = null;
|
|
@@ -7084,6 +7383,51 @@ ${err.message}` : ""}`
|
|
|
7084
7383
|
);
|
|
7085
7384
|
});
|
|
7086
7385
|
};
|
|
7386
|
+
let autoScrollDirection = "up";
|
|
7387
|
+
const startAutoScroll = (direction, mouseX) => {
|
|
7388
|
+
autoScrollDirection = direction;
|
|
7389
|
+
lastDragMouseX = mouseX;
|
|
7390
|
+
if (autoScrollTimer) return;
|
|
7391
|
+
autoScrollTimer = setInterval(() => {
|
|
7392
|
+
if (!selectionState.dragging || !selectionState.anchor || fixedInput.isPaused()) {
|
|
7393
|
+
stopAutoScroll();
|
|
7394
|
+
return;
|
|
7395
|
+
}
|
|
7396
|
+
const tty = output;
|
|
7397
|
+
const rows = tty.rows ?? 24;
|
|
7398
|
+
const columns = tty.columns ?? 80;
|
|
7399
|
+
const visibleHeight = Math.max(1, rows - fixedInput.getInputLines());
|
|
7400
|
+
const contentWidth = Math.max(1, columns - 1);
|
|
7401
|
+
if (autoScrollDirection === "up") {
|
|
7402
|
+
if (history.scrollTop > 0) {
|
|
7403
|
+
history.scrollTop = Math.max(0, history.scrollTop - 1);
|
|
7404
|
+
history.followBottom = false;
|
|
7405
|
+
} else {
|
|
7406
|
+
stopAutoScroll();
|
|
7407
|
+
}
|
|
7408
|
+
} else {
|
|
7409
|
+
const { totalLines } = buildTurnOffsets(history, contentWidth);
|
|
7410
|
+
const maxScroll = Math.max(0, totalLines - visibleHeight);
|
|
7411
|
+
if (history.scrollTop < maxScroll) {
|
|
7412
|
+
history.scrollTop = Math.min(maxScroll, history.scrollTop + 1);
|
|
7413
|
+
} else {
|
|
7414
|
+
stopAutoScroll();
|
|
7415
|
+
}
|
|
7416
|
+
}
|
|
7417
|
+
const screenRow = autoScrollDirection === "up" ? 0 : visibleHeight - 1;
|
|
7418
|
+
const hit = hitTestHistory(
|
|
7419
|
+
history,
|
|
7420
|
+
screenRow,
|
|
7421
|
+
lastDragMouseX - 1,
|
|
7422
|
+
contentWidth,
|
|
7423
|
+
history.scrollTop
|
|
7424
|
+
);
|
|
7425
|
+
if (hit) {
|
|
7426
|
+
selectionState.head = hit;
|
|
7427
|
+
}
|
|
7428
|
+
paintFrame(buffer);
|
|
7429
|
+
}, 60);
|
|
7430
|
+
};
|
|
7087
7431
|
const handleInputToken = async (sequence) => {
|
|
7088
7432
|
if (done) return;
|
|
7089
7433
|
if (copyViewExitResolver) {
|
|
@@ -7158,6 +7502,84 @@ ${merged}` : merged;
|
|
|
7158
7502
|
return handleInputToken("\r");
|
|
7159
7503
|
}
|
|
7160
7504
|
const busyLock = busy;
|
|
7505
|
+
const mouseEvent = parseSgrMouseEvent(sequence);
|
|
7506
|
+
if (mouseEvent) {
|
|
7507
|
+
if (fixedInput.isPaused()) return;
|
|
7508
|
+
if (mouseEvent.kind === "wheel") {
|
|
7509
|
+
const scrollAction2 = mouseEvent.wheelDirection === "down" ? "wheel-down" : "wheel-up";
|
|
7510
|
+
applyScrollAction(history, scrollAction2, output, fixedInput.getInputLines());
|
|
7511
|
+
paintFrame(buffer);
|
|
7512
|
+
return;
|
|
7513
|
+
}
|
|
7514
|
+
const tty = output;
|
|
7515
|
+
const rows = tty.rows ?? 24;
|
|
7516
|
+
const columns = tty.columns ?? 80;
|
|
7517
|
+
const visibleHeight = Math.max(1, rows - fixedInput.getInputLines());
|
|
7518
|
+
const contentWidth = Math.max(1, columns - 1);
|
|
7519
|
+
const screenRow = mouseEvent.y - 1;
|
|
7520
|
+
const screenCol = mouseEvent.x - 1;
|
|
7521
|
+
if (mouseEvent.kind === "press" && mouseEvent.button === "left") {
|
|
7522
|
+
stopAutoScroll();
|
|
7523
|
+
if (screenRow < visibleHeight && screenCol < contentWidth) {
|
|
7524
|
+
const hit = hitTestHistory(
|
|
7525
|
+
history,
|
|
7526
|
+
screenRow,
|
|
7527
|
+
screenCol,
|
|
7528
|
+
contentWidth,
|
|
7529
|
+
history.scrollTop
|
|
7530
|
+
);
|
|
7531
|
+
selectionState.anchor = hit;
|
|
7532
|
+
selectionState.head = hit;
|
|
7533
|
+
selectionState.dragging = false;
|
|
7534
|
+
} else {
|
|
7535
|
+
clearSelection();
|
|
7536
|
+
}
|
|
7537
|
+
return;
|
|
7538
|
+
}
|
|
7539
|
+
if (mouseEvent.kind === "drag" && mouseEvent.button === "left") {
|
|
7540
|
+
if (!selectionState.anchor) return;
|
|
7541
|
+
selectionState.dragging = true;
|
|
7542
|
+
lastDragMouseX = mouseEvent.x;
|
|
7543
|
+
const clampedRow = Math.max(0, Math.min(visibleHeight - 1, screenRow));
|
|
7544
|
+
const hit = hitTestHistory(
|
|
7545
|
+
history,
|
|
7546
|
+
clampedRow,
|
|
7547
|
+
screenCol,
|
|
7548
|
+
contentWidth,
|
|
7549
|
+
history.scrollTop
|
|
7550
|
+
);
|
|
7551
|
+
if (hit) {
|
|
7552
|
+
selectionState.head = hit;
|
|
7553
|
+
}
|
|
7554
|
+
if (screenRow <= 1 && history.scrollTop > 0) {
|
|
7555
|
+
startAutoScroll("up", mouseEvent.x);
|
|
7556
|
+
} else if (screenRow >= visibleHeight - 2) {
|
|
7557
|
+
startAutoScroll("down", mouseEvent.x);
|
|
7558
|
+
} else {
|
|
7559
|
+
stopAutoScroll();
|
|
7560
|
+
}
|
|
7561
|
+
paintFrame(buffer);
|
|
7562
|
+
return;
|
|
7563
|
+
}
|
|
7564
|
+
if (mouseEvent.kind === "release") {
|
|
7565
|
+
stopAutoScroll();
|
|
7566
|
+
if (selectionState.dragging && selectionState.anchor && selectionState.head && !areSelectionPointsEqual(selectionState.anchor, selectionState.head)) {
|
|
7567
|
+
const textToCopy = extractSelectedText(
|
|
7568
|
+
history,
|
|
7569
|
+
selectionState.anchor,
|
|
7570
|
+
selectionState.head
|
|
7571
|
+
);
|
|
7572
|
+
if (textToCopy.length > 0) {
|
|
7573
|
+
import("./clipboardy-MMBYVRLF.js").then(({ default: clipboard }) => clipboard.write(textToCopy)).catch(() => {
|
|
7574
|
+
});
|
|
7575
|
+
}
|
|
7576
|
+
}
|
|
7577
|
+
clearSelection();
|
|
7578
|
+
paintFrame(buffer);
|
|
7579
|
+
return;
|
|
7580
|
+
}
|
|
7581
|
+
return;
|
|
7582
|
+
}
|
|
7161
7583
|
const scrollAction = parseScrollAction(sequence);
|
|
7162
7584
|
if (scrollAction) {
|
|
7163
7585
|
if (fixedInput.isPaused()) return;
|