The user's terminal reports 186x60 via stty (which uses stdin fd)
and via COLUMNS/LINES, but ioctl on stdout's fd returns 80x24.
Priority: fd 0 → backend output fd → env vars → 80x24 fallback.
The previous logic (check ioctl result, prefer env when 80x24)
added complexity and crashes. Simple or with env vars after ioctl
is safe: ioctl returns 80x24 on stdout fd mismatch, env vars
(COLUMNS/LINES from shell) provide the correct initial size.
ioctl on stdout's fd can return the default 80x24 even when the
terminal is much larger (fd mismatch). The new logic:
1. Try ioctl — if it returns >80x24, trust it (correct at runtime).
2. If ioctl returned 80x24 (suspicious default), try COLUMNS/LINES
from the shell environment instead.
3. If both fail, return whatever ioctl gave us (80x24).
This fixes initial sizing on terminals where ioctl disagrees with
the real TTY size, without breaking runtime SIGWINCH resize
(which always re-queries ioctl, and that is correct after resize).
ioctl on stdout's fd can disagree with the real terminal size when
the process is started with stdout redirected or in some terminal
multiplexer configurations. / are set by every POSIX
shell at process start and reflect the actual terminal dimensions.
Priority: ioctl → env vars → 80x24 fallback.
This covers both initial sizing and dynamic SIGWINCH-driven resize.
The CSI 18t query leaks into the threaded keyboard reader because
the response arrives on stdin after the reader thread starts. The
response bytes get queued as key events and inserted as text into
the TUI input buffer. Removing the query entirely — ioctl is
sufficient for terminal size detection on all modern terminals.
%query-terminal-size uses blocking read-char on an fd 0 stream
to read the terminal's response to \033[18t. This works even when
unix-simple-poll on fd 0 returns NIL (unlike read-char-no-hang).
Added as fallback in both modern and simple backends.
The %query-terminal-size function sent \033[18t and tried to read
the response via read-char-no-hang on fd 0, which always returns nil
in this SBCL environment. The response leaked into user input,
displaying garbled CSI sequences. Rely on ioctl only.
- Disabled \033[?u kitty keyboard protocol in modern-backend
(converts all keys to escape sequences, breaking Ctrl+letter dispatch)
- Fixed parse-csi-sequence: use multiple-value-bind instead of let*
with destructuring-bind (lost secondary return value from read-param)
- Fixed parse-csi-params format string: pass char-code of terminator
as distinct argument for ~d, keeping the character for ~C
- Added %query-terminal-size in classes.lisp: ANSI CSI 18t fallback
for terminal size detection when ioctl fails or returns zero
Application code (passepartout TUI) calls draw-text with a framebuffer
(2D array) as the first argument, but draw-text only had methods for
framebuffer-backend CLOS instances. Added a method on array that sets
cells directly on the framebuffer array, matching make-framebuffer's
return type.
Bug fixes:
- Fix OSC8 format strings (backslash escape layering) in modern-backend.org
- Test format string had single backslash instead of double, causing
unclosed CL string that cascaded through 3 subsequent test forms
- Implementation format string had leading escaped quote (not a string
opener) and triple-backslash ending (also not a string terminator)
- Fix missing closing parens in border-char-rounded and border-char-double tests
- Fix ASDF input-tests pathname (file lives in tests/, not src/components/)
New features:
- Implement suspend-backend / resume-backend protocol methods
- modern-backend: exit/enter alt screen, re-enable mouse/kitty/bracketed-paste
- simple-backend: no-ops (no terminal state to preserve)
Infrastructure:
- Update test suite to cover suspend/resume (backend + modern-backend suites)
- 454 checks, 100% pass across 14 test suites