Document 0.3.0 across bilingual READMEs, doctests, and ARCHITECTURE.md
README.md/README_CN.md gain verified sections for every 0.3.0 feature: layer visibility (hide/show model, flatten/merge exclusion), lower and canonical rotate orders, stack introspection (tp-layer-stack-at, tp-describe-layer), the reactive layer-buffer registry and lifecycle (track-buffer, anonymous-layer GC, minimal-diff tp-text), search bounds/SUBEXP/PREDICATE, multi-argument parameterized layers, ABSOLUTE interval coordinates, palette primaries, prefix-conforming define aliases, and deprecation boxes for the raw search wrappers. Return conventions corrected against probed behavior (add-to-layers mutates in place; tp-clear now explicitly returns nil in code and docs), the in-place string-mutation warning added for all 16 stack mutators, and the stale pre-B43 with-range example fixed in both languages. EN/CN parity is exact (132 headings, 158 fenced blocks each); all 316 blocks executed with 0 failures. tp-doctest.el grows 63 -> 88 assertions, all accessor-based for Emacs-28 print-order safety. docs/ARCHITECTURE.md rewritten to the post-review truth: two hook variables, verified per-module dependency table, relocated subsystem homes, and a new mutable-state inventory. Suite 578/578, doctests 88/88, shuffled green, compile clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
aa214456df
commit
fe2c03d2bd
956
README_CN.md
956
README_CN.md
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,7 @@
|
||||
|
||||
本文档描述 tp 库的模块分层结构与函数调用层次,从底层基础模块到上层功能模块的分层组织。
|
||||
|
||||
自 0.2.0 起,原来的单文件 tp.el 已拆分为九个分层模块,`tp.el` 只作为总入口(`(require 'tp)` 依次加载全部模块,用户接口不变)。各模块的变更缘由见 [CHANGELOG.md](../CHANGELOG.md)。
|
||||
自 0.2.0 起,原来的单文件 tp.el 已拆分为九个分层模块,`tp.el` 只作为总入口(`(require 'tp)` 依次加载全部模块,用户接口不变)。0.3.0 进一步收紧了模块边界:`tp-text` 处理链下沉至 tp-ops、批量更新上收至 tp-render、层栈存储编解码与匿名层机制归位 tp-layer,钩子变量从四个减少到两个。各变更的缘由见 [CHANGELOG.md](../CHANGELOG.md)。
|
||||
|
||||
## 目录
|
||||
|
||||
@ -10,14 +10,15 @@
|
||||
- [模块分层](#模块分层)
|
||||
- [tp-core.el:基础工具](#tp-coreel基础工具)
|
||||
- [tp-reactive.el:响应式基础设施](#tp-reactiveel响应式基础设施)
|
||||
- [tp-layer.el:层定义与解析](#tp-layerel层定义与解析)
|
||||
- [tp-ops.el:核心属性操作](#tp-opsel核心属性操作)
|
||||
- [tp-layer.el:层定义、解析与层栈存储](#tp-layerel层定义解析与层栈存储)
|
||||
- [tp-ops.el:核心属性操作与 tp-text 处理链](#tp-opsel核心属性操作与-tp-text-处理链)
|
||||
- [tp-search.el:模式匹配与搜索](#tp-searchel模式匹配与搜索)
|
||||
- [tp-render.el:响应式渲染引擎](#tp-renderel响应式渲染引擎)
|
||||
- [tp-stack.el:属性层栈操作](#tp-stackel属性层栈操作)
|
||||
- [tp-palette.el:调色板数据](#tp-paletteel调色板数据)
|
||||
- [tp-builtins.el:内置层与辅助工具](#tp-builtinsel内置层与辅助工具)
|
||||
- [钩子变量:唯一许可的反向调用](#钩子变量唯一许可的反向调用)
|
||||
- [可变状态清单](#可变状态清单)
|
||||
- [函数调用关系图](#函数调用关系图)
|
||||
- [设计原则](#设计原则)
|
||||
|
||||
@ -32,6 +33,20 @@ tp-core → tp-reactive → tp-layer → tp-ops → tp-search
|
||||
→ tp-render → tp-stack → tp-palette → tp-builtins
|
||||
```
|
||||
|
||||
注意加载顺序是依赖顺序的**上界**:并非每个模块都依赖它前面的全部模块。各模块实际 `require` 的 tp- 模块如下(逐一核对自源码头部):
|
||||
|
||||
| 模块 | require 的 tp- 模块 |
|
||||
|------|--------------------|
|
||||
| tp-core | —(仅 cl-lib、dash、seq) |
|
||||
| tp-reactive | tp-core |
|
||||
| tp-layer | tp-core、tp-reactive |
|
||||
| tp-ops | tp-core、tp-reactive、tp-layer |
|
||||
| tp-search | tp-core、tp-reactive、tp-layer、tp-ops |
|
||||
| tp-render | tp-core、tp-reactive、tp-layer、tp-ops、tp-search |
|
||||
| tp-stack | tp-core、tp-reactive、tp-layer(**不依赖 tp-ops / tp-search / tp-render**) |
|
||||
| tp-palette | —(不依赖任何 tp- 模块,仅 subr-x) |
|
||||
| tp-builtins | tp-core、tp-layer、tp-ops、tp-palette |
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────────┐
|
||||
│ tp.el —— 总入口,按序 require 全部模块 │
|
||||
@ -41,25 +56,28 @@ tp-core → tp-reactive → tp-layer → tp-ops → tp-search
|
||||
│ tp-palette-show、显示缓冲辅助宏 │
|
||||
├────────────────────────────────────────────────────────────────┤
|
||||
│ tp-palette.el 明/暗主题调色板数据、tp-parse-color │
|
||||
│ (独立叶模块,不依赖任何 tp- 模块) │
|
||||
├────────────────────────────────────────────────────────────────┤
|
||||
│ tp-stack.el 层栈操作(push/pop/move/merge/flatten …) │
|
||||
│ tp-stack.el 层栈操作(push/pop/move/hide/show/merge …) │
|
||||
├────────────────────────────────────────────────────────────────┤
|
||||
│ tp-render.el 响应式重渲染引擎 ──┐ │
|
||||
├──────────────────────────────────── │ ─────────────────────────┤
|
||||
│ tp-search.el tp-match-*/tp-regexp-*、tp-search、导航 │
|
||||
├──────────────────────────────────── │ ─────────────────────────┤
|
||||
│ tp-ops.el tp-set/reset/add/get/at/remove/clear │
|
||||
│ ◁╌╌ tp--tp-text-handler-function ╌╌╌╌┤ │
|
||||
├──────────────────────────────────── │ ─────────────────────────┤
|
||||
│ tp-layer.el define-tp/define-tps、层注册表与解析 │
|
||||
│ ◁╌╌ tp--layer-refresh-function ╌╌╌╌╌╌┤ │
|
||||
├──────────────────────────────────── │ ─────────────────────────┤
|
||||
│ tp-reactive.el 响应式依赖注册表、变量监听、批量队列 │
|
||||
│ ◁╌╌ tp--reactive-update-function ╌╌╌╌┤ │
|
||||
│ ◁╌╌ tp--reactive-flush-function ╌╌╌╌╌┘ │
|
||||
│ tp-render.el 响应式重渲染引擎、最小差异 tp-text 编辑、 │
|
||||
│ 批量更新(tp-with-batch-updates + flush)──┐ │
|
||||
├─────────────────────────────────────────────────────────── │ ──┤
|
||||
│ tp-search.el tp-match-*/tp-regexp-*、tp-search、导航 │ │
|
||||
├─────────────────────────────────────────────────────────── │ ──┤
|
||||
│ tp-ops.el tp-set/reset/add/get/at/remove/clear、 │ │
|
||||
│ tp-text 处理链(0.3.0 起在此,直接调用) │ │
|
||||
├─────────────────────────────────────────────────────────── │ ──┤
|
||||
│ tp-layer.el define-tp/define-tps、层注册表与解析、 │ │
|
||||
│ 层栈存储编解码、匿名层机制与 GC │ │
|
||||
│ ◁╌╌ tp--layer-refresh-function ╌╌╌╌╌╌╌╌╌╌┤ │
|
||||
├─────────────────────────────────────────────────────────── │ ──┤
|
||||
│ tp-reactive.el 响应式依赖注册表、变量监听、批量队列、 │ │
|
||||
│ 层→缓冲区注册表 │ │
|
||||
│ ◁╌╌ tp--reactive-update-function ╌╌╌╌╌╌╌╌╌┘ │
|
||||
├────────────────────────────────────────────────────────────────┤
|
||||
│ tp-core.el 区间遍历、plist/face 合并引擎、 │
|
||||
│ 调试日志、$var 符号工具 │
|
||||
│ 调试日志、$var 符号工具(无可变状态) │
|
||||
└────────────────────────────────────────────────────────────────┘
|
||||
|
||||
实线层级:上层模块调用下层模块(require 依赖)。
|
||||
@ -67,7 +85,7 @@ tp-core → tp-reactive → tp-layer → tp-ops → tp-search
|
||||
由 tp-render.el 在加载时安装实现(见下文)。
|
||||
```
|
||||
|
||||
早期文档把"响应式系统"画在高级 API 之下、却又让它向上调用 `tp-search-map`,与自身的分层原则矛盾。现在这一矛盾已在代码层面消除:需要向上调用的逻辑全部收拢进 `tp-render.el`(位于 `tp-search.el` 之上,可以直接调用它);下层模块(tp-reactive、tp-layer、tp-ops)通过**钩子变量**触发渲染,自身不依赖任何上层模块。
|
||||
需要"向上调用"的逻辑全部收拢在 `tp-render.el`(位于 `tp-search.el` 之上,可以直接调用它)。0.2.0 时这类反向调用靠四个钩子变量实现;0.3.0 把其中两个消除在了代码层面——`tp-text` 处理链整体下沉进 tp-ops(`tp-set` 等直接调用,不再需要 `tp--tp-text-handler-function`;只加载到 tp-ops 的部分加载也能得到可用的 `tp-text` 文本替换),批量刷新整体上收进 tp-render(`tp--flush-batch-updates` 直接调用 `tp--reactive-flush-entry`,不再需要 `tp--reactive-flush-function`)。剩下的两个钩子对应真正源自下层的事件:变量监听器触发(tp-reactive)与层重定义触发(tp-layer)。
|
||||
|
||||
---
|
||||
|
||||
@ -75,14 +93,14 @@ tp-core → tp-reactive → tp-layer → tp-ops → tp-search
|
||||
|
||||
### tp-core.el:基础工具
|
||||
|
||||
最底层模块,不依赖任何其他 tp 模块,提供区间遍历、合并引擎与调试能力。
|
||||
最底层模块,不依赖任何其他 tp 模块,提供区间遍历、合并引擎与调试能力。0.3.0 起 tp-core **不再持有任何可变状态**(匿名层计数器已迁至 tp-layer;仅剩 `tp-debug-mode` / `tp-debug-echo` 两个 defcustom 用户选项)。
|
||||
|
||||
#### 区间操作
|
||||
| 函数 | 描述 | 主要调用者 |
|
||||
|------|------|--------|
|
||||
| `tp-intervals` | 获取区域内文本属性区间列表(裁剪到 [START, END)) | tp-intervals-map, tp-get |
|
||||
| `tp-intervals-map` | 对区间应用函数 | 多个属性/层操作函数 |
|
||||
| `tp--map-intervals` | 共享的裁剪式区间遍历引擎 | tp-intervals-map, tp-ops/tp-stack 的区域操作 |
|
||||
| `tp-intervals` | 获取区域内文本属性区间列表(裁剪到 [START, END);可选 ABSOLUTE 参数返回缓冲区原生坐标,默认仍为相对坐标) | tp-intervals-map, tp-get |
|
||||
| `tp-intervals-map` | 对区间应用函数(同样支持 ABSOLUTE) | 多个属性/层操作函数 |
|
||||
| `tp--map-intervals` | 共享的裁剪式区间遍历引擎 | tp-intervals-map, tp-ops/tp-stack 的区域操作, tp-reactive 的缓冲区扫描 |
|
||||
| `tp-plist` | 获取区域中合并后的所有属性 | 用户 API |
|
||||
| `tp-empty-p` | 检查对象是否没有文本属性 | 用户 API |
|
||||
|
||||
@ -94,6 +112,7 @@ tp-core → tp-reactive → tp-layer → tp-ops → tp-search
|
||||
| `tp--merge-face-values` | 合并两个 face 值 | 合并引擎内部 |
|
||||
| `tp--merge-duplicate-keys` | 合并 plist 中的重复键 | tp--parse-args |
|
||||
| `tp--parse-face-list` | 解析 face 列表 | 合并引擎内部 |
|
||||
| `tp--merge-string-props-into-plist` | 将字符串内嵌属性并入 plist | tp-ops 的 tp-text 处理链 |
|
||||
| `tp--get-nested` | 按路径获取嵌套属性值 | tp-get, tp-at |
|
||||
|
||||
`tp-face-properties`(常量,`'(face font-lock-face mouse-face)`)定义参与 face 感知合并的属性家族。
|
||||
@ -122,98 +141,139 @@ tp-core → tp-reactive → tp-layer → tp-ops → tp-search
|
||||
|
||||
### tp-reactive.el:响应式基础设施
|
||||
|
||||
只依赖 tp-core。维护响应式依赖注册表、变量监听器与批量更新队列;**不包含任何渲染逻辑**,重渲染通过钩子变量委托给 tp-render.el。
|
||||
只依赖 tp-core。维护响应式依赖注册表、变量监听器、批量更新队列与 0.3.0 新增的**层→缓冲区注册表**;**不包含任何渲染逻辑**,重渲染通过钩子变量委托给 tp-render.el。批量更新的队列(`tp--batch-update-pending`、`tp--queue-batch-update`)定义在这里,但 `tp-with-batch-updates` 宏与刷新逻辑自 0.3.0 起位于 tp-render.el。
|
||||
|
||||
#### 依赖注册与管理
|
||||
| 函数/变量 | 描述 |
|
||||
|------|------|
|
||||
| `tp-reactive-deps` | 变量 → 依赖它的层及属性 的注册表 |
|
||||
| `tp--register-reactive-deps` | 注册响应式依赖 |
|
||||
| `tp--unregister-reactive-deps` | 取消注册依赖(含 watchers/computed/data) |
|
||||
| `tp--unregister-reactive-deps` | 取消注册依赖(含 watchers/computed/data,并移除该层的缓冲区注册表条目) |
|
||||
| `tp--layer-has-reactive-deps-p` | 层是否有响应式依赖 |
|
||||
| `tp--register-layer-watchers` / `tp--unregister-layer-watchers` | 注册/清除 `:watch` 回调 |
|
||||
| `tp--register-layer-computed` / `tp--unregister-layer-computed` | 注册/清除 `:compute` 计算属性 |
|
||||
| `tp--register-layer-data` / `tp--unregister-layer-data` | 注册/清除 `:data` 变量 |
|
||||
| `tp--apply-initial-computed` | 计算 `:compute` 的初始值 |
|
||||
| `tp--ensure-reactive-variables` | 确保 `$var` 对应的变量已定义 |
|
||||
| `tp-reactive-reset` | 重置全部响应式注册表 |
|
||||
| `tp-reactive-reset` | 重置全部响应式注册表(含批量队列与层→缓冲区注册表) |
|
||||
|
||||
#### 变量监听与批量更新
|
||||
| 函数/宏 | 描述 |
|
||||
#### 层→缓冲区注册表(0.3.0)
|
||||
响应式更新不再全量扫描 `(buffer-list)`:每条会写入 `tp-name` 的缓冲区路径(tp-set 家族、栈变更函数、match/regexp 应用器)都把目标缓冲区登记到注册表,更新时只访问登记过的缓冲区。
|
||||
|
||||
| 函数/变量 | 描述 |
|
||||
|------|------|
|
||||
| `tp--layer-buffers` | 哈希表(`:test equal`):层名 → 展示该层的缓冲区列表。键存在但值为空表示"已知:无缓冲区展示该层",与键不存在(`unknown`)严格区分 |
|
||||
| `tp-reactive--register-layer-buffer` | 幂等登记(公开写入口,tp-ops/tp-search/tp-stack 各自的注册助手最终都调用它);首次使用时安装 `kill-buffer-hook` 清理器 |
|
||||
| `tp-reactive-layer-buffers` | 查询某层的已登记存活缓冲区,或返回符号 `unknown`;惰性剔除已死缓冲区 |
|
||||
| `tp-reactive--buffer-layer-names` | 栈感知的缓冲区扫描:直接 `tp-name` 与 `tp-layers` 栈存储内的层(被覆盖或被隐藏)都算在场。`tp-reactive-track-buffer` 与匿名层 GC 的存活检查共用它 |
|
||||
| `tp-reactive-track-buffer` | 交互命令:扫描缓冲区并登记其中的全部层。用于弥补"插入已带属性的字符串"绕过登记路径的已知缺口 |
|
||||
| `tp-reactive--prune-killed-buffer` / `tp-reactive--install-kill-buffer-hook` | kill-buffer 时从注册表剔除死缓冲区(条目保留为空列表,即"已知:无") |
|
||||
|
||||
对 `unknown` 层,tp-render 的更新走一次**学习性**全扫描并登记实际找到的缓冲区;一处都没找到的层刻意保持 `unknown`,以便之后经非登记路径(如字符串插入)出现时仍能被下次扫描发现。
|
||||
|
||||
#### 变量监听与批量队列
|
||||
| 函数 | 描述 |
|
||||
|------|------|
|
||||
| `tp--reactive-variable-watcher` | `add-variable-watcher` 回调;调用 `:watch` 后经 `tp--reactive-update-function` 委托重渲染 |
|
||||
| `tp--invoke-layer-watchers` | 调用层的 `:watch` 回调 |
|
||||
| `tp-with-batch-updates` | 批量更新宏 |
|
||||
| `tp--queue-batch-update` | 将更新加入待处理队列 |
|
||||
| `tp--flush-batch-updates` | 刷新队列,经 `tp--reactive-flush-function` 委托重渲染 |
|
||||
| `tp--queue-batch-update` | 将更新加入待处理队列 `tp--batch-update-pending`(刷新在 tp-render) |
|
||||
|
||||
钩子变量:`tp--reactive-update-function`、`tp--reactive-flush-function`(定义于此,由 tp-render.el 安装)。
|
||||
钩子变量:`tp--reactive-update-function`(定义于此,由 tp-render.el 安装)。
|
||||
|
||||
---
|
||||
|
||||
### tp-layer.el:层定义与解析
|
||||
### tp-layer.el:层定义、解析与层栈存储
|
||||
|
||||
依赖 tp-core、tp-reactive。提供 `define-tp` / `define-tps` 宏、层注册表、层名解析,以及层栈的数据结构原语。
|
||||
依赖 tp-core、tp-reactive。提供 `define-tp` / `define-tps` 宏、层注册表、层名解析,以及 0.3.0 归位至此的**层栈存储编解码**与**匿名层完整生命周期**(铸造、驻留、注销、GC)。
|
||||
|
||||
#### 层定义
|
||||
| 函数/宏 | 描述 | 依赖 |
|
||||
|---------|------|------|
|
||||
| `define-tp` | 定义单个自定义文本属性(层) | tp--define-layer-internal |
|
||||
| `define-tps` | 定义自定义文本属性组(层组);别名 `define-tp-group` | tp--define-layer-group-internal |
|
||||
| `define-tp` | 定义单个自定义文本属性(层);别名 `tp-define-layer` | tp--define-layer-internal |
|
||||
| `define-tps` | 定义自定义文本属性组(层组);别名 `define-tp-group`、`tp-define-group` | tp--define-layer-group-internal |
|
||||
| `tp--define-layer-internal` | 层定义的运行时实现 | tp--parse-define-layer-args, tp--collect-reactive-symbols, tp--ensure-reactive-variables, tp--register-*, tp--layer-refresh |
|
||||
| `tp--parse-define-layer-args` | 解析 `:props` / `:data` / `:compute` / `:watch` / `:transform` | - |
|
||||
| `tp--parse-layer-group-element` | 解析层组元素 | tp--layer-group-element-format |
|
||||
| `tp--define-layer-from-parsed` | 从解析结果定义层 | (与 define-tp 类似的依赖) |
|
||||
| `tp--check-layer-cycle` | 检测循环层引用并报错 | tp--layer-expansion-stack |
|
||||
| `tp--anonymous-layer-name-for` | 匿名响应式层的驻留(`equal` 的 props 复用注册项) | - |
|
||||
|
||||
0.3.0 起参数化层/层组的 ARGLIST 可以声明**任意个**参数(此前仅限一个);`(LAYER ARG1 ... ARGN)` 与包裹形式 `(LAYER (ARG1 ... ARGN))` 在 `tp-set` 与 `tp-put-layer` 规格中均可用,实参数量不匹配会报出点名该层与两个数量的清晰错误。
|
||||
|
||||
#### 注册表与查询
|
||||
| 函数/变量 | 描述 |
|
||||
|------|------|
|
||||
| `tp-layer-alist` / `tp-layer-groups` / `tp-layer-transforms` | 层、层组、转换函数注册表 |
|
||||
| `tp--group-generated-layers` | 层组 → 其定义生成的层 的注册表(组重定义/注销时随之清理) |
|
||||
| `tp--set-layer-props` / `tp--set-group-layers` | 写入注册表 |
|
||||
| `tp-layer-props` / `tp-group-props` | 获取层/层组属性(`&optional INCLUDE-TP-NAME`,默认不含 `tp-name`;返回副本) |
|
||||
| `tp-layer-props-with-arg` / `tp-group-props-with-arg` | 参数化层/层组的属性求值 |
|
||||
| `tp-layer-props-with-arg` / `tp-group-props-with-arg` | 单参数形式(0.3.0 起是 -with-args 的薄封装) |
|
||||
| `tp-layer-props-with-args` / `tp-group-props-with-args` | 多参数形式:ARGS 按位置绑定到层参数 |
|
||||
| `tp-layer-arglist` | 返回参数化层的形参表副本(非参数化层返回 nil) |
|
||||
| `tp-layer-parameterized-p` / `tp-group-parameterized-p` | 是否参数化 |
|
||||
| `tp-layer-reset` | 重置层系统 |
|
||||
| `tp-undefine-layer` / `tp-undefine-group` | 删除层/层组(含其响应式依赖与转换) |
|
||||
| `tp-describe-layer` | 交互命令:在 help 缓冲区展示层的存储格式、形参表、原始定义体、展开属性、响应式依赖、transform 与所属层组(数据采集在 `tp--describe-layer-data`) |
|
||||
| `tp-layer-reset` | 重置层系统(连带调用 `tp-reactive-reset`;见[可变状态清单](#可变状态清单)) |
|
||||
| `tp-undefine-layer` / `tp-undefine-group` | 删除层/层组(含其响应式依赖、转换与匿名层注册表条目) |
|
||||
|
||||
#### 属性解析
|
||||
| 函数 | 描述 | 依赖 |
|
||||
|------|------|------|
|
||||
| `tp--resolve-props` | 解析属性(展开层名、`$var`、注册依赖) | tp-layer-props, tp--collect-reactive-symbols, tp--resolve-reactive-symbols, tp--register-reactive-deps |
|
||||
| `tp--resolve-props` | 解析属性(展开层名、多参数规格、`$var`、注册依赖、驻留匿名层) | tp-layer-props(-with-args), tp--collect-reactive-symbols, tp--resolve-reactive-symbols, tp--anonymous-layer-name-for, tp--register-reactive-deps |
|
||||
| `tp--expand-layer-in-plist` | 展开 plist 中的层名键 | tp--is-layer-name-p |
|
||||
| `tp--expand-layer-to-props-list` | 层名展开为属性列表 | tp--check-layer-cycle |
|
||||
|
||||
#### 层栈数据结构原语
|
||||
#### 匿名层机制与 GC(0.3.0 归位/新增)
|
||||
| 函数/变量 | 描述 |
|
||||
|------|------|
|
||||
| `tp--anonymous-layer-counter` | 匿名层名计数器。**刻意不被任何 reset 清零**:脱离缓冲区的字符串可能仍携带旧的 `tp-anon-N` 属性值,计数器单调递增保证新铸名字永不与之混淆 |
|
||||
| `tp--generate-anonymous-layer-name` | 生成唯一的 `tp-anon-N` 符号 |
|
||||
| `tp--anonymous-layer-registry` | 匿名响应式层驻留表:`equal` 的 props 规格复用既有注册项 |
|
||||
| `tp--anonymous-layer-name-for` | 驻留查询/铸造入口 |
|
||||
| `tp--buffer-has-layer-region-p` | 栈感知的存活检查:直接 `tp-name` 或 `tp-layers` 内(被覆盖/被隐藏)皆算存活 |
|
||||
| `tp-gc-anonymous-layers` | 交互命令:回收已无任何已登记存活缓冲区展示的匿名层;注册表状态为 `unknown` 的层(可能仅被游离字符串引用)保守保留 |
|
||||
|
||||
#### 层栈存储编解码
|
||||
层栈在原始文本属性上的编码/解码知识集中在这里,tp-stack(栈操作)与 tp-render(响应式写穿)都向下调用它,互不 require。
|
||||
|
||||
| 函数 | 描述 |
|
||||
|------|------|
|
||||
| `tp--normalize-layer-spec` | 规范化层规格 |
|
||||
| `tp--get-layer-stack` | 获取位置的层栈 |
|
||||
| `tp--build-layer-props` | 从层列表构建属性 |
|
||||
| `tp--layer-stack-to-list` | 将层栈转换为列表 |
|
||||
| `tp--normalize-layer-spec` | 规范化层规格(含多参数 `(LAYER ARG1 ... ARGN)`) |
|
||||
| `tp--build-layer-props` / `tp--layer-stack-to-list` | 旧式编解码原语(无隐藏层语义) |
|
||||
| `tp--stack-hidden-p` | 层 plist 是否带 `tp-hidden` 标志 |
|
||||
| `tp--stack-props-to-list` | 原始属性 → 有序层列表(顶层在前,含隐藏层)。有隐藏层时 `tp-layers` 持有完整栈,直接属性只是最顶可见层的渲染缓存 |
|
||||
| `tp--stack-build-props` | 有序层列表 → 原始属性。单层栈不携带 `tp-layers`;含隐藏层时切换为"完整栈 + 渲染缓存"存储模式(全部隐藏时不渲染任何层属性) |
|
||||
| `tp--get-layer-by-idx-or-name` | 通过索引或名称查找层 |
|
||||
|
||||
钩子变量:`tp--layer-refresh-function`(定义于此,由 tp-render.el 安装为 `tp--update-layer-regions`);`tp--layer-refresh` 是它的调用入口,层重定义后经它触发已应用区域的重渲染。
|
||||
|
||||
---
|
||||
|
||||
### tp-ops.el:核心属性操作
|
||||
### tp-ops.el:核心属性操作与 tp-text 处理链
|
||||
|
||||
依赖 tp-core、tp-layer。面向用户的核心属性读写函数,直接调用 Emacs 原生文本属性 API。
|
||||
依赖 tp-core、tp-reactive、tp-layer。面向用户的核心属性读写函数,直接调用 Emacs 原生文本属性 API。0.3.0 起 `tp-text` 处理链从 tp-render 下沉至此,`tp-set` 等**同模块直接调用**它(不再经钩子变量)——因此只加载到 tp-ops 的部分加载也能得到可用的 `tp-text` 文本替换。
|
||||
|
||||
#### 参数解析
|
||||
| 函数 | 描述 | 调用者 |
|
||||
|------|------|--------|
|
||||
| `tp--parse-args` | 解析灵活的调用格式(整串/区域/层名) | tp-set, tp-reset, tp-add |
|
||||
| `tp--parse-args` | 解析灵活的调用格式(整串/区域/层名/多参数层) | tp-set, tp-reset, tp-add |
|
||||
| `tp--apply-props-to-string` | 字符串路径的属性应用 | tp-set, tp-reset, tp-add |
|
||||
| `tp--ops-register-layer-buffer` | 应用带 `tp-name` 的属性到缓冲区后,登记到层→缓冲区注册表 | tp-set, tp-reset, tp-add |
|
||||
|
||||
#### tp-text 处理链(0.3.0 自 tp-render 迁入)
|
||||
| 函数 | 描述 |
|
||||
|------|------|
|
||||
| `tp--handle-tp-text-property` | `tp-text` 属性的总入口:初始化/替换文本、双向同步响应式变量 |
|
||||
| `tp--tp-text-replace` | 执行文本替换(缓冲区与字符串两条路径) |
|
||||
| `tp--tp-text-transform` | 应用层的 `:transform`(首次渲染同样生效) |
|
||||
| `tp--find-tp-text-reactive-var` | 找到层 `tp-text` 绑定的响应式变量 |
|
||||
| `tp--merge-embedded-props` | 合并 tp-text 字符串内嵌属性与外部属性 |
|
||||
| `tp--apply-reactive-text-props` | 把结果属性应用到替换文本(值未变的区段跳过写入,保持 buffer-modified 状态) |
|
||||
| `tp--put-text-property-unless-equal` | 仅在值确实变化时写属性 |
|
||||
|
||||
#### 设置属性
|
||||
| 函数 | 描述 | 依赖 | 被依赖 |
|
||||
|------|------|------|--------|
|
||||
| `tp-set` | 设置文本属性(保留其他属性) | tp--parse-args, tp--handle-tp-text | tp-match-set, 层操作 |
|
||||
| `tp-reset` | 完全替换所有文本属性 | tp--parse-args, tp--handle-tp-text | tp-match-reset |
|
||||
| `tp-add` | 深度合并属性 | tp--parse-args, tp--deep-merge-plist, tp--prepend-face | tp-match-add |
|
||||
| `tp-set` | 设置文本属性(保留其他属性) | tp--parse-args, tp--handle-tp-text-property, tp--ops-register-layer-buffer | tp-match-set, 层操作 |
|
||||
| `tp-reset` | 完全替换所有文本属性 | 同上 | tp-match-reset |
|
||||
| `tp-add` | 深度合并属性 | 同上 + tp--deep-merge-plist, tp--prepend-face | tp-match-add |
|
||||
|
||||
#### 获取属性
|
||||
| 函数 | 描述 | 依赖 | 被依赖 |
|
||||
@ -226,39 +286,39 @@ tp-core → tp-reactive → tp-layer → tp-ops → tp-search
|
||||
| 函数 | 描述 | 依赖 | 被依赖 |
|
||||
|------|------|------|--------|
|
||||
| `tp-remove` | 移除属性或子属性 | tp--remove-property, tp--remove-sub, tp--remove-*-from-string | 用户 API |
|
||||
| `tp-clear` | 清除所有属性 | - | 用户 API |
|
||||
|
||||
钩子变量:`tp--tp-text-handler-function`(定义于此,由 tp-render.el 安装为 `tp--handle-tp-text-property`);`tp--handle-tp-text` 是它的调用入口,未安装时 `tp-text` 属性按普通属性处理。
|
||||
| `tp-clear` | 清除所有属性(显式返回 nil) | - | 用户 API |
|
||||
|
||||
---
|
||||
|
||||
### tp-search.el:模式匹配与搜索
|
||||
|
||||
依赖 tp-core、tp-layer、tp-ops。提供模式匹配式属性应用、属性搜索与导航。
|
||||
依赖 tp-core、tp-reactive、tp-layer、tp-ops(0.3.0 新增 tp-reactive 依赖:应用器写入缓冲区后经 `tp--search-register-layer-buffer` 登记层→缓冲区注册表)。提供模式匹配式属性应用、属性搜索与导航。
|
||||
|
||||
#### 模式匹配
|
||||
| 函数 | 描述 | 依赖 |
|
||||
|------|------|------|
|
||||
| `tp-match-set` / `tp-match-reset` / `tp-match-add` | 在字符串匹配处设置/重置/合并属性 | tp--match-apply |
|
||||
| `tp-regexp-set` / `tp-regexp-reset` / `tp-regexp-add` | 在正则匹配处设置/重置/合并属性 | tp--regexp-apply |
|
||||
| `tp-match-set` / `tp-match-reset` / `tp-match-add` | 在字符串匹配处设置/重置/合并属性;0.3.0 起接受 START/END 界限(视同只存在该部分;颠倒的界限自动交换) | tp--match-apply |
|
||||
| `tp-regexp-set` / `tp-regexp-reset` / `tp-regexp-add` | 在正则匹配处设置/重置/合并属性;0.3.0 起额外接受 SUBEXP(属性作用于每个匹配的该捕获组;超出组数报清晰错误) | tp--regexp-apply |
|
||||
| `tp--match-apply` / `tp--regexp-apply` | 字面/正则匹配的入口(含多模式支持) | tp--pattern-apply |
|
||||
| `tp--pattern-apply` / `tp--pattern-apply-single` | 共享的模式匹配引擎(空模式/零宽模式安全) | tp-set/tp-reset/tp-add 风格的 apply-fn |
|
||||
| `tp--deep-merge-apply` / `tp--reset-apply` | 传给引擎的合并/重置回调 | tp--deep-merge-plist 等 |
|
||||
| `tp--pattern-apply` / `tp--pattern-apply-single` | 共享的模式匹配引擎(空模式/零宽模式安全;承载 START/END/SUBEXP) | tp-set/tp-reset/tp-add 风格的 apply-fn |
|
||||
| `tp--deep-merge-apply` / `tp--reset-apply` | 传给引擎的合并/重置回调(缓冲区路径顺带登记注册表) | tp--deep-merge-plist, tp--search-register-layer-buffer |
|
||||
| `tp--search-register-layer-buffer` | 登记助手,转发到 `tp-reactive--register-layer-buffer` | tp-reactive |
|
||||
|
||||
#### 搜索和导航
|
||||
| 函数 | 描述 | 依赖 |
|
||||
|------|------|------|
|
||||
| `tp-search-forward` | 向前搜索属性 | text-property-search-forward |
|
||||
| `tp-search-backward` | 向后搜索属性 | tp--property-search-backward |
|
||||
| `tp--property-search-backward` | 带等值谓词的向后搜索(与向前语义对称) | text-property-search-backward |
|
||||
| `tp-forward` | 向前搜索 N 次并移动点 | tp-search-forward |
|
||||
| `tp-backward` | 向后搜索 N 次并移动点 | tp-search-backward |
|
||||
| `tp-forward` | 向前搜索 N 次并移动点;0.3.0 起接受 PREDICATE 与 NOT-CURRENT(默认保持 0.2.0 的对称 `equal` 匹配契约) | text-property-search-forward |
|
||||
| `tp-backward` | 向后搜索 N 次并移动点(与向前语义对称,同样新增 PREDICATE/NOT-CURRENT) | tp--property-search-backward |
|
||||
| `tp--property-search-backward` | 带谓词的向后搜索引擎 | text-property-search-backward |
|
||||
| `tp--property-match-p` | 谓词归一化(nil/t → `equal`;函数 → `(funcall PRED VALUE PROP-VALUE)`) | - |
|
||||
| `tp--string-property-matches` | 字符串路径的按段匹配收集器 | - |
|
||||
| `tp-search` | 收集所有匹配区间 | tp-intervals 等 |
|
||||
| `tp-search-forward` / `tp-search-backward` | **已废弃(0.3.0,make-obsolete)**:裸封装原语,nil-PREDICATE 默认语义与库内 `equal` 匹配相悖;请改用 `tp-forward` / `tp-backward`,或直接用 Emacs 原语 | text-property-search-* |
|
||||
|
||||
#### 遍历与替换
|
||||
| 函数 | 描述 | 依赖 |
|
||||
|------|------|------|
|
||||
| `tp-forward-do` / `tp-backward-do` | 向前/向后搜索并对匹配执行函数 | tp--forward-do / tp--backward-do |
|
||||
| `tp-forward-do` / `tp-backward-do` | 向前/向后搜索并在第 TIMES 个匹配处执行函数(同样透传 PREDICATE/NOT-CURRENT) | tp--forward-do / tp--backward-do |
|
||||
| `tp--forward-do` / `tp--backward-do` | 单方向遍历的内部实现 | tp--replace-match-text |
|
||||
| `tp-search-map` | 对所有匹配应用函数(FUNCTION 接收 TEXT &optional START END IDX) | tp--search-do |
|
||||
| `tp--search-do` | 搜索遍历的内部实现 | tp--replace-match-text |
|
||||
@ -268,35 +328,47 @@ tp-core → tp-reactive → tp-layer → tp-ops → tp-search
|
||||
|
||||
### tp-render.el:响应式渲染引擎
|
||||
|
||||
依赖 tp-core、tp-reactive、tp-layer、tp-ops、tp-search。这是唯一"知道"渲染如何进行的模块:它可以直接调用 `tp-search-map`、`tp-add` 等前置模块的函数,并在加载末尾把自己的入口函数**安装**进下层模块预留的钩子变量。
|
||||
依赖 tp-core、tp-reactive、tp-layer、tp-ops、tp-search。这是唯一"知道"渲染如何进行的模块:它直接调用 `tp-search-map`、`tp--tp-text-transform`、`tp--apply-reactive-text-props`(后两者位于 tp-ops——这条 require 是真实的下行调用,不只是加载顺序),并在加载末尾把自己的入口函数**安装**进下层模块预留的两个钩子变量。0.3.0 起批量更新宏与刷新逻辑也位于此。
|
||||
|
||||
#### 缓冲区遍历(0.3.0:注册表驱动)
|
||||
| 函数 | 描述 | 依赖 |
|
||||
|------|------|------|
|
||||
| `tp--render-visit-buffer` | 单缓冲区访问接缝(测试可包裹它统计访问次数) | tp-with-current-buffer |
|
||||
| `tp--map-layer-buffers` | 在可能展示该层的缓冲区中执行更新:WHERE 为缓冲区(setq-local)时只走它;否则查注册表只访问已登记缓冲区;`unknown` 层回退为一次学习性 `(buffer-list)` 全扫描并登记实际命中的缓冲区 | tp-reactive-layer-buffers, tp--buffer-has-layer-region-p |
|
||||
|
||||
#### 重渲染
|
||||
| 函数 | 描述 | 依赖 |
|
||||
|------|------|------|
|
||||
| `tp--update-layer-regions` | 重渲染携带某层的所有文本区域(替换该层自己的属性键,保留其他来源属性) | tp--layer-render-props, tp-search-map |
|
||||
| `tp--update-layer-regions` | 重渲染携带某层的所有文本区域(替换该层自己的属性键,保留其他来源属性),并**写穿**到 `tp-layers` 栈存储 | tp--layer-render-props, tp-search-map, tp--write-layer-through-stack-storage |
|
||||
| `tp--write-layer-through-stack-storage` | 把新属性写进栈存储里该层的条目(被覆盖或被隐藏的副本也保持最新,`tp-show-layer` 后渲染当前值而非陈旧快照;值未变的段不触碰缓冲区) | tp--stack-props-to-list, tp--stack-build-props [tp-layer] |
|
||||
| `tp--merge-props-into-stack-entry` | 更新栈条目的键,保留其 `tp-hidden` 标志与栈位置 | - |
|
||||
| `tp--update-layer-computed` | 更新 `:compute` 计算属性(nil 值可正常传播) | tp--resolve-reactive-symbols, tp--set-layer-props |
|
||||
| `tp--layer-render-props` / `tp--layer-reactive-props` | 求取层的渲染属性 | tp-layer-props |
|
||||
|
||||
#### 响应式文本(tp-text)
|
||||
| 函数 | 描述 | 依赖 |
|
||||
|------|------|------|
|
||||
| `tp--handle-tp-text-property` | 处理 `tp-text` 属性(文本替换) | tp--tp-text-replace |
|
||||
| `tp--update-reactive-text` | 变量变化后更新响应式文本 | tp--replace-reactive-text-in-buffer |
|
||||
| `tp--replace-reactive-text-in-buffer` | 在缓冲区中替换响应式文本 | - |
|
||||
| `tp--tp-text-transform` | 应用 `:transform` 转换(首次渲染同样生效) | tp-layer-transforms |
|
||||
| `tp--update-reactive-text` | 变量变化后更新响应式文本 | tp--replace-reactive-text-in-buffer, tp--map-layer-buffers |
|
||||
| `tp--replace-reactive-text-in-buffer` | 在缓冲区中替换响应式文本(0.3.0:**最小差异编辑**——修剪公共前后缀只编辑差异区段,且先插入后删除,未变文本内的点位与标记不动;文本相同的更新完全不触碰缓冲区) | tp--edit-region-minimal-diff |
|
||||
| `tp--edit-region-minimal-diff` | 最小差异编辑原语 | - |
|
||||
| `tp--pos-holds-layer-in-storage-only-p` | 某位置的层是否只存在于栈存储(隐藏/被覆盖,跳过可见文本替换) | - |
|
||||
|
||||
#### 批量更新(0.3.0 自 tp-reactive 迁入)
|
||||
| 函数/宏 | 描述 |
|
||||
|------|------|
|
||||
| `tp-with-batch-updates` | 批量更新宏:BODY 内的多次变量修改合并为一次刷新(队列变量仍在 tp-reactive,宏向下 let 绑定它们) |
|
||||
| `tp--flush-batch-updates` | 刷新队列,按层去重后**直接调用** `tp--reactive-flush-entry`(不再经钩子) |
|
||||
| `tp--reactive-flush-entry` | 单条刷新的工作函数(属性更新或 tp-text 替换) |
|
||||
|
||||
#### 引擎入口与钩子安装
|
||||
| 函数 | 描述 |
|
||||
|------|------|
|
||||
| `tp--reactive-apply-update` | 变量变化的完整处理:更新 computed、合并层定义、重渲染或入批量队列(嵌套写入经队列而非递归)。安装为 `tp--reactive-update-function` |
|
||||
| `tp--reactive-flush-entry` | 批量队列刷新时的重渲染入口。安装为 `tp--reactive-flush-function` |
|
||||
| `tp--reactive-apply-update` | 变量变化的完整处理:更新 computed、合并层定义、重渲染或入批量队列(嵌套写入经队列而非递归)。尾部刷新置于 `unwind-protect` 清理段中,重渲染抛错也不会把队列条目困死。安装为 `tp--reactive-update-function` |
|
||||
|
||||
加载末尾执行安装:
|
||||
加载末尾执行安装(与源码逐字一致):
|
||||
|
||||
```elisp
|
||||
(setq tp--reactive-update-function #'tp--reactive-apply-update)
|
||||
(setq tp--reactive-flush-function #'tp--reactive-flush-entry)
|
||||
(setq tp--tp-text-handler-function #'tp--handle-tp-text-property)
|
||||
(setq tp--layer-refresh-function #'tp--update-layer-regions)
|
||||
```
|
||||
|
||||
@ -304,15 +376,16 @@ tp-core → tp-reactive → tp-layer → tp-ops → tp-search
|
||||
|
||||
### tp-stack.el:属性层栈操作
|
||||
|
||||
依赖 tp-core、tp-layer、tp-ops。所有栈变更函数建立在共享的裁剪式区域遍历之上,区域操作不会影响 [START, END) 之外的文本。
|
||||
依赖 tp-core、tp-reactive、tp-layer——**不依赖 tp-ops**(0.2.0 的幻影依赖已在 0.3.0 移除,独立字节编译无警告)。所有栈变更函数建立在共享的裁剪式区域遍历之上,区域操作不会影响 [START, END) 之外的文本;栈的存储编解码在 tp-layer(向下调用)。0.3.0 起所有栈变更函数**返回实际修改的属性段数量**(0 表示无匹配;`tp-put-layer`/`tp-push-layer` 例外,仍返回 OBJECT 或 `(START . END)`),每次改写后经 `tp--stack-register-layers` 登记层→缓冲区注册表。字符串形式**原地修改**字符串(与 `tp-set` 的复制语义不同,各函数 docstring 均有警示)。
|
||||
|
||||
#### 内部助手
|
||||
| 函数 | 描述 | 依赖 |
|
||||
|------|------|------|
|
||||
| `tp--parse-layer-args` | 解析层操作的灵活参数 | - |
|
||||
| `tp--stack-map-region` | 按区间遍历区域内层栈的共享引擎 | tp--map-intervals 风格遍历 |
|
||||
| `tp--stack-build-props` | 从层列表构建栈属性(单层栈不携带 `tp-layers`) | - |
|
||||
| `tp--put-layer-specs` | 展开层规格(层名/内联 plist/层名列表/参数化/层组) | tp--normalize-layer-spec, tp-group-props(-with-arg) |
|
||||
| `tp--plist-remove` | 返回去掉某键的 plist 副本 | - |
|
||||
| `tp--stack-map-region` | 按区间遍历区域内层栈的共享引擎(解码经 tp--stack-props-to-list,含隐藏层) | tp--map-intervals [tp-core], tp--stack-props-to-list [tp-layer] |
|
||||
| `tp--stack-register-layers` | 把新栈中每个带 `tp-name` 的层(含被覆盖与隐藏的)登记到缓冲区注册表 | tp-reactive--register-layer-buffer [tp-reactive] |
|
||||
| `tp--put-layer-specs` | 展开层规格(层名/内联 plist/层名列表/参数化/层组) | tp--normalize-layer-spec, tp-group-props(-with-arg) [tp-layer] |
|
||||
| `tp--move-layer-in-stack` | 在栈中移动层 | tp--get-layer-by-idx-or-name |
|
||||
| `tp--raise-layer-in-stack` | 在栈中上下移动层 | tp--move-layer-in-stack |
|
||||
| `tp--switch-layers-in-stack` | 交换两个层的位置 | tp--get-layer-by-idx-or-name |
|
||||
@ -320,25 +393,29 @@ tp-core → tp-reactive → tp-layer → tp-ops → tp-search
|
||||
#### 层操作(公开 API)
|
||||
| 函数 | 描述 | 依赖 |
|
||||
|------|------|------|
|
||||
| `tp-put-layer` | 在指定索引放置层(区域局部) | tp--put-layer-specs, tp--stack-map-region |
|
||||
| `tp-push-layer` | 将层推到顶部 | tp-put-layer |
|
||||
| `tp-put-layer` | 在指定索引放置层(区域局部;0.3.0 新增尾参 NOERROR:未定义层名返回 nil 而非报错) | tp--put-layer-specs, tp--stack-map-region |
|
||||
| `tp-push-layer` | 将层推到顶部(同样支持 NOERROR) | tp-put-layer |
|
||||
| `tp-delete-layer` | 删除层 | tp--stack-map-region |
|
||||
| `tp-pop-layer` | 弹出顶层 | tp-delete-layer |
|
||||
| `tp-move-layer` | 移动层到指定位置 | tp--move-layer-in-stack, tp--stack-map-region |
|
||||
| `tp-raise-layer` | 上移/下移层 | tp--raise-layer-in-stack, tp--stack-map-region |
|
||||
| `tp-rotate-layer` | 轮换层 | tp-move-layer |
|
||||
| `tp-pin-layer` | 将层置顶 | tp-move-layer |
|
||||
| `tp-raise-layer` | 上移层 | tp--raise-layer-in-stack, tp--stack-map-region |
|
||||
| `tp-lower-layer` | 下移层(0.3.0 新增,tp-raise-layer 的镜像) | tp--raise-layer-in-stack, tp--stack-map-region |
|
||||
| `tp-rotate-layer` | 轮换层(0.3.0:规范顺序 `(START END DIRECTION [COUNT] [OBJECT])`,凭 `up`/`down` 符号无歧义分派;旧顺序永久兼容;单趟栈旋转实现) | tp--stack-map-region |
|
||||
| `tp-pin-layer` | 将层一次性移到栈顶(不阻止后续 push 覆盖) | tp-move-layer |
|
||||
| `tp-switch-layer` | 交换两个层 | tp--switch-layers-in-stack, tp--stack-map-region |
|
||||
| `tp-merge-layers` | 合并多个层(显式 nil 值保留) | tp--merge-layer-props, tp--stack-map-region |
|
||||
| `tp-flatten-layers` | 扁平化所有层 | tp--merge-layer-props, tp--stack-map-region |
|
||||
| `tp-hide-layer` | 隐藏层(0.3.0 新增):层留在栈中、继续接收响应式更新但不渲染;隐藏可见顶层则显露下一可见层;全部隐藏时文本仅剩 `tp-layers` 记账属性 | tp--stack-map-region, tp--stack-build-props [tp-layer] |
|
||||
| `tp-show-layer` | 取消隐藏(0.3.0 新增) | 同上 |
|
||||
| `tp-merge-layers` | 合并多个层(显式 nil 值保留;隐藏的匹配层不贡献属性,全部匹配层均隐藏时合并结果保持隐藏) | tp--merge-layer-props, tp--stack-map-region |
|
||||
| `tp-flatten-layers` | 扁平化所有层(只合并可见层;全部隐藏时得到裸文本) | tp--merge-layer-props, tp--stack-map-region |
|
||||
|
||||
#### 层查询
|
||||
| 函数 | 描述 | 依赖 |
|
||||
|------|------|------|
|
||||
| `tp-layer-list` | 列出所有层名称 | tp--stack-map-region |
|
||||
| `tp-layer-count` | 计算层数量 | tp--stack-map-region |
|
||||
| `tp-layer-list` | 列出所有层名称(含隐藏层) | tp--stack-map-region |
|
||||
| `tp-layer-count` | 计算层数量(含隐藏层) | tp--stack-map-region |
|
||||
| `tp-layer-exists-p` | 检查层是否存在 | tp-layer-list |
|
||||
| `tp-layer-top` | 获取顶层名称(覆盖整个请求区域) | tp--stack-map-region |
|
||||
| `tp-layer-top` | 获取顶层名称(覆盖整个请求区域;按栈序报告最顶层,即使它被隐藏) | tp--stack-map-region |
|
||||
| `tp-layer-stack-at` | 单个位置的完整有序层栈:`(NAME . PROPS)` 列表,顶层在前,隐藏层以 PROPS 中的 `tp-hidden t` 标识(0.3.0 新增) | tp--stack-props-to-list [tp-layer] |
|
||||
| `tp-region-layer-props` | 获取区域中特定层的属性 | tp--stack-map-region |
|
||||
|
||||
#### 层属性操作
|
||||
@ -351,16 +428,18 @@ tp-core → tp-reactive → tp-layer → tp-ops → tp-search
|
||||
|
||||
### tp-palette.el:调色板数据
|
||||
|
||||
只依赖 tp-core(及 subr-x)。明/暗主题双值调色板系统,`tp-palette-alist` 是唯一数据源。
|
||||
**不依赖任何 tp- 模块**(仅 subr-x),是独立的叶模块。明/暗主题双值调色板系统,`tp-palette-alist` 是唯一数据源。
|
||||
|
||||
| 函数/宏/变量 | 描述 |
|
||||
|------|------|
|
||||
| `define-tp-palette` | 定义调色板(重定义立即生效) |
|
||||
| `define-tp-palette` | 定义调色板(重定义立即生效);别名 `tp-define-palette` |
|
||||
| `tp-palette-alist` | 调色板注册表(唯一数据源) |
|
||||
| `tp-parse-color` | 解析颜色规格(支持 `("light" . "dark")` 及单边 cons) |
|
||||
| `tp-theme-dark-p` / `tp-theme-light-p` | 当前主题判断 |
|
||||
| `tp-palette-fg-color` / `tp-palette-bg-color` / `tp-palette-border-color` | 取前景/背景/边框色 |
|
||||
| `tp-palette-p` / `tp-palette-fg-p` / `tp-palette-bg-p` / `tp-palette-fbg-p` / `tp-palette-border-p` | 调色板谓词 |
|
||||
| `tp-palette-color` | 通用的主题解析取色器(0.3.0 新增的首选查询入口) |
|
||||
| `tp-palette-has-p` | 谓词整合入口:KIND 取 `:fg`/`:bg`/`:border`/nil(0.3.0 新增) |
|
||||
| `tp-palette-fg-color` / `tp-palette-bg-color` / `tp-palette-border-color` | 取前景/背景/边框色(兼容便捷函数) |
|
||||
| `tp-palette-p` / `tp-palette-fg-p` / `tp-palette-bg-p` / `tp-palette-fbg-p` / `tp-palette-border-p` | 调色板谓词(兼容便捷函数) |
|
||||
| `tp-palette-pure` | 取纯色值 |
|
||||
|
||||
---
|
||||
@ -374,20 +453,46 @@ tp-core → tp-reactive → tp-layer → tp-ops → tp-search
|
||||
| 内置层 | `tp-palette`、`tp-fg`、`tp-bg`、`tp-button`、`tp-underline`、`tp-delete`、`tp-link`、`tp-space`、`tp-headline`、`tp-action` 等(`define-tp` 定义;`tp-link` 的颜色在应用时解析,主题切换即时生效) |
|
||||
| `tp-pop-to-buffer` / `tp-switch-to-buffer` | 显示带属性文本的缓冲辅助宏(q 绑定在缓冲区局部 minor-mode keymap 中) |
|
||||
| `tp-palette-show` | 展示所有调色板 |
|
||||
| `tp-suffix-symbol` | 符号加后缀助手 |
|
||||
| `tp--suffix-symbol` | 符号加后缀助手(0.3.0 起转为私有;`tp-suffix-symbol` 保留为废弃兼容别名) |
|
||||
|
||||
---
|
||||
|
||||
## 钩子变量:唯一许可的反向调用
|
||||
|
||||
分层规则的唯一例外是四个**钩子变量**:下层模块声明变量并在需要时 `funcall`,实现由 tp-render.el 在加载时安装。这样下层模块不必 `require` 上层模块,依赖图保持严格单向;而在未加载 tp-render 时,下层模块依然可用(钩子为 nil 时优雅降级)。
|
||||
分层规则的唯一例外是两个**钩子变量**:下层模块声明变量并在需要时 `funcall`,实现由 tp-render.el 在加载时安装。这样下层模块不必 `require` 上层模块,依赖图保持严格单向;而在未加载 tp-render 时,下层模块依然可用(钩子为 nil 时优雅降级:层可以定义与应用,只是没有自动重渲染)。
|
||||
|
||||
| 钩子变量 | 声明于 | 安装的实现(tp-render.el) | 用途 |
|
||||
|----------|--------|---------------------------|------|
|
||||
| `tp--reactive-update-function` | tp-reactive.el | `tp--reactive-apply-update` | 变量监听器触发的重计算与重渲染 |
|
||||
| `tp--reactive-flush-function` | tp-reactive.el | `tp--reactive-flush-entry` | 批量更新队列刷新时的重渲染 |
|
||||
| `tp--layer-refresh-function` | tp-layer.el | `tp--update-layer-regions` | 层重定义后刷新已应用区域 |
|
||||
| `tp--tp-text-handler-function` | tp-ops.el | `tp--handle-tp-text-property` | `tp-set` 等操作中处理 `tp-text` 属性 |
|
||||
|
||||
0.2.0 时钩子有四个;0.3.0 删掉了其中两个,代之以真实的模块内/下行调用:
|
||||
|
||||
- `tp--tp-text-handler-function`(原声明于 tp-ops):整条 `tp-text` 处理链移入 tp-ops,`tp-set` 等直接调用 `tp--handle-tp-text-property`。副产品:只加载 tp-ops 的部分加载也能完成 `tp-text` 文本替换。
|
||||
- `tp--reactive-flush-function`(原声明于 tp-reactive):`tp-with-batch-updates` 与 `tp--flush-batch-updates` 移入 tp-render,刷新直接调用 `tp--reactive-flush-entry`。副产品:部分加载下批量刷新不再被静默丢弃,而是诚实地报 void-function。
|
||||
|
||||
留下的两个钩子对应真正**源自下层的事件**(变量被 set、层被重定义),无法在不打破分层的前提下改写为下行调用。
|
||||
|
||||
---
|
||||
|
||||
## 可变状态清单
|
||||
|
||||
各模块持有的可变运行时状态及其清理入口(0.3.0 全面核对):
|
||||
|
||||
| 模块 | 状态 | 描述 | 清理 |
|
||||
|------|------|------|------|
|
||||
| tp-core | —— | **无可变状态**(仅 `tp-debug-mode`/`tp-debug-echo` 两个用户选项;调试日志写入 *tp-debug* 缓冲区,由 `tp-debug-clear` 清除) | - |
|
||||
| tp-reactive | `tp-reactive-deps` | 变量 → 依赖层 注册表 | `tp-reactive-reset` |
|
||||
| tp-reactive | `tp-layer-watchers` / `tp-layer-computed` / `tp-layer-data` | `:watch` / `:compute` / `:data` 注册表 | `tp-reactive-reset` |
|
||||
| tp-reactive | `tp--batch-update-pending` | 批量更新队列(0.3.0 起也被 reset 清空,防止残留条目对新定义的层重放) | `tp-reactive-reset` |
|
||||
| tp-reactive | `tp--layer-buffers` | 层→缓冲区注册表(哈希表,0.3.0 新增) | `tp-reactive-reset`(clrhash);单层条目随 `tp-undefine-layer`/层重定义移除;死缓冲区经 kill-buffer-hook 与惰性访问剔除 |
|
||||
| tp-reactive | `tp--batch-update-active` / `tp--reactive-updating` | 动态标志(let 绑定,非持久状态) | 随作用域退出 |
|
||||
| tp-layer | `tp-layer-alist` / `tp-layer-groups` / `tp-layer-transforms` | 层、层组、转换注册表 | `tp-layer-reset` |
|
||||
| tp-layer | `tp--group-generated-layers` | 层组生成的层 | `tp-layer-reset` |
|
||||
| tp-layer | `tp--anonymous-layer-registry` | 匿名层驻留表 | `tp-layer-reset`;单条随 `tp-undefine-layer` / `tp-gc-anonymous-layers` |
|
||||
| tp-layer | `tp--anonymous-layer-counter` | 匿名层名计数器——**刻意不清零**(任何 reset 都不动它):游离字符串上残留的 `tp-anon-N` 名字永远不能与新铸层重名 | 从不 |
|
||||
|
||||
`tp-reactive-reset` 移除全部变量监听器并清空上表 tp-reactive 各行;`tp-layer-reset` 先调用 `tp-reactive-reset`,再清空 tp-layer 各注册表(计数器除外)。
|
||||
|
||||
---
|
||||
|
||||
@ -401,26 +506,31 @@ tp-set [tp-ops]
|
||||
├── tp--parse-args [tp-ops]
|
||||
│ ├── tp--merge-duplicate-keys [tp-core]
|
||||
│ └── tp--resolve-props [tp-layer]
|
||||
│ ├── tp-layer-props
|
||||
│ ├── tp-layer-props / tp-layer-props-with-args [tp-layer]
|
||||
│ ├── tp--collect-reactive-symbols [tp-core]
|
||||
│ ├── tp--resolve-reactive-symbols [tp-core]
|
||||
│ ├── tp--anonymous-layer-name-for [tp-layer]($var 匿名层驻留)
|
||||
│ └── tp--register-reactive-deps [tp-reactive]
|
||||
├── tp--handle-tp-text [tp-ops]
|
||||
│ ╌╌▷ tp--handle-tp-text-property [tp-render](经钩子)
|
||||
├── tp--handle-tp-text-property [tp-ops](0.3.0 起同模块直接调用,不再经钩子)
|
||||
│ └── tp--tp-text-transform / tp--tp-text-replace [tp-ops]
|
||||
├── tp--apply-props-to-string [tp-ops](整串形式,返回新字符串)
|
||||
└── set-text-properties / put-text-property(Emacs 原生,区域形式)
|
||||
├── set-text-properties / put-text-property(Emacs 原生,区域形式)
|
||||
└── tp--ops-register-layer-buffer [tp-ops](缓冲区目标)
|
||||
└── tp-reactive--register-layer-buffer [tp-reactive]
|
||||
```
|
||||
|
||||
### tp-add 调用链
|
||||
```
|
||||
tp-add [tp-ops]
|
||||
├── tp--parse-args [tp-ops]
|
||||
├── tp--handle-tp-text [tp-ops] ╌╌▷ tp--handle-tp-text-property [tp-render]
|
||||
├── tp--handle-tp-text-property [tp-ops](直接调用)
|
||||
├── text-properties-at(Emacs 原生)
|
||||
├── tp--prepend-face [tp-core](face 家族属性)
|
||||
│ └── tp--deep-merge-plist [tp-core]
|
||||
├── tp--deep-merge-plist [tp-core](其他嵌套属性)
|
||||
└── put-text-property(Emacs 原生)
|
||||
├── put-text-property(Emacs 原生)
|
||||
└── tp--ops-register-layer-buffer [tp-ops]
|
||||
└── tp-reactive--register-layer-buffer [tp-reactive]
|
||||
```
|
||||
|
||||
### define-tp 调用链
|
||||
@ -429,7 +539,7 @@ define-tp [tp-layer](宏)
|
||||
└── tp--define-layer-internal [tp-layer]
|
||||
├── tp--parse-define-layer-args [tp-layer]
|
||||
├── tp--collect-reactive-symbols [tp-core]
|
||||
├── tp--unregister-reactive-deps [tp-reactive]
|
||||
├── tp--unregister-reactive-deps [tp-reactive](连带移除旧的缓冲区注册表条目)
|
||||
├── tp--ensure-reactive-variables [tp-reactive]
|
||||
├── tp--register-layer-data [tp-reactive]
|
||||
│ └── add-variable-watcher(Emacs 原生)
|
||||
@ -455,8 +565,11 @@ tp-push-layer [tp-stack]
|
||||
│ │ └── tp-layer-props [tp-layer]
|
||||
│ └── tp-group-props / tp-group-props-with-arg [tp-layer]
|
||||
└── tp--stack-map-region [tp-stack](裁剪到 [START, END))
|
||||
├── tp--stack-build-props [tp-stack]
|
||||
└── set-text-properties(Emacs 原生)
|
||||
├── tp--stack-props-to-list [tp-layer](解码既有栈,含隐藏层)
|
||||
├── tp--stack-build-props [tp-layer](编码新栈/渲染缓存)
|
||||
├── set-text-properties(Emacs 原生)
|
||||
└── tp--stack-register-layers [tp-stack]
|
||||
└── tp-reactive--register-layer-buffer [tp-reactive]
|
||||
```
|
||||
|
||||
### 响应式更新调用链
|
||||
@ -470,15 +583,27 @@ tp-push-layer [tp-stack]
|
||||
│ └── tp--set-layer-props [tp-layer]
|
||||
├── tp--set-layer-props [tp-layer](深合并回层定义;setq-local 不写全局)
|
||||
├── tp--update-layer-regions [tp-render](属性更新)
|
||||
│ └── tp-search-map [tp-search]
|
||||
│ └── put-text-property
|
||||
│ └── tp--map-layer-buffers [tp-render]
|
||||
│ │(只访问注册表登记的缓冲区;unknown 层回退为
|
||||
│ │ 一次学习性全扫描并登记命中缓冲区)
|
||||
│ ├── tp-reactive-layer-buffers [tp-reactive]
|
||||
│ ├── tp--buffer-has-layer-region-p [tp-layer](回退路径)
|
||||
│ └── 每缓冲区:
|
||||
│ ├── tp-search-map [tp-search] → put-text-property
|
||||
│ └── tp--write-layer-through-stack-storage [tp-render]
|
||||
│ └── tp--stack-props-to-list /
|
||||
│ tp--stack-build-props [tp-layer]
|
||||
│ (隐藏/被覆盖的层副本同步刷新)
|
||||
└── tp--update-reactive-text [tp-render](tp-text 文本替换)
|
||||
└── tp--replace-reactive-text-in-buffer [tp-render]
|
||||
└── tp--edit-region-minimal-diff [tp-render]
|
||||
(最小差异、先插入后删除;文本相同则完全不动缓冲区)
|
||||
|
||||
批量模式(tp-with-batch-updates)/ 更新中的嵌套写入:
|
||||
批量模式(tp-with-batch-updates [tp-render])/ 更新中的嵌套写入:
|
||||
└── tp--queue-batch-update [tp-reactive](入队,不递归)
|
||||
└── tp--flush-batch-updates [tp-reactive](退出批量时)
|
||||
└── ╌╌▷ tp--reactive-flush-entry [tp-render](经钩子)
|
||||
└── tp--flush-batch-updates [tp-render](退出批量/最外层更新结束时;
|
||||
置于 unwind-protect 清理段,重渲染抛错也会排空队列)
|
||||
└── tp--reactive-flush-entry [tp-render](0.3.0 起同模块直接调用,不再经钩子)
|
||||
├── tp--update-layer-regions
|
||||
└── tp--update-reactive-text
|
||||
```
|
||||
@ -487,9 +612,9 @@ tp-push-layer [tp-stack]
|
||||
|
||||
## 设计原则
|
||||
|
||||
1. **严格分层**:模块只允许 `require` 并调用排在它前面的模块,字节编译器强制检查依赖顺序
|
||||
2. **钩子反转**:唯一许可的"向上调用"是四个钩子变量(`tp--tp-text-handler-function`、`tp--reactive-update-function`、`tp--reactive-flush-function`、`tp--layer-refresh-function`),由 tp-render.el 统一安装实现
|
||||
3. **单一职责**:每个模块(和函数)只负责一件事
|
||||
4. **复用优先**:共享引擎(`tp--map-intervals`、`tp--stack-map-region`、`tp--pattern-apply`、`tp--replace-match-text`)承载重复逻辑,高层函数复用而非复制
|
||||
5. **统一接口**:所有核心属性函数支持相同的调用约定(整串/区域形式、层名、`$var`)
|
||||
6. **响应式解耦**:tp-reactive/tp-layer/tp-ops 不依赖渲染引擎;不加载 tp-render 时钩子为 nil,各模块优雅降级
|
||||
1. **严格分层**:模块只允许 `require` 并调用排在它前面的模块,字节编译器强制检查依赖顺序;且只声明真实存在的依赖(0.3.0 移除了 tp-stack→tp-ops 的幻影依赖,tp-palette 不依赖任何 tp- 模块)
|
||||
2. **钩子反转**:唯一许可的"向上调用"是两个钩子变量(`tp--reactive-update-function`、`tp--layer-refresh-function`),由 tp-render.el 统一安装实现;能改写为下行调用的反转(tp-text 链、批量刷新)已在 0.3.0 改写掉
|
||||
3. **单一职责**:每个模块(和函数)只负责一件事;一个子系统的完整生命周期住在一个模块里(匿名层的铸造/驻留/注销/GC 全在 tp-layer,层栈存储格式知识全在 tp-layer 的编解码器)
|
||||
4. **复用优先**:共享引擎(`tp--map-intervals`、`tp--stack-map-region`、`tp--pattern-apply`、`tp--replace-match-text`、`tp-reactive--buffer-layer-names`)承载重复逻辑,高层函数复用而非复制
|
||||
5. **统一接口**:所有核心属性函数支持相同的调用约定(整串/区域形式、层名、`$var`、多参数层)
|
||||
6. **响应式解耦**:tp-reactive/tp-layer/tp-ops 不依赖渲染引擎;不加载 tp-render 时钩子为 nil,各模块优雅降级(`tp-text` 替换自 0.3.0 起随 tp-ops 即可用);重渲染只访问层→缓冲区注册表登记的缓冲区,未知层才回退全扫描
|
||||
|
||||
311
tp-doctest.el
311
tp-doctest.el
@ -564,6 +564,317 @@
|
||||
(list (tp-forward-do #'upcase 'marker nil str 3)
|
||||
(substring-no-properties str))))
|
||||
|
||||
;; ---- 0.3.0: search bounds and SUBEXP ----
|
||||
;; Compared via tp-search / tp-at accessors, not prin1 output, so the
|
||||
;; property print order difference between Emacs 28 and 29+ cannot bite.
|
||||
(chk "V3-match-bounds" '((10 . 14))
|
||||
(with-temp-buffer
|
||||
(insert "TODO one TODO two")
|
||||
(tp-match-set "TODO" '(face warning) nil 5 18)))
|
||||
(chk "V3-subexp" '(((8 10 bold) (13 14 bold)) ((0 3 bold)))
|
||||
(list (tp-search (tp-regexp-set "\\([0-9]+\\)px" '(face bold)
|
||||
"margin: 10px 4px" nil nil 1)
|
||||
'face)
|
||||
;; group 1 does not participate in the "bar" match
|
||||
(tp-search (tp-regexp-set "\\(foo\\)\\|bar" '(face bold)
|
||||
"foo bar" nil nil 1)
|
||||
'face)))
|
||||
(chk "V3-subexp-out-of-range"
|
||||
'(:ERROR (error "Regexp \"[0-9]+\" has no group 2"))
|
||||
(tp-regexp-set "[0-9]+" '(face bold) "abc 123" nil nil 2))
|
||||
(chk "V3-regexp-bounds-and-reversed" '(((1 3 bold)) ((1 3 bold)))
|
||||
(list (tp-search (tp-regexp-set "a+" '(face bold) "aaaa" 1 3) 'face)
|
||||
(tp-search (tp-regexp-set "a+" '(face bold) "aaaa" 3 1) 'face)))
|
||||
|
||||
;; ---- 0.3.0: PREDICATE / NOT-CURRENT ----
|
||||
(chk "V3-predicate" '((3 6) ((6 11 20)))
|
||||
(list (with-temp-buffer
|
||||
(insert "abcdef")
|
||||
(tp-set 1 3 '(size 10))
|
||||
(tp-set 3 6 '(size 20))
|
||||
(goto-char 1)
|
||||
(let ((match (tp-forward 'size 15 nil 1
|
||||
(lambda (target v) (and v (> v target))))))
|
||||
(list (prop-match-beginning match) (prop-match-end match))))
|
||||
(let ((str (copy-sequence "hello world")))
|
||||
(tp-set 0 5 '(size 10) str)
|
||||
(tp-set 6 11 '(size 20) str)
|
||||
(tp-forward 'size 15 str 2
|
||||
(lambda (target v) (and v (> v target)))))))
|
||||
(chk "V3-not-current" '(2 5)
|
||||
(with-temp-buffer
|
||||
(insert "one two")
|
||||
(tp-set 1 4 '(mark t))
|
||||
(tp-set 5 8 '(mark t))
|
||||
(let (a b)
|
||||
(goto-char 2)
|
||||
(setq a (prop-match-beginning (tp-forward 'mark t)))
|
||||
(goto-char 2)
|
||||
(setq b (prop-match-beginning (tp-forward 'mark t nil 1 nil t)))
|
||||
(list a b))))
|
||||
|
||||
;; ---- 0.3.0: multi-argument parameterized layers ----
|
||||
(chk "V3-multiarg-specs" '((:foreground "red" :background "blue")
|
||||
((:foreground "red" :background "blue") "tip")
|
||||
(:foreground "white" :background "black"))
|
||||
(progn
|
||||
(tp-layer-reset)
|
||||
(define-tp tp-colors (fg bg)
|
||||
`(face (:foreground ,fg :background ,bg)))
|
||||
(list (tp-at 0 'face (tp-set "hello" 'tp-colors "red" "blue"))
|
||||
(let ((str (copy-sequence "hello")))
|
||||
(tp-set 0 5 '(tp-colors ("red" "blue") help-echo "tip") str)
|
||||
(list (tp-at 0 'face str) (tp-at 0 'help-echo str)))
|
||||
(with-temp-buffer
|
||||
(insert "Hello World")
|
||||
(tp-put-layer 1 10 '(tp-colors "white" "black") 0)
|
||||
(tp-at 1 'face)))))
|
||||
(chk "V3-multiarg-arity-error"
|
||||
'(:ERROR (error "tp layer tp-colors takes 2 argument(s), got 1"))
|
||||
(tp-set "hello" 'tp-colors "red"))
|
||||
(chk "V3-args-introspection"
|
||||
'((face (:foreground "red" :background "blue"))
|
||||
(fg bg)
|
||||
((face (:foreground "white" :background "black")) (face bold)))
|
||||
(progn
|
||||
(define-tps tp-badge (fg bg)
|
||||
`(tp-colors ,fg ,bg)
|
||||
'(face bold))
|
||||
(list (tp-layer-props-with-args 'tp-colors '("red" "blue"))
|
||||
(tp-layer-arglist 'tp-colors)
|
||||
(tp-group-props-with-args 'tp-badge '("white" "black")))))
|
||||
|
||||
;; ---- 0.3.0: layer visibility ----
|
||||
(chk "V3-hide-reveals-below"
|
||||
'(:visible base :face default :count 2 :layers (highlight base))
|
||||
(progn
|
||||
(tp-layer-reset)
|
||||
(define-tp base () '(face default))
|
||||
(define-tp highlight () '(face (:background "yellow")))
|
||||
(with-temp-buffer
|
||||
(insert "Hello World")
|
||||
(tp-push-layer 1 10 'base)
|
||||
(tp-push-layer 1 10 'highlight)
|
||||
(tp-hide-layer 1 10 'highlight)
|
||||
(list :visible (tp-at 1 'tp-name)
|
||||
:face (tp-at 1 'face)
|
||||
:count (tp-layer-count 1 10)
|
||||
:layers (tp-layer-list 1 10)))))
|
||||
(chk "V3-hide-all-bare-and-show" '((:face nil :count 2) (:background "yellow"))
|
||||
(progn
|
||||
(tp-layer-reset)
|
||||
(define-tp base () '(face default))
|
||||
(define-tp highlight () '(face (:background "yellow")))
|
||||
(with-temp-buffer
|
||||
(insert "Hello World")
|
||||
(tp-push-layer 1 10 'base)
|
||||
(tp-push-layer 1 10 'highlight)
|
||||
(tp-hide-layer 1 10 'highlight)
|
||||
(tp-hide-layer 1 10 'base)
|
||||
(let ((all-hidden (list :face (tp-at 1 'face)
|
||||
:count (tp-layer-count 1 10))))
|
||||
(tp-show-layer 1 10 'highlight)
|
||||
(list all-hidden (tp-at 1 'face))))))
|
||||
(chk "V3-hide-run-counts" '(1 0 0)
|
||||
(progn
|
||||
(tp-layer-reset)
|
||||
(define-tp base () '(face default))
|
||||
(with-temp-buffer
|
||||
(insert "Hello World")
|
||||
(tp-push-layer 1 10 'base)
|
||||
(list (tp-hide-layer 1 10 'base)
|
||||
(tp-hide-layer 1 10 'base)
|
||||
(tp-hide-layer 1 10 'nonexistent)))))
|
||||
(chk "V3-merge-excludes-hidden" '(:face bold :help nil :name merged)
|
||||
(progn
|
||||
(tp-layer-reset)
|
||||
(define-tp layer1 () '(face bold))
|
||||
(define-tp layer2 () '(help-echo "tip"))
|
||||
(with-temp-buffer
|
||||
(insert "Hello World")
|
||||
(tp-push-layer 1 10 'layer1)
|
||||
(tp-push-layer 1 10 'layer2)
|
||||
(tp-hide-layer 1 10 'layer2)
|
||||
(tp-merge-layers 1 10 'merged '(layer1 layer2))
|
||||
(list :face (tp-at 1 'face)
|
||||
:help (tp-at 1 'help-echo)
|
||||
:name (tp-at 1 'tp-name)))))
|
||||
(chk "V3-flatten-discards-hidden" '(default flat)
|
||||
(progn
|
||||
(tp-layer-reset)
|
||||
(define-tp base () '(face default))
|
||||
(define-tp highlight () '(face (:background "yellow")))
|
||||
(with-temp-buffer
|
||||
(insert "Hello World")
|
||||
(tp-push-layer 1 10 'base)
|
||||
(tp-push-layer 1 10 'highlight)
|
||||
(tp-hide-layer 1 10 'highlight)
|
||||
(tp-flatten-layers 1 10 'flat)
|
||||
(list (tp-at 1 'face) (tp-at 1 'tp-name)))))
|
||||
|
||||
;; ---- 0.3.0: movement additions and stack introspection ----
|
||||
(chk "V3-lower-layer" '(layer2 (layer2 layer3 layer1))
|
||||
(progn
|
||||
(tp-layer-reset)
|
||||
(define-tp layer1 () '(face bold))
|
||||
(define-tp layer2 () '(face italic))
|
||||
(define-tp layer3 () '(face underline))
|
||||
(with-temp-buffer
|
||||
(insert "Hello World")
|
||||
(tp-push-layer 1 10 'layer1)
|
||||
(tp-push-layer 1 10 'layer2)
|
||||
(tp-push-layer 1 10 'layer3)
|
||||
(tp-lower-layer 1 10 'layer3 1)
|
||||
(list (tp-layer-top 1 10) (tp-layer-list 1 10)))))
|
||||
(chk "V3-rotate-canonical" '((layer1 layer3 layer2) (layer1 layer3 layer2))
|
||||
(progn
|
||||
(tp-layer-reset)
|
||||
(define-tp layer1 () '(face bold))
|
||||
(define-tp layer2 () '(face italic))
|
||||
(define-tp layer3 () '(face underline))
|
||||
(list (with-temp-buffer
|
||||
(insert "Hello World")
|
||||
(tp-push-layer 1 10 'layer1)
|
||||
(tp-push-layer 1 10 'layer2)
|
||||
(tp-push-layer 1 10 'layer3)
|
||||
(tp-rotate-layer 1 10 'up)
|
||||
(tp-layer-list 1 10))
|
||||
(with-temp-buffer
|
||||
(insert "Hello World")
|
||||
(tp-push-layer 1 10 'layer1)
|
||||
(tp-push-layer 1 10 'layer2)
|
||||
(tp-push-layer 1 10 'layer3)
|
||||
(tp-rotate-layer 1 10 'down 2)
|
||||
(tp-layer-list 1 10)))))
|
||||
;; Compared via assq/plist-get per layer: the top layer's PROPS come from
|
||||
;; the direct text properties, whose plist order varies on Emacs 28.
|
||||
(chk "V3-layer-stack-at" '(((highlight base) (:background "yellow") default nil)
|
||||
((highlight base) (:background "yellow") default t)
|
||||
nil)
|
||||
(progn
|
||||
(tp-layer-reset)
|
||||
(define-tp base () '(face default))
|
||||
(define-tp highlight () '(face (:background "yellow")))
|
||||
(with-temp-buffer
|
||||
(insert "Hello World")
|
||||
(tp-push-layer 1 10 'base)
|
||||
(tp-push-layer 1 10 'highlight)
|
||||
(let* ((probe (lambda ()
|
||||
(let ((stack (tp-layer-stack-at 1)))
|
||||
(list (mapcar #'car stack)
|
||||
(plist-get (cdr (assq 'highlight stack)) 'face)
|
||||
(plist-get (cdr (assq 'base stack)) 'face)
|
||||
(plist-get (cdr (assq 'highlight stack))
|
||||
'tp-hidden)))))
|
||||
(visible (funcall probe)))
|
||||
(tp-hide-layer 1 10 'highlight)
|
||||
(list visible
|
||||
(funcall probe)
|
||||
(with-temp-buffer (insert "Hello") (tp-layer-stack-at 1)))))))
|
||||
(chk "V3-put-push-noerror" '(nil nil)
|
||||
(with-temp-buffer
|
||||
(insert "Hello World")
|
||||
(list (tp-put-layer 1 10 'no-such-layer 0 nil t)
|
||||
(tp-push-layer 1 10 'no-such-layer nil t))))
|
||||
|
||||
;; ---- 0.3.0: reactive layer-buffer registry and lifecycle ----
|
||||
(defvar reg-color "red")
|
||||
(chk "V3-registry-and-track" '(unknown t (reg-layer))
|
||||
(progn
|
||||
(tp-layer-reset)
|
||||
(define-tp reg-layer ()
|
||||
:props '(face (:foreground $reg-color)))
|
||||
(let ((before (tp-reactive-layer-buffers 'reg-layer)))
|
||||
(with-temp-buffer
|
||||
(insert "Hello")
|
||||
(tp-push-layer 1 6 'reg-layer)
|
||||
(let ((registered (equal (tp-reactive-layer-buffers 'reg-layer)
|
||||
(list (current-buffer)))))
|
||||
(list before
|
||||
registered
|
||||
(let ((s (tp-set "hello" 'reg-layer)))
|
||||
(with-temp-buffer
|
||||
(insert s)
|
||||
(tp-reactive-track-buffer)))))))))
|
||||
(defvar tmp-color "green")
|
||||
(chk "V3-gc-anonymous" '(1 nil nil)
|
||||
(progn
|
||||
(tp-reactive-reset)
|
||||
(tp-layer-reset)
|
||||
(let ((buf (generate-new-buffer "*gc-demo*")))
|
||||
(with-current-buffer buf
|
||||
(insert "Hello")
|
||||
(tp-set 1 6 '(face (:foreground $tmp-color))))
|
||||
(kill-buffer buf)
|
||||
(let ((collected (tp-gc-anonymous-layers)))
|
||||
(list (length collected)
|
||||
(tp-layer-props (car collected))
|
||||
;; string-only layers stay `unknown' and are kept
|
||||
(let ((s (tp-set "hello" '(face (:foreground $tmp-color)))))
|
||||
(ignore s)
|
||||
(tp-gc-anonymous-layers)))))))
|
||||
|
||||
;; ---- 0.3.0: minimal-diff tp-text re-rendering ----
|
||||
(defvar counter-val "0")
|
||||
(chk "V3-tp-text-minimal-diff" '("count: 9 items" 105 10)
|
||||
(progn
|
||||
(tp-layer-reset)
|
||||
(setq counter-val "0")
|
||||
(define-tp counter-label ()
|
||||
:props '(tp-text $counter-val))
|
||||
(with-temp-buffer
|
||||
(insert "count: 0 items")
|
||||
(tp-set 8 9 'counter-label)
|
||||
(let ((m (copy-marker 10))) ; marker on the "i" of "items"
|
||||
(setq counter-val "9")
|
||||
(list (buffer-substring-no-properties 1 (point-max))
|
||||
(char-after m)
|
||||
(marker-position m))))))
|
||||
(chk "V3-tp-text-noop-unmodified" nil
|
||||
(with-temp-buffer
|
||||
(insert "count: 9 items")
|
||||
(tp-set 8 9 'counter-label)
|
||||
(set-buffer-modified-p nil)
|
||||
(setq counter-val "9")
|
||||
(buffer-modified-p)))
|
||||
|
||||
;; ---- 0.3.0: ABSOLUTE coordinates and palette primaries ----
|
||||
(chk "V3-intervals-absolute"
|
||||
'(((1 6 (face bold)) (6 7 nil) (7 12 (face italic))) "bold text")
|
||||
(list (with-temp-buffer
|
||||
(insert "Hello World")
|
||||
(tp-set 1 6 '(face bold))
|
||||
(tp-set 7 12 '(face italic))
|
||||
(tp-intervals 1 12 nil t))
|
||||
(with-temp-buffer
|
||||
(insert "Hello World")
|
||||
(tp-set 1 6 '(face bold))
|
||||
(dolist (iv (tp-intervals 1 12 nil t))
|
||||
(when (eq (plist-get (nth 2 iv) 'face) 'bold)
|
||||
(tp-add (nth 0 iv) (nth 1 iv) '(help-echo "bold text"))))
|
||||
(tp-at 1 'help-echo))))
|
||||
(chk "V3-intervals-map-absolute" '((1 6 bold) (6 7 nil) (7 12 italic))
|
||||
(with-temp-buffer
|
||||
(insert "Hello World")
|
||||
(tp-set 1 6 '(face bold))
|
||||
(tp-set 7 12 '(face italic))
|
||||
(tp-intervals-map
|
||||
(lambda (start end props belows)
|
||||
(ignore belows)
|
||||
(list start end (plist-get props 'face)))
|
||||
1 12 nil t)))
|
||||
;; The resolved color depends on the frame's light/dark mode, like the
|
||||
;; U-parsecolor2 assertion above.
|
||||
(chk "V3-palette-primaries" '(t nil (t t t nil))
|
||||
(list (and (member (tp-palette-color 'info :fg)
|
||||
'("#0969da" "#58a6ff"))
|
||||
t)
|
||||
(tp-palette-color 'no-such-palette :fg)
|
||||
(list (tp-palette-has-p 'info)
|
||||
(tp-palette-has-p 'info :fg)
|
||||
(tp-palette-has-p 'info :border)
|
||||
(tp-palette-has-p 'no-such-palette))))
|
||||
|
||||
(princ (format "\nTOTAL: %d FAILS: %d\n" tp-doctest--total tp-doctest--fails))
|
||||
(when (> tp-doctest--fails 0) (kill-emacs 1))
|
||||
|
||||
|
||||
@ -1148,7 +1148,8 @@ Returns a new plist (does not modify the original)."
|
||||
OBJECT is a string or buffer; nil means the current buffer.
|
||||
If START and END are not provided, they default to the whole of
|
||||
OBJECT: 0/(length OBJECT) for strings, `point-min'/`point-max' of
|
||||
OBJECT for buffers (the current buffer when OBJECT is nil)."
|
||||
OBJECT for buffers (the current buffer when OBJECT is nil).
|
||||
Returns nil."
|
||||
(interactive)
|
||||
(let ((beg (or start
|
||||
(cond ((stringp object) 0)
|
||||
@ -1160,7 +1161,8 @@ OBJECT for buffers (the current buffer when OBJECT is nil)."
|
||||
((bufferp object)
|
||||
(with-current-buffer object (point-max)))
|
||||
(t (point-max))))))
|
||||
(set-text-properties beg finish nil object)))
|
||||
(set-text-properties beg finish nil object)
|
||||
nil))
|
||||
|
||||
(provide 'tp-ops)
|
||||
;;; tp-ops.el ends here
|
||||
|
||||
Loading…
Reference in New Issue
Block a user