# TP 2.0 公共 API 与用法参考 本文是 TP 当前实现的完整公共入口索引。它以 tp.el 加载的模块为准;带 tp-- 前缀的函数、变量和结构体是内部实现,不属于本文的稳定 API。 - 快速开始与能力边界:[README](../README.md)、[中文 README](../README_CN.md) - 语义合同:[API-SEMANTICS.md](API-SEMANTICS.md) - 当前架构:[ARCHITECTURE.md](ARCHITECTURE.md) - 可运行示例:[examples/](../examples/) ## 1. 运行边界 TP 只负责 Emacs text properties、响应式 signal/binding、retained object、 marker-backed mount、diff、事务和 Buffer publication。它不实现 CSS selector、 stylesheet、specificity、cascade、Box、Flex、Grid、测量或布局,也不依赖 Ebox/ECSS。 所有坐标都遵循 Emacs 原生对象的坐标规则: - string 使用从 0 开始的 [start, end); - buffer 使用从 1 开始的 [start, end); - tp-surface-plan 中的 content leaf range 是相对于该 leaf 文本的 0-based offset,不是 Buffer position。 普通函数值、callback、keymap command 和 list 都是 literal data。只有显式的 tp-computed source 会被执行。显式存在且值为 nil 与属性不存在始终不同。 ## 2. 先选入口 | 目标 | 入口 | 是否建立 live state | | --- | --- | --- | | 创建带属性的 string | tp-propertize | 否 | | 一次性改已有范围 | tp-apply、tp-set、tp-reset、tp-add、tp-remove、tp-clear | 否 | | 查询属性和区间 | tp-get、tp-at、tp-member、tp-lookup | 否 | | 按文字或属性搜索 | tp-match-*、tp-regexp-*、tp-search*、tp-forward/backward | 否 | | 让已有 host text 响应变化 | tp-watch | 是,properties | | 管理 TP 自己拥有的文字 | tp-surface-mount / tp-surface-update | 是,content | | 检查或卸载 publication | tp-surface-inspect / tp-surface-report / tp-surface-unmount | 是 | | 定义可复用声明 | define-tp、define-tps | 只建立 recipe,不建立 live state | | 定义主题颜色 | define-tp-palette | 只更新 palette registry | 安装只需要把仓库加入 load-path: ~~~elisp (add-to-list 'load-path "/path/to/tp") (require 'tp) ~~~ tp.el 会加载所有运行时模块。单独加载模块只适合包开发或测试。 ## 3. 一次性文本属性操作 ### 3.1 创建和应用 ~~~elisp (tp-propertize "Hello" '(face bold help-echo "greeting" keymap nil)) (with-current-buffer (get-buffer-create "*tp-demo*") (erase-buffer) (insert "abcdef") (tp-apply (current-buffer) 2 5 '(face italic))) ~~~ tp-propertize 返回原 string 的副本;tp-apply 保留范围内未出现在 declarations 中的其他属性,并返回 (START . END)。 declarations 可以是原生 property plist、define-tp recipe、recipe call, 或包含 recipe key 的 plist。tp-apply 和下面的直接操作不会创建 object、 binding、marker、subscription 或 surface。 ### 3.2 set/reset/add/remove/clear 对完整 string 的形式会返回新 string;对 Buffer 范围的形式会原地修改,并 返回 (START . END)(tp-remove 和 tp-clear 的 Buffer 形式返回 nil)。 ~~~elisp ;; string:property/value 形式,原 string 不变 (tp-set "item" 'face 'bold) (tp-reset "item" 'face 'italic) (tp-add "item" 'face 'underline) (tp-remove (tp-set "item" 'face 'bold) 'face) ;; buffer 或 string 范围:一个 direct property plist,可选 OBJECT (tp-set start end '(face bold help-echo "tip") buffer) (tp-reset start end '(face italic) buffer) (tp-add start end '(face (:weight bold)) buffer) (tp-remove start end 'help-echo buffer) (tp-clear start end buffer) ~~~ - tp-set 替换所指定的顶层属性; - tp-reset 用 declarations 完全替换范围内所有属性; - tp-add 合并属性;face、font-lock-face、mouse-face 支持 contribution 合成和嵌套 plist 合并; - tp-remove 支持移除顶层属性,也支持 (property sub-key) 或 (property sub-key nested-key...); - tp-clear 移除范围内全部 text properties。 ## 4. 声明、property policy 和 recipe ### 4.1 Property policy ~~~elisp (tp-define-property-policy 'text/my-property :normalizer #'identity :validator (lambda (_value) t) :equality #'equal :merge (lambda (_old new) new) :projector #'identity) (tp-property-policy 'text/my-property) (tp-register-text-property 'help-echo) (tp-text-property-id 'help-echo) (tp-text-declarations '(face bold help-echo "tip")) ~~~ tp-define-property-policy 的 id 必须是包含 / 的 canonical symbol。可选策略 为 :normalizer、:validator、:equality、:merge、:projector。注册是原子的; 无效策略不会替换旧定义。 - tp-register-text-property 为原生 Emacs property 安装默认 policy; - tp-text-property-id 把原生 property 映射为 text/PROPERTY; - tp-text-declarations 把原生 plist 转成 canonical declarations; - tp-merge-declarations 按参数顺序合并 direct declaration groups,后者 覆盖前者,并保留显式 nil; - tp-computed 把一个函数标记为唯一允许执行的 value source; - tp-resolve-value 解析 literal 或显式 computed value; - tp-define-style、tp-style-declarations、tp-undefine-style 管理已归一化的 命名 direct style。 ### 4.2 静态 recipe ~~~elisp (define-tp link-style (color) (list 'face (list :foreground color :weight 'bold) 'mouse-face 'highlight)) (define-tps status-group () link-style '(help-echo "status")) (tp-set 1 5 '(link-style "#58a6ff") buffer) (tp-layer-props-with-arg 'link-style "#58a6ff") (tp-group-props 'status-group) ~~~ 入口及别名: - define-tp(别名 tp-define-layer)定义一个返回原生 property plist 的 recipe; - define-tps(别名 define-tp-group、tp-define-group)定义由多个 recipe、 recipe call、原生 plist 或命名元素组成的 declaration group; - tp-layer-parameterized-p、tp-layer-arglist、tp-layer-props、 tp-layer-props-with-args、tp-layer-props-with-arg 查询或展开 layer; - tp-group-parameterized-p、tp-group-props、tp-group-props-with-args、 tp-group-props-with-arg 查询或展开 group; - tp-undefine-layer、tp-undefine-group、tp-layer-reset 删除 recipe; - tp-describe-layer 返回 recipe 的声明式诊断数据。 recipe 是 definition-time convenience,不是 mounted layer,也不会向文本 写入 identity、provenance、tp-name 或 tp-layers。旧的 $variable reactive syntax 会被拒绝。 tp-layer-alist 和 tp-layer-groups 是 recipe registry;通常通过上面的 query、 undefine 和 reset API 访问,不要直接修改 registry。 ## 5. Reactive signal 和 binding ### 5.1 Signal ~~~elisp (let ((online (tp-signal-create nil))) (tp-signal-read online) ; 在 binding/producer 中收集依赖 (tp-signal-peek online) ; 读取但不收集依赖 (tp-signal-set online t) (tp-signal-subscriber-count online) (tp-signal-live-p online) (tp-signal-dispose online)) ~~~ tp-signal-create 的关键字选项: - :equality,默认 equal;相等写入是 no-op; - :scope,默认 global,也可以是一个 live buffer。Buffer kill 会释放该范围 内 signal。 tp-signal-read 只在当前 computation 中登记 dependency;tp-signal-peek 不会 登记。disposed signal 的读取会报错。 ### 5.2 Binding ~~~elisp (let* ((source (tp-signal-create 0)) (owner (list 'owner)) (binding (tp-bind owner 'value (lambda () (tp-signal-read source)) :lifecycle 'delete))) (tp-binding-read binding) (tp-binding-live-p binding) (tp-binding-dependency-count binding) (tp-binding-subscriber-count binding) (tp-binding-owner-bindings owner) (tp-binding-dispose binding) (tp-signal-dispose source)) ~~~ tp-bind 按 OWNER + KEY 幂等安装 computation。KEY 应使用调用者自己的命名空间; :equality 默认 equal;:lifecycle 为 delete 或 retain。binding 依赖集合按每次 实际读取重建,因此条件分支会自动断开不再使用的 source。tp-binding-read 会在需要时计算并把 binding-to-binding 依赖登记到当前 computation。 tp-binding-dispose-owner 释放 owner 的全部 binding,返回释放数量; tp-binding-dispose 释放单个 binding。 ### 5.3 Transaction 和变量适配器 ~~~elisp (let ((left (tp-signal-create 0)) (right (tp-signal-create 0))) (tp-with-transaction (tp-signal-set left 1) (tp-signal-set right 2)) (tp-signal-dispose left) (tp-signal-dispose right)) (tp-with-transaction (tp-transaction-participate-v2 :key 'my-structured-state :stage (lambda () (my-stage)) :rollback (lambda () (my-rollback)))) (tp-transaction-active-p) (tp-runtime-manifest) (tp-variable-signal 'my-variable) (tp-variable-signal 'my-buffer-variable some-buffer) (tp-reactive-counters) (tp-reactive-reset-counters) (tp-reactive-reset) ~~~ tp-with-transaction 将 signal、binding、surface 和注册的 transaction participant 一起原子处理。participant 必须在 active transaction 内注册; stage 在 surface publication 后、source commit 前运行,失败时按逆序 rollback。consumer 使用 `tp-transaction-participate-v2`;它 返回 key,不暴露内部 participant 对象。tp-variable-signal 用 Emacs variable watcher 适配全局或指定 Buffer 的变量,不是旧的 $variable API。 tp-transaction-active-p 是只读边界查询:只在当前 dynamic extent 已进入 或加入 TP transaction 时返回严格的 t,否则返回 nil。它不暴露 transaction 对象、participant 或内部状态,调用方只能用它在 mutation 前拒绝不支持的 嵌套事务边界。 tp-runtime-manifest 返回防御性 capability snapshot;本版本的 `:transaction-protocol` 为 `tp-transaction-protocol-v2`,`:version` 为 `"2.0.0"`。`:structured-participant-api` 指向 `tp-transaction-participate-v2`;`:batch-execute`、`:batch-artifacts` 和 `:single-live-writer` 均为 non-nil。manifest 不再发布 execution route、 v1 adapter 或 v1 rollback route。 从 TP 1.x 迁移时,把 `(tp-transaction-participate KEY PUBLISH ROLLBACK)` 精确替换为 `(tp-transaction-participate-v2 :key KEY :stage PUBLISH :rollback ROLLBACK)`。删除所有对 `tp-transaction-execution-route` 和 `tp--transaction-artifact-mode` 的设置。 ETAF registers one opaque participant for its immutable generation and Ebox client state. Its publish is paired with rollback across TP final accept; the ETAF runtime separately records effect input/version tuples and reports a bounded non-converging flush instead of spinning. ## 6. Retained surface ### 6.1 Plan、result 和 object ~~~elisp (tp-surface-plan-create :key 'label :kind 'text :text "Ready" :props '(face bold) :tags '(:role status) :capability 'content) ~~~ Plan 字段为 key、kind、text、props、children、tags、capability。leaf 使用 text,容器使用 children;同一层的 key 必须唯一。capability 是 content 或 properties。 - tp-surface-plan-create 防御性复制 caller-owned 数据; - tp-surface-plan-create-owned 直接接收 candidate-local 数据;调用者必须 转移所有权,之后不得修改或向其他 owner 暴露; - tp-surface-result-create 返回携带 plan 和 opaque client-state 的 producer result; - tp-surface-result-create-owned 只可对当前 active prepare context 使用, 结果只消费一次。 - tp-surface-retained-content-result-create 用于对象拓扑不变的 content candidate;最后一个可选 `property-contributions` 参数接受按顺序排列的 `(:start N :end N :props PLIST)` 相对范围。TP 使用已注册 property merge policy 在 prepare 内组合这些贡献,再通过同一个 content surface 原子 diff、 发布和回滚;调用者不需要创建重叠的 properties surface,也不应预先压平 Theme/状态/inline face。 producer 接收一个 prepare context,并应返回 plan 或 result: ~~~elisp (lambda (context) (let ((object (tp-object-ensure context nil 'row 'text))) (tp-surface-plan-create :key 'row :kind 'text :text "row" :props '(face italic) :capability 'content))) ~~~ producer 不得在 prepare 阶段直接修改 live surface buffer;plan 不携带 position、marker、patch operation、producer closure 或 continuation。 对象入口: - tp-object-ensure 按 parent、sibling key、kind 返回或创建当前 candidate 的 稳定 opaque object; - tp-object-live-p、tp-object-mounted-p 检查 object 状态; - tp-object-resolve 用 key path 从 surface side index 取得 object,不扫描文本; - tp-object-mounts 返回 :start、:end、:tags 的数值快照; - tp-object-retain 保留没有输出 fragment 的 object; - tp-object-retain-subtree 保留已证明未删除的 object 子树; - tp-object-reuse-subtree 复用已证明完全不变的 object 子树; - tp-object-attach-fragment 把一个 object 绑定到 content fragment; - tp-object-attach-content-range 把 object 绑定到 leaf 的相对字符范围; - tp-object-attach-content-ranges 批量绑定 range,并复制 tags; - tp-object-attach-content-ranges-owned 批量绑定 candidate-owned tags。 retain-subtree/reuse-subtree 不会替调用者证明 candidate 完整或输出未变化; producer 仍须提交完整 plan,并承担“不变”证明。 ### 6.2 Mount、update、scope 和 report ~~~elisp (let* ((surface (tp-surface-mount buffer producer '(:capability content :start 1 :end 1 :client-state initial-state :inhibit-read-only t :observers (my-after-commit))))) (tp-surface-update surface producer) (tp-surface-update-scoped surface (list object) producer '(:on-mismatch error :return-report t)) (tp-surface-report surface) (tp-surface-report-summary surface) (tp-surface-inspect surface) (tp-surface-unmount surface)) ~~~ tp-surface-mount 的 plan-or-producer 可以是 plan、result 或 producer; producer 的调用上下文由 TP 管理。properties surface 只能写属性,content surface 才能拥有和更新文字。可用 mount options: :capability、:start、:end、:inhibit-read-only、:coordinate-mounts、 :client-state、:observers。 tp-surface-update 发布下一份完整 candidate。tp-surface-update-scoped 仍要求 producer 生成完整 candidate,但只授权指定 object 当前 mount 范围; :on-mismatch 默认报 tp-scope-mismatch,设为 root 才允许显式 root fallback; :return-report 控制是否返回 report。 其他 surface API: - tp-surface-live-p、tp-surface-revision、tp-surface-client-state; - tp-surface-materialize-string 使用相同 producer/plan 语义生成一次性 string, 但不保留 surface、object、binding、subscription 或 anchor; - tp-surface-at-point 通过 side index 返回当前位置的 live objects; - tp-surface-report 返回完整 defensive report; - tp-surface-report-summary 只返回 scalar commit metrics; - tp-surface-inspect 返回 surface、capability、revision、object/mount 数量、 client state 和 report; - tp-surface-unmount 卸载并返回 report。Content 会删除自己的 span; properties 只撤销仍由 TP 拥有的 contribution。 Report 的常用字段包括: :transaction-id、:surface-id、:old-revision、:new-revision、 :candidate-source-writes、:invalidated-bindings、:recomputed-bindings、 :skipped-bindings、:reconciled-objects、:created-objects、:removed-objects、 :moved-objects、:text-operations、:property-operations、 :touched-characters、:full-root、:scope-count、:scope-range-count、 :scope-fallback、:property-conflicts、:rolled-back、:failure、 :observer-errors、:timing。 已经精确计算出变更区间的 producer 可以使用 `tp-commit-batch-create` 构造 批次,再由 `tp-commit-batch-result-create` 绑定当前 prepare context;发布和 回滚仍使用相同 surface 事务。批次绑定前后 revision、extent 和坐标映射。 每个 patch 的 `:replacement` 是完整属性文本,也可以携带局部 `:property-contributions`:其中 `:start`/`:end` 相对于该 replacement,按列表 顺序使用已注册的 property merge policy 合成。策略在**构造批次时**求值; 批次只保留合成后的文本快照,不保留贡献列表,之后的调用方修改或策略替换 不会重新计算这份批次。函数、record 等 opaque 属性身份按既有 snapshot 规则保留。 producer 只有在证明整个挂载拓扑、tags 和坐标均与已提交版本相同时,才能向 `tp-commit-batch-result-create` 传 `:reuse-mount-projection t`。它不能与显式 `:mount-specs` 同时使用;数量相同或对象没有增删都不能替代完整的不变证明。 ### 6.3 Host range 和 tp-watch ~~~elisp (let ((anchor (tp-range-anchor-create buffer start end :start-insertion-type nil :end-insertion-type t :boundary-policy 'shorten))) ;; 在 producer 的 context 中: (tp-object-attach-range context object anchor) (tp-range-anchor-live-p anchor) (tp-range-rebase anchor)) ~~~ boundary-policy 可为 stale、shorten、remove。anchor 是 marker-backed opaque range;host text 编辑由 marker 跟随,TP 不扫描附近文字猜测位置。 tp-range-rebase 明确接受当前 host properties 作为新 baseline。 tp-watch 是 properties-only surface 的便捷入口: ~~~elisp (let ((surface (tp-watch buffer start end (lambda () (list 'face (if enabled 'success 'shadow)))))) (tp-surface-report surface)) ~~~ compute 是零参数函数,返回原生 declarations。文字由 host 所有;返回值是 底层 properties surface,可交给 update/report/inspect/unmount。 ## 7. 属性查询、区间和 mutation policy ### 7.1 Direct query - tp-get 返回范围内的 (START END PROPS) property intervals;指定 property 或 nested path 时只返回对应区间; - tp-at 返回某一位置的完整 plist,或指定 property/nested path 的值; - tp-member 只在 property 存在时返回 (PROPERTY VALUE),因此可区分 present nil 和 absent; - tp-intervals 返回对象范围的 property intervals,可用 absolute 请求 Buffer 原生坐标; - tp-intervals-map 对每个 interval 调用函数; - tp-plist 返回位置或 string range 的合并 property plist; - tp-empty-p 判断对象是否为空; - tp-text-snapshot 返回 string 和 text properties 的防御性快照。 ### 7.2 Native query ~~~elisp (tp-lookup position 'face :object buffer :mode :text-effective) (tp-property-change position :property 'face :direction :next) (tp-property-any start end 'face 'bold buffer) (tp-property-not-all start end 'face 'bold buffer) (tp-with-mutation-policy '(:modified :silent :read-only :inhibit) (tp-apply buffer start end '(face bold))) ~~~ tp-lookup 返回 tp-lookup-result,mode 可为: - :text-direct:直接 text property; - :text-effective:考虑 category/default 等 text-property 继承; - :text-source:返回实际 text source; - :char:使用 get-char-property-and-overlay 的字符属性; - :char-source:字符属性的实际来源,overlay 会记录为 :overlay。 result 的 present-p 区分显式 nil;tp-property-change 的 direction 为 :next 或 :previous,property 为 nil 时观察任意属性变化。 tp-with-mutation-policy 的 :modified 可为 :ordinary 或 :silent, :read-only 可为 :respect 或 :inhibit。支持 ordinary/respect、 ordinary/inhibit、silent/inhibit;silent/respect 会报错。 ## 8. Match、regexp、search 和 navigation 所有 search 都是 presence-aware:省略 VALUE 或显式传入 tp-any-value 匹配 所有存在的值;显式 nil 只匹配“存在且值为 nil”。 ### 8.1 按文字匹配并修改 - tp-match-set:literal pattern 的所有匹配上设置属性; - tp-match-reset:literal pattern 的所有匹配上重置属性; - tp-match-add:literal pattern 的所有匹配上合并属性; - tp-regexp-set、tp-regexp-reset、tp-regexp-add:regexp 匹配,可用 subexp 只操作 capture group。 Pattern 可以是一个 string 或 string 列表。String object 返回新 string; Buffer object 原地修改并返回匹配范围列表。start > end 时边界会交换, 匹配不会跨出指定范围。 ### 8.2 查找和批量处理 ~~~elisp (tp-search string 'status) (tp-search start end 'status 'ready buffer) (tp-forward 'status tp-any-value buffer 2) (tp-backward 'status nil buffer) (tp-search-map (lambda (text _start _end _index) (upcase text)) 'status tp-any-value buffer) ~~~ - tp-search 返回所有匹配的 (START END VALUE); - tp-forward / tp-backward 在 Buffer 中从 point 搜索并返回 prop-match, 在 string 中返回 0-based 区间列表; - tp-forward-do / tp-backward-do 找到第 N 个匹配后只对最后一个执行 function,不是 for-each; - tp-search-map 对每个匹配执行 function。function 可返回替换 string、 修改 text 后的 string,或 nil 跳过。String 替换必须保持长度不变; Buffer 替换可以改变长度; - tp-search-forward / tp-search-backward 只是 Emacs text-property-search-* 的 obsolete raw wrapper,新增代码使用 tp-forward / tp-backward 或直接使用 Emacs primitive。 ## 9. Palette、内置 recipe 和显示辅助 ~~~elisp (define-tp-palette status :fg ("#22863a" . "#3fb950") :bg ("#f0fff4" . "#1a2e1f")) (tp-palette-color 'status :fg) (tp-palette-fg-color 'status) (tp-palette-bg-color 'status) (tp-palette-border-color 'status) (tp-palette-has-p 'status :fg) (tp-palette-pure 'status-fg) (tp-set "Ready" 'tp-palette 'status-fg) ~~~ define-tp-palette(别名 tp-define-palette)注册 :fg、:bg、:border。颜色 可以是 string、(LIGHT . DARK) 或 (:light LIGHT :dark DARK)。查询和主题工具: tp-palette-alist 是 palette lookup 的单一来源;使用 define-tp-palette/tp-define-palette 更新它。 - tp-theme-dark-p、tp-theme-light-p、tp-parse-color; - tp-palette-color、tp-palette-fg-color、tp-palette-bg-color、 tp-palette-border-color; - tp-palette-has-p 判断 palette 或 key 是否存在; - tp-palette-p 判断 palette 名; - tp-palette-fg-p、tp-palette-bg-p、tp-palette-fbg-p、tp-palette-border-p 判断 NAME-* variant; - tp-palette-pure 去掉 variant suffix; - tp-palette-show 打开 *tp-palette-gallery*,按 q 退出。 TP 自带的 recipe 包括: tp-palette、tp-fg、tp-bg、tp-button、tp-underline、tp-delete、tp-link、 tp-space、tp-headline、tp-action。 显示辅助: - tp-pop-to-buffer:清空并填充 buffer 后 pop-to-buffer,最后设为只读; - tp-switch-to-buffer:同样的填充和只读行为,但使用 switch-to-buffer; - tp-display-buffer-mode:为 TP 显示 buffer 提供 buffer-local 的 q 退出键, 不修改共享 major-mode map。 tp-display-buffer-mode-map 是该 minor mode 的 keymap;默认只绑定 q 到 quit-window。 ## 10. Debug 和公共 record Debug 入口: - tp-debug-mode、tp-debug-echo 控制日志行为; - tp-debug-log 记录格式化消息; - tp-debug-clear 清空日志; - tp-debug-show 显示日志; - tp-with-current-buffer 在指定 Buffer 中执行 body; - tp-face-properties 列出 face family properties。 以下公共结果类型由 cl-defstruct 提供 predicate 和字段 accessor。调用者不应 直接调用内部 constructor;优先使用前文的 create/query API: - tp-property-policy:id、normalizer、validator、equality、merge、projector; - tp-signal:id、committed-value、equality、scope、revision 等运行时字段; - tp-binding:id、owner、key、compute、last-value、dependencies、lifecycle 等运行时字段; - tp-surface-plan:key、kind、text、props、children、tags、capability; - tp-surface-result:plan、client-state 及 owned/consumed 状态; - tp-lookup-result:property、value、present-p、source、mode、object、 position、overlay。 ## 11. 错误、生命周期和已删除 API 重要错误类型: - core:tp-unsupported-buffer; - property:tp-property-error、tp-invalid-property-policy、 tp-invalid-declaration; - recipe:tp-invalid-layer-definition、tp-unresolved-layer; - reactive:tp-reactive-error、tp-invalid-signal-scope、tp-disposed-signal、 tp-disposed-binding、tp-binding-cycle; - surface:tp-surface-error、tp-invalid-surface-plan、tp-duplicate-object-key、 tp-invalid-prepare-context、tp-stale-object、tp-cross-surface-object、 tp-orphan-object、tp-capability-error、tp-stale-mount、 tp-property-conflict、tp-dead-surface、tp-invalid-range-anchor、 tp-invalid-content-range、tp-producer-buffer-mutation、 tp-publication-mismatch、tp-owned-result-error、tp-scope-mismatch。 Live object、binding、surface、anchor 或 signal 被 dispose、unmount 或 Buffer kill 后,继续使用会报相应 stale/disposed 错误。Observer 只在成功 commit 后运行;observer error 会记录在 report,不会回滚已提交 publication。 TP 1.0 已删除并且不应在新代码中使用: - tp-render.el、tp-stack.el、managed stack mutation; - tp-text、$variable、inline tp-name/tp-layers/tp-meta runtime database; - layer-to-buffer registry、scan-driven refresh、managed attach/detach; - tp-with-batch-updates 和旧 CSS/ECSS runtime integration。 因此,当前正确的组合是:静态声明用 recipe/direct API,已有文字的响应式 属性用 tp-watch,TP 自己拥有的响应式文字用 content surface。 ## 12. 完整模块索引 | 模块 | 当前公共入口 | | --- | --- | | tp-core.el | tp-debug-*、tp-with-current-buffer、tp-intervals、tp-intervals-map、tp-empty-p、tp-plist、tp-text-snapshot | | tp-style.el | tp-define-property-policy、tp-property-policy、tp-text-property-id、tp-register-text-property、tp-text-declarations、tp-computed、tp-resolve-value、tp-merge-declarations、tp-define-style、tp-style-declarations、tp-undefine-style | | tp-layer.el | define-tp/tp-define-layer、define-tps/define-tp-group/tp-define-group、layer/group query、tp-layer-reset、tp-undefine-*、tp-describe-layer | | tp-transaction.el | structured batch/entry、final-marker 与 tagged-outcome 内部合同 | | tp-reactive.el | signal、binding、transaction coordinator、variable adapter、counter 和 reset API | | tp-surface.el | plan/result、object、range anchor、surface lifecycle、scoped update、report、tp-watch | | tp-ops.el | tp-propertize、tp-apply、tp-set、tp-reset、tp-add、tp-remove、tp-clear、tp-get、tp-at、tp-member | | tp-search.el | tp-match-*、tp-regexp-*、tp-search、tp-search-map、tp-forward*、tp-backward*、tp-any-value | | tp-query.el | tp-lookup、tp-property-change、tp-property-any、tp-property-not-all、tp-with-mutation-policy | | tp-palette.el | palette definition、theme/color lookup、palette predicates | | tp-builtins.el | built-in recipes、tp-palette-show、display-buffer macros/mode | Makefile 提供 make test、make test-shuffled、make doctest、make compile-all WERROR=t、 make checkdoc、make package-lint、make diff-check 和 make benchmark。实现细节 和测试合同以 source、tests/、[API semantics](API-SEMANTICS.md) 和 [architecture](ARCHITECTURE.md) 为准。