Replace sb-posix:termios raw mode with stty-based approach
set-raw-mode now uses (stty raw -echo ...) via sb-ext:run-program instead of sb-posix:tcgetattr/tcsetattr + termios flag manipulation. The sb-posix termios API changed between SBCL versions (termios-cc accessor went from 2-arg to 1-arg), and tcgetattr fails in some container/PTY environments. Stty is available on every Unix and is independent of SBCL's sb-posix version. set-raw-mode errors if stty -g returns empty (no real terminal attached). restore-terminal-state is a no-op when called with nil.
This commit is contained in:
@@ -42,39 +42,27 @@
|
||||
(raw nil :type (or string null)))
|
||||
|
||||
;;; ---------------------------------------------------------------------------
|
||||
;;; Terminal raw mode
|
||||
;;; Terminal raw mode (stty-based — portable across Unices)
|
||||
;;; ---------------------------------------------------------------------------
|
||||
(defun save-terminal-state ()
|
||||
(sb-posix:tcgetattr 0))
|
||||
|
||||
(defun make-raw-termios (termios)
|
||||
(flet ((clear-flag (flags mask)
|
||||
(logand flags (lognot mask))))
|
||||
(setf (sb-posix:termios-iflag termios)
|
||||
(clear-flag (sb-posix:termios-iflag termios)
|
||||
(logior sb-posix:brkint sb-posix:ignpar
|
||||
sb-posix:istrip sb-posix:inlcr
|
||||
sb-posix:igncr sb-posix:icrnl
|
||||
sb-posix:ixon)))
|
||||
(setf (sb-posix:termios-oflag termios)
|
||||
(clear-flag (sb-posix:termios-oflag termios)
|
||||
sb-posix:opost))
|
||||
(setf (sb-posix:termios-lflag termios)
|
||||
(clear-flag (sb-posix:termios-lflag termios)
|
||||
(logior sb-posix:icanon sb-posix:echo
|
||||
sb-posix:isig sb-posix:iexten)))
|
||||
(let ((cc-array (sb-posix:termios-cc termios)))
|
||||
(setf (aref cc-array sb-posix:vmin) 1)
|
||||
(setf (aref cc-array sb-posix:vtime) 0))
|
||||
termios))
|
||||
"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))))
|
||||
|
||||
(defun set-raw-mode ()
|
||||
(let ((raw (make-raw-termios (save-terminal-state))))
|
||||
(sb-posix:tcsetattr 0 sb-posix:tcsanow raw)
|
||||
raw))
|
||||
"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)
|
||||
saved))
|
||||
|
||||
(defun restore-terminal-state (termios)
|
||||
(sb-posix:tcsetattr 0 sb-posix:tcsanow termios))
|
||||
(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)))
|
||||
|
||||
(defmacro with-raw-terminal (&body body)
|
||||
(let ((saved (gensym "SAVED")))
|
||||
|
||||
Reference in New Issue
Block a user