fix: replace stty size with tput cols/lines in backend-size

stty size returns incomplete data when run through uiop:run-program
(the child may not have terminal access). tput is a terminfo utility
that outputs a single number per call, avoiding parsing issues.
Works reliably in any subprocess context.
This commit is contained in:
2026-05-14 14:40:11 -04:00
parent 733ba7c1b8
commit 21c7b1c2d9
2 changed files with 26 additions and 32 deletions

View File

@@ -162,25 +162,21 @@ as a fallback when a keyword is not in *named-colors*.")
(values))
(defmethod backend-size ((b modern-backend))
(or ;; stty size via subprocess — most reliable across all systems.
;; Returns "ROWS COLS". stty size queries the terminal via ioctl,
;; not stdin, so no :input redirection is needed.
(or ;; tput lines / tput cols via subprocess — most reliable across
;; all systems. Each outputs a single number. Works in any
;; subprocess context, no parsing complexity.
(multiple-value-bind (cols rows)
(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 parts
(let ((a (parse-integer (first parts) :junk-allowed t))
(b (when (cdr parts) (parse-integer (second parts) :junk-allowed t))))
(if (and a b (> a 0) (> b 0))
;; stty returns "ROWS COLS"
(values b a)
;; stty returned only one value — treat as cols
(when (and a (> a 0))
(values a nil)))))))
(values
(ignore-errors
(parse-integer
(string-trim '(#\newline #\space)
(uiop:run-program '("tput" "cols") :output :string
:ignore-error-status t))))
(ignore-errors
(parse-integer
(string-trim '(#\newline #\space)
(uiop:run-program '("tput" "lines") :output :string
:ignore-error-status t)))))
(when (and cols rows (> cols 0) (> rows 0))
(values cols rows)))
;; ioctl on stdout fd — fast, correct after SIGWINCH at runtime.