feat: 编辑器波浪线自动标记 + SQLFluff 默认方言改 oracle + AI 审查行号修正
- 波浪线标记:打开/编辑/保存自动静态分析,新增 markers.enabled 配置与 onStartupFinished 激活,带防抖与版本竞态保护 - SQLFluff:默认方言 sql->oracle;PRS 解析错误改用 i18n 三语友好提示(含当前方言与配置指引)并提升为 error - AI 审查:mergeResults 统一 aiFindings 行号为 0 基,修复整文件审查行号偏移 1 行
This commit is contained in:
@@ -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 文档 | 行为统一,符合"已打开文件都应有波浪线"预期 |
|
||||
| 批量执行方式 | 串行执行 | 避免多个 JVM(PMD)/ 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` 通过
|
||||
Reference in New Issue
Block a user