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-P6PZ64PS.js");
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nolo-cli",
3
- "version": "0.33.0-alpha.19",
3
+ "version": "0.33.0-alpha.20",
4
4
  "type": "module",
5
5
  "description": "Agent-first terminal workspace for Nolo",
6
6
  "bin": {
@@ -675,13 +675,11 @@ function renderDialogCommand(text, colorEnabled = resolveCliColorEnabled()) {
675
675
  return themeText(` ${text}`, "danger", colorEnabled);
676
676
  }
677
677
 
678
- // packages/cli/tui/tuiScrollbar.ts
679
- var SGR_MOUSE_REGEX = /^\x1b\[<(\d+);\d+;\d+[Mm]$/;
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 mouse = SGR_MOUSE_REGEX.exec(sequence);
700
- if (mouse) {
701
- const button = Number(mouse[1]);
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 buildTurnOffsets(history, contentWidth) {
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 } = buildTurnOffsets(
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
- const visibleLines = new Array(visibleHeight).fill("");
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 } = buildTurnOffsets(history, contentWidth);
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[?1000h");
5433
+ if (mouseEnabled) write("\x1B[?1006h\x1B[?1002h");
5161
5434
  };
5162
- const disableMouse = () => write("\x1B[?1000l\x1B[?1006l");
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[?1000h");
5610
+ write("\x1B[?1006h\x1B[?1002h");
5338
5611
  } else {
5339
- write("\x1B[?1000l\x1B[?1006l");
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(output, history, fixedInput.getInputLines());
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;