fix: 优化后端服务不可用时的错误处理,移除本地模拟回复逻辑
This commit is contained in:
@ -19,7 +19,7 @@ import { dialogManager, DialogSession } from "../services/dialogService";
|
|||||||
import { userInteractionManager } from "../services/userInteraction";
|
import { userInteractionManager } from "../services/userInteraction";
|
||||||
import { healthCheck } from "../services/apiClient";
|
import { healthCheck } from "../services/apiClient";
|
||||||
|
|
||||||
import type { RunMode } from '../types/api';
|
import type { RunMode } from "../types/api";
|
||||||
|
|
||||||
/** 是否使用后端服务(可通过配置控制) */
|
/** 是否使用后端服务(可通过配置控制) */
|
||||||
let useBackendService = true;
|
let useBackendService = true;
|
||||||
@ -32,7 +32,7 @@ let pendingPlanExecution: {
|
|||||||
panel: vscode.WebviewPanel;
|
panel: vscode.WebviewPanel;
|
||||||
planTitle: string;
|
planTitle: string;
|
||||||
extensionPath: string;
|
extensionPath: string;
|
||||||
taskId: string; // 保存 taskId 以便复用
|
taskId: string; // 保存 taskId 以便复用
|
||||||
} | null = null;
|
} | null = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -45,7 +45,7 @@ export function setPendingPlanExecution(
|
|||||||
taskId: string
|
taskId: string
|
||||||
): void {
|
): void {
|
||||||
pendingPlanExecution = { panel, planTitle, extensionPath, taskId };
|
pendingPlanExecution = { panel, planTitle, extensionPath, taskId };
|
||||||
console.log('[MessageHandler] 设置待执行计划:', planTitle, 'taskId:', taskId);
|
console.log("[MessageHandler] 设置待执行计划:", planTitle, "taskId:", taskId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -90,29 +90,22 @@ export async function handleUserMessage(
|
|||||||
await handleUserMessageWithBackend(panel, text, extensionPath, mode);
|
await handleUserMessageWithBackend(panel, text, extensionPath, mode);
|
||||||
return;
|
return;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("后端服务不可用,回退到本地模式:", error);
|
console.error("后端服务不可用:", error);
|
||||||
// 后端不可用时,使用本地模拟回复
|
panel.webview.postMessage({
|
||||||
|
command: "updateStatus",
|
||||||
|
text: "后端服务不可用",
|
||||||
|
type: "error",
|
||||||
|
});
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 本地模拟回复(后端不可用时的 fallback)
|
// 如果没有 extensionPath,显示错误
|
||||||
console.log("使用本地模拟回复");
|
panel.webview.postMessage({
|
||||||
const reply = getMockReply(text);
|
command: "updateStatus",
|
||||||
|
text: "无法处理消息:缺少必要参数",
|
||||||
// 记录AI回复到历史(允许失败)
|
type: "error",
|
||||||
try {
|
});
|
||||||
const historyManager = ChatHistoryManager.getInstance();
|
|
||||||
await historyManager.addAiMessage(reply);
|
|
||||||
} catch (error) {
|
|
||||||
console.warn("记录AI回复历史失败:", error);
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
panel.webview.postMessage({
|
|
||||||
command: "receiveMessage",
|
|
||||||
text: reply,
|
|
||||||
});
|
|
||||||
}, 500);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -123,13 +116,13 @@ async function handleUserMessageWithBackend(
|
|||||||
text: string,
|
text: string,
|
||||||
extensionPath: string,
|
extensionPath: string,
|
||||||
mode?: RunMode,
|
mode?: RunMode,
|
||||||
reuseTaskId?: string // 可选,复用现有 taskId(用于 Plan 模式确认后继续执行)
|
reuseTaskId?: string // 可选,复用现有 taskId(用于 Plan 模式确认后继续执行)
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
// 创建或复用会话
|
// 创建或复用会话
|
||||||
if (!currentSession || !currentSession.active) {
|
if (!currentSession || !currentSession.active) {
|
||||||
currentSession = dialogManager.createSession(extensionPath, reuseTaskId);
|
currentSession = dialogManager.createSession(extensionPath, reuseTaskId);
|
||||||
if (reuseTaskId) {
|
if (reuseTaskId) {
|
||||||
console.log('[MessageHandler] 复用 taskId 创建会话:', reuseTaskId);
|
console.log("[MessageHandler] 复用 taskId 创建会话:", reuseTaskId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,117 +136,134 @@ async function handleUserMessageWithBackend(
|
|||||||
});
|
});
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
currentSession!.sendMessage(text, {
|
currentSession!.sendMessage(
|
||||||
onText: (fullText, isStreaming) => {
|
text,
|
||||||
// 不再单独处理文本,统一通过 onSegmentUpdate 处理
|
{
|
||||||
|
onText: (fullText, isStreaming) => {
|
||||||
|
// 不再单独处理文本,统一通过 onSegmentUpdate 处理
|
||||||
|
},
|
||||||
|
|
||||||
|
onSegmentUpdate: (segments) => {
|
||||||
|
// 实时发送段落更新,按后端返回顺序展示
|
||||||
|
panel.webview.postMessage({
|
||||||
|
command: "updateSegments",
|
||||||
|
segments: segments,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onToolStart: (toolName) => {
|
||||||
|
// 更新状态栏
|
||||||
|
panel.webview.postMessage({
|
||||||
|
command: "updateStatus",
|
||||||
|
text: `正在执行 ${toolName}...`,
|
||||||
|
type: "working",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onToolComplete: (toolName, result) => {
|
||||||
|
// 工具完成,不需要单独处理,通过 onSegmentUpdate 统一更新
|
||||||
|
},
|
||||||
|
|
||||||
|
onToolError: (toolName, error) => {
|
||||||
|
// 工具错误,不需要单独处理,通过 onSegmentUpdate 统一更新
|
||||||
|
},
|
||||||
|
|
||||||
|
onQuestion: (askId, question, options) => {
|
||||||
|
// 只更新状态栏,问题显示由 onSegmentUpdate 统一处理
|
||||||
|
panel.webview.postMessage({
|
||||||
|
command: "updateStatus",
|
||||||
|
text: "等待用户回答...",
|
||||||
|
type: "working",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onComplete: async (segments) => {
|
||||||
|
// 隐藏状态栏
|
||||||
|
panel.webview.postMessage({
|
||||||
|
command: "hideStatus",
|
||||||
|
});
|
||||||
|
|
||||||
|
// 最后一次发送完整的段落
|
||||||
|
console.log("[MessageHandler] 对话完成, 段落数:", segments.length);
|
||||||
|
console.log(
|
||||||
|
"[MessageHandler] segments 内容:",
|
||||||
|
JSON.stringify(segments)
|
||||||
|
);
|
||||||
|
|
||||||
|
const result = await panel.webview.postMessage({
|
||||||
|
command: "updateSegments",
|
||||||
|
segments: segments,
|
||||||
|
isComplete: true,
|
||||||
|
});
|
||||||
|
console.log("[MessageHandler] postMessage 返回值:", result);
|
||||||
|
|
||||||
|
// 保存完整的 segments 到历史记录
|
||||||
|
try {
|
||||||
|
// 将完整的 segments 保存到一条 AI 消息中
|
||||||
|
// 这样加载时可以完整还原对话样式
|
||||||
|
const textContent = segments
|
||||||
|
.filter((s) => s.type === "text" && s.content)
|
||||||
|
.map((s) => s.content)
|
||||||
|
.join("\n");
|
||||||
|
|
||||||
|
await historyManager.addAiMessage(textContent, undefined, segments);
|
||||||
|
} catch (error) {
|
||||||
|
console.warn("保存AI响应历史失败:", error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否有待执行的计划(Plan 模式确认后自动执行)
|
||||||
|
if (pendingPlanExecution) {
|
||||||
|
const {
|
||||||
|
panel: execPanel,
|
||||||
|
planTitle,
|
||||||
|
extensionPath: execPath,
|
||||||
|
taskId: reuseTaskId,
|
||||||
|
} = pendingPlanExecution;
|
||||||
|
pendingPlanExecution = null;
|
||||||
|
console.log(
|
||||||
|
"[MessageHandler] 自动执行计划:",
|
||||||
|
planTitle,
|
||||||
|
"复用 taskId:",
|
||||||
|
reuseTaskId
|
||||||
|
);
|
||||||
|
|
||||||
|
// 延迟一小段时间确保当前对话完全结束
|
||||||
|
setTimeout(async () => {
|
||||||
|
try {
|
||||||
|
// 复用 taskId 创建新会话,确保知识图谱数据不丢失
|
||||||
|
await handleUserMessageWithBackend(
|
||||||
|
execPanel,
|
||||||
|
`请按照刚才的计划执行:${planTitle}`,
|
||||||
|
execPath,
|
||||||
|
"agent",
|
||||||
|
reuseTaskId // 复用 Plan 模式的 taskId
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
console.error("[MessageHandler] 自动执行计划失败:", err);
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
},
|
||||||
|
|
||||||
|
onError: (message) => {
|
||||||
|
panel.webview.postMessage({
|
||||||
|
command: "hideLoading",
|
||||||
|
});
|
||||||
|
panel.webview.postMessage({
|
||||||
|
command: "receiveMessage",
|
||||||
|
text: `❌ 错误: ${message}`,
|
||||||
|
});
|
||||||
|
reject(new Error(message));
|
||||||
|
},
|
||||||
|
|
||||||
|
onNotification: (message) => {
|
||||||
|
vscode.window.showInformationMessage(message);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
mode
|
||||||
onSegmentUpdate: (segments) => {
|
);
|
||||||
// 实时发送段落更新,按后端返回顺序展示
|
|
||||||
panel.webview.postMessage({
|
|
||||||
command: "updateSegments",
|
|
||||||
segments: segments,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
onToolStart: (toolName) => {
|
|
||||||
// 更新状态栏
|
|
||||||
panel.webview.postMessage({
|
|
||||||
command: "updateStatus",
|
|
||||||
text: `正在执行 ${toolName}...`,
|
|
||||||
type: "working",
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
onToolComplete: (toolName, result) => {
|
|
||||||
// 工具完成,不需要单独处理,通过 onSegmentUpdate 统一更新
|
|
||||||
},
|
|
||||||
|
|
||||||
onToolError: (toolName, error) => {
|
|
||||||
// 工具错误,不需要单独处理,通过 onSegmentUpdate 统一更新
|
|
||||||
},
|
|
||||||
|
|
||||||
onQuestion: (askId, question, options) => {
|
|
||||||
// 只更新状态栏,问题显示由 onSegmentUpdate 统一处理
|
|
||||||
panel.webview.postMessage({
|
|
||||||
command: "updateStatus",
|
|
||||||
text: "等待用户回答...",
|
|
||||||
type: "working",
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
onComplete: async (segments) => {
|
|
||||||
// 隐藏状态栏
|
|
||||||
panel.webview.postMessage({
|
|
||||||
command: "hideStatus",
|
|
||||||
});
|
|
||||||
|
|
||||||
// 最后一次发送完整的段落
|
|
||||||
console.log('[MessageHandler] 对话完成, 段落数:', segments.length);
|
|
||||||
console.log('[MessageHandler] segments 内容:', JSON.stringify(segments));
|
|
||||||
|
|
||||||
const result = await panel.webview.postMessage({
|
|
||||||
command: "updateSegments",
|
|
||||||
segments: segments,
|
|
||||||
isComplete: true,
|
|
||||||
});
|
|
||||||
console.log('[MessageHandler] postMessage 返回值:', result);
|
|
||||||
|
|
||||||
// 保存完整的 segments 到历史记录
|
|
||||||
try {
|
|
||||||
// 将完整的 segments 保存到一条 AI 消息中
|
|
||||||
// 这样加载时可以完整还原对话样式
|
|
||||||
const textContent = segments
|
|
||||||
.filter(s => s.type === 'text' && s.content)
|
|
||||||
.map(s => s.content)
|
|
||||||
.join('\n');
|
|
||||||
|
|
||||||
await historyManager.addAiMessage(textContent, undefined, segments);
|
|
||||||
} catch (error) {
|
|
||||||
console.warn("保存AI响应历史失败:", error);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查是否有待执行的计划(Plan 模式确认后自动执行)
|
|
||||||
if (pendingPlanExecution) {
|
|
||||||
const { panel: execPanel, planTitle, extensionPath: execPath, taskId: reuseTaskId } = pendingPlanExecution;
|
|
||||||
pendingPlanExecution = null;
|
|
||||||
console.log('[MessageHandler] 自动执行计划:', planTitle, '复用 taskId:', reuseTaskId);
|
|
||||||
|
|
||||||
// 延迟一小段时间确保当前对话完全结束
|
|
||||||
setTimeout(async () => {
|
|
||||||
try {
|
|
||||||
// 复用 taskId 创建新会话,确保知识图谱数据不丢失
|
|
||||||
await handleUserMessageWithBackend(
|
|
||||||
execPanel,
|
|
||||||
`请按照刚才的计划执行:${planTitle}`,
|
|
||||||
execPath,
|
|
||||||
'agent',
|
|
||||||
reuseTaskId // 复用 Plan 模式的 taskId
|
|
||||||
);
|
|
||||||
} catch (err) {
|
|
||||||
console.error('[MessageHandler] 自动执行计划失败:', err);
|
|
||||||
}
|
|
||||||
}, 500);
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve();
|
|
||||||
},
|
|
||||||
|
|
||||||
onError: (message) => {
|
|
||||||
panel.webview.postMessage({
|
|
||||||
command: "hideLoading",
|
|
||||||
});
|
|
||||||
panel.webview.postMessage({
|
|
||||||
command: "receiveMessage",
|
|
||||||
text: `❌ 错误: ${message}`,
|
|
||||||
});
|
|
||||||
reject(new Error(message));
|
|
||||||
},
|
|
||||||
|
|
||||||
onNotification: (message) => {
|
|
||||||
vscode.window.showInformationMessage(message);
|
|
||||||
},
|
|
||||||
}, mode);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,52 +308,52 @@ export async function handlePlanAction(
|
|||||||
planTitle: string,
|
planTitle: string,
|
||||||
extensionPath: string
|
extensionPath: string
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
console.log('[handlePlanAction] action:', action, 'planTitle:', planTitle);
|
console.log("[handlePlanAction] action:", action, "planTitle:", planTitle);
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case 'confirm':
|
case "confirm":
|
||||||
// 确认执行:切换到 Agent 模式并发送执行消息
|
// 确认执行:切换到 Agent 模式并发送执行消息
|
||||||
panel.webview.postMessage({
|
panel.webview.postMessage({
|
||||||
command: 'switchMode',
|
command: "switchMode",
|
||||||
mode: 'agent'
|
mode: "agent",
|
||||||
});
|
});
|
||||||
// 发送执行消息
|
// 发送执行消息
|
||||||
await handleUserMessage(
|
await handleUserMessage(
|
||||||
panel,
|
panel,
|
||||||
`请按照刚才的计划执行:${planTitle}`,
|
`请按照刚才的计划执行:${planTitle}`,
|
||||||
extensionPath,
|
extensionPath,
|
||||||
'agent'
|
"agent"
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'modify':
|
case "modify":
|
||||||
// 修改计划:提示用户输入修改建议
|
// 修改计划:提示用户输入修改建议
|
||||||
const modification = await vscode.window.showInputBox({
|
const modification = await vscode.window.showInputBox({
|
||||||
prompt: '请输入您对计划的修改建议',
|
prompt: "请输入您对计划的修改建议",
|
||||||
placeHolder: '例如:第2步需要先检查文件是否存在...',
|
placeHolder: "例如:第2步需要先检查文件是否存在...",
|
||||||
ignoreFocusOut: true
|
ignoreFocusOut: true,
|
||||||
});
|
});
|
||||||
if (modification) {
|
if (modification) {
|
||||||
await handleUserMessage(
|
await handleUserMessage(
|
||||||
panel,
|
panel,
|
||||||
`请根据以下建议修改计划:${modification}`,
|
`请根据以下建议修改计划:${modification}`,
|
||||||
extensionPath,
|
extensionPath,
|
||||||
'plan'
|
"plan"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'cancel':
|
case "cancel":
|
||||||
// 取消计划:通知用户
|
// 取消计划:通知用户
|
||||||
panel.webview.postMessage({
|
panel.webview.postMessage({
|
||||||
command: 'addMessage',
|
command: "addMessage",
|
||||||
text: '计划已取消。',
|
text: "计划已取消。",
|
||||||
sender: 'bot'
|
sender: "bot",
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
console.warn('[handlePlanAction] 未知操作:', action);
|
console.warn("[handlePlanAction] 未知操作:", action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -382,7 +392,9 @@ function parseFileOperation(text: string): {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 匹配重命名文件:将 xxx.ts 重命名为 yyy.ts 或 把 xxx.ts 改名为 yyy.ts(优先匹配,避免被修改匹配)
|
// 匹配重命名文件:将 xxx.ts 重命名为 yyy.ts 或 把 xxx.ts 改名为 yyy.ts(优先匹配,避免被修改匹配)
|
||||||
const renameMatch = lowerText.match(/(?:将|把)\s*(.+?\.\w+)\s*(?:重命名|改名)\s*(?:为|成)\s*(.+?\.\w+)/);
|
const renameMatch = lowerText.match(
|
||||||
|
/(?:将|把)\s*(.+?\.\w+)\s*(?:重命名|改名)\s*(?:为|成)\s*(.+?\.\w+)/
|
||||||
|
);
|
||||||
if (renameMatch) {
|
if (renameMatch) {
|
||||||
const oldPath = renameMatch[1].trim();
|
const oldPath = renameMatch[1].trim();
|
||||||
const newPath = renameMatch[2].trim();
|
const newPath = renameMatch[2].trim();
|
||||||
@ -397,7 +409,9 @@ function parseFileOperation(text: string): {
|
|||||||
// 格式1: 在 xxx.ts 中将 "aaa" 替换为 "bbb"
|
// 格式1: 在 xxx.ts 中将 "aaa" 替换为 "bbb"
|
||||||
// 格式2: 将 xxx.ts 文件 "aaa" 替换为 "bbb"
|
// 格式2: 将 xxx.ts 文件 "aaa" 替换为 "bbb"
|
||||||
// 格式3: 将 xxx.ts 文件 'aaa' 替换为 'bbb'
|
// 格式3: 将 xxx.ts 文件 'aaa' 替换为 'bbb'
|
||||||
const replaceMatch1 = lowerText.match(/在\s*(.+?\.\w+)\s*(?:文件)?中?\s*(?:将|把)\s*["'](.+?)["']\s*替换\s*(?:为|成)\s*["'](.+?)["']/);
|
const replaceMatch1 = lowerText.match(
|
||||||
|
/在\s*(.+?\.\w+)\s*(?:文件)?中?\s*(?:将|把)\s*["'](.+?)["']\s*替换\s*(?:为|成)\s*["'](.+?)["']/
|
||||||
|
);
|
||||||
if (replaceMatch1) {
|
if (replaceMatch1) {
|
||||||
const filePath = replaceMatch1[1].trim();
|
const filePath = replaceMatch1[1].trim();
|
||||||
const searchText = replaceMatch1[2].trim();
|
const searchText = replaceMatch1[2].trim();
|
||||||
@ -411,7 +425,9 @@ function parseFileOperation(text: string): {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 格式2: 将 xxx.ts 文件 "aaa" 替换为 "bbb"
|
// 格式2: 将 xxx.ts 文件 "aaa" 替换为 "bbb"
|
||||||
const replaceMatch2 = lowerText.match(/(?:将|把)\s*(.+?\.\w+)\s*(?:文件)?\s*["'](.+?)["']\s*替换\s*(?:为|成)\s*["'](.+?)["']/);
|
const replaceMatch2 = lowerText.match(
|
||||||
|
/(?:将|把)\s*(.+?\.\w+)\s*(?:文件)?\s*["'](.+?)["']\s*替换\s*(?:为|成)\s*["'](.+?)["']/
|
||||||
|
);
|
||||||
if (replaceMatch2) {
|
if (replaceMatch2) {
|
||||||
const filePath = replaceMatch2[1].trim();
|
const filePath = replaceMatch2[1].trim();
|
||||||
const searchText = replaceMatch2[2].trim();
|
const searchText = replaceMatch2[2].trim();
|
||||||
@ -739,41 +755,6 @@ export async function handleReplaceInFile(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取模拟回复
|
|
||||||
*/
|
|
||||||
function getMockReply(question: string): string {
|
|
||||||
const replies = [
|
|
||||||
`已收到您的问题:"${question}"
|
|
||||||
|
|
||||||
这是一个演示版本,实际需要连接AI服务。
|
|
||||||
|
|
||||||
示例回复:这是一个计数器模板:
|
|
||||||
\`\`\`verilog
|
|
||||||
module counter (
|
|
||||||
input clk,
|
|
||||||
input rst_n,
|
|
||||||
output reg [3:0] count
|
|
||||||
);
|
|
||||||
always @(posedge clk or negedge rst_n) begin
|
|
||||||
if (!rst_n) count <= 0;
|
|
||||||
else count <= count + 1;
|
|
||||||
end
|
|
||||||
endmodule
|
|
||||||
\`\`\``,
|
|
||||||
|
|
||||||
`感谢提问!关于"${question}",在真实版本中我会:
|
|
||||||
1. 分析您的代码上下文
|
|
||||||
2. 提供优化建议
|
|
||||||
3. 生成完整代码
|
|
||||||
4. 解释设计原理
|
|
||||||
|
|
||||||
当前是演示版,请点击侧边栏按钮快速生成代码。`,
|
|
||||||
];
|
|
||||||
|
|
||||||
return replies[Math.floor(Math.random() * replies.length)];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将代码插入到编辑器
|
* 将代码插入到编辑器
|
||||||
*/
|
*/
|
||||||
@ -866,7 +847,8 @@ async function handleVCDGeneration(
|
|||||||
|
|
||||||
if (!projectCheck.hasTestbench) {
|
if (!projectCheck.hasTestbench) {
|
||||||
errorMsg += "• ❌ 缺少 testbench 文件\n";
|
errorMsg += "• ❌ 缺少 testbench 文件\n";
|
||||||
errorMsg += "\n提示: testbench 文件应包含 $dumpfile 和 $dumpvars 语句来生成 VCD 文件。\n";
|
errorMsg +=
|
||||||
|
"\n提示: testbench 文件应包含 $dumpfile 和 $dumpvars 语句来生成 VCD 文件。\n";
|
||||||
} else {
|
} else {
|
||||||
errorMsg += `• ✅ Testbench: ${projectCheck.testbenchFile}\n`;
|
errorMsg += `• ✅ Testbench: ${projectCheck.testbenchFile}\n`;
|
||||||
}
|
}
|
||||||
@ -910,9 +892,7 @@ async function handleVCDGeneration(
|
|||||||
fileName: fileName,
|
fileName: fileName,
|
||||||
});
|
});
|
||||||
|
|
||||||
vscode.window.showInformationMessage(
|
vscode.window.showInformationMessage(`VCD 文件生成成功: ${fileName}`);
|
||||||
`VCD 文件生成成功: ${fileName}`
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
panel.webview.postMessage({
|
panel.webview.postMessage({
|
||||||
command: "receiveMessage",
|
command: "receiveMessage",
|
||||||
|
|||||||
Reference in New Issue
Block a user