From 2e3e245cc651dc24e48a560981755571487ad1be Mon Sep 17 00:00:00 2001 From: timkjr Date: Sat, 19 Sep 2026 14:02:16 -0500 Subject: [PATCH] fix(split-pane): throttle the drag, chunk the scrollback, and the rest of Ark0N's second pass MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two majors: - The divider drag was unthrottled: every mousemove did a full xterm reflow on BOTH panes and sent Pane B a {t:'z'} resize frame with no unchanged-dimensions skip, fanning out into a `tmux resize-window` child plus a SIGWINCH per event — ~50 of each dragging across half a wide viewport. SplitTerminalPane.fit() is now split into localFit() (reflow only) and fit() (reflow + send); the drag coalesces moves into one localFit() per animation frame via requestAnimationFrame, and sends the real resize for both panes exactly once, at drag end, matching the primary pane's own throttledResize convention. - Pane B pulled the FULL scrollback unchunked for every session mode, writing it in one terminal.write() call. Mirrors the primary pane's own mode check (app.js's selectSession): shell sessions get a bounded 1MiB ?tail= fetch instead of ?full=1, and the fetched buffer is written through a minimal chunked writer (32KB slices, yielding a frame between each) instead of one primary-pane chunkedTerminalWrite this simpler, independently created/destroyed pane has no equivalent of (no session-switch generation counters or live-output gate). Smaller items from the same review: - Pane B now follows live appearance changes (applyTerminalSkin, applyTerminalFontFamily, applyTerminalFontWeights, setFontSize all propagate to it, matching the teammateTerminals pattern) and reads the real codeman-font-size/terminalFontFamily/weights/DEFAULT_SCROLLBACK settings at construction instead of hardcoding fontSize 14 / scrollback 5000. - The Pane-B-promotion path now skips selectSession() when _closingSessions already owns this delete (the user closing Pane A's own tab), matching _onSessionDeleted's own active-session-handoff guard. - Detaching a session AFTER a split is already open now yields the PTY size in _sendResize() too (not just at picker-open time), mirroring sendResize's own detachedElsewhere guard. - .btn-split joins the body.solo-mode hide list, next to .btn-multimonitor. - The split row was 6px wider than its container (two flex-shrink:0 50% panes plus a 6px divider): both panes are now flex-shrink 1. - Pane B's header and the split-picker rows are marked so i18n.js's exact-string lookup skips them, matching .session-name elsewhere — a session literally named e.g. "Sessions" was translatable on zh-CN. - The Split button now reflects open/closed state via a `.split-open` accent style, aria-pressed, and a title/aria-label that says which behaviour the next click gets. - _splitPane.connect() is no longer an unawaited call with no .catch(). - terminal-split.js's fileoverview pointed at a doc path that was renamed away in the previous push; @dependency now credits constants.js for CodemanTerminalFont, not terminal-ui.js. - index.html's Split settings chip no longer reuses data-preview-order "12" (already the Ultracode Agents chip's slot in the same "header" preview group). Co-Authored-By: Claude Sonnet 5 --- src/web/public/constants.js | 10 + src/web/public/index.html | 4 +- src/web/public/mobile.css | 13 +- src/web/public/styles.css | 37 +++- src/web/public/terminal-split.js | 202 +++++++++++++++++---- src/web/public/terminal-ui.js | 20 ++ test/split-pane-auto-collapse-unit.test.ts | 20 ++ 7 files changed, 264 insertions(+), 42 deletions(-) diff --git a/src/web/public/constants.js b/src/web/public/constants.js index 72cc6e7d..ba2deec1 100644 --- a/src/web/public/constants.js +++ b/src/web/public/constants.js @@ -1520,6 +1520,15 @@ function terminalLogicalLine(buffer, row, cols, maxRows) { // Split-Pane Sessions — pure helpers (divider math, picker list) // ═══════════════════════════════════════════════════════════════ +// Desktop-only, same reasoning and same threshold as HOME_SESSIONS_MIN_WIDTH +// (home-sessions.js): two 240px min-width panes plus the divider need ~486px, +// which a phone or narrow tablet cannot give them, and the divider has no +// touch handlers. A dedicated constant rather than reusing +// HOME_SESSIONS_MIN_WIDTH directly — that name lives in home-sessions.js, +// which loads AFTER this file (load order 12.56 vs 7.5), so referencing it +// from module-evaluation-time code here would be a ReferenceError. +const SPLIT_PANE_MIN_WIDTH = 1180; + function clampDividerPercent(rawPercent, min = 20, max = 80) { if (rawPercent < min) return min; if (rawPercent > max) return max; @@ -1550,5 +1559,6 @@ if (typeof window !== 'undefined') { window.CodemanSplitPane = { clampDividerPercent, buildSplitPickerSessions, + SPLIT_PANE_MIN_WIDTH, }; } diff --git a/src/web/public/index.html b/src/web/public/index.html index 6fed16d6..4c970475 100644 --- a/src/web/public/index.html +++ b/src/web/public/index.html @@ -191,7 +191,7 @@ - +
—