From 11a70956a043127d48e52e3f2017140ee6d3433f Mon Sep 17 00:00:00 2001 From: Amr Gharbeia Date: Thu, 14 May 2026 14:48:54 -0400 Subject: [PATCH] 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. --- src/backend/modern.lisp | 24 ++++++++++++------------ src/backend/simple.lisp | 22 +++++++++++----------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/backend/modern.lisp b/src/backend/modern.lisp index 8766227..4362763 100644 --- a/src/backend/modern.lisp +++ b/src/backend/modern.lisp @@ -162,20 +162,20 @@ as a fallback when a keyword is not in *named-colors*.") (values)) (defmethod backend-size ((b modern-backend)) - (or ;; stty size with :input :interactive — opens /dev/tty for the - ;; child's stdin so stty can query the terminal via ioctl. + (or ;; ioctl on fd 0 (stdin) — the parent's own terminal, which IS + ;; the real controlling terminal when running from a shell. (multiple-value-bind (cols rows) (ignore-errors - (let* ((out (uiop:run-program '("stty" "size") :output :string - :input :interactive - :ignore-error-status t)) - (parts (and out (uiop:split-string - (string-trim '(#\newline #\space) out))))) - (when (and parts (= (length parts) 2)) - (let ((r (parse-integer (first parts) :junk-allowed t)) - (c (parse-integer (second parts) :junk-allowed t))) - (when (and r c (> r 0) (> c 0)) - (values c r)))))) + (let ((winsize (sb-alien:make-alien sb-alien:unsigned-short 4))) + (unwind-protect + (let ((ok (sb-unix:unix-ioctl 0 21523 + (sb-alien:alien-sap winsize)))) + (when ok + (let ((c (sb-alien:deref winsize 1)) + (r (sb-alien:deref winsize 0))) + (when (and c r (> c 0) (> r 0)) + (values c r))))) + (sb-alien:free-alien winsize)))) (when (and cols rows (> cols 0) (> rows 0)) (values cols rows))) ;; ioctl on stdout fd — fast, correct after SIGWINCH at runtime. diff --git a/src/backend/simple.lisp b/src/backend/simple.lisp index 33529a3..2fbfdb3 100644 --- a/src/backend/simple.lisp +++ b/src/backend/simple.lisp @@ -22,19 +22,19 @@ (values)) (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) (ignore-errors - (let* ((out (uiop:run-program '("stty" "size") :output :string - :input :interactive - :ignore-error-status t)) - (parts (and out (uiop:split-string - (string-trim '(#\newline #\space) out))))) - (when (and parts (= (length parts) 2)) - (let ((r (parse-integer (first parts) :junk-allowed t)) - (c (parse-integer (second parts) :junk-allowed t))) - (when (and r c (> r 0) (> c 0)) - (values c r)))))) + (let ((winsize (sb-alien:make-alien sb-alien:unsigned-short 4))) + (unwind-protect + (let ((ok (sb-unix:unix-ioctl 0 21523 + (sb-alien:alien-sap winsize)))) + (when ok + (let ((c (sb-alien:deref winsize 1)) + (r (sb-alien:deref winsize 0))) + (when (and c r (> c 0) (> r 0)) + (values c r))))) + (sb-alien:free-alien winsize)))) (when (and cols rows (> cols 0) (> rows 0)) (values cols rows))) ;; ioctl on stdout fd — fast, correct after SIGWINCH at runtime.