diff --git a/TeXmacs/packages/customize/document/three-columns.ts b/TeXmacs/packages/customize/document/three-columns.ts index ab371feb1b..0773dc2744 100644 --- a/TeXmacs/packages/customize/document/three-columns.ts +++ b/TeXmacs/packages/customize/document/three-columns.ts @@ -54,6 +54,5 @@ <\initial> <\collection> - \ No newline at end of file diff --git a/TeXmacs/plugins/autosave/progs/autosave/plugin.scm b/TeXmacs/plugins/autosave/progs/autosave/plugin.scm index c792fdd3c6..cc0cb5e2f0 100644 --- a/TeXmacs/plugins/autosave/progs/autosave/plugin.scm +++ b/TeXmacs/plugins/autosave/progs/autosave/plugin.scm @@ -11,7 +11,10 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (texmacs-module (autosave plugin) - (:use (utils library cursor) (texmacs texmacs tm-collab)) + (:use (utils library cursor) + (texmacs texmacs tm-collab) + (texmacs texmacs tm-files) + ) ;:use ) ;texmacs-module (import (liii uuid)) @@ -96,6 +99,7 @@ (not (url-rooted-tmfs? name)) (not (auto-backup-texmacs-path-buffer? name)) (in? (url-format name) '("texmacs" "stm" "tmu" "stem")) + (not (style-buffer? name)) ) ;and ) ;tm-define @@ -106,20 +110,22 @@ (tm-define (auto-backup-buffer-doc-id name) (catch #t (lambda () - ;; First try to get from init-env (memory), then from document tree (file) - (with-buffer name - (let* ((from-env (get-init-env "stem-doc-id")) - (doc-id (if (and (string? from-env) (!= from-env "")) - from-env - (let* ((doc (buffer-get name)) (initial (tmfile-extract doc 'initial))) - (and initial (collection-ref initial "stem-doc-id")) - ) ;let* - ) ;if - ) ;doc-id - ) ; - doc-id - ) ;let* - ) ;with-buffer + (and (not (style-buffer? name)) + ;; First try to get from init-env (memory), then from document tree (file) + (with-buffer name + (let* ((from-env (get-init-env "stem-doc-id")) + (doc-id (if (and (string? from-env) (!= from-env "")) + from-env + (let* ((doc (buffer-get name)) (initial (tmfile-extract doc 'initial))) + (and initial (collection-ref initial "stem-doc-id")) + ) ;let* + ) ;if + ) ;doc-id + ) ; + doc-id + ) ;let* + ) ;with-buffer + ) ;and ) ;lambda (lambda args #f) ) ;catch @@ -180,6 +186,22 @@ ) ;catch ) ;tm-define +(tm-define (auto-backup-clear-buffer-doc-id! name) + (catch #t + (lambda () (with-buffer name (init-default "stem-doc-id"))) + (lambda args #f) + ) ;catch +) ;tm-define + +;; 「样式 buffer 清除、文档 buffer 补齐」的 doc id 策略统一收口在这里, +;; 各保存路径只需无条件调用本函数。 +(tm-define (auto-backup-sync-buffer-doc-id! name) + (if (style-buffer? name) + (auto-backup-clear-buffer-doc-id! name) + (auto-backup-ensure-buffer-doc-id! name) + ) ;if +) ;tm-define + (tm-define (auto-backup-trig-payload name kind) (let* ((collab? (collab-buffer? name)) ;; 协作文档:path 指向本地不可见备份文件(collab-silent-backup 已在 save-buffer-save @@ -338,7 +360,7 @@ (tm-define (save-all-buffers) (for-each (lambda (buf) (when (buffer-modified? buf) - (auto-backup-ensure-buffer-doc-id! buf) + (auto-backup-sync-buffer-doc-id! buf) (buffer-save buf) ) ;when ) ;lambda diff --git a/TeXmacs/plugins/bash/doc/bash.en.tmu b/TeXmacs/plugins/bash/doc/bash.en.tmu index 9a86dfd412..7ba9ac7a70 100644 --- a/TeXmacs/plugins/bash/doc/bash.en.tmu +++ b/TeXmacs/plugins/bash/doc/bash.en.tmu @@ -71,6 +71,5 @@ - diff --git a/TeXmacs/progs/texmacs/texmacs/tm-files-test.scm b/TeXmacs/progs/texmacs/texmacs/tm-files-test.scm index 1603e0a553..b56ca589cd 100644 --- a/TeXmacs/progs/texmacs/texmacs/tm-files-test.scm +++ b/TeXmacs/progs/texmacs/texmacs/tm-files-test.scm @@ -12,7 +12,7 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (texmacs-module (texmacs texmacs tm-files-test) - (:use (texmacs texmacs tm-files) (autosave plugin)) + (:use (texmacs texmacs tm-files) (autosave plugin) (utils library cursor)) ) ;texmacs-module (import (liii check)) @@ -139,6 +139,85 @@ ) ;let* ) ;define +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Tests for style-buffer? and stem-doc-id eligibility +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define (test-style-buffer-and-doc-id) + ;; 1. .ts 后缀 buffer 属于样式 buffer,不生成 stem-doc-id + (let* ((orig (current-buffer)) + (buf (new-buffer ".tmu")) + (ts-url (system->url "/tmp/test_custom_style.ts")) + ) ; + (buffer-rename buf ts-url) + (check (style-buffer? ts-url) => #t) + (check (auto-backup-buffer-eligible? ts-url) => #f) + (check (auto-backup-ensure-buffer-doc-id! ts-url) => #f) + (buffer-close ts-url) + (switch-to-buffer orig) + ) ;let* + + ;; 2. 实际为样式的 .stem buffer(style 为 source)不生成 stem-doc-id + (let* ((orig (current-buffer)) + (stem-style-buf (new-buffer ".stem")) + (style-doc '(document (TeXmacs "2.1.4") + (style (tuple "source")) + (body (document (active* (src-title (document (src-package "my-pkg" + "1.0"))))))) + ) ;style-doc + ) ; + (buffer-set stem-style-buf style-doc) + (check (style-buffer? stem-style-buf) => #t) + (check (auto-backup-buffer-eligible? stem-style-buf) => #f) + (check (auto-backup-ensure-buffer-doc-id! stem-style-buf) => #f) + ;; 验证若环境中已存在 doc-id,clear 会将其清除 + (with-buffer stem-style-buf (init-env "stem-doc-id" "test-uuid")) + (auto-backup-clear-buffer-doc-id! stem-style-buf) + (with-buffer stem-style-buf (check (get-init-env "stem-doc-id") => #f)) + (check (auto-backup-buffer-doc-id stem-style-buf) => #f) + (buffer-close stem-style-buf) + (switch-to-buffer orig) + ) ;let* + + ;; 3. 普通文档 buffer(.stem / .tmu,style 为 generic)生成 stem-doc-id + (for-each (lambda (suffix) + (let* ((orig (current-buffer)) + (buf (new-buffer suffix)) + (doc '(document (TeXmacs "2.1.4") + (style (tuple "generic")) + (body (document "Hello document"))) + ) ;doc + ) ; + (buffer-set buf doc) + (check (style-buffer? buf) => #f) + (check (auto-backup-buffer-eligible? buf) => #t) + (let ((doc-id (auto-backup-ensure-buffer-doc-id! buf))) + (check (string? doc-id) => #t) + (check (!= doc-id "") => #t) + (check (auto-backup-buffer-doc-id buf) => doc-id) + ) ;let + (buffer-close buf) + (switch-to-buffer orig) + ) ;let* + ) ;lambda + '(".stem" ".tmu") + ) ;for-each + + ;; 4. 导出样式包生成的草稿 buffer 属于样式 buffer,不生成 stem-doc-id + (let ((orig-buf (current-buffer))) + (when (defined? 'extract-style-package) + (extract-style-package) + (let ((style-draft (current-buffer))) + (check (style-buffer? style-draft) => #t) + (check (auto-backup-buffer-eligible? style-draft) => #f) + (check (auto-backup-ensure-buffer-doc-id! style-draft) => #f) + (buffer-close style-draft) + (switch-to-buffer orig-buf) + ) ;let + ) ;when + ) ;let +) ;define + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Test entry point ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -151,5 +230,6 @@ (test-scratch-buffer-title-stem) (test-scratch-buffer-title-old-and-new-stamp) (test-scratch-buffer-title-legacy-one-underscore-this-week) + (test-style-buffer-and-doc-id) (check-report) ) ;tm-define diff --git a/TeXmacs/progs/texmacs/texmacs/tm-files.scm b/TeXmacs/progs/texmacs/texmacs/tm-files.scm index 03ee4aa5bc..eefa5344ed 100644 --- a/TeXmacs/progs/texmacs/texmacs/tm-files.scm +++ b/TeXmacs/progs/texmacs/texmacs/tm-files.scm @@ -215,6 +215,53 @@ ) ;with ) ;tm-define +(define (source-markup-tag? t) + (and (pair? t) (in? (car t) '(src-title src-package src-style-file))) +) ;define + +(define (body-has-source-markup? doc) + (let ((body (and doc (tmfile-extract doc 'body)))) + (and (pair? body) + (== (car body) 'document) + (pair? (cdr body)) + ;; 导出样式包的草稿把 src-* 标记包在 active* 里,其内还可能再套一层 document + (let* ((first (cadr body)) + (inner (if (and (pair? first) (== (car first) 'active*) (pair? (cdr first))) + (cadr first) + first + ) ;if + ) ;inner + ) ; + (or (source-markup-tag? inner) + (and (pair? inner) + (== (car inner) 'document) + (pair? (cdr inner)) + (source-markup-tag? (cadr inner)) + ) ;and + ) ;or + ) ;let* + ) ;and + ) ;let +) ;define + +(tm-define (style-buffer? name) + (catch #t + (lambda () + (and (url? name) + (buffer-exists? name) + (or (== (url-suffix name) "ts") + (and (defined? 'style-package-target-url) + (url? (style-package-target-url name)) + ) ;and + (with-buffer name (has-style-package? "source")) + (body-has-source-markup? (buffer-get name)) + ) ;or + ) ;and + ) ;lambda + (lambda args #f) + ) ;catch +) ;tm-define + (tm-define (buffer-set-default-style) (init-style "generic") (with lan @@ -428,8 +475,8 @@ ;; (display* "save-buffer-save " name "\n") (with vname `(verbatim ,(utf8->cork (url->system name))) - (when (defined? 'auto-backup-ensure-buffer-doc-id!) - (auto-backup-ensure-buffer-doc-id! name) + (when (defined? 'auto-backup-sync-buffer-doc-id!) + (auto-backup-sync-buffer-doc-id! name) ) ;when (if (buffer-save name) (begin diff --git a/devel/1297.md b/devel/1297.md new file mode 100644 index 0000000000..1b683ee81b --- /dev/null +++ b/devel/1297.md @@ -0,0 +1,57 @@ +# [1297] 仅对文档缓冲区生成 stem-doc-id + +## 1 相关文档 +- [dddd.md](dddd.md) - 任务文档模板 +- [1104.md](1104.md) - 修复新建文档未写入 stem-doc-id 的问题 +- [1131.md](1131.md) - 添加 stem 格式并全量迁移 plugins 下 .ts → .stem +- [1293.md](1293.md) - 草稿文件后缀放开为 .tmu 与 .stem 并导出样式包为 .stem 草稿 +- [200_33.md](200_33.md) - stem-doc-id 自动备份标识机制说明 + +## 2 任务相关的代码文件 +- `TeXmacs/progs/texmacs/texmacs/tm-files.scm` — 定义 `style-buffer?` 谓词;保存文件时统一调用 `auto-backup-sync-buffer-doc-id!` +- `TeXmacs/plugins/autosave/progs/autosave/plugin.scm` — `auto-backup-buffer-eligible?` 排除样式 buffer;新增 `auto-backup-clear-buffer-doc-id!` 与 `auto-backup-sync-buffer-doc-id!`(样式 buffer 清除、文档 buffer 补齐的策略收口);`auto-backup-buffer-doc-id` 对样式 buffer 返回 `#f` +- `TeXmacs/progs/texmacs/texmacs/tm-files-test.scm` — 单元测试:验证样式 buffer 与文档 buffer 判定,以及 `stem-doc-id` 生成与清除 +- `TeXmacs/packages/customize/document/three-columns.ts`、`TeXmacs/plugins/bash/doc/bash.en.tmu` — 移除历史遗留误写入的 `stem-doc-id` + +## 3 如何测试 + +### 3.1 单元测试 +```bash +xmake b stem +xmake b tm-files-test && xmake r tm-files-test +``` +预期: +1. `.ts` 文件被判定为样式 buffer(`style-buffer?` 为 `#t`),不具备自动备份与 `stem-doc-id` 绑定资格; +2. 实际为样式的 `.stem` 文件(包含 `source` 样式或样式声明标记)被判定为样式 buffer,不填入 `stem-doc-id`; +3. 作为普通文档的 `.stem` 文件(非 `source` 样式)被判定为文档 buffer,正常绑定 `stem-doc-id`; +4. 普通 `.tmu`/`.tm` 文档正常保持绑定 `stem-doc-id` 的行为; +5. 单元测试全部通过。 + +### 3.2 手动测试 +1. 打开一个 `.ts` 样式文件或 `.stem` 样式包(如 `std.stem`),修改后保存: + - 检查保存后的文件内容,确认没有写入 `` 或 `(associate "stem-doc-id" ...)`. +2. 新建或打开一个 `.stem` 文档(如 `test.stem`,样式为 `generic` 或 `article`),修改后保存: + - 检查保存后的文件内容,确认包含 `stem-doc-id`. +3. 新建或打开普通 `.tmu` 文档并保存: + - 确认正常包含 `stem-doc-id`. + +## 4 为什么(Why) +1. `stem-doc-id` 是用于文档追踪和自动备份的稳定唯一标识,仅应存在于文档缓冲区。 +2. `.ts` 文件是 TeXmacs 样式文件,不属于文档;而 `.stem` 扩展名既可用于样式文件(作为 `.ts` 的 S-expression 继任格式),也可用于保存普通文档。 +3. 此前 `auto-backup-buffer-eligible?` 仅依据格式 `in? '("texmacs" "stm" "tmu" "stem")` 进行判断,导致 `.ts` 以及实际上是样式的 `.stem` 在保存或触发自动备份时被误填入 `stem-doc-id`(例如 `three-columns.ts` 中就遗留了误写入的 doc id)。 +4. 不能单纯依靠文件后缀区分样式与文档,需要根据缓冲区实际内容与样式属性(如是否具备 `source` 样式、是否包含宏包标记、是否关联样式包导出目标等)准确判定。 + +## 5 怎么做(How) +1. 在 `tm-files.scm` 中实现 `style-buffer?`: + - 识别 `.ts` 后缀; + - 识别通过「导出样式包」创建的关联草稿(`style-package-target-url`); + - 检查缓冲区是否具备 `source` 样式包(`has-style-package?`,读取 buffer 的样式环境); + - 检查缓冲区文档树首部是否包含 `src-title` / `src-package` / `src-style-file` 等样式文件特征标记(`body-has-source-markup?`)。 +2. 在 `plugin.scm` 中: + - 将 `auto-backup-buffer-eligible?` 调整为要求 `(not (style-buffer? name))`; + - 实现 `auto-backup-clear-buffer-doc-id!`,在样式缓冲区保存时调用 `(init-default "stem-doc-id")` 重置环境中的 doc id; + - 新增 `auto-backup-sync-buffer-doc-id!`,把「样式 buffer 清除、文档 buffer 补齐」的策略收口到一处,各保存路径无条件调用; + - `auto-backup-buffer-doc-id` 对样式缓冲区直接返回 `#f`。 +3. `tm-files.scm` 的 `save-buffer-save-file` 与 `plugin.scm` 的 `save-all-buffers` 均通过 `auto-backup-sync-buffer-doc-id!` 同步 doc id。 +4. 清理 `three-columns.ts` 与 `bash.en.tmu` 中残留的 `stem-doc-id`。 +5. 在 `tm-files-test.scm` 中增加针对样式判定与 doc id 行为的单元测试。