diff --git a/src/backend/modern.lisp b/src/backend/modern.lisp index 20d8a3c..84697ff 100644 --- a/src/backend/modern.lisp +++ b/src/backend/modern.lisp @@ -173,39 +173,32 @@ 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)))) - ;; $COLUMNS/$LINES fallback — some systems return 80x24 from - ;; ioctl on stdout's fd even when the terminal is larger. + ;; stty size — reliable across all shells and terminals. + ;; SBCL strips COLUMNS/LINES from the environment, so env var + ;; fallbacks won't work for those names. (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)))) - ;; If env vars are missing, use stty size (rows cols) - (unless (and cols rows) - (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 ((stty-rows (parse-integer (first parts) :junk-allowed t)) - (stty-cols (parse-integer (second parts) :junk-allowed t))) - (when (and stty-rows stty-cols (> stty-rows 0) (> stty-cols 0)) - (unless cols (setf cols stty-cols)) - (unless rows (setf rows stty-rows))))))) - ;; If still missing, try tput as final shell fallback - (unless (and cols rows) - (let ((out (uiop:run-program '("sh" "-c" "tput cols 2>/dev/null; tput lines 2>/dev/null") - :output :string - :ignore-error-status t))) - (when out - (let* ((parts (uiop:split-string (string-trim '(#\newline #\space) out))) - (a (when parts (parse-integer (first parts) :junk-allowed t))) - (b (when (cdr parts) (parse-integer (second parts) :junk-allowed t)))) - (when a (setf cols a)) - (when b (setf rows b)))))) - (when (and cols rows (> cols 0) (> rows 0)) - (values cols rows)))) + (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)))))) + ;; tput — final shell fallback for esoteric terminals + (ignore-errors + (let* ((out (uiop:run-program '("sh" "-c" "tput cols 2>/dev/null; tput lines 2>/dev/null") + :output :string + :ignore-error-status t)) + (parts (and out (uiop:split-string + (string-trim '(#\newline #\space) out))))) + (when (and parts (= (length parts) 2)) + (let ((cols (parse-integer (first parts) :junk-allowed t)) + (rows (parse-integer (second parts) :junk-allowed t))) + (when (and rows cols (> rows 0) (> cols 0)) + (values cols rows)))))) (values 80 24))) (defmethod backend-write ((b modern-backend) string) diff --git a/src/backend/simple.lisp b/src/backend/simple.lisp index 67738d0..ea1f7de 100644 --- a/src/backend/simple.lisp +++ b/src/backend/simple.lisp @@ -34,35 +34,30 @@ (values (sb-alien:deref winsize 1) (sb-alien:deref winsize 0))) (sb-alien:free-alien winsize)))) + ;; stty size — reliable across all shells and terminals. (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)))) - (unless (and cols rows) - (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 ((stty-rows (parse-integer (first parts) :junk-allowed t)) - (stty-cols (parse-integer (second parts) :junk-allowed t))) - (when (and stty-rows stty-cols (> stty-rows 0) (> stty-cols 0)) - (unless cols (setf cols stty-cols)) - (unless rows (setf rows stty-rows))))))) - (unless (and cols rows) - (let ((out (uiop:run-program '("sh" "-c" "tput cols 2>/dev/null; tput lines 2>/dev/null") - :output :string - :ignore-error-status t))) - (when out - (let* ((parts (uiop:split-string (string-trim '(#\newline #\space) out))) - (a (when parts (parse-integer (first parts) :junk-allowed t))) - (b (when (cdr parts) (parse-integer (second parts) :junk-allowed t)))) - (when a (setf cols a)) - (when b (setf rows b)))))) - (when (and cols rows (> cols 0) (> rows 0)) - (values cols rows)))) + (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)))))) + ;; tput — final shell fallback + (ignore-errors + (let* ((out (uiop:run-program '("sh" "-c" "tput cols 2>/dev/null; tput lines 2>/dev/null") + :output :string + :ignore-error-status t)) + (parts (and out (uiop:split-string + (string-trim '(#\newline #\space) out))))) + (when (and parts (= (length parts) 2)) + (let ((cols (parse-integer (first parts) :junk-allowed t)) + (rows (parse-integer (second parts) :junk-allowed t))) + (when (and rows cols (> rows 0) (> cols 0)) + (values cols rows)))))) (values 80 24))) (defmethod backend-write ((b simple-backend) string)