diff --git a/src/services/toolExecutor.ts b/src/services/toolExecutor.ts index 930e5e6..c61c54e 100644 --- a/src/services/toolExecutor.ts +++ b/src/services/toolExecutor.ts @@ -291,7 +291,7 @@ async function executeSyntaxCheck( // 检查 iverilog 是否可用 const iverilogCheck = await checkIverilogAvailable(context.extensionPath); if (!iverilogCheck.available) { - throw new Error(`iverilog 不可用: ${iverilogCheck.message}`); + throw new Error(`IC Coder编译器不可用: ${iverilogCheck.message}`); } // 创建临时文件 @@ -372,7 +372,7 @@ async function executeIverilog( // 检查 iverilog 是否可用 const iverilogCheck = await checkIverilogAvailable(context.extensionPath); if (!iverilogCheck.available) { - throw new Error(`iverilog 不可用: ${iverilogCheck.message}`); + throw new Error(`IC Coder编译器不可用: ${iverilogCheck.message}`); } // 获取工作目录 diff --git a/src/utils/iverilogRunner.ts b/src/utils/iverilogRunner.ts index 2067c0f..ac0af58 100644 --- a/src/utils/iverilogRunner.ts +++ b/src/utils/iverilogRunner.ts @@ -7,7 +7,7 @@ import { promisify } from "util"; function execCommand( command: string, args: string[], - options: { cwd: string; env?: any } + options: { cwd: string; env?: any }, ): Promise<{ stdout: string; stderr: string }> { return new Promise((resolve, reject) => { // 在 Windows 上,如果路径包含空格,不使用 shell,直接用 spawn @@ -23,25 +23,25 @@ function execCommand( let stderr = ""; // 在 Windows 上使用 GBK 编码解码输出 - const encoding = process.platform === 'win32' ? 'gbk' : 'utf8'; + const encoding = process.platform === "win32" ? "gbk" : "utf8"; child.stdout.on("data", (data) => { try { // 尝试使用 iconv-lite 解码(如果可用) - const iconv = require('iconv-lite'); + const iconv = require("iconv-lite"); stdout += iconv.decode(data, encoding); } catch { // 如果 iconv-lite 不可用,使用默认解码 - stdout += data.toString('utf8'); + stdout += data.toString("utf8"); } }); child.stderr.on("data", (data) => { try { - const iconv = require('iconv-lite'); + const iconv = require("iconv-lite"); stderr += iconv.decode(data, encoding); } catch { - stderr += data.toString('utf8'); + stderr += data.toString("utf8"); } }); @@ -93,7 +93,7 @@ export interface VCDGenerationResult { * 检查项目中的 Verilog 文件完整性 */ export async function checkVerilogProject( - projectPath: string + projectPath: string, ): Promise { const result: VerilogProjectCheck = { isComplete: false, @@ -164,7 +164,7 @@ export async function checkVerilogProject( return result; } catch (error) { result.errors.push( - `检查项目时出错: ${error instanceof Error ? error.message : "未知错误"}` + `检查项目时出错: ${error instanceof Error ? error.message : "未知错误"}`, ); return result; } @@ -209,12 +209,30 @@ async function getIverilogPath(extensionPath: string): Promise { let iverilogBin = ""; if (platform === "win32") { - iverilogBin = path.join(extensionPath, "tools", "iverilog", "bin", "iverilog.exe"); + iverilogBin = path.join( + extensionPath, + "tools", + "iverilog", + "bin", + "iverilog.exe", + ); } else if (platform === "darwin") { - iverilogBin = path.join(extensionPath, "tools", "iverilog", "bin", "iverilog"); + iverilogBin = path.join( + extensionPath, + "tools", + "iverilog", + "bin", + "iverilog", + ); } else { // Linux - iverilogBin = path.join(extensionPath, "tools", "iverilog", "bin", "iverilog"); + iverilogBin = path.join( + extensionPath, + "tools", + "iverilog", + "bin", + "iverilog", + ); } // 如果插件包中没有,尝试使用系统安装的 iverilog @@ -258,7 +276,7 @@ async function getVvpPath(extensionPath: string): Promise { */ export async function generateVCD( projectPath: string, - extensionPath: string + extensionPath: string, ): Promise { try { // 1. 检查项目完整性 @@ -302,7 +320,7 @@ export async function generateVCD( } catch (error: any) { return { success: false, - message: `iverilog 编译失败:\n${error.message}`, + message: `IC Coder编译器编译失败:\n${error.message}`, stderr: error.stderr, stdout: error.stdout, }; @@ -310,17 +328,17 @@ export async function generateVCD( // 6.5. 删除 shebang 行(修复 Windows 上的 vvp 解析错误) try { - const fs = require('fs'); - const vvpContent = fs.readFileSync(outputFile, 'utf8'); - const lines = vvpContent.split('\n'); + const fs = require("fs"); + const vvpContent = fs.readFileSync(outputFile, "utf8"); + const lines = vvpContent.split("\n"); - if (lines.length > 0 && lines[0].startsWith('#!')) { - const cleanedContent = lines.slice(1).join('\n'); - fs.writeFileSync(outputFile, cleanedContent, 'utf8'); - console.log('已删除 .vvp 文件的 shebang 行'); + if (lines.length > 0 && lines[0].startsWith("#!")) { + const cleanedContent = lines.slice(1).join("\n"); + fs.writeFileSync(outputFile, cleanedContent, "utf8"); + console.log("已删除 .vvp 文件的 shebang 行"); } } catch (error) { - console.warn('删除 shebang 失败,继续执行:', error); + console.warn("删除 shebang 失败,继续执行:", error); } // 7. 执行仿真生成 VCD @@ -346,13 +364,17 @@ export async function generateVCD( const projectUri = vscode.Uri.file(projectPath); const entries = await vscode.workspace.fs.readDirectory(projectUri); const vcdFiles = entries - .filter(([fileName, fileType]) => fileType === vscode.FileType.File && fileName.endsWith('.vcd')) + .filter( + ([fileName, fileType]) => + fileType === vscode.FileType.File && fileName.endsWith(".vcd"), + ) .map(([fileName]) => fileName); if (vcdFiles.length === 0) { return { success: false, - message: "VCD 文件未生成。请确保 testbench 中包含 $dumpfile 和 $dumpvars 语句。", + message: + "VCD 文件未生成。请确保 testbench 中包含 $dumpfile 和 $dumpvars 语句。", stdout: simResult.stdout, }; } @@ -388,7 +410,7 @@ export async function generateVCD( * 检查 iverilog 是否可用 */ export async function checkIverilogAvailable( - extensionPath: string + extensionPath: string, ): Promise<{ available: boolean; version?: string; message: string }> { try { const iverilogPath = await getIverilogPath(extensionPath); @@ -400,7 +422,7 @@ export async function checkIverilogAvailable( } catch (error) { return { available: false, - message: `iverilog 不可用。未找到文件: ${iverilogPath}`, + message: `IC Coder编译器不可用。未找到文件: ${iverilogPath}`, }; } @@ -419,12 +441,12 @@ export async function checkIverilogAvailable( return { available: true, version: version, - message: `iverilog 可用: ${version}`, + message: `IC Coder编译器可用: ${version}`, }; } catch (error: any) { return { available: false, - message: `iverilog 执行失败: ${error.message}\n${error.stderr || ""}`, + message: `IC Coder编译器执行失败: ${error.message}\n${error.stderr || ""}`, }; } } @@ -433,8 +455,8 @@ export async function checkIverilogAvailable( * 要 dump 的模块定义 */ export interface DumpModule { - name: string; // 模块名(用于 VCD 文件名和宏名) - path: string; // 实例路径(如 dut.u_tx) + name: string; // 模块名(用于 VCD 文件名和宏名) + path: string; // 实例路径(如 dut.u_tx) } /** @@ -459,10 +481,11 @@ export interface MultiVCDResult { function injectConditionalDump( tbContent: string, dumpModules: DumpModule[], - vcdDir: string + vcdDir: string, ): string { // 匹配 $dumpfile 和 $dumpvars 语句(可能跨多行) - const dumpPattern = /(\$dumpfile\s*\([^)]+\)\s*;[\s\S]*?\$dumpvars\s*\([^)]+\)\s*;)/g; + const dumpPattern = + /(\$dumpfile\s*\([^)]+\)\s*;[\s\S]*?\$dumpvars\s*\([^)]+\)\s*;)/g; // 生成条件编译代码 const conditionalCode = generateConditionalDumpCode(dumpModules, vcdDir); @@ -484,7 +507,7 @@ function injectConditionalDump( */ function generateConditionalDumpCode( dumpModules: DumpModule[], - vcdDir: string + vcdDir: string, ): string { if (dumpModules.length === 0) { return '$dumpfile("output.vcd");\n $dumpvars(0, dut);'; @@ -495,7 +518,7 @@ function generateConditionalDumpCode( dumpModules.forEach((module, index) => { const macroName = `DUMP_${module.name.toUpperCase()}`; const vcdPath = `${vcdDir}/${module.name}.vcd`; - const directive = index === 0 ? '`ifdef' : '`elsif'; + const directive = index === 0 ? "`ifdef" : "`elsif"; lines.push(`${directive} ${macroName}`); lines.push(` $dumpfile("${vcdPath}");`); @@ -503,12 +526,12 @@ function generateConditionalDumpCode( }); // 添加默认分支(使用第一个模块) - lines.push('`else'); + lines.push("`else"); lines.push(` $dumpfile("${vcdDir}/${dumpModules[0].name}.vcd");`); lines.push(` $dumpvars(1, ${dumpModules[0].path});`); - lines.push('`endif'); + lines.push("`endif"); - return lines.join('\n'); + return lines.join("\n"); } /** @@ -519,10 +542,10 @@ export async function generateMultiVCD( extensionPath: string, tbPath: string, dumpModules: DumpModule[], - vcdDir: string = 'vcd' + vcdDir: string = "vcd", ): Promise { - const results: MultiVCDResult['vcdFiles'] = []; - let allStdout = ''; + const results: MultiVCDResult["vcdFiles"] = []; + let allStdout = ""; try { // 1. 创建 vcd 目录 @@ -535,16 +558,21 @@ export async function generateMultiVCD( } // 2. 读取原始 testbench - const tbFullPath = path.isAbsolute(tbPath) ? tbPath : path.join(projectPath, tbPath); + const tbFullPath = path.isAbsolute(tbPath) + ? tbPath + : path.join(projectPath, tbPath); const tbUri = vscode.Uri.file(tbFullPath); const tbBytes = await vscode.workspace.fs.readFile(tbUri); - const originalTb = Buffer.from(tbBytes).toString('utf-8'); + const originalTb = Buffer.from(tbBytes).toString("utf-8"); // 3. 注入条件编译代码 const modifiedTb = injectConditionalDump(originalTb, dumpModules, vcdDir); - await vscode.workspace.fs.writeFile(tbUri, Buffer.from(modifiedTb, 'utf-8')); + await vscode.workspace.fs.writeFile( + tbUri, + Buffer.from(modifiedTb, "utf-8"), + ); - console.log('[generateMultiVCD] Testbench 已修改,开始多次仿真...'); + console.log("[generateMultiVCD] Testbench 已修改,开始多次仿真..."); // 4. 获取工具路径 const iverilogPath = await getIverilogPath(extensionPath); @@ -569,27 +597,34 @@ export async function generateMultiVCD( // 编译(带宏定义) const compileArgs = [ `-D${macroName}`, - "-o", outputFile, - ...projectCheck.allVerilogFiles + "-o", + outputFile, + ...projectCheck.allVerilogFiles, ]; await execCommand(iverilogPath, compileArgs, { cwd: projectPath, env }); // 仿真 - const simResult = await execCommand(vvpPath, [outputFile], { cwd: projectPath, env }); + const simResult = await execCommand(vvpPath, [outputFile], { + cwd: projectPath, + env, + }); allStdout += `\n[${module.name}] ${simResult.stdout}`; results.push({ moduleName: module.name, vcdPath: vcdPath, - success: true + success: true, }); } catch (error: any) { - console.error(`[generateMultiVCD] 模块 ${module.name} 仿真失败:`, error.message); + console.error( + `[generateMultiVCD] 模块 ${module.name} 仿真失败:`, + error.message, + ); results.push({ moduleName: module.name, vcdPath: vcdPath, success: false, - error: error.message + error: error.message, }); // 继续执行其他模块 } @@ -602,19 +637,18 @@ export async function generateMultiVCD( // 忽略 } - const successCount = results.filter(r => r.success).length; + const successCount = results.filter((r) => r.success).length; return { success: successCount > 0, vcdFiles: results, message: `生成完成:${successCount}/${dumpModules.length} 个 VCD 文件成功`, - stdout: allStdout + stdout: allStdout, }; - } catch (error) { return { success: false, vcdFiles: results, - message: `生成多 VCD 文件失败: ${error instanceof Error ? error.message : '未知错误'}` + message: `生成多 VCD 文件失败: ${error instanceof Error ? error.message : "未知错误"}`, }; } } diff --git a/src/utils/messageHandler.ts b/src/utils/messageHandler.ts index 13ef613..919e88a 100644 --- a/src/utils/messageHandler.ts +++ b/src/utils/messageHandler.ts @@ -41,7 +41,11 @@ let currentSession: DialogSession | null = null; /** 最后一个活跃的 taskId(用于压缩等操作) */ let lastTaskId: string | null = null; -async function trackFileChange(filePath: string, oldContent: string, newContent: string): Promise { +async function trackFileChange( + filePath: string, + oldContent: string, + newContent: string, +): Promise { try { changeTracker.trackChange(filePath, oldContent, newContent); } catch (error) { @@ -58,7 +62,7 @@ export async function handleUserMessage( extensionPath?: string, mode?: RunMode, serviceTier?: ServiceTier, // 服务等级参数 - contextItems?: Array<{ id: number; type: string; path: string }> // 上下文项参数 + contextItems?: Array<{ id: number; type: string; path: string }>, // 上下文项参数 ) { console.log("收到用户消息:", text); @@ -68,7 +72,9 @@ export async function handleUserMessage( // 从 session 中获取 token let token: string | undefined; try { - const session = await vscode.authentication.getSession("iccoder", [], { createIfNone: false }); + const session = await vscode.authentication.getSession("iccoder", [], { + createIfNone: false, + }); token = session?.accessToken; } catch (error) { console.warn("[MessageHandler] 获取 session 失败:", error); @@ -78,20 +84,20 @@ export async function handleUserMessage( console.warn("[MessageHandler] 未登录,阻止发送"); // 保存待发送的消息 - await context.globalState.update('pendingMessage', { + await context.globalState.update("pendingMessage", { text, mode, serviceTier, - timestamp: Date.now() + timestamp: Date.now(), }); // 显示弹窗提示 const action = await vscode.window.showWarningMessage( - '请先登录后再发送消息', - '立即登录' + "请先登录后再发送消息", + "立即登录", ); - if (action === '立即登录') { + if (action === "立即登录") { vscode.commands.executeCommand("ic-coder.login", { forceReauth: true, }); @@ -110,24 +116,24 @@ export async function handleUserMessage( console.warn("[MessageHandler] Token 已过期,阻止发送"); // 保存待发送的消息 - await context.globalState.update('pendingMessage', { + await context.globalState.update("pendingMessage", { text, mode, serviceTier, - timestamp: Date.now() + timestamp: Date.now(), }); // 清除过期的 session - await context.globalState.update('icCoderSessions', []); - await context.globalState.update('icCoderUserInfo', undefined); + await context.globalState.update("icCoderSessions", []); + await context.globalState.update("icCoderUserInfo", undefined); // 显示弹窗提示 const action = await vscode.window.showWarningMessage( - '登录已过期,请重新登录', - '立即登录' + "登录已过期,请重新登录", + "立即登录", ); - if (action === '立即登录') { + if (action === "立即登录") { vscode.commands.executeCommand("ic-coder.login", { forceReauth: true, }); @@ -190,11 +196,11 @@ export async function handleUserMessage( // 显示错误提示 const selection = await vscode.window.showWarningMessage( balanceCheck.message || "资源点余额不足", - "去充值" + "去充值", ); if (selection === "去充值") { vscode.env.openExternal( - vscode.Uri.parse("https://iccoder.com/memberCenter") + vscode.Uri.parse("https://iccoder.com/memberCenter"), ); } // 恢复输入状态 @@ -216,14 +222,14 @@ export async function handleUserMessage( mode, undefined, serviceTier, - contextItems + contextItems, ); return; } catch (error) { - console.error("后端服务不可用:", error); + console.error("当前访问人数过多,请稍后重试:", error); panel.webview.postMessage({ command: "updateStatus", - text: "后端服务不可用", + text: "当前访问人数过多,请稍后重试", type: "error", }); // 恢复输入状态 @@ -254,7 +260,7 @@ async function handleUserMessageWithBackend( mode?: RunMode, reuseTaskId?: string, // 可选,复用现有 taskId(用于 Plan 模式确认后继续执行) serviceTier?: ServiceTier, // 服务等级参数 - contextItems?: Array<{ id: number; type: string; path: string }> // 上下文项参数 + contextItems?: Array<{ id: number; type: string; path: string }>, // 上下文项参数 ): Promise { const historyManager = ChatHistoryManager.getInstance(); @@ -262,7 +268,7 @@ async function handleUserMessageWithBackend( let enhancedText = text; if (contextItems && contextItems.length > 0) { console.log("[MessageHandler] 处理上下文项:", contextItems.length); - const paths = contextItems.map(item => item.path).join('\n'); + const paths = contextItems.map((item) => item.path).join("\n"); enhancedText = `${paths}\n\n${text}`; } @@ -273,7 +279,7 @@ async function handleUserMessageWithBackend( // 创建会话(dialogManager 会自动处理旧会话的中止) currentSession = dialogManager.createSession( extensionPath, - taskIdToUse || undefined + taskIdToUse || undefined, ); // 保存 taskId 用于后续操作(如压缩) lastTaskId = currentSession.getTaskId(); @@ -281,7 +287,7 @@ async function handleUserMessageWithBackend( "[MessageHandler] 创建会话: taskId=", lastTaskId, "来源=", - taskIdToUse ? "historyManager" : "新生成" + taskIdToUse ? "historyManager" : "新生成", ); // 显示状态栏 @@ -324,7 +330,10 @@ async function handleUserMessageWithBackend( // 工具错误,不需要单独处理,通过 onSegmentUpdate 统一更新 }, - onQuestion: (askId: string, questions: import("../types/api").QuestionItem[]) => { + onQuestion: ( + askId: string, + questions: import("../types/api").QuestionItem[], + ) => { // 只更新状态栏,问题显示由 onSegmentUpdate 统一处理 panel.webview.postMessage({ command: "updateStatus", @@ -379,18 +388,21 @@ async function handleUserMessageWithBackend( // 发送系统通知 - AI 响应完成 const notificationService = NotificationService.getInstance(); notificationService.success( - 'IC Coder - AI 响应完成', - '您的问题已得到回复,点击查看详情', + "IC Coder - AI 响应完成", + "您的问题已得到回复,点击查看详情", () => { // 点击通知时聚焦到面板 panel.reveal(); - } + }, ); // 发送代码变更到前端 sendChangesToWebview(panel); } catch (error) { - console.warn("[MessageHandler] 更新面板失败(面板可能已关闭):", error); + console.warn( + "[MessageHandler] 更新面板失败(面板可能已关闭):", + error, + ); } resolve(); @@ -458,7 +470,7 @@ async function handleUserMessageWithBackend( }, }, mode, - serviceTier // 传递服务等级 + serviceTier, // 传递服务等级 ); }); } @@ -470,7 +482,7 @@ export async function handleUserAnswer( askId: string, selected?: string[], customInput?: string, - answers?: { [questionIndex: string]: string[] } + answers?: { [questionIndex: string]: string[] }, ): Promise { if (currentSession) { await currentSession.submitAnswer(askId, selected, customInput, answers); @@ -540,7 +552,7 @@ export async function handlePlanAction( action: string, planTitle: string, extensionPath: string, - serviceTier?: ServiceTier + serviceTier?: ServiceTier, ): Promise { console.log( "[handlePlanAction] action:", @@ -548,7 +560,7 @@ export async function handlePlanAction( "planTitle:", planTitle, "serviceTier:", - serviceTier + serviceTier, ); switch (action) { @@ -564,7 +576,7 @@ export async function handlePlanAction( `请按照刚才的计划执行:${planTitle}`, extensionPath, "agent", - serviceTier + serviceTier, ); break; @@ -581,7 +593,7 @@ export async function handlePlanAction( `请根据以下建议修改计划:${modification}`, extensionPath, "plan", - serviceTier + serviceTier, ); } break; @@ -636,7 +648,7 @@ function parseFileOperation(text: string): { // 匹配重命名文件:将 xxx.ts 重命名为 yyy.ts 或 把 xxx.ts 改名为 yyy.ts(优先匹配,避免被修改匹配) const renameMatch = lowerText.match( - /(?:将|把)\s*(.+?\.\w+)\s*(?:重命名|改名)\s*(?:为|成)\s*(.+?\.\w+)/ + /(?:将|把)\s*(.+?\.\w+)\s*(?:重命名|改名)\s*(?:为|成)\s*(.+?\.\w+)/, ); if (renameMatch) { const oldPath = renameMatch[1].trim(); @@ -653,7 +665,7 @@ function parseFileOperation(text: string): { // 格式2: 将 xxx.ts 文件 "aaa" 替换为 "bbb" // 格式3: 将 xxx.ts 文件 'aaa' 替换为 'bbb' const replaceMatch1 = lowerText.match( - /在\s*(.+?\.\w+)\s*(?:文件)?中?\s*(?:将|把)\s*["'](.+?)["']\s*替换\s*(?:为|成)\s*["'](.+?)["']/ + /在\s*(.+?\.\w+)\s*(?:文件)?中?\s*(?:将|把)\s*["'](.+?)["']\s*替换\s*(?:为|成)\s*["'](.+?)["']/, ); if (replaceMatch1) { const filePath = replaceMatch1[1].trim(); @@ -669,7 +681,7 @@ function parseFileOperation(text: string): { // 格式2: 将 xxx.ts 文件 "aaa" 替换为 "bbb" const replaceMatch2 = lowerText.match( - /(?:将|把)\s*(.+?\.\w+)\s*(?:文件)?\s*["'](.+?)["']\s*替换\s*(?:为|成)\s*["'](.+?)["']/ + /(?:将|把)\s*(.+?\.\w+)\s*(?:文件)?\s*["'](.+?)["']\s*替换\s*(?:为|成)\s*["'](.+?)["']/, ); if (replaceMatch2) { const filePath = replaceMatch2[1].trim(); @@ -718,7 +730,7 @@ async function handleFileOperation( newPath?: string; searchText?: string; replaceText?: string; - } + }, ) { const historyManager = ChatHistoryManager.getInstance(); @@ -734,7 +746,7 @@ async function handleFileOperation( text: responseText, }); vscode.window.showInformationMessage( - `文件创建成功: ${operation.filePath}` + `文件创建成功: ${operation.filePath}`, ); await historyManager.addAiMessage(responseText); break; @@ -747,7 +759,7 @@ async function handleFileOperation( text: responseText, }); vscode.window.showInformationMessage( - `文件删除成功: ${operation.filePath}` + `文件删除成功: ${operation.filePath}`, ); await historyManager.addAiMessage(responseText); break; @@ -783,7 +795,7 @@ async function handleFileOperation( text: responseText, }); vscode.window.showInformationMessage( - `文件重命名成功: ${operation.filePath} → ${operation.newPath}` + `文件重命名成功: ${operation.filePath} → ${operation.newPath}`, ); await historyManager.addAiMessage(responseText); break; @@ -792,21 +804,29 @@ async function handleFileOperation( if (!operation.searchText || !operation.replaceText) { throw new Error("缺少替换内容"); } - const oldContentBeforeReplace = await readFileContent(operation.filePath); + const oldContentBeforeReplace = await readFileContent( + operation.filePath, + ); await replaceFile( operation.filePath, operation.searchText, - operation.replaceText + operation.replaceText, + ); + const newContentAfterReplace = await readFileContent( + operation.filePath, + ); + await trackFileChange( + operation.filePath, + oldContentBeforeReplace, + newContentAfterReplace, ); - const newContentAfterReplace = await readFileContent(operation.filePath); - await trackFileChange(operation.filePath, oldContentBeforeReplace, newContentAfterReplace); responseText = `✅ 文件内容替换成功: ${operation.filePath}`; panel.webview.postMessage({ command: "receiveMessage", text: responseText, }); vscode.window.showInformationMessage( - `文件内容替换成功: ${operation.filePath}` + `文件内容替换成功: ${operation.filePath}`, ); await historyManager.addAiMessage(responseText); break; @@ -866,7 +886,7 @@ function getDefaultContent(filePath: string): string { */ export async function handleReadFile( panel: vscode.WebviewPanel, - filePath: string + filePath: string, ) { try { const content = await readFileContent(filePath); @@ -890,7 +910,7 @@ export async function handleCreateFile( panel: vscode.WebviewPanel, filePath: string, content: string, - overwrite: boolean = false //是否覆盖 + overwrite: boolean = false, //是否覆盖 ) { try { if (overwrite) { @@ -909,11 +929,14 @@ export async function handleCreateFile( // 发送系统通知 const notificationService = NotificationService.getInstance(); notificationService.success( - 'IC Coder - 文件创建', + "IC Coder - 文件创建", `文件已创建: ${path.basename(filePath)}`, () => { - vscode.commands.executeCommand('vscode.open', vscode.Uri.file(filePath)); - } + vscode.commands.executeCommand( + "vscode.open", + vscode.Uri.file(filePath), + ); + }, ); } catch (error) { panel.webview.postMessage({ @@ -921,7 +944,7 @@ export async function handleCreateFile( error: error instanceof Error ? error.message : "创建文件失败", }); vscode.window.showErrorMessage( - `创建文件失败: ${error instanceof Error ? error.message : "未知错误"}` + `创建文件失败: ${error instanceof Error ? error.message : "未知错误"}`, ); } } @@ -932,7 +955,7 @@ export async function handleCreateFile( export async function handleUpdateFile( panel: vscode.WebviewPanel, filePath: string, - content: string + content: string, ) { try { const oldContent = await readFileContent(filePath); @@ -948,8 +971,8 @@ export async function handleUpdateFile( // 发送系统通知 const notificationService = NotificationService.getInstance(); notificationService.info( - 'IC Coder - 文件更新', - `文件已更新: ${path.basename(filePath)}` + "IC Coder - 文件更新", + `文件已更新: ${path.basename(filePath)}`, ); } catch (error) { panel.webview.postMessage({ @@ -957,7 +980,7 @@ export async function handleUpdateFile( error: error instanceof Error ? error.message : "更新文件失败", }); vscode.window.showErrorMessage( - `更新文件失败: ${error instanceof Error ? error.message : "未知错误"}` + `更新文件失败: ${error instanceof Error ? error.message : "未知错误"}`, ); } } @@ -968,7 +991,7 @@ export async function handleUpdateFile( export async function handleRenameFile( panel: vscode.WebviewPanel, oldPath: string, - newPath: string + newPath: string, ) { try { await renameFile(oldPath, newPath); @@ -979,7 +1002,7 @@ export async function handleRenameFile( message: "文件重命名成功", }); vscode.window.showInformationMessage( - `文件重命名成功: ${oldPath} → ${newPath}` + `文件重命名成功: ${oldPath} → ${newPath}`, ); } catch (error) { panel.webview.postMessage({ @@ -987,7 +1010,7 @@ export async function handleRenameFile( error: error instanceof Error ? error.message : "重命名文件失败", }); vscode.window.showErrorMessage( - `重命名文件失败: ${error instanceof Error ? error.message : "未知错误"}` + `重命名文件失败: ${error instanceof Error ? error.message : "未知错误"}`, ); } } @@ -999,7 +1022,7 @@ export async function handleReplaceInFile( panel: vscode.WebviewPanel, filePath: string, searchText: string, - replaceText: string + replaceText: string, ) { try { const oldContent = await readFileContent(filePath); @@ -1018,7 +1041,7 @@ export async function handleReplaceInFile( error: error instanceof Error ? error.message : "替换文件内容失败", }); vscode.window.showErrorMessage( - `替换文件内容失败: ${error instanceof Error ? error.message : "未知错误"}` + `替换文件内容失败: ${error instanceof Error ? error.message : "未知错误"}`, ); } } @@ -1063,7 +1086,7 @@ function isVCDGenerationCommand(text: string): boolean { */ async function handleVCDGeneration( panel: vscode.WebviewPanel, - extensionPath: string + extensionPath: string, ) { try { // 获取当前工作区路径 @@ -1090,7 +1113,7 @@ async function handleVCDGeneration( if (!iverilogCheck.available) { panel.webview.postMessage({ command: "receiveMessage", - text: `❌ ${iverilogCheck.message}\n\n请参考插件文档安装 iverilog 工具。`, + text: `❌ ${iverilogCheck.message}。`, }); vscode.window.showErrorMessage(iverilogCheck.message); return; @@ -1165,12 +1188,15 @@ async function handleVCDGeneration( // 发送系统通知 const notificationService = NotificationService.getInstance(); notificationService.success( - 'IC Coder - 仿真完成', + "IC Coder - 仿真完成", `VCD 文件已生成: ${fileName}`, () => { // 点击通知时打开 VCD 查看器 - vscode.commands.executeCommand('ic-coder.openVCDViewer', result.vcdFilePath); - } + vscode.commands.executeCommand( + "ic-coder.openVCDViewer", + result.vcdFilePath, + ); + }, ); } else { panel.webview.postMessage({ @@ -1199,12 +1225,12 @@ async function handleVCDGeneration( // 发送系统通知 const notificationService = NotificationService.getInstance(); notificationService.error( - 'IC Coder - 仿真失败', - 'VCD 文件生成失败,请查看错误信息', + "IC Coder - 仿真失败", + "VCD 文件生成失败,请查看错误信息", () => { // 点击通知时聚焦到面板 panel.reveal(); - } + }, ); } } catch (error) { @@ -1222,11 +1248,11 @@ async function handleVCDGeneration( // 发送系统通知 const notificationService = NotificationService.getInstance(); notificationService.error( - 'IC Coder - 仿真错误', - error instanceof Error ? error.message : '生成 VCD 文件时出错', + "IC Coder - 仿真错误", + error instanceof Error ? error.message : "生成 VCD 文件时出错", () => { panel.reveal(); - } + }, ); } } @@ -1236,7 +1262,7 @@ async function handleVCDGeneration( */ export async function handleOptimizePrompt( panel: vscode.WebviewPanel, - prompt: string + prompt: string, ): Promise { console.log("[MessageHandler] ========== 收到提示词优化请求 =========="); console.log("[MessageHandler] prompt:", prompt); @@ -1268,7 +1294,7 @@ export async function handleOptimizePrompt( */ export async function handleAcceptChange( panel: vscode.WebviewPanel, - changeId: string + changeId: string, ) { try { const success = await changeTracker.acceptChange(changeId); @@ -1276,14 +1302,14 @@ export async function handleAcceptChange( panel.webview.postMessage({ command: "changeAccepted", changeId: changeId, - success: true + success: true, }); } else { panel.webview.postMessage({ command: "changeAccepted", changeId: changeId, success: false, - error: "采纳变更失败" + error: "采纳变更失败", }); } } catch (error) { @@ -1292,7 +1318,7 @@ export async function handleAcceptChange( command: "changeAccepted", changeId: changeId, success: false, - error: String(error) + error: String(error), }); } } @@ -1302,7 +1328,7 @@ export async function handleAcceptChange( */ export async function handleRejectChange( panel: vscode.WebviewPanel, - changeId: string + changeId: string, ) { try { const success = await changeTracker.rejectChange(changeId); @@ -1310,14 +1336,14 @@ export async function handleRejectChange( panel.webview.postMessage({ command: "changeRejected", changeId: changeId, - success: true + success: true, }); } else { panel.webview.postMessage({ command: "changeRejected", changeId: changeId, success: false, - error: "拒绝变更失败" + error: "拒绝变更失败", }); } } catch (error) { @@ -1326,7 +1352,7 @@ export async function handleRejectChange( command: "changeRejected", changeId: changeId, success: false, - error: String(error) + error: String(error), }); } } @@ -1337,18 +1363,18 @@ export async function handleRejectChange( export function sendChangesToWebview(panel: vscode.WebviewPanel) { const session = changeTracker.endSession(); if (session && session.changes.length > 0) { - const changesWithDiff = session.changes.map(change => { + const changesWithDiff = session.changes.map((change) => { const diffLines = generateDiff(change.oldContent, change.newContent); const diffHtml = renderDiffHtml(diffLines); return { ...change, - diffHtml + diffHtml, }; }); panel.webview.postMessage({ command: "showChanges", - changes: changesWithDiff + changes: changesWithDiff, }); } } @@ -1365,62 +1391,67 @@ export function startChangeSession(sessionId: string) { */ export async function handleOpenFileDiff( panel: vscode.WebviewPanel, - changeId: string + changeId: string, ) { try { const session = changeTracker.getCurrentSession(); if (!session) { - vscode.window.showErrorMessage('没有找到变更会话'); + vscode.window.showErrorMessage("没有找到变更会话"); return; } - const change = session.changes.find(c => c.changeId === changeId); + const change = session.changes.find((c) => c.changeId === changeId); if (!change) { - vscode.window.showErrorMessage('没有找到该变更'); + vscode.window.showErrorMessage("没有找到该变更"); return; } const workspaceFolder = vscode.workspace.workspaceFolders?.[0]; if (!workspaceFolder) { - vscode.window.showErrorMessage('没有打开的工作区'); + vscode.window.showErrorMessage("没有打开的工作区"); return; } // 创建临时文件用于对比 const filePath = change.filePath; const absolutePath = vscode.Uri.file( - path.join(workspaceFolder.uri.fsPath, filePath) + path.join(workspaceFolder.uri.fsPath, filePath), ); // 创建虚拟文档显示旧内容 const oldUri = vscode.Uri.parse( - `ic-coder-diff:${filePath}.old?${changeId}` - ).with({ scheme: 'ic-coder-diff' }); + `ic-coder-diff:${filePath}.old?${changeId}`, + ).with({ scheme: "ic-coder-diff" }); // 注册文档内容提供者(如果还没注册) if (!(global as any).__diffProviderRegistered) { - const provider = new (class implements vscode.TextDocumentContentProvider { + 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 || ''; + const change = session?.changes.find((c) => c.changeId === changeId); + return change?.oldContent || ""; } })(); - vscode.workspace.registerTextDocumentContentProvider('ic-coder-diff', provider); + vscode.workspace.registerTextDocumentContentProvider( + "ic-coder-diff", + provider, + ); (global as any).__diffProviderRegistered = true; } // 打开 diff 编辑器 await vscode.commands.executeCommand( - 'vscode.diff', + "vscode.diff", oldUri, absolutePath, - `${filePath} (变更对比)` + `${filePath} (变更对比)`, ); } catch (error) { - console.error('[MessageHandler] 打开 diff 失败:', error); + console.error("[MessageHandler] 打开 diff 失败:", error); vscode.window.showErrorMessage(`打开 diff 失败: ${error}`); } }