passepartout: v0.7.0 — TUI Essentials: Terminal Parity

TDD cycle: contract → RED test → GREEN implementation for each item.

- Unicode width (char-width): 6 tests, 11 assertions. ASCII/CJK/emoji/combining.
- Status bar fix: timestamp right-aligned, focus at :x 1. No overlap.
- Ctrl key bindings: Ctrl+D/Q/L/U/W, Ctrl+A/E, Ctrl+X+E. 6 tests.
- External editor: Ctrl+X prefix state tracking + Ctrl+E chord.
- Deeper autocomplete: /theme subcommand, /focus directory, @ file paths.
- Scroll notification: :scroll-notify flag set when scrolled up on new msg.
- Pre-existing tests: messages init-state assertion fixed (nil→vectorp).

Remaining: scroll pads (needs Croatoan terminal), setup wizard (v0.8.0).
This commit is contained in:
2026-05-08 10:45:05 -04:00
parent 66df5b493a
commit 55e0c962f4
5 changed files with 249 additions and 13 deletions

View File

@@ -10,6 +10,9 @@ All state mutation flows through event handlers in the controller.
1. (init-state): returns a fresh state plist with ~:msgs~ list,
~:input~ buffer, ~:dirty~ flag, ~:busy~ flag, and ~:connection~ status.
v0.7.0: ~:scroll-at-bottom~ flag tracks whether the user is scrolled to
the bottom. ~add-msg~ sets ~:scroll-notify~ t when a new message arrives
and the user is scrolled up.
2. (add-msg role content &key gate-trace): appends a message object
to the ~:messages~ vector (v0.3.3), tagged with timestamp, role,
and optional gate-trace from the daemon (v0.4.0).
@@ -132,6 +135,8 @@ See *tui-theme-presets* for named presets (dark, light, solarized, gruvbox).")
:input-buffer nil :input-history nil :input-hpos 0
:messages (make-array 16 :adjustable t :fill-pointer 0)
:scroll-offset 0 :busy nil :cursor-pos 0
:pending-ctrl-x nil :scroll-at-bottom t
:scroll-notify nil)
:dirty (list nil nil nil))))
#+end_src
@@ -166,6 +171,9 @@ See *tui-theme-presets* for named presets (dark, light, solarized, gruvbox).")
(defun add-msg (role content &key gate-trace)
(vector-push-extend (list :role role :content content :time (now) :gate-trace gate-trace) (st :messages))
;; v0.7.0: if scrolled up, set notification flag
(unless (st :scroll-at-bottom)
(setf (st :scroll-notify) t))
(setf (st :dirty) (list t t nil)))
#+end_src