feat:代码变更diff可视化功能实现
This commit is contained in:
@ -26,6 +26,9 @@ import {
|
||||
import { optimizePrompt } from "../services/promptOptimizeService";
|
||||
import { NotificationService } from "../services/notificationService";
|
||||
import { TrialExpirationService } from "../services/trialExpirationService";
|
||||
import { showFileDiff } from "./fileDiff";
|
||||
import { changeTracker } from "../services/changeTracker";
|
||||
import { generateDiff, renderDiffHtml } from "./diffRenderer";
|
||||
|
||||
import type { RunMode, ServiceTier } from "../types/api";
|
||||
|
||||
@ -38,6 +41,14 @@ let currentSession: DialogSession | null = null;
|
||||
/** 最后一个活跃的 taskId(用于压缩等操作) */
|
||||
let lastTaskId: string | null = null;
|
||||
|
||||
async function trackFileChange(filePath: string, oldContent: string, newContent: string): Promise<void> {
|
||||
try {
|
||||
changeTracker.trackChange(filePath, oldContent, newContent);
|
||||
} catch (error) {
|
||||
console.warn("[MessageHandler] 记录文件变更失败:", error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理用户消息
|
||||
*/
|
||||
@ -372,6 +383,9 @@ async function handleUserMessageWithBackend(
|
||||
panel.reveal();
|
||||
}
|
||||
);
|
||||
|
||||
// 发送代码变更到前端
|
||||
sendChangesToWebview(panel);
|
||||
} catch (error) {
|
||||
console.warn("[MessageHandler] 更新面板失败(面板可能已关闭):", error);
|
||||
}
|
||||
@ -774,11 +788,14 @@ async function handleFileOperation(
|
||||
if (!operation.searchText || !operation.replaceText) {
|
||||
throw new Error("缺少替换内容");
|
||||
}
|
||||
const oldContentBeforeReplace = await readFileContent(operation.filePath);
|
||||
await replaceFile(
|
||||
operation.filePath,
|
||||
operation.searchText,
|
||||
operation.replaceText
|
||||
);
|
||||
const newContentAfterReplace = await readFileContent(operation.filePath);
|
||||
await trackFileChange(operation.filePath, oldContentBeforeReplace, newContentAfterReplace);
|
||||
responseText = `✅ 文件内容替换成功: ${operation.filePath}`;
|
||||
panel.webview.postMessage({
|
||||
command: "receiveMessage",
|
||||
@ -914,7 +931,9 @@ export async function handleUpdateFile(
|
||||
content: string
|
||||
) {
|
||||
try {
|
||||
const oldContent = await readFileContent(filePath);
|
||||
await updateFile(filePath, content);
|
||||
await trackFileChange(filePath, oldContent, content);
|
||||
panel.webview.postMessage({
|
||||
command: "fileUpdated",
|
||||
filePath: filePath,
|
||||
@ -979,7 +998,10 @@ export async function handleReplaceInFile(
|
||||
replaceText: string
|
||||
) {
|
||||
try {
|
||||
const oldContent = await readFileContent(filePath);
|
||||
await replaceFile(filePath, searchText, replaceText);
|
||||
const newContent = await readFileContent(filePath);
|
||||
await trackFileChange(filePath, oldContent, newContent);
|
||||
panel.webview.postMessage({
|
||||
command: "fileReplaced",
|
||||
filePath: filePath,
|
||||
@ -1236,3 +1258,165 @@ export async function handleOptimizePrompt(
|
||||
vscode.window.showErrorMessage(`提示词优化失败: ${errorMsg}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理采纳变更
|
||||
*/
|
||||
export async function handleAcceptChange(
|
||||
panel: vscode.WebviewPanel,
|
||||
changeId: string
|
||||
) {
|
||||
try {
|
||||
const success = await changeTracker.acceptChange(changeId);
|
||||
if (success) {
|
||||
panel.webview.postMessage({
|
||||
command: "changeAccepted",
|
||||
changeId: changeId,
|
||||
success: true
|
||||
});
|
||||
} else {
|
||||
panel.webview.postMessage({
|
||||
command: "changeAccepted",
|
||||
changeId: changeId,
|
||||
success: false,
|
||||
error: "采纳变更失败"
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("[MessageHandler] 采纳变更失败:", error);
|
||||
panel.webview.postMessage({
|
||||
command: "changeAccepted",
|
||||
changeId: changeId,
|
||||
success: false,
|
||||
error: String(error)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理拒绝变更
|
||||
*/
|
||||
export async function handleRejectChange(
|
||||
panel: vscode.WebviewPanel,
|
||||
changeId: string
|
||||
) {
|
||||
try {
|
||||
const success = await changeTracker.rejectChange(changeId);
|
||||
if (success) {
|
||||
panel.webview.postMessage({
|
||||
command: "changeRejected",
|
||||
changeId: changeId,
|
||||
success: true
|
||||
});
|
||||
} else {
|
||||
panel.webview.postMessage({
|
||||
command: "changeRejected",
|
||||
changeId: changeId,
|
||||
success: false,
|
||||
error: "拒绝变更失败"
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("[MessageHandler] 拒绝变更失败:", error);
|
||||
panel.webview.postMessage({
|
||||
command: "changeRejected",
|
||||
changeId: changeId,
|
||||
success: false,
|
||||
error: String(error)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 在对话结束时发送变更列表到前端
|
||||
*/
|
||||
export function sendChangesToWebview(panel: vscode.WebviewPanel) {
|
||||
const session = changeTracker.endSession();
|
||||
if (session && session.changes.length > 0) {
|
||||
const changesWithDiff = session.changes.map(change => {
|
||||
const diffLines = generateDiff(change.oldContent, change.newContent);
|
||||
const diffHtml = renderDiffHtml(diffLines);
|
||||
return {
|
||||
...change,
|
||||
diffHtml
|
||||
};
|
||||
});
|
||||
|
||||
panel.webview.postMessage({
|
||||
command: "showChanges",
|
||||
changes: changesWithDiff
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始新的变更会话
|
||||
*/
|
||||
export function startChangeSession(sessionId: string) {
|
||||
changeTracker.startSession(sessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开文件 diff 编辑器
|
||||
*/
|
||||
export async function handleOpenFileDiff(
|
||||
panel: vscode.WebviewPanel,
|
||||
changeId: string
|
||||
) {
|
||||
try {
|
||||
const session = changeTracker.getCurrentSession();
|
||||
if (!session) {
|
||||
vscode.window.showErrorMessage('没有找到变更会话');
|
||||
return;
|
||||
}
|
||||
|
||||
const change = session.changes.find(c => c.changeId === changeId);
|
||||
if (!change) {
|
||||
vscode.window.showErrorMessage('没有找到该变更');
|
||||
return;
|
||||
}
|
||||
|
||||
const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
|
||||
if (!workspaceFolder) {
|
||||
vscode.window.showErrorMessage('没有打开的工作区');
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建临时文件用于对比
|
||||
const filePath = change.filePath;
|
||||
const absolutePath = vscode.Uri.file(
|
||||
path.join(workspaceFolder.uri.fsPath, filePath)
|
||||
);
|
||||
|
||||
// 创建虚拟文档显示旧内容
|
||||
const oldUri = vscode.Uri.parse(
|
||||
`ic-coder-diff:${filePath}.old?${changeId}`
|
||||
).with({ scheme: 'ic-coder-diff' });
|
||||
|
||||
// 注册文档内容提供者(如果还没注册)
|
||||
if (!(global as any).__diffProviderRegistered) {
|
||||
const provider = new (class implements vscode.TextDocumentContentProvider {
|
||||
provideTextDocumentContent(uri: vscode.Uri): string {
|
||||
const changeId = uri.query;
|
||||
const session = changeTracker.getCurrentSession();
|
||||
const change = session?.changes.find(c => c.changeId === changeId);
|
||||
return change?.oldContent || '';
|
||||
}
|
||||
})();
|
||||
|
||||
vscode.workspace.registerTextDocumentContentProvider('ic-coder-diff', provider);
|
||||
(global as any).__diffProviderRegistered = true;
|
||||
}
|
||||
|
||||
// 打开 diff 编辑器
|
||||
await vscode.commands.executeCommand(
|
||||
'vscode.diff',
|
||||
oldUri,
|
||||
absolutePath,
|
||||
`${filePath} (变更对比)`
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('[MessageHandler] 打开 diff 失败:', error);
|
||||
vscode.window.showErrorMessage(`打开 diff 失败: ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user