literate: add with-terminal, suspend-backend, resume-backend to org source
with-terminal macro was only in tangled .lisp (not .org). suspend-backend and resume-backend generics + simple-backend methods + tests were also in hand-edited .lisp only. All three added to org/backend-protocol.org with proper prose, following the literate programming discipline. Also added suspend/resume assertions to simple-backend-lifecycle test suite.
This commit is contained in:
@@ -160,6 +160,8 @@ simple backend.
|
|||||||
(is (typep b 'simple-backend))
|
(is (typep b 'simple-backend))
|
||||||
(initialize-backend b)
|
(initialize-backend b)
|
||||||
(is-false (capable-p b :truecolor) "simple backend has no truecolor")
|
(is-false (capable-p b :truecolor) "simple backend has no truecolor")
|
||||||
|
(is (null (multiple-value-list (suspend-backend b))))
|
||||||
|
(is (null (multiple-value-list (resume-backend b))))
|
||||||
(shutdown-backend b)))
|
(shutdown-backend b)))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
@@ -401,6 +403,7 @@ construction without actually rendering to a terminal.
|
|||||||
#:backend #:simple-backend
|
#:backend #:simple-backend
|
||||||
;; Lifecycle
|
;; Lifecycle
|
||||||
#:initialize-backend #:shutdown-backend
|
#:initialize-backend #:shutdown-backend
|
||||||
|
#:suspend-backend #:resume-backend
|
||||||
#:backend-size #:backend-write #:backend-clear
|
#:backend-size #:backend-write #:backend-clear
|
||||||
;; Drawing
|
;; Drawing
|
||||||
#:draw-text #:draw-border #:draw-rect
|
#:draw-text #:draw-border #:draw-rect
|
||||||
@@ -414,8 +417,9 @@ construction without actually rendering to a terminal.
|
|||||||
;; Queries
|
;; Queries
|
||||||
#:capable-p
|
#:capable-p
|
||||||
;; Constructors
|
;; Constructors
|
||||||
#:make-simple-backend
|
#:make-simple-backend
|
||||||
;; Modern backend
|
#:with-terminal
|
||||||
|
;; Modern backend
|
||||||
#:modern-backend #:make-modern-backend
|
#:modern-backend #:make-modern-backend
|
||||||
;; Detection
|
;; Detection
|
||||||
#:detect-backend #:*detected-backend*
|
#:detect-backend #:*detected-backend*
|
||||||
@@ -664,6 +668,78 @@ keywords include ~:truecolor~, ~:osc8~, ~:sync~, ~:mouse~,
|
|||||||
nil))
|
nil))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
|
*** Suspend and Resume
|
||||||
|
|
||||||
|
Temporary terminal suspension and re-initialization. Used when the
|
||||||
|
application receives SIGTSTP (suspend) or SIGCONT (resume) signals.
|
||||||
|
The default methods are no-ops; backends with terminal state override
|
||||||
|
these to restore cooked mode on suspend and raw mode on resume.
|
||||||
|
|
||||||
|
#+BEGIN_SRC lisp :tangle ../src/backend/classes.lisp
|
||||||
|
(in-package :cl-tty.backend)
|
||||||
|
|
||||||
|
(defgeneric suspend-backend (backend)
|
||||||
|
(:documentation "Temporarily suspend the backend, restoring terminal to normal state.
|
||||||
|
Called before SIGTSTP or similar suspension. Application should redraw after resume.")
|
||||||
|
(:method ((b backend)) (values)))
|
||||||
|
|
||||||
|
(defgeneric resume-backend (backend)
|
||||||
|
(:documentation "Re-initialize the backend after suspension.
|
||||||
|
Called after SIGCONT or similar resume. Re-enables raw mode and backend features.")
|
||||||
|
(:method ((b backend)) (values)))
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
*** With Terminal
|
||||||
|
|
||||||
|
A convenience macro that initializes a terminal backend, executes body,
|
||||||
|
and guarantees cleanup on exit via ~unwind-protect~.
|
||||||
|
|
||||||
|
The macro detects a suitable backend, initializes it, captures the
|
||||||
|
terminal dimensions, binds them to the provided variables, executes the
|
||||||
|
body, and always calls ~shutdown-backend~ when the body exits (whether
|
||||||
|
normally or by a non-local control transfer).
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
- ~backend-var~ — bound to the detected backend instance.
|
||||||
|
- ~cols-var~, ~rows-var~ (optional) — bound to terminal columns and
|
||||||
|
lines captured after initialization.
|
||||||
|
- ~&body body~ — executed with the above bindings.
|
||||||
|
|
||||||
|
#+BEGIN_SRC lisp :tangle ../src/backend/classes.lisp
|
||||||
|
(in-package :cl-tty.backend)
|
||||||
|
|
||||||
|
(defmacro with-terminal ((backend-var &optional cols-var rows-var)
|
||||||
|
&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))
|
||||||
|
,@(when cols-var `((,c-sym (nth-value 0 (backend-size ,be-sym)))))
|
||||||
|
,@(when rows-var `((,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)))))
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
** Simple Backend
|
** Simple Backend
|
||||||
|
|
||||||
~simple-backend~ inherits from ~backend~ and implements every
|
~simple-backend~ inherits from ~backend~ and implements every
|
||||||
@@ -721,6 +797,24 @@ restore. Returns multiple values to satisfy the protocol contract.
|
|||||||
(values))
|
(values))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
|
*** Suspend (simple-backend)
|
||||||
|
|
||||||
|
No-op — simple backend has no terminal state to save.
|
||||||
|
|
||||||
|
#+begin_src lisp :tangle ../src/backend/simple.lisp
|
||||||
|
(defmethod suspend-backend ((b simple-backend))
|
||||||
|
(values))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
*** Resume (simple-backend)
|
||||||
|
|
||||||
|
No-op — simple backend has no terminal state to restore.
|
||||||
|
|
||||||
|
#+begin_src lisp :tangle ../src/backend/simple.lisp
|
||||||
|
(defmethod resume-backend ((b simple-backend))
|
||||||
|
(values))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
*** Backend Size (Simple)
|
*** Backend Size (Simple)
|
||||||
|
|
||||||
Returns hard-coded 80x24 dimensions. A real implementation would use
|
Returns hard-coded 80x24 dimensions. A real implementation would use
|
||||||
|
|||||||
@@ -8,47 +8,6 @@
|
|||||||
(defgeneric shutdown-backend (backend)
|
(defgeneric shutdown-backend (backend)
|
||||||
(:method ((b backend)) (values)))
|
(:method ((b backend)) (values)))
|
||||||
|
|
||||||
(defgeneric suspend-backend (backend)
|
|
||||||
(:documentation "Temporarily suspend the backend, restoring terminal to normal state.
|
|
||||||
Called before SIGTSTP or similar suspension. Application should redraw after resume.")
|
|
||||||
(:method ((b backend)) (values)))
|
|
||||||
|
|
||||||
(defgeneric resume-backend (backend)
|
|
||||||
(:documentation "Re-initialize the backend after suspension.
|
|
||||||
Called after SIGCONT or similar resume. Re-enables raw mode and backend features.")
|
|
||||||
(:method ((b backend)) (values)))
|
|
||||||
|
|
||||||
(defmacro with-terminal ((backend-var &optional cols-var rows-var)
|
|
||||||
&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))
|
|
||||||
,@(when cols-var `((,c-sym (nth-value 0 (backend-size ,be-sym)))))
|
|
||||||
,@(when rows-var `((,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)))
|
||||||
@@ -103,3 +62,48 @@ Example:
|
|||||||
(:method ((b backend) feature)
|
(:method ((b backend) feature)
|
||||||
(declare (ignore feature))
|
(declare (ignore feature))
|
||||||
nil))
|
nil))
|
||||||
|
|
||||||
|
(in-package :cl-tty.backend)
|
||||||
|
|
||||||
|
(defgeneric suspend-backend (backend)
|
||||||
|
(:documentation "Temporarily suspend the backend, restoring terminal to normal state.
|
||||||
|
Called before SIGTSTP or similar suspension. Application should redraw after resume.")
|
||||||
|
(:method ((b backend)) (values)))
|
||||||
|
|
||||||
|
(defgeneric resume-backend (backend)
|
||||||
|
(:documentation "Re-initialize the backend after suspension.
|
||||||
|
Called after SIGCONT or similar resume. Re-enables raw mode and backend features.")
|
||||||
|
(:method ((b backend)) (values)))
|
||||||
|
|
||||||
|
(in-package :cl-tty.backend)
|
||||||
|
|
||||||
|
(defmacro with-terminal ((backend-var &optional cols-var rows-var)
|
||||||
|
&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))
|
||||||
|
,@(when cols-var `((,c-sym (nth-value 0 (backend-size ,be-sym)))))
|
||||||
|
,@(when rows-var `((,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)))))
|
||||||
|
|||||||
@@ -19,9 +19,9 @@
|
|||||||
;; Queries
|
;; Queries
|
||||||
#:capable-p
|
#:capable-p
|
||||||
;; Constructors
|
;; Constructors
|
||||||
#:make-simple-backend
|
#:make-simple-backend
|
||||||
#:with-terminal
|
#:with-terminal
|
||||||
;; Modern backend
|
;; Modern backend
|
||||||
#:modern-backend #:make-modern-backend
|
#:modern-backend #:make-modern-backend
|
||||||
;; Detection
|
;; Detection
|
||||||
#:detect-backend #:*detected-backend*
|
#:detect-backend #:*detected-backend*
|
||||||
|
|||||||
@@ -24,6 +24,8 @@
|
|||||||
(is (typep b 'simple-backend))
|
(is (typep b 'simple-backend))
|
||||||
(initialize-backend b)
|
(initialize-backend b)
|
||||||
(is-false (capable-p b :truecolor) "simple backend has no truecolor")
|
(is-false (capable-p b :truecolor) "simple backend has no truecolor")
|
||||||
|
(is (null (multiple-value-list (suspend-backend b))))
|
||||||
|
(is (null (multiple-value-list (resume-backend b))))
|
||||||
(shutdown-backend b)))
|
(shutdown-backend b)))
|
||||||
|
|
||||||
(test simple-backend-draw-text
|
(test simple-backend-draw-text
|
||||||
@@ -103,8 +105,6 @@
|
|||||||
(is (null (multiple-value-list (cursor-style b :block))))
|
(is (null (multiple-value-list (cursor-style b :block))))
|
||||||
(is (null (multiple-value-list (begin-sync b))))
|
(is (null (multiple-value-list (begin-sync b))))
|
||||||
(is (null (multiple-value-list (end-sync b))))
|
(is (null (multiple-value-list (end-sync b))))
|
||||||
(is (null (multiple-value-list (suspend-backend b))))
|
|
||||||
(is (null (multiple-value-list (resume-backend b))))
|
|
||||||
(shutdown-backend b)))
|
(shutdown-backend b)))
|
||||||
|
|
||||||
(test sync-is-noop-on-simple
|
(test sync-is-noop-on-simple
|
||||||
|
|||||||
Reference in New Issue
Block a user