mirror of
https://github.com/Gmaker689/ai-diff-preview.git
synced 2026-09-27 15:31:51 +08:00
refactor: 架构变更:Webview → VSCode 内置 Diff + 浮动标签
This commit is contained in:
@@ -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';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user