From 4a86ae327406ce763e9c3252cbdf18bdab2f563c Mon Sep 17 00:00:00 2001 From: Amr Gharbeia Date: Thu, 14 May 2026 13:07:05 -0400 Subject: [PATCH] fix: ioctl on stdin fd (0) first, then stdout fd, then env vars MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The user's terminal reports 186x60 via stty (which uses stdin fd) and via COLUMNS/LINES, but ioctl on stdout's fd returns 80x24. Priority: fd 0 → backend output fd → env vars → 80x24 fallback. --- src/backend/modern.lisp | 45 ++++++++++++++++++++++------------------- src/backend/simple.lisp | 42 +++++++++++++++++++------------------- 2 files changed, 45 insertions(+), 42 deletions(-) diff --git a/src/backend/modern.lisp b/src/backend/modern.lisp index e53a2d8..d87bc28 100644 --- a/src/backend/modern.lisp +++ b/src/backend/modern.lisp @@ -164,27 +164,30 @@ as a fallback when a keyword is not in *named-colors*.") (values)) (defmethod backend-size ((b modern-backend)) - (or (ignore-errors - (let* ((+tiocgwinsz+ 21523) ; 0x5413 on Linux - (winsize (sb-alien:make-alien sb-alien:unsigned-short 4))) - (unwind-protect - (progn - (sb-unix:unix-ioctl (sb-sys:fd-stream-fd (backend-output-stream b)) - +tiocgwinsz+ - (sb-alien:alien-sap winsize)) - (values (sb-alien:deref winsize 1) ;; cols - (sb-alien:deref winsize 0))) ;; rows - (sb-alien:free-alien winsize)))) - ;; $COLUMNS/$LINES fallback — some systems don't update the - ;; TTY size via ioctl on stdout's fd. - (ignore-errors - (let* ((cstr (sb-ext:posix-getenv "COLUMNS")) - (rstr (sb-ext:posix-getenv "LINES")) - (cols (when cstr (parse-integer cstr :junk-allowed t))) - (rows (when rstr (parse-integer rstr :junk-allowed t)))) - (when (and cols rows (> cols 0) (> rows 0)) - (values cols rows)))) - (values 80 24))) + (flet ((ioctl-size (fd) + (let* ((+tiocgwinsz+ 21523) ; 0x5413 on Linux + (winsize (sb-alien:make-alien sb-alien:unsigned-short 4))) + (unwind-protect + (progn + (sb-unix:unix-ioctl fd +tiocgwinsz+ + (sb-alien:alien-sap winsize)) + (values (sb-alien:deref winsize 1) ;; cols + (sb-alien:deref winsize 0))) ;; rows + (sb-alien:free-alien winsize))))) + (or ;; Try ioctl on fd 0 first (stdin — stty uses this) + (ignore-errors (ioctl-size 0)) + ;; Then try the output stream's fd + (ignore-errors + (ioctl-size (sb-sys:fd-stream-fd (backend-output-stream b)))) + ;; $COLUMNS/$LINES fallback — set by every POSIX shell + (ignore-errors + (let* ((cstr (sb-ext:posix-getenv "COLUMNS")) + (rstr (sb-ext:posix-getenv "LINES")) + (cols (when cstr (parse-integer cstr :junk-allowed t))) + (rows (when rstr (parse-integer rstr :junk-allowed t)))) + (when (and cols rows (> cols 0) (> rows 0)) + (values cols rows)))) + (values 80 24)))) (defmethod backend-write ((b modern-backend) string) (let ((stream (backend-output-stream b))) diff --git a/src/backend/simple.lisp b/src/backend/simple.lisp index b0fb84a..b01ffce 100644 --- a/src/backend/simple.lisp +++ b/src/backend/simple.lisp @@ -27,27 +27,27 @@ (values)) (defmethod backend-size ((b simple-backend)) - (or (ignore-errors - (let* ((+tiocgwinsz+ 21523) - (winsize (sb-alien:make-alien sb-alien:unsigned-short 4))) - (unwind-protect - (progn - (sb-unix:unix-ioctl (sb-sys:fd-stream-fd - (backend-output-stream b)) - +tiocgwinsz+ - (sb-alien:alien-sap winsize)) - (values (sb-alien:deref winsize 1) - (sb-alien:deref winsize 0))) - (sb-alien:free-alien winsize)))) - ;; $COLUMNS/$LINES fallback - (ignore-errors - (let* ((cstr (sb-ext:posix-getenv "COLUMNS")) - (rstr (sb-ext:posix-getenv "LINES")) - (cols (when cstr (parse-integer cstr :junk-allowed t))) - (rows (when rstr (parse-integer rstr :junk-allowed t)))) - (when (and cols rows (> cols 0) (> rows 0)) - (values cols rows)))) - (values 80 24))) + (flet ((ioctl-size (fd) + (let* ((+tiocgwinsz+ 21523) + (winsize (sb-alien:make-alien sb-alien:unsigned-short 4))) + (unwind-protect + (progn + (sb-unix:unix-ioctl fd +tiocgwinsz+ + (sb-alien:alien-sap winsize)) + (values (sb-alien:deref winsize 1) + (sb-alien:deref winsize 0))) + (sb-alien:free-alien winsize))))) + (or (ignore-errors (ioctl-size 0)) + (ignore-errors + (ioctl-size (sb-sys:fd-stream-fd (backend-output-stream b)))) + (ignore-errors + (let* ((cstr (sb-ext:posix-getenv "COLUMNS")) + (rstr (sb-ext:posix-getenv "LINES")) + (cols (when cstr (parse-integer cstr :junk-allowed t))) + (rows (when rstr (parse-integer rstr :junk-allowed t)))) + (when (and cols rows (> cols 0) (> rows 0)) + (values cols rows)))) + (values 80 24)))) (defmethod backend-write ((b simple-backend) string) (let ((stream (backend-output-stream b)))