From ef613927e6bf832962e1545ca830bf627f2e753b Mon Sep 17 00:00:00 2001 From: Amr Gharbeia Date: Mon, 18 May 2026 16:45:50 -0400 Subject: [PATCH] v1.0.0: merge container (scrollbox + tabbar) into cl-tty.box Eliminates the cl-tty.container package by merging scrollbox and tabbar components directly into cl-tty.box, where the component system lives. Changes: - added scrollbox/tabbar exports to cl-tty.box defpackage in package.org - changed scrollbox.org in-package from cl-tty.container to cl-tty.box - changed tabbar.org in-package from cl-tty.container to cl-tty.box - tabbar's key-event-key references are qualified with cl-tty.input: (avoids circular :use dependency with cl-tty.input which :uses cl-tty.box) - deleted container-package.org - updated test packages, integration tests, scripts, ASDF - all 14 test suites pass at 100% --- cl-tty.asd | 9 ++- org/container-package.org | 127 ------------------------------------ org/integration-tests.org | 2 +- org/package.org | 13 +++- org/scrollbox.org | 4 +- org/tabbar.org | 4 +- scripts/audit-compiler.lisp | 1 - scripts/code-audit.lisp | 1 - 8 files changed, 20 insertions(+), 141 deletions(-) delete mode 100644 org/container-package.org diff --git a/cl-tty.asd b/cl-tty.asd index 7d9de15..9e6bc53 100644 --- a/cl-tty.asd +++ b/cl-tty.asd @@ -33,11 +33,10 @@ (:file "text-input" :depends-on ("input-package" "input" "box")) (:file "textarea" :depends-on ("input-package" "input" "box")) (:file "keybindings" :depends-on ("input-package" "input")) - ;; Container components (v0.6.0) - (:file "container-package" :depends-on ("package" "input-package")) - (:file "scrollbox" :depends-on ("container-package" "dirty" "box")) - (:file "tabbar" :depends-on ("container-package" "dirty" "box")) - ;; Markdown + Code + Diff rendering (v0.8.0) + ;; Container components merged into box (v0.6.0) + (:file "scrollbox" :depends-on ("package" "dirty" "box")) + (:file "tabbar" :depends-on ("package" "dirty" "box")) + ;; Markdown + Code + Diff rendering (v0.8.0) (:file "markdown-package" :depends-on ("package")) (:file "markdown" :depends-on ("markdown-package")) ;; Dialog + Toast (v0.9.0) diff --git a/org/container-package.org b/org/container-package.org deleted file mode 100644 index e2f32e3..0000000 --- a/org/container-package.org +++ /dev/null @@ -1,127 +0,0 @@ -#+TITLE: Container Package -#+STARTUP: content -#+FILETAGS: :cl-tty:container: - -* Overview - -The ~cl-tty.container~ package defines the container component types: -ScrollBox and TabBar. It uses ~cl-tty.backend~, ~cl-tty.box~, -~cl-tty.layout~, and ~cl-tty.input~. - -The package exports both ScrollBox and TabBar classes, constructors, -accessors, and navigation functions. - -* Why a Separate Package? - -The base ~cl-tty.box~ package was designed for the fundamental -renderable types — box, text, spans, dirty-tracking, the render -pipeline, and the theme engine. These are the building blocks that -virtually every component depends on. Container components — -ScrollBox and TabBar — are higher-level composite widgets with -specific behavioral contracts (viewport scrolling, tab navigation, -keyboard dispatch) that are not needed by every component user. - -Separating them into ~cl-tty.container~ achieves two things: - - 1. It keeps ~cl-tty.box~ lean. Users who only need basic - renderables (boxes, text) do not pull in scroll-logic or - tab-navigation code. This is especially important for the - test suite — container tests have their own setup, backend - capture, and assertion patterns that are unrelated to the - base component tests. - - 2. It establishes a clean dependency boundary. ~cl-tty.box~ - depends only on ~cl-tty.backend~ and ~cl-tty.layout~. - Container components additionally depend on ~cl-tty.input~, - because TabBar handles key events. By putting container - code in its own package, we avoid creating a circular or - incidental dependency between the input system and the - base component layer. - -* What the Container Package Provides - -The package exports two full component families: - -- **ScrollBox**: A viewport-based container that holds a list of - child components and provides vertical/horizontal scrolling with - viewport culling (only visible children are rendered), scrollbar - display, sticky-scroll (auto-scroll to bottom on new content), - and scroll-offset clamping. ScrollBox inherits ~dirty-mixin~, - implements the component protocol (~render~, ~component-children~, - ~component-layout-node~), and integrates with the layout engine. - Its constructor ~make-scroll-box~ accepts ~:children~, - ~:scroll-y~, ~:scroll-x~, and ~:sticky-scroll-p~ keyword args. - -- **TabBar**: A horizontal tab-navigation widget that manages a - list of named tabs, tracks the active tab, and dispatches - keyboard events (Left/Right for prev/next). TabBar also inherits - ~dirty-mixin~ and implements ~render~ and ~component-layout-node~. - It provides ~tab-bar-add~ for dynamic tab creation, ~tab-bar-next~ - / ~tab-bar-prev~ for cycling, ~tab-bar-select~ for direct - activation, and ~tab-bar-handle-key~ for keyboard integration. - -Both components export the generic ~render~ method, allowing the -rendering pipeline to dispatch ~(render instance backend)~ uniformly. - -* Design Decisions: ScrollBox and TabBar in One Package - -ScrollBox and TabBar are very different widgets — one manages a -scrollable viewport, the other renders a row of selectable labels. -They are kept in the same package rather than split into -~cl-tty.scroll-box~ and ~cl-tty.tab-bar~ for several reasons: - - 1. **Shared dependencies**: Both components :use the same four - packages (~cl-tty.backend~, ~cl-tty.box~, ~cl-tty.layout~, - ~cl-tty.input~). They both inherit from ~dirty-mixin~ and - implement the component protocol. A shared package avoids - duplicating the ~:use~ and ~:export~ boilerplate. - - 2. **Co-located tests**: The test suite - (~tests/scrollbox-tabbar-tests.lisp~) tests both components - in one file and one FiveAM suite. They share test helpers, - backend-capture patterns, and the same package dependency. - Keeping them in one source package means the test defpackage - only needs one ~:use~ clause for the container, and symbols - from both components are visible together. - - 3. **Common contract**: Both components are "containers" in the - architectural sense — they manage a collection of sub-items - (children or tabs) and provide navigation over them. A - TabBar is conceptually a horizontal container of selectable - entries; a ScrollBox is a vertical container with scroll. - Placing them under the same ~:cl-tty.container~ namespace - signals to users that these are the composite widget types, - as opposed to the atomic renderables in ~:cl-tty.box~. - - 4. **Practical usage patterns**: In typical TUI applications, a - TabBar switches between views and a ScrollBox displays the - content of each view. They are often used together in the - same composition. Having them in one package eliminates - cross-package qualification or redundant ~:import-from~ - declarations when building combined layouts. - -If either component grows substantial internal logic in the future -(say, ScrollBox develops virtual scrolling, infinite loading, or -its own input model), it could be split into its own package at -that point. The current scope favors simplicity and co-location. - -* Package Definition - -#+BEGIN_SRC lisp :tangle ~/.local/share/cl-tty/src/components/container-package.lisp -(defpackage :cl-tty.container - (:use :cl :cl-tty.backend :cl-tty.box :cl-tty.layout :cl-tty.input) - (:export - ;; ScrollBox - #:scroll-box #:make-scroll-box - #:scroll-box-scroll-y #:scroll-box-scroll-x - #:scroll-box-children - #:scroll-by #:sticky-scroll-p - #:clamp-scroll - ;; TabBar - #:tab-bar #:make-tab-bar - #:tab-bar-active #:tab-bar-tabs - #:tab-bar-add #:tab-bar-next #:tab-bar-prev - #:tab-bar-select #:tab-bar-handle-key - ;; Rendering - #:render)) -#+END_SRC diff --git a/org/integration-tests.org b/org/integration-tests.org index ed8816d..026d1fc 100644 --- a/org/integration-tests.org +++ b/org/integration-tests.org @@ -50,7 +50,7 @@ package, so the symbol must be interned and accessible. (defpackage :cl-tty-integration-test (:use :cl :fiveam :cl-tty.backend :cl-tty.box :cl-tty.layout - :cl-tty.input :cl-tty.container + :cl-tty.input :cl-tty.rendering :cl-tty.dialog)) (in-package :cl-tty-integration-test) diff --git a/org/package.org b/org/package.org index 856d9ea..15b98a7 100644 --- a/org/package.org +++ b/org/package.org @@ -175,6 +175,15 @@ means themes can be swapped without touching component instances. #+BEGIN_SRC lisp :tangle ~/.local/share/cl-tty/src/components/package.lisp ;; Theme engine #:theme #:make-theme #:theme-mode - #:theme-color #:load-preset #:define-preset)) -(in-package :cl-tty.box) + #:theme-color #:load-preset #:define-preset + ;; Container components (merged from cl-tty.container) + #:scroll-box #:make-scroll-box + #:scroll-box-scroll-y #:scroll-box-scroll-x + #:scroll-box-children + #:scroll-by #:sticky-scroll-p + #:clamp-scroll + #:tab-bar #:make-tab-bar + #:tab-bar-active #:tab-bar-tabs + #:tab-bar-add #:tab-bar-next #:tab-bar-prev + #:tab-bar-select #:tab-bar-handle-key)) #+END_SRC diff --git a/org/scrollbox.org b/org/scrollbox.org index 96b7225..a9097b2 100644 --- a/org/scrollbox.org +++ b/org/scrollbox.org @@ -46,7 +46,7 @@ the CLOS-based component protocol — ~render~ dispatches on the class, and dirty-mixin provides the marking machinery used by the refresh loop. #+BEGIN_SRC lisp :tangle ~/.local/share/cl-tty/src/components/scrollbox.lisp -(in-package #:cl-tty.container) +(in-package :cl-tty.box) (defclass scroll-box (dirty-mixin) ((children :initform nil :initarg :children @@ -344,7 +344,7 @@ unconditionally; it runs the ~scrollbox-suite~ and prints results via #+BEGIN_SRC lisp :tangle ~/.local/share/cl-tty/tests/scrollbox-tabbar-tests.lisp (defpackage :cl-tty-scrollbox-test - (:use :cl :fiveam :cl-tty.backend :cl-tty.box :cl-tty.layout :cl-tty.input :cl-tty.container) + (:use :cl :fiveam :cl-tty.backend :cl-tty.box :cl-tty.layout :cl-tty.input) (:export #:run-tests)) (in-package #:cl-tty-scrollbox-test) diff --git a/org/tabbar.org b/org/tabbar.org index a8b4946..78da774 100644 --- a/org/tabbar.org +++ b/org/tabbar.org @@ -33,7 +33,7 @@ the symbol namespace clean and avoids accidental collisions with user-level code. #+BEGIN_SRC lisp :tangle ~/.local/share/cl-tty/src/components/tabbar.lisp -(in-package #:cl-tty.container) +(in-package :cl-tty.box) #+END_SRC ** TabBar class @@ -168,7 +168,7 @@ bar lives alongside other focusable elements. #+BEGIN_SRC lisp :tangle ~/.local/share/cl-tty/src/components/tabbar.lisp (defun tab-bar-handle-key (tb event) "Handle a key-event on a TabBar. Returns T if handled." - (case (key-event-key event) + (case (cl-tty.input:key-event-key event) (:left (tab-bar-prev tb) t) (:right (tab-bar-next tb) t) (t nil))) diff --git a/scripts/audit-compiler.lisp b/scripts/audit-compiler.lisp index c4524a2..53d697d 100644 --- a/scripts/audit-compiler.lisp +++ b/scripts/audit-compiler.lisp @@ -29,7 +29,6 @@ '("src/backend/classes.lisp" "src/backend/package.lisp" "src/backend/detection.lisp" "src/backend/simple.lisp" "src/backend/modern.lisp" "src/layout/layout.lisp" - "src/components/container-package.lisp" "src/components/dialog-package.lisp" "src/components/dialog.lisp" "src/components/dirty.lisp" "src/components/input-package.lisp" "src/components/input.lisp" diff --git a/scripts/code-audit.lisp b/scripts/code-audit.lisp index 823fe76..1ca60ed 100644 --- a/scripts/code-audit.lisp +++ b/scripts/code-audit.lisp @@ -28,7 +28,6 @@ '("src/backend/classes.lisp" "src/backend/package.lisp" "src/backend/detection.lisp" "src/backend/simple.lisp" "src/backend/modern.lisp" "src/layout/layout.lisp" - "src/components/container-package.lisp" "src/components/dialog-package.lisp" "src/components/dialog.lisp" "src/components/dirty.lisp" "src/components/input-package.lisp" "src/components/input.lisp"