From 0886cdca79eb4f05ad4d9008d268bdd82609cd84 Mon Sep 17 00:00:00 2001 From: Da Shen Date: Sun, 31 May 2026 21:09:55 +0800 Subject: [PATCH] =?UTF-8?q?[0075]=20fmt=20=E5=92=8C=20fix=20=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E6=94=AF=E6=8C=81=E8=87=AA=E5=AE=9A=E4=B9=89=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E5=90=8E=E7=BC=80=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 默认只处理 .scm 文件 - 添加 -e, --extension EXT 选项支持传入自定义后缀名 - 扩展名参数不需要带点,内部自动补全 - 支持逗号分隔多个后缀名,如 scm,sld - 修改 changed-scheme-files-since 增加可选扩展名列表参数 --- devel/0075.md | 60 +++++++++++++++++++++++ tools/common/liii/goldtool-changed.scm | 30 +++++++++--- tools/fix/liii/goldfix.scm | 53 +++++++++++++++++---- tools/fmt/liii/goldfmt.scm | 66 ++++++++++++++++++++------ 4 files changed, 180 insertions(+), 29 deletions(-) create mode 100644 devel/0075.md diff --git a/devel/0075.md b/devel/0075.md new file mode 100644 index 00000000..1891b7cc --- /dev/null +++ b/devel/0075.md @@ -0,0 +1,60 @@ +# [0075] fmt 和 fix 工具支持自定义文件后缀名 + +## 1. 相关文档 +- [dddd.md](dddd.md) - 任务文档模板 + +## 2. 任务相关的代码文件 +- `tools/fmt/liii/goldfmt.scm` - fmt 工具主入口 +- `tools/fix/liii/goldfix.scm` - fix 工具主入口 +- `tools/common/liii/goldtool-changed.scm` - changed-scheme-files-since 通用函数 + +## 3. 如何测试 + +### 3.1 确定性测试(单元测试) +```bash +xmake b goldfish +bin/gf test tools/common/tests/liii/goldtool-changed/changed-files-since-test.scm +bin/gf test tools/fmt/tests/ +bin/gf test tools/fix/tests/ +``` + +### 3.2 非确定性测试(功能验证) +```bash +# 默认只处理 .scm 文件 +bin/gf fmt /path/to/dir +bin/gf fix /path/to/dir + +# 指定其他后缀名 +bin/gf fmt -e sld /path/to/dir +bin/gf fix -e sld /path/to/dir + +# 逗号分隔同时指定多个后缀名 +bin/gf fmt -e scm,sld /path/to/dir +bin/gf fix -e scm,sld /path/to/dir +``` + +## 4. 如何提交 + +提交前执行以下最少步骤: + +```bash +bin/gf test --changed-since=main +``` + +## 5. 2026-05-31 任务描述 + +### 5.1 What +1. `fmt` 和 `fix` 工具默认只允许文件后缀名为 `.scm` +2. 为两个工具添加 `-e, --extension EXT` 命令行选项,支持传入自定义文件后缀名 +3. 扩展名参数不需要带 `.`,内部自动补全 +4. `--extension` 支持逗号分隔多个后缀名,如 `scm,sld` + +### 5.2 Why +项目中除了 `.scm` 文件外,还可能存在其他 Scheme 相关后缀的文件(如 `.sld`),需要格式化或修复括号时,硬编码的 `.scm` 过滤会遗漏这些文件。 + +### 5.3 How +1. 在 `goldfmt.scm` 和 `goldfix.scm` 的 `make-*-arg-parser` 中添加 `--extension` 选项(默认值为 `"scm"`) +2. 在 `main` 函数中通过 `parse-extensions` 将逗号分隔的原始扩展名解析为列表,并自动补全 `.` +3. 添加 `file-extension-match?` 辅助函数判断文件是否匹配任一扩展名 +4. 将 `format-directory`、`fix-directory` 和 `format-changed-since` 中的硬编码 `".scm"` 替换为扩展名列表 +5. 修改 `changed-scheme-files-since`,增加可选的扩展名列表参数(保持向后兼容) diff --git a/tools/common/liii/goldtool-changed.scm b/tools/common/liii/goldtool-changed.scm index d1331020..f2501b4c 100644 --- a/tools/common/liii/goldtool-changed.scm +++ b/tools/common/liii/goldtool-changed.scm @@ -107,12 +107,30 @@ ) ;define (define (changed-scheme-files-since since . maybe-path) - (filter (lambda (file) (and (string-ends? file ".scm") (path-file? file))) - (if (null? maybe-path) - (changed-files-since since) - (changed-files-since since (car maybe-path)) - ) ;if - ) ;filter + (let* ((has-extension-param? (and (not (null? maybe-path)) + (not (null? (cdr maybe-path))))) + (extensions (if has-extension-param? (cadr maybe-path) '(".scm"))) + (path (if has-extension-param? (car maybe-path) + (if (null? maybe-path) #f (car maybe-path))))) + (filter (lambda (file) + (and (path-file? file) + (let loop ((exts extensions)) + (if (null? exts) + #f + (if (string-ends? file (car exts)) + #t + (loop (cdr exts)) + ) ;if + ) ;if + ) ;let + ) ;and + ) ;lambda + (if path + (changed-files-since since path) + (changed-files-since since) + ) ;if + ) ;filter + ) ;let* ) ;define ) ;begin diff --git a/tools/fix/liii/goldfix.scm b/tools/fix/liii/goldfix.scm index 0b73c787..a0a311ce 100644 --- a/tools/fix/liii/goldfix.scm +++ b/tools/fix/liii/goldfix.scm @@ -3,6 +3,7 @@ (import (liii base) (liii sys) (liii path) + (liii string) (liii argparse) (liii hashlib) (liii os) @@ -54,6 +55,8 @@ (newline) (display " --dry-run 预览模式(仅支持单个文件)") (newline) + (display " -e, --extension EXT 指定文件后缀名(默认 scm,支持逗号分隔多个)") + (newline) (newline) (display "Arguments:") (newline) @@ -73,6 +76,12 @@ (display " gf fix /path/to/dir 递归修正目录下所有 .scm 文件" ) ;display (newline) + (display " gf fix -e sld /path/to/dir 递归修正目录下所有 .sld 文件" + ) ;display + (newline) + (display " gf fix -e scm,sld /path/to/dir 递归修正目录下所有 .scm 和 .sld 文件" + ) ;display + (newline) ) ;define (define (display-diagnostics diagnostics) @@ -143,7 +152,19 @@ (fix-file-core path-str use-cache?) ) ;define* - (define (fix-directory dir-path) + (define (file-extension-match? filename extensions) + (let loop ((exts extensions)) + (if (null? exts) + #f + (if (string-suffix? (car exts) filename) + #t + (loop (cdr exts)) + ) ;if + ) ;if + ) ;let + ) ;define + + (define (fix-directory dir-path extensions) (let ((fmt-cmd (string-append (executable) " fmt " dir-path))) (os-call fmt-cmd) ) ;let @@ -155,7 +176,7 @@ (let ((entry (vector-ref entries i))) (cond ((path-file? entry) (let ((entry-str (path->string entry))) - (if (string-suffix? ".scm" entry-str) + (if (file-extension-match? entry-str extensions) (let ((result (fix-file-core entry-str))) (cond ((eq? result 'cached) (loop (+ i 1) (+ total 1) updated (+ cached 1))) @@ -172,7 +193,7 @@ ) ;let ) ; ((path-dir? entry) - (call-with-values (lambda () (fix-directory (path->string entry))) + (call-with-values (lambda () (fix-directory (path->string entry) extensions)) (lambda (sub-total sub-updated sub-cached) (loop (+ i 1) (+ total sub-total) (+ updated sub-updated) (+ cached sub-cached)) ) ;lambda @@ -202,6 +223,10 @@ (short . "h") (action . store-true))) (parser :add-argument '((name . "dry-run") (action . store-true))) + (parser :add-argument '((name . "extension") + (short . "e") + (type . string) + (default . "scm"))) parser ) ;let ) ;define @@ -212,13 +237,25 @@ ) ;let ) ;define + (define (normalize-extension ext) + (if (and (> (string-length ext) 0) + (char=? (string-ref ext 0) #\.)) + ext + (string-append "." ext)) + ) ;define + + (define (parse-extensions raw) + (map normalize-extension (string-split raw ",")) + ) ;define + (define (main) (let ((parser (make-fix-arg-parser))) (parser :parse-argv (argv)) - (let ((help-flag (parser 'help)) - (dry-run (parser 'dry-run)) - (path-str (first-positional parser)) - ) ; + (let* ((help-flag (parser 'help)) + (dry-run (parser 'dry-run)) + (extensions (parse-extensions (parser 'extension))) + (path-str (first-positional parser)) + ) ; (cond ((or help-flag (string=? path-str "")) (display-help) #t) ((path-file? (path path-str)) (if dry-run @@ -246,7 +283,7 @@ (newline) (exit 1) ) ;begin - (call-with-values (lambda () (fix-directory path-str)) + (call-with-values (lambda () (fix-directory path-str extensions)) (lambda (total updated cached) (display (string-append "Total files fixed: " (number->string total) diff --git a/tools/fmt/liii/goldfmt.scm b/tools/fmt/liii/goldfmt.scm index 534b3396..36a41b43 100644 --- a/tools/fmt/liii/goldfmt.scm +++ b/tools/fmt/liii/goldfmt.scm @@ -95,7 +95,9 @@ (display " --dry-run 预览模式(不写回文件;目录路径不支持)" ) ;display (newline) - (display " --changed-since REV 仅格式化自 REV 以来变更的 .scm 文件" + (display " -e, --extension EXT 指定文件后缀名(默认 scm,支持逗号分隔多个)") + (newline) + (display " --changed-since REV 仅格式化自 REV 以来变更的文件" ) ;display (newline) (newline) @@ -114,7 +116,7 @@ (newline) (display " gf fmt --dry-run file.scm 预览格式化结果") (newline) - (display " gf fmt --changed-since=HEAD 格式化自 HEAD 以来变更的 .scm 文件" + (display " gf fmt --changed-since=HEAD 格式化自 HEAD 以来变更的文件" ) ;display (newline) (display " gf fmt --dry-run --changed-since=HEAD 预览变更文件的格式化结果" @@ -123,6 +125,12 @@ (display " gf fmt /path/to/dir 递归格式化目录下所有 .scm 文件" ) ;display (newline) + (display " gf fmt -e sld /path/to/dir 递归格式化目录下所有 .sld 文件" + ) ;display + (newline) + (display " gf fmt -e scm,sld /path/to/dir 递归格式化目录下所有 .scm 和 .sld 文件" + ) ;display + (newline) ) ;define ;; ; 格式化单个文件(dry-run 模式,输出到终端) @@ -196,7 +204,19 @@ ) ;let ) ;define - (define (format-changed-since since path-str dry-run) + (define (file-extension-match? filename extensions) + (let loop ((exts extensions)) + (if (null? exts) + #f + (if (string-suffix? (car exts) filename) + #t + (loop (cdr exts)) + ) ;if + ) ;if + ) ;let + ) ;define + + (define (format-changed-since since path-str dry-run extensions) (let ((scope (if (string=? path-str "") #f path-str))) (cond ((and scope (not (or (path-file? (path scope)) (path-dir? (path scope))))) (display (string-append "错误: 路径不存在 - " scope)) @@ -204,8 +224,8 @@ (exit 1) ) ; (else (let ((files (if scope - (changed-scheme-files-since since scope) - (changed-scheme-files-since since) + (changed-scheme-files-since since scope extensions) + (changed-scheme-files-since since extensions) ) ;if ) ;files ) ; @@ -238,7 +258,7 @@ ;; ; 递归格式化目录 ;; ; 返回值: (values total updated cached) - 处理的文件总数、更新数、缓存命中数 - (define (format-directory dir-path) + (define (format-directory dir-path extensions) (let ((entries (path-list-path (path dir-path)))) (let loop ((i 0) (total 0) (updated 0) (cached 0)) @@ -247,7 +267,7 @@ (let ((entry (vector-ref entries i))) (cond ((path-file? entry) (let ((entry-str (path->string entry))) - (if (string-suffix? ".scm" entry-str) + (if (file-extension-match? entry-str extensions) (let ((result (format-file entry-str))) (cond ((eq? result 'cached) (loop (+ i 1) (+ total 1) updated (+ cached 1)) @@ -267,7 +287,7 @@ ) ;let ) ; ((path-dir? entry) - (call-with-values (lambda () (format-directory (path->string entry))) + (call-with-values (lambda () (format-directory (path->string entry) extensions)) (lambda (sub-total sub-updated sub-cached) (loop (+ i 1) (+ total sub-total) (+ updated sub-updated) (+ cached sub-cached)) ) ;lambda @@ -297,6 +317,10 @@ (short . "h") (action . store-true))) (parser :add-argument '((name . "dry-run") (action . store-true))) + (parser :add-argument '((name . "extension") + (short . "e") + (type . string) + (default . "scm"))) (parser :add-argument '((name . "changed-since") (type . string))) parser ) ;let @@ -308,17 +332,29 @@ ) ;let ) ;define + (define (normalize-extension ext) + (if (and (> (string-length ext) 0) + (char=? (string-ref ext 0) #\.)) + ext + (string-append "." ext)) + ) ;define + + (define (parse-extensions raw) + (map normalize-extension (string-split raw ",")) + ) ;define + ;; ; 主入口函数 (define (main) (let ((parser (make-fmt-arg-parser))) (parser :parse-argv (argv)) - (let ((help-flag (parser 'help)) - (dry-run (parser 'dry-run)) - (changed-since (parser 'changed-since)) - (path-str (first-positional parser)) - ) ; + (let* ((help-flag (parser 'help)) + (dry-run (parser 'dry-run)) + (extensions (parse-extensions (parser 'extension))) + (changed-since (parser 'changed-since)) + (path-str (first-positional parser)) + ) ; (cond (help-flag (display-help) #t) - (changed-since (format-changed-since changed-since path-str dry-run)) + (changed-since (format-changed-since changed-since path-str dry-run extensions)) ((string=? path-str "") (display-help) #t) ((path-file? (path path-str)) (if dry-run @@ -346,7 +382,7 @@ (newline) (exit 1) ) ;begin - (call-with-values (lambda () (format-directory path-str)) + (call-with-values (lambda () (format-directory path-str extensions)) (lambda (total updated cached) (display (string-append "Total files formatted: " (number->string total)