CRITICAL: case b → cond in %read-event (input.lisp:280)
case with (and ...) predicate clauses treats keys as eql-compared
atoms — all range clauses were dead code. Every Ctrl+letter and
printable ASCII fell through to :unknown. text-input/textarea
widgets were non-functional with real terminal input. No test
coverage of %read-event masked this.
HIGH: Theme resolution wired (backend/modern.lisp, theme.lisp)
sgr-fg/sgr-bg now fall back to *theme-colors* hash for semantic
keywords (:accent, :text-muted, :background-element). *theme-colors*
exported from cl-tty.backend. load-preset populates it from preset
hex values. Previously all themed render output was invisible.
HIGH: SGR mouse parser wired (input.lisp:210-215)
parse-sgr-mouse was defined but never called. Now %read-escape-sequence
detects ESC[< prefix and routes to parse-sgr-mouse. Mouse drags,
releases, and scroll events now parse correctly.
MEDIUM: Rendering stubs replaced
- scrollbox: delegates to (render child backend) with position
offset via unwind-protect (was debug string 'child at ~D')
- text-input: draws value/placeholder at layout position
- textarea: draws visible lines at layout position
MEDIUM: hit-test uses component-layout-node (mouse.lisp:18-31)
Was checking nonexistent x/y/width/height slots. Now reads
layout-node-x/y/w/h via component-layout-node generic.
MEDIUM: test runner exit code (run-all-tests.lisp, cl-tty.asd)
run-all-tests.lisp exits 1 if any suite fails.
asdf:test-system exits 1 on failure.
Renamed :cl-tty-tests to :cl-tty/test (ASDF convention).
MEDIUM: draw-border respects x/y on simple-backend (simple.lisp:42-53)
Was writing to cursor position only. Now uses newlines+spaces
to reach specified coordinates (no escape sequences needed).
LOW: TabBar truncation off-by-one fixed (tabbar.lisp:47)
>= changed to > to avoid cutting tabs 2 chars early.
LOW: Scrollbar coordinates absolute (scrollbox.lisp:61-73)
Scrollbar drawn at viewport-relative (0,0). Now adds layout
node x/y offset for correct terminal positioning.
LOW: backend-write calls finish-output (modern.lisp:169)
LOW: load-preset no longer flips theme-mode (theme.lisp:43-45)
Mode toggle caused load-preset to load wrong variant on
second call.
All backported to org source files (org/text-input.org,
org/scrollbox-tabbar.org) so tangling produces matching .lisp.
392 tests pass, exit code 0.
79 lines
2.8 KiB
Common Lisp
79 lines
2.8 KiB
Common Lisp
(in-package :cl-tty.backend)
|
|
|
|
(defclass simple-backend (backend)
|
|
((output-stream :initform *standard-output*
|
|
:initarg :output-stream
|
|
:accessor backend-output-stream)))
|
|
|
|
(defun make-simple-backend (&key output-stream)
|
|
(make-instance 'simple-backend
|
|
:output-stream (or output-stream *standard-output*)))
|
|
|
|
(defmethod initialize-backend ((b simple-backend))
|
|
b)
|
|
|
|
(defmethod shutdown-backend ((b simple-backend))
|
|
(values))
|
|
|
|
(defmethod backend-size ((b simple-backend))
|
|
;; Try ioctl, fall back to 80x24
|
|
(values 80 24))
|
|
|
|
(defmethod backend-write ((b simple-backend) string)
|
|
(let ((stream (backend-output-stream b)))
|
|
(write-string string stream)
|
|
(finish-output stream)
|
|
(length string)))
|
|
|
|
(defmethod draw-text ((b simple-backend) x y string fg bg
|
|
&key bold italic underline reverse dim blink)
|
|
(declare (ignore x y fg bg bold italic underline reverse dim blink))
|
|
(backend-write b string))
|
|
|
|
(defun %simple-border-char (edge-style pos)
|
|
"Return ASCII border character for EDGE-STYLE at POS.
|
|
POS is :top-left, :top-right, :bottom-left, :bottom-right,
|
|
:horizontal, or :vertical."
|
|
(case pos
|
|
((:top-left :top-right :bottom-left :bottom-right) #\+)
|
|
(:horizontal #\-)
|
|
(:vertical #\|)))
|
|
|
|
(defmethod draw-border ((b simple-backend) x y width height
|
|
&key style fg bg title title-align)
|
|
(declare (ignore style fg bg title title-align))
|
|
(let ((h (%simple-border-char nil :horizontal))
|
|
(v (%simple-border-char nil :vertical)))
|
|
;; Position cursor with newlines and spaces (no escape sequences)
|
|
(dotimes (row y) (backend-write b (string #\Newline)))
|
|
;; Top edge
|
|
(backend-write b (make-string x :initial-element #\space))
|
|
(backend-write b (make-string width :initial-element h))
|
|
;; Sides
|
|
(loop for i from 1 below (1- height)
|
|
do (backend-write b (string #\Newline))
|
|
(backend-write b (make-string x :initial-element #\space))
|
|
(backend-write b (string v))
|
|
(backend-write b (make-string (- width 2) :initial-element #\space))
|
|
(backend-write b (string v)))
|
|
;; Bottom edge
|
|
(backend-write b (string #\Newline))
|
|
(backend-write b (make-string x :initial-element #\space))
|
|
(backend-write b (make-string width :initial-element h))))
|
|
|
|
(defmethod draw-rect ((b simple-backend) x y width height
|
|
&key bg)
|
|
(declare (ignore x y width height bg))
|
|
;; On simple backend, background fill is a no-op
|
|
(values))
|
|
|
|
(defmethod draw-link ((b simple-backend) x y string url
|
|
&key fg bg)
|
|
(declare (ignore url fg bg))
|
|
(draw-text b x y string nil nil))
|
|
|
|
(defmethod draw-ellipsis ((b simple-backend) x y width
|
|
&key fg bg)
|
|
(declare (ignore x y width fg bg))
|
|
(backend-write b "..."))
|