feat: 编辑器波浪线自动标记 + SQLFluff 默认方言改 oracle + AI 审查行号修正

- 波浪线标记:打开/编辑/保存自动静态分析,新增 markers.enabled 配置与 onStartupFinished 激活,带防抖与版本竞态保护
- SQLFluff:默认方言 sql->oracle;PRS 解析错误改用 i18n 三语友好提示(含当前方言与配置指引)并提升为 error
- AI 审查:mergeResults 统一 aiFindings 行号为 0 基,修复整文件审查行号偏移 1 行
This commit is contained in:
范智鹏
2026-08-04 22:10:41 +08:00
parent 247f19fd44
commit 50855dae67
9 changed files with 232 additions and 20 deletions
@@ -0,0 +1,92 @@
# 打开文件自动静态分析 + 波浪线 设计文档
> 面向 AI 编码 agent 的技术实施文档。本文档包含完整的根因分析、方案设计、文件清单和验收标准,可直接据此编码。
## 功能目标
修复插件对**已打开文件不做静态分析、不显示波浪线**的问题:
1. VSCode 启动后(`onStartupFinished`)插件自动激活,对**所有已打开的文件**串行做静态分析并显示波浪线。
2. 文本编辑时先清除波浪线(即时反馈),停止输入 1s 后自动重新分析。
3. 保存文件仍按现有 500ms 防抖重分析。
## 根因分析
| 问题 | 位置 | 说明 |
|------|------|------|
| 插件不自动激活 | `package.json:12` `activationEvents: []` | 无 `onStartupFinished` 等事件,插件只在执行命令/打开面板时激活 |
| 存量文件不分析 | `extension.ts` activate 无初始扫描 | `onDidOpenTextDocument` 只对"激活后新打开"的文件触发,激活前已打开的文件永远不会被分析 |
| 编辑不重分析 | `extension.ts:63-66` | `onDidChangeTextDocument``markers.clear`,需等保存才有波浪线 |
## 架构决策
| 决策 | 选择 | 理由 |
|------|------|------|
| 激活时机 | `onStartupFinished` | VSCode 启动完成后激活,不拖慢启动,兼容性最好 |
| 初始分析范围 | 所有已打开 file 文档 | 行为统一,符合"已打开文件都应有波浪线"预期 |
| 批量执行方式 | 串行执行 | 避免多个 JVMPMD/ Python 进程(SQLFluff)并发;JS/TS/CSS 为进程内执行,无压力 |
| 串行顺序 | 活动文件优先 | 用户眼前文件先出波浪线 |
| 编辑时行为 | 1s 防抖自动重分析 | 更接近 ESLint 等 linter 体验 |
| 防抖调度 | 统一按 URI 调度器 | 合并保存/编辑两类防抖,逻辑单一 |
## 文件变更清单
| 文件 | 变更 |
|------|------|
| `package.json` | `activationEvents``[]` 改为 `["onStartupFinished"]` |
| `src/extension.ts` | ① 初始串行扫描(活动文件优先);② 统一 `scheduleAnalysis` 调度器;③ 编辑时防抖重分析 |
无新增依赖。
## 关键实现
### 统一防抖调度器(`src/extension.ts`
```ts
const analysisTimers = new Map<string, NodeJS.Timeout>();
function scheduleAnalysis(document: vscode.TextDocument, delay: number): void {
if (document.uri.scheme !== 'file' || !isMarkersEnabled()) { return; }
const key = document.uri.toString();
const existing = analysisTimers.get(key);
if (existing) { clearTimeout(existing); }
const timer = setTimeout(async () => {
analysisTimers.delete(key);
await runStaticAndApply(document);
}, delay);
analysisTimers.set(key, timer);
}
```
### 激活时初始串行扫描(活动文件优先)
```ts
const docs = vscode.workspace.textDocuments;
const active = vscode.window.activeTextEditor?.document;
const ordered = [...docs].sort((a, b) => a === active ? -1 : b === active ? 1 : 0);
for (const doc of ordered) {
if (doc.uri.scheme !== 'file' || !isMarkersEnabled()) { continue; }
await runStaticAndApply(doc);
}
```
### 事件改写
- `onDidChangeTextDocument``markers.clear(uri)` + `scheduleAnalysis(doc, 1000)`
- `onDidSaveTextDocument`:删除原 `debounceTimers` Map,改用 `scheduleAnalysis(doc, 500)`
复用现有 `runStaticAndApply`(含版本竞态保护)与 `markers.apply`,行为不变。
## 影响范围
- **激活行为**:插件随 VSCode 启动自动激活(内存常驻,激活逻辑本已完整,代价极小)
- **兼容性**`markers.enabled` 配置全程生效;命令/CodeLens/AI 审查流程不受影响
- **进程压力**:初始串行扫描保证任一时刻最多 1 个 JVM 在跑
## 验收标准
1. 启动 Extension Dev Host,预置多个已打开文件(含活动与非活动),确认启动后活动文件波浪线先出现、其余依次出现
2. 编辑文件停止 1s 后波浪线自动刷新;输入过程中波浪线消失
3. 保存文件 500ms 后波浪线刷新
4. `markers.enabled=false` 时不显示任何波浪线且不触发分析
5. `npm run lint``npm run compile` 通过