fix: add stty size subprocess fallback in both backends

stty size via uiop:run-program is the most reliable method —
it works from the shell on every Unix system and bypasses
alien/ioctl quirks. Placed between stdout ioctl and /dev/tty
ioctl in the fallback chain.
This commit is contained in:
2026-05-14 14:15:30 -04:00
parent 41e2b867be
commit 4df3048a13
2 changed files with 26 additions and 1 deletions

View File

@@ -173,6 +173,19 @@ 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))))
;; stty size via subprocess — reliable on every Unix, bypasses
;; SBCL's alien/ioctl quirks. Returns "ROWS COLS".
(ignore-errors
(let* ((out (uiop:run-program '("stty" "size")
:output :string
:ignore-error-status t))
(parts (and out (uiop:split-string
(string-trim '(#\newline #\space) out)))))
(when (and parts (= (length parts) 2))
(let ((rows (parse-integer (first parts) :junk-allowed t))
(cols (parse-integer (second parts) :junk-allowed t)))
(when (and rows cols (> rows 0) (> cols 0))
(values cols rows))))))
;; Direct ioctl on /dev/tty — opens the real controlling terminal. ;; Direct ioctl on /dev/tty — opens the real controlling terminal.
(ignore-errors (ignore-errors
(let ((tty-fd (sb-unix:unix-open "/dev/tty" 0 0))) ; O_RDONLY (let ((tty-fd (sb-unix:unix-open "/dev/tty" 0 0))) ; O_RDONLY

View File

@@ -33,7 +33,19 @@
(sb-alien:alien-sap winsize)) (sb-alien:alien-sap winsize))
(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))))
;; stty size via subprocess — reliable on every Unix.
(ignore-errors
(let* ((out (uiop:run-program '("stty" "size")
:output :string
:ignore-error-status t))
(parts (and out (uiop:split-string
(string-trim '(#\newline #\space) out)))))
(when (and parts (= (length parts) 2))
(let ((rows (parse-integer (first parts) :junk-allowed t))
(cols (parse-integer (second parts) :junk-allowed t)))
(when (and rows cols (> rows 0) (> cols 0))
(values cols rows))))))
(ignore-errors (ignore-errors
(let ((tty-fd (sb-unix:unix-open "/dev/tty" 0 0))) ; O_RDONLY (let ((tty-fd (sb-unix:unix-open "/dev/tty" 0 0))) ; O_RDONLY
(when (and tty-fd (numberp tty-fd) (> tty-fd 0)) (when (and tty-fd (numberp tty-fd) (> tty-fd 0))