docs(ebox): align public API and usage references

This commit is contained in:
Kinneyzhang 2026-08-11 21:09:12 +08:00
parent 3dc0706af9
commit 972126e239
14 changed files with 1303 additions and 62 deletions

View File

@ -22,15 +22,15 @@ node tree
-> pure TP surface plan
```
The owners are `ebox-tree.el` for Ebox identity and traversal, `ebox-style.el` for style semantics, `ebox-measure.el` for display-sensitive measurement, `ebox-layout.el`/`ebox-flex.el`/`ebox-grid.el` for geometry, `ebox-fragment.el` for fragment facts, `ebox-surface.el` for pure TP plan projection, and `ebox-incremental.el` for dirty-owner planning. During the staged cutover, the existing Ebox buffer backend still publishes live public entry points; it is not used by the pure projector and will be removed when those entry points move to TP surfaces.
The owners are `ebox-tree.el` for Ebox identity and traversal, `ebox-style.el` for style semantics, `ebox-measure.el` for display-sensitive measurement, `ebox-layout.el`/`ebox-flex.el`/`ebox-grid.el` for geometry, `ebox-fragment.el` for fragment facts, `ebox-surface.el` for pure TP plan projection and retained publication, and `ebox-incremental.el` for dirty-owner planning. `ebox-buffer-backend.el` only builds and reshapes propertized render strings; all public live buffer publication routes through the TP surface boundary.
## Public boundary
Use `ebox-create`, `ebox-column`, `ebox-row`, `ebox-flex`, `ebox-grid`, `ebox-build`, `ebox-render`, `ebox-render-to-buffer`, `ebox-commit`, and selector entry points. Do not call `ebox--*` names from an application or a sibling package. Higher-level Component, reactive, behavior, data, and control concepts belong to ETAF.
Use the functions and properties in `docs/user/ebox-api-reference.en.md`; the facade inventory is `ebox-public-api`. Do not call `ebox--*` names from an application or a sibling package. Higher-level Component, reactive, behavior, data, and control concepts belong to ETAF.
## Layout scope
Ebox supports character and pixel dimensions, padding, margins, borders, colors, faces, overflow, wrapping, row/column/flex formatting, and Grid tracks including fixed, fractional, implicit, gap, placement, span, and alignment behavior. CSS compatibility is intentionally partial: browser cascade, percentages, absolute positioning, z-index, shadows, full typography, and browser-level bidi are outside this package.
Ebox supports character and pixel dimensions, padding, margins, borders, colors, Emacs face/font properties, overflow, wrapping, row/column/flex formatting, and Grid tracks including fixed, fractional, implicit, gap, placement, span, and alignment behavior. The supported typography subset is `:font`, `:font-family`, `:font-height`/`:font-size`, `:font-weight`, and `:font-slant`. CSS compatibility is intentionally partial: percentages, absolute positioning, z-index, shadows, border radius, full browser typography, and browser-level bidi are outside this package.
## Verification rule

View File

@ -22,15 +22,15 @@ Ebox 是底层空间渲染引擎。它负责把声明式节点树转换为经过
-> 纯 TP surface plan
```
各层 owner 是:`ebox-tree.el` 负责 Ebox identity 与遍历,`ebox-style.el` 负责样式语义,`ebox-measure.el` 负责 display 敏感测量,`ebox-layout.el`、`ebox-flex.el`、`ebox-grid.el` 负责几何,`ebox-fragment.el` 负责 fragment 事实,`ebox-surface.el` 负责纯 TP plan 投影,`ebox-incremental.el` 负责 dirty owner 规划。分阶段切换期间,现有 Ebox buffer backend 仍为公开 live 入口执行发布;纯 projector 不调用它,公开入口切到 TP surface 后会删除这套发布执行器
各层 owner 是:`ebox-tree.el` 负责 Ebox identity 与遍历,`ebox-style.el` 负责样式语义,`ebox-measure.el` 负责 display 敏感测量,`ebox-layout.el`、`ebox-flex.el`、`ebox-grid.el` 负责几何,`ebox-fragment.el` 负责 fragment 事实,`ebox-surface.el` 负责纯 TP plan 投影与 retained 发布`ebox-incremental.el` 负责 dirty owner 规划。`ebox-buffer-backend.el` 只构造和整形带文本属性的 render string所有公共 live buffer 发布路径都经过 TP surface 边界
## 公共边界
使用 `ebox-create`、`ebox-column`、`ebox-row`、`ebox-flex`、`ebox-grid`、`ebox-build`、`ebox-render`、`ebox-render-to-buffer`、`ebox-commit` 以及 selector 入口。应用和同级包不得调用 `ebox--*` 私有名称。更高层的 Component、响应式、behavior、data 和 control 概念属于 ETAF。
使用 `docs/user/ebox-api-reference.zh.md` 中的函数与 property门面清单是 `ebox-public-api`。应用和同级包不得调用 `ebox--*` 私有名称。更高层的 Component、响应式、behavior、data 和 control 概念属于 ETAF。
## 布局范围
Ebox 支持字符和像素尺寸、padding、margin、border、颜色、face、overflow、换行、row/column/flex formatting以及固定、分数、隐式、gap、放置、span 和对齐等 Grid 能力。CSS 兼容性有意是部分实现:浏览器 cascade、百分比、绝对定位、z-index、阴影、完整 typography 和浏览器级 bidi 不属于本包。
Ebox 支持字符和像素尺寸、padding、margin、border、颜色、Emacs face/font property、overflow、换行、row/column/flex formatting以及固定、分数、隐式、gap、放置、span 和对齐等 Grid 能力。支持的 typography 子集是 `:font`、`:font-family`、`:font-height`/`:font-size`、`:font-weight` 和 `:font-slant`CSS 兼容性有意是部分实现百分比、绝对定位、z-index、阴影、border radius、完整浏览器 typography 和浏览器级 bidi 不属于本包。
## 验证规则

View File

@ -22,7 +22,7 @@ ECSS and TP are independent packages and may be installed in either order. Insta
:bgcolor "#F4F6FB")))
```
The public model is a tree of Ebox nodes. `ebox-create` builds a leaf or wrapper node; `ebox-column`, `ebox-row`, `ebox-flex`, and `ebox-grid` compose nodes; `ebox-render` materializes propertized text through an ephemeral TP surface; `ebox-render-to-buffer` mounts a retained TP surface; `ebox-display-buffer` displays that same retained-surface path; and `ebox-commit` atomically updates the mount from a fresh root tree. Ebox copies declarative input before assigning runtime identity, so one source tree may be mounted in multiple buffers without transferring ownership. It exposes no separate public macro that erases a live buffer and evaluates arbitrary body forms.
The public model is a tree of Ebox nodes. `ebox-create` builds a leaf or wrapper node; `ebox-column`, `ebox-row`, `ebox-flex`, and `ebox-grid` compose nodes; `ebox-render` materializes propertized text without publishing buffer state (using isolated pure materialization when no cascade/inheritance dependency requires a TP object tree); `ebox-render-to-buffer` mounts a retained TP surface; `ebox-display-buffer` displays that same retained-surface path; and `ebox-commit` atomically updates the mount from a fresh root tree. Ebox copies declarative input before assigning runtime identity, so one source tree may be mounted in multiple buffers without transferring ownership. It exposes no separate public macro that erases a live buffer and evaluates arbitrary body forms.
CSS-like selector strings are compiled to ECSS's structured selector AST. Ebox supplies logical node relations and indexed candidates; ECSS is the only selector matcher and cascade engine for tree queries, rendered-buffer queries, and style rules.
@ -41,7 +41,8 @@ ETAF belongs in the sibling package. Install it separately when you need the uni
| Path | Responsibility |
| --- | --- |
| `ebox.el` | Public facade and package entry point. |
| `ebox-style.el`, `ebox-tree.el`, `ebox-measure.el` | Style, tree, and measurement models. |
| `ebox-cache.el`, `ebox-style.el`, `ebox-tree.el`, `ebox-measure.el` | Cache, style, tree, and measurement models. |
| `ebox-fragment.el`, `ebox-render-context.el` | Layout facts and render-local context. |
| `ebox-layout.el`, `ebox-flex.el`, `ebox-grid.el` | Formatting contexts and layout algorithms. |
| `ebox-surface.el` | Ebox candidate projection plus TP surface mount/update and atomic Ebox runtime-state participation. |
| `ebox-buffer-backend.el`, `ebox-incremental.el` | Layout dirty planning, marker indexes, and specialized local update paths. |
@ -61,4 +62,4 @@ make native-rust-tests
Run the smallest focused target first (`make grid-tests`, `make surface-tests`, `make dsl-tests`, or `make visual-check-tests`), then run `make check` for shared rendering or public API changes. Sibling ECSS and TP checkouts are found at `../new-architecture/ecss` and `../tp` by default; override `ECSS_DIR` or `TP_DIR` when they live elsewhere.
Read the [Ebox user guide](docs/user/ebox-user-guide.en.md) for public construction examples and the [current implementation reference](docs/maintainer/ebox-current-implementation-reference.en.md) for ownership boundaries and invariants.
Read the [Ebox user guide](docs/user/ebox-user-guide.en.md) for a guided start, the [public API reference](docs/user/ebox-api-reference.en.md) for the complete function/property/configuration inventory, and the [current implementation reference](docs/maintainer/ebox-current-implementation-reference.en.md) for ownership boundaries and invariants.

View File

@ -22,7 +22,7 @@ ECSS 与 TP 是互相独立的包,安装顺序任意。两者都安装后再
:bgcolor "#F4F6FB")))
```
公共模型是一棵 Ebox 节点树。`ebox-create` 构造叶子或包装节点;`ebox-column`、`ebox-row`、`ebox-flex` 和 `ebox-grid` 组合节点;`ebox-render` 通过临时 TP surface 生成带属性文本`ebox-render-to-buffer` 挂载 retained TP surface`ebox-display-buffer` 展示同一条 retained-surface 路径;`ebox-commit` 使用新的根树原子更新该 mount。Ebox 会在分配 runtime identity 前复制声明式输入,因此同一 source tree 可以挂载到多个 buffer而不转移所有权。公共 API 不再提供另一套擦除 live buffer 后执行任意 BODY 的宏。
公共模型是一棵 Ebox 节点树。`ebox-create` 构造叶子或包装节点;`ebox-column`、`ebox-row`、`ebox-flex` 和 `ebox-grid` 组合节点;`ebox-render` 生成带属性文本但不发布 buffer state没有 cascade/inheritance 依赖时使用隔离的 pure materialization`ebox-render-to-buffer` 挂载 retained TP surface`ebox-display-buffer` 展示同一条 retained-surface 路径;`ebox-commit` 使用新的根树原子更新该 mount。Ebox 会在分配 runtime identity 前复制声明式输入,因此同一 source tree 可以挂载到多个 buffer而不转移所有权。公共 API 不再提供另一套擦除 live buffer 后执行任意 BODY 的宏。
CSS-like selector 字符串会编译为 ECSS 的 structured selector AST。Ebox 提供逻辑节点关系与索引候选;对于 tree query、rendered-buffer query 和样式规则ECSS 是唯一 selector matcher 与 cascade engine。
@ -41,9 +41,10 @@ ETAF 属于同级独立包。当你需要统一 View 语法、Component、响应
| 路径 | 职责 |
| --- | --- |
| `ebox.el` | 公共门面与包入口。 |
| `ebox-style.el`、`ebox-tree.el`、`ebox-measure.el` | 样式、树和测量模型。 |
| `ebox-cache.el`、`ebox-style.el`、`ebox-tree.el`、`ebox-measure.el` | 缓存、样式、树和测量模型。 |
| `ebox-fragment.el`、`ebox-render-context.el` | 布局事实与 render-local context。 |
| `ebox-layout.el`、`ebox-flex.el`、`ebox-grid.el` | Formatting Context 与布局算法。 |
| `ebox-surface.el` | 将 Ebox runtime/layout 投影为通用 TP surface plan。 |
| `ebox-surface.el` | 将 Ebox runtime/layout 投影为 TP surface plan,并负责 retained mount/update 与原子 runtime-state 参与。 |
| `ebox-buffer-backend.el`、`ebox-incremental.el` | Render-string backend 与 Ebox 增量规划。 |
| `ebox-dsl.el`、`ebox-selector.el` | 独立 DSL 与基于 ECSS 的树/runtime 查询。 |
| `ebox-native-reflow.el`、`native/` | 可选 native reflow 边界。 |
@ -61,4 +62,4 @@ make native-rust-tests
小范围修改先运行对应目标(例如 `make grid-tests`、`make surface-tests`、`make dsl-tests` 或 `make visual-check-tests`);共享渲染或公共 API 修改后运行完整的 `make check`。默认从 `../new-architecture/ecss``../tp` 查找同级 ECSS 和 TP checkout若路径不同可覆盖 `ECSS_DIR``TP_DIR`
公共构造示例见 [Ebox 用户指南](docs/user/ebox-user-guide.zh.md),职责边界与不变量见 [当前实现参考](docs/maintainer/ebox-current-implementation-reference.zh.md)。
入门构造示例见 [Ebox 用户指南](docs/user/ebox-user-guide.zh.md),完整函数/property/配置清单见 [公共 API 参考](docs/user/ebox-api-reference.zh.md),职责边界与不变量见 [当前实现参考](docs/maintainer/ebox-current-implementation-reference.zh.md)。

View File

@ -7,9 +7,10 @@ This is the maintainer entry point for the standalone Ebox repository. It descri
1. Read `AGENTS.md` for repository rules.
2. Read `README.md` for installation and the public boundary.
3. Read `docs/user/ebox-user-guide.en.md` for public construction patterns.
4. Read this document for ownership and verification.
5. Read `docs/maintainer/ebox-incremental-update-contract.en.md` before changing publication or patch planning.
6. Read `docs/maintainer/ebox-performance-architecture-analysis.en.md` before changing performance, retained surfaces, or incremental data flow.
4. Read `docs/user/ebox-api-reference.en.md` for the complete public function/property/configuration inventory.
5. Read this document for ownership and verification.
6. Read `docs/maintainer/ebox-incremental-update-contract.en.md` before changing publication or patch planning.
7. Read `docs/maintainer/ebox-performance-architecture-analysis.en.md` before changing performance, retained surfaces, or incremental data flow.
## Active source map
@ -86,7 +87,7 @@ Caller-owned Source Tree
## Grid contract
Grid currently covers fixed and pixel tracks, `auto`, fractional tracks, `minmax`, `repeat`, implicit rows and columns, row/column gap, auto-flow, one-based placement, positive spans, item/content alignment, and ordinary buffer rendering and updates. CSS cascade, percentages, absolute positioning, z-index, border radius, shadows, full typography, and browser-level bidi are outside the contract.
Grid currently covers fixed and pixel tracks, `auto`, fractional tracks, `minmax`, `repeat`, implicit rows and columns, row/column gap, auto-flow, one-based placement, positive spans, item/content alignment, and ordinary buffer rendering and updates. Ebox supports a finite typography subset (`:font`, `:font-family`, `:font-height`/`:font-size`, `:font-weight`, and `:font-slant`); full browser typography is outside the contract. Percentages, absolute positioning, z-index, border radius, shadows, and browser-level bidi are also outside the contract.
## Active examples and tests

View File

@ -7,9 +7,10 @@
1. 先读 `AGENTS.md` 了解仓库规则。
2. 读 `README.md` 了解安装和公共边界。
3. 读 `docs/user/ebox-user-guide.zh.md` 了解公共构造方式。
4. 读本文了解所有权和验证方式。
5. 修改发布或 patch 规划前,读 `docs/maintainer/ebox-incremental-update-contract.zh.md`
6. 修改性能、retained surface 或增量数据流前,读 `docs/maintainer/ebox-performance-architecture-analysis.zh.md`
4. 读 `docs/user/ebox-api-reference.zh.md` 了解完整的公共函数/property/配置清单。
5. 读本文了解所有权和验证方式。
6. 修改发布或 patch 规划前,读 `docs/maintainer/ebox-incremental-update-contract.zh.md`
7. 修改性能、retained surface 或增量数据流前,读 `docs/maintainer/ebox-performance-architecture-analysis.zh.md`
## Active 源码清单
@ -86,7 +87,7 @@ active 合同还覆盖 `Makefile`、`.github/workflows/ci.yml`、`tests/ebox-cor
## Grid 合同
当前 Grid 支持固定和像素轨道、`auto`、分数轨道、`minmax`、`repeat`、隐式行列、行列 gap、auto-flow、从 1 开始的 placement、正整数 span、item/content 对齐,以及普通 buffer 渲染和更新。CSS cascade、百分比、绝对定位、z-index、圆角、阴影、完整 typography 和浏览器级 bidi 不在合同内。
当前 Grid 支持固定和像素轨道、`auto`、分数轨道、`minmax`、`repeat`、隐式行列、行列 gap、auto-flow、从 1 开始的 placement、正整数 span、item/content 对齐,以及普通 buffer 渲染和更新。Ebox 支持有限 typography 子集(`:font`、`:font-family`、`:font-height`/`:font-size`、`:font-weight` 和 `:font-slant`);完整浏览器 typography 不在合同内。百分比、绝对定位、z-index、圆角、阴影和浏览器级 bidi 不在合同内。
## Active 示例与测试

View File

@ -0,0 +1,567 @@
# Ebox public API reference
[中文](ebox-api-reference.zh.md)
This document is the exhaustive user-facing inventory for the standalone Ebox
package. It describes the supported node model, properties, layout helpers,
rendering/publication workflows, selectors, scrolling, measurement, DSL, and
optional native module. `ebox--*` names and undocumented module helpers are
implementation details. The facade inventory is also available as the
`ebox-public-api` constant after `(require 'ebox)`.
Ebox owns box nodes, style normalization, measurement, layout, rendering,
semantic update planning, selector integration, Grid, and the optional Rust
reflow accelerator. TP owns live buffer publication, physical diff execution,
revisions, and rollback. ECSS owns selector parsing, matching, and cascade
semantics. Ebox does not provide Components, application state, UI controls,
or an application lifecycle.
## 1. Install and load
Ebox requires Emacs 29.1 or newer, ECSS, and TP. With sibling source
checkouts:
```elisp
(add-to-list 'load-path "/path/to/github/ecss")
(add-to-list 'load-path "/path/to/github/tp")
(add-to-list 'load-path "/path/to/github/ebox")
(require 'ebox)
```
Loading Ebox loads the Elisp layout/runtime modules. It does not create a
buffer, enable a mode in the current buffer, build Rust, or mutate the current
editing buffer. The optional native module is loaded only when its workflow or
an eligible native path requests it.
## 2. The normal lifecycle
The public workflow is:
```elisp
(let ((root
(ebox-column
(ebox-create :id "status" :content "Ready" :width '(240))
(ebox-create :content "A caller-owned source tree"))))
;; Pure materialization; returns a multi-line propertized string.
(ebox-render root)
;; Retained TP surface; returns the live buffer.
(ebox-render-to-buffer "*Ebox Demo*" root)
;; Later, build a new declarative root and publish it atomically.
(ebox-commit
"*Ebox Demo*"
(ebox-column
(ebox-create :id "status" :content "Updated" :width '(240))
(ebox-create :content "The unchanged source is not mutated."))))
```
`ebox-render` has no live-buffer side effect. A static tree without an active
stylesheet or inline inherited-style dependency can use isolated pure
materialization; stylesheet-dependent pure renders use an ephemeral TP
materialization. Both produce the same public string contract. The two buffer
entry points use a retained TP surface. Ebox copies declarative input before
assigning runtime identity, so the same source tree may be mounted in several
buffers.
`ebox-display-buffer` is the convenience wrapper when Ebox should also display
the buffer. It deletes other windows before switching to the rendered buffer;
use `ebox-render-to-buffer` when the caller owns window selection.
## 3. Nodes and composition
### Box and simple layout constructors
```elisp
(ebox-create &rest properties)
(ebox-concat node-1 node-2) ; two nodes side by side
(ebox-stack node-1 node-2) ; two nodes vertically
(ebox-row &rest nodes) ; many nodes side by side
(ebox-column &rest nodes) ; many nodes vertically
(ebox-spacer &rest properties) ; blank box
```
`ebox-create` returns a declarative box node. `:content` is string content;
container children are normally supplied to `ebox-row`, `ebox-column`,
`ebox-flex`, or `ebox-grid`. `ebox-concat` and `ebox-stack` accept two nodes;
use the variadic row/column helpers for more than two children. Nil children
are ignored. An empty row or column becomes a spacer.
`:key` is the stable application identity for a sibling. `:id` is a logical
selector/update identifier. `:host-ref` is an opaque application-owned anchor
used by host-reference lookup and logical candidate replacement. Host refs
must be unique and non-nil within one source tree.
### Flex
```elisp
(ebox-flex
:width '(480)
:flex-flow '(row wrap)
:gap '(1 (12))
(ebox-flex-item (ebox-create :content "A")
:flex '(1 1 auto)
:align-self 'center)
(ebox-create :content "B" :flex-grow 2))
```
Container properties are `:flex-direction`, `:flex-wrap`, `:flex-flow`,
`:justify-content`, `:align-items`, `:align-content`, `:gap`, `:row-gap`, and
`:column-gap`, plus ordinary box properties such as `:width`, `:height`,
padding, border, and paint. Defaults are row direction, nowrap, flex-start
main-axis justification, and stretch cross-axis alignment.
Item properties are `:order`, `:flex`, `:flex-grow`, `:flex-shrink`,
`:flex-basis`, and `:align-self`. They may be placed directly on a child or
attached with `ebox-flex-item`. Non-item properties passed to
`ebox-flex-item` wrap the child in a normal box.
The supported size keywords for flex preferred/min/max sizes are the Ebox
subset `auto`, `min-content`, `max-content`, `fit-content`, `stretch`, and
`contain`; the max-size set also accepts `none`. `fit-content` may carry a
numeric or viewport-relative limit. These are Ebox layout values, not a claim
of full browser CSS compatibility.
### Grid
```elisp
(ebox-grid
:width '(640)
:grid-template-columns '((200) 1fr 1fr)
:grid-template-rows '(1 1)
:gap '(1 (12))
(ebox-grid-item
(ebox-create :content "Header")
:grid-column '(1 :span 3))
(ebox-create :content "Main" :grid-column 1 :grid-row 2)
(ebox-create :content "Aside" :grid-column 2 :grid-row 2))
```
`ebox-grid-fr` constructs a fractional track: `(ebox-grid-fr 2)` returns
`(fr 2)`. Grid tracks support fixed sizes, `auto`, fractional tracks written
as `(fr FACTOR)` or symbols such as `1fr`, `minmax`, and `repeat`. Omitted
positions use implicit tracks. `:grid-auto-columns`, `:grid-auto-rows`, and
`:grid-auto-flow` (`row` or `column`) control implicit placement.
Grid item placement is one-based. `:grid-column` and `:grid-row` accept a
positive start integer, `(start :span positive-integer)`, or `(start end)` with
`end` greater than `start`. `:grid-column-span` and `:grid-row-span` accept
positive integers. `ebox-grid-item` is a convenience wrapper; placement
properties may also be placed directly on a child node.
## 4. Units, box properties, and text properties
### Size units
| Value | Meaning |
| --- | --- |
| Ordinary horizontal number, e.g. `12` | Character columns, converted using the current display's space width. |
| One-element horizontal list, e.g. `'(240)` | Absolute pixels. |
| Vertical number, e.g. `3` | Lines. |
| `(viewport)` or `viewport` | Current viewport width in pixels. |
| `(viewport-height)` or `viewport-height` | Current viewport height in lines. |
| `auto`, `min-content`, `max-content`, `fit-content`, `stretch`, `contain` | Intrinsic/preferred width values where the property and formatting context support them. |
`:box-sizing` defaults to `border-box`; `content-box` is also supported.
Width values include `:width`, `:min-width`, and `:max-width`; height values
include `:height`, `:min-height`, and `:max-height`. Negative geometry is
rejected. A viewport-dependent node must be rendered with a viewport context
or rerendered with `ebox-rerender-buffer-with-context`.
### Box, paint, and text properties
The following names are inputs to `ebox-create`. Style rules accept the
style/geometry names in this table, while `ebox-region-update` accepts the
mutable content/style/scroll subset supported by its target. Direct updates do
not add children or change selector metadata; use `ebox-commit` or a logical
candidate for structural changes. Structural metadata, `:content`, and
`:surface-properties` are node/render inputs rather than stylesheet
declarations. Canonical logical names and compatibility aliases are shown
together.
| Area | Properties |
| --- | --- |
| Content/geometry | `:content`, `:box-sizing`, `:width`, `:min-width`, `:max-width`, `:height`, `:min-height`, `:max-height` |
| Padding | `:padding`, `:padding-inline`, `:padding-block`; longhands `:padding-block-start`, `:padding-inline-end`, `:padding-block-end`, `:padding-inline-start`; aliases `:padding-top`, `:padding-right`, `:padding-bottom`, `:padding-left` and the pixel/height aliases `:padding-right-pixel`, `:padding-left-pixel`, `:padding-top-height`, `:padding-bottom-height` |
| Margin | `:margin`, `:margin-inline`, `:margin-block`; longhands `:margin-block-start`, `:margin-inline-end`, `:margin-block-end`, `:margin-inline-start`; aliases `:margin-top`, `:margin-right`, `:margin-bottom`, `:margin-left` and the pixel/height aliases `:margin-right-pixel`, `:margin-left-pixel`, `:margin-top-height`, `:margin-bottom-height` |
| Border | `:border`, `:border-top`, `:border-right`, `:border-bottom`, `:border-left`, `:border-width`, `:border-style`, `:border-color`; side longhands `:border-*-width`, `:border-*-style`, `:border-*-color`; compatibility aliases `:border-top-p`, `:border-bottom-p`, `:border-left-pixel`, `:border-right-pixel` |
| Paint | `:color`, `:background-color`, and alias `:bgcolor` |
| Typography | `:font`, `:font-family`, `:font-height` and alias `:font-size`, `:font-weight`, `:font-slant` |
| Text/layout | `:text-align` (`left`, `center`, `right`), `:vertical-align` (`top`, `center`/`middle`, `bottom`), `:overflow` (`scroll`, `hidden`, `visible`), `:wrap-mode` (`word`, `char`, `kp`, or nil), `:visibility` (`visible` or `hidden`) |
| Structural style | `:display` is computed for node/layout contexts; the layout constructors normally choose the valid display tuple. |
| Flex container/item | `:flex-direction`, `:flex-wrap`, `:flex-flow`, `:justify-content`, `:align-items`, `:align-content`, `:gap`, `:row-gap`, `:column-gap` (aliases `:grid-row-gap`, `:grid-column-gap`); item names `:order`, `:flex`, `:flex-grow`, `:flex-shrink`, `:flex-basis`, `:align-self` |
| Grid container/item | `:grid-template-columns`, `:grid-template-rows`, `:grid-auto-columns`, `:grid-auto-rows`, `:grid-auto-flow`, `:justify-items`; item placement `:grid-column`, `:grid-row`, `:grid-column-span`, `:grid-row-span` |
| Extra text properties | `:surface-properties` accepts an even property list of Emacs text properties, applied to rendered characters without newlines. Inner non-nil properties win. |
Use `:font`, not `:face`, for the box font. `:font` accepts an Emacs face
symbol, a face name string, or a face plist; the typography longhands are
merged into that face. `:visibility 'hidden` suppresses ink while preserving
layout footprint and metadata. With `:overflow 'visible`, excess lines are
published as visible overflow; `hidden` clips them; `scroll` exposes a bounded
window and enables Ebox scrolling when content is taller than the box.
Padding and margin use CSS 14-value expansion. Horizontal entries use the
horizontal units above, while top/bottom entries use line units. Left/right
border widths are pixel geometry. Top/bottom borders use Emacs overline and
underline faces, so their width is a presence flag rather than arbitrary pixel
thickness.
### Node metadata and selector inputs
These inputs identify nodes without changing their geometry:
| Input | Meaning |
| --- | --- |
| `:id` | Logical selector/update id. Symbols and other scalar values are normalized to strings; an id should be unique where a direct update resolves it. |
| `:key` | Stable sibling identity used by reconciliation and also exposed as the built-in selector `:key` attribute. |
| `:class` | One class token or a list of class tokens for selector matching. |
| `:selector-state` | One state token or a list of state tokens matched by state pseudos such as `:hover` and `:active`. |
| `:selector-attributes` | Explicit attribute alist, such as `((role . button))`; content, layout values, and runtime fields are never inferred. |
| `:host-ref` | Unique application-owned opaque anchor for `ebox-host-ref-position`, `ebox-host-ref-bounds`, and host-ref candidate replacement. |
| `:scroll-offset` | Initial/controlled line offset for a scroll region. Prefer scroll commands for interaction; updates require a live region handle. |
`:id`, `:key`, and `:host-ref` are not stylesheet declarations. `:class`,
`:selector-state`, and `:selector-attributes` are selector metadata, not
general-purpose application state.
## 5. Stylesheets and cascade
Inline properties are enough for most nodes. For selector-driven styles, use
the isolated Ebox stylesheet:
```elisp
(ebox-style-reset-rules)
(ebox-style-add-rule
".card"
'(:color "#1F2937"
:background-color "#F8FAFC"
:padding '(1 (12)))
:layer 'base)
(ebox-style-add-rule
".card:has(> .warning)"
'(:border-color "#DC2626")
:layer 'state)
```
`ebox-style-add-rule` accepts a selector string or parsed AST, an Ebox
declaration plist, and the ECSS cascade keywords `:origin`, `:layer`, and
`:scope`. `ebox-style-reset-rules` clears the stylesheet. Rules are global to
the loaded Ebox style registry; changing rules does not silently publish an
already-mounted buffer, so rerender or commit the affected buffer after a
rule change. `ebox-style-cascade-active-p` reports whether rules are present.
The ECSS-backed style domain includes inheritance for color and typography,
computed values, cascade layers, custom-property declarations, and dirty
classification for paint/geometry/structure changes. Ebox interprets only the
properties listed in this reference; percentages, absolute positioning,
z-index, shadows, border radius, browser bidi, and full browser typography are
outside the package.
Custom properties whose names start with `--` may be carried by the ECSS style
domain, but they do not affect Ebox output unless a host integration resolves
them into one of the supported Ebox properties.
## 6. Rendering, identity, and updates
### Region ids and logical handles
`ebox-region-ids` returns region ids in document order from an unrendered tree
or rendered string. Capture ids before the first mount if a low-level source
mapping needs them:
```elisp
(let* ((root (ebox-column
(ebox-create :id "title" :content "Title")
(ebox-create :id "body" :content "Body")))
(ids (ebox-region-ids root)))
(ebox-render-to-buffer "*Ebox Demo*" root)
ids)
```
For application updates, prefer logical ids and opaque handles:
```elisp
(let ((handle (ebox-region-resolve "*Ebox Demo*" "body")))
(ebox-region-update handle :content "Changed" :color "#166534"))
```
`ebox-region-resolve` signals when the buffer is absent, the logical id is
missing, or the id is ambiguous. A handle is scoped to one retained TP
surface; it becomes stale when its object is removed or its buffer is killed.
Numeric region ids are render metadata and are not accepted by
`ebox-region-update`.
### Direct and selector updates
`ebox-region-update` accepts mutable content/style/scroll property keywords and
returns the committed update report unless an explicit batch queues it. It
builds an isolated candidate, plans the smallest safe Ebox owner, and asks TP
to publish once. It does not add children or mutate `:id`, `:class`, `:key`,
or other selector metadata. Invalid declarations, render failures, publication
failures, and callback failures leave the previous buffer/runtime/report intact.
`ebox-selector-update-buffer` applies properties to all editable selector
matches and returns:
```elisp
(:selector SELECTOR
:matched INTEGER
:updated INTEGER
:skipped ((:node-id ID :reason no-region) ...)
:reports (REPORT ...))
```
An explicit multi-update batch can use the lower-level incremental batch
functions only when an application deliberately owns that boundary; the
normal public alternative is `ebox-selector-update-buffer`.
### Logical candidates
Candidates are one-shot transactions based on the exact currently published
runtime. They are useful when several stable subtrees must be replaced before
one commit:
```elisp
(let* ((buffer (get-buffer "*Ebox Demo*"))
(candidate (ebox-candidate-begin buffer))
(match (car (ebox-selector-query-buffer buffer "#body"))))
(ebox-candidate-replace
candidate
(plist-get match :node-id)
(ebox-create :id "body" :content "Candidate replacement"))
(ebox-commit buffer candidate))
```
`ebox-candidate-replace-host-ref` uses an application-owned `:host-ref`
instead of a runtime node id. Both replacement functions accept optional
`old-semantic-key` and `new-semantic-key` pairs for bounded detached identity
reuse. A candidate is sealed by commit and cannot be reused; it also becomes
stale if the captured buffer runtime or buffer tick changes.
### Host-reference positions
```elisp
(ebox-host-ref-position "*Ebox Demo*" 'toolbar)
;; => first live character position, or nil
(ebox-host-ref-bounds "*Ebox Demo*" 'toolbar)
;; => (START . END), excluding margins, or nil
```
Positions and bounds belong to the current publication generation. Obtain new
values after any update. Ebox's host-reference table is distinct from logical
selector ids.
### Reports and viewport reflow
`ebox-buffer-update-report` returns a defensive copy of the last successful
report for a mounted buffer; it signals for a missing/non-Ebox buffer. A fresh
mount has no update report until its first update. Reports include the Ebox
strategy and publication scope plus TP surface revision and physical
operation/reconciliation facts.
Use `ebox-rerender-buffer-with-context` when a root depends on a new viewport:
```elisp
(ebox-rerender-buffer-with-context
(get-buffer "*Ebox Demo*")
800 ; viewport width in pixels
30) ; optional viewport height in lines
```
This preserves node/region identity and routes the change through viewport
dirty planning. `(viewport)` and `(viewport-height)` are resolved from this
context. For pure rendering, callers may instead bind `ebox-viewport-width`
in pixels and `ebox-viewport-height` in lines around the render. Do not mutate
a published node tree in place.
## 7. Selectors
`ebox-selector-parse` delegates to ECSS and returns its structured AST.
`ebox-selector-match-node-p` matches one declarative node against a selector
or AST. `ebox-selector-query-all` returns document-ordered matches from an
unmounted tree. `ebox-selector-query-buffer` queries the retained runtime of a
live buffer and adds `:buffer` and, when the node is editable, `:region-handle`
to each match record.
Supported selector syntax comes from ECSS:
- selector lists and compound type/id/class selectors;
- attribute presence and `=`, `~=`, `|=`, `^=`, `$=`, `*=` operators with `i`
and `s` flags;
- state pseudos such as `:hover` and `:active` through `:selector-state`;
- `:is(...)`, `:where(...)`, `:not(...)`, and relational `:has(...)`;
- descendant whitespace, child `>`, adjacent sibling `+`, and general sibling
`~` combinators.
Ebox node types are exposed as selector types `box`, `row`, `column`, `flex`,
`grid`, and `item`. `:id` and `:key` become built-in attributes. Additional
attributes must be supplied explicitly, for example
`:selector-attributes '((role . button))`; visible content, layout values,
and internal runtime slots are never inferred as selector attributes.
```elisp
(ebox-selector-query-buffer "*Ebox Demo*" ".toolbar > box.action")
(ebox-selector-query-buffer "*Ebox Demo*" "div:has(> .warning)")
(ebox-selector-update-buffer "*Ebox Demo*" "[role=button]"
:color "#2563EB")
```
The compatibility aliases `ebox-select-all` and `ebox-update-selector` refer
to `ebox-selector-query-buffer` and `ebox-selector-update-buffer`.
## 8. Scrolling and viewport state
Set `:overflow 'scroll` (the default) and a finite `:height` to create a
scroll window:
```elisp
(ebox-create
:id "log"
:width '(420)
:height 8
:overflow 'scroll
:content (mapconcat #'identity lines "\n"))
```
`ebox-scroll-down`, `ebox-scroll-up`, `ebox-scroll-page-down`, and
`ebox-scroll-page-up` operate on the innermost scroll region at point. They
delegate to ordinary Emacs scrolling when no Ebox region can consume the
command. `ebox-wheel-scroll-down` and `ebox-wheel-scroll-up` accept mouse
events, animate when `ebox-wheel-smooth-scroll` is non-nil, and otherwise
delegate to `mwheel-scroll`. `ebox-buffer-mode` installs `ebox-scroll-map`
locally; `ebox-render-to-buffer` enables the mode on its returned buffer.
`ebox-scroll-state` accepts a numeric region id and returns a read-only state
plist for source-model mapping. Its useful public facts include the current
`:scroll-offset`, content height/lines, and cached visible lines. Treat the
plist as diagnostic/read-only data; use `ebox-region-update` with
`:scroll-offset` or the scroll commands to change position.
Scroll content is lazily prefetched and can be rendered in bounded slices.
Ebox preserves cached scroll state across safe retained updates and rolls it
back with the rest of a failed publication.
## 9. Measurement and cache controls
`ebox-string-pixel-width` returns the first-line display pixel width of a
string, honoring text scale and fixed `display` spaces. It is the same public
measurement primitive used by layout. `ebox-display-signature` returns the
current display inputs used for measurement cache invalidation. Call
`ebox-clear-cache` after changing font or named-face metrics outside the normal
display-signature signals.
The main customization variables are:
| Group | Variables and defaults |
| --- | --- |
| Render cache | `ebox-render-cache-max-entries` 2048; `ebox-render-cache-max-bytes` 32 MiB; `ebox-render-root-cache-max-entries` 16; `ebox-render-root-cache-max-bytes` 8 MiB |
| Keyboard/mouse scroll | `ebox-scroll-step` 1; `ebox-wheel-scroll-step` 16; `ebox-wheel-smooth-scroll` t; `ebox-wheel-smooth-scroll-interval` 0.016; `ebox-wheel-smooth-scroll-lines-per-tick` 4; `ebox-wheel-smooth-scroll-target-ticks` 8 |
| Lazy scroll | `ebox-scroll-lazy-prefix-lookahead-lines` 8; `ebox-scroll-lazy-idle-prefetch-lines` 128; `ebox-scroll-lazy-idle-prefetch-slice-lines` 16; `ebox-scroll-lazy-idle-prefetch-delay` 0.15 |
| Runtime prewarm | `ebox-runtime-idle-prewarm` t; `ebox-runtime-idle-prewarm-delay` 0.1; `ebox-runtime-idle-prewarm-prefix-resume-delay` 2.0; `ebox-runtime-idle-prewarm-slice-size` 32 |
| Predicted reflow | `ebox-runtime-idle-reflow-cache-prewarm` t; `ebox-runtime-idle-reflow-cache-prewarm-delay` 0.15 |
| Reflow GC | `ebox-reflow-cache-prewarm-gc-cons-threshold` `auto`; `ebox-reflow-cache-prewarm-gc-auto-frame-budget` 0.2; `ebox-reflow-cache-prewarm-gc-auto-min-threshold` 64 MiB; `ebox-reflow-cache-prewarm-gc-auto-max-threshold` 1 GiB; `ebox-reflow-cache-prewarm-gc-auto-initial-threshold` 512 MiB; `ebox-reflow-cache-prewarm-gc-auto-target-layouts` 24; `ebox-reflow-cache-prewarm-gc-cons-percentage` 0.1 |
| Visual verification | `ebox-visual-check-output-dir` points to the temporary directory used for optional screenshots and reports. |
Idle prewarming never publishes buffer text or runtime state. Set the relevant
boolean to nil when a host application must avoid background preparation.
## 10. Standalone `.ebox` DSL
`ebox-build` compiles a data-oriented list form. Supported tags are `box` and
`ebox`, `row`, `column`, `flex`, `item`, `grid`, `grid-item`, and `spacer`:
```elisp
(ebox-build
'(grid :width (640)
:grid-template-columns ((200) 1fr 1fr)
:gap (1 (12))
(grid-item :grid-column (1 :span 3)
(box :content "Header"))
(box :content "Main")))
```
Strings directly under `box` become newline-joined content. Child forms become
a default vertical child layout. `row` and `column` can receive box
properties around their child layout. `flex` accepts container properties;
`item` accepts flex item properties and exactly one or more child forms;
`grid-item` requires exactly one child; `spacer` accepts no children.
Inside a `.ebox` file, keep structural forms unquoted. Quote list and symbol
constants in property positions when they are data, such as
`:gap '(1 (12))` or `:justify-content 'center`; executable Elisp expressions
remain unquoted for the sibling playground runner.
## 11. Optional Rust reflow
The native module is an accelerator, not a correctness dependency. Its Rust
boundary receives bounded numeric layout work only; Ebox keeps the Elisp path
as the exact fallback and never builds Rust while loading.
```elisp
(ebox-native-status) ; show toolchain, path, ABI, and load diagnosis
(ebox-native-build) ; asynchronous build/install
(ebox-native-build t) ; clean Ebox's private Cargo cache first
```
The equivalent repository command is `make native-build`. Configure
`ebox-native-reflow-module-path` with a module file or directory. Session
limits are `ebox-native-reflow-max-jobs` 512,
`ebox-native-reflow-max-results` 512, and
`ebox-native-reflow-max-result-bytes` 64 MiB. A missing or incompatible module
leaves Ebox on Elisp; `ebox-native-status` reports the reason.
`ebox-byte-compile` recompiles all active Ebox Elisp sources and does not build
Rust. Restart Emacs after a successful byte compilation if the current
process should load the new `.elc` files.
## 12. Public function inventory
The following table covers the public functions in the facade inventory. The
style-rule functions immediately below are public module-level style APIs.
| Function | Use |
| --- | --- |
| `ebox-create`, `ebox-build` | Create a node or compile the `.ebox` list DSL. |
| `ebox-concat`, `ebox-stack`, `ebox-row`, `ebox-column`, `ebox-spacer` | Compose simple horizontal/vertical layouts and blank boxes. |
| `ebox-flex`, `ebox-flex-item` | Build flex containers and item metadata. |
| `ebox-grid`, `ebox-grid-fr`, `ebox-grid-item` | Build Grid layouts, fractional tracks, and placement metadata. |
| `ebox-render`, `ebox-render-to-buffer`, `ebox-display-buffer` | Pure materialization, retained mount, and display wrapper. |
| `ebox-commit`, `ebox-buffer-update-report`, `ebox-rerender-buffer-with-context` | Atomic root commit, report lookup, and viewport-context rerender. |
| `ebox-region-ids`, `ebox-region-resolve`, `ebox-region-update` | Region mapping, logical handle lookup, and direct update. |
| `ebox-candidate-begin`, `ebox-candidate-replace`, `ebox-candidate-replace-host-ref` | One-shot logical candidate transactions. |
| `ebox-host-ref-bounds`, `ebox-host-ref-position` | Live host-reference bounds and first position. |
| `ebox-selector-parse`, `ebox-selector-match-node-p`, `ebox-selector-query-all`, `ebox-selector-query-buffer`, `ebox-selector-update-buffer` | ECSS selector compilation, matching, querying, and batch update. |
| `ebox-select-all`, `ebox-update-selector` | Compatibility aliases for the two buffer selector functions. |
| `ebox-buffer-mode`, `ebox-scroll-map`, `ebox-scroll-down`, `ebox-scroll-up`, `ebox-scroll-page-down`, `ebox-scroll-page-up`, `ebox-wheel-scroll-down`, `ebox-wheel-scroll-up`, `ebox-scroll-state` | Interactive scrolling, local keymap, and read-only scroll state. |
| `ebox-string-pixel-width`, `ebox-display-signature`, `ebox-clear-cache` | Display-aware measurement and cache management. |
| `ebox-native-build`, `ebox-native-status`, `ebox-byte-compile` | Optional native workflow and Elisp byte compilation. |
Style-rule and style inspection entry points available after `(require 'ebox)`
include `ebox-style-add-rule`, `ebox-style-reset-rules`,
`ebox-style-cascade-active-p`, `ebox-style-compute`,
`ebox-style-expand-shorthands`, `ebox-style-compile-declarations`,
`ebox-style-merge-declarations`, `ebox-style-compute-subject`,
`ebox-style-property`, `ebox-style-canonical-name`, and
`ebox-style-dirty-kind`. The first two are the normal application entry
points; the remaining helpers are for integrations that need to inspect or
prepare ECSS-backed style data.
## 13. Verification and support boundary
From the repository root:
```sh
make load EMACS=/Applications/Emacs.app/Contents/MacOS/Emacs
make compile EMACS=/Applications/Emacs.app/Contents/MacOS/Emacs
make check EMACS=/Applications/Emacs.app/Contents/MacOS/Emacs
make docs-contract-tests EMACS=/Applications/Emacs.app/Contents/MacOS/Emacs
make native-rust-tests
```
Focused targets include `make core-tests`, `make grid-tests`,
`make surface-tests`, `make selector-tests`, `make dsl-tests`,
`make flex-tests`, and `make visual-check-tests`. The sibling
`ebox-playground` package owns runnable example fixtures; ETAF owns
Components, state, controls, and application behavior. Do not call private
`ebox--*` functions or edit the historical `emacs-box` checkout as part of
this package.

View File

@ -0,0 +1,519 @@
# Ebox 公共 API 参考
[English](ebox-api-reference.en.md)
本文是独立 Ebox 包面向用户的完整清单覆盖节点模型、property、布局
辅助函数、渲染/发布、selector、滚动、测量、DSL 和可选 native 模块。
`ebox--*` 名称与没有在本文说明的模块辅助函数属于实现细节。加载
`(require 'ebox)` 后,也可以通过 `ebox-public-api` 查看门面入口清单。
Ebox 负责 box node、样式归一化、测量、布局、渲染、语义更新规划、selector
适配、Grid 和可选 Rust reflow 加速器。TP 负责 live buffer 发布、物理 diff、
revision 和 rollbackECSS 负责 selector 解析、匹配与 cascade。Ebox 不提供
Component、应用状态、UI control 或应用生命周期。
## 1. 安装与加载
Ebox 需要 Emacs 29.1 或更新版本,以及 ECSS 和 TP。使用同级源码 checkout
```elisp
(add-to-list 'load-path "/path/to/github/ecss")
(add-to-list 'load-path "/path/to/github/tp")
(add-to-list 'load-path "/path/to/github/ebox")
(require 'ebox)
```
加载 Ebox 会加载 Elisp 布局/runtime 模块,但不会创建 buffer、在当前 buffer
启用 mode、构建 Rust 或修改当前编辑 buffer。可选 native 模块只在其工作流
或合资格的 native 路径需要时加载。
## 2. 常规生命周期
公共工作流如下:
```elisp
(let ((root
(ebox-column
(ebox-create :id "status" :content "Ready" :width '(240))
(ebox-create :content "调用者拥有的 source tree"))))
;; 纯 materialization返回多行带属性字符串。
(ebox-render root)
;; retained TP surface返回 live buffer。
(ebox-render-to-buffer "*Ebox Demo*" root)
;; 后续构造新的声明式根树并原子发布。
(ebox-commit
"*Ebox Demo*"
(ebox-column
(ebox-create :id "status" :content "Updated" :width '(240))
(ebox-create :content "未修改调用者的 source tree。"))))
```
`ebox-render` 不产生 live buffer 副作用。没有 active stylesheet 和 inline
继承样式依赖的静态树可以使用隔离的 pure materialization依赖 stylesheet
的 pure render 使用临时 TP materialization。两者都遵守同一个公共字符串
契约。两个 buffer 入口都使用 retained TP surface。Ebox 会在分配 runtime
identity 前复制声明式输入,因此同一 source tree 可以挂载到多个 buffer。
`ebox-display-buffer` 是同时需要展示 buffer 时的便捷包装;它会先删除其他
window再切换到渲染后的 buffer。如果窗口选择由调用方负责应使用
`ebox-render-to-buffer`
## 3. 节点与组合
### Box 与简单布局构造器
```elisp
(ebox-create &rest properties)
(ebox-concat node-1 node-2) ; 两个节点横向排列
(ebox-stack node-1 node-2) ; 两个节点纵向排列
(ebox-row &rest nodes) ; 多个节点横向排列
(ebox-column &rest nodes) ; 多个节点纵向排列
(ebox-spacer &rest properties) ; 空白 box
```
`ebox-create` 返回声明式 box node。`:content` 是字符串内容;容器子节点通常
交给 `ebox-row`、`ebox-column`、`ebox-flex` 或 `ebox-grid`。`ebox-concat` 和
`ebox-stack` 接受两个节点;超过两个子节点时使用 row/column。nil 子节点会
被忽略;空 row/column 会变成 spacer。
`:key` 是兄弟节点范围内的稳定业务 identity`:id` 是 logical selector/update
标识;`:host-ref` 是应用拥有的不透明锚点,用于 host-reference 查询和逻辑
candidate replacement。一个 source tree 内的非 nil host-ref 必须唯一。
### Flex
```elisp
(ebox-flex
:width '(480)
:flex-flow '(row wrap)
:gap '(1 (12))
(ebox-flex-item (ebox-create :content "A")
:flex '(1 1 auto)
:align-self 'center)
(ebox-create :content "B" :flex-grow 2))
```
容器 property 是 `:flex-direction`、`:flex-wrap`、`:flex-flow`、
`:justify-content`、`:align-items`、`:align-content`、`:gap`、`:row-gap` 和
`:column-gap`,另加 `:width`、`:height`、padding、border、paint 等普通 box
property。默认方向是 row、nowrap主轴是 flex-start交叉轴是 stretch。
item property 是 `:order`、`:flex`、`:flex-grow`、`:flex-shrink`、`:flex-basis`
`:align-self`。它们可以直接放在 child box 上,也可以通过
`ebox-flex-item` 附加。传给 `ebox-flex-item` 的非 item property 会在 child
外包一层普通 box。
Flex preferred/min/max size 支持 Ebox 子集:`auto`、`min-content`、
`max-content`、`fit-content`、`stretch`、`contain`max-size 还支持
`none`。`fit-content` 可以带数字或 viewport 相对限制。这些是 Ebox 布局值,
不表示完整浏览器 CSS 兼容性。
### Grid
```elisp
(ebox-grid
:width '(640)
:grid-template-columns '((200) 1fr 1fr)
:grid-template-rows '(1 1)
:gap '(1 (12))
(ebox-grid-item
(ebox-create :content "Header")
:grid-column '(1 :span 3))
(ebox-create :content "Main" :grid-column 1 :grid-row 2)
(ebox-create :content "Aside" :grid-column 2 :grid-row 2))
```
`ebox-grid-fr` 构造分数轨道:`(ebox-grid-fr 2)` 返回 `(fr 2)`。Grid 轨道支持
固定尺寸、`auto`、`(fr FACTOR)`、`1fr` 这样的 symbol、`minmax` 和 `repeat`
没有显式给出的行列使用隐式轨道;`:grid-auto-columns`、`:grid-auto-rows`
`:grid-auto-flow``row` 或 `column`)控制隐式放置。
Grid placement 从 1 开始。`:grid-column` 和 `:grid-row` 接受正整数起点、
`(start :span 正整数)`,或 `start` 小于 `end``(start end)`
`:grid-column-span``:grid-row-span` 接受正整数。`ebox-grid-item` 是便捷
包装器placement property 也可以直接放在 child node 上。
## 4. 单位、box property 与文本属性
### 尺寸单位
| 值 | 含义 |
| --- | --- |
| 普通横向数字,例如 `12` | 字符列数,按当前 display 的空格宽度转换。 |
| 单元素横向 list例如 `'(240)` | 绝对像素。 |
| 纵向数字,例如 `3` | 行数。 |
| `(viewport)``viewport` | 当前 viewport 的像素宽度。 |
| `(viewport-height)``viewport-height` | 当前 viewport 的行高。 |
| `auto`、`min-content`、`max-content`、`fit-content`、`stretch`、`contain` | 在对应 property 与 formatting context 支持时使用 intrinsic/preferred width。 |
`:box-sizing` 默认是 `border-box`,也支持 `content-box`。宽度 property 是
`:width`、`:min-width`、`:max-width`;高度 property 是 `:height`
`:min-height`、`:max-height`。几何负值会被拒绝。依赖 viewport 的节点要在
viewport context 中渲染,或通过 `ebox-rerender-buffer-with-context` 重排。
### Box、paint 与文本 property
以下名称可用于 `ebox-create`。Stylesheet 规则使用其中的 style/geometry
property`ebox-region-update` 接受其目标支持的可变 content/style/scroll
子集。Direct update 不会添加 child 或修改 selector metadata结构变化使用
`ebox-commit` 或 logical candidate。结构 metadata、`:content` 和
`:surface-properties` 是节点/render 输入,不是 stylesheet declaration。表中
同时列出 canonical 名称与兼容别名。
| 范围 | Property |
| --- | --- |
| Content/geometry | `:content`、`:box-sizing`、`:width`、`:min-width`、`:max-width`、`:height`、`:min-height`、`:max-height` |
| Padding | `:padding`、`:padding-inline`、`:padding-block`longhand `:padding-block-start`、`:padding-inline-end`、`:padding-block-end`、`:padding-inline-start`;别名 `:padding-top`、`:padding-right`、`:padding-bottom`、`:padding-left`,以及 `:padding-right-pixel`、`:padding-left-pixel`、`:padding-top-height`、`:padding-bottom-height` |
| Margin | `:margin`、`:margin-inline`、`:margin-block`longhand `:margin-block-start`、`:margin-inline-end`、`:margin-block-end`、`:margin-inline-start`;别名 `:margin-top`、`:margin-right`、`:margin-bottom`、`:margin-left`,以及 `:margin-right-pixel`、`:margin-left-pixel`、`:margin-top-height`、`:margin-bottom-height` |
| Border | `:border`、`:border-top`、`:border-right`、`:border-bottom`、`:border-left`、`:border-width`、`:border-style`、`:border-color`side longhand `:border-*-width`、`:border-*-style`、`:border-*-color`;兼容别名 `:border-top-p`、`:border-bottom-p`、`:border-left-pixel`、`:border-right-pixel` |
| Paint | `:color`、`:background-color` 和别名 `:bgcolor` |
| Typography | `:font`、`:font-family`、`:font-height` 和别名 `:font-size`、`:font-weight`、`:font-slant` |
| Text/layout | `:text-align``left`、`center`、`right`)、`:vertical-align``top`、`center`/`middle`、`bottom`)、`:overflow``scroll`、`hidden`、`visible`)、`:wrap-mode``word`、`char`、`kp` 或 nil、`:visibility``visible` 或 `hidden` |
| Structural style | `:display` 会在 node/layout context 中计算;有效的 display tuple 通常由布局构造器选择。 |
| Flex container/item | `:flex-direction`、`:flex-wrap`、`:flex-flow`、`:justify-content`、`:align-items`、`:align-content`、`:gap`、`:row-gap`、`:column-gap`(别名 `:grid-row-gap`、`:grid-column-gap`item 名称 `:order`、`:flex`、`:flex-grow`、`:flex-shrink`、`:flex-basis`、`:align-self` |
| Grid container/item | `:grid-template-columns`、`:grid-template-rows`、`:grid-auto-columns`、`:grid-auto-rows`、`:grid-auto-flow`、`:justify-items`item placement `:grid-column`、`:grid-row`、`:grid-column-span`、`:grid-row-span` |
| 额外文本属性 | `:surface-properties` 接受偶数长度的 Emacs text-property plist应用到不含换行的渲染字符内层非 nil 属性优先。 |
Box 字体入口是 `:font`,不是 `:face`。`:font` 接受 Emacs face symbol、face
名称字符串或 face plisttypography longhand 会合并到该 face。`:visibility
'hidden` 会隐藏 ink但保留布局 footprint 与 metadata。`:overflow 'visible`
会发布超出高度的可见行;`hidden` 会裁剪;`scroll` 暴露有限窗口,并在内容
高于 box 时启用 Ebox 滚动。
Padding 与 margin 使用 CSS 的 14 值展开。横向值使用上述横向单位,顶部和
底部使用行单位。左右 border 是像素几何;上下 border 通过 Emacs overline/
underline face 实现,因此宽度是存在性标志而非任意像素厚度。
### Node metadata 与 selector 输入
这些输入用于标识节点,不会直接改变几何:
| 输入 | 含义 |
| --- | --- |
| `:id` | logical selector/update id。symbol 和其他标量会归一化为字符串;直接 update 解析时应保持 id 唯一。 |
| `:key` | reconciliation 使用的稳定兄弟 identity同时作为内建 selector `:key` attribute 暴露。 |
| `:class` | 一个 class token 或 class token 列表,用于 selector matching。 |
| `:selector-state` | 一个 state token 或 state token 列表,用于匹配 `:hover`、`:active` 等 state pseudo。 |
| `:selector-attributes` | 显式 attribute alist例如 `((role . button))`content、布局值和 runtime 字段不会自动推断。 |
| `:host-ref` | 应用拥有的唯一不透明 anchor用于 `ebox-host-ref-position`、`ebox-host-ref-bounds` 和 host-ref candidate replacement。 |
| `:scroll-offset` | scroll region 的初始/受控行偏移。交互优先使用滚动命令update 必须使用 live region handle。 |
`:id`、`:key` 和 `:host-ref` 不是 stylesheet declaration。`:class`、
`:selector-state``:selector-attributes` 是 selector metadata不是通用
应用状态。
## 5. Stylesheet 与 cascade
多数节点只需 inline property。需要 selector 驱动样式时使用隔离的 Ebox
stylesheet
```elisp
(ebox-style-reset-rules)
(ebox-style-add-rule
".card"
'(:color "#1F2937"
:background-color "#F8FAFC"
:padding '(1 (12)))
:layer 'base)
(ebox-style-add-rule
".card:has(> .warning)"
'(:border-color "#DC2626")
:layer 'state)
```
`ebox-style-add-rule` 接受 selector string 或 AST、Ebox declaration plist
以及 ECSS cascade 关键字 `:origin`、`:layer`、`:scope`。
`ebox-style-reset-rules` 清空 stylesheet。规则属于已加载的全局 Ebox style
registry改变规则不会自动发布已有 mounted buffer因此规则变化后要对
目标 buffer rerender 或 commit。`ebox-style-cascade-active-p` 可检查当前
是否存在规则。
基于 ECSS 的 style domain 包含 color 与 typography inheritance、computed
value、cascade layer、custom-property declaration以及 paint/geometry/
structure dirty 分类。Ebox 只解释本文列出的 property百分比、绝对定位、
z-index、阴影、border radius、浏览器级 bidi 和完整浏览器 typography 不属于
本包。
名称以 `--` 开头的 custom property 可以由 ECSS style domain 携带,但除非宿主
集成把它解析为本文支持的 Ebox property否则不会影响 Ebox 输出。
## 6. 渲染、identity 与更新
### Region id 与 logical handle
`ebox-region-ids` 会从未渲染树或已渲染字符串按文档顺序返回 region id。需要
低层 source 映射时,在第一次 mount 前捕获:
```elisp
(let* ((root (ebox-column
(ebox-create :id "title" :content "Title")
(ebox-create :id "body" :content "Body")))
(ids (ebox-region-ids root)))
(ebox-render-to-buffer "*Ebox Demo*" root)
ids)
```
应用更新优先使用 logical id 与不透明 handle
```elisp
(let ((handle (ebox-region-resolve "*Ebox Demo*" "body")))
(ebox-region-update handle :content "Changed" :color "#166534"))
```
`ebox-region-resolve` 在 buffer 不存在、logical id 缺失或 id 有歧义时发出
错误。Handle 绑定一个 retained TP surface对象移除或 buffer kill 后会 stale。
数字 region id 是渲染 metadata不能作为 `ebox-region-update` 的参数。
### Direct 与 selector 更新
`ebox-region-update` 接受可变 content/style/scroll property 关键字;除非处于
显式 batch否则返回已提交的 update report。它先构造隔离 candidate规划
最小安全 Ebox owner再请求 TP 发布一次。它不会添加 child也不会修改
`:id`、`:class`、`:key` 或其他 selector metadata。非法 declaration、render
失败、publication 失败或 callback 失败都会保留原 buffer/runtime/report。
`ebox-selector-update-buffer` 把 property 应用到 buffer 中所有可编辑的
selector match返回
```elisp
(:selector SELECTOR
:matched INTEGER
:updated INTEGER
:skipped ((:node-id ID :reason no-region) ...)
:reports (REPORT ...))
```
显式多更新 batch 只有在应用确实拥有该边界时才使用较低层 incremental batch
函数;一般场景使用 `ebox-selector-update-buffer`
### Logical candidate
Candidate 是基于当前已发布 runtime 的一次性 transaction。多个稳定 subtree
需要一起替换并只提交一次时使用:
```elisp
(let* ((buffer (get-buffer "*Ebox Demo*"))
(candidate (ebox-candidate-begin buffer))
(match (car (ebox-selector-query-buffer buffer "#body"))))
(ebox-candidate-replace
candidate
(plist-get match :node-id)
(ebox-create :id "body" :content "Candidate replacement"))
(ebox-commit buffer candidate))
```
`ebox-candidate-replace-host-ref` 使用应用拥有的 `:host-ref`,不需要 runtime
node id。两个 replacement 函数都接受可选的 `old-semantic-key`
`new-semantic-key`,用于有限的 detached identity 复用。Candidate 在 commit
时 sealed不能复用若捕获的 runtime 或 buffer tick 发生变化,它也会 stale。
### Host-reference 位置
```elisp
(ebox-host-ref-position "*Ebox Demo*" 'toolbar)
;; => 第一个 live 字符位置,或 nil
(ebox-host-ref-bounds "*Ebox Demo*" 'toolbar)
;; => (START . END),不含 margin或 nil
```
位置与 bounds 属于当前 publication generation每次更新后都要重新获取。
Host-reference table 与 logical selector id 是两套不同的机制。
### Report 与 viewport reflow
`ebox-buffer-update-report` 返回 mounted buffer 上一次成功报告的 defensive
copy目标缺失或不是 Ebox runtime 时会报错。首次 mount 在第一次 update
前没有 update report。报告包含 Ebox strategy、publication scope、TP surface
revision、物理 operation 和 reconciliation 事实。
当 root 依赖新的 viewport 时使用 `ebox-rerender-buffer-with-context`
```elisp
(ebox-rerender-buffer-with-context
(get-buffer "*Ebox Demo*")
800 ; viewport 像素宽度
30) ; 可选 viewport 行高
```
该调用保留 node/region identity并通过 viewport dirty planning 处理变化。
`(viewport)``(viewport-height)` 从该 context 解析。纯渲染时也可以在
render 外部动态绑定 `ebox-viewport-width`(像素)与 `ebox-viewport-height`
(行数)。不要原地修改已经发布的 node tree。
## 7. Selector
`ebox-selector-parse` 委托 ECSS 并返回结构化 AST
`ebox-selector-match-node-p` 匹配单个声明式节点;`ebox-selector-query-all`
从未 mounted tree 返回按文档顺序的 match`ebox-selector-query-buffer` 查询
live buffer 的 retained runtime并给每条 match 添加 `:buffer`,可编辑节点
还会添加 `:region-handle`
ECSS 支持的 selector 语法包括:
- selector list、compound type/id/class selector
- attribute presence 与 `=`、`~=`、`|=`、`^=`、`$=`、`*=`,以及 `i`/`s` flag
- 通过 `:selector-state` 提供的 `:hover`、`:active` 等 state pseudo
- `:is(...)`、`:where(...)`、`:not(...)` 与 relational `:has(...)`
- 空格 descendant、子节点 `>`、相邻兄弟 `+`、一般兄弟 `~` combinator。
Ebox 的 node type 会映射为 selector type`box`、`row`、`column`、`flex`、
`grid`、`item`。`:id` 与 `:key` 是内建 attribute额外 attribute 必须显式
传入,例如 `:selector-attributes '((role . button))`。可见 content、布局
值和内部 runtime slot 不会被推断成 selector attribute。
```elisp
(ebox-selector-query-buffer "*Ebox Demo*" ".toolbar > box.action")
(ebox-selector-query-buffer "*Ebox Demo*" "div:has(> .warning)")
(ebox-selector-update-buffer "*Ebox Demo*" "[role=button]"
:color "#2563EB")
```
兼容别名 `ebox-select-all``ebox-update-selector` 分别指向
`ebox-selector-query-buffer``ebox-selector-update-buffer`
## 8. 滚动与 viewport state
设置 `:overflow 'scroll`(默认值)和有限的 `:height` 创建滚动窗口:
```elisp
(ebox-create
:id "log"
:width '(420)
:height 8
:overflow 'scroll
:content (mapconcat #'identity lines "\n"))
```
`ebox-scroll-down`、`ebox-scroll-up`、`ebox-scroll-page-down` 和
`ebox-scroll-page-up` 操作 point 所在的最内层滚动区域;找不到可消费该命令
的 Ebox region 时委托普通 Emacs scrolling。`ebox-wheel-scroll-down` 与
`ebox-wheel-scroll-up` 接受 mouse event`ebox-wheel-smooth-scroll` 非 nil
时会分步动画,否则委托 `mwheel-scroll`。`ebox-buffer-mode` 在本地安装
`ebox-scroll-map``ebox-render-to-buffer` 会在返回的 buffer 上启用该 mode。
`ebox-scroll-state` 接受数字 region id返回用于 source-model 映射的只读
state plist。可用事实包括 `:scroll-offset`、content height/lines 与缓存的
visible lines。把 plist 当作 diagnostic/read-only 数据;用
`ebox-region-update``:scroll-offset` 或滚动命令改变位置。
Scroll content 会惰性预取,并按有界 slice 渲染。安全的 retained update 会
保留缓存 scroll state发布失败时它与其他 runtime 状态一起 rollback。
## 9. 测量与缓存配置
`ebox-string-pixel-width` 返回字符串第一行的 display 像素宽度,同时考虑
text scale 和固定 `display` space它也是布局使用的公共测量原语。
`ebox-display-signature` 返回测量缓存使用的当前 display 输入。
如果在正常 display-signature 信号之外修改了字体或 named face可调用
`ebox-clear-cache`
主要 customization 变量如下:
| 分组 | 变量与默认值 |
| --- | --- |
| Render cache | `ebox-render-cache-max-entries` 2048`ebox-render-cache-max-bytes` 32 MiB`ebox-render-root-cache-max-entries` 16`ebox-render-root-cache-max-bytes` 8 MiB |
| 键盘/鼠标滚动 | `ebox-scroll-step` 1`ebox-wheel-scroll-step` 16`ebox-wheel-smooth-scroll` t`ebox-wheel-smooth-scroll-interval` 0.016`ebox-wheel-smooth-scroll-lines-per-tick` 4`ebox-wheel-smooth-scroll-target-ticks` 8 |
| Lazy scroll | `ebox-scroll-lazy-prefix-lookahead-lines` 8`ebox-scroll-lazy-idle-prefetch-lines` 128`ebox-scroll-lazy-idle-prefetch-slice-lines` 16`ebox-scroll-lazy-idle-prefetch-delay` 0.15 |
| Runtime prewarm | `ebox-runtime-idle-prewarm` t`ebox-runtime-idle-prewarm-delay` 0.1`ebox-runtime-idle-prewarm-prefix-resume-delay` 2.0`ebox-runtime-idle-prewarm-slice-size` 32 |
| 预测 reflow | `ebox-runtime-idle-reflow-cache-prewarm` t`ebox-runtime-idle-reflow-cache-prewarm-delay` 0.15 |
| Reflow GC | `ebox-reflow-cache-prewarm-gc-cons-threshold` `auto``ebox-reflow-cache-prewarm-gc-auto-frame-budget` 0.2`ebox-reflow-cache-prewarm-gc-auto-min-threshold` 64 MiB`ebox-reflow-cache-prewarm-gc-auto-max-threshold` 1 GiB`ebox-reflow-cache-prewarm-gc-auto-initial-threshold` 512 MiB`ebox-reflow-cache-prewarm-gc-auto-target-layouts` 24`ebox-reflow-cache-prewarm-gc-cons-percentage` 0.1 |
| Visual verification | `ebox-visual-check-output-dir` 指向可选 screenshot/report 使用的临时目录。 |
Idle prewarm 不会发布 buffer text 或 runtime state。宿主应用不希望后台准备
工作时,可把对应的 boolean 设为 nil。
## 10. 独立 `.ebox` DSL
`ebox-build` 编译数据型 list form。支持的 tag 是 `box`/`ebox`、`row`、
`column`、`flex`、`item`、`grid`、`grid-item` 和 `spacer`
```elisp
(ebox-build
'(grid :width (640)
:grid-template-columns ((200) 1fr 1fr)
:gap (1 (12))
(grid-item :grid-column (1 :span 3)
(box :content "Header"))
(box :content "Main")))
```
`box` 下的直接字符串会合并为换行内容child form 会变成默认纵向 child
layout。`row` 与 `column` 可以接收 box property 并包住 child layout`flex`
接收容器 property`item` 接收 flex item property`grid-item` 必须有一个
child`spacer` 不能有 child。
`.ebox` 文件中,结构 form 保持不加 quoteproperty 位置的 list 和 symbol
常量要作为 data quote例如 `:gap '(1 (12))``:justify-content 'center`
要执行的 Elisp property expression 保持不 quote交给同级 playground runner
求值。
## 11. 可选 Rust reflow
Native 模块是加速器不是正确性的依赖。Rust 边界只接收有界的数值布局工作;
Ebox 保留完全等价的 Elisp fallback加载时绝不构建 Rust。
```elisp
(ebox-native-status) ; 显示 toolchain、路径、ABI 与加载诊断
(ebox-native-build) ; 异步构建/安装
(ebox-native-build t) ; 先清理 Ebox 私有 Cargo cache
```
仓库命令是 `make native-build`。使用 `ebox-native-reflow-module-path` 配置
module 文件或目录。Session 限制为 `ebox-native-reflow-max-jobs` 512、
`ebox-native-reflow-max-results` 512、`ebox-native-reflow-max-result-bytes`
64 MiB。模块缺失或 ABI 不兼容时继续使用 Elisp原因可由
`ebox-native-status` 查看。
`ebox-byte-compile` 会重新编译所有 active Ebox Elisp 源码,但不会构建 Rust。
成功后如需当前进程加载新的 `.elc`,请重启 Emacs。
## 12. 公共函数清单
下表覆盖门面清单中的公共函数;其下列出的 style-rule 函数是模块级公共
style API。
| 函数 | 用途 |
| --- | --- |
| `ebox-create`、`ebox-build` | 创建节点或编译 `.ebox` list DSL。 |
| `ebox-concat`、`ebox-stack`、`ebox-row`、`ebox-column`、`ebox-spacer` | 组合简单横向/纵向布局与空白 box。 |
| `ebox-flex`、`ebox-flex-item` | 构建 Flex 容器与 item metadata。 |
| `ebox-grid`、`ebox-grid-fr`、`ebox-grid-item` | 构建 Grid、分数轨道和 placement metadata。 |
| `ebox-render`、`ebox-render-to-buffer`、`ebox-display-buffer` | 纯 materialization、retained mount 与展示包装。 |
| `ebox-commit`、`ebox-buffer-update-report`、`ebox-rerender-buffer-with-context` | 原子根提交、报告查询和 viewport-context rerender。 |
| `ebox-region-ids`、`ebox-region-resolve`、`ebox-region-update` | Region 映射、logical handle 查询与直接更新。 |
| `ebox-candidate-begin`、`ebox-candidate-replace`、`ebox-candidate-replace-host-ref` | 一次性 logical candidate transaction。 |
| `ebox-host-ref-bounds`、`ebox-host-ref-position` | Host-reference 的 live bounds 与首位置。 |
| `ebox-selector-parse`、`ebox-selector-match-node-p`、`ebox-selector-query-all`、`ebox-selector-query-buffer`、`ebox-selector-update-buffer` | ECSS selector 编译、匹配、查询与批量更新。 |
| `ebox-select-all`、`ebox-update-selector` | 两个 buffer selector 函数的兼容别名。 |
| `ebox-buffer-mode`、`ebox-scroll-map`、`ebox-scroll-down`、`ebox-scroll-up`、`ebox-scroll-page-down`、`ebox-scroll-page-up`、`ebox-wheel-scroll-down`、`ebox-wheel-scroll-up`、`ebox-scroll-state` | 交互滚动、本地 keymap 与只读滚动状态。 |
| `ebox-string-pixel-width`、`ebox-display-signature`、`ebox-clear-cache` | Display-aware 测量与缓存管理。 |
| `ebox-native-build`、`ebox-native-status`、`ebox-byte-compile` | 可选 native 工作流与 Elisp byte compile。 |
加载 `(require 'ebox)` 后可用的 style inspection/rule 入口还包括
`ebox-style-add-rule`、`ebox-style-reset-rules`、
`ebox-style-cascade-active-p`、`ebox-style-compute`、
`ebox-style-expand-shorthands`、`ebox-style-compile-declarations`、
`ebox-style-merge-declarations`、`ebox-style-compute-subject`、
`ebox-style-property`、`ebox-style-canonical-name` 和
`ebox-style-dirty-kind`。前两个是应用通常使用的入口;其余函数供需要检查
或准备 ECSS-backed style data 的集成使用。
## 13. 验证与支持边界
在仓库根目录运行:
```sh
make load EMACS=/Applications/Emacs.app/Contents/MacOS/Emacs
make compile EMACS=/Applications/Emacs.app/Contents/MacOS/Emacs
make check EMACS=/Applications/Emacs.app/Contents/MacOS/Emacs
make docs-contract-tests EMACS=/Applications/Emacs.app/Contents/MacOS/Emacs
make native-rust-tests
```
聚焦目标包括 `make core-tests`、`make grid-tests`、`make surface-tests`、
`make selector-tests`、`make dsl-tests`、`make flex-tests` 和
`make visual-check-tests`。可运行的 `.ebox` 示例由同级 `ebox-playground`
包负责ETAF 负责 Component、state、control 和应用行为。本包不要调用
私有 `ebox--*` 函数,也不要在 Ebox 任务中编辑历史 `emacs-box` checkout。

View File

@ -1,6 +1,6 @@
# Ebox user guide
Ebox is the low-level box, layout, and buffer-rendering package. Use it directly when an application needs precise geometry or use it as the rendering substrate below ETAF. This guide intentionally does not introduce Components, reactive state, behaviors, or application data.
Ebox is the low-level box, layout, and buffer-rendering package. Use it directly when an application needs precise geometry or use it as the rendering substrate below ETAF. This guide intentionally does not introduce Components, reactive state, behaviors, or application data. For the complete function/property/configuration inventory, see the [public API reference](ebox-api-reference.en.md).
## 1. Load the package
@ -18,7 +18,7 @@ Loading defines the public package and its pure layout modules. It does not crea
```elisp
(ebox-column
(ebox-create :content "Title"
:face 'bold
:font 'bold
:color "#263244"
:bgcolor "#F4F6FB"
:padding '(1 2))
@ -27,7 +27,10 @@ Loading defines the public package and its pure layout modules. It does not crea
(ebox-create :content "Right" :width 12)))
```
The public shape is data, not rendered text. A node may contain `:content`, `:ebox-content-node`, or child nodes supplied to a container. Use `:key` when siblings have stable application identity and `:host-ref` when an application needs a public handle position after rendering.
The public shape is data, not rendered text. A node may contain string
`:content` or child nodes supplied to a container helper; wrapper bookkeeping
stays internal. Use `:key` when siblings have stable application identity and
`:host-ref` when an application needs a public handle position after rendering.
## 3. Dimensions and surface properties
@ -44,7 +47,20 @@ Ordinary horizontal numbers are character columns. A one-element list denotes a
:bgcolor "#FFFFFF")
```
Keep foreground and background explicit on tinted surfaces. `:face` may be a face symbol or a face plist; use `:color` and `:bgcolor` when the surface itself carries semantic colors.
Keep foreground and background explicit on tinted surfaces. `:font` may be a face symbol or a face plist; use `:color` and `:bgcolor` when the surface itself carries semantic colors. `:font-family`, `:font-height`/`:font-size`, `:font-weight`, and `:font-slant` are the supported typography longhands.
### Stylesheet rules
Inline properties are compiled by Ebox's ECSS-backed style domain. Selector-driven rules use the isolated stylesheet:
```elisp
(ebox-style-reset-rules)
(ebox-style-add-rule ".card"
'(:color "#1F2937" :padding '(1 (12)))
:layer 'base)
```
Rules use ECSS cascade semantics, including `:origin`, `:layer`, and `:scope`. A rule change does not publish an already-mounted buffer automatically; rerender or commit the affected buffer after changing rules. See the [API reference](ebox-api-reference.en.md#5-stylesheets-and-cascade) for the complete property schema.
## 4. Row, column, flex, and Grid
@ -110,15 +126,38 @@ Selectors query the rendered tree and return public match records. They do not o
The same logical id in two buffers resolves to two different handles, so updating one surface cannot accidentally mutate the other. A handle becomes stale when its retained object is removed or its buffer is killed. `ebox-region-update` accepts only a live handle; numeric region ids are internal render metadata and are not an update API.
`ebox-selector-parse` compiles CSS-like strings directly to ECSS's structured selector AST. Queries support type, `#id`, `.class`, `[key=value]`, descendant whitespace, child `>`, adjacent sibling `+`, and general sibling `~`. Ebox maps logical children and indexed candidates to ECSS subjects; `ecss-selector-match-p` is the only final matcher, so query and cascade semantics cannot diverge. Attribute selectors see built-in `:id`/`:key` plus metadata explicitly supplied through `:selector-attributes`, for example `:selector-attributes '((role . button))`; visible content, layout properties, Ebox runtime containers, and internal `:ebox-*` slots never become selector attributes implicitly.
`ebox-selector-parse` compiles CSS-like strings directly to ECSS's structured selector AST. Queries support selector lists, type, `#id`, `.class`, attribute presence and `=`, `~=`, `|=`, `^=`, `$=`, `*=` operators, state pseudos, `:is()`, `:where()`, `:not()`, `:has()`, descendant whitespace, child `>`, adjacent sibling `+`, and general sibling `~`. Ebox maps logical children and indexed candidates to ECSS subjects; `ecss-selector-match-p` is the only final matcher, so query and cascade semantics cannot diverge. Attribute selectors see built-in `:id`/`:key` plus metadata explicitly supplied through `:selector-attributes`, for example `:selector-attributes '((role . button))`; visible content, layout properties, Ebox runtime containers, and internal `:ebox-*` slots never become selector attributes implicitly.
```elisp
(ebox-selector-query-buffer "*Ebox Demo*" ".toolbar > box.action")
(ebox-selector-query-buffer "*Ebox Demo*" "#first + .later")
(ebox-selector-query-buffer "*Ebox Demo*" "#first ~ [role=button]")
(ebox-selector-update-buffer "*Ebox Demo*" ".action" :color "#2563EB")
```
## 8. Standalone `.ebox` files
`ebox-selector-update-buffer` returns `:matched`, `:updated`, structured `:skipped`, and `:reports` fields. The compatibility aliases `ebox-select-all` and `ebox-update-selector` refer to the query and update functions.
## 8. Scroll and viewport context
Give a box `:overflow 'scroll` (the default) and a finite `:height` to create a scroll window:
```elisp
(ebox-create :id "log" :width '(420) :height 8
:overflow 'scroll
:content (mapconcat #'identity lines "\n"))
```
`ebox-scroll-down`, `ebox-scroll-up`, `ebox-scroll-page-down`, and `ebox-scroll-page-up` operate on the innermost Ebox scroll region at point and fall back to Emacs scrolling when no Ebox region can consume the command. `ebox-wheel-scroll-down` and `ebox-wheel-scroll-up` consume mouse events for Ebox regions and otherwise delegate to `mwheel-scroll`. `ebox-buffer-mode` installs `ebox-scroll-map` locally; `ebox-render-to-buffer` enables it on its returned buffer. `ebox-scroll-state` exposes read-only scroll facts for a numeric region id; use scroll commands or `ebox-region-update` with `:scroll-offset` to change position.
Viewport-dependent values use `(viewport)` and `(viewport-height)`. Rerender a mounted buffer with an explicit context:
```elisp
(ebox-rerender-buffer-with-context (get-buffer "*Ebox Demo*") 800 30)
```
The call preserves node and region identity. The [API reference](ebox-api-reference.en.md#8-scrolling-and-viewport-state) lists lazy prefix, idle prefetch, cache, and scroll customization variables.
## 9. Standalone `.ebox` files
`ebox-build` reads one data-oriented Ebox form:
@ -136,15 +175,15 @@ Inside a `.ebox` fixture, keep the structural form unquoted. Quote list and symb
Executable `.ebox` references are maintained by the sibling [`ebox-playground`](../../ebox-playground/README.md) package. Its `examples/` directory contains the migrated Basic, Comprehensive, Flex, Responsive, and complete Grid reference files; they remain low-level layout examples and do not require the ETAF framework.
## 9. Optional native reflow
## 10. Optional native reflow
The Rust module accelerates eligible reflow work; it is not required for correctness. Load Ebox normally, run `make native-build` when you want a local module, and configure `ebox-native-reflow-module-path` if the module is outside its default location. Ebox keeps the Elisp path as the exact fallback and never builds native code while loading.
The Rust module accelerates eligible reflow work; it is not required for correctness. Load Ebox normally, run `make native-build` when you want a local module, and configure `ebox-native-reflow-module-path` if the module is outside its default location. Ebox keeps the Elisp path as the exact fallback and never builds native code while loading. `ebox-native-status` shows toolchain, module, ABI, and load diagnosis; `ebox-native-build` starts an asynchronous build and accepts a prefix argument for a clean private Cargo cache rebuild.
## 10. Public boundary
## 11. Public boundary
Use public `ebox-*` functions and constructors. Names beginning with `ebox--` are private implementation details and may change. ETAF is the sibling package for Components, View trees, state, behavior, Context, data, and application lifecycle; Ebox should stay focused on geometry and publication.
Use the functions and properties listed in the [public API reference](ebox-api-reference.en.md) and the `ebox-public-api` facade inventory. Names beginning with `ebox--` are private implementation details and may change. ETAF is the sibling package for Components, View trees, state, behavior, Context, data, and application lifecycle; Ebox should stay focused on geometry and publication.
## 11. Verification
## 12. Verification
From the repository root:
@ -152,6 +191,7 @@ From the repository root:
make load EMACS=/Applications/Emacs.app/Contents/MacOS/Emacs
make compile EMACS=/Applications/Emacs.app/Contents/MacOS/Emacs
make check EMACS=/Applications/Emacs.app/Contents/MacOS/Emacs
make docs-contract-tests EMACS=/Applications/Emacs.app/Contents/MacOS/Emacs
```
Use `make grid-tests`, `make dsl-tests`, or `make visual-check-tests` for focused changes. Use `make native-rust-tests` after changing the native module.
Use `make grid-tests`, `make dsl-tests`, `make selector-tests`, `make surface-tests`, or `make visual-check-tests` for focused changes. Use `make native-rust-tests` after changing the native module.

View File

@ -1,6 +1,6 @@
# Ebox 用户指南
Ebox 是底层的 box、布局和 buffer 渲染包。当应用需要精确几何时可以直接使用,也可以作为 ETAF 下方的渲染基座。本指南不引入 Component、响应式状态、behavior 或应用数据。
Ebox 是底层的 box、布局和 buffer 渲染包。当应用需要精确几何时可以直接使用,也可以作为 ETAF 下方的渲染基座。本指南不引入 Component、响应式状态、behavior 或应用数据。完整的函数、property、配置清单见[公共 API 参考](ebox-api-reference.zh.md)。
## 1. 加载包
@ -18,7 +18,7 @@ Ebox 是底层的 box、布局和 buffer 渲染包。当应用需要精确几何
```elisp
(ebox-column
(ebox-create :content "Title"
:face 'bold
:font 'bold
:color "#263244"
:bgcolor "#F4F6FB"
:padding '(1 2))
@ -27,7 +27,9 @@ Ebox 是底层的 box、布局和 buffer 渲染包。当应用需要精确几何
(ebox-create :content "Right" :width 12)))
```
公共形状是数据,而不是已渲染文本。节点可以有 `:content`、`:ebox-content-node`,或由容器接收的子节点。兄弟节点具有稳定业务 identity 时使用 `:key`;应用需要在渲染后查询公开位置时使用 `:host-ref`
公共形状是数据,而不是已渲染文本。节点可以有字符串 `:content`,或由容器
辅助函数接收的子节点wrapper bookkeeping 保持内部。兄弟节点具有稳定业务
identity 时使用 `:key`;应用需要在渲染后查询公开位置时使用 `:host-ref`
## 3. 尺寸与表面属性
@ -44,7 +46,20 @@ Ebox 是底层的 box、布局和 buffer 渲染包。当应用需要精确几何
:bgcolor "#FFFFFF")
```
带色背景的 surface 要显式设置前景色与背景色。`:face` 可以是 face symbol 或 face plist当 surface 本身承载语义颜色时,优先使用 `:color``:bgcolor`
带色背景的 surface 要显式设置前景色与背景色。`:font` 可以是 face symbol 或 face plist当 surface 本身承载语义颜色时,优先使用 `:color``:bgcolor`。支持的 typography longhand 是 `:font-family`、`:font-height`/`:font-size`、`:font-weight` 和 `:font-slant`
### Stylesheet 规则
Inline property 会由 Ebox 的 ECSS-backed style domain 编译。需要 selector 驱动规则时使用隔离的 stylesheet
```elisp
(ebox-style-reset-rules)
(ebox-style-add-rule ".card"
'(:color "#1F2937" :padding '(1 (12)))
:layer 'base)
```
规则使用 ECSS cascade 语义,包括 `:origin`、`:layer` 和 `:scope`。改变规则不会自动发布已经 mounted 的 buffer规则变更后要对目标 buffer rerender 或 commit。完整 property schema 见[公共 API 参考](ebox-api-reference.zh.md)。
## 4. row、column、flex 与 Grid
@ -110,15 +125,39 @@ Selector 查询已渲染的树并返回公共匹配记录,但不拥有应用
两个 buffer 中相同的逻辑 id 会解析为两个不同 handle因此更新一个 surface 不会误改另一个。retained object 被删除或 buffer 被 kill 后,原 handle 会变 stale。`ebox-region-update` 只接受 live handle数字 region id 只是内部渲染元数据,不是更新 API。
`ebox-selector-parse` 会把 CSS-like 字符串直接编译成 ECSS 的结构化 selector AST。查询支持 type、`#id`、`.class`、`[key=value]`、空格 descendant、子节点 `>`、相邻兄弟 `+` 和一般兄弟 `~`。Ebox 只负责把逻辑子节点关系与索引候选映射成 ECSS subject最终匹配统一由 `ecss-selector-match-p` 决定,因此 query 与 cascade 不会产生两套语义。属性 selector 只看内建的 `:id`/`:key`,以及通过 `:selector-attributes` 显式传入的元数据,例如 `:selector-attributes '((role . button))`;可见 content、布局属性、Ebox runtime 容器与内部 `:ebox-*` 槽位绝不会被隐式转换成 selector 属性。
`ebox-selector-parse` 会把 CSS-like 字符串直接编译成 ECSS 的结构化 selector AST。查询支持 selector list、type、`#id`、`.class`、attribute presence 与 `=`、`~=`、`|=`、`^=`、`$=`、`*=` 操作符、state pseudo、`:is()`、`:where()`、`:not()`、`:has()`、空格 descendant、子节点 `>`、相邻兄弟 `+` 和一般兄弟 `~`。Ebox 只负责把逻辑子节点关系与索引候选映射成 ECSS subject最终匹配统一由 `ecss-selector-match-p` 决定,因此 query 与 cascade 不会产生两套语义。属性 selector 只看内建的 `:id`/`:key`,以及通过 `:selector-attributes` 显式传入的元数据,例如 `:selector-attributes '((role . button))`;可见 content、布局属性、Ebox runtime 容器与内部 `:ebox-*` 槽位绝不会被隐式转换成 selector 属性。
```elisp
(ebox-selector-query-buffer "*Ebox Demo*" ".toolbar > box.action")
(ebox-selector-query-buffer "*Ebox Demo*" "#first + .later")
(ebox-selector-query-buffer "*Ebox Demo*" "#first ~ [role=button]")
(ebox-selector-update-buffer "*Ebox Demo*" ".action" :color "#2563EB")
```
## 8. 独立 `.ebox` 文件
`ebox-selector-update-buffer` 返回 `:matched`、`:updated`、结构化 `:skipped``:reports`。兼容别名 `ebox-select-all``ebox-update-selector` 分别指向 query 和 update 函数。
## 8. Scroll 与 viewport context
给 box 设置 `:overflow 'scroll`(默认值)和有限的 `:height` 创建 scroll window
```elisp
(ebox-create :id "log" :width '(420) :height 8
:overflow 'scroll
:content (mapconcat #'identity lines "\n"))
```
`ebox-scroll-down`、`ebox-scroll-up`、`ebox-scroll-page-down` 和
`ebox-scroll-page-up` 操作 point 所在的最内层 Ebox scroll region没有可消费命令的 Ebox region 时回退到 Emacs scrolling。`ebox-wheel-scroll-down` 与 `ebox-wheel-scroll-up` 为 Ebox region 消费 mouse event否则委托 `mwheel-scroll`。`ebox-buffer-mode` 本地安装 `ebox-scroll-map``ebox-render-to-buffer` 会在返回的 buffer 上启用它。`ebox-scroll-state` 为数字 region id 提供只读 scroll facts使用滚动命令或 `ebox-region-update``:scroll-offset` 改变位置。
Viewport 值使用 `(viewport)``(viewport-height)`。mounted buffer 要用显式 context 重排:
```elisp
(ebox-rerender-buffer-with-context (get-buffer "*Ebox Demo*") 800 30)
```
该调用保留 node 与 region identity。[公共 API 参考](ebox-api-reference.zh.md)列出了 lazy prefix、idle prefetch、cache 和滚动配置变量。
## 9. 独立 `.ebox` 文件
`ebox-build` 读取一个面向数据的 Ebox form
@ -136,15 +175,15 @@ Selector 查询已渲染的树并返回公共匹配记录,但不拥有应用
可执行的 `.ebox` 参考文件由同级 [`ebox-playground`](../../ebox-playground/README.md) 包维护。它的 `examples/` 目录包含迁移后的 Basic、Comprehensive、Flex、Responsive 以及完整 Grid 参考文件;这些文件只演示低层布局,不依赖 ETAF。
## 9. 可选 native reflow
## 10. 可选 native reflow
Rust 模块用于加速符合条件的 reflow但不是正确性的前提。正常加载 Ebox需要本地模块时运行 `make native-build`,若模块不在默认位置则配置 `ebox-native-reflow-module-path`。Ebox 保留完全等价的 Elisp 路径,并且加载时不会自动构建 native。
Rust 模块用于加速符合条件的 reflow但不是正确性的前提。正常加载 Ebox需要本地模块时运行 `make native-build`,若模块不在默认位置则配置 `ebox-native-reflow-module-path`。Ebox 保留完全等价的 Elisp 路径,并且加载时不会自动构建 native。`ebox-native-status` 显示 toolchain、module、ABI 与加载诊断;`ebox-native-build` 异步构建,并接受 prefix argument 以清理私有 Cargo cache 后重建。
## 10. 公共边界
## 11. 公共边界
使用公共的 `ebox-*` 函数与构造器。以 `ebox--` 开头的名称是私有实现细节可能随时变化。ETAF 是同级包,负责 Component、View 树、状态、behavior、Context、data 和应用生命周期Ebox 应保持对几何与发布的专注。
使用[公共 API 参考](ebox-api-reference.zh.md)和 `ebox-public-api` 门面清单中列出的函数与 property。以 `ebox--` 开头的名称是私有实现细节可能随时变化。ETAF 是同级包,负责 Component、View 树、状态、behavior、Context、data 和应用生命周期Ebox 应保持对几何与发布的专注。
## 11. 验证
## 12. 验证
在仓库根目录运行:
@ -152,6 +191,7 @@ Rust 模块用于加速符合条件的 reflow但不是正确性的前提。
make load EMACS=/Applications/Emacs.app/Contents/MacOS/Emacs
make compile EMACS=/Applications/Emacs.app/Contents/MacOS/Emacs
make check EMACS=/Applications/Emacs.app/Contents/MacOS/Emacs
make docs-contract-tests EMACS=/Applications/Emacs.app/Contents/MacOS/Emacs
```
局部修改可先运行 `make grid-tests`、`make dsl-tests` 或 `make visual-check-tests`;修改 native 模块后运行 `make native-rust-tests`
局部修改可先运行 `make grid-tests`、`make dsl-tests`、`make selector-tests`、`make surface-tests``make visual-check-tests`;修改 native 模块后运行 `make native-rust-tests`

View File

@ -25,7 +25,7 @@
"ebox-incremental" (buffer))
(declare-function ebox-incremental-begin-batch "ebox-incremental" (buffer))
(declare-function ebox-incremental-flush "ebox-incremental" (buffer))
(declare-function ebox-region-update "ebox" (region-id &rest props))
(declare-function ebox-region-update "ebox" (handle &rest props))
(cl-defstruct
(ebox-region-handle

42
ebox.el
View File

@ -3640,10 +3640,11 @@ REGION-ID and CHANGED-KEYS describe one update; CHANGES describes a batch."
(defun ebox-region-update (handle &rest props)
"Update the box identified by surface-scoped HANDLE with PROPS.
HANDLE must come from ebox-region-resolve or an Ebox selector result. PROPS
accepts the same shorthand and longhand keywords as ebox-create. The update
builds an isolated candidate, runs the Ebox owner planner, and publishes once
through the mounted TP surface. Return nil while queued in an explicit batch;
otherwise return the committed update report.
accepts mutable content, style, and scroll keywords supported by the target;
it does not add children or mutate selector metadata. The update builds an
isolated candidate, runs the Ebox owner planner, and publishes once through the
mounted TP surface. Return nil while queued in an explicit batch; otherwise
return the committed update report.
Examples:
(ebox-region-update (ebox-region-resolve buffer \"status\")
@ -3920,11 +3921,18 @@ through dirty-set and patch-set execution before falling back to root rerender."
ebox-concat
ebox-create
ebox-display-buffer
ebox-display-signature
ebox-flex
ebox-flex-item
ebox-grid
ebox-grid-fr
ebox-grid-item
ebox-host-ref-bounds
ebox-host-ref-position
ebox-native-build
ebox-native-status
ebox-region-ids
ebox-region-resolve
ebox-region-update
ebox-render
ebox-render-to-buffer
@ -3944,10 +3952,15 @@ through dirty-set and patch-set execution before falling back to root rerender."
ebox-selector-update-buffer
ebox-spacer
ebox-stack
ebox-string-pixel-width
ebox-update-selector
ebox-wheel-scroll-down
ebox-wheel-scroll-up)
"Stable core Ebox entry points available to applications and tooling.")
"Stable core Ebox entry points available to applications and tooling.
This inventory includes the public autoloaded constructors, render/update
commands, selector/scroll helpers, measurement accessors, Grid helpers, and
optional native workflow commands. Style-rule helpers live in `ebox-style.el'
and are documented separately in the public API reference.")
(defconst ebox-feature-families
'(box-model
@ -3975,9 +3988,10 @@ through dirty-set and patch-set execution before falling back to root rerender."
;;; ============================================================
;;; Public API Summary
;;; ============================================================
;; The following functions form the stable public interface of ebox.
;; All other ebox-- prefixed functions are internal implementation
;; details and may change without notice.
;; The complete facade inventory is `ebox-public-api'. Style-rule entry points
;; are defined in `ebox-style.el' and the user-facing inventory is maintained
;; in `docs/user/ebox-api-reference.en.md` and its Chinese counterpart.
;; All other ebox-- prefixed functions are internal implementation details.
;;
;; ── Creation ──────────────────────────────────────────────────
;; ebox-create &rest plist
@ -4019,14 +4033,10 @@ through dirty-set and patch-set execution before falling back to root rerender."
;; call BEFORE render-to-buffer
;;
;; ── Dynamic Updates (call inside with-current-buffer + inhibit-read-only) ──
;; ebox-region-update region-id &rest props
;; Single entry-point for all dynamic changes. PROPS keywords mirror
;; those of ebox-create:
;; :content STRING
;; :width SIZE :padding-left SIZE :padding-right SIZE …
;; :border-color COLOR :border-top-color COLOR …
;; :bgcolor COLOR
;; Multiple keywords may be combined in one call.
;; ebox-region-update handle &rest props
;; Single entry-point for all dynamic changes. HANDLE comes from
;; ebox-region-resolve or a selector match's :region-handle field;
;; numeric region ids are not update handles.
;;
;; ── Scroll ────────────────────────────────────────────────────
;; ebox-scroll-up &optional n

View File

@ -9,6 +9,7 @@
(defconst ebox-docs-test--current-docs
'("AGENTS.md" "README.md" "README.zh-CN.md" "DESIGN.md" "DESIGN.zh.md"
"docs/user/ebox-user-guide.en.md" "docs/user/ebox-user-guide.zh.md"
"docs/user/ebox-api-reference.en.md" "docs/user/ebox-api-reference.zh.md"
"docs/maintainer/ebox-current-implementation-reference.en.md"
"docs/maintainer/ebox-current-implementation-reference.zh.md"
"docs/maintainer/ebox-incremental-update-contract.en.md"
@ -72,6 +73,8 @@
"Every long-lived user and maintainer document should have both languages."
(dolist (pair '(("docs/user/ebox-user-guide.en.md"
"docs/user/ebox-user-guide.zh.md")
("docs/user/ebox-api-reference.en.md"
"docs/user/ebox-api-reference.zh.md")
("docs/maintainer/ebox-current-implementation-reference.en.md"
"docs/maintainer/ebox-current-implementation-reference.zh.md")
("docs/maintainer/ebox-incremental-update-contract.en.md"
@ -79,6 +82,17 @@
(dolist (file pair)
(should (file-exists-p (expand-file-name file ebox-docs-test--root))))))
(ert-deftest ebox-docs-public-api-reference-covers-facade ()
"The bilingual API references should name every facade entry point."
(require 'ebox)
(dolist (file '("docs/user/ebox-api-reference.en.md"
"docs/user/ebox-api-reference.zh.md"))
(let ((source (ebox-docs-test--read file)))
(dolist (entry ebox-public-api)
(should (string-match-p
(regexp-quote (format "`%s`" entry))
source))))))
(ert-deftest ebox-docs-do-not-present-legacy-source-as-active ()
"The standalone package documentation must not claim ETAF source ownership."
(dolist (file ebox-docs-test--current-docs)

View File

@ -156,6 +156,53 @@
(regexp-quote (car entry)))
source)))))
(ert-deftest ebox-public-api-includes-all-public-autoloaded-entry-points ()
"The facade inventory should not omit an autoloaded public entry point."
(dolist (entry '(ebox-byte-compile
ebox-buffer-update-report
ebox-build
ebox-buffer-mode
ebox-candidate-begin
ebox-candidate-replace
ebox-candidate-replace-host-ref
ebox-clear-cache
ebox-column
ebox-commit
ebox-concat
ebox-create
ebox-display-buffer
ebox-display-signature
ebox-flex
ebox-flex-item
ebox-grid
ebox-grid-fr
ebox-grid-item
ebox-host-ref-bounds
ebox-host-ref-position
ebox-native-build
ebox-native-status
ebox-region-ids
ebox-region-resolve
ebox-region-update
ebox-render
ebox-render-to-buffer
ebox-rerender-buffer-with-context
ebox-row
ebox-scroll-down
ebox-scroll-page-down
ebox-scroll-page-up
ebox-scroll-state
ebox-scroll-up
ebox-selector-match-node-p
ebox-selector-parse
ebox-selector-query-all
ebox-selector-query-buffer
ebox-selector-update-buffer
ebox-spacer
ebox-stack
ebox-string-pixel-width))
(should (memq entry ebox-public-api))))
(ert-deftest ebox-live-buffer-publication-uses-only-tp-surfaces ()
"The facade should expose no raw live-buffer writer beside TP surfaces."
(require 'ebox)