v1.0.0: TUI support — resize events, with-terminal macro
- read-event now checks *terminal-resized-p* and returns :resize on SIGWINCH - Added with-terminal convenience macro (detect → init → body → shutdown) - Exported *terminal-resized-p* from cl-tty.input package - Exported with-terminal from cl-tty.backend package - Updated text-input.org with resize event integration and refactored tests - Tests: 461 checks, 100% pass (93 input suite, +2 new test cases)
This commit is contained in:
@@ -196,6 +196,7 @@ via ~sb-posix~ directly.
|
|||||||
#:with-raw-terminal
|
#:with-raw-terminal
|
||||||
;; Event reading
|
;; Event reading
|
||||||
#:read-event
|
#:read-event
|
||||||
|
#:*terminal-resized-p*
|
||||||
;; UTF-8 input support
|
;; UTF-8 input support
|
||||||
#:utf8-decode
|
#:utf8-decode
|
||||||
;; TextInput
|
;; TextInput
|
||||||
@@ -704,6 +705,12 @@ All the complexity lives in ~%read-event~ and its callees.
|
|||||||
#+BEGIN_SRC lisp :tangle ../src/components/input.lisp
|
#+BEGIN_SRC lisp :tangle ../src/components/input.lisp
|
||||||
(defmethod read-event ((b cl-tty.backend:backend) &key timeout)
|
(defmethod read-event ((b cl-tty.backend:backend) &key timeout)
|
||||||
(declare (ignore b))
|
(declare (ignore b))
|
||||||
|
;; Check for pending terminal resize before reading input.
|
||||||
|
;; The SIGWINCH handler sets *terminal-resized-p* asynchronously.
|
||||||
|
(when *terminal-resized-p*
|
||||||
|
(setf *terminal-resized-p* nil)
|
||||||
|
(multiple-value-bind (w h) (backend-size b)
|
||||||
|
(return-from read-event (values :resize (cons w h)))))
|
||||||
(when (probe-file "/dev/stdin")
|
(when (probe-file "/dev/stdin")
|
||||||
(%read-event :timeout timeout)))
|
(%read-event :timeout timeout)))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
@@ -2062,4 +2069,22 @@ The test suite is tangled to ~../tests/input-tests.lisp~ and covers:
|
|||||||
(remhash :local *keymaps*)
|
(remhash :local *keymaps*)
|
||||||
(is-false (gethash :global *keymaps*))
|
(is-false (gethash :global *keymaps*))
|
||||||
(is-false (gethash :local *keymaps*)))
|
(is-false (gethash :local *keymaps*)))
|
||||||
|
|
||||||
|
(test resize-event-check
|
||||||
|
"read-event returns :resize when *terminal-resized-p* is set"
|
||||||
|
(let ((b (make-instance 'cl-tty.backend:backend)))
|
||||||
|
(setf cl-tty.input:*terminal-resized-p* t)
|
||||||
|
(multiple-value-bind (type data) (cl-tty.input:read-event b :timeout 0)
|
||||||
|
(is (eq :resize type))
|
||||||
|
(is (consp data))
|
||||||
|
(is (integerp (car data)))
|
||||||
|
(is (integerp (cdr data))))
|
||||||
|
(is-false cl-tty.input:*terminal-resized-p*)))
|
||||||
|
|
||||||
|
(test with-terminal-macro-expands
|
||||||
|
"with-terminal macro expands and compiles"
|
||||||
|
(is (macro-function 'cl-tty.backend:with-terminal))
|
||||||
|
(let ((expanded (macroexpand-1 '(cl-tty.backend:with-terminal (be)
|
||||||
|
(print be)))))
|
||||||
|
(is (listp expanded))))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|||||||
@@ -18,6 +18,37 @@ Called before SIGTSTP or similar suspension. Application should redraw after res
|
|||||||
Called after SIGCONT or similar resume. Re-enables raw mode and backend features.")
|
Called after SIGCONT or similar resume. Re-enables raw mode and backend features.")
|
||||||
(:method ((b backend)) (values)))
|
(:method ((b backend)) (values)))
|
||||||
|
|
||||||
|
(defmacro with-terminal ((backend-var &optional (cols-var (gensym)) (rows-var (gensym)))
|
||||||
|
&body body)
|
||||||
|
"Execute BODY with a fully initialized terminal backend.
|
||||||
|
|
||||||
|
DETECT-BACKEND, INITIALIZE-BACKEND, and SHUTDOWN-BACKEND are called
|
||||||
|
automatically. The backend instance is bound to BACKEND-VAR. If
|
||||||
|
COLS-VAR and ROWS-VAR are provided, they are bound to the terminal
|
||||||
|
dimensions at startup.
|
||||||
|
|
||||||
|
The caller should wrap this in SB-POSIX:WITH-RAW-TERMINAL (or
|
||||||
|
equivalent) if raw-mode input handling is needed.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
(with-terminal (be cols rows)
|
||||||
|
(loop for ev = (read-event be :timeout 0.1)
|
||||||
|
while ev
|
||||||
|
do (format t \"~A~%\" ev))))"
|
||||||
|
(let ((be-sym (gensym "BE"))
|
||||||
|
(c-sym (gensym "COLS"))
|
||||||
|
(r-sym (gensym "ROWS")))
|
||||||
|
`(let* ((,be-sym (detect-backend))
|
||||||
|
(,c-sym (nth-value 0 (backend-size ,be-sym)))
|
||||||
|
(,r-sym (nth-value 1 (backend-size ,be-sym))))
|
||||||
|
(initialize-backend ,be-sym)
|
||||||
|
(unwind-protect
|
||||||
|
(let ((,backend-var ,be-sym)
|
||||||
|
,@(when cols-var `((,cols-var ,c-sym)))
|
||||||
|
,@(when rows-var `((,rows-var ,r-sym))))
|
||||||
|
,@body)
|
||||||
|
(shutdown-backend ,be-sym)))))
|
||||||
|
|
||||||
(defgeneric backend-size (backend)
|
(defgeneric backend-size (backend)
|
||||||
(:method ((b backend))
|
(:method ((b backend))
|
||||||
(values 80 24)))
|
(values 80 24)))
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#:capable-p
|
#:capable-p
|
||||||
;; Constructors
|
;; Constructors
|
||||||
#:make-simple-backend
|
#:make-simple-backend
|
||||||
|
#:with-terminal
|
||||||
;; Modern backend
|
;; Modern backend
|
||||||
#:modern-backend #:make-modern-backend
|
#:modern-backend #:make-modern-backend
|
||||||
;; Detection
|
;; Detection
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#:with-raw-terminal
|
#:with-raw-terminal
|
||||||
;; Event reading
|
;; Event reading
|
||||||
#:read-event
|
#:read-event
|
||||||
|
#:*terminal-resized-p*
|
||||||
;; UTF-8 input support
|
;; UTF-8 input support
|
||||||
#:utf8-decode
|
#:utf8-decode
|
||||||
;; TextInput
|
;; TextInput
|
||||||
|
|||||||
@@ -187,5 +187,11 @@
|
|||||||
|
|
||||||
(defmethod read-event ((b cl-tty.backend:backend) &key timeout)
|
(defmethod read-event ((b cl-tty.backend:backend) &key timeout)
|
||||||
(declare (ignore b))
|
(declare (ignore b))
|
||||||
|
;; Check for pending terminal resize before reading input.
|
||||||
|
;; The SIGWINCH handler sets *terminal-resized-p* asynchronously.
|
||||||
|
(when *terminal-resized-p*
|
||||||
|
(setf *terminal-resized-p* nil)
|
||||||
|
(multiple-value-bind (w h) (backend-size b)
|
||||||
|
(return-from read-event (values :resize (cons w h)))))
|
||||||
(when (probe-file "/dev/stdin")
|
(when (probe-file "/dev/stdin")
|
||||||
(%read-event :timeout timeout)))
|
(%read-event :timeout timeout)))
|
||||||
|
|||||||
@@ -389,3 +389,21 @@
|
|||||||
(remhash :local *keymaps*)
|
(remhash :local *keymaps*)
|
||||||
(is-false (gethash :global *keymaps*))
|
(is-false (gethash :global *keymaps*))
|
||||||
(is-false (gethash :local *keymaps*)))
|
(is-false (gethash :local *keymaps*)))
|
||||||
|
|
||||||
|
(test resize-event-check
|
||||||
|
"read-event returns :resize when *terminal-resized-p* is set"
|
||||||
|
(let ((b (make-instance 'cl-tty.backend:backend)))
|
||||||
|
(setf cl-tty.input:*terminal-resized-p* t)
|
||||||
|
(multiple-value-bind (type data) (cl-tty.input:read-event b :timeout 0)
|
||||||
|
(is (eq :resize type))
|
||||||
|
(is (consp data))
|
||||||
|
(is (integerp (car data)))
|
||||||
|
(is (integerp (cdr data))))
|
||||||
|
(is-false cl-tty.input:*terminal-resized-p*)))
|
||||||
|
|
||||||
|
(test with-terminal-macro-expands
|
||||||
|
"with-terminal macro expands and compiles"
|
||||||
|
(is (macro-function 'cl-tty.backend:with-terminal))
|
||||||
|
(let ((expanded (macroexpand-1 '(cl-tty.backend:with-terminal (be)
|
||||||
|
(print be)))))
|
||||||
|
(is (listp expanded))))
|
||||||
|
|||||||
Reference in New Issue
Block a user