From 4df3048a13c6e8a14eed687a779916852d3f54a3 Mon Sep 17 00:00:00 2001 From: Amr Gharbeia Date: Thu, 14 May 2026 14:15:30 -0400 Subject: [PATCH] fix: add stty size subprocess fallback in both backends MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- src/backend/modern.lisp | 13 +++++++++++++ src/backend/simple.lisp | 14 +++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/backend/modern.lisp b/src/backend/modern.lisp index 348581b..17254a7 100644 --- a/src/backend/modern.lisp +++ b/src/backend/modern.lisp @@ -173,6 +173,19 @@ as a fallback when a keyword is not in *named-colors*.") (values (sb-alien:deref winsize 1) ;; cols (sb-alien:deref winsize 0))) ;; rows (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. (ignore-errors (let ((tty-fd (sb-unix:unix-open "/dev/tty" 0 0))) ; O_RDONLY diff --git a/src/backend/simple.lisp b/src/backend/simple.lisp index 0e6dcd0..9b1f479 100644 --- a/src/backend/simple.lisp +++ b/src/backend/simple.lisp @@ -33,7 +33,19 @@ (sb-alien:alien-sap winsize)) (values (sb-alien:deref winsize 1) (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 (let ((tty-fd (sb-unix:unix-open "/dev/tty" 0 0))) ; O_RDONLY (when (and tty-fd (numberp tty-fd) (> tty-fd 0))