mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-09-30 12:39:42 +02:00
fix(split-pane): populate Pane B history and force-resize Pane A on split changes
Pane B's SplitTerminalPane.connect() only opened a WebSocket and waited for live output — ws-routes.ts's terminal socket sends nothing on connect, only future 'terminal' events — so it stayed blank until the target session happened to produce new output. It looked intermittent rather than always-broken because a resize sent by _sendResize() often nudges the session's real tmux window to a new size, and tmux repaints its current screen on resize; that incidental repaint was what usually populated the pane. When Pane B's computed dimensions already matched the session's last-known size, Session.resize() skipped the resize as a no-op and the pane stayed empty. Fetch the existing scrollback (?full=1) before opening the socket, same as the primary pane does. Pane A never told its own session's PTY/tmux about a size change at all, relying purely on the passive 300ms-debounced ResizeObserver in terminal-ui.js. openSplitPane() now force-resizes Pane A immediately on entering split (mirroring closeSplitPane()'s existing symmetric call), and the divider-drag handler force-resizes it once at drag end (matching the codebase's established trailing-edge debounce convention rather than flooding a resize per mousemove). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
33b2605815
commit
3859506f9b
@@ -21,9 +21,10 @@
|
||||
this.fitAddon = null;
|
||||
this.ws = null;
|
||||
this._wsReady = false;
|
||||
this._destroyed = false;
|
||||
}
|
||||
|
||||
connect() {
|
||||
async connect() {
|
||||
this.terminal = new Terminal({
|
||||
theme: { ...global.codemanCurrentXtermTheme() },
|
||||
fontFamily: global.CodemanTerminalFont.resolve(),
|
||||
@@ -49,6 +50,28 @@
|
||||
}
|
||||
});
|
||||
|
||||
// Load existing scrollback before going live. The WS below is
|
||||
// subscribe-only (ws-routes.ts sends nothing on connect, only future
|
||||
// 'terminal' events), so without this Pane B stays blank until the
|
||||
// target session happens to produce new output. It LOOKED
|
||||
// intermittent rather than always-broken because _sendResize() below
|
||||
// often nudges the shared session's real tmux window to a new size,
|
||||
// and tmux repaints its current screen on resize — that repaint was
|
||||
// getting captured and streamed here, incidentally populating the
|
||||
// pane. When Pane B's computed dimensions happened to already match
|
||||
// the session's last-known size, Session.resize() (session.ts) skips
|
||||
// the resize as a no-op, no repaint fires, and the pane stayed blank.
|
||||
try {
|
||||
const res = await fetch(`${window.CodemanBase.base}/api/sessions/${this.sessionId}/terminal?full=1`);
|
||||
const payload = (await res.json())?.data ?? {};
|
||||
if (payload.terminalBuffer && this.terminal) {
|
||||
this.terminal.write(payload.terminalBuffer);
|
||||
}
|
||||
} catch {
|
||||
/* Best-effort — live output still arrives once the socket below connects. */
|
||||
}
|
||||
if (this._destroyed) return;
|
||||
|
||||
const proto = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||
const url = `${proto}//${location.host}${window.CodemanBase.base}/ws/sessions/${this.sessionId}/terminal`;
|
||||
this.ws = new WebSocket(url);
|
||||
@@ -106,6 +129,7 @@
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this._destroyed = true;
|
||||
if (this.ws) {
|
||||
this.ws.onopen = null;
|
||||
this.ws.onmessage = null;
|
||||
@@ -255,6 +279,14 @@ Object.assign(CodemanApp.prototype, {
|
||||
this._splitPane.connect();
|
||||
this._splitSessionId = sessionId;
|
||||
|
||||
// Pane A just went from full width to 50%, but nothing has told its
|
||||
// session's PTY/tmux window about it yet — the passive ResizeObserver in
|
||||
// terminal-ui.js debounces 300ms and would eventually catch up, but
|
||||
// relying on that left the pane showing stale-width content (existing
|
||||
// box-drawing lines, banners) until the user hit "Redraw Terminal".
|
||||
// Force it immediately, mirroring closeSplitPane()'s symmetric call.
|
||||
this.sendResize?.(this.activeSessionId, { force: true })?.catch?.(() => {});
|
||||
|
||||
this._installSplitDividerDrag(divider, wrap, paneB);
|
||||
},
|
||||
|
||||
@@ -296,6 +328,17 @@ Object.assign(CodemanApp.prototype, {
|
||||
divider.classList.remove('dragging');
|
||||
document.removeEventListener('mousemove', onMove);
|
||||
document.removeEventListener('mouseup', onUp);
|
||||
// Pane B force-resizes on every move via _splitPane.fit() (SplitTerminalPane
|
||||
// has no client-side "dims unchanged" skip, so it always reaches the
|
||||
// server). Pane A's onMove above only calls fitAddon.fit() — a LOCAL
|
||||
// xterm reflow that changes how many columns xterm displays but never
|
||||
// tells Pane A's own PTY/tmux window the new size, so existing content
|
||||
// (box-drawing lines, banners) stays laid out for the old width. Fire
|
||||
// once here, at drag end, rather than per-move (matching the codebase's
|
||||
// established trailing-edge debounce convention — see throttledResize
|
||||
// in terminal-ui.js — so a fast drag doesn't flood dozens of
|
||||
// intermediate SIGWINCH/reflow states into scrollback).
|
||||
this.sendResize?.(this.activeSessionId, { force: true })?.catch?.(() => {});
|
||||
};
|
||||
|
||||
divider.addEventListener('mousedown', () => {
|
||||
|
||||
Reference in New Issue
Block a user