ebox/docs/user/ebox-user-guide.en.md

6.9 KiB

Ebox user guide

中文

Ebox is the low-level Text/Box layout and buffer-rendering package. This guide uses one public author grammar and keeps framework-integration details separate. See the API reference for the complete function inventory.

1. Load Ebox

(require 'ebox)

Loading Ebox does not create a buffer, enable a mode in the current buffer, or build Rust.

2. Learn one author model

An Ebox document contains Text and Box nodes. The author grammar has exactly seven entries:

Entry Meaning
"text" Short form for one Text node.
(text ... "text") Text with explicit text properties.
(box ... CHILD...) A normal visual Box.
(row ... CHILD...) A Box with simple horizontal child layout.
(column ... CHILD...) A Box with simple vertical child layout.
(flex ... CHILD...) A Box with Flex child layout.
(grid ... CHILD...) A Box with Grid child layout.

Children are always nested directly. A layout form is a Box with a selected child-layout algorithm, not a different kind of visual object.

(defvar ebox-guide-root
  (ebox-build
   '(column :padding (1 2)
            :border ((1) solid "#8A93A6")
            (text :color "#263244" "Research notes")
            (row :item-gap 1
                 (box :id "status" :background-color "#F4F6FB" "Inbox")
                 (box :background-color "#EEF2FF" "Archive")))))

Use box with geometry but no child when an empty rectangular area is needed. No extra node type is necessary.

3. Choose the layout that states the intent

Use box for ordinary content, row or column for direct one-axis composition, flex when free space or wrapping matters, and grid for two-dimensional tracks or explicit placement.

Row and column

row and column accept :item-gap and :cross-align. Their children remain ordinary Text or Box nodes.

(ebox-build
 '(row :item-gap 2 :cross-align center
       (box :width 12 "Left")
       (box :width 12 "Right")))

Flex

Flex container properties belong to flex. Participation properties belong directly to a child box because they describe the parent-child relationship.

(ebox-build
 '(flex :width (480)
        :flex-flow (row wrap)
        :gap (1 (12))
        (box :flex (1 1 auto) "Primary")
        (box :flex-grow 2 "Secondary")))

Grid

Grid placement is one-based. Tracks may be fixed, auto, fractional, minmax, or repeat values. Placement properties also belong directly to a child box.

(ebox-build
 '(grid :width (640)
        :grid-template-columns ((200) 1fr 1fr)
        :grid-template-rows (1 1)
        :gap (1 (12))
        (box :grid-column (1 :span 3) "Header")
        (box :grid-column 1 :grid-row 2 "Navigation")
        (box :grid-column 2 :grid-row 2 "Main")
        (box :grid-column 3 :grid-row 2 "Aside")))

4. Use geometry and paint properties

Horizontal numbers are character columns; a one-element list such as (240) is a pixel width. Vertical numbers are lines. Text accepts only font, foreground/background, and text-decoration properties. Padding, margin, border, size, :outer, overflow, visibility, and wrapping policy belong only to Box. Font and color on Box may feed inherited Text facts, but never give Text Box geometry.

(ebox-build
 '(box :width (420)
       :padding (1 2)
       :margin (0 1)
       :border ((1) solid "#8A93A6")
       :color "#263244"
       :background-color "#FFFFFF"
       "A readable panel"))

Use :outer inline or :outer block to state how a Box participates in its parent. The child-layout algorithm still comes from the form name.

5. Render and publish

ebox-render returns propertized text without changing a live buffer. ebox-render-to-buffer mounts a retained TP surface and returns its buffer.

(ebox-render ebox-guide-root)
(ebox-render-to-buffer "*Ebox Guide*" ebox-guide-root)

Build a fresh root and use ebox-commit for an atomic update:

(ebox-commit
 "*Ebox Guide*"
 (ebox-build
  '(column :padding (1 2)
           (text "Updated notes")
           (box :key body "The new root is caller-owned."))))

Validation, rendering, or publication failure leaves the previous buffer and runtime state intact. ebox-buffer-update-report returns a defensive copy of the last successful update report.

6. Query and update a mounted surface

:id, :class, and :key are author metadata. Selectors use ECSS semantics. Resolve an :id to an opaque, surface-scoped handle before a direct update:

(let ((handle (ebox-region-resolve "*Ebox Guide*" "status")))
  (ebox-region-update handle :color "#166534"))

ebox-selector-query-buffer returns document-ordered matches from a mounted buffer. ebox-selector-update-buffer applies one style update to all editable matches. Numeric region ids are diagnostic render metadata, not stable update handles.

7. Resize and scroll

A finite height plus :overflow scroll creates a scroll window. Ebox buffer mode installs keyboard and wheel commands that route through the innermost scroll owner before falling back to ordinary Emacs scrolling.

(ebox-build
 '(box :id log :width (420) :height 8 :overflow scroll
       "line 1\nline 2\nline 3\nline 4\nline 5\nline 6\nline 7\nline 8\nline 9"))

Visible mounted buffers follow their display window. Integrations may apply an explicit viewport with:

(ebox-rerender-buffer-with-context
 (get-buffer "*Ebox Guide*") 800 30)

8. Standalone .ebox files

A .ebox file contains one unquoted structural form:

(column :padding '(1 2)
        (text :color "#263244" "Title")
        (box :width '(240) "Body"))

The sibling ebox-playground evaluates property expressions before calling ebox-build. Quote list and symbol constants in a .ebox file, as shown above. When calling ebox-build directly, pass inert data as in the earlier examples.

9. Typed integration API

Frameworks that already normalize author input may bypass the list DSL. They construct one TextNode with ebox-text-create, one typed LayoutConfig with the matching layout constructor, then one BoxNode with ebox-box-create.

(ebox-box-create
 :layout (ebox-row-layout-create :item-gap 1 :cross-align 'center)
 :children (list (ebox-text-create :value "Left")
                 (ebox-text-create :value "Right")))

Here :layout and :children are fields of the evaluated typed constructor. They are not author properties and do not extend the seven-entry grammar.

10. Optional native reflow and verification

The Rust module is optional and Ebox never builds it while loading:

(ebox-native-status)
(ebox-native-build)

From the repository root:

make docs-contract-tests EMACS=/Applications/Emacs.app/Contents/MacOS/Emacs
make dsl-tests EMACS=/Applications/Emacs.app/Contents/MacOS/Emacs
make check EMACS=/Applications/Emacs.app/Contents/MacOS/Emacs