#+TITLE: Base Component Package #+STARTUP: content #+FILETAGS: :cl-tty:components: * Overview The ~cl-tty.box~ package is the central namespace for the component system. It aggregates all component-related symbols — box, text, dirty tracking, render dispatch, theme engine — under one package. Why ~box~ as the package name? Historically the package was created for the ~box~ and ~text~ renderables, and the name stuck as the package grew to encompass the entire component layer. The package ~:use~s ~cl-tty.backend~ (for drawing primitives) and ~cl-tty.layout~ (for layout nodes). All component code lives in this package. This org file is documentation-only: it explains the package design but the code itself is just a ~defpackage~ form. * Contract The ~cl-tty.box~ package exports these symbol groups: - Box: ~box~, ~make-box~, ~render-box~, border style/title accessors - Span: ~span~, span attribute readers - Text: ~text~, ~make-text~, ~render-text~, text accessors - Dirty: ~dirty-mixin~, ~dirty-p~, ~mark-clean~, ~mark-dirty~ - Render: ~render~, ~render-screen~, ~render-node~, tree navigation - Theme: ~theme~, ~make-theme~, ~theme-color~, ~load-preset~, ~define-preset~ * Implementation ~cl-tty.box~ uses ~cl-tty.backend~ for ~draw-text~, ~draw-border~, etc., and ~cl-tty.layout~ for ~layout-node~, ~compute-layout~, and the ~vbox~/~hbox~ macros. The only direct dependencies are these two packages — no other application code is needed to define components. ** Box exports The ~box~ class is the primary rectangular container: it renders a bordered region with optional title and background color. The accessor family (~box-border-style~, ~box-title~, ~box-title-align~, ~box-fg~, ~box-bg~) follows a consistent naming convention so that users can infer slot names from the class name. ~render-box~ is the specialized method that draws the border and fills the interior. The ~box-layout-node~ accessor connects the box to its layout tree node, which is essential for the render pipeline's coordinate computation. We export it separately from the rendering symbols because it is also needed by code that walks the component tree without triggering a full render. #+BEGIN_SRC lisp :tangle ~/.local/share/cl-tty/src/components/package.lisp (defpackage :cl-tty.box (:use :cl :cl-tty.backend :cl-tty.layout) (:export ;; Box #:box #:make-box #:box-layout-node #:box-border-style #:box-title #:box-title-align #:box-fg #:box-bg #:render-box #+END_SRC ** Span exports Spans are lightweight inline-style records — not full classes with layout. Each span stores a substring of the parent text along with its visual attributes. The reader-named accessors (~span-text~, ~span-bold~, ~span-italic~, etc.) let rendering code inspect span properties without pulling in the internal representation. We keep the accessor list flat (no grouping macro) to make the package surface easy to grep and to keep the API browser-friendly. #+BEGIN_SRC lisp :tangle ~/.local/share/cl-tty/src/components/package.lisp ;; Span #:span #:span-text #:span-bold #:span-italic #:span-underline #:span-reverse #:span-dim #:span-fg #:span-bg #+END_SRC ** Text exports ~text~ and ~make-text~ are the construction interface for the text renderable. The ~text-layout-node~ accessor follows the same pattern as ~box-layout-node~, bridging the component and layout layers. ~text-content~ and ~text-spans~ expose the raw data for rendering; ~text-fg~, ~text-bg~, and ~text-wrap-mode~ control global text appearance. ~render-text~ is the CLOS method that walks the span list and calls ~draw-text~ from the backend. These symbols live in the ~cl-tty.box~ package rather than a separate ~cl-tty.text~ package to keep inter-component references trivial — boxes can hold text children, and text can be nested inside other components, all without cross-package imports. #+BEGIN_SRC lisp :tangle ~/.local/share/cl-tty/src/components/package.lisp ;; Text #:text #:make-text #:text-layout-node #:text-content #:text-spans #:text-fg #:text-bg #:text-wrap-mode #:render-text #+END_SRC ** Utility exports (for tests) ~word-wrap~ and ~split-string~ are internal text-processing utilities used by the text renderer to break lines and tokenize input. They are exported specifically so the test suite can unit-test them in isolation. They are not part of the public component API and should not be relied upon by application code outside of tests. #+BEGIN_SRC lisp :tangle ~/.local/share/cl-tty/src/components/package.lisp ;; Utilities (for tests) #:word-wrap #:split-string #:char-width #+END_SRC ** Dirty tracking The dirty-mixin protocol lets any component class participate in the change-propagation system. ~dirty-mixin~ is the mixin class, and ~dirty-p~, ~mark-clean~, ~mark-dirty~ are the three operations that the render pipeline calls to decide whether a subtree needs re-rendering. Having these as generic functions (rather than a single ~(setf dirty-p)~) makes it easy for subclasses to add side effects on dirty transitions — for example, invalidating a cached bitmap or recomputing string metrics. #+BEGIN_SRC lisp :tangle ~/.local/share/cl-tty/src/components/package.lisp ;; Dirty tracking #:dirty-mixin #:dirty-p #:mark-clean #:mark-dirty #+END_SRC ** Rendering pipeline ~render~, ~render-screen~, and ~render-node~ are the three entry points into the rendering dispatch. ~component-layout-node~, ~component-children~, and ~component-parent~ form the tree-navigation interface that ~render-node~ uses to walk the component hierarchy. ~available-width~ and ~available-height~ are passed down the tree to constrain layout. ~propagate-dirty~ walks upward from a changed component to mark ancestors as dirty, ensuring the screen is re-drawn from the correct root. Collecting these under a single "Rendering pipeline" group signals to readers that they form a coherent subsystem — if you override one, you likely need to understand all of them. #+BEGIN_SRC lisp :tangle ~/.local/share/cl-tty/src/components/package.lisp ;; Rendering pipeline #:render #:render-screen #:render-node #:component-layout-node #:component-children #:component-parent #:available-width #:available-height #:propagate-dirty #+END_SRC ** Theme engine ~theme~ and ~make-theme~ are the constructor and class for theme objects. ~theme-mode~ selects the active color mode (light/dark). ~theme-color~ looks up a named color in the current theme. ~load-preset~ loads a theme from a file, and ~define-preset~ registers a preset at compile time. The theme engine is isolated from the rest of the component layer — boxes and text reference theme colors by name at render time, and the theme object is passed in from the application level. This separation 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 ;; 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