mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-11 09:49:41 +02:00
fix(tiles): Redraw on a tile sends the forced resize and reports only what it sent
Redraw (Ctrl+Shift+R and the header button, restoreTerminalSize) on a
focused tile or the split's Pane B called tile.fit({ force: true }) and
always toasted "Terminal restored to CxR". In TerminalTile._sendResize,
force only skipped the client-side dedupe: the frame carried no `f`, so
Session.resize skipped a size equal to the one it last applied and the
server did nothing. And _sendResize returned silently with the socket down
or the session popped out to its own window, while the toast still
claimed success.
Both halves are fixed, the first as parity with the primary pane:
- a forced fit now sends `f: true`, the flag the primary's sendResize sets,
which the server honours (ws-routes reads msg.f, Session.resize then runs
tmux resize-window and the PTY resize at the same size);
- fit() and _sendResize() return whether a frame went out, and
restoreTerminalSize toasts success only then. Otherwise it says why, as
the primary branch does: "sized by its own window" for a detached
session, "not connected" while the tile's socket is down (it announces
its size again on reopen), and the primary's "Could not determine
terminal size" for a pane that measured nothing.
What this does not claim: a forced resize to the size the PTY already has
changes no geometry, so it is not a cure for a garbled tile whose PTY
already matches; the primary pane's forced resize has the same limit. It
matters when the server's recorded size has drifted from the tmux window.
Tests: the forced frame carries f:true (and plain ones do not), fit()'s
return value on send, dedupe, detached and closed-socket paths, and Redraw
end to end on a real tile (sent, socket down, popped out), plus the three
no-success toasts in focused-pane-shortcuts.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1205,23 +1205,26 @@
|
||||
// Reflow to the container and tell the PTY, as one step: the xterm and the
|
||||
// PTY must never disagree about size (#464), and a font change is a size
|
||||
// change too, so the font setters call this rather than localFit().
|
||||
// `force` resends an unchanged size.
|
||||
// `force` resends an unchanged size and asks the server to apply it anyway
|
||||
// (Redraw, restoreTerminalSize). Returns whether a resize went out.
|
||||
fit({ force = false } = {}) {
|
||||
this.localFit();
|
||||
this._sendResize({ force });
|
||||
return this._sendResize({ force });
|
||||
}
|
||||
|
||||
// Returns true only once a `{t:'z'}` frame was sent, false at every early
|
||||
// exit, so Redraw can say when nothing reached the PTY.
|
||||
_sendResize({ force = false } = {}) {
|
||||
if (!this._wsReady || !this.fitAddon || !this.terminal) return;
|
||||
if (!this._wsReady || !this.fitAddon || !this.terminal) return false;
|
||||
// One PTY cannot hold two sizes (mirrors sendResize's own
|
||||
// detachedElsewhere yield in terminal-ui.js): the session got detached
|
||||
// to its own window AFTER this pane was opened, so its own window now
|
||||
// owns the PTY's size and this pane must stand aside.
|
||||
if (this.detachedSessions?.has(this.sessionId)) return;
|
||||
if (this.detachedSessions?.has(this.sessionId)) return false;
|
||||
// A hidden pane (a web tab over it, a zoomed neighbour) measures NaN, and
|
||||
// fit() then leaves the xterm alone: there is no size worth reporting.
|
||||
const dims = this.fitAddon.proposeDimensions();
|
||||
if (!dims || !Number.isFinite(dims.cols) || !Number.isFinite(dims.rows)) return;
|
||||
if (!dims || !Number.isFinite(dims.cols) || !Number.isFinite(dims.rows)) return false;
|
||||
// Report what the xterm actually holds, so the PTY gets exactly the size
|
||||
// the pane renders at. Unclamped, unlike the primary pane's 40x10 floor:
|
||||
// a floor would misreport the split's Pane B at its divider's reachable
|
||||
@@ -1231,9 +1234,20 @@
|
||||
const cols = this.terminal.cols;
|
||||
const rows = this.terminal.rows;
|
||||
const last = this._lastSentDims;
|
||||
if (!force && last && last.cols === cols && last.rows === rows) return;
|
||||
if (!force && last && last.cols === cols && last.rows === rows) return false;
|
||||
// `f` is the primary pane's forced resize (sendResize, terminal-ui.js):
|
||||
// Session.resize (session.ts) otherwise skips a size equal to the one it
|
||||
// last applied, so without it a forced resend reached the server and did
|
||||
// nothing there (no tmux resize-window, no PTY resize).
|
||||
const msg = { t: 'z', c: cols, r: rows, v: 'desktop' };
|
||||
if (force) msg.f = true;
|
||||
try {
|
||||
this.ws.send(JSON.stringify(msg));
|
||||
} catch {
|
||||
return false; // nothing went out, so nothing is recorded as sent
|
||||
}
|
||||
this._lastSentDims = { cols, rows };
|
||||
this.ws.send(JSON.stringify({ t: 'z', c: cols, r: rows, v: 'desktop' }));
|
||||
return true;
|
||||
}
|
||||
|
||||
// The session's PTY is new: a tile can connect before its session has a
|
||||
|
||||
@@ -4664,11 +4664,24 @@ Object.assign(CodemanApp.prototype, {
|
||||
*/
|
||||
async restoreTerminalSize() {
|
||||
// A second pane owns its own geometry: refit it and force its PTY to the
|
||||
// size it renders at (TerminalTile.fit), whatever another device set.
|
||||
// size it renders at (TerminalTile.fit sends the same forced `f` resize
|
||||
// sendResize sends below), whatever another device set. fit() says whether
|
||||
// the resize went out; when it did not, say why rather than report a size
|
||||
// that was never sent, as the primary branch does below.
|
||||
const pane = this._focusedPane();
|
||||
if (!pane.isPrimary) {
|
||||
pane.tile.fit({ force: true });
|
||||
this.showToast(`Terminal restored to ${pane.terminal.cols}x${pane.terminal.rows}`, 'success');
|
||||
const sent = pane.tile.fit({ force: true });
|
||||
if (sent !== false) {
|
||||
this.showToast(`Terminal restored to ${pane.terminal.cols}x${pane.terminal.rows}`, 'success');
|
||||
} else if (this.detachedSessions?.has(pane.sessionId)) {
|
||||
// Its own window owns the PTY's size (TerminalTile._sendResize yields).
|
||||
this.showToast('This session is sized by its own window', 'warning');
|
||||
} else if (!pane.tile._wsReady) {
|
||||
// The tile announces its size again as soon as its socket reopens.
|
||||
this.showToast('Terminal not connected: its size is sent when it reconnects', 'warning');
|
||||
} else {
|
||||
this.showToast('Could not determine terminal size', 'error');
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!this.activeSessionId) {
|
||||
|
||||
Reference in New Issue
Block a user