mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-09-30 12:39:42 +02:00
fix(tui): escape the separator in the switch binding, closing the sizing leak
The loose end from777f974, now explained. Sessions came back from a detach on `window-size latest` instead of `manual`, and the restore primitive round-tripped correctly in isolation, so the corruption had to be upstream of it. It was: the snapshot was taken from state this code had already broken. `bindSwitchKey` passed a bare `;` between the two commands it wanted in one binding. That is a command separator to tmux's OWN parser, not an argument: it ended the `bind-key` and executed what followed immediately. So the binding kept only `switch-client`, and `set-window-option ... window-size latest` RAN against every switchable session at attach time — before the sizing snapshot was taken. Every session was therefore snapshotted as `latest` and faithfully restored to `latest`. Proven against real tmux both ways before fixing: a bare `;` leaves the session on `latest` and stores a one-command binding, while `\;` leaves it `manual` and stores both commands. Verified end to end: 7 sessions manual before, 1 latest + 6 manual during the attach (the attached one follows the terminal, the rest are pre-sized), no dot padding on a switch, and all 7 back to 120x40 manual after the detach. This also means the "follow the terminal after switching" half of777f974never actually worked — it was never in the binding.
This commit is contained in:
@@ -1004,6 +1004,13 @@ export class TuiClient {
|
||||
// It is already the right size (see presizeWindow), so `latest` changes
|
||||
// nothing on arrival and costs no repaint — it matters only if the
|
||||
// terminal is resized while sitting in that session.
|
||||
//
|
||||
// ⚠️ The separator MUST be an escaped `\;`. A bare `;` is a command
|
||||
// separator to tmux's own parser, so it ends the `bind-key` and RUNS
|
||||
// what follows immediately: the binding kept only `switch-client`, and
|
||||
// every session got `window-size latest` executed on it at attach time.
|
||||
// That is what left sessions on `latest` after a detach, since the
|
||||
// snapshot was then taken from already-corrupted state.
|
||||
await this.exec('tmux', [
|
||||
'-L',
|
||||
this.socket,
|
||||
@@ -1014,7 +1021,7 @@ export class TuiClient {
|
||||
'switch-client',
|
||||
'-t',
|
||||
target,
|
||||
';',
|
||||
'\\;',
|
||||
'set-window-option',
|
||||
'-t',
|
||||
target,
|
||||
|
||||
@@ -602,6 +602,32 @@ describe('attach window sizing', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('TuiClient.bindSwitchKey', () => {
|
||||
it('escapes the command separator, or tmux runs the second command instead of binding it', () => {
|
||||
// ⚠️ A bare `;` argument is a command separator to tmux's OWN parser: it
|
||||
// ends the bind-key and executes what follows immediately. That bound only
|
||||
// `switch-client` and ran `window-size latest` against every session at
|
||||
// attach time, which is why sessions were left on `latest` after a detach —
|
||||
// the sizing snapshot was taken from already-corrupted state. Verified
|
||||
// against real tmux both ways before this test was written.
|
||||
const calls: string[][] = [];
|
||||
const exec: TuiExecFile = async (_file, args) => {
|
||||
calls.push([...args]);
|
||||
return { stdout: '', stderr: '' };
|
||||
};
|
||||
const client = new TuiClient({ baseUrl: BASE_URL, socket: 'codeman-beta', exec });
|
||||
return client.bindSwitchKey('M-2', 'codeman-aaaa1111').then(() => {
|
||||
const bind = calls.find((args) => args.includes('bind-key'));
|
||||
expect(bind).toBeDefined();
|
||||
expect(bind).toContain('\\;');
|
||||
expect(bind).not.toContain(';');
|
||||
// Both commands have to be in the ONE binding.
|
||||
expect(bind?.join(' ')).toContain('switch-client -t codeman-aaaa1111');
|
||||
expect(bind?.join(' ')).toContain('window-size latest');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('parsePrefixBinding', () => {
|
||||
const REAL = [
|
||||
'bind-key -T prefix d detach-client',
|
||||
|
||||
Reference in New Issue
Block a user