fix: ioctl on stdin fd (0) first, then stdout fd, then env vars

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.
This commit is contained in:
2026-05-14 13:07:05 -04:00
parent 7813e27907
commit 4a86ae3274
2 changed files with 45 additions and 42 deletions

View File

@@ -164,27 +164,30 @@ as a fallback when a keyword is not in *named-colors*.")
(values)) (values))
(defmethod backend-size ((b modern-backend)) (defmethod backend-size ((b modern-backend))
(or (ignore-errors (flet ((ioctl-size (fd)
(let* ((+tiocgwinsz+ 21523) ; 0x5413 on Linux (let* ((+tiocgwinsz+ 21523) ; 0x5413 on Linux
(winsize (sb-alien:make-alien sb-alien:unsigned-short 4))) (winsize (sb-alien:make-alien sb-alien:unsigned-short 4)))
(unwind-protect (unwind-protect
(progn (progn
(sb-unix:unix-ioctl (sb-sys:fd-stream-fd (backend-output-stream b)) (sb-unix:unix-ioctl fd +tiocgwinsz+
+tiocgwinsz+ (sb-alien:alien-sap winsize))
(sb-alien:alien-sap winsize)) (values (sb-alien:deref winsize 1) ;; cols
(values (sb-alien:deref winsize 1) ;; cols (sb-alien:deref winsize 0))) ;; rows
(sb-alien:deref winsize 0))) ;; rows (sb-alien:free-alien winsize)))))
(sb-alien:free-alien winsize)))) (or ;; Try ioctl on fd 0 first (stdin — stty uses this)
;; $COLUMNS/$LINES fallback — some systems don't update the (ignore-errors (ioctl-size 0))
;; TTY size via ioctl on stdout's fd. ;; Then try the output stream's fd
(ignore-errors (ignore-errors
(let* ((cstr (sb-ext:posix-getenv "COLUMNS")) (ioctl-size (sb-sys:fd-stream-fd (backend-output-stream b))))
(rstr (sb-ext:posix-getenv "LINES")) ;; $COLUMNS/$LINES fallback — set by every POSIX shell
(cols (when cstr (parse-integer cstr :junk-allowed t))) (ignore-errors
(rows (when rstr (parse-integer rstr :junk-allowed t)))) (let* ((cstr (sb-ext:posix-getenv "COLUMNS"))
(when (and cols rows (> cols 0) (> rows 0)) (rstr (sb-ext:posix-getenv "LINES"))
(values cols rows)))) (cols (when cstr (parse-integer cstr :junk-allowed t)))
(values 80 24))) (rows (when rstr (parse-integer rstr :junk-allowed t))))
(when (and cols rows (> cols 0) (> rows 0))
(values cols rows))))
(values 80 24))))
(defmethod backend-write ((b modern-backend) string) (defmethod backend-write ((b modern-backend) string)
(let ((stream (backend-output-stream b))) (let ((stream (backend-output-stream b)))

View File

@@ -27,27 +27,27 @@
(values)) (values))
(defmethod backend-size ((b simple-backend)) (defmethod backend-size ((b simple-backend))
(or (ignore-errors (flet ((ioctl-size (fd)
(let* ((+tiocgwinsz+ 21523) (let* ((+tiocgwinsz+ 21523)
(winsize (sb-alien:make-alien sb-alien:unsigned-short 4))) (winsize (sb-alien:make-alien sb-alien:unsigned-short 4)))
(unwind-protect (unwind-protect
(progn (progn
(sb-unix:unix-ioctl (sb-sys:fd-stream-fd (sb-unix:unix-ioctl fd +tiocgwinsz+
(backend-output-stream b)) (sb-alien:alien-sap winsize))
+tiocgwinsz+ (values (sb-alien:deref winsize 1)
(sb-alien:alien-sap winsize)) (sb-alien:deref winsize 0)))
(values (sb-alien:deref winsize 1) (sb-alien:free-alien winsize)))))
(sb-alien:deref winsize 0))) (or (ignore-errors (ioctl-size 0))
(sb-alien:free-alien winsize)))) (ignore-errors
;; $COLUMNS/$LINES fallback (ioctl-size (sb-sys:fd-stream-fd (backend-output-stream b))))
(ignore-errors (ignore-errors
(let* ((cstr (sb-ext:posix-getenv "COLUMNS")) (let* ((cstr (sb-ext:posix-getenv "COLUMNS"))
(rstr (sb-ext:posix-getenv "LINES")) (rstr (sb-ext:posix-getenv "LINES"))
(cols (when cstr (parse-integer cstr :junk-allowed t))) (cols (when cstr (parse-integer cstr :junk-allowed t)))
(rows (when rstr (parse-integer rstr :junk-allowed t)))) (rows (when rstr (parse-integer rstr :junk-allowed t))))
(when (and cols rows (> cols 0) (> rows 0)) (when (and cols rows (> cols 0) (> rows 0))
(values cols rows)))) (values cols rows))))
(values 80 24))) (values 80 24))))
(defmethod backend-write ((b simple-backend) string) (defmethod backend-write ((b simple-backend) string)
(let ((stream (backend-output-stream b))) (let ((stream (backend-output-stream b)))