@chengzhao-dev/dsh-cpp-workflow 0.6.7 → 0.6.9
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 +3 -3
- package/README.md +4 -4
- package/lib/client.js +353 -287
- package/lib/comment-policy.js +81 -62
- package/lib/index.js +20 -14
- package/package.json +2 -2
- package/skills/building-cpp/SKILL.md +1 -1
- package/skills/configuring-cmake/SKILL.md +1 -1
- package/skills/developing-cpp/SKILL.md +2 -2
- package/skills/developing-cpp/examples/structure.md +1 -1
- package/skills/developing-cpp/references/comments.md +27 -6
- package/skills/developing-cpp/references/google-cpp-style.md +2 -2
- package/skills/developing-cpp/references/language.md +2 -1
- package/skills/developing-cpp/references/types.md +1 -1
- package/skills/developing-cpp/scripts/checking-comments.mjs +139 -17
- package/skills/developing-cpp/steps/03-declaration.md +1 -1
package/lib/comment-policy.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 注释标签策略:设置页的预览、技能快照与检查器参数共用这一份。
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* `skills/developing-cpp/references/comments.md`。设置页保存的值由宿主
|
|
4
|
+
* 配置只描述「写注释时默认带哪些标签、声明用哪种注释符号」,不描述写法本身;
|
|
5
|
+
* 写法在 `skills/developing-cpp/references/comments.md`。设置页保存的值由宿主
|
|
6
6
|
* 写回插件 Config,服务端 `apply(ctx, config)` 用它生成本页快照与检查器参数。
|
|
7
7
|
*
|
|
8
8
|
* 这份文件被 `tsc` 编进 `lib/comment-policy.js`,打包客户端半侧时再内联进
|
|
@@ -10,29 +10,16 @@
|
|
|
10
10
|
*/
|
|
11
11
|
/** 文件头标签。 */
|
|
12
12
|
export const HEADER_TAGS = ['brief', 'author', 'date', 'copyright', 'version'];
|
|
13
|
-
/**
|
|
13
|
+
/** 函数声明标签:开关决定是否要求写出。 */
|
|
14
14
|
export const CONTRACT_TAGS = ['param', 'returns', 'throws'];
|
|
15
|
-
/**
|
|
15
|
+
/** 函数声明里出厂开启的补充标签。 */
|
|
16
|
+
export const FUNCTION_EXTRA_TAGS = ['pre', 'post', 'retval'];
|
|
17
|
+
/** 类型标签:出厂开启,函数模板共用同一组键。 */
|
|
18
|
+
export const TYPE_TAGS = ['tparam', 'note', 'see'];
|
|
19
|
+
/** 全部可选标签,快照与测试按它排序。 */
|
|
16
20
|
export const EXTRA_TAGS = ['note', 'see', 'pre', 'post', 'tparam', 'retval'];
|
|
17
21
|
/** 只有用户主动填了非空值才放行的隐私标签。 */
|
|
18
22
|
export const PRIVACY_TAGS = ['author', 'date', 'copyright', 'version'];
|
|
19
|
-
/** 标签说明:设置页逐行显示,用作行的辅助文字。 */
|
|
20
|
-
export const TAG_TEXT = {
|
|
21
|
-
brief: '一句话说明这个文件定义或实现什么',
|
|
22
|
-
author: '只在用户填了非空值时写出',
|
|
23
|
-
date: '只在用户填了非空值时写出',
|
|
24
|
-
copyright: '只在用户填了非空值时写出',
|
|
25
|
-
version: '只在用户填了非空值时写出',
|
|
26
|
-
param: '函数参数的含义、范围或所有权',
|
|
27
|
-
returns: '返回值的条件;返回类型自明时可以省略',
|
|
28
|
-
throws: '抛出的异常类型与条件;不抛异常的函数不写',
|
|
29
|
-
note: '调用方需要注意的补充说明',
|
|
30
|
-
see: '相关函数、类型或文档',
|
|
31
|
-
pre: '调用前必须成立的条件',
|
|
32
|
-
post: '调用后保证成立的条件',
|
|
33
|
-
tparam: '模板参数',
|
|
34
|
-
retval: '特定返回值的含义',
|
|
35
|
-
};
|
|
36
23
|
/** 开关型标签在设置页的标题。 */
|
|
37
24
|
export const TAG_LABEL = {
|
|
38
25
|
file: '@file',
|
|
@@ -55,22 +42,25 @@ export const TAG_LABEL = {
|
|
|
55
42
|
export const SAMPLE_BRIEF = '<一句话说明本文件>';
|
|
56
43
|
/** 预览里的示例文件名:只是占位符,不对应任何工程的真实文件。 */
|
|
57
44
|
export const SAMPLE_FILE = '<文件名>';
|
|
58
|
-
/**
|
|
45
|
+
/**
|
|
46
|
+
* 出厂配置:声明用 `///`,除 @file 与函数体 // 外全部开启;空值仍不写文件头。
|
|
47
|
+
*/
|
|
59
48
|
export const DEFAULT_CONFIG = {
|
|
49
|
+
commentStyle: 'slash',
|
|
60
50
|
brief: { enabled: true, value: '' },
|
|
61
|
-
author: { enabled:
|
|
62
|
-
date: { enabled:
|
|
63
|
-
copyright: { enabled:
|
|
64
|
-
version: { enabled:
|
|
51
|
+
author: { enabled: true, value: '' },
|
|
52
|
+
date: { enabled: true, value: '' },
|
|
53
|
+
copyright: { enabled: true, value: '' },
|
|
54
|
+
version: { enabled: true, value: '' },
|
|
65
55
|
param: true,
|
|
66
56
|
returns: true,
|
|
67
57
|
throws: true,
|
|
68
|
-
note:
|
|
69
|
-
see:
|
|
70
|
-
pre:
|
|
71
|
-
post:
|
|
72
|
-
tparam:
|
|
73
|
-
retval:
|
|
58
|
+
note: true,
|
|
59
|
+
see: true,
|
|
60
|
+
pre: true,
|
|
61
|
+
post: true,
|
|
62
|
+
tparam: true,
|
|
63
|
+
retval: true,
|
|
74
64
|
};
|
|
75
65
|
/**
|
|
76
66
|
* 宿主把 volatile 字段交给插件时给的是可读写单元(`.get()`),设置页快照给的是普通值;
|
|
@@ -92,12 +82,16 @@ function flag(value, fallback) {
|
|
|
92
82
|
const plain = unwrap(value);
|
|
93
83
|
return typeof plain === 'boolean' ? plain : fallback;
|
|
94
84
|
}
|
|
85
|
+
/** 声明符号只认两档;未知值回到 `///`。 */
|
|
86
|
+
export function commentStyleOf(raw) {
|
|
87
|
+
return unwrap(raw) === 'block' ? 'block' : 'slash';
|
|
88
|
+
}
|
|
95
89
|
/**
|
|
96
90
|
* 把宿主给的值补齐成完整配置;缺字段、旧版本或手工改坏的配置都回到出厂值。
|
|
97
91
|
*/
|
|
98
92
|
export function normalizeConfig(raw) {
|
|
99
93
|
const source = raw && typeof raw === 'object' ? raw : {};
|
|
100
|
-
const config = {};
|
|
94
|
+
const config = { commentStyle: commentStyleOf(source.commentStyle) };
|
|
101
95
|
for (const tag of HEADER_TAGS) {
|
|
102
96
|
const entry = source[tag] && typeof source[tag] === 'object' ? source[tag] : {};
|
|
103
97
|
config[tag] = {
|
|
@@ -110,59 +104,85 @@ export function normalizeConfig(raw) {
|
|
|
110
104
|
}
|
|
111
105
|
return config;
|
|
112
106
|
}
|
|
107
|
+
/** 一行声明注释:`/// 内容` 或块注释里的 ` * 内容`。 */
|
|
108
|
+
function declarationLine(style, content) {
|
|
109
|
+
return style === 'block' ? ` * ${content}` : `/// ${content}`;
|
|
110
|
+
}
|
|
111
|
+
/** 文件头后面的说明行:块注释里空行写成 ` *`。 */
|
|
112
|
+
function separatorLine(style) {
|
|
113
|
+
return style === 'block' ? ' *' : '///';
|
|
114
|
+
}
|
|
113
115
|
/**
|
|
114
|
-
* 按配置渲染文件头;`@file`
|
|
116
|
+
* 按配置渲染文件头;`@file` 始终是传入的文件名,块注释按 Doxygen 结构分行。
|
|
115
117
|
*/
|
|
116
118
|
export function renderFileHeader(raw, fileName) {
|
|
117
119
|
const config = normalizeConfig(raw);
|
|
118
120
|
const name = text(fileName) || SAMPLE_FILE;
|
|
119
|
-
const lines = [
|
|
121
|
+
const lines = [`@file ${name}`];
|
|
120
122
|
if (config.brief.enabled) {
|
|
121
|
-
lines.push(config.brief.value ?
|
|
123
|
+
lines.push(config.brief.value ? `@brief ${config.brief.value}` : '@brief');
|
|
122
124
|
}
|
|
123
125
|
for (const tag of ['author', 'date', 'copyright', 'version']) {
|
|
124
126
|
if (config[tag].enabled && config[tag].value)
|
|
125
|
-
lines.push(
|
|
127
|
+
lines.push(`@${tag} ${config[tag].value}`);
|
|
128
|
+
}
|
|
129
|
+
if (config.commentStyle === 'block') {
|
|
130
|
+
return ['/**', ...lines.map((line) => ` * ${line}`), ' */'];
|
|
126
131
|
}
|
|
127
|
-
return lines;
|
|
132
|
+
return lines.map((line) => `/// ${line}`);
|
|
128
133
|
}
|
|
129
134
|
/**
|
|
130
135
|
* 设置页的预览:文件头 + 一段函数注释,只显示当前配置会写出的标签。
|
|
136
|
+
* 返回值里的 `header` 已按声明符号排好,`contract` 是每行标签的正文。
|
|
131
137
|
*/
|
|
132
138
|
export function previewParts(raw, sampleName) {
|
|
133
139
|
const config = normalizeConfig(raw);
|
|
134
140
|
const header = renderFileHeader(config, sampleName || SAMPLE_FILE);
|
|
135
141
|
// 预览是示例:@brief 开着但用户没填句子时,用示例文件自己的摘要顶替。
|
|
136
|
-
const briefIndex = header.
|
|
137
|
-
if (briefIndex !== -1)
|
|
138
|
-
header[briefIndex] =
|
|
142
|
+
const briefIndex = header.findIndex((line) => /@brief$/.test(line.trim()));
|
|
143
|
+
if (briefIndex !== -1) {
|
|
144
|
+
header[briefIndex] = header[briefIndex].replace(/@brief$/, `@brief ${SAMPLE_BRIEF}`);
|
|
145
|
+
}
|
|
139
146
|
const contract = [];
|
|
140
147
|
if (config.param)
|
|
141
|
-
contract.push('
|
|
148
|
+
contract.push('@param row 目标行号。');
|
|
142
149
|
if (config.returns)
|
|
143
|
-
contract.push('
|
|
150
|
+
contract.push('@return 放置成功时为 true。');
|
|
144
151
|
if (config.throws)
|
|
145
|
-
contract.push('
|
|
146
|
-
|
|
147
|
-
return { header, contract, declaration };
|
|
152
|
+
contract.push('@throws std::out_of_range 行号越界时抛出。');
|
|
153
|
+
return { header, contract, declaration: '[[nodiscard]] bool Place(int row, int column);' };
|
|
148
154
|
}
|
|
149
155
|
/**
|
|
150
156
|
* 设置页预览的纯文本形式;客户端半侧用同一份实现渲染 `<pre>`。
|
|
157
|
+
* 块注释的每个内容行前加 ` * `,首尾各占一行。
|
|
151
158
|
*/
|
|
152
159
|
export function previewText(raw, sampleName) {
|
|
153
|
-
const
|
|
154
|
-
const
|
|
160
|
+
const config = normalizeConfig(raw);
|
|
161
|
+
const { header, contract, declaration } = previewParts(config, sampleName);
|
|
162
|
+
const style = config.commentStyle;
|
|
163
|
+
const summary = '放置成功时返回 true;行号越界或目标格子已占时返回 false。';
|
|
164
|
+
if (style === 'block') {
|
|
165
|
+
const body = [declarationLine(style, summary)];
|
|
166
|
+
if (contract.length > 0) {
|
|
167
|
+
body.push(separatorLine(style), ...contract.map((line) => declarationLine(style, line)));
|
|
168
|
+
}
|
|
169
|
+
return [...header, '/**', ...body, ' */', declaration].join('\n');
|
|
170
|
+
}
|
|
171
|
+
const lines = [...header, separatorLine(style), declarationLine(style, summary)];
|
|
155
172
|
if (contract.length > 0)
|
|
156
|
-
lines.push(
|
|
173
|
+
lines.push(separatorLine(style), ...contract.map((line) => declarationLine(style, line)));
|
|
157
174
|
lines.push(declaration);
|
|
158
175
|
return lines.join('\n');
|
|
159
176
|
}
|
|
160
177
|
/**
|
|
161
|
-
* 检查器参数:隐私标签要显式放行,@brief
|
|
178
|
+
* 检查器参数:隐私标签要显式放行,@brief 被关掉时跳过摘要检查,
|
|
179
|
+
* 声明符号切到块注释时让检查器按块注释收口。
|
|
162
180
|
*/
|
|
163
181
|
export function checkerArgs(raw) {
|
|
164
182
|
const config = normalizeConfig(raw);
|
|
165
183
|
const args = [];
|
|
184
|
+
if (config.commentStyle === 'block')
|
|
185
|
+
args.push('--comment-style', 'block');
|
|
166
186
|
if (!config.brief.enabled)
|
|
167
187
|
args.push('--no-brief');
|
|
168
188
|
for (const tag of PRIVACY_TAGS) {
|
|
@@ -173,10 +193,11 @@ export function checkerArgs(raw) {
|
|
|
173
193
|
}
|
|
174
194
|
/**
|
|
175
195
|
* 技能快照:`get()` 把它接在技能正文末尾,让代理看到当前 profile 的标签开关。
|
|
196
|
+
* 只写一行,列出声明符号、开启与关闭的标签,避免正文膨胀。
|
|
176
197
|
*/
|
|
177
198
|
export function snapshotText(raw) {
|
|
178
199
|
const config = normalizeConfig(raw);
|
|
179
|
-
const on = [];
|
|
200
|
+
const on = ['@file'];
|
|
180
201
|
const off = [];
|
|
181
202
|
for (const tag of HEADER_TAGS) {
|
|
182
203
|
const entry = config[tag];
|
|
@@ -186,15 +207,13 @@ export function snapshotText(raw) {
|
|
|
186
207
|
else
|
|
187
208
|
off.push(TAG_LABEL[tag]);
|
|
188
209
|
}
|
|
189
|
-
const
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
];
|
|
199
|
-
return head + body.join('\n');
|
|
210
|
+
for (const tag of [...CONTRACT_TAGS, ...EXTRA_TAGS]) {
|
|
211
|
+
if (config[tag])
|
|
212
|
+
on.push(TAG_LABEL[tag]);
|
|
213
|
+
else
|
|
214
|
+
off.push(TAG_LABEL[tag]);
|
|
215
|
+
}
|
|
216
|
+
const style = config.commentStyle === 'block' ? '/** ... */' : '///';
|
|
217
|
+
const line = `- 声明符号:${style}(函数体固定 //);开启 ${on.join('、')};关闭 ${off.join('、') || '无'}。`;
|
|
218
|
+
return `## 当前注释配置(profile)\n\n${line}`;
|
|
200
219
|
}
|
package/lib/index.js
CHANGED
|
@@ -27,28 +27,34 @@ import { normalizeConfig, snapshotText } from './comment-policy.js';
|
|
|
27
27
|
export const name = 'dsh-cpp-workflow';
|
|
28
28
|
export const inject = ['skills'];
|
|
29
29
|
// 设置页保存的标签开关;字段即时生效,改配置不必重装插件。
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
// 每个文件头标签各建一个对象:四个标签共用一个 Schema 实例时,volatile 叶子会撞在同一条路径上,
|
|
31
|
+
// 保存 @author 会被宿主拒绝或写到别的标签。
|
|
32
|
+
function headerTag() {
|
|
33
|
+
return Schema.object({
|
|
34
|
+
enabled: Schema.boolean().default(true).volatile(),
|
|
35
|
+
value: Schema.string().default('').volatile(),
|
|
36
|
+
});
|
|
37
|
+
}
|
|
34
38
|
export const Config = Schema.object({
|
|
39
|
+
// 声明注释符号:`///` 或 Doxygen 块注释;缺省值由 comment-policy 兜底。
|
|
40
|
+
commentStyle: Schema.string().default('slash').volatile(),
|
|
35
41
|
brief: Schema.object({
|
|
36
42
|
enabled: Schema.boolean().default(true).volatile(),
|
|
37
43
|
value: Schema.string().default('').volatile(),
|
|
38
44
|
}),
|
|
39
|
-
author:
|
|
40
|
-
date:
|
|
41
|
-
copyright:
|
|
42
|
-
version:
|
|
45
|
+
author: headerTag(),
|
|
46
|
+
date: headerTag(),
|
|
47
|
+
copyright: headerTag(),
|
|
48
|
+
version: headerTag(),
|
|
43
49
|
param: Schema.boolean().default(true).volatile(),
|
|
44
50
|
returns: Schema.boolean().default(true).volatile(),
|
|
45
51
|
throws: Schema.boolean().default(true).volatile(),
|
|
46
|
-
note: Schema.boolean().default(
|
|
47
|
-
see: Schema.boolean().default(
|
|
48
|
-
pre: Schema.boolean().default(
|
|
49
|
-
post: Schema.boolean().default(
|
|
50
|
-
tparam: Schema.boolean().default(
|
|
51
|
-
retval: Schema.boolean().default(
|
|
52
|
+
note: Schema.boolean().default(true).volatile(),
|
|
53
|
+
see: Schema.boolean().default(true).volatile(),
|
|
54
|
+
pre: Schema.boolean().default(true).volatile(),
|
|
55
|
+
post: Schema.boolean().default(true).volatile(),
|
|
56
|
+
tparam: Schema.boolean().default(true).volatile(),
|
|
57
|
+
retval: Schema.boolean().default(true).volatile(),
|
|
52
58
|
});
|
|
53
59
|
const PROVIDER = 'dsh-cpp-workflow';
|
|
54
60
|
const RANK = 550;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chengzhao-dev/dsh-cpp-workflow",
|
|
3
|
-
"version": "0.6.
|
|
4
|
-
"description": "写 C++ 源码、配 CMake、用 Clang 构建;头文件用 /// Doxygen 文档注释,函数体用 // 分段说明,文件头标签可在设置里改。
|
|
3
|
+
"version": "0.6.9",
|
|
4
|
+
"description": "写 C++ 源码、配 CMake、用 Clang 构建;头文件用 /// Doxygen 文档注释,函数体用 // 分段说明,文件头标签可在设置里改。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
7
7
|
"exports": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: building-cpp
|
|
3
|
-
description:
|
|
3
|
+
description: 在已写好 CMake 的 C++11–C++23 工程上配置、构建和检查时使用:Ninja、compile_commands.json、clang-format、clang-tidy、clangd、environment.json 与 running-build.sh。不用于只改源码语义、文档、Python 或与 C++ 无关的文件。
|
|
4
4
|
metadata:
|
|
5
5
|
short-description: C++11–C++23 构建三步
|
|
6
6
|
---
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: configuring-cmake
|
|
3
|
-
description:
|
|
3
|
+
description: 编写或重构 C++11–C++23 工程的 CMake 时使用:CMakeLists.txt、cmake 模块、target 属性、依赖与输出目录、语言标准;新工程默认 C++23。不用于 Quarto、Python 或非 C++ 文档。
|
|
4
4
|
metadata:
|
|
5
5
|
short-description: CMake 配置三步
|
|
6
6
|
---
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: developing-cpp
|
|
3
|
-
description: 编写或修改 C++11–C++23
|
|
3
|
+
description: 编写或修改 C++11–C++23 源码、头文件、命名、异常与源码注释时使用,新工程默认 C++23;一次改动同时碰到源码和构建文件时先打开本技能。不用于只改文档、Python、CMake、构建脚本或与 C++ 无关的文件。
|
|
4
4
|
metadata:
|
|
5
5
|
short-description: C++11–C++23 源码四步
|
|
6
6
|
---
|
|
@@ -22,7 +22,7 @@ metadata:
|
|
|
22
22
|
| 增量修正 | 用户点了一个函数、一条诊断或一个文件 | 沿本技能步骤走,只改判为不合格的那一处,其余保持原样 |
|
|
23
23
|
| 整段重构 | 新工程、新阶段、用户没点名范围,或改动跨过库与程序的边界 | 同样四步;第 1、2 步先定删留,不动函数体;第 3、4 步才改代码 |
|
|
24
24
|
|
|
25
|
-
两种走法共用这些约束:不发明阶段表和用户请求里没有的行为、类型和命令;选类型与写法时以项目声明的语言标准为上限;只改注释或格式时不改可观察行为;不覆盖已有源码;不安装工具链;代理侧不写 `wsl` 或 `bash -lc
|
|
25
|
+
两种走法共用这些约束:不发明阶段表和用户请求里没有的行为、类型和命令;选类型与写法时以项目声明的语言标准为上限;只改注释或格式时不改可观察行为;不覆盖已有源码;不安装工具链;代理侧不写 `wsl` 或 `bash -lc`。计划、命名方案或注释措辞与条文、项目技能或用户明确要求冲突时,先列冲突位置、原文与出处,由用户选一条;不自行取舍,也不默认采用计划。后一步发现前一步没做完,退回那一步,不在当前步补结构。拿不准先用增量修正;做到一半发现边界被打破,退回整段重构,从被打破的那一步重走。
|
|
26
26
|
|
|
27
27
|
## 步骤
|
|
28
28
|
|
|
@@ -99,7 +99,7 @@ std::vector<std::vector<CellPosition>> BuildLines() {
|
|
|
99
99
|
|
|
100
100
|
```cpp
|
|
101
101
|
// board.cpp 的 namespace tictactoe:行、列、对角线三组,坐标固定。
|
|
102
|
-
constexpr std::array<std::array<CellPosition, 3>, 8> kLines{{
|
|
102
|
+
constexpr std::array<std::array<CellPosition, 3>, 8> kLines = {{
|
|
103
103
|
{{{0, 0}, {0, 1}, {0, 2}}}, // 行 0
|
|
104
104
|
{{{1, 0}, {1, 1}, {1, 2}}}, // 行 1
|
|
105
105
|
{{{2, 0}, {2, 1}, {2, 2}}}, // 行 2
|
|
@@ -32,7 +32,7 @@ class Board {
|
|
|
32
32
|
- 不写尚未发生的用法、方案对比与取舍论证、广告句。
|
|
33
33
|
- 纯数据结构不写「只保存…,不拥有…,不含…」这类否定式边界;这些由成员类型和所有权表达。
|
|
34
34
|
- 领域尺寸不写进类型注释:格子数由 `cells_` 的声明表达,棋盘边长由 `kBoardRows`、`kBoardCols` 表达。
|
|
35
|
-
-
|
|
35
|
+
- 枚举与只承载数据的结构体:第一句是名词短语,写这个取值表示什么;行尾 `///<` 的两种句式见「枚举项与 `struct` 短字段:两种句式」。
|
|
36
36
|
|
|
37
37
|
### 构造函数与析构函数:先写标签,再写职责
|
|
38
38
|
|
|
@@ -62,12 +62,21 @@ GameResult result_ = GameResult::kInProgress;
|
|
|
62
62
|
|
|
63
63
|
`board_` 这类名字已经说明存放对象的成员不写「对局棋盘」;`cells_` 不写「存储…」这种把声明读一遍的句子,但上一行要先说它是棋盘格子数组,再补轴向、哨兵和改写次序。`clang-format` 不会把行尾注释搬到上一行,位置由本规则和检查器保证。
|
|
64
64
|
|
|
65
|
+
### 枚举项与 `struct` 短字段:两种句式
|
|
66
|
+
|
|
67
|
+
枚举项与只承载数据的 `struct` 短字段用行尾 `///<`,同一枚举各行的 `///<` 对齐。只写两种句式:
|
|
68
|
+
|
|
69
|
+
- 语义本身已经完整:`///< 空格子。`
|
|
70
|
+
- 语义之外还要补一条能核实的条件或结果:`///< 非法参数:传入空棋盘格子类型。`
|
|
71
|
+
|
|
72
|
+
冒号用全角 `:`;冒号前写类别,冒号后写说明,两侧都不能为空。禁止空冒号(`///< 落子成功:。`)、禁止用逗号把类别和说明连起来(`///< 传入空棋盘格子类型,非法参数。`)、禁止把说明写在类别前面。同一枚举要么每一项都写 `///<`,要么都不写;都写时两种句式可以混用。
|
|
73
|
+
|
|
65
74
|
### 函数:两段式契约
|
|
66
75
|
|
|
67
76
|
有参数或有返回值的函数写两段:第一段写结果、失败方式或检查项;第二段按签名把标签写齐。
|
|
68
77
|
|
|
69
78
|
1. 第一段:普通函数写正常返回什么、失败时返回什么或抛什么;布尔查询与 `operator==` 写「检查…是否…」。
|
|
70
|
-
2. 第二段:每个参数一条 `@param`;有返回值默认写 `@return`,成立条件已由函数名与返回类型说清时可省略;会抛才写 `@throws
|
|
79
|
+
2. 第二段:每个参数一条 `@param`;有返回值默认写 `@return`,成立条件已由函数名与返回类型说清时可省略;会抛才写 `@throws`;`@pre`、`@post`、`@retval`、`@tparam`、`@note`、`@see` 出厂开关打开;只在确有需要时写,不需要可在设置里关掉。
|
|
71
80
|
|
|
72
81
|
```cpp
|
|
73
82
|
/// 检查坐标能否落子,不修改棋盘。
|
|
@@ -122,18 +131,18 @@ GameResult result_ = GameResult::kInProgress;
|
|
|
122
131
|
|
|
123
132
|
## 布局:放在哪一层、哪一行
|
|
124
133
|
|
|
125
|
-
-
|
|
134
|
+
- 文件头与声明注释用设置里选定的符号(默认 `///`,也可 `/** ... */`):头文件里的类型、函数声明、枚举项、公开与私有数据成员,以及文件头的 `@file`/`@brief` 块。调用方和 Doxygen 从这里取契约。
|
|
126
135
|
- `///<` 只给枚举项和 `struct` 短字段的行尾;不要写在赋值、`break` 或普通语句后面。
|
|
127
136
|
- `//` 给函数体内的阶段说明、局部变量、守卫理由和普通语句行尾;这些注释不接 Doxygen 文档。
|
|
128
137
|
- `//` 也给工具指令与别种文件:`// NOLINTNEXTLINE(...)`、`#endif // MACRO`,以及 CMake、YAML 等非 C++ 文件。
|
|
129
|
-
-
|
|
138
|
+
- 判断看位置:声明写契约,用选定的文档符号;实现写理由,用 `//`。
|
|
130
139
|
- 位置固定:文件头在最上方;类型注释紧贴类型声明;特殊成员(构造、析构、拷贝与移动)排在其他函数之前;函数注释紧贴函数声明;数据成员的主注释紧贴声明上一行,不写行尾补充。
|
|
131
140
|
- 类数据成员(含私有)的主注释用 `///`;行尾 `///<` 只给枚举项和 `struct` 的短字段。
|
|
132
141
|
- 注释和它说明的声明之间不留空行;同一个声明块内,空行只用来分组。
|
|
133
142
|
|
|
134
143
|
### 文件头
|
|
135
144
|
|
|
136
|
-
每个手写源文件开头写一段 doxygen
|
|
145
|
+
每个手写源文件开头写一段 doxygen 文件头:第一行写 `@file <文件名>`,第二行写 `@brief` 一句话说明这个文件定义或实现什么,用一行空注释隔开后,只写本文件自己的组成部分或边界。`@file` 的参数必须与文件名逐字相同,检查器会核对。`@brief` 始终写出;`@author`、`@date`、`@copyright`、`@version` 的开关出厂打开,只有填了非空值才写出,空值整条省略;作者、年份和变更史按团队约定填写,不填就不出现在源码里。删掉把读者指去另一个头文件、另一个目录或另一层的句子,也删掉「这一层不负责什么」。不写作者、版权年份、变更日志和外部资料路径。
|
|
137
146
|
|
|
138
147
|
```cpp
|
|
139
148
|
/// @file board.h
|
|
@@ -142,12 +151,24 @@ GameResult result_ = GameResult::kInProgress;
|
|
|
142
151
|
/// 棋盘保存九个棋盘格子的状态,提供查询、落子与清空棋盘。
|
|
143
152
|
```
|
|
144
153
|
|
|
154
|
+
选择块注释时,同一段写成:
|
|
155
|
+
|
|
156
|
+
```cpp
|
|
157
|
+
/**
|
|
158
|
+
* @file board.h
|
|
159
|
+
* @brief 定义井字棋棋盘、格子坐标与格子类型。
|
|
160
|
+
*
|
|
161
|
+
* 棋盘保存九个棋盘格子的状态,提供查询、落子与清空棋盘。
|
|
162
|
+
*/
|
|
163
|
+
```
|
|
164
|
+
|
|
145
165
|
- C++ 源文件用以上格式;CMake 用 `#`,YAML/JSON 用 `#`。
|
|
146
166
|
- 超过约 200 行的文件用空行分成几节,每节的说明写在一行 `///` 上,不画装饰线。
|
|
147
167
|
- 文件头 3–7 行;`@file` 与 `@brief` 各占一行,后面只写本文件的范围与组成,不写实现步骤、作者和变更史。
|
|
148
168
|
|
|
149
169
|
## 排版:符号、宽度与标签
|
|
150
170
|
|
|
171
|
+
- 注释符号在插件设置里选择:`///` 是默认写法,`/** ... */` 是另一种 Doxygen 写法;文件头与声明注释统一用同一种,函数体内仍只用 `//`。块注释每行以 ` * ` 对齐,收尾单独一行 ` */`。
|
|
151
172
|
- 行宽跟项目 `.clang-format` 的 `ColumnLimit` 走(Google 基线是 80 列,中文按两列计)。
|
|
152
173
|
- 行尾注释与代码之间空两格;`///<` 只接在枚举项和 `struct` 短字段声明行尾。
|
|
153
174
|
- `@param`、`@return`、`@throws` 标签保持英文;`@param` 后先写参数名,再写一句。
|
|
@@ -155,7 +176,7 @@ GameResult result_ = GameResult::kInProgress;
|
|
|
155
176
|
- `.clang-format`、`.clang-tidy`、`.clangd`、CMake 的配置项旁边写「为什么这样设」,不写「这一项是什么」;配置注释贴在被解释的键上方。
|
|
156
177
|
- 禁止:大段表格、装饰图案、表情;外部资料路径、跨仓库引用、团队流程;注释掉的代码;注释元叙述(「其余内容见某处」「两处不重复」)。
|
|
157
178
|
- `///` 与 `@param` 不进入 `.qmd`、YAML、CSS。
|
|
158
|
-
- 函数体内不写
|
|
179
|
+
- 函数体内不写 `///` 或 `/** ... */`;`//` 用于实现说明与 `// NOLINTNEXTLINE(...)` 这类工具指令。
|
|
159
180
|
|
|
160
181
|
## 润色:删复述,统一句式
|
|
161
182
|
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
- 纯数据聚合用 `struct`;有不变量的类型用 `class`,不变量在构造函数和公共成员函数里维持。
|
|
52
52
|
- 单参数构造函数写 `explicit`;零参数构造函数不写。
|
|
53
53
|
- 默认成员初始化写在声明处(NSDMI),不要在构造函数初始化列表里重复。
|
|
54
|
-
- 默认用花括号初始化:`int count{};`、`std::vector<int> values{1, 2, 3};`。只有需要对比、`auto` 推导或赋值语义时用
|
|
54
|
+
- 默认用花括号初始化:`int count{};`、`std::vector<int> values{1, 2, 3};`。只有需要对比、`auto` 推导或赋值语义时用 `=`;`name = {{` 只用于多行聚合常量表,单个对象和空初始化仍写 `count{}`;不要用 `()` 初始化普通对象。
|
|
55
55
|
- 类声明顺序:public → protected → private;类型与别名 → 静态常量 → 工厂 → 构造/赋值/析构 → 其他函数 → 数据成员。
|
|
56
56
|
- 用户声明的拷贝/移动/析构函数在头文件声明、在 `.cpp` 定义;只有零参数且默认实现足够时才写 `= default`。
|
|
57
57
|
- 查询成员函数标尾部 `const`;返回结果对象的 API 加 `[[nodiscard]]`,不要给所有非 `void` 函数机械添加。
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
- 混合优先级算术加显式括号,消除 `readability-math-missing-parentheses`。
|
|
78
78
|
- 内建整数默认用 `int`;需要确定宽度时用 `<cstdint>` 的 `std::int32_t`、`std::int64_t` 等(可省略 `std::` 前缀),可能到 2^31 的值用 64 位;`std::size_t` / `std::ptrdiff_t` 只用于大小和指针差。不要用无符号类型表达「这个值不会为负」。
|
|
79
79
|
- 封闭状态码用 `enum class`;底层类型默认 `int`,只有确实需要缩小存储时才写固定底层类型并说明理由。枚举值总是带作用域:`OrderResult::kSuccess`。
|
|
80
|
-
-
|
|
80
|
+
- 枚举的尾随注释要么全写要么全不写;两种句式与禁止项见 `references/comments.md`「枚举项与 `struct` 短字段:两种句式」。
|
|
81
81
|
- 浮点不用 `==` 比较计算结果;按量纲给容差,金额用最小货币单位的整数。
|
|
82
82
|
- 数值宽度、符号、枚举、强类型、`const` 成员和下标访问的完整规则见 `references/types.md`;初始化、RAII、移动和模板见 `references/language.md`。
|
|
83
83
|
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
## 初始化与列表初始化
|
|
14
14
|
|
|
15
|
-
默认用花括号初始化,只在需要对比、`auto` 推导或赋值语义时用
|
|
15
|
+
默认用花括号初始化,只在需要对比、`auto` 推导或赋值语义时用 `=`;`name = {{` 只用于多行聚合常量表:
|
|
16
16
|
|
|
17
17
|
```cpp
|
|
18
18
|
int count{}; // 值初始化,0
|
|
@@ -21,6 +21,7 @@ std::string name = "demo"; // 拷贝初始化,类型明确
|
|
|
21
21
|
auto total = 0.0; // auto 只能用 =,不能用 {}
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
+
- `kLines` 这类多行聚合常量表写 `name = {{`;单个对象和空初始化仍写 `count{}`,不写 `=`;不把其他花括号初始化改成 `=`。
|
|
24
25
|
- `T value{}` 做值初始化:内置类型得 0,类类型调用默认构造函数。
|
|
25
26
|
- 花括号禁止窄化转换:`int x{3.5}` 编译失败,`int x = 3.5` 静默截断。需要截断时显式 `static_cast<int>(3.5)`。
|
|
26
27
|
- `std::vector<int> values(3)` 是三个 0;`values{3}` 是一个元素 3。两种括号语义不同,不要凭习惯混用。
|
|
@@ -68,7 +68,7 @@ std::array<TaskState, kItemCount> items_{};
|
|
|
68
68
|
|
|
69
69
|
- 新代码用 `enum class`;unscoped `enum` 只用于兼容 C 接口,不作为默认写法。
|
|
70
70
|
- 封闭状态码默认写 `: std::uint8_t`;普通枚举用默认底层类型。
|
|
71
|
-
-
|
|
71
|
+
- 枚举值的行尾注释要么全写要么全不写;两种句式与禁止项见 `references/comments.md`「枚举项与 `struct` 短字段:两种句式」。
|
|
72
72
|
- 需要“编号”与“名字”两套表示时,写显式映射函数,例如 `TaskStateToName` / `TaskStateFromName`,不要在枚举和整数之间来回隐式转换。
|
|
73
73
|
|
|
74
74
|
## 强类型包装
|