The %query-terminal-size function sent \033[18t and tried to read the response via read-char-no-hang on fd 0, which always returns nil in this SBCL environment. The response leaked into user input, displaying garbled CSI sequences. Rely on ioctl only.
110 lines
3.4 KiB
Common Lisp
110 lines
3.4 KiB
Common Lisp
(in-package :cl-tty.backend)
|
|
|
|
(defclass backend () ())
|
|
|
|
(defgeneric initialize-backend (backend)
|
|
(:method ((b backend)) b))
|
|
|
|
(defgeneric shutdown-backend (backend)
|
|
(:method ((b backend)) (values)))
|
|
|
|
(defgeneric backend-size (backend)
|
|
(:method ((b backend))
|
|
(values 80 24)))
|
|
|
|
(defgeneric backend-write (backend string))
|
|
|
|
(defgeneric backend-clear (backend)
|
|
(:method ((b backend))
|
|
(backend-write b (format nil "~C[2J~C[H" #\Esc #\Esc))))
|
|
|
|
(defgeneric draw-text (backend x y string fg bg &key
|
|
bold italic underline reverse dim blink
|
|
&allow-other-keys))
|
|
|
|
(defgeneric draw-border (backend x y width height
|
|
&key style fg bg title title-align))
|
|
|
|
(defgeneric draw-rect (backend x y width height &key bg))
|
|
|
|
(defgeneric draw-link (backend x y string url &key fg bg))
|
|
|
|
(defgeneric draw-ellipsis (backend x y width &key fg bg))
|
|
|
|
(defgeneric cursor-move (backend x y)
|
|
(:method ((b backend) x y) (declare (ignore x y)) (values)))
|
|
|
|
(defgeneric cursor-hide (backend)
|
|
(:method ((b backend)) (values)))
|
|
|
|
(defgeneric cursor-show (backend)
|
|
(:method ((b backend)) (values)))
|
|
|
|
(defgeneric cursor-style (backend shape &key blink)
|
|
(:method ((b backend) shape &key blink) (values)))
|
|
|
|
(defgeneric begin-sync (backend)
|
|
(:method ((b backend)) (values)))
|
|
|
|
(defgeneric end-sync (backend)
|
|
(:method ((b backend)) (values)))
|
|
|
|
(defgeneric read-event (backend &key timeout)
|
|
(:method ((b backend) &key timeout) (values nil nil)))
|
|
|
|
(defgeneric enable-mouse (backend)
|
|
(:method ((b backend)) (values)))
|
|
|
|
(defgeneric enable-bracketed-paste (backend)
|
|
(:method ((b backend)) (values)))
|
|
|
|
(defgeneric capable-p (backend feature)
|
|
(:method ((b backend) feature)
|
|
(declare (ignore feature))
|
|
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)))))
|