@happy-nut/monacori 0.1.6 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -34,12 +34,6 @@ npm install -g @happy-nut/monacori
34
34
 
35
35
  The short command is `mo`.
36
36
 
37
- Homebrew users can install from the tap as well:
38
-
39
- ```bash
40
- brew install happy-nut/monacori/monacori
41
- ```
42
-
43
37
  ## Quick Start
44
38
 
45
39
  Inside any Git repository:
package/dist/app-main.js CHANGED
@@ -71,37 +71,10 @@ ipcMain.handle("monacori:pty-spawn", (_event, size) => {
71
71
  if (mainWindow && !mainWindow.isDestroyed())
72
72
  mainWindow.webContents.send(channel, payload);
73
73
  };
74
- // pty output can arrive as many tiny chunks (thousands/sec under fast output). One IPC per chunk floods
75
- // the renderer, so coalesce: buffer chunks and flush on a short timer, or immediately once the buffer is
76
- // large bounding both IPC traffic and added latency.
77
- let outBuf = "";
78
- let flushTimer;
79
- const flushOut = () => {
80
- flushTimer = undefined;
81
- if (!outBuf)
82
- return;
83
- const data = outBuf;
84
- outBuf = "";
85
- deliver("monacori:pty-data", { id, data });
86
- };
87
- t.onData((data) => {
88
- outBuf += data;
89
- if (outBuf.length >= 64 * 1024) {
90
- if (flushTimer)
91
- clearTimeout(flushTimer);
92
- flushOut();
93
- }
94
- else if (!flushTimer) {
95
- flushTimer = setTimeout(flushOut, 12);
96
- }
97
- });
98
- t.onExit(() => {
99
- if (flushTimer)
100
- clearTimeout(flushTimer);
101
- flushOut(); // deliver any buffered tail before signaling exit
102
- terms.delete(id);
103
- deliver("monacori:pty-exit", { id });
104
- });
74
+ // Relay pty output to the renderer immediately, one IPC per chunk. (A coalescing buffer was tried as an
75
+ // optimization but it broke terminal I/O the shell prompt and echo stopped appearing so it's removed.)
76
+ t.onData((data) => deliver("monacori:pty-data", { id, data }));
77
+ t.onExit(() => { terms.delete(id); deliver("monacori:pty-exit", { id }); });
105
78
  return { ok: true, id };
106
79
  });
107
80
  ipcMain.on("monacori:pty-write", (_event, msg) => { terms.get(msg?.id)?.write(msg.data); });
@@ -455,6 +455,20 @@ function scheduleDiffScroll(row) {
455
455
  });
456
456
  }
457
457
 
458
+ // Coalesced scrollIntoView for caret/focus moves. Holding an arrow key fires key-repeat faster than a
459
+ // reflow-forcing scrollIntoView can run, so collapse them to one (latest element) per animation frame and
460
+ // use block:nearest (no per-row center-jump). Shared by the tree, source caret, and diff caret.
461
+ var pendingScrollEl = null, scrollElRaf = 0;
462
+ function scheduleScrollIntoView(el) {
463
+ pendingScrollEl = el || null;
464
+ if (scrollElRaf) return;
465
+ scrollElRaf = requestAnimationFrame(function () {
466
+ scrollElRaf = 0;
467
+ var e = pendingScrollEl; pendingScrollEl = null;
468
+ if (e && e.scrollIntoView) { try { e.scrollIntoView({ block: 'nearest', inline: 'nearest' }); } catch (x) {} }
469
+ });
470
+ }
471
+
458
472
  var setActiveRaf = 0, setActiveScrollPending = true;
459
473
  function setActive(index, shouldScroll = true) {
460
474
  if (hunkTotal() === 0) return;
@@ -814,10 +828,11 @@ function treeRows() {
814
828
  function focusTree(index) {
815
829
  const rows = treeRows();
816
830
  if (rows.length === 0) return;
831
+ // Incremental: drop the old focus class and add the new one — no full forEach over every row per keystroke.
832
+ if (treeFocusIndex >= 0 && treeFocusIndex < rows.length) rows[treeFocusIndex]?.classList.remove('tree-focus');
817
833
  treeFocusIndex = Math.max(0, Math.min(rows.length - 1, index));
818
- rows.forEach((row, i) => row.classList.toggle('tree-focus', i === treeFocusIndex));
819
834
  const el = rows[treeFocusIndex];
820
- if (el) el.scrollIntoView({ block: 'nearest' });
835
+ if (el) { el.classList.add('tree-focus'); scheduleScrollIntoView(el); }
821
836
  }
822
837
 
823
838
  function clearTreeFocus() {
@@ -1454,10 +1469,7 @@ function setDiffCursor(path, side, rowIndex, column, reveal) {
1454
1469
  diffSelectionAnchor = null; // any direct caret placement (click/F7/Cmd-arrow) drops the selection; Shift+Arrow re-sets it
1455
1470
  renderDiffCaret();
1456
1471
  applyDiffSelection();
1457
- if (reveal) {
1458
- var r = diffRowAt(wrapper, side, ri);
1459
- if (r && r.scrollIntoView) requestAnimationFrame(function () { try { r.scrollIntoView({ block: 'nearest' }); } catch (e) {} });
1460
- }
1472
+ if (reveal) scheduleScrollIntoView(diffRowAt(wrapper, side, ri));
1461
1473
  recordNav(navEntryOf('diff'));
1462
1474
  }
1463
1475
  function navEntryOf(kind) {
@@ -2923,11 +2935,7 @@ function setSourceCursor(path, lineIndex, column, shouldReveal = false, targetLi
2923
2935
  const shouldSwitch = !viewer || viewer.dataset.openPath !== path || viewer.classList.contains('hidden');
2924
2936
  openSourceFile(path, shouldSwitch);
2925
2937
  }
2926
- if (shouldReveal) {
2927
- requestAnimationFrame(() => {
2928
- document.querySelector('.source-row.cursor-line')?.scrollIntoView({ block: 'center' });
2929
- });
2930
- }
2938
+ if (shouldReveal) scheduleScrollIntoView(document.querySelector('.source-row.cursor-line'));
2931
2939
  recordNav(navEntryOf('source'));
2932
2940
  }
2933
2941
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@happy-nut/monacori",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "Validation control plane for AI-generated code changes.",
5
5
  "type": "module",
6
6
  "repository": {