docs(ebox): align public API and usage references
This commit is contained in:
parent
3dc0706af9
commit
972126e239
@ -22,15 +22,15 @@ node tree
|
|||||||
-> pure TP surface plan
|
-> 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
|
## 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
|
## 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
|
## Verification rule
|
||||||
|
|
||||||
|
|||||||
@ -22,15 +22,15 @@ Ebox 是底层空间渲染引擎。它负责把声明式节点树转换为经过
|
|||||||
-> 纯 TP surface plan
|
-> 纯 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 不属于本包。
|
||||||
|
|
||||||
## 验证规则
|
## 验证规则
|
||||||
|
|
||||||
|
|||||||
@ -22,7 +22,7 @@ ECSS and TP are independent packages and may be installed in either order. Insta
|
|||||||
:bgcolor "#F4F6FB")))
|
: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.
|
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 |
|
| Path | Responsibility |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `ebox.el` | Public facade and package entry point. |
|
| `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-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-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. |
|
| `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.
|
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.
|
||||||
|
|||||||
@ -22,7 +22,7 @@ ECSS 与 TP 是互相独立的包,安装顺序任意。两者都安装后再
|
|||||||
:bgcolor "#F4F6FB")))
|
: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。
|
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.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-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-buffer-backend.el`、`ebox-incremental.el` | Render-string backend 与 Ebox 增量规划。 |
|
||||||
| `ebox-dsl.el`、`ebox-selector.el` | 独立 DSL 与基于 ECSS 的树/runtime 查询。 |
|
| `ebox-dsl.el`、`ebox-selector.el` | 独立 DSL 与基于 ECSS 的树/runtime 查询。 |
|
||||||
| `ebox-native-reflow.el`、`native/` | 可选 native reflow 边界。 |
|
| `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`。
|
小范围修改先运行对应目标(例如 `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)。
|
||||||
|
|||||||
@ -7,9 +7,10 @@ This is the maintainer entry point for the standalone Ebox repository. It descri
|
|||||||
1. Read `AGENTS.md` for repository rules.
|
1. Read `AGENTS.md` for repository rules.
|
||||||
2. Read `README.md` for installation and the public boundary.
|
2. Read `README.md` for installation and the public boundary.
|
||||||
3. Read `docs/user/ebox-user-guide.en.md` for public construction patterns.
|
3. Read `docs/user/ebox-user-guide.en.md` for public construction patterns.
|
||||||
4. Read this document for ownership and verification.
|
4. Read `docs/user/ebox-api-reference.en.md` for the complete public function/property/configuration inventory.
|
||||||
5. Read `docs/maintainer/ebox-incremental-update-contract.en.md` before changing publication or patch planning.
|
5. Read this document for ownership and verification.
|
||||||
6. Read `docs/maintainer/ebox-performance-architecture-analysis.en.md` before changing performance, retained surfaces, or incremental data flow.
|
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
|
## Active source map
|
||||||
|
|
||||||
@ -86,7 +87,7 @@ Caller-owned Source Tree
|
|||||||
|
|
||||||
## Grid contract
|
## 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
|
## Active examples and tests
|
||||||
|
|
||||||
|
|||||||
@ -7,9 +7,10 @@
|
|||||||
1. 先读 `AGENTS.md` 了解仓库规则。
|
1. 先读 `AGENTS.md` 了解仓库规则。
|
||||||
2. 读 `README.md` 了解安装和公共边界。
|
2. 读 `README.md` 了解安装和公共边界。
|
||||||
3. 读 `docs/user/ebox-user-guide.zh.md` 了解公共构造方式。
|
3. 读 `docs/user/ebox-user-guide.zh.md` 了解公共构造方式。
|
||||||
4. 读本文了解所有权和验证方式。
|
4. 读 `docs/user/ebox-api-reference.zh.md` 了解完整的公共函数/property/配置清单。
|
||||||
5. 修改发布或 patch 规划前,读 `docs/maintainer/ebox-incremental-update-contract.zh.md`。
|
5. 读本文了解所有权和验证方式。
|
||||||
6. 修改性能、retained surface 或增量数据流前,读 `docs/maintainer/ebox-performance-architecture-analysis.zh.md`。
|
6. 修改发布或 patch 规划前,读 `docs/maintainer/ebox-incremental-update-contract.zh.md`。
|
||||||
|
7. 修改性能、retained surface 或增量数据流前,读 `docs/maintainer/ebox-performance-architecture-analysis.zh.md`。
|
||||||
|
|
||||||
## Active 源码清单
|
## Active 源码清单
|
||||||
|
|
||||||
@ -86,7 +87,7 @@ active 合同还覆盖 `Makefile`、`.github/workflows/ci.yml`、`tests/ebox-cor
|
|||||||
|
|
||||||
## Grid 合同
|
## 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 示例与测试
|
## Active 示例与测试
|
||||||
|
|
||||||
|
|||||||
567
docs/user/ebox-api-reference.en.md
Normal file
567
docs/user/ebox-api-reference.en.md
Normal 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 1–4-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.
|
||||||
519
docs/user/ebox-api-reference.zh.md
Normal file
519
docs/user/ebox-api-reference.zh.md
Normal 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 和 rollback;ECSS 负责 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 plist;typography longhand 会合并到该 face。`:visibility
|
||||||
|
'hidden` 会隐藏 ink,但保留布局 footprint 与 metadata。`:overflow 'visible`
|
||||||
|
会发布超出高度的可见行;`hidden` 会裁剪;`scroll` 暴露有限窗口,并在内容
|
||||||
|
高于 box 时启用 Ebox 滚动。
|
||||||
|
|
||||||
|
Padding 与 margin 使用 CSS 的 1–4 值展开。横向值使用上述横向单位,顶部和
|
||||||
|
底部使用行单位。左右 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 保持不加 quote;property 位置的 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。
|
||||||
@ -1,6 +1,6 @@
|
|||||||
# Ebox user guide
|
# 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
|
## 1. Load the package
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ Loading defines the public package and its pure layout modules. It does not crea
|
|||||||
```elisp
|
```elisp
|
||||||
(ebox-column
|
(ebox-column
|
||||||
(ebox-create :content "Title"
|
(ebox-create :content "Title"
|
||||||
:face 'bold
|
:font 'bold
|
||||||
:color "#263244"
|
:color "#263244"
|
||||||
:bgcolor "#F4F6FB"
|
:bgcolor "#F4F6FB"
|
||||||
:padding '(1 2))
|
: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)))
|
(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
|
## 3. Dimensions and surface properties
|
||||||
|
|
||||||
@ -44,7 +47,20 @@ Ordinary horizontal numbers are character columns. A one-element list denotes a
|
|||||||
:bgcolor "#FFFFFF")
|
: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
|
## 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.
|
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
|
```elisp
|
||||||
(ebox-selector-query-buffer "*Ebox Demo*" ".toolbar > box.action")
|
(ebox-selector-query-buffer "*Ebox Demo*" ".toolbar > box.action")
|
||||||
(ebox-selector-query-buffer "*Ebox Demo*" "#first + .later")
|
(ebox-selector-query-buffer "*Ebox Demo*" "#first + .later")
|
||||||
(ebox-selector-query-buffer "*Ebox Demo*" "#first ~ [role=button]")
|
(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:
|
`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.
|
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:
|
From the repository root:
|
||||||
|
|
||||||
@ -152,6 +191,7 @@ From the repository root:
|
|||||||
make load EMACS=/Applications/Emacs.app/Contents/MacOS/Emacs
|
make load EMACS=/Applications/Emacs.app/Contents/MacOS/Emacs
|
||||||
make compile 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 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.
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
# Ebox 用户指南
|
# Ebox 用户指南
|
||||||
|
|
||||||
Ebox 是底层的 box、布局和 buffer 渲染包。当应用需要精确几何时可以直接使用,也可以作为 ETAF 下方的渲染基座。本指南不引入 Component、响应式状态、behavior 或应用数据。
|
Ebox 是底层的 box、布局和 buffer 渲染包。当应用需要精确几何时可以直接使用,也可以作为 ETAF 下方的渲染基座。本指南不引入 Component、响应式状态、behavior 或应用数据。完整的函数、property、配置清单见[公共 API 参考](ebox-api-reference.zh.md)。
|
||||||
|
|
||||||
## 1. 加载包
|
## 1. 加载包
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ Ebox 是底层的 box、布局和 buffer 渲染包。当应用需要精确几何
|
|||||||
```elisp
|
```elisp
|
||||||
(ebox-column
|
(ebox-column
|
||||||
(ebox-create :content "Title"
|
(ebox-create :content "Title"
|
||||||
:face 'bold
|
:font 'bold
|
||||||
:color "#263244"
|
:color "#263244"
|
||||||
:bgcolor "#F4F6FB"
|
:bgcolor "#F4F6FB"
|
||||||
:padding '(1 2))
|
:padding '(1 2))
|
||||||
@ -27,7 +27,9 @@ Ebox 是底层的 box、布局和 buffer 渲染包。当应用需要精确几何
|
|||||||
(ebox-create :content "Right" :width 12)))
|
(ebox-create :content "Right" :width 12)))
|
||||||
```
|
```
|
||||||
|
|
||||||
公共形状是数据,而不是已渲染文本。节点可以有 `:content`、`:ebox-content-node`,或由容器接收的子节点。兄弟节点具有稳定业务 identity 时使用 `:key`;应用需要在渲染后查询公开位置时使用 `:host-ref`。
|
公共形状是数据,而不是已渲染文本。节点可以有字符串 `:content`,或由容器
|
||||||
|
辅助函数接收的子节点;wrapper bookkeeping 保持内部。兄弟节点具有稳定业务
|
||||||
|
identity 时使用 `:key`;应用需要在渲染后查询公开位置时使用 `:host-ref`。
|
||||||
|
|
||||||
## 3. 尺寸与表面属性
|
## 3. 尺寸与表面属性
|
||||||
|
|
||||||
@ -44,7 +46,20 @@ Ebox 是底层的 box、布局和 buffer 渲染包。当应用需要精确几何
|
|||||||
:bgcolor "#FFFFFF")
|
: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
|
## 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。
|
两个 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
|
```elisp
|
||||||
(ebox-selector-query-buffer "*Ebox Demo*" ".toolbar > box.action")
|
(ebox-selector-query-buffer "*Ebox Demo*" ".toolbar > box.action")
|
||||||
(ebox-selector-query-buffer "*Ebox Demo*" "#first + .later")
|
(ebox-selector-query-buffer "*Ebox Demo*" "#first + .later")
|
||||||
(ebox-selector-query-buffer "*Ebox Demo*" "#first ~ [role=button]")
|
(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:
|
`ebox-build` 读取一个面向数据的 Ebox form:
|
||||||
|
|
||||||
@ -136,15 +175,15 @@ Selector 查询已渲染的树并返回公共匹配记录,但不拥有应用
|
|||||||
|
|
||||||
可执行的 `.ebox` 参考文件由同级 [`ebox-playground`](../../ebox-playground/README.md) 包维护。它的 `examples/` 目录包含迁移后的 Basic、Comprehensive、Flex、Responsive 以及完整 Grid 参考文件;这些文件只演示低层布局,不依赖 ETAF。
|
可执行的 `.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 load EMACS=/Applications/Emacs.app/Contents/MacOS/Emacs
|
||||||
make compile 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 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`。
|
||||||
|
|||||||
@ -25,7 +25,7 @@
|
|||||||
"ebox-incremental" (buffer))
|
"ebox-incremental" (buffer))
|
||||||
(declare-function ebox-incremental-begin-batch "ebox-incremental" (buffer))
|
(declare-function ebox-incremental-begin-batch "ebox-incremental" (buffer))
|
||||||
(declare-function ebox-incremental-flush "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
|
(cl-defstruct
|
||||||
(ebox-region-handle
|
(ebox-region-handle
|
||||||
|
|||||||
42
ebox.el
42
ebox.el
@ -3640,10 +3640,11 @@ REGION-ID and CHANGED-KEYS describe one update; CHANGES describes a batch."
|
|||||||
(defun ebox-region-update (handle &rest props)
|
(defun ebox-region-update (handle &rest props)
|
||||||
"Update the box identified by surface-scoped HANDLE with PROPS.
|
"Update the box identified by surface-scoped HANDLE with PROPS.
|
||||||
HANDLE must come from ebox-region-resolve or an Ebox selector result. 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
|
accepts mutable content, style, and scroll keywords supported by the target;
|
||||||
builds an isolated candidate, runs the Ebox owner planner, and publishes once
|
it does not add children or mutate selector metadata. The update builds an
|
||||||
through the mounted TP surface. Return nil while queued in an explicit batch;
|
isolated candidate, runs the Ebox owner planner, and publishes once through the
|
||||||
otherwise return the committed update report.
|
mounted TP surface. Return nil while queued in an explicit batch; otherwise
|
||||||
|
return the committed update report.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
(ebox-region-update (ebox-region-resolve buffer \"status\")
|
(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-concat
|
||||||
ebox-create
|
ebox-create
|
||||||
ebox-display-buffer
|
ebox-display-buffer
|
||||||
|
ebox-display-signature
|
||||||
ebox-flex
|
ebox-flex
|
||||||
ebox-flex-item
|
ebox-flex-item
|
||||||
|
ebox-grid
|
||||||
|
ebox-grid-fr
|
||||||
|
ebox-grid-item
|
||||||
ebox-host-ref-bounds
|
ebox-host-ref-bounds
|
||||||
ebox-host-ref-position
|
ebox-host-ref-position
|
||||||
|
ebox-native-build
|
||||||
|
ebox-native-status
|
||||||
ebox-region-ids
|
ebox-region-ids
|
||||||
|
ebox-region-resolve
|
||||||
ebox-region-update
|
ebox-region-update
|
||||||
ebox-render
|
ebox-render
|
||||||
ebox-render-to-buffer
|
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-selector-update-buffer
|
||||||
ebox-spacer
|
ebox-spacer
|
||||||
ebox-stack
|
ebox-stack
|
||||||
|
ebox-string-pixel-width
|
||||||
ebox-update-selector
|
ebox-update-selector
|
||||||
ebox-wheel-scroll-down
|
ebox-wheel-scroll-down
|
||||||
ebox-wheel-scroll-up)
|
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
|
(defconst ebox-feature-families
|
||||||
'(box-model
|
'(box-model
|
||||||
@ -3975,9 +3988,10 @@ through dirty-set and patch-set execution before falling back to root rerender."
|
|||||||
;;; ============================================================
|
;;; ============================================================
|
||||||
;;; Public API Summary
|
;;; Public API Summary
|
||||||
;;; ============================================================
|
;;; ============================================================
|
||||||
;; The following functions form the stable public interface of ebox.
|
;; The complete facade inventory is `ebox-public-api'. Style-rule entry points
|
||||||
;; All other ebox-- prefixed functions are internal implementation
|
;; are defined in `ebox-style.el' and the user-facing inventory is maintained
|
||||||
;; details and may change without notice.
|
;; in `docs/user/ebox-api-reference.en.md` and its Chinese counterpart.
|
||||||
|
;; All other ebox-- prefixed functions are internal implementation details.
|
||||||
;;
|
;;
|
||||||
;; ── Creation ──────────────────────────────────────────────────
|
;; ── Creation ──────────────────────────────────────────────────
|
||||||
;; ebox-create &rest plist
|
;; 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
|
;; call BEFORE render-to-buffer
|
||||||
;;
|
;;
|
||||||
;; ── Dynamic Updates (call inside with-current-buffer + inhibit-read-only) ──
|
;; ── Dynamic Updates (call inside with-current-buffer + inhibit-read-only) ──
|
||||||
;; ebox-region-update region-id &rest props
|
;; ebox-region-update handle &rest props
|
||||||
;; Single entry-point for all dynamic changes. PROPS keywords mirror
|
;; Single entry-point for all dynamic changes. HANDLE comes from
|
||||||
;; those of ebox-create:
|
;; ebox-region-resolve or a selector match's :region-handle field;
|
||||||
;; :content STRING
|
;; numeric region ids are not update handles.
|
||||||
;; :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.
|
|
||||||
;;
|
;;
|
||||||
;; ── Scroll ────────────────────────────────────────────────────
|
;; ── Scroll ────────────────────────────────────────────────────
|
||||||
;; ebox-scroll-up &optional n
|
;; ebox-scroll-up &optional n
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
(defconst ebox-docs-test--current-docs
|
(defconst ebox-docs-test--current-docs
|
||||||
'("AGENTS.md" "README.md" "README.zh-CN.md" "DESIGN.md" "DESIGN.zh.md"
|
'("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-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.en.md"
|
||||||
"docs/maintainer/ebox-current-implementation-reference.zh.md"
|
"docs/maintainer/ebox-current-implementation-reference.zh.md"
|
||||||
"docs/maintainer/ebox-incremental-update-contract.en.md"
|
"docs/maintainer/ebox-incremental-update-contract.en.md"
|
||||||
@ -72,6 +73,8 @@
|
|||||||
"Every long-lived user and maintainer document should have both languages."
|
"Every long-lived user and maintainer document should have both languages."
|
||||||
(dolist (pair '(("docs/user/ebox-user-guide.en.md"
|
(dolist (pair '(("docs/user/ebox-user-guide.en.md"
|
||||||
"docs/user/ebox-user-guide.zh.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.en.md"
|
||||||
"docs/maintainer/ebox-current-implementation-reference.zh.md")
|
"docs/maintainer/ebox-current-implementation-reference.zh.md")
|
||||||
("docs/maintainer/ebox-incremental-update-contract.en.md"
|
("docs/maintainer/ebox-incremental-update-contract.en.md"
|
||||||
@ -79,6 +82,17 @@
|
|||||||
(dolist (file pair)
|
(dolist (file pair)
|
||||||
(should (file-exists-p (expand-file-name file ebox-docs-test--root))))))
|
(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 ()
|
(ert-deftest ebox-docs-do-not-present-legacy-source-as-active ()
|
||||||
"The standalone package documentation must not claim ETAF source ownership."
|
"The standalone package documentation must not claim ETAF source ownership."
|
||||||
(dolist (file ebox-docs-test--current-docs)
|
(dolist (file ebox-docs-test--current-docs)
|
||||||
|
|||||||
@ -156,6 +156,53 @@
|
|||||||
(regexp-quote (car entry)))
|
(regexp-quote (car entry)))
|
||||||
source)))))
|
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 ()
|
(ert-deftest ebox-live-buffer-publication-uses-only-tp-surfaces ()
|
||||||
"The facade should expose no raw live-buffer writer beside TP surfaces."
|
"The facade should expose no raw live-buffer writer beside TP surfaces."
|
||||||
(require 'ebox)
|
(require 'ebox)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user