@chengzhao-dev/dsh-cpp-workflow 0.6.14 → 0.6.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.en.md CHANGED
@@ -19,13 +19,13 @@ The exception material follows the C++ Core Guidelines' Error handling section a
19
19
  Pinned npm install:
20
20
 
21
21
  ```bash
22
- dsh plugin --profile web add npm:@chengzhao-dev/dsh-cpp-workflow@0.6.14
22
+ dsh plugin --profile web add npm:@chengzhao-dev/dsh-cpp-workflow@0.6.16
23
23
  ```
24
24
 
25
25
  The matching Git tag:
26
26
 
27
27
  ```bash
28
- dsh plugin --profile web add github:chengzhao-dev/dsh-cpp-workflow#v0.6.14
28
+ dsh plugin --profile web add github:chengzhao-dev/dsh-cpp-workflow#v0.6.16
29
29
  ```
30
30
 
31
31
  The desktop app owns the `desktop` profile. If the command-line `add` is rejected, add the plugin in the app settings and use the same pinned npm version. A Git tag install uses the prebuilt `lib/` committed in the repository and runs no build on the target machine; the package has no install script that needs approval.
package/README.md CHANGED
@@ -19,13 +19,13 @@
19
19
  npm 安装钉死版本:
20
20
 
21
21
  ```bash
22
- dsh plugin --profile web add npm:@chengzhao-dev/dsh-cpp-workflow@0.6.14
22
+ dsh plugin --profile web add npm:@chengzhao-dev/dsh-cpp-workflow@0.6.16
23
23
  ```
24
24
 
25
25
  同版本的 Git 标签:
26
26
 
27
27
  ```bash
28
- dsh plugin --profile web add github:chengzhao-dev/dsh-cpp-workflow#v0.6.14
28
+ dsh plugin --profile web add github:chengzhao-dev/dsh-cpp-workflow#v0.6.16
29
29
  ```
30
30
 
31
31
  桌面应用独占 `desktop` profile。命令行 `add` 被拒绝时,在应用设置里添加插件,地址填同一个 npm 版本。Git 标签安装使用仓库内已构建的 `lib/`,不在目标机器上重新构建;包内也不含需要授权执行的安装脚本。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chengzhao-dev/dsh-cpp-workflow",
3
- "version": "0.6.14",
3
+ "version": "0.6.16",
4
4
  "description": "写 C++ 源码、配 CMake、用 Clang 构建;头文件用 /// Doxygen 文档注释,函数体用 // 分段说明,文件头标签可在设置里改。",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -65,11 +65,11 @@ clang-format --dry-run --Werror src/*.cpp include/*.h
65
65
  | 输出 | 先看 | 回到 |
66
66
  | --- | --- | --- |
67
67
  | `CMake Error ... CXX compiler` | `environment.json`、`--live` | `building-cpp` 的定构建 / 通过检查 |
68
- | `ninja: error: ... missing and no known rule` | 源文件是否在 CMake 中列出 | 定构建 |
69
- | `fatal error: ... No such file` | `target_include_directories` | 定构建 |
70
- | `undefined reference` | `target_link_libraries`、库 target 名 | 定构建 |
68
+ | `ninja: error: ... missing and no known rule` | 源文件是否在 CMake 中列出 | `configuring-cmake` 的 target 源文件清单 |
69
+ | `fatal error: ... No such file` | `target_include_directories` | `configuring-cmake` 的包含边界 |
70
+ | `undefined reference` | `target_link_libraries`、库 target 名 | `configuring-cmake` 的链接边界 |
71
71
  | `CTest` 失败 | 测试断言、行为句 | `developing-cpp` 的定行为 / 定实现 |
72
- | 运行时报找不到 `.so` | RPATH / `LD_LIBRARY_PATH` | 定构建 |
72
+ | 运行时报找不到 `.so` | RPATH / `LD_LIBRARY_PATH` | `configuring-cmake` 的链接边界与 RPATH |
73
73
 
74
74
  ## 验收
75
75
 
@@ -36,7 +36,7 @@ metadata:
36
36
  | 3 | 定声明 | `steps/03-declaration.md` | 写命名、声明顺序、头文件契约和声明注释 |
37
37
  | 4 | 定实现 | `steps/04-implementation.md` | 写 `.cpp` 函数体的操作顺序、分组和实现注释 |
38
38
 
39
- 每步只打开同号的一个步骤文件。判不准才打开 `examples/` 里与该步对应的案例;`references/` 保存完整条文,只在排错、整目录重构,或步骤里明确指向某一条文时按需打开。性能问题读 `references/performance.md`,标准库设施选型读 `references/standard-library.md`,链接与产物的细节读 `building-cpp` 的 `references/linking.md`。
39
+ 每步只打开同号的一个步骤文件。判不准才打开 `examples/` 里与该步对应的案例;`references/` 保存完整条文,只在排错、整目录重构,或步骤里明确指向某一条文时按需打开。性能问题读 `references/performance.md`,标准库设施选型读 `references/standard-library.md`,注释术语判不准读 `references/comment-terms.md`,链接与产物的细节读 `building-cpp` 的 `references/linking.md`。
40
40
 
41
41
  本轮激活按三条上限走:
42
42
 
@@ -193,7 +193,7 @@ friend bool operator==(const Position&, const Position&) = default;
193
193
  /// 检查指定坐标上的棋盘格子是否为空。
194
194
  ///
195
195
  /// @param position 待检查的坐标。
196
- /// @return 坐标在棋盘内且该格为空时返回 true;越界或该格已有棋子时返回 false。
196
+ /// @return 坐标在棋盘内且该格为空时返回 true;越界或该格已有状态时返回 false。
197
197
  [[nodiscard]] bool IsCellEmpty(Position position) const;
198
198
  ```
199
199
 
@@ -215,14 +215,14 @@ enum class Player : std::uint8_t {
215
215
  ```cpp
216
216
  /// 对局结果。
217
217
  enum class GameResult : std::uint8_t {
218
- kInProgress = 0, ///< 游戏进行中:还可以落子。
219
- kCrossWin = 1, ///< X 获胜:达成三连。
220
- kNoughtWin = 2, ///< O 获胜:达成三连。
221
- kDraw = 3, ///< 平局:棋盘已满,双方都没有三连。
218
+ kInProgress = 0, ///< 对局尚未结束
219
+ kCrossWin = 1, ///< 对局由 X 获胜
220
+ kNoughtWin = 2, ///< 对局由 O 获胜
221
+ kDraw = 3, ///< 对局以平局结束
222
222
  };
223
223
  ```
224
224
 
225
- 行尾注释先写语义,需要时用冒号补一句能核实的条件或结果,两段都短;不重复名字,不写嵌套子句,同一枚举要么全写要么全不写。
225
+ 行尾注释必须以枚举主体的同一个词开头,写成完整的状态或结果;需要补原因时用「主体 + 结果:原因」,冒号前后都不能空。不写「X 成线」「尚未结束」这种只有谓语的片段,同一枚举要么全写要么全不写。
226
226
 
227
227
  ## 数据成员
228
228
 
@@ -0,0 +1,65 @@
1
+ # 注释术语与用词
2
+
3
+ 本文件是 `comments.md` 的附录,只在判不准用词、改写类型注释或核对书稿摘录时打开;它不随 `comments.md` 一起加载,也不重复句式、位置和长度规则。
4
+
5
+ ## 一条概念只认一个词
6
+
7
+ | 概念 | 首选 | 避免 | 说明 |
8
+ | --- | --- | --- | --- |
9
+ | `Position` 类型 | 行列坐标 | 位置类型、坐标点 | 类型名和参数名保持 `Position`、`position` |
10
+ | 棋盘上的点 | 位置 | 坐标点、格子坐标 | 说语义位置时用「位置」 |
11
+ | `Cell` | 格子 | 单元、方格、棋子 | 「棋子」只指对局中的 X 或 O |
12
+ | `Board` | 棋盘 | 盘面、棋局 | 「棋局」只指一局对局 |
13
+ | `CellState` 类型 | 格子状态 | 格子的状态、格子状态值 | 类型注释写「格子状态。」 |
14
+ | `CellState` 的取值 | 格子为空、格子为 X、格子为 O | 状态为空、尚未设置、状态为 X | 每行都以「格子」开头,写完整状态 |
15
+ | `Place` 的动作 | 更新状态 | 写入格子、放置、落子 | `Board::Place` 也用「更新」 |
16
+ | `PlaceResult` 类型 | 格子状态变更结果 | 格子状态的变更结果、放置结果 | 类型注释写「格子状态变更结果。」 |
17
+ | `PlaceResult` 的取值 | 格子状态已变更/未变更:原因 | 已变更、未变更、成功、失败 | 先写主体与变更,再写原因 |
18
+ | `GameResult` 类型 | 对局结果 | 对局的结果、游戏结果、一局的结果 | 类型注释写「对局结果。」 |
19
+ | `GameResult` 的取值 | 对局尚未结束、对局由 X 获胜、对局由 O 获胜、对局以平局结束 | 尚未结束、X 成线、O 成线、棋盘已满 | 每行都以「对局」开头,写完整结果 |
20
+ | `Clear` 的动作 | 重置为空、清空 | 清空值、收回 `kEmpty` | 逐格重置,不叫「清空值」 |
21
+ | `GetCell` 的返回 | 格子副本 | 格子、引用 | 按值返回必须说「副本」 |
22
+ | 坐标越界 | 坐标越界时抛出 `std::out_of_range` | 检查越界 | 只用于会抛的校验函数 |
23
+ | `GetGameResult` | 当前结果 | 现在的结果、最新结果 | 结果是棋盘的快照 |
24
+ | `row`、`col` | 行号、列号 | 行、列 | 成员注释写「从 0 起算」,类注释不重复 |
25
+
26
+ ## 位置与坐标
27
+
28
+ - `Position` 是类型名,中文叫「行列坐标」;参数名用 `position`,不改成 `pos`。
29
+ - 「棋盘上的一个位置」指语义位置;「一行一列的坐标」指具体值。两者不混成「坐标点」。
30
+ - 成员注释写「行号,从 0 起算」「列号,从 0 起算」;类注释不再重复「都从 0 起算」,否则和成员注释冲突。
31
+
32
+ ## 格子与棋盘
33
+
34
+ - `Cell` 只说「格子」;「棋盘上的格子」只在需要强调归属时用,类型注释本身不写棋盘。
35
+ - `Board` 只说「棋盘」;`cells_` 说「格子数组」,不写「存储格子的数组」这种复述。
36
+ - 「棋子」只指对局中的 X 或 O;格子的内部值叫「状态」,不叫「棋子」。
37
+ - `PlaceResult` 的三种结果说「格子状态已变更」「格子状态未变更」,不说「成功」「失败」;拒绝覆盖说「已有状态」,不说「占据」。
38
+
39
+ ## 更新与写入
40
+
41
+ - `Place` 的动作统一写「更新状态」:`Cell::Place` 更新一格,`Board::Place` 把坐标转给对应格子。
42
+ - 「写入」只用于数组、文件、流这类输出目标;不写「写入一个格子」「把状态写入格子」。
43
+ - 「设置」只表示有没有状态;「更新」表示这次动作;「已有状态」表示拒绝覆盖。三者不互换。
44
+ - `Clear` 说「重置为空」或「重置为 `kEmpty`」,不写「清空值」「删除状态」。
45
+
46
+ ## 返回值与副本
47
+
48
+ - `GetCell` 按值返回:第一句和 `@return` 都写「格子副本」,不写「该位置的格子」,否则读者会以为拿到引用。
49
+ - `GetState` 返回枚举值,写「当前状态」,不写「状态值」。
50
+ - `GetGameResult` 写「当前结果」,不写「现在的结果」。
51
+ - 会抛的查询先写抛出条件,再写 `@throws`;`@param` 写「待检查/读取/更新的坐标」,不把「棋盘内」当前置条件。
52
+
53
+ ## 初始状态与特殊成员
54
+
55
+ - 类注释拥有初始状态与生命周期;默认构造函数只写「建立初始状态」,不再重复具体状态值。
56
+ - 数据成员只写成员自身:`row`、`col` 写行号/列号与从 0 起算;`state_` 写「格子当前的状态」,不重复类注释的初始值。
57
+ - 文件头只写 `@file`、`@brief` 与文件组成;不写作者、版权年份、变更史。
58
+
59
+ ## 依据
60
+
61
+ - [Google 中文 C++ 风格指南·注释](https://zh-google-styleguide.readthedocs.io/en/stable/google-cpp-styleguide/comments.html):类讲用途,函数讲输入输出,不翻译代码。
62
+ - [LeviLamina C++ 风格指南](https://docs.levimc.org/LeviLamina/zh/maintainer_guides/cpp_style_guide/):类注释至少简介与公开成员,函数注释含参数、返回值与异常。
63
+ - [OpenHarmony C++ 语言编程规范·注释](https://www.bookstack.cn/read/openharmony-1.0-zh-cn/contribute-OpenHarmony-cpp-coding-style-guide.md):按需、简洁、无二义性,不重复代码信息。
64
+
65
+ 判不准时先查本表,再查 `comments.md` 的句式与位置;改完运行 `node "<skill-dir>/scripts/checking-comments.mjs" --root <项目根>`。
@@ -6,6 +6,8 @@
6
6
 
7
7
  按四类改动查:写作决定写什么,布局决定放哪一层哪一行,排版决定符号、宽度与标签,润色删复述、统一句式。四步都可能删句子,但后置条件和成员约定只有写作能定,润色不得以「精简」为由删掉。
8
8
 
9
+ 用词与术语见 `comment-terms.md`:判不准时再开,本文件不复制词表。
10
+
9
11
  ## 写作:只写声明里看不出的事实
10
12
 
11
13
  - **第一句先写结果、保证或检查项**:类型用名词短语写它是什么;普通函数写正常返回什么、失败时返回什么或抛什么;布尔查询与 `operator==` 写「检查…是否…」。第一句不写「返回 true/false」;`@return` 仍要写明成立时返回 true、不成立时返回 false。条件、参数与实现理由放第二句以后。
@@ -20,7 +22,7 @@
20
22
 
21
23
  对象是类、结构体、枚举和类型别名。第一句是名词短语:类写「这个类型是什么」,可用全角冒号补初始状态;纯数据结构和枚举写「这个取值表示什么」。
22
24
 
23
- 只有类有不变量,且不重复领域尺寸时,才加第二段。第二段直接写不变量与生命周期:初始状态、状态迁移、重置条件;生命周期写在类注释,不拆到成员注释。不加「限制:」这类标签,也不写「这一层不负责什么」。纯数据结构和枚举不写第二句。
25
+ 只有类有不变量,且不重复领域尺寸时,才加第二段。第二段直接写不变量与生命周期:初始状态、状态迁移、重置条件;生命周期写在类注释,不拆到成员注释。第二段用概念句写生命周期,不点成员函数名。不加「限制:」这类标签,也不写「这一层不负责什么」。纯数据结构和枚举不写第二句。
24
26
 
25
27
  ```cpp
26
28
  /// 井字棋棋盘。
@@ -29,24 +31,24 @@ class Board {
29
31
 
30
32
  禁止事项:
31
33
 
32
- - 不写成员清单,不按声明顺序复述接口。函数各自的契约写在函数上。
34
+ - 不写成员清单,不按声明顺序复述接口。函数各自的契约写在函数上。连 `Place`、`Clear` 这样的成员名也不写进类注释;生命周期用「空白格子至多成功更新一次」这类概念句。
33
35
  - 不写跨类分工。边界靠类型与所有权表达,注释只写本类型保证什么。
34
36
  - 不写类型系统已经表达的性质(`值语义`、`所有查询都是 const`)。
35
37
  - 不写尚未发生的用法、方案对比与取舍论证、广告句。
36
38
  - 纯数据结构不写「只保存…,不拥有…,不含…」这类否定式边界;这些由成员类型和所有权表达。
37
39
  - 领域尺寸不写进类型注释:格子数由 `cells_` 的声明表达,棋盘边长由 `kRowCount`、`kColumnCount` 表达。
38
- - 枚举与只承载数据的结构体:第一句是名词短语,写这个取值表示什么。状态枚举上一行写「格子的状态。」,结果枚举写「表示…结果。」;行尾 `///<` 的两种句式见「枚举项与 `struct` 短字段:两种句式」。
40
+ - 枚举与只承载数据的结构体:第一句是名词短语,写这个取值表示什么。状态枚举写「格子状态。」,结果枚举写「格子状态变更结果。」或「对局结果。」这类「<对象><属性>」;不用「表示…结果。」开头,也不写成「格子的状态。」「对局的结果。」这种带「的」的短语。行尾 `///<` 的句式见「枚举项与 `struct` 短字段:两种句式」。
39
41
 
40
42
  ### 构造函数与析构函数:先写标签,再写职责
41
43
 
42
44
  特殊成员用标签开头:`默认构造函数:`、`拷贝构造函数:`、`移动构造函数:`、`析构函数:`;其他构造函数写 `构造函数:`。标签后写构造完成后的后置条件,或析构函数负责什么。`= default` 配合成员初始化器建立的不变量,签名上看不见,必须写成后置条件。只写读者能观察到的事实,不写「创建对象」「初始化成员」这类复述。
43
45
 
44
46
  ```cpp
45
- /// 默认构造函数:每一格都是 `kEmpty`。
47
+ /// 默认构造函数:每一格都是空格子。
46
48
  Board() = default;
47
49
  ```
48
50
 
49
- 默认构造与析构可以只写一行:标签后直接写后置条件或职责。`= default` 的后置条件写在标签那一行就够,不再另起一段写「不抛异常」,也不为了注释加 `noexcept`。无参数、无返回值的动作只在签名看不出结果时再写一句,不把「不抛异常」当成这句;不写 `@throws` 就表示不抛。不写空的 `@param`、`@return`。有参数或有返回值的函数按下一节写标签,构造与析构不写 `@return`。标签说明这是哪一类特殊成员,不重复类名;非默认构造同样写建立的不变量与失败方式。
51
+ 默认构造与析构可以只写一行:标签后直接写后置条件或职责。`= default` 的后置条件写在标签那一行就够,不再另起一段写「不抛异常」,也不为了注释加 `noexcept`。无参数、无返回值的动作只在签名看不出结果时再写一句,不把「不抛异常」当成这句;不写 `@throws` 就表示不抛。类注释已经写了初始状态时,默认构造函数只写「建立初始状态」,不重复具体值;类注释没写时,才在这里写后置条件。不写空的 `@param`、`@return`。有参数或有返回值的函数按下一节写标签,构造与析构不写 `@return`。标签说明这是哪一类特殊成员,不重复类名;非默认构造同样写建立的不变量与失败方式。
50
52
 
51
53
  ### 数据成员:上一行 `///`,先写名词再写约定
52
54
 
@@ -66,9 +68,9 @@ GameResult result_ = GameResult::kInProgress;
66
68
  类的生命周期写在类注释,成员注释只留这个成员是什么:
67
69
 
68
70
  ```cpp
69
- /// 格子:初始状态为 `kEmpty`。
71
+ /// 格子:初始时为空。
70
72
  ///
71
- /// `Place` 至多一次将空白格子置为 `kX` 或 `kO`;`Clear` 将其重置为 `kEmpty`。
73
+ /// 空白格子至多成功更新一次;更新后只能重置。
72
74
  class Cell {
73
75
  /// 格子当前的状态。
74
76
  CellState state_{CellState::kEmpty};
@@ -79,12 +81,12 @@ class Cell {
79
81
 
80
82
  ### 枚举项与 `struct` 短字段:两种句式
81
83
 
82
- 枚举项与只承载数据的 `struct` 短字段用行尾 `///<`,同一枚举各行的 `///<` 对齐。只写两种句式:
84
+ 枚举项与只承载数据的 `struct` 短字段用行尾 `///<`,同一枚举各行的 `///<` 对齐。每个枚举项的注释必须以枚举主体的同一个词开头,写成完整的状态或结果,不写只有谓语的片段:
83
85
 
84
- - 语义本身已经完整,只写一句:`///< 状态为空,尚未设置`
85
- - 语义之外还要补一条能核实的条件或结果:`///< 非法参数:传入空棋盘格子类型。`
86
+ - 完整句:`///< 格子为空`、`///< 对局由 X 获胜`
87
+ - 主体加类别与说明:`///< 格子状态未变更:传入状态为空`、`///< 对局以平局结束`
86
88
 
87
- 两类都不收句号。冒号用全角 `:`;冒号前写类别,冒号后写说明,两侧都不能为空。禁止空冒号(`///< 落子成功:。`)、禁止把说明写在类别前面(`///< 传入空棋盘格子类型,非法参数。`)。无冒号的行尾是一句完整的话,可以有句内逗号;有冒号时不得用逗号代替冒号。同一枚举要么每一项都写 `///<`,要么都不写;都写时两种句式可以混用。
89
+ 两类都不收句号。冒号用全角 `:`;冒号前写主体与类别,冒号后写能核实的说明,两侧都不能为空。禁止「X 成线。」「尚未结束。」这类没有主体、只有谓语的片段;禁止空冒号(`///< 落子成功:。`)、禁止把说明写在类别前面(`///< 传入空棋盘格子类型,非法参数。`)。无冒号的行尾是一句完整的话,可以有句内逗号;有冒号时不得用逗号代替冒号。同一枚举要么每一项都写 `///<`,要么都不写;都写时两种句式可以混用。
88
90
 
89
91
  ### 函数:两段式契约
90
92
 
@@ -97,16 +99,16 @@ class Cell {
97
99
  /// 检查坐标能否落子,不修改棋盘。
98
100
  ///
99
101
  /// @param position 目标行列坐标。
100
- /// @param state 要放置的棋盘格子类型,必须是 kX 或 kO。
101
- /// @return 可以落子返回 kPlaced;越界、state 为 kEmpty 或目标已有棋子时返回对应拒绝值。
102
+ /// @param state 要设置的格子状态,必须是 kX 或 kO。
103
+ /// @return 可以落子返回 kPlaced;越界、state 为 kEmpty 或目标已有状态时返回对应拒绝值。
102
104
  [[nodiscard]] Cell::PlaceResult CheckPlaceable(Position position, CellState state) const;
103
105
  ```
104
106
 
105
107
  - 布尔查询与 `operator==`:第一句写「检查…是否…」;`@return` 写成「成立时返回 true;不成立时返回 false」,不写「否则」省略后半句。`Is`、`Has` 开头的名字与 `bool` 返回类型已经把成立条件说清时可省略 `@return`,不为了形式补一句同义反复。
106
- - `@param` 每个参数都写,写范围、单位或所有权,不写「索引」这类同义反复;没有参数就不写空的 `@param`。
108
+ - `@param` 每个参数都写,写范围、单位或所有权,不写「索引」这类同义反复;没有参数就不写空的 `@param`。会校验并抛出的参数写「待检查/读取/更新的坐标」,不把「棋盘内」当前置条件。
107
109
  - `@return` 默认写,写返回值怎么读或失败时返回什么;返回类型与函数名已把条件说清时可省略,不要用「见上」或重复第一段。
108
- - 查询函数(`Get` 开头):第一句写「获取…」;`@return` 列出可能取到的值,枚举值在 `///` 里用反引号,例如 `kEmpty`、`kX` 或 `kO`。
109
- - 更新函数:第一段写动作,第二段写清楚何时更新、什么时候不改;多个结果用 `@retval`,已变更的写在最前,其余按失败次序;标签组之间空一行,`@note` 写判断次序。
110
+ - 查询函数(`Get` 开头):第一句写「获取…」;`@return` 列出可能取到的值,枚举值在 `///` 里用反引号,例如 `kEmpty`、`kX` 或 `kO`。返回副本时第一句和 `@return` 都写「副本」,不写「该位置的格子」这类可读成引用的句子。
111
+ - 更新函数:第一段写动作,第二段写清楚何时更新、什么时候不改;多个结果用 `@retval`,已变更的写在最前,其余按失败次序;描述与标签组之间空一行,标签之间不空行,`@note` 写判断次序。会抛的诊断函数(如 `ValidatePosition`)第一句写「……时抛出 `std::out_of_range`」,不写「检查……是否……」。
110
112
  - `@throws` 必须与 `references/exceptions.md` 一致;不抛异常的函数不写。
111
113
  - 私有函数同样写契约,不能默认调用者知道前置条件;输出参数标 `[out]`,既读又写标 `[in,out]`。
112
114
 
@@ -187,6 +189,8 @@ class Cell {
187
189
 
188
190
  - 注释符号在插件设置里选择:`///` 是默认写法,`/** ... */` 是另一种 Doxygen 写法;文件头与声明注释统一用同一种,函数体内仍只用 `//`。块注释每行以 ` * ` 对齐,收尾单独一行 ` */`。
189
191
  - 行宽跟项目 `.clang-format` 的 `ColumnLimit` 走;项目没写时按 Google 默认 80 列,中文按两列计。
192
+ - Doxygen 文档块:摘要与详细描述之间空一行;段落之间空一行;详细描述与标签块之间空一行;标签之间不空行。`@param`、`@retval`、`@return`、`@throws`、`@note` 连续排列,不插空 `///` 行。
193
+ - 注释换行:一句一行;超过列宽在分号或逗号处分句,续行与正文同缩进;标签描述尽量单行,超宽时在分句处断,续行相对标签文字缩进两格;不把一句话拆成一个词一行。
190
194
  - 行尾注释与代码之间空两格;`///<` 只接在枚举项和 `struct` 短字段声明行尾。
191
195
  - `@param`、`@return`、`@throws` 标签保持英文;`@param` 后先写参数名,再写一句。
192
196
  - `TODO:` 后先写定位(阶段名或 issue 号),再写一个短横线,再写动作;不写 `TODO(某人)`,不写没有动作的 TODO。
@@ -207,14 +211,6 @@ class Cell {
207
211
  - 注释写给维护者,正文写给读者;设计理由、方案比较与算法取舍写在正文或实现注释里,公开接口只留契约。
208
212
  - 禁止用注释代替类型、`const` 或 `[[nodiscard]]`。
209
213
 
210
- ### 例:格子状态这一对文件的用词
211
-
212
- `cell.h` 与 `cell.cpp` 用下面这套词,只约束这一对文件,不是全项目禁令:
214
+ ### 术语与用词
213
215
 
214
- - 说状态与格子状态,不说「取值」。
215
- - 说尚未设置、状态为空、空白格子,不说「空格子」「尚未放置」「占据」。
216
- - 说已设置状态、已有状态,不说「已放置」「有棋子」。
217
- - 说更新,不说「写入」「放置」「落子」。
218
- - 说未变更、已变更,不说「失败」「成功」。
219
- - 说「不进行覆盖」「不做修改」「保持不变」;「不进行覆盖」只出现在 `.cpp`。这些是本次调用的结果,不是能力边界,不要把它们扩成「不检查…」清单。
220
- - 「设置」只管有没有状态,「更新」只管这次动作,「已有状态」只管拒绝覆盖,三者不互换。
216
+ 判不准用词时开 `comment-terms.md`。它列「位置/坐标」「格子/棋盘」「更新/写入」「副本」「越界」与 `cell.h`/`cell.cpp` 这一组文件的用词;本文件不复制表。
@@ -75,7 +75,7 @@ Google 原文不使用 C++ 异常;本工作流只在开发阶段的源码指
75
75
  - 组合消息以 `std::format` 为主:`std::format("任务 {} 进入状态 {}", task, state)`。
76
76
  - `std::print` 只在 C++23 且标准库支持时使用,通常放在程序边界;库代码仍用 `std::format` 组合消息。C++20 及更早把格式化结果写到 `std::cout` / `std::cerr` / `std::ostringstream`。
77
77
  - 简单字面量输出可以直接用 `std::cout << "..."`;需要拼接变量、对齐、数值格式时用 `std::format`。
78
- - 列宽上限 80,每级缩进 2 个空格,代码不用 tab;这些都来自 Google 预设,不要在 `.clang-format` 里覆盖。
78
+ - 列宽跟工程根 `.clang-format` 的 `ColumnLimit` 走;项目已声明 100 时按 100,模板资产不写 `ColumnLimit`。每级缩进 2 个空格,代码不用 tab;缩进与对齐由 `.clang-format` 统一,不在条文里另定一套。
79
79
  - 浮点输出固定精度,整数不依赖隐式格式;`std::format` 的格式串写全。
80
80
 
81
81
  ## 注释
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  // 只读注释审计:按 references/comments.md 的硬规则检查 C/C++ 源文件。
3
3
  //
4
- // 检查项:Doxygen 文件头、注释行宽度、标签、注释与声明的贴合、
4
+ // 检查项:Doxygen 文件头、注释行宽度、标签、标签间空行、注释与声明的贴合、
5
5
  // 类型注释存在性、成员功能清单、设计论证(方案对比)、否定式边界、领域尺寸、谓词首句、@param 完整性、枚举成员注释一致性、枚举行尾句式、数据成员主注释位置。
6
6
  // 不重写任何文件。
7
7
  //
@@ -121,6 +121,20 @@ export function displayWidth(text) {
121
121
  return width
122
122
  }
123
123
 
124
+ /** 标签块开始后是否出现空行;描述与首个标签之间的空行不算。 */
125
+ function hasTagGap(contents) {
126
+ let seenTag = false
127
+ for (const content of contents) {
128
+ const trimmed = content.trim()
129
+ if (trimmed.startsWith('@')) {
130
+ seenTag = true
131
+ continue
132
+ }
133
+ if (seenTag && trimmed === '') return true
134
+ }
135
+ return false
136
+ }
137
+
124
138
  /** 取出顶层逗号分隔的参数段,忽略模板与括号内的逗号。 */
125
139
  function splitParams(text) {
126
140
  const parts = []
@@ -316,6 +330,9 @@ export function checkText(text, options = {}) {
316
330
  if (content.includes(tag)) add(doc.start + 1, 'forbidden-tag', `禁止使用 ${tag},按 references/comments.md 的标签表改写`)
317
331
  }
318
332
  }
333
+ if (!doc.contents.some((content) => content.includes('@file')) && hasTagGap(doc.contents)) {
334
+ add(doc.start + 1, 'tag-gap', 'Doxygen 标签之间有空行:描述与标签组之间空一行,标签之间不空行')
335
+ }
319
336
  index = doc.end
320
337
  }
321
338
  }
@@ -341,6 +358,10 @@ export function checkText(text, options = {}) {
341
358
  if (next >= lines.length) continue
342
359
  const declaration = lines[next].trim()
343
360
  const block = lines.slice(start, end + 1).join('\n')
361
+ const docContents = lines.slice(start, end + 1).map((line) => line.trim().replace(/^\/\/\/\s?/, ''))
362
+ if (hasTagGap(docContents)) {
363
+ add(start + 1, 'tag-gap', 'Doxygen 标签之间有空行:描述与标签组之间空一行,标签之间不空行')
364
+ }
344
365
  const isType = /^(template\s*<[^>]*>\s*)?(class|struct|union|enum)\b/.test(declaration)
345
366
  if (RATIONALE.test(block)) {
346
367
  add(start + 1, 'rationale', '注释在写设计取舍:方案对比与理由移到正文或实现注释,接口注释只留契约')
@@ -15,7 +15,7 @@
15
15
  - 头文件只就地定义约 10 行以内的短函数;模板与 `constexpr` 例外,其余函数体在 `.cpp`。
16
16
  - 失败是调用方的正常结果时,用结果类型、`bool` + 输出参数或 `std::optional` 表达;函数无法完成自己的任务、或构造函数无法建立不变量时才抛,异常类型的选择与消息见 `references/exceptions.md`。
17
17
  - 一次操作有多种必须区分的正常结果时用 `enum class` 返回(如落子:成功、越界、类型非法、已占),不用 `bool` 把原因压掉;成功还要附带数据时再考虑 `std::expected` 或结果结构。纯查询谓词仍用 `bool`。
18
- - 声明注释按 `references/comments.md` 的四节写:类型注释、特殊成员、函数注释、数据成员。本步只决定「写哪些事实」:结果、失败方式、检查项、参数与返回值契约;句式、标签、宽度和示例由该文件定。
18
+ - 声明注释按 `references/comments.md` 的四节写:类型注释、特殊成员、函数注释、数据成员。本步只决定「写哪些事实」:结果、失败方式、检查项、参数与返回值契约;句式、标签、宽度和示例由该文件定。判不准用词时再开 `references/comment-terms.md`,它只列词表,不重复句式。
19
19
  - 组合消息用 `std::format`;声明里只承诺 `std::format`,`std::print` 是 C++23 的程序边界设施。
20
20
 
21
21
  ## 情况