fix: revert to simple ioctl-first with env var 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.
This commit is contained in:
2026-05-14 13:05:53 -04:00
parent abe4edaffc
commit 7813e27907
2 changed files with 42 additions and 68 deletions

View File

@@ -164,7 +164,6 @@ 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))
(multiple-value-bind (w h)
(or (ignore-errors (or (ignore-errors
(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)))
@@ -176,31 +175,16 @@ as a fallback when a keyword is not in *named-colors*.")
(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))))
(values 0 0)) ;; $COLUMNS/$LINES fallback — some systems don't update the
;; If ioctl returned a plausible size (not the 80x24 default), ;; TTY size via ioctl on stdout's fd.
;; trust it — it will be correct at runtime after SIGWINCH. (ignore-errors
(if (and (> w 80) (> h 24))
(values w h)
;; ioctl returned 80x24 or less — suspicious. Try $COLUMNS/
;; $LINES from the shell, which reflect the true size at
;; process start even when ioctl on stdout's fd disagrees.
(or (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))))
;; Some environments set only COLUMNS or only LINES.
;; If one is missing, try the other from stty.
(when (and cols (null rows))
(let* ((out (uiop:run-program '("stty" "size")
:output :string
:ignore-error-status t))
(parts (when out (uiop:split-string (string-trim '(#\newline #\space) out)))))
(setf rows (when (and parts (= (length parts) 2))
(parse-integer (second parts) :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 w h))))) (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,7 +27,6 @@
(values)) (values))
(defmethod backend-size ((b simple-backend)) (defmethod backend-size ((b simple-backend))
(multiple-value-bind (w h)
(or (ignore-errors (or (ignore-errors
(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)))
@@ -40,24 +39,15 @@
(values (sb-alien:deref winsize 1) (values (sb-alien:deref winsize 1)
(sb-alien:deref winsize 0))) (sb-alien:deref winsize 0)))
(sb-alien:free-alien winsize)))) (sb-alien:free-alien winsize))))
(values 0 0)) ;; $COLUMNS/$LINES fallback
(if (and (> w 80) (> h 24)) (ignore-errors
(values w h)
(or (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 (null rows))
(let* ((out (uiop:run-program '("stty" "size")
:output :string
:ignore-error-status t))
(parts (when out (uiop:split-string (string-trim '(#\newline #\space) out)))))
(setf rows (when (and parts (= (length parts) 2))
(parse-integer (second parts) :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 w h))))) (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)))