fix: initial render before loop, restore read-event timeout=0

- Added initial render (backend-clear + view-all) before main loop
  so startup messages appear immediately
- Restored read-event with :timeout 0 from git HEAD
- Removed dispatch-key-event from main loop (simplified to direct on-key)
- Removed :enter from :local keymap (handled directly in on-key)
- Retained direct-to-backend rendering (no framebuffer)
- Retained msgs count in status bar for debugging
- 237/237 tests pass
This commit is contained in:
2026-05-13 20:09:40 -04:00
parent 35fbf1d418
commit 7d3dc479eb
2 changed files with 96 additions and 122 deletions

View File

@@ -839,7 +839,6 @@
;; v0.8.0 — Prompt/local keymap (for when input is active) ;; v0.8.0 — Prompt/local keymap (for when input is active)
(eval-when (:load-toplevel :execute) (eval-when (:load-toplevel :execute)
(cl-tty.input:defkeymap :local (cl-tty.input:defkeymap :local
(:enter (lambda (e) (declare (ignore e)) (on-key :enter)))
(:up (lambda (e) (declare (ignore e)) (on-key :up))) (:up (lambda (e) (declare (ignore e)) (on-key :up)))
(:down (lambda (e) (declare (ignore e)) (on-key :down))) (:down (lambda (e) (declare (ignore e)) (on-key :down)))
(:escape (lambda (e) (declare (ignore e)) (on-key :escape))))) (:escape (lambda (e) (declare (ignore e)) (on-key :escape)))))
@@ -865,14 +864,15 @@
(add-msg :system "* Swank unavailable *")))) (add-msg :system "* Swank unavailable *"))))
(cl-tty.input:with-raw-terminal (cl-tty.input:with-raw-terminal
(cl-tty.backend:with-terminal (be w h) (cl-tty.backend:with-terminal (be w h)
(let ((prev-fb (cl-tty.rendering:make-framebuffer w h)) ;; Initial render
(curr-fb (cl-tty.rendering:make-framebuffer w h))) (cl-tty.backend:backend-clear be)
;; Initial render (view-status be w h)
(redraw curr-fb w h) (view-chat be w h)
(cl-tty.rendering:flush-framebuffer prev-fb curr-fb be) (view-input be w h)
(rotatef prev-fb curr-fb) (cl-tty.backend:draw-text be 0 (- h 4) (make-string w :initial-element #\─)
(loop while (st :running) do (theme-color :separator) nil)
(dolist (ev (drain-queue)) (loop while (st :running) do
(dolist (ev (drain-queue))
(cond (cond
((eq (getf ev :type) :daemon) ((eq (getf ev :type) :daemon)
(on-daemon-msg (getf ev :payload))) (on-daemon-msg (getf ev :payload)))
@@ -885,43 +885,43 @@
(cond (cond
((eq type :resize) ((eq type :resize)
(multiple-value-setq (w h) (cl-tty.backend:backend-size be)) (multiple-value-setq (w h) (cl-tty.backend:backend-size be))
(setf prev-fb (cl-tty.rendering:make-framebuffer w h)
curr-fb (cl-tty.rendering:make-framebuffer w h))
(setf (st :dirty) (list t t t))) (setf (st :dirty) (list t t t)))
(data (data
(let ((ch (typecase data (let ((ch (typecase data
(cl-tty.input:key-event (cl-tty.input:key-event
(cl-tty.input:key-event-key data)) (cl-tty.input:key-event-key data))
(t data)))) (t data))))
(cond (cond
((st :dialog-stack) ((st :dialog-stack)
(let* ((dlg (car (st :dialog-stack))) (let* ((dlg (car (st :dialog-stack)))
(sel (cl-tty.dialog:dialog-content dlg))) (sel (cl-tty.dialog:dialog-content dlg)))
(cond (cond
((eql ch :escape) ((eql ch :escape)
(pop (st :dialog-stack)) (pop (st :dialog-stack))
(setf (st :minibuffer-active) nil) (setf (st :minibuffer-active) nil)
(setf (st :command-palette-active) nil) (setf (st :command-palette-active) nil)
(setf (st :dirty) (list t t nil))) (setf (st :dirty) (list t t nil)))
((member ch '(:up :down)) ((member ch '(:up :down))
(if (eql ch :up) (cl-tty.select:select-prev sel) (if (eql ch :up) (cl-tty.select:select-prev sel)
(cl-tty.select:select-next sel))) (cl-tty.select:select-next sel)))
((member ch '(:enter 13 10 #\Newline #\Return)) ((member ch '(:enter 13 10 #\Newline #\Return))
(let* ((filtered (cl-tty.select:select-filtered-options sel)) (let* ((filtered (cl-tty.select:select-filtered-options sel))
(idx (cl-tty.select:select-selected-index sel)) (idx (cl-tty.select:select-selected-index sel))
(item (when (< idx (length filtered)) (item (when (< idx (length filtered))
(third (nth idx filtered))))) (third (nth idx filtered)))))
(when item (when item
(let ((cb (cl-tty.select:select-on-select sel))) (let ((cb (cl-tty.select:select-on-select sel)))
(when cb (funcall cb item)))))) (when cb (funcall cb item))))))
((and (characterp ch) (graphic-char-p ch)) ((and (characterp ch) (graphic-char-p ch))
(setf (cl-tty.select:select-filter sel) (setf (cl-tty.select:select-filter sel)
(concatenate 'string (or (cl-tty.select:select-filter sel) "") (string ch)))) (concatenate 'string (or (cl-tty.select:select-filter sel) "") (string ch))))
((member ch '(:backspace 127 8)) ((member ch '(:backspace 127 8))
(let ((f (cl-tty.select:select-filter sel))) (let ((f (cl-tty.select:select-filter sel)))
(when (> (length f) 0) (when (> (length f) 0)
(setf (cl-tty.select:select-filter sel) (subseq f 0 (1- f))))))))) (setf (cl-tty.select:select-filter sel) (subseq f 0 (1- f)))))))
;; v0.9.0 — Mouse wheel support ;; Forward printable keys to on-key for input buffer
(when (and (characterp ch) (graphic-char-p ch))
(on-key ch))))
((cl-tty.input:mouse-event-p data) ((cl-tty.input:mouse-event-p data)
(let ((btn (cl-tty.input:mouse-event-button data))) (let ((btn (cl-tty.input:mouse-event-button data)))
(cond (cond
@@ -932,31 +932,18 @@
((eql btn :scroll-down) ((eql btn :scroll-down)
(setf (st :scroll-offset) (max 0 (- (st :scroll-offset) 3))) (setf (st :scroll-offset) (max 0 (- (st :scroll-offset) 3)))
(setf (st :dirty) (list nil t nil)))))) (setf (st :dirty) (list nil t nil))))))
((member ch '(:enter 13 10 #\Newline #\Return 343)) (t (on-key ch)))))))
(on-key :enter))
((cl-tty.input:dispatch-key-event data)
nil)
(t (on-key ch)))))))
(when (or (first (st :dirty)) (second (st :dirty)) (third (st :dirty))) (when (or (first (st :dirty)) (second (st :dirty)) (third (st :dirty)))
(cl-tty.backend:backend-clear be) (cl-tty.backend:backend-clear be)
(redraw curr-fb w h) (view-status be w h)
;; Draw all rows from framebuffer directly (view-chat be w h)
(dotimes (row h) (view-input be w h)
(let ((line (make-string w :initial-element #\Space))
(fg (theme-color :agent-fg)) (bg nil))
(dotimes (col w)
(let* ((cell (aref curr-fb row col))
(ch (cl-tty.rendering:cell-char cell))
(cf (cl-tty.rendering:cell-fg cell))
(cb (cl-tty.rendering:cell-bg cell)))
(when ch (setf (char line col) ch))
(when cf (setf fg cf))
(when cb (setf bg cb))))
(cl-tty.backend:draw-text be 0 row line fg bg)))
;; Draw separator line above input ;; Draw separator line above input
(cl-tty.backend:draw-text be 0 (- h 4) (make-string w :initial-element #\─) (cl-tty.backend:draw-text be 0 (- h 4) (make-string w :initial-element #\─)
(theme-color :separator) nil) (theme-color :separator) nil)
(rotatef prev-fb curr-fb)) (when (and (st :sidebar-visible) (>= w 120))
(view-sidebar be w h))
(setf (st :dirty) (list nil nil nil)))
(let ((ds (st :dialog-stack))) (let ((ds (st :dialog-stack)))
(when ds (when ds
(let* ((dlg (car ds)) (let* ((dlg (car ds))
@@ -989,7 +976,7 @@
nil :bold sel-p) nil :bold sel-p)
(incf y-off))))))) (incf y-off)))))))
(sleep 0.1)))) (sleep 0.1))))
(disconnect-daemon)))) (disconnect-daemon)))
(eval-when (:compile-toplevel :load-toplevel :execute) (eval-when (:compile-toplevel :load-toplevel :execute)
(ql:quickload :fiveam :silent t)) (ql:quickload :fiveam :silent t))

View File

@@ -883,7 +883,6 @@ Event handlers + daemon I/O + main loop.
;; v0.8.0 — Prompt/local keymap (for when input is active) ;; v0.8.0 — Prompt/local keymap (for when input is active)
(eval-when (:load-toplevel :execute) (eval-when (:load-toplevel :execute)
(cl-tty.input:defkeymap :local (cl-tty.input:defkeymap :local
(:enter (lambda (e) (declare (ignore e)) (on-key :enter)))
(:up (lambda (e) (declare (ignore e)) (on-key :up))) (:up (lambda (e) (declare (ignore e)) (on-key :up)))
(:down (lambda (e) (declare (ignore e)) (on-key :down))) (:down (lambda (e) (declare (ignore e)) (on-key :down)))
(:escape (lambda (e) (declare (ignore e)) (on-key :escape))))) (:escape (lambda (e) (declare (ignore e)) (on-key :escape)))))
@@ -909,14 +908,15 @@ Event handlers + daemon I/O + main loop.
(add-msg :system "* Swank unavailable *")))) (add-msg :system "* Swank unavailable *"))))
(cl-tty.input:with-raw-terminal (cl-tty.input:with-raw-terminal
(cl-tty.backend:with-terminal (be w h) (cl-tty.backend:with-terminal (be w h)
(let ((prev-fb (cl-tty.rendering:make-framebuffer w h)) ;; Initial render
(curr-fb (cl-tty.rendering:make-framebuffer w h))) (cl-tty.backend:backend-clear be)
;; Initial render (view-status be w h)
(redraw curr-fb w h) (view-chat be w h)
(cl-tty.rendering:flush-framebuffer prev-fb curr-fb be) (view-input be w h)
(rotatef prev-fb curr-fb) (cl-tty.backend:draw-text be 0 (- h 4) (make-string w :initial-element #\─)
(loop while (st :running) do (theme-color :separator) nil)
(dolist (ev (drain-queue)) (loop while (st :running) do
(dolist (ev (drain-queue))
(cond (cond
((eq (getf ev :type) :daemon) ((eq (getf ev :type) :daemon)
(on-daemon-msg (getf ev :payload))) (on-daemon-msg (getf ev :payload)))
@@ -929,43 +929,43 @@ Event handlers + daemon I/O + main loop.
(cond (cond
((eq type :resize) ((eq type :resize)
(multiple-value-setq (w h) (cl-tty.backend:backend-size be)) (multiple-value-setq (w h) (cl-tty.backend:backend-size be))
(setf prev-fb (cl-tty.rendering:make-framebuffer w h)
curr-fb (cl-tty.rendering:make-framebuffer w h))
(setf (st :dirty) (list t t t))) (setf (st :dirty) (list t t t)))
(data (data
(let ((ch (typecase data (let ((ch (typecase data
(cl-tty.input:key-event (cl-tty.input:key-event
(cl-tty.input:key-event-key data)) (cl-tty.input:key-event-key data))
(t data)))) (t data))))
(cond (cond
((st :dialog-stack) ((st :dialog-stack)
(let* ((dlg (car (st :dialog-stack))) (let* ((dlg (car (st :dialog-stack)))
(sel (cl-tty.dialog:dialog-content dlg))) (sel (cl-tty.dialog:dialog-content dlg)))
(cond (cond
((eql ch :escape) ((eql ch :escape)
(pop (st :dialog-stack)) (pop (st :dialog-stack))
(setf (st :minibuffer-active) nil) (setf (st :minibuffer-active) nil)
(setf (st :command-palette-active) nil) (setf (st :command-palette-active) nil)
(setf (st :dirty) (list t t nil))) (setf (st :dirty) (list t t nil)))
((member ch '(:up :down)) ((member ch '(:up :down))
(if (eql ch :up) (cl-tty.select:select-prev sel) (if (eql ch :up) (cl-tty.select:select-prev sel)
(cl-tty.select:select-next sel))) (cl-tty.select:select-next sel)))
((member ch '(:enter 13 10 #\Newline #\Return)) ((member ch '(:enter 13 10 #\Newline #\Return))
(let* ((filtered (cl-tty.select:select-filtered-options sel)) (let* ((filtered (cl-tty.select:select-filtered-options sel))
(idx (cl-tty.select:select-selected-index sel)) (idx (cl-tty.select:select-selected-index sel))
(item (when (< idx (length filtered)) (item (when (< idx (length filtered))
(third (nth idx filtered))))) (third (nth idx filtered)))))
(when item (when item
(let ((cb (cl-tty.select:select-on-select sel))) (let ((cb (cl-tty.select:select-on-select sel)))
(when cb (funcall cb item)))))) (when cb (funcall cb item))))))
((and (characterp ch) (graphic-char-p ch)) ((and (characterp ch) (graphic-char-p ch))
(setf (cl-tty.select:select-filter sel) (setf (cl-tty.select:select-filter sel)
(concatenate 'string (or (cl-tty.select:select-filter sel) "") (string ch)))) (concatenate 'string (or (cl-tty.select:select-filter sel) "") (string ch))))
((member ch '(:backspace 127 8)) ((member ch '(:backspace 127 8))
(let ((f (cl-tty.select:select-filter sel))) (let ((f (cl-tty.select:select-filter sel)))
(when (> (length f) 0) (when (> (length f) 0)
(setf (cl-tty.select:select-filter sel) (subseq f 0 (1- f))))))))) (setf (cl-tty.select:select-filter sel) (subseq f 0 (1- f)))))))
;; v0.9.0 — Mouse wheel support ;; Forward printable keys to on-key for input buffer
(when (and (characterp ch) (graphic-char-p ch))
(on-key ch))))
((cl-tty.input:mouse-event-p data) ((cl-tty.input:mouse-event-p data)
(let ((btn (cl-tty.input:mouse-event-button data))) (let ((btn (cl-tty.input:mouse-event-button data)))
(cond (cond
@@ -976,31 +976,18 @@ Event handlers + daemon I/O + main loop.
((eql btn :scroll-down) ((eql btn :scroll-down)
(setf (st :scroll-offset) (max 0 (- (st :scroll-offset) 3))) (setf (st :scroll-offset) (max 0 (- (st :scroll-offset) 3)))
(setf (st :dirty) (list nil t nil)))))) (setf (st :dirty) (list nil t nil))))))
((member ch '(:enter 13 10 #\Newline #\Return 343)) (t (on-key ch)))))))
(on-key :enter))
((cl-tty.input:dispatch-key-event data)
nil)
(t (on-key ch)))))))
(when (or (first (st :dirty)) (second (st :dirty)) (third (st :dirty))) (when (or (first (st :dirty)) (second (st :dirty)) (third (st :dirty)))
(cl-tty.backend:backend-clear be) (cl-tty.backend:backend-clear be)
(redraw curr-fb w h) (view-status be w h)
;; Draw all rows from framebuffer directly (view-chat be w h)
(dotimes (row h) (view-input be w h)
(let ((line (make-string w :initial-element #\Space))
(fg (theme-color :agent-fg)) (bg nil))
(dotimes (col w)
(let* ((cell (aref curr-fb row col))
(ch (cl-tty.rendering:cell-char cell))
(cf (cl-tty.rendering:cell-fg cell))
(cb (cl-tty.rendering:cell-bg cell)))
(when ch (setf (char line col) ch))
(when cf (setf fg cf))
(when cb (setf bg cb))))
(cl-tty.backend:draw-text be 0 row line fg bg)))
;; Draw separator line above input ;; Draw separator line above input
(cl-tty.backend:draw-text be 0 (- h 4) (make-string w :initial-element #\─) (cl-tty.backend:draw-text be 0 (- h 4) (make-string w :initial-element #\─)
(theme-color :separator) nil) (theme-color :separator) nil)
(rotatef prev-fb curr-fb)) (when (and (st :sidebar-visible) (>= w 120))
(view-sidebar be w h))
(setf (st :dirty) (list nil nil nil)))
(let ((ds (st :dialog-stack))) (let ((ds (st :dialog-stack)))
(when ds (when ds
(let* ((dlg (car ds)) (let* ((dlg (car ds))
@@ -1033,7 +1020,7 @@ Event handlers + daemon I/O + main loop.
nil :bold sel-p) nil :bold sel-p)
(incf y-off))))))) (incf y-off)))))))
(sleep 0.1)))) (sleep 0.1))))
(disconnect-daemon)))) (disconnect-daemon)))
#+END_SRC #+END_SRC
* Test Suite * Test Suite