v0.15.0: Critical input/rendering fixes, subagent-reviewed #7

Merged
amr merged 36 commits from feature/v0.11.0-slots into main 2026-05-11 22:03:18 -04:00
Showing only changes of commit 0ed7427802 - Show all commits

View File

@@ -42,27 +42,31 @@
(raw nil :type (or string null)))
;;; ---------------------------------------------------------------------------
;;; Terminal raw mode (stty-based — portable across Unices)
;;; Terminal raw mode (stty on /dev/tty — portable across Unices)
;;; ---------------------------------------------------------------------------
(defun stty-run (args)
"Run stty with ARGS on the controlling terminal. Returns stdout as string."
(with-output-to-string (s)
(sb-ext:run-program "stty" (append '("-F" "/dev/tty") args)
:output s :input :stdin :wait t)))
(defun save-terminal-state ()
"Save current terminal settings via stty -g. Returns a string."
(string-trim '(#\Newline #\Space)
(with-output-to-string (s)
(sb-ext:run-program "stty" '("-g") :output s :wait t))))
(let ((s (string-trim '(#\Newline #\Space) (stty-run '("-g")))))
(when (zerop (length s))
(error "stty -g failed — not running in a real terminal"))
s))
(defun set-raw-mode ()
"Put terminal in raw mode via stty. Returns the saved state string."
(let ((saved (save-terminal-state)))
(when (zerop (length saved))
(error "stty -g failed: stdout is not a terminal"))
(sb-ext:run-program "stty" '("raw" "-echo" "isig" "icanon" "min" "1" "time" "0")
:wait t :input :stdin :output t)
(stty-run '("raw" "-echo" "-isig" "-icanon" "min" "1" "time" "0"))
saved))
(defun restore-terminal-state (saved)
"Restore saved terminal state (a string from stty -g, or nil)."
(when saved
(sb-ext:run-program "stty" (list saved) :wait t :input :stdin :output t)))
(when (and saved (plusp (length saved)))
(stty-run (list saved))))
(defmacro with-raw-terminal (&body body)
(let ((saved (gensym "SAVED")))