Skip to content

fix(pty): refuse a degenerate terminal size instead of honouring it - #52

Merged
404SecNotFound merged 1 commit into
mainfrom
fix/terminal-min-dimensions
Aug 3, 2026
Merged

fix(pty): refuse a degenerate terminal size instead of honouring it#52
404SecNotFound merged 1 commit into
mainfrom
fix/terminal-min-dimensions

Conversation

@404SecNotFound

Copy link
Copy Markdown
Owner

Found while verifying F-04 in a real browser, not by review.

The xterm fit addon measures its container. A tab that has not been laid out
yet, or a pane that is briefly zero-width, makes it compute cols: 1 and send
it. _bounded accepted anything from 1 to MAX_DIMENSION, so the PTY was duly
resized to one column and every prompt after that wrapped one character per
line.

What made it hard to recognise: the Rich banner is printed at spawn, before the
resize frame arrives, so it stays perfectly readable at 100 columns while
everything after it is a vertical ribbon. It reads as a font or rendering fault
rather than as a resize the server agreed to. The give-away was that the
.xterm-rows first row was still 100 characters wide while the live prompt was
not.

Floored server-side at 20 columns rather than fixed in the client. The client is
the thing that was wrong, and a bound that only holds when the client is correct
is not a bound. 20 leaves room for the menu to be legible while still refusing
anything that is obviously a measurement of nothing.

One existing parametrised case asserted that 1 was usable. It is the assumption
being corrected, so it is now MIN_DIMENSION with a note saying why.

842 py. black, ruff, mypy clean.

Found while verifying F-04 in a real browser, not by review.

The xterm fit addon measures its container. A tab that has not been laid out
yet, or a pane that is briefly zero-width, makes it compute `cols: 1` and send
it. `_bounded` accepted anything from 1 to MAX_DIMENSION, so the PTY was duly
resized to one column and every prompt after that wrapped one character per
line.

What made it hard to recognise: the Rich banner is printed at spawn, before the
resize frame arrives, so it stays perfectly readable at 100 columns while
everything after it is a vertical ribbon. It reads as a font or rendering fault
rather than as a resize the server agreed to. The give-away was that the
`.xterm-rows` first row was still 100 characters wide while the live prompt was
not.

Floored server-side at 20 columns rather than fixed in the client. The client is
the thing that was wrong, and a bound that only holds when the client is correct
is not a bound. 20 leaves room for the menu to be legible while still refusing
anything that is obviously a measurement of nothing.

One existing parametrised case asserted that 1 was usable. It is the assumption
being corrected, so it is now MIN_DIMENSION with a note saying why.

842 py. black, ruff, mypy clean.
@404SecNotFound
404SecNotFound merged commit 1b969b2 into main Aug 3, 2026
10 checks passed
@404SecNotFound
404SecNotFound deleted the fix/terminal-min-dimensions branch August 3, 2026 18:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant