实战:注释与符号工具插件
把前两章学到的 API 综合运用,实现一个「注释 + 符号统计」工具插件:给代码加规范注释、统计文件中的函数/类符号数量、状态栏实时显示结果。
目标
实现一个注释与符号工具插件:
- 命令面板快速插入多种格式注释(块注释/文档注释/分隔注释)
- 统计当前文件符号数量(函数、类、变量)
- 状态栏实时显示统计结果
第一步:声明命令
package.json 中声明命令:
json
{
"contributes": {
"commands": [
{
"command": "symbolTools.addComment",
"title": "插入代码注释",
"category": "符号工具"
},
{
"command": "symbolTools.statFile",
"title": "统计文件符号",
"category": "符号工具"
}
]
}
}第二步:插入注释命令
src/extension.ts 中实现注释插入,用 QuickPick 选择注释类型:
typescript
import * as vscode from 'vscode';
export function activate(context: vscode.ExtensionContext) {
// 状态栏项:显示统计结果
const statusBar = vscode.window.createStatusBarItem(
vscode.StatusBarAlignment.Right,
90
);
statusBar.text = '$(symbol-namespace) 待统计';
statusBar.show();
context.subscriptions.push(statusBar);
// 命令一:插入代码注释
context.subscriptions.push(
vscode.commands.registerCommand(
'symbolTools.addComment',
async () => {
const editor = vscode.window.activeTextEditor;
if (!editor) {
vscode.window.showWarningMessage('请先打开文件');
return;
}
const document = editor.document;
const languageId = document.languageId;
// 根据语言选择注释符号
const commentMark = isCStyleLanguage(languageId) ? '//' : '#';
// QuickPick 选择注释类型
const type = await vscode.window.showQuickPick(
[
{
label: '$(comment) 块注释',
description: '代码块说明注释',
value: 'block'
},
{
label: '$(symbol-method) 函数注释',
description: '函数/方法文档注释',
value: 'function'
},
{
label: '$(paintcan) 分隔注释',
description: '区块分隔线',
value: 'separator'
}
],
{ title: '选择注释类型' }
);
if (!type) {
return;
}
// 输入注释内容
const content = await vscode.window.showInputBox({
title: '注释内容',
placeHolder: '请输入注释内容',
validateInput: (text) =>
text.trim() ? undefined : '内容不能为空'
});
if (!content) {
return;
}
const line = editor.selection.active.line;
const text = buildComment(type.value, content, commentMark);
await editor.edit((builder) => {
builder.insert(
new vscode.Position(line, 0),
text
);
});
vscode.window.showInformationMessage('注释已插入');
}
)
);
// 命令二:统计文件符号
context.subscriptions.push(
vscode.commands.registerCommand(
'symbolTools.statFile',
async () => {
const editor = vscode.window.activeTextEditor;
if (!editor) {
return;
}
const stats = analyzeSymbols(editor.document);
statusBar.text = `$(symbol-namespace) 函数 ${stats.functions} | 类 ${stats.classes}`;
const picked = await vscode.window.showQuickPick(
[
{ label: `函数数量: ${stats.functions}` },
{ label: `类数量: ${stats.classes}` },
{ label: `总行数: ${stats.lines}` },
{ label: `注释行: ${stats.comments}` }
],
{ title: '文件符号统计' }
);
}
)
);
}第三步:辅助函数
typescript
// 判断是否是 C 系语言(// 注释)
function isCStyleLanguage(languageId: string): boolean {
return [
'typescript', 'javascript', 'java', 'c', 'cpp',
'csharp', 'go', 'rust', 'php', 'swift'
].includes(languageId);
}
// 构建注释文本
function buildComment(
type: string,
content: string,
commentMark: string
): string {
switch (type) {
case 'block':
return `${commentMark} ===============\n` +
`${commentMark} ${content}\n` +
`${commentMark} ===============\n`;
case 'function':
return `${commentMark} ---------------------------------\n` +
`${commentMark} 函数: ${content}\n` +
`${commentMark} 说明: 待补充\n` +
`${commentMark} ---------------------------------\n`;
case 'separator':
return `${commentMark} ---------- ${content} ----------\n`;
default:
return `${commentMark} ${content}\n`;
}
}
// 统计符号
function analyzeSymbols(document: vscode.TextDocument) {
const text = document.getText();
const lines = document.lineCount;
// 简单统计(生产可用正则更精确)
const functions = (text.match(/function\s+\w+/g) || []).length;
const classes = (text.match(/class\s+\w+/g) || []).length;
// 统计注释行
let comments = 0;
for (let i = 0; i < lines; i++) {
const lineText = document.lineAt(i).text.trim();
if (lineText.startsWith('//') || lineText.startsWith('#')) {
comments++;
}
}
return { functions, classes, lines, comments };
}第四步:配置自定义注释格式
在 package.json 中增加配置,让用户自定义注释样式:
json
{
"contributes": {
"configuration": {
"title": "符号工具",
"properties": {
"symbolTools.separatorChar": {
"type": "string",
"default": "-",
"description": "分隔注释使用的字符"
},
"symbolTools.separatorLength": {
"type": "number",
"default": 12,
"description": "分隔注释的长度"
}
}
}
}
}在代码中读取配置:
typescript
function getSeparator(): string {
const config = vscode.workspace.getConfiguration('symbolTools');
const char = config.get('separatorChar', '-');
const length = config.get('separatorLength', 12);
return char.repeat(length);
}第五步:监听配置变更
typescript
context.subscriptions.push(
vscode.workspace.onDidChangeConfiguration((event) => {
if (event.affectsConfiguration('symbolTools')) {
statusBar.text = '$(gear) 配置已更新';
setTimeout(() => {
statusBar.text = '$(symbol-namespace) 待统计';
}, 2000);
}
})
);运行与验证
按 F5 启动调试,验证:
| 步骤 | 操作 | 预期 |
|---|---|---|
| 1 | 打开一个 TS 文件 | 状态栏出现图标 |
| 2 | 命令面板执行「插入代码注释」 | 弹出注释类型选择 |
| 3 | 选择「函数注释」,输入内容 | 光标行上方插入注释块 |
| 4 | 执行「统计文件符号」 | 弹出统计列表 |
| 5 | 修改插件配置 | 状态栏提示配置已更新 |
功能扩展
当前插件可继续扩展:
- 更精确的符号识别(AST 解析)
- 一键给全部函数加注释
- 注释风格模板配置
- 符号跳转列表(QuickPick 选择后跳转)
常见问题
| 问题 | 处理 |
|---|---|
| 注释符号错误 | 确认 isCStyleLanguage 覆盖目标语言 |
| 统计不准确 | 用正则/AST 精确匹配 |
| 状态栏不更新 | 检查 statusBar.text 赋值后 show() |
| 配置不生效 | 确认 affectsConfiguration 匹配 section |
本实战串联了 Command、QuickPick、InputBox、TextEditor、状态栏、配置读取与变更监听,覆盖了基础 API 的核心用法,是构建实用工具插件的模板。