Give independent consumers their own rules, cascade layer ordering, and source-order counters so packages such as Ebox cannot pollute TP's default stylesheet or each other. Match generic class and state tokens by value and document caller-owned stylesheet lifecycle. Verified: make clean; make test (728/728); make compile WERROR=t; checkdoc tp-style.el; git diff --check; Ebox make test against ../tp.
57 KiB
tp 代码架构文档
未来主版本目标:TP 将重构为独立 retained/reactive text runtime,并可作为 Ebox 等高级 consumer 的通用底层执行器。TP 自身完整、可独立阅读的已批准目标见 TP Retained/Reactive Text Runtime 目标架构(English);它不依赖 sibling Ebox checkout。本文描述当前已经落地的实现,并明确标出仍处于迁移期的旧 runtime 与 TP 1.0 功能切片。
本文档描述 tp 库的模块分层结构与函数调用层次,从底层基础模块到上层功能模块的分层组织。TP 1.0 的纯 style/cascade kernel、exact signal/binding graph 与 retained surface publication 已分别在 tp-style.el、tp-reactive.el、tp-surface.el 落地;旧 managed façade 尚未切换。
当前 API 的规范契约见 API-SEMANTICS.md;Emacs 原生 文本属性覆盖范围、已确认问题与演进路线见 REPOSITORY-AUDIT.md。
自 0.2.0 起,原来的单文件 tp.el 已拆分为分层模块,tp.el 只作为总入口((require 'tp) 依次加载全部模块,用户接口不变)。0.3.0 进一步收紧了模块边界:tp-text 处理链下沉至 tp-ops、批量更新上收至 tp-render、层栈存储编解码与匿名层机制归位 tp-layer,钩子变量从四个减少到两个。Stage 3 新增 tp-query,承载原生文本查询/change 封装与修改策略。各变更的缘由见 CHANGELOG.md。
目录
架构概述
tp 采用严格的线性分层:每个模块只允许 require 并调用排在它前面的模块,字节编译器强制检查这一依赖顺序。加载顺序即依赖顺序:
tp-core → tp-style → tp-reactive → tp-layer → tp-ops → tp-search
→ tp-render → tp-stack → tp-query → tp-palette → tp-builtins
注意加载顺序是依赖顺序的上界:并非每个模块都依赖它前面的全部模块。各模块实际 require 的 tp- 模块如下(逐一核对自源码头部):
| 模块 | require 的 tp- 模块 |
|---|---|
| tp-core | —(仅 cl-lib、dash、seq) |
| tp-style | tp-core |
| tp-reactive | tp-core |
| tp-layer | tp-core、tp-style、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-query | tp-core |
| tp-palette | —(不依赖任何 tp- 模块,仅 subr-x) |
| tp-builtins | tp-core、tp-layer、tp-ops、tp-palette |
┌────────────────────────────────────────────────────────────────┐
│ tp.el —— 总入口,按序 require 全部模块 │
└────────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────────┐
│ tp-builtins.el 内置层(tp-link, tp-space, tp-headline …)、 │
│ tp-palette-show、显示缓冲辅助宏 │
├────────────────────────────────────────────────────────────────┤
│ tp-palette.el 明/暗主题调色板数据、tp-parse-color │
│ (独立叶模块,不依赖任何 tp- 模块) │
├────────────────────────────────────────────────────────────────┤
│ tp-query.el 原生文本 lookup/change 封装、mutation policy │
├────────────────────────────────────────────────────────────────┤
│ tp-stack.el 层栈操作(push/pop/move/hide/show/merge …) │
├────────────────────────────────────────────────────────────────┤
│ 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-style.el property schema、structured selector、 │
│ cascade、custom property、computed value │
├────────────────────────────────────────────────────────────────┤
│ tp-core.el 区间遍历、plist/face 合并引擎、 │
│ 调试日志、$var 符号工具(无可变状态) │
└────────────────────────────────────────────────────────────────┘
实线层级:上层模块调用下层模块(require 依赖)。
虚线(◁╌╌):钩子变量 —— 下层模块预留的函数变量,
由 tp-render.el 在加载时安装实现(见下文)。
需要"向上调用"的逻辑全部收拢在 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)。
模块分层
Canonical records 与 dataflow
Stage 2 canonical façade 是内部模型,不改变公开入口和历史返回值。五个记录承担模块间的规范数据边界:
| 记录 | 所有者 | 用途 |
|---|---|---|
tp--native-range |
tp-core | 目标对象的原生 [START, END) 范围;字符串使用 0-based,缓冲区使用原生 buffer position |
tp--presence |
tp-core | 区分属性缺失、present nil、present non-nil |
tp--request |
tp-ops | 公开重载参数解析后的规范请求:对象、范围、操作、属性/值/谓词、修改策略 |
tp--match |
tp-search | 搜索内部匹配结果,统一字符串与缓冲区路径 |
tp--result |
tp-search | 搜索内部结果载体;最终按公开 API 的历史契约适配返回 |
数据流为:公开入口解析成 tp--request,tp-core 提供对象、native range、presence 与 adapter,tp-ops/tp-search/tp-stack 只在 I/O 边界按对象类型分支。内部搜索先产生 canonical tp--match / tp--result,再由公开入口保留旧返回结构;tp-intervals / tp-intervals-map 的缓冲区 relative 默认是显式保留的兼容例外。
tp-core.el:基础工具
最底层模块,不依赖任何其他 tp 模块,提供区间遍历、合并引擎与调试能力。0.3.0 起 tp-core 不再持有任何可变状态(匿名层计数器已迁至 tp-layer;仅剩 tp-debug-mode / tp-debug-echo 两个 defcustom 用户选项)。
区间操作
| 函数 | 描述 | 主要调用者 |
|---|---|---|
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 |
plist / face 合并引擎
| 函数 | 描述 | 主要调用者 |
|---|---|---|
tp--deep-merge-plist |
深度合并两个 plist | tp-add, tp--prepend-face 等 |
tp--prepend-face |
face 家族属性的合并逻辑 | tp-add, tp-match-add |
tp--merge-face-values |
合并两个 face 值 | 合并引擎内部 |
tp--merge-duplicate-keys |
合并 plist 中的重复键 | tp--parse-args |
tp--parse-face-list |
解析 face 列表 | 合并引擎内部 |
tp--get-nested |
按路径获取嵌套属性值 | tp-get, tp-at |
tp-face-properties(常量,'(face font-lock-face mouse-face))定义参与 face 感知合并的属性家族。
$var 符号工具
| 函数 | 描述 |
|---|---|
tp--reactive-symbol-p |
检查是否为 $var 响应式符号 |
tp--reactive-var-symbol |
$var 符号转变量符号 |
tp--collect-reactive-symbols |
收集表达式中所有 $var 符号 |
tp--resolve-reactive-symbols |
将 $var 解析为当前值(支持覆盖表) |
tp--extract-reactive-props |
提取引用特定变量的属性 |
调试工具
| 变量/函数 | 描述 |
|---|---|
tp-debug-mode |
启用/禁用调试模式 |
tp-debug-echo |
是否在 minibuffer 显示调试信息 |
tp-debug-log |
记录调试信息 |
tp-debug-show |
显示 tp-debug 缓冲区 |
tp-debug-clear |
清除调试日志 |
另有辅助宏 tp-with-current-buffer。
tp-style.el:纯 schema 与 cascade kernel
只依赖 tp-core,不接触 buffer、marker、mount 或订阅。它拥有 namespaced property schema、structured subject/selector、origin/importance/layer/specificity/scope/source-order cascade、逐属性继承、tagged CSS-wide values、custom property/tp-var、显式 tp-computed、named style、provenance 和最终 Emacs property projection。默认 stylesheet 只服务便利入口;独立 consumer 使用 tp-stylesheet-create 持有隔离的 rule、layer 与 source-order domain。
普通 function value 保持 literal;只有 tp-computed 才会求值一次。schema/rule 注册先完整校验再原子替换。shorthand 在进入候选集前展开一次,计算结果随后经过 variable/wide-value resolution、normalizer 和 validator。该模块提供后续 signal/binding 与 retained surface 共用的唯一 style 语义,不建立第二套 renderer。
tp-reactive.el:响应式基础设施
只依赖 tp-core。文件上半部是 TP 1.0 的唯一新响应式执行语义:global/buffer-scoped signal、owner+key binding identity、dynamic dependency collection、binding→binding graph、transaction-local candidate signal values、dirty dedupe/topological lazy flush、nested write stabilization、rollback-capable transaction participant、cycle path、owner disposal、variable adapter 和 public counters。participant 在全部 surface side state 发布后、source commit 前晋升 client-owned opaque state,失败时按逆序撤销;它不解释 client state。正常新热路径只从 source subscriber set 到 dirty binding,不读取 buffer-list、文本上的 tp-name/tp-layers 或 layer→buffer registry。
文件下半部仍暂存 0.3 façade 所需的变量→layer watcher、batch queue 和 layer→buffer registry,以保持旧测试在 retained surface 建成前可运行;它们没有被新 graph 调用,并将在最终 cutover phase 与 tp-render.el 扫描路径一起删除。这个暂存区不是第二套长期 public runtime。
tp-surface.el:retained publication owner
该模块拥有 surface/object identity、marker-backed mount index、range anchor、properties ledger、buffer diff、publication journal 与 revision。tp-surface-update-scoped 复用同一完整 candidate prepare 和同一事务发布器,只把 live object handles 解析成当前事务的授权范围;它不是子树 renderer,也不接受 Ebox owner、dirty kind、layout patch 或 raw marker。范围外输出变化在 prepare 阶段拒绝,显式 root fallback 除外。
只依赖 tp-core、tp-style 与 tp-reactive。它集中拥有 prepare context、candidate/live object identity、pure surface plan、content/properties capability、range anchor、logical object→多个 marker-backed mounts、object-keyed mount index、position→object side index、properties contribution ledger、text/property diff、multi-buffer change group、silent-property inverse journal、opaque client state、revision、generic report 和 buffer-kill lifecycle。没有可见字符的 logical object 必须显式 retain;不连续输出通过 prepare-only object→plan-fragment attachment 建立,plan 本身仍没有 handle 或 position。normal update 从 binding owner 直接取得 prepared surface,再从 object 直接取得 mounts;不读取 buffer-list,也不按 tp-name、tp-layers 或显示文本反查 identity。
content mount 可以替换其拥有的 disjoint span;外部字符编辑会使 mount stale。properties mount 只能修改 attached anchor 上声明的 direct properties;同一 surface 内重叠 contribution 通过 native property schema 合成。外部值与 TP last-published value 不同时,prepare 报 tp-property-conflict,调用者必须 tp-range-rebase 或 unmount。独立 surfaces 的字符范围当前必须不重叠,以保持单一、可证明的 ownership journal。
tp-propertize 与 tp-apply 是 tp-style projection 加 tp-ops mutation primitive 的 one-shot 组合,不创建 runtime state。tp-watch 只把 range anchor、object binding 和 properties surface 组合成普通用户入口;它没有独立 scheduler、diff 或 publication path。
依赖注册与管理
| 函数/变量 | 描述 |
|---|---|
tp-reactive-deps |
变量 → 依赖它的层及属性 的注册表 |
tp--register-reactive-deps |
注册响应式依赖 |
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 |
重置全部响应式注册表(含批量队列与层→缓冲区注册表) |
层→缓冲区注册表(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--queue-batch-update |
将更新加入待处理队列 tp--batch-update-pending(刷新在 tp-render) |
钩子变量:tp--reactive-update-function(定义于此,由 tp-render.el 安装)。
tp-layer.el:层定义、解析与层栈存储
依赖 tp-core、tp-reactive。提供 define-tp / define-tps 宏、层注册表、层名解析,以及 0.3.0 归位至此的层栈存储编解码与匿名层完整生命周期(铸造、驻留、注销、GC)。
层定义
| 函数/宏 | 描述 | 依赖 |
|---|---|---|
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 |
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 |
单参数形式(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-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(-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 |
匿名层机制与 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 |
规范化层规格(含多参数 (LAYER ARG1 ... ARGN)) |
tp--build-layer-props / tp--layer-stack-to-list |
旧式编解码原语(无隐藏层语义) |
tp--stack-hidden-p |
层 plist 是否带 tp-hidden 标志 |
tp--plist-equivalent-p / tp--assert-hidden-render-cache |
普通栈解码时验证完整存储的直接渲染缓存;无刷新上下文的不一致在改写前发出 tp-layer-conflict |
tp--stack-props-to-list |
原始属性 → 有序层列表(顶层在前,含隐藏层)。完整存储模式下 tp-layers 持有完整栈,直接属性只是最顶可见层的渲染缓存,并在普通解码时执行冲突检查;definition/reactive refresh 由 tp-render 在明确可见 entry 上协调外部编辑 |
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 是它的调用入口,非参数化
层重定义后把 old props 一并传给渲染层,触发已挂载区域的 old/new 所有权协调。
tp-ops.el:核心属性操作与 tp-text 处理链
依赖 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--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-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 |
获取属性
| 函数 | 描述 | 依赖 | 被依赖 |
|---|---|---|---|
tp-get |
获取范围内的属性值(返回区间列表) | tp--get-nested | 搜索函数 |
tp-at |
获取单个位置的属性值 | tp--get-nested | 大多数高层函数 |
tp-member |
区分"属性值为 nil"与"属性不存在"(plist-member 风格) | - | 用户 API |
删除属性
| 函数 | 描述 | 依赖 | 被依赖 |
|---|---|---|---|
tp-remove |
移除属性或子属性 | tp--remove-property, tp--remove-sub, tp--remove-*-from-string | 用户 API |
tp-clear |
清除所有属性(显式返回 nil) | - | 用户 API |
tp-search.el:模式匹配与搜索
依赖 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 |
在字符串匹配处设置/重置/合并属性;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 |
共享的模式匹配引擎(空模式/零宽模式安全;承载 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-forward |
向前搜索 N 次并移动点;省略 VALUE 匹配任意直接存在值,显式 nil 精确匹配 present-nil | tp--property-search-forward |
tp-backward |
向后搜索 N 次并移动点(与向前语义对称,同样新增 PREDICATE/NOT-CURRENT) | tp--property-search-backward |
tp--property-search-forward / tp--property-search-backward |
基于统一直接属性 run 的单步搜索引擎 | tp--property-matches |
tp--property-match-p |
谓词归一化(函数优先;否则 tp-any-value 通配,其他值用 equal) |
- |
tp--property-matches |
字符串/缓冲区共用、presence-aware 的直接属性 run 收集器 | text-properties-at, next-property-change |
tp-search |
收集所有 (START END VALUE) 匹配区间 |
tp--property-matches |
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 |
向前/向后搜索并在第 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 |
tp--replace-match-text |
共享的匹配文本替换助手(缓冲区支持变长替换;字符串变长时报错) | - |
tp-render.el:响应式渲染引擎
依赖 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 |
用 old/new 所有权协调重渲染已挂载区域,并写穿到 tp-layers 栈存储 |
tp--layer-render-props, tp-search-map, tp--write-layer-through-stack-storage |
tp--write-layer-through-stack-storage |
先按旧定义移除仍由该层拥有的键,再写入新定义;被覆盖或隐藏的副本也保持最新 | tp--stack-props-to-list, tp--stack-build-props [tp-layer] |
tp--reconcile-layer-props / tp--reconcile-layer-region |
计算和写入 old/new 属性协调;保留不属于旧层或已被外部改写的值 | - |
tp--update-layer-computed |
更新 :compute 计算属性(nil 可传播;错误向上抛出) |
tp--store-computed-value |
tp--layer-render-props / tp--layer-reactive-props |
求取层的渲染属性 | tp-layer-props |
响应式文本(tp-text)
| 函数 | 描述 | 依赖 |
|---|---|---|
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、合并层定义、重渲染或入批量队列(嵌套写入经队列而非递归)。尾部刷新置于 unwind-protect 清理段中,重渲染抛错也不会把队列条目困死。安装为 tp--reactive-update-function |
加载末尾执行安装(与源码逐字一致):
(setq tp--reactive-update-function #'tp--reactive-apply-update)
(setq tp--layer-refresh-function #'tp--update-layer-regions)
tp-stack.el:属性层栈操作
依赖 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--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 |
层操作(公开 API)
| 函数 | 描述 | 依赖 |
|---|---|---|
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-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-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-exists-p |
检查层是否存在 | tp-layer-list |
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 |
层属性操作
| 函数 | 描述 | 依赖 |
|---|---|---|
tp-add-to-layers |
向特定层添加属性 | tp--deep-merge-plist, tp--stack-map-region |
tp-add-to-all-layers |
向所有层添加属性 | tp-add-to-layers |
Managed lifecycle(Stage 4)
| 函数/状态 | 描述 | 依赖 |
|---|---|---|
tp-meta |
lifecycle metadata,保存在 tp-layers 权威存储中;直接渲染属性和 public stack query 会剥离它 |
tp--managed-render-props, tp--managed-public-layer-props |
tp--managed-operation-counter |
transaction/entry id 的单调计数器 | tp--managed-next-operation-id |
tp-attach-managed-layers |
扫描已有 managed storage、规范化 metadata、登记发现的层并返回层名 | tp--managed-normalize-stack, tp-reactive--register-layer-buffer |
tp-detach-managed-layers |
移除 managed storage;KEEP-RENDERED 时保留当前可见渲染属性 | tp--managed-detached-props |
tp-managed-layer-diagnostics |
只读层诊断:entries、args、registry、buffers、errors | tp--managed-buffer-diagnostic-data |
tp-managed-buffer-diagnostics |
只读缓冲区诊断 | tp--managed-buffer-diagnostic-data |
tp-managed-diagnostics |
全局只读诊断,含 theme diagnostics | tp--managed-theme-diagnostics |
tp-layer-transaction |
managed transaction;失败恢复原文本/属性快照,默认发出 tp-layer-transaction-error |
tp--transaction-* |
只要 layer stack entry 携带 tp-meta,即使只有一个 managed layer,也使用 tp-layers 保存权威 stack storage。参数化 mounted entry 保存 args、arglist 与 definition-version;层重定义后通过保存的 args 刷新既有 entry。历史无 metadata entry 作为 legacy entry 保守处理。
tp-query.el:原生文本查询与修改策略
只依赖 tp-core。提供 Stage 3/5 原生 façade:直接/effective/source-aware text lookup、overlay-aware char lookup、property change/any/not-all 封装,以及显式 modified/read-only 修改策略。overlay lifecycle(创建、移动、删除、priority 管理)不属于 tp-query。
查询记录与 lookup
| 函数/记录 | 描述 | 依赖 |
|---|---|---|
tp-lookup-result |
cl-defstruct 结果记录:property、value、present-p、source、mode、object、position、overlay |
- |
tp-lookup |
按 MODE 查询属性;支持 :text-direct、:text-effective、:text-source、:char、:char-source |
tp--lookup-direct, tp--lookup-effective, tp--lookup-char, tp--lookup-source-cell |
tp--lookup-direct |
只检查 text-properties-at 的直接 plist,区分 explicit nil 与 absent |
plist-member |
tp--lookup-effective |
值使用 get-text-property,source 使用 text-only 解释 |
tp--lookup-source-cell |
tp--lookup-char |
使用 get-char-property-and-overlay,overlay 获胜时 source 为 :overlay 且记录 overlay 对象 |
get-char-property-and-overlay |
tp--lookup-source-cell |
按 direct → category → alias → default → absent 解释来源 | text-properties-at, symbol-plist, char-property-alias-alist, default-text-properties |
tp--lookup-alias-cell |
查找 char-property-alias-alist 中第一个直接存在的 alias 属性 |
plist-member |
property change 与区域谓词
| 函数 | 描述 | 依赖 |
|---|---|---|
tp-property-change |
:direction :next / :previous;传入 PROPERTY 时走 single-property change,省略时走 all-property change |
next/previous-property-change, next/previous-single-property-change |
tp-property-any |
text-property-any 薄封装 |
text-property-any |
tp-property-not-all |
text-property-not-all 薄封装 |
text-property-not-all |
修改策略
| 函数/宏 | 描述 |
|---|---|
tp--mutation-policy-modes |
校验并归一化 :modified 与 :read-only;拒绝 (:modified :silent :read-only :respect) |
tp-with-mutation-policy |
三种有效组合:ordinary+respect、ordinary+inhibit、silent+inhibit |
insert/copy/yank/stickiness/narrowing/indirect buffer 均不在 tp-query 中封装,行为直接委托 Emacs 原生操作。
tp-palette.el:调色板数据
不依赖任何 tp- 模块(仅 subr-x),是独立的叶模块。明/暗主题双值调色板系统,tp-palette-alist 是唯一数据源。
| 函数/宏/变量 | 描述 |
|---|---|
define-tp-palette |
定义调色板(重定义立即生效);别名 tp-define-palette |
tp-palette-alist |
调色板注册表(唯一数据源) |
tp-theme-generation / tp-theme-last-* |
theme lifecycle diagnostics:generation、last hook source、refresh mode、refreshed ranges、errors |
tp-theme-change-hook |
enable-theme / disable-theme 后运行的 hook;palette 只负责事件检测,managed renderer 可订阅 |
tp--palette-after-enable-theme / tp--palette-after-disable-theme |
theme lifecycle advice,递增 generation 并记录来源 |
tp-parse-color |
解析颜色规格(支持 ("light" . "dark") 及单边 cons) |
tp-theme-dark-p / tp-theme-light-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 |
取纯色值 |
tp-builtins.el:内置层与辅助工具
最上层模块,依赖 tp-core、tp-layer、tp-ops、tp-palette。提供开箱即用的内置层与展示/缓冲辅助。
| 定义 | 描述 |
|---|---|
| 内置层 | 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 |
符号加后缀助手(0.3.0 起转为私有;tp-suffix-symbol 保留为废弃兼容别名) |
钩子变量:唯一许可的反向调用
分层规则的唯一例外是两个钩子变量:下层模块声明变量并在需要时 funcall,实现由 tp-render.el 在加载时安装。这样下层模块不必 require 上层模块,依赖图保持严格单向;而在未加载 tp-render 时,下层模块依然可用(钩子为 nil 时优雅降级:层可以定义与应用,只是没有自动重渲染)。
| 钩子变量 | 声明于 | 安装的实现(tp-render.el) | 用途 |
|---|---|---|---|
tp--reactive-update-function |
tp-reactive.el | tp--reactive-apply-update |
变量监听器触发的重计算与重渲染 |
tp--layer-refresh-function |
tp-layer.el | tp--update-layer-regions |
层重定义后刷新已应用区域 |
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-style | schema、named style、default stylesheet 与调用方持有的独立 stylesheet instances | 纯 style definition 和 rule/layer/source-order 状态;不保存 object、buffer 或 mount;独立实例不被全局 reset 暗中清理 | tp-style-reset / tp-style-reset-rules |
| tp-reactive | signals、owner bindings、dependency subscriber sets、variable adapters、transaction-local scheduler state、public counters | TP 1.0 exact reactive graph;normal update 不扫描 buffer | tp-reactive-reset;buffer-scoped signal 随 buffer kill |
| tp-surface | buffer-local surfaces、object/mount/index、range anchors、property ledgers、root/scoped publication、plan/client-state/revision/report | TP 1.0 retained publication;global registry 仅 weak-reference | tp-surface-unmount;buffer kill authoritative teardown |
| tp-reactive | tp-reactive-deps |
变量 → 依赖层 注册表 | tp-reactive-reset |
| tp-reactive | tp-layer-watchers / tp-layer-computed / tp-layer-data / tp-reactive-observer-errors |
:watch / :compute / :data 注册表与结构化 observer 错误 |
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 各注册表(计数器除外)。
函数调用关系图
(标注 [模块] 表示函数所在文件;╌╌▷ 表示经钩子变量的间接调用。)
tp-set 调用链
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-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-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 原生,区域形式)
└── 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-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 原生)
└── tp--ops-register-layer-buffer [tp-ops]
└── tp-reactive--register-layer-buffer [tp-reactive]
define-tp 调用链
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--ensure-reactive-variables [tp-reactive]
├── tp--register-layer-data [tp-reactive]
│ └── add-variable-watcher(Emacs 原生)
├── tp--register-layer-computed [tp-reactive]
├── tp--apply-initial-computed [tp-reactive]
├── tp--register-reactive-deps [tp-reactive]
├── tp--register-layer-watchers [tp-reactive]
├── tp--resolve-reactive-symbols [tp-core]
├── tp--set-layer-props [tp-layer]
└── tp--layer-refresh [tp-layer]
╌╌▷ tp--update-layer-regions [tp-render](经钩子)
└── tp-search-map [tp-search]
└── put-text-property
tp-push-layer 调用链
tp-push-layer [tp-stack]
├── tp--parse-layer-args [tp-stack]
└── tp-put-layer [tp-stack]
├── tp--put-layer-specs [tp-stack]
│ ├── tp--normalize-layer-spec [tp-layer]
│ │ └── 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-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]
响应式更新调用链
(setq some-reactive-var new-value)
└── tp--reactive-variable-watcher [tp-reactive]
├── tp--invoke-layer-watchers [tp-reactive](:watch 回调)
└── ╌╌▷ tp--reactive-apply-update [tp-render](经钩子)
├── tp--update-layer-computed [tp-render]
│ ├── tp--resolve-reactive-symbols [tp-core]
│ └── tp--set-layer-props [tp-layer]
├── tp--set-layer-props [tp-layer](深合并回层定义;setq-local 不写全局)
├── tp--update-layer-regions [tp-render](属性更新)
│ └── 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-render])/ 更新中的嵌套写入:
└── tp--queue-batch-update [tp-reactive](入队,不递归)
└── 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
设计原则
- 严格分层:模块只允许
require并调用排在它前面的模块,字节编译器强制检查依赖顺序;且只声明真实存在的依赖(0.3.0 移除了 tp-stack→tp-ops 的幻影依赖,tp-palette 不依赖任何 tp- 模块) - 钩子反转:唯一许可的"向上调用"是两个钩子变量(
tp--reactive-update-function、tp--layer-refresh-function),由 tp-render.el 统一安装实现;能改写为下行调用的反转(tp-text 链、批量刷新)已在 0.3.0 改写掉 - 单一职责:每个模块(和函数)只负责一件事;一个子系统的完整生命周期住在一个模块里(匿名层的铸造/驻留/注销/GC 全在 tp-layer,层栈存储格式知识全在 tp-layer 的编解码器)
- 复用优先:共享引擎(
tp--map-intervals、tp--stack-map-region、tp--pattern-apply、tp--replace-match-text、tp-reactive--buffer-layer-names)承载重复逻辑,高层函数复用而非复制 - 统一接口:所有核心属性函数支持相同的调用约定(整串/区域形式、层名、
$var、多参数层) - 响应式解耦:tp-reactive/tp-layer/tp-ops 不依赖渲染引擎;不加载 tp-render 时钩子为 nil,各模块优雅降级(
tp-text替换自 0.3.0 起随 tp-ops 即可用);重渲染只访问层→缓冲区注册表登记的缓冲区,未知层才回退全扫描