fix: use ioctl on fd 0 (stdin) as primary sizing method

The parent's fd 0 IS the real terminal when running from a shell.
This directly queries the terminal size without subprocess or
alien complexity. Added proper when guard on the unix-ioctl result.
This commit is contained in:
2026-05-14 14:48:54 -04:00
parent 9a54b7ade6
commit 11a70956a0
2 changed files with 23 additions and 23 deletions

View File

@@ -162,20 +162,20 @@ 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 ;; stty size with :input :interactive — opens /dev/tty for the (or ;; ioctl on fd 0 (stdin) — the parent's own terminal, which IS
;; child's stdin so stty can query the terminal via ioctl. ;; the real controlling terminal when running from a shell.
(multiple-value-bind (cols rows) (multiple-value-bind (cols rows)
(ignore-errors (ignore-errors
(let* ((out (uiop:run-program '("stty" "size") :output :string (let ((winsize (sb-alien:make-alien sb-alien:unsigned-short 4)))
:input :interactive (unwind-protect
:ignore-error-status t)) (let ((ok (sb-unix:unix-ioctl 0 21523
(parts (and out (uiop:split-string (sb-alien:alien-sap winsize))))
(string-trim '(#\newline #\space) out))))) (when ok
(when (and parts (= (length parts) 2)) (let ((c (sb-alien:deref winsize 1))
(let ((r (parse-integer (first parts) :junk-allowed t)) (r (sb-alien:deref winsize 0)))
(c (parse-integer (second parts) :junk-allowed t))) (when (and c r (> c 0) (> r 0))
(when (and r c (> r 0) (> c 0)) (values c r)))))
(values c r)))))) (sb-alien:free-alien winsize))))
(when (and cols rows (> cols 0) (> rows 0)) (when (and cols rows (> cols 0) (> rows 0))
(values cols rows))) (values cols rows)))
;; ioctl on stdout fd — fast, correct after SIGWINCH at runtime. ;; ioctl on stdout fd — fast, correct after SIGWINCH at runtime.

View File

@@ -22,19 +22,19 @@
(values)) (values))
(defmethod backend-size ((b simple-backend)) (defmethod backend-size ((b simple-backend))
(or ;; stty size with :input :interactive — opens /dev/tty. (or ;; ioctl on fd 0 (stdin) — the parent's own terminal.
(multiple-value-bind (cols rows) (multiple-value-bind (cols rows)
(ignore-errors (ignore-errors
(let* ((out (uiop:run-program '("stty" "size") :output :string (let ((winsize (sb-alien:make-alien sb-alien:unsigned-short 4)))
:input :interactive (unwind-protect
:ignore-error-status t)) (let ((ok (sb-unix:unix-ioctl 0 21523
(parts (and out (uiop:split-string (sb-alien:alien-sap winsize))))
(string-trim '(#\newline #\space) out))))) (when ok
(when (and parts (= (length parts) 2)) (let ((c (sb-alien:deref winsize 1))
(let ((r (parse-integer (first parts) :junk-allowed t)) (r (sb-alien:deref winsize 0)))
(c (parse-integer (second parts) :junk-allowed t))) (when (and c r (> c 0) (> r 0))
(when (and r c (> r 0) (> c 0)) (values c r)))))
(values c r)))))) (sb-alien:free-alien winsize))))
(when (and cols rows (> cols 0) (> rows 0)) (when (and cols rows (> cols 0) (> rows 0))
(values cols rows))) (values cols rows)))
;; ioctl on stdout fd — fast, correct after SIGWINCH at runtime. ;; ioctl on stdout fd — fast, correct after SIGWINCH at runtime.