mirror of
https://github.com/Gmaker689/ai-diff-preview.git
synced 2026-10-01 22:01:51 +08:00
refactor: 架构变更:Webview → VSCode 内置 Diff + 浮动标签
This commit is contained in:
+163
-6
@@ -2,10 +2,16 @@
|
||||
* AI Code Diff Preview - 插件入口
|
||||
*
|
||||
* 工作流程:
|
||||
* 1. PostToolUse (Edit/Write) → 收集变更到 ChangeSet
|
||||
* 2. Stop (对话结束) → 弹出通知
|
||||
* 3. 用户点击"查看更改" → 打开 Review 双栏面板
|
||||
* 1. PostToolUse (Edit/Write) → 收集变更到 ChangeSet (EditRecord 粒度)
|
||||
* 2. Stop (对话结束) → 根据配置弹出 QuickPick 文件列表或通知
|
||||
* 3. 用户选择文件 → 打开 VSCode 内置 Diff 编辑器
|
||||
* 4. 用户 Accept/Reject → 应用或丢弃变更
|
||||
*
|
||||
* 快捷键:
|
||||
* - Alt+↑/↓: 上一个/下一个变更
|
||||
* - Tab: 接受当前编辑
|
||||
* - Esc: 拒绝当前编辑
|
||||
* - Ctrl+Shift+D: 显示文件列表
|
||||
*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
@@ -13,12 +19,14 @@ import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import { ChangeSetManager } from './snapshot/snapshotManager';
|
||||
import { HookHandler } from './trigger/hookHandler';
|
||||
import { DiffViewer } from './render/diffViewer';
|
||||
import { ReviewPanel } from './render/reviewPanel';
|
||||
import { COMMANDS } from './models/constants';
|
||||
import { ClaudeHookEvent } from './models/types';
|
||||
|
||||
let changeSetManager: ChangeSetManager;
|
||||
let hookHandler: HookHandler;
|
||||
let diffViewer: DiffViewer;
|
||||
let reviewPanel: ReviewPanel;
|
||||
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
@@ -27,6 +35,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
// 初始化核心模块
|
||||
changeSetManager = new ChangeSetManager();
|
||||
hookHandler = new HookHandler(changeSetManager);
|
||||
diffViewer = hookHandler.getDiffViewer();
|
||||
reviewPanel = new ReviewPanel(changeSetManager);
|
||||
|
||||
// 注册命令
|
||||
@@ -40,12 +49,160 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
}
|
||||
|
||||
function registerCommands(context: vscode.ExtensionContext) {
|
||||
// 显示 Review 面板
|
||||
// === Diff 查看 ===
|
||||
|
||||
// 显示文件列表 (QuickPick)
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand(COMMANDS.SHOW_DIFF_PANEL, () => {
|
||||
reviewPanel.show();
|
||||
hookHandler.showFileListPicker();
|
||||
})
|
||||
);
|
||||
|
||||
// 显示当前活动文件的 Diff
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand(COMMANDS.SHOW_CURRENT_FILE_DIFF, () => {
|
||||
diffViewer.showCurrentFileDiff();
|
||||
})
|
||||
);
|
||||
|
||||
// === Accept / Reject ===
|
||||
|
||||
// 接受当前编辑(光标所在位置的编辑)
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand(COMMANDS.ACCEPT_CURRENT_EDIT, () => {
|
||||
const result = findCurrentEditAtCursor();
|
||||
if (!result) {
|
||||
vscode.window.showInformationMessage('AI Diff: 光标不在变更区域内');
|
||||
return;
|
||||
}
|
||||
changeSetManager.acceptEditRecord(result.fileChange.id, result.edit.id);
|
||||
vscode.window.showInformationMessage(`AI Diff: 已接受编辑 #${result.edit.id.slice(0, 6)}`);
|
||||
})
|
||||
);
|
||||
|
||||
// 拒绝当前编辑
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand(COMMANDS.REJECT_CURRENT_EDIT, () => {
|
||||
const result = findCurrentEditAtCursor();
|
||||
if (!result) {
|
||||
vscode.window.showInformationMessage('AI Diff: 光标不在变更区域内');
|
||||
return;
|
||||
}
|
||||
changeSetManager.rejectEditRecord(result.fileChange.id, result.edit.id);
|
||||
vscode.window.showInformationMessage(`AI Diff: 已拒绝编辑 #${result.edit.id.slice(0, 6)}`);
|
||||
})
|
||||
);
|
||||
|
||||
// 接受全部
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand(COMMANDS.ACCEPT_ALL, () => {
|
||||
const count = changeSetManager.acceptAll();
|
||||
vscode.window.showInformationMessage(`AI Diff: 已接受 ${count} 个文件的变更`);
|
||||
})
|
||||
);
|
||||
|
||||
// 拒绝全部
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand(COMMANDS.REJECT_ALL, () => {
|
||||
const count = changeSetManager.rejectAll();
|
||||
vscode.window.showInformationMessage(`AI Diff: 已拒绝 ${count} 个文件的变更`);
|
||||
})
|
||||
);
|
||||
|
||||
// === 导航 ===
|
||||
|
||||
// 下一个变更
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand(COMMANDS.NEXT_DIFF, () => {
|
||||
navigateDiff(1);
|
||||
})
|
||||
);
|
||||
|
||||
// 上一个变更
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand(COMMANDS.PREV_DIFF, () => {
|
||||
navigateDiff(-1);
|
||||
})
|
||||
);
|
||||
|
||||
// 旧版兼容命令
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand(COMMANDS.ACCEPT_CHUNK, () => {
|
||||
vscode.commands.executeCommand(COMMANDS.ACCEPT_CURRENT_EDIT);
|
||||
})
|
||||
);
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand(COMMANDS.REJECT_CHUNK, () => {
|
||||
vscode.commands.executeCommand(COMMANDS.REJECT_CURRENT_EDIT);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找光标所在位置的编辑记录
|
||||
*/
|
||||
function findCurrentEditAtCursor(): { fileChange: any; edit: any } | null {
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
if (!editor) return null;
|
||||
|
||||
const set = changeSetManager.getCurrentSet();
|
||||
if (!set) return null;
|
||||
|
||||
const normalizedPath = path.normalize(editor.document.uri.fsPath).replace(/\\/g, '/');
|
||||
const fileChange = set.changes.find(
|
||||
c => path.normalize(c.filePath).replace(/\\/g, '/') === normalizedPath && c.status === 'pending'
|
||||
);
|
||||
if (!fileChange) return null;
|
||||
|
||||
const cursorLine = editor.selection.active.line;
|
||||
|
||||
// 在文件聚合 diff 中查找光标所在行对应的 edit
|
||||
for (const edit of fileChange.edits) {
|
||||
if (edit.status !== 'pending') continue;
|
||||
// 找到该 edit 中匹配的行范围
|
||||
for (const d of edit.diffLines) {
|
||||
if (d.type === 'context' || d.type === 'add') {
|
||||
if (d.newLineNum - 1 === cursorLine) {
|
||||
return { fileChange, edit };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 回退:返回第一个 pending edit
|
||||
const firstPending = fileChange.edits.find(e => e.status === 'pending');
|
||||
if (firstPending) {
|
||||
return { fileChange, edit: firstPending };
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 在变更文件之间导航
|
||||
*/
|
||||
function navigateDiff(direction: 1 | -1): void {
|
||||
const set = changeSetManager.getCurrentSet();
|
||||
if (!set) return;
|
||||
|
||||
const pending = set.changes.filter(c => c.status === 'pending');
|
||||
if (pending.length === 0) {
|
||||
vscode.window.showInformationMessage('AI Diff: 无待处理变更');
|
||||
return;
|
||||
}
|
||||
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
const currentPath = editor
|
||||
? path.normalize(editor.document.uri.fsPath).replace(/\\/g, '/')
|
||||
: null;
|
||||
|
||||
// 找到当前文件在 pending 列表中的位置
|
||||
let idx = currentPath
|
||||
? pending.findIndex(c => path.normalize(c.filePath).replace(/\\/g, '/') === currentPath)
|
||||
: -1;
|
||||
|
||||
idx = idx === -1 ? 0 : (idx + direction + pending.length) % pending.length;
|
||||
diffViewer.showFileDiff(pending[idx]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,7 +210,7 @@ function registerCommands(context: vscode.ExtensionContext) {
|
||||
*
|
||||
* 监听 .claude/hooks/pending.json:
|
||||
* - toolName: Edit/Write → 收集变更
|
||||
* - toolName: Stop → 弹出 Review 通知
|
||||
* - toolName: Stop → 弹出 Review 通知/文件列表
|
||||
*/
|
||||
function registerHookFileWatcher(context: vscode.ExtensionContext) {
|
||||
const hookDir = vscode.workspace.workspaceFolders?.[0]
|
||||
|
||||
@@ -16,6 +16,16 @@ export const COMMANDS = {
|
||||
ACCEPT_ALL: 'aiDiffPreview.acceptAll',
|
||||
REJECT_ALL: 'aiDiffPreview.rejectAll',
|
||||
SHOW_DIFF_PANEL: 'aiDiffPreview.showDiffPanel',
|
||||
/** 显示当前文件的 Diff */
|
||||
SHOW_CURRENT_FILE_DIFF: 'aiDiffPreview.showCurrentFileDiff',
|
||||
/** 接受光标所在位置的编辑 */
|
||||
ACCEPT_CURRENT_EDIT: 'aiDiffPreview.acceptCurrentEdit',
|
||||
/** 拒绝光标所在位置的编辑 */
|
||||
REJECT_CURRENT_EDIT: 'aiDiffPreview.rejectCurrentEdit',
|
||||
/** 跳转到下一个待处理变更 */
|
||||
NEXT_DIFF: 'aiDiffPreview.nextDiff',
|
||||
/** 跳转到上一个待处理变更 */
|
||||
PREV_DIFF: 'aiDiffPreview.prevDiff',
|
||||
} as const;
|
||||
|
||||
/**
|
||||
@@ -27,6 +37,17 @@ export const CONTEXT_KEYS = {
|
||||
CHUNK_COUNT: 'aiDiffPreview.chunkCount',
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* 配置项键名
|
||||
*/
|
||||
export const CONFIG_KEYS = {
|
||||
ENABLE_AUTO_TRIGGER: 'enableAutoTrigger',
|
||||
AUTO_SHOW_DIFF_PER_EDIT: 'autoShowDiffPerEdit',
|
||||
SHOW_ALL_DIFFS_ON_STOP: 'showAllDiffsOnStop',
|
||||
FLOATING_LABEL_MODE: 'floatingLabelMode',
|
||||
MAX_FILE_SIZE: 'maxFileSize',
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* 装饰器类型 ID
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* Diff 查看器 - 调用 VSCode 内置 Diff 编辑器
|
||||
*
|
||||
* 使用 vscode.diff 命令展示原始内容 vs 变更后内容,
|
||||
* 完全不使用自定义 Webview,保持 VSCode 原生交互体验。
|
||||
*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as path from 'path';
|
||||
import { EditRecord, FileChange } from '../models/types';
|
||||
import { ChangeSetManager } from '../snapshot/snapshotManager';
|
||||
|
||||
export class DiffViewer {
|
||||
constructor(private changeSetManager: ChangeSetManager) {}
|
||||
|
||||
/**
|
||||
* 打开单次编辑的 Diff(VSCode 内置 Diff 编辑器)
|
||||
*/
|
||||
async showEditDiff(editRecord: EditRecord): Promise<void> {
|
||||
const beforeDoc = await vscode.workspace.openTextDocument({
|
||||
content: editRecord.beforeContent,
|
||||
language: this.getLanguageId(editRecord.filePath),
|
||||
});
|
||||
const afterDoc = await vscode.workspace.openTextDocument({
|
||||
content: editRecord.afterContent,
|
||||
language: this.getLanguageId(editRecord.filePath),
|
||||
});
|
||||
|
||||
const fileName = path.basename(editRecord.filePath);
|
||||
const toolLabel = editRecord.toolName === 'Write' ? '写入' : '编辑';
|
||||
|
||||
await vscode.commands.executeCommand(
|
||||
'vscode.diff',
|
||||
beforeDoc.uri,
|
||||
afterDoc.uri,
|
||||
`${fileName} — AI ${toolLabel} #${editRecord.id.slice(0, 6)} (原始 ↔ 变更后)`
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开整个文件的聚合 Diff
|
||||
*/
|
||||
async showFileDiff(fileChange: FileChange): Promise<void> {
|
||||
const beforeDoc = await vscode.workspace.openTextDocument({
|
||||
content: fileChange.originalContent,
|
||||
language: this.getLanguageId(fileChange.filePath),
|
||||
});
|
||||
const afterDoc = await vscode.workspace.openTextDocument({
|
||||
content: fileChange.latestContent,
|
||||
language: this.getLanguageId(fileChange.filePath),
|
||||
});
|
||||
|
||||
const fileName = path.basename(fileChange.filePath);
|
||||
|
||||
await vscode.commands.executeCommand(
|
||||
'vscode.diff',
|
||||
beforeDoc.uri,
|
||||
afterDoc.uri,
|
||||
`${fileName} — 原始 ↔ 变更后 (${fileChange.edits.length} 次编辑)`
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开当前活动文件在编辑器中的 Diff
|
||||
*/
|
||||
async showCurrentFileDiff(): Promise<void> {
|
||||
const changeSet = this.changeSetManager.getCurrentSet();
|
||||
if (!changeSet) return;
|
||||
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
if (!editor) return;
|
||||
|
||||
const normalizedPath = path.normalize(editor.document.uri.fsPath).replace(/\\/g, '/');
|
||||
const fileChange = changeSet.changes.find(
|
||||
c => path.normalize(c.filePath).replace(/\\/g, '/') === normalizedPath && c.status === 'pending'
|
||||
);
|
||||
if (!fileChange) {
|
||||
vscode.window.showInformationMessage('AI Diff: 当前文件无待处理变更');
|
||||
return;
|
||||
}
|
||||
|
||||
await this.showFileDiff(fileChange);
|
||||
}
|
||||
|
||||
/**
|
||||
* 聚焦文件到编辑器(跳转到该文件并定位到第一个变更行)
|
||||
*/
|
||||
async focusFileInEditor(fileChange: FileChange): Promise<void> {
|
||||
const uri = vscode.Uri.file(fileChange.filePath);
|
||||
const doc = await vscode.workspace.openTextDocument(uri);
|
||||
const editor = await vscode.window.showTextDocument(doc, { preview: false });
|
||||
|
||||
// 滚动到第一个变更行
|
||||
if (fileChange.diffLines.length > 0) {
|
||||
const firstChange = fileChange.diffLines.find(
|
||||
d => d.type === 'add' || d.type === 'delete'
|
||||
);
|
||||
if (firstChange) {
|
||||
const line = (firstChange.newLineNum || firstChange.oldLineNum) - 1;
|
||||
const pos = new vscode.Position(Math.max(0, line), 0);
|
||||
editor.selection = new vscode.Selection(pos, pos);
|
||||
editor.revealRange(new vscode.Range(pos, pos), vscode.TextEditorRevealType.InCenter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private getLanguageId(filePath: string): string {
|
||||
const ext = path.extname(filePath).toLowerCase();
|
||||
const map: Record<string, string> = {
|
||||
'.ts': 'typescript', '.tsx': 'typescriptreact',
|
||||
'.js': 'javascript', '.jsx': 'javascriptreact',
|
||||
'.json': 'json', '.md': 'markdown',
|
||||
'.css': 'css', '.scss': 'scss', '.less': 'less',
|
||||
'.html': 'html', '.htm': 'html',
|
||||
'.py': 'python', '.rs': 'rust', '.go': 'go',
|
||||
'.java': 'java', '.cpp': 'cpp', '.c': 'c',
|
||||
'.yaml': 'yaml', '.yml': 'yaml',
|
||||
'.xml': 'xml', '.sql': 'sql', '.sh': 'shell',
|
||||
};
|
||||
return map[ext] || 'plaintext';
|
||||
}
|
||||
}
|
||||
+104
-15
@@ -1,23 +1,41 @@
|
||||
/**
|
||||
* Hook 处理器
|
||||
*
|
||||
* PostToolUse (Edit/Write) → 收集变更,不显示 UI
|
||||
* Stop → 对话结束,弹出 Review 通知
|
||||
* PostToolUse (Edit/Write) → 收集变更
|
||||
* + autoShowDiffPerEdit=true → 立即弹出 VSCode 内置 Diff
|
||||
* + autoShowDiffPerEdit=false → 静默收集
|
||||
*
|
||||
* Stop → 对话结束
|
||||
* + showAllDiffsOnStop=true → 弹出 QuickPick 文件列表
|
||||
* + showAllDiffsOnStop=false → 仅状态栏通知
|
||||
*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as path from 'path';
|
||||
import { ChangeSetManager } from '../snapshot/snapshotManager';
|
||||
import { ClaudeHookEvent } from '../models/types';
|
||||
import { DiffViewer } from '../render/diffViewer';
|
||||
import { ClaudeHookEvent, FileChange } from '../models/types';
|
||||
import { CONFIG_SECTION, CONFIG_KEYS } from '../models/constants';
|
||||
|
||||
const SETTING_AUTO_SHOW_DIFF = `${CONFIG_SECTION}.${CONFIG_KEYS.AUTO_SHOW_DIFF_PER_EDIT}`;
|
||||
const SETTING_SHOW_ALL_ON_STOP = `${CONFIG_SECTION}.${CONFIG_KEYS.SHOW_ALL_DIFFS_ON_STOP}`;
|
||||
|
||||
export class HookHandler {
|
||||
private diffViewer: DiffViewer;
|
||||
|
||||
constructor(
|
||||
private changeSetManager: ChangeSetManager
|
||||
) {}
|
||||
) {
|
||||
this.diffViewer = new DiffViewer(changeSetManager);
|
||||
}
|
||||
|
||||
getDiffViewer(): DiffViewer {
|
||||
return this.diffViewer;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理 PostToolUse 事件(Edit/Write)
|
||||
* 只收集变更,不弹 UI
|
||||
* 收集变更,根据配置决定是否自动弹 Diff
|
||||
*/
|
||||
handleEdit(event: ClaudeHookEvent): void {
|
||||
event.filePath = path.normalize(event.filePath);
|
||||
@@ -30,11 +48,29 @@ export class HookHandler {
|
||||
event.newString || '',
|
||||
event.content || ''
|
||||
);
|
||||
|
||||
// 根据配置决定是否自动弹 Diff
|
||||
const autoShow = vscode.workspace.getConfiguration(CONFIG_SECTION).get<boolean>(CONFIG_KEYS.AUTO_SHOW_DIFF_PER_EDIT, false);
|
||||
if (autoShow) {
|
||||
const set = this.changeSetManager.getCurrentSet();
|
||||
if (set) {
|
||||
const normalizedPath = path.normalize(event.filePath).replace(/\\/g, '/');
|
||||
const fileChange = set.changes.find(
|
||||
c => path.normalize(c.filePath).replace(/\\/g, '/') === normalizedPath
|
||||
);
|
||||
if (fileChange) {
|
||||
const lastEdit = fileChange.edits[fileChange.edits.length - 1];
|
||||
this.diffViewer.showEditDiff(lastEdit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 更新上下文键
|
||||
vscode.commands.executeCommand('setContext', 'aiDiffPreview.isActive', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理 Stop 事件(对话结束)
|
||||
* 弹出通知,提示用户查看变更
|
||||
*/
|
||||
handleStop(): void {
|
||||
const changeSet = this.changeSetManager.markReady();
|
||||
@@ -44,16 +80,69 @@ export class HookHandler {
|
||||
}
|
||||
|
||||
const count = changeSet.changes.length;
|
||||
console.log(`[AI Diff] 对话结束,${count} 个文件有变更`);
|
||||
const pendingCount = changeSet.changes.filter(c => c.status === 'pending').length;
|
||||
console.log(`[AI Diff] 对话结束,${count} 个文件有变更 (pending: ${pendingCount})`);
|
||||
|
||||
// 弹出通知,带"查看更改"按钮
|
||||
vscode.window.showInformationMessage(
|
||||
`AI Diff: ${count} 个文件已修改`,
|
||||
'查看更改'
|
||||
).then(selection => {
|
||||
if (selection === '查看更改') {
|
||||
vscode.commands.executeCommand('aiDiffPreview.showDiffPanel');
|
||||
}
|
||||
const showAll = vscode.workspace.getConfiguration(CONFIG_SECTION).get<boolean>(CONFIG_KEYS.SHOW_ALL_DIFFS_ON_STOP, true);
|
||||
|
||||
if (showAll && pendingCount > 0) {
|
||||
// 弹出 QuickPick 文件列表
|
||||
this.showFileListPicker(changeSet.changes.filter(c => c.status === 'pending'));
|
||||
} else {
|
||||
// 仅状态栏通知
|
||||
const msg = pendingCount > 0
|
||||
? `AI Diff: ${pendingCount} 个文件有待处理变更`
|
||||
: `AI Diff: ${count} 个文件变更已完成`;
|
||||
vscode.window.showInformationMessage(msg, '查看变更').then(selection => {
|
||||
if (selection === '查看变更') {
|
||||
this.showFileListPicker(changeSet.changes.filter(c => c.status === 'pending'));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 弹出 QuickPick 文件列表
|
||||
*/
|
||||
async showFileListPicker(fileChanges?: FileChange[]): Promise<void> {
|
||||
let changes = fileChanges;
|
||||
if (!changes) {
|
||||
const set = this.changeSetManager.getCurrentSet();
|
||||
if (!set) return;
|
||||
changes = set.changes.filter(c => c.status === 'pending');
|
||||
}
|
||||
|
||||
if (changes.length === 0) {
|
||||
vscode.window.showInformationMessage('AI Diff: 无待处理变更');
|
||||
return;
|
||||
}
|
||||
|
||||
const items: vscode.QuickPickItem[] = changes.map(c => {
|
||||
const name = path.basename(c.filePath);
|
||||
const adds = c.diffLines.filter(d => d.type === 'add').length;
|
||||
const dels = c.diffLines.filter(d => d.type === 'delete').length;
|
||||
const typeMap: Record<string, string> = { modify: '$(edit)', create: '$(new-file)', delete: '$(trash)' };
|
||||
|
||||
return {
|
||||
label: `${typeMap[c.type] || '$(file)'} ${name}`,
|
||||
description: `+${adds} -${dels} · ${c.edits.length} 次编辑`,
|
||||
detail: c.filePath,
|
||||
// 存储 fileChange id 以便查找
|
||||
id: c.id,
|
||||
};
|
||||
});
|
||||
|
||||
const selected = await vscode.window.showQuickPick(items, {
|
||||
placeHolder: `AI Diff Review — ${changes.length} 个文件有变更`,
|
||||
matchOnDescription: true,
|
||||
matchOnDetail: true,
|
||||
});
|
||||
|
||||
if (selected && selected.id) {
|
||||
const fileChange = changes.find(c => c.id === selected.id);
|
||||
if (fileChange) {
|
||||
await this.diffViewer.showFileDiff(fileChange);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user