From c6bfcb6795faf4fd09fde88ab25a232698a8ffb8 Mon Sep 17 00:00:00 2001 From: yinyu Date: Thu, 28 May 2026 09:58:24 +0800 Subject: [PATCH] =?UTF-8?q?[0411]=20=E6=94=AF=E6=8C=81=E8=A1=8C=E9=97=B4?= =?UTF-8?q?=E8=B7=9D=E5=AF=B9=E8=AF=9D=E6=A1=86=E5=AD=90=E6=8E=A7=E4=BB=B6?= =?UTF-8?q?=E7=9A=84=E5=8A=A8=E6=80=81=E6=98=BE=E7=A4=BA=E4=B8=8E=E6=95=B0?= =?UTF-8?q?=E5=80=BC=E4=BF=9D=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TeXmacs/plugins/lang/dic/en_US/zh_CN.scm | 10 +- TeXmacs/progs/generic/document-menu.scm | 3 +- TeXmacs/progs/generic/format-menu.scm | 3 +- TeXmacs/progs/generic/format-widgets.scm | 249 +++++++++++++++++++++-- devel/0411.md | 126 ++++++++++++ 5 files changed, 367 insertions(+), 24 deletions(-) create mode 100644 devel/0411.md diff --git a/TeXmacs/plugins/lang/dic/en_US/zh_CN.scm b/TeXmacs/plugins/lang/dic/en_US/zh_CN.scm index ea26d608a6..34d53e2b3a 100644 --- a/TeXmacs/plugins/lang/dic/en_US/zh_CN.scm +++ b/TeXmacs/plugins/lang/dic/en_US/zh_CN.scm @@ -1,6 +1,7 @@ ("(re)build autocompletion index" "构建/重建自动补全索引") (" (length: " "(长度为") -("1.5 line spacing" "1.5 倍行距") +("1.5 line spacing" "1.5倍行距") +("2 line spacing" "2倍行距") ("Upgrade VIP" "升级会员") ("Upgrade to unlock AI writing, MathOCR, and more advanced features." "开通会员,立即解锁 AI 写作、MathOCR 等高阶功能。") ("All" "全部") @@ -17,6 +18,7 @@ ("Archive selected" "归档所选") ("Archive selected (%1)" "归档所选 (%1)") ("As" "作为") +("At least" "最小值") ("Auto backup:" "自动备份:") ("Backslash \\ /" "反斜线 \\ /") ("BibTeX command" "BibTeX命令") @@ -50,6 +52,7 @@ ("End::keyboard" "End") ("Expand TeXmacs macros with no LaTeX equivalents" "展开没有 LaTeX 等价项的 TeXmacs 宏") ("Experimental features (to be used with care)" "实验性功能(请谨慎使用)") +("Exactly" "固定值") ("expired" "到期") ("Expired" "已过期") ("Export mathematical formulas as MathJax" "将数学公式导出为 MathJax") @@ -73,6 +76,7 @@ ("Merge lines into paragraphs unless separated by blank lines" "无空行分隔时自动合并多行为段落") ("Math Modeling" "数学建模") ("Multi-select" "多选") +("Multiple" "多倍行距") ("No matching command found!" "未找到匹配指令!") ("No multiple spaces" "不允许多个空格") ("NSFC Young Scientists Fund" "国自然基金青年基金申请模板") @@ -1375,6 +1379,7 @@ ("line wrapping" "自动换行") ("Interline space" "行距") ("Line spacing presets:" "行距预设:") +("Line spacing:" "行距:") ("line" "线") ("linear algebra" "线性代数") ("lines around block" "双划线块") @@ -2253,6 +2258,9 @@ ("space between lines" "行间空白") ("space between paragraphs" "段间空白") ("spacing" "间隔") +("Spacing value:" "设置值:") +("Minimum value:" "最小值:") +("Multiple value:" "倍数:") ("spanish" "西班牙语") ("special functions" "特殊函数") ("special properties" "特殊属性") diff --git a/TeXmacs/progs/generic/document-menu.scm b/TeXmacs/progs/generic/document-menu.scm index 28963b1f40..07b5c7abd3 100644 --- a/TeXmacs/progs/generic/document-menu.scm +++ b/TeXmacs/progs/generic/document-menu.scm @@ -560,8 +560,9 @@ (-> "Spacing" ("Default" (init-default "par-sep" "par-line-sep" "interpargraph space")) --- + ("Single line spacing" (init-env "par-sep" "0fn")) ("1.5 line spacing" (init-env "par-sep" "0.5fn")) - ("Double line spacing" (init-env "par-sep" "1.0fn")) + ("2 line spacing" (init-env "par-sep" "1.0fn")) --- ("Interline separation" (init-interactive-env "par-sep")) ("Interline space" (init-interactive-env "par-line-sep")) diff --git a/TeXmacs/progs/generic/format-menu.scm b/TeXmacs/progs/generic/format-menu.scm index b89d1dd023..99e1cfe789 100644 --- a/TeXmacs/progs/generic/format-menu.scm +++ b/TeXmacs/progs/generic/format-menu.scm @@ -301,8 +301,9 @@ (link indentation-menu) ) ;-> (-> "Spacing" + ("Single line spacing" (make-line-with "par-sep" "0fn")) ("1.5 line spacing" (make-line-with "par-sep" "0.5fn")) - ("Double line spacing" (make-line-with "par-sep" "1.0fn")) + ("2 line spacing" (make-line-with "par-sep" "1.0fn")) --- ("Interline separation" (make-interactive-line-with "par-sep")) ("Interline space" (make-interactive-line-with "par-line-sep")) diff --git a/TeXmacs/progs/generic/format-widgets.scm b/TeXmacs/progs/generic/format-widgets.scm index dc3a708c3a..4269d192db 100644 --- a/TeXmacs/progs/generic/format-widgets.scm +++ b/TeXmacs/progs/generic/format-widgets.scm @@ -139,6 +139,146 @@ ) ;list ) ;tm-define +(define (safe-string-null? s) + (or (not s) (not (string? s)) (equal? s ""))) + +(define (safe-string-ends? s suffix) + (and (string? s) + (string? suffix) + (>= (string-length s) (string-length suffix)) + (equal? (substring s (- (string-length s) (string-length suffix)) (string-length s)) suffix))) + +(define (get-current-par-sep new) + (let ((val (ahash-ref new "par-sep"))) + (if (and val (string? val)) val ""))) + +(define (get-current-par-ver-sep new) + (let ((val (ahash-ref new "par-ver-sep"))) + (if (and val (string? val)) val ""))) + +(define (par-sep->multiplier par-sep) + (if (and (safe-string-ends? par-sep "fn") (>= (string-length par-sep) 2)) + (let* ((num-str (substring par-sep 0 (- (string-length par-sep) 2))) + (num (string->number num-str))) + (if num + (number->string (+ num 1.0)) + "1.2")) + "1.2")) + +(define (multiplier->par-sep mult-str) + (let ((num (string->number mult-str))) + (if num + (let ((val (- num 1.0))) + (string-append (number->string val) "fn")) + "0.2fn"))) + +(define (get-fn-val s) + (and (string? s) + (safe-string-ends? s "fn") + (>= (string-length s) 2) + (string->number (substring s 0 (- (string-length s) 2))))) + +(define (get-line-spacing-type par-sep par-ver-sep) + (let ((val (get-fn-val par-sep))) + (cond + ((and (not (safe-string-null? par-ver-sep)) + (not (equal? par-ver-sep "")) + (or (safe-string-null? par-sep) (and val (= val 0)))) + "At least") + ((or (safe-string-null? par-sep) (and val (= val 0))) + "Single line spacing") + ((and val (= val 0.5)) + "1.5 line spacing") + ((and val (= val 1.0)) + "2 line spacing") + ((and val (not (or (= val 0) (= val 0.5) (= val 1.0)))) + "Multiple") + (else + "Exactly")))) + +(define (par-sep->multiplier-str par-sep) + (let ((val (get-fn-val par-sep))) + (if val + (number->string (+ val 1.0)) + "1.2"))) + +(define (multiplier-str->par-sep mult-str) + (let ((num (string->number mult-str))) + (if num + (let ((val (- num 1.0))) + (string-append (number->string val) "fn")) + "0.2fn"))) + +(define (get-multiple-default par-sep) + (let ((val (get-fn-val par-sep))) + (if (and val (not (or (= val 0) (= val 0.5) (= val 1.0)))) + par-sep + "0.2fn"))) + +(define (get-at-least-default par-ver-sep) + (if (and (string? par-ver-sep) (not (safe-string-null? par-ver-sep))) + par-ver-sep + "12pt")) + +(define (get-exactly-default par-sep) + (let ((val (get-fn-val par-sep))) + (if (not val) + (if (and (string? par-sep) (not (safe-string-null? par-sep))) + par-sep + "12pt") + "12pt"))) + +;; State variables to preserve line spacing values across type switches +(define line-spacing-exactly-value "12pt") +(define line-spacing-at-least-value "12pt") +(define line-spacing-multiple-value "0.2fn") + +(define (save-line-spacing-values new) + "Save current line spacing values before switching types" + (let* ((p-sep (get-current-par-sep new)) + (pv-sep (get-current-par-ver-sep new)) + (sp-type (get-line-spacing-type p-sep pv-sep))) + (cond ((equal? sp-type "Exactly") + (set! line-spacing-exactly-value p-sep)) + ((equal? sp-type "At least") + (set! line-spacing-at-least-value pv-sep)) + ((equal? sp-type "Multiple") + (set! line-spacing-multiple-value p-sep))))) + +(define (get-exactly-default-with-save par-sep) + "Get default for Exactly mode, using saved value if current is a fn value" + (let ((val (get-fn-val par-sep))) + (if (not val) + (if (and (string? par-sep) (not (safe-string-null? par-sep))) + par-sep + line-spacing-exactly-value) + line-spacing-exactly-value))) + +(define (get-at-least-default-with-save par-ver-sep) + "Get default for At least mode, using saved value if current is empty" + (if (and (string? par-ver-sep) (not (safe-string-null? par-ver-sep))) + par-ver-sep + line-spacing-at-least-value)) + +(define (get-multiple-default-with-save par-sep) + "Get default for Multiple mode, using saved value if current is a standard fn value" + (let ((val (get-fn-val par-sep))) + (if (and val (not (or (= val 0) (= val 0.5) (= val 1.0)))) + par-sep + line-spacing-multiple-value))) + +(define (line-spacing-exactly? new) + "Check if current line spacing type is Exactly" + (equal? (get-line-spacing-type (get-current-par-sep new) (get-current-par-ver-sep new)) "Exactly")) + +(define (line-spacing-at-least? new) + "Check if current line spacing type is At least" + (equal? (get-line-spacing-type (get-current-par-sep new) (get-current-par-ver-sep new)) "At least")) + +(define (line-spacing-multiple? new) + "Check if current line spacing type is Multiple" + (equal? (get-line-spacing-type (get-current-par-sep new) (get-current-par-ver-sep new)) "Multiple")) + (tm-widget (paragraph-formatter-basic old new fun u flag?) (aligned (item (text "Alignment:") (enum (change "par-mode" answer old new fun u) @@ -172,30 +312,87 @@ ) ;enum ) ;item (item ====== ======) - (item (text "Interline space:") - (enum (change "par-sep" answer old new fun u) - (cons-new (ahash-ref new "par-sep") '("0fn" "0.2fn" "0.5fn" "1fn" "")) - (ahash-ref new "par-sep") + (item (text "Line spacing:") + (enum + (cond + ((equal? answer "Single line spacing") + (begin + (save-line-spacing-values new) + (change "par-sep" "0fn" old new fun u) + (change "par-ver-sep" "" old new fun u) + (refresh-now "paragraph-formatter"))) + ((equal? answer "1.5 line spacing") + (begin + (save-line-spacing-values new) + (change "par-sep" "0.5fn" old new fun u) + (change "par-ver-sep" "" old new fun u) + (refresh-now "paragraph-formatter"))) + ((equal? answer "2 line spacing") + (begin + (save-line-spacing-values new) + (change "par-sep" "1.0fn" old new fun u) + (change "par-ver-sep" "" old new fun u) + (refresh-now "paragraph-formatter"))) + ((equal? answer "At least") + (begin + (save-line-spacing-values new) + (change "par-sep" "0fn" old new fun u) + (change "par-ver-sep" (get-at-least-default-with-save (get-current-par-ver-sep new)) old new fun u) + (refresh-now "paragraph-formatter"))) + ((equal? answer "Exactly") + (begin + (save-line-spacing-values new) + (change "par-sep" (get-exactly-default-with-save (get-current-par-sep new)) old new fun u) + (change "par-ver-sep" "" old new fun u) + (refresh-now "paragraph-formatter"))) + ((equal? answer "Multiple") + (begin + (save-line-spacing-values new) + (change "par-sep" (get-multiple-default-with-save (get-current-par-sep new)) old new fun u) + (change "par-ver-sep" "" old new fun u) + (refresh-now "paragraph-formatter"))) + ) ;cond + '("Single line spacing" "1.5 line spacing" "2 line spacing" "At least" "Exactly" "Multiple") + (get-line-spacing-type (get-current-par-sep new) (get-current-par-ver-sep new)) "10em" ) ;enum ) ;item - (item (hlist // (text "Line spacing presets:")) - (hlist ("1.5x" - (begin - (change "par-sep" "0.5fn" old new fun u) - (refresh-now "paragraph-formatter") - ) ;begin - ) ; - // - // - ("2.0x" + (assuming (line-spacing-exactly? new) + (item (text "Spacing value:") + (enum (begin - (change "par-sep" "1.0fn" old new fun u) - (refresh-now "paragraph-formatter") - ) ;begin - ) ; - ) ;hlist - ) ;item + (change "par-sep" answer old new fun u) + (refresh-now "paragraph-formatter")) + (cons-new (get-current-par-sep new) '("10pt" "12pt" "15pt" "18pt" "20pt" "24pt")) + (get-current-par-sep new) + "10em" + ) ;enum + ) ;item + ) ;assuming + (assuming (line-spacing-at-least? new) + (item (text "Minimum value:") + (enum + (begin + (change "par-ver-sep" answer old new fun u) + (refresh-now "paragraph-formatter")) + (cons-new (get-current-par-ver-sep new) '("10pt" "12pt" "15pt" "18pt" "20pt" "24pt")) + (get-current-par-ver-sep new) + "10em" + ) ;enum + ) ;item + ) ;assuming + (assuming (line-spacing-multiple? new) + (item (text "Multiple value:") + (enum + (begin + (change "par-sep" (multiplier-str->par-sep answer) old new fun u) + (refresh-now "paragraph-formatter")) + (cons-new (par-sep->multiplier-str (get-current-par-sep new)) '("1.2" "1.3" "1.4" "1.6" "1.8" "2.5")) + (par-sep->multiplier-str (get-current-par-sep new)) + "10em" + ) ;enum + ) ;item + ) ;assuming (item (text "Interparagraph space:") (enum (change "par-par-sep" answer old new fun u) (cons-new (ahash-ref new "par-par-sep") @@ -369,7 +566,17 @@ (let* ((old (get-env-table paragraph-parameters)) (new (get-env-table paragraph-parameters)) (u (current-buffer)) - ) ; + (p-sep (get-current-par-sep new)) + (pv-sep (get-current-par-ver-sep new)) + (sp-type (get-line-spacing-type p-sep pv-sep)) + ) ; + ;; Initialize saved values from current document state + (cond ((equal? sp-type "Exactly") + (set! line-spacing-exactly-value p-sep)) + ((equal? sp-type "At least") + (set! line-spacing-at-least-value pv-sep)) + ((equal? sp-type "Multiple") + (set! line-spacing-multiple-value p-sep))) (dialogue-window (paragraph-formatter old new make-multi-line-with u #f) noop "Paragraph format" diff --git a/devel/0411.md b/devel/0411.md new file mode 100644 index 0000000000..1e7d8654db --- /dev/null +++ b/devel/0411.md @@ -0,0 +1,126 @@ +# [0411] 支持行间距对话框子控件的动态显示与数值保持 + +任务编号:0411 + +## 1 相关文档 +- [dddd.md](dddd.md) - 任务文档模板 + +## 2 任务相关的代码文件 +- TeXmacs/progs/generic/format-widgets.scm +- TeXmacs/plugins/lang/dic/en_US/zh_CN.scm + +## 3 如何测试 + +### 3.1 确定性测试(单元测试) +```bash +xmake b stem +``` + +### 3.2 非确定性测试(文档验证) +```bash +xmake r stem +# 打开任意文档,验证段落格式对话框: +# 1. 选择"格式"→"段落"→"段落格式",打开对话框 +# 2. 选择行间距为"固定值",设置为15pt,点击确定 +# 3. 重新打开对话框,切换到"单倍行距",观察"设置值"字段是否消失 +# 4. 切换回"固定值",确认值显示为15pt(而非默认的12pt) +# 5. 类似测试"最小值"模式(如设为18pt)和"多倍"模式(如设为1.8) +# 6. 确认"最小值:"和"多倍值:"标签显示为中文 +``` + +## 4 如何提交 + +提交前执行以下最少步骤: + +```bash +xmake b stem +``` + +## 5 What + +修复段落格式对话框中"行间距"功能的问题: + +1. **子控件动态显示/隐藏问题**:当切换行间距类型(单倍/1.5倍/2倍/最小值/固定值/多倍)时,对应的子控件(如"设置值"、"最小值"、"多倍值")无法正确显示或隐藏 +2. **数值重置问题**:当从"固定值"切换到其他类型再切换回来时,之前设置的值会重置为默认值(如12pt),而不是保持用户设置的值 +3. **中文翻译**:为"Minimum value:"和"Multiple value:"添加中文翻译 + +## 6 Why + +1. **条件渲染复杂度过高**:`assuming` 块中使用了多层嵌套的 `let*` 表达式来动态计算行间距类型,导致 TeXmacs 的 widget DSL 无法正确判断条件并渲染子控件 +2. **状态丢失**:`par-sep` 和 `par-ver-sep` 是文档的实际属性,切换行间距类型时会直接覆盖这些值,导致用户之前设置的数值丢失 +3. **默认值硬编码**:`get-exactly-default` 等函数在无法获取有效值时总是返回固定的 `"12pt"`,没有记忆用户之前的设置 + +## 7 How + +### 7.1 简化条件渲染逻辑 + +将复杂的 `let*` 嵌套提取为独立的辅助函数,使 `assuming` 条件判断更清晰: + +```scheme +(define (line-spacing-exactly? new) + (equal? (get-line-spacing-type (get-current-par-sep new) + (get-current-par-ver-sep new)) "Exactly")) + +(define (line-spacing-at-least? new) + (equal? (get-line-spacing-type (get-current-par-sep new) + (get-current-par-ver-sep new)) "At least")) + +(define (line-spacing-multiple? new) + (equal? (get-line-spacing-type (get-current-par-sep new) + (get-current-par-ver-sep new)) "Multiple")) +``` + +在 `assuming` 块中使用这些函数: + +```scheme +(assuming (line-spacing-exactly? new) + (item (text "Spacing value:") ...)) +``` + +### 7.2 添加状态变量保存用户值 + +添加三个全局状态变量,用于保存各类型下的用户设置: + +```scheme +(define line-spacing-exactly-value "12pt") +(define line-spacing-at-least-value "12pt") +(define line-spacing-multiple-value "0.2fn") +``` + +### 7.3 添加保存与恢复机制 + +- `save-line-spacing-values`:在切换行间距类型前,保存当前类型的设置值到对应的状态变量 +- `get-exactly-default-with-save`:返回保存的固定值,而非硬编码默认值 +- `get-at-least-default-with-save`:返回保存的最小值 +- `get-multiple-default-with-save`:返回保存的多倍值 + +### 7.4 修改类型切换回调 + +在"行间距"下拉框的每个选项回调中,先调用 `save-line-spacing-values` 保存当前值,再切换到新类型: + +```scheme +((equal? answer "Exactly") + (begin + (save-line-spacing-values new) + (change "par-sep" (get-exactly-default-with-save ...) ...) + ...)) +``` + +### 7.5 初始化对话框状态 + +在 `open-paragraph-format-window` 中,根据文档当前状态初始化状态变量,确保对话框打开时能正确加载已有设置。 + +### 7.6 修复字符串拼接Bug + +修复 `multiplier->par-sep` 函数中的字符串拼接问题: + +```scheme +;; 修复前:"0fn" +;; 修复后:"fn" +``` + +### 7.7 添加中文翻译 + +在 `zh_CN.scm` 中添加: +- "Minimum value:" → "最小值:" +- "Multiple value:" → "多倍值:"