Merge branch 'feat/plugin-initialization' into feat/back-to-front

This commit is contained in:
Roe-xin
2025-12-17 10:07:08 +08:00
6 changed files with 1454 additions and 48 deletions

View File

@ -8,18 +8,22 @@ import {
handleRenameFile,
handleReplaceInFile,
handleUserAnswer,
abortCurrentDialog
abortCurrentDialog,
} from "../utils/messageHandler";
import { VCDViewerPanel } from "./VCDViewerPanel";
/**
* 创建并显示 IC 助手面板
*/
export function showICHelperPanel(context: vscode.ExtensionContext) {
export function showICHelperPanel(
context: vscode.ExtensionContext,
viewColumn?: vscode.ViewColumn
) {
// 创建WebView面板
const panel = vscode.window.createWebviewPanel(
"icCoder", // 面板ID
"IC Coder", // 面板标题
vscode.ViewColumn.Beside, // 显示在旁边
viewColumn || vscode.ViewColumn.Beside, // 默认显示在旁边,但可以指定
{
enableScripts: true,
retainContextWhenHidden: true,
@ -28,7 +32,11 @@ export function showICHelperPanel(context: vscode.ExtensionContext) {
);
// 设置标签页图标
panel.iconPath = vscode.Uri.joinPath(context.extensionUri, "media", "图案(方底).png");
panel.iconPath = vscode.Uri.joinPath(
context.extensionUri,
"media",
"图案(方底).png"
);
// 获取页面内图标URI
const iconUri = panel.webview.asWebviewUri(
@ -55,7 +63,12 @@ export function showICHelperPanel(context: vscode.ExtensionContext) {
handleRenameFile(panel, message.oldPath, message.newPath);
break;
case "replaceInFile":
handleReplaceInFile(panel, message.filePath, message.searchText, message.replaceText);
handleReplaceInFile(
panel,
message.filePath,
message.searchText,
message.replaceText
);
break;
case "insertCode":
insertCodeToEditor(message.code);
@ -63,9 +76,42 @@ export function showICHelperPanel(context: vscode.ExtensionContext) {
case "showInfo":
vscode.window.showInformationMessage(message.text);
break;
case "openWaveformViewer":
// 打开波形查看器
if (message.vcdFilePath) {
VCDViewerPanel.createOrShow(
context.extensionUri,
message.vcdFilePath
);
}
break;
case "getVCDInfo":
// 获取 VCD 文件信息
if (message.vcdFilePath && message.containerId) {
getVCDFileInfo(panel, message.vcdFilePath, message.containerId);
}
break;
case "createNewConversation":
// 创建新会话 - 在当前编辑器组中打开新标签页
showICHelperPanel(context, panel.viewColumn);
break;
case "loadConversationHistory":
// 加载会话历史(暂未实现)
panel.webview.postMessage({
command: "conversationHistory",
history: [],
});
break;
case "selectConversation":
// 选择会话(暂未实现)
break;
// 新增:处理用户回答
case "submitAnswer":
handleUserAnswer(message.askId, message.selected, message.customInput);
handleUserAnswer(
message.askId,
message.selected,
message.customInput
);
break;
// 新增:中止对话
case "abortDialog":
@ -77,3 +123,182 @@ export function showICHelperPanel(context: vscode.ExtensionContext) {
context.subscriptions
);
}
/**
* 获取 VCD 文件信息
*/
async function getVCDFileInfo(
panel: vscode.WebviewPanel,
vcdFilePath: string,
containerId: string
) {
try {
const fs = require("fs");
const path = require("path");
// 检查文件是否存在
if (!fs.existsSync(vcdFilePath)) {
panel.webview.postMessage({
command: "vcdInfo",
containerId: containerId,
vcdInfo: {
signalCount: "N/A",
timeRange: "N/A",
fileSize: "N/A",
error: "文件不存在",
},
});
return;
}
// 获取文件大小
const stats = fs.statSync(vcdFilePath);
const fileSizeKB = stats.size / 1024;
const fileSize =
fileSizeKB < 1024
? `${fileSizeKB.toFixed(2)} KB`
: `${(fileSizeKB / 1024).toFixed(2)} MB`;
// 读取 VCD 文件内容
const content = fs.readFileSync(vcdFilePath, "utf-8");
// 解析信号数量
const varMatches = content.match(/\$var/g);
const signalCount = varMatches ? varMatches.length : 0;
// 解析时间范围
let timeRange = "N/A";
const timeMatch = content.match(/#(\d+)/g);
if (timeMatch && timeMatch.length > 0) {
const times = timeMatch.map((t: string) => parseInt(t.substring(1)));
const minTime = Math.min(...times);
const maxTime = Math.max(...times);
timeRange = `${minTime} - ${maxTime}`;
}
// 解析前几个信号的真实数据
const signals = parseVCDSignals(content, 3); // 只解析前3个信号
// 发送信息回前端
panel.webview.postMessage({
command: "vcdInfo",
containerId: containerId,
vcdInfo: {
signalCount: signalCount.toString(),
timeRange: timeRange,
fileSize: fileSize,
signals: signals, // 添加真实信号数据
},
});
} catch (error) {
console.error("获取 VCD 文件信息失败:", error);
panel.webview.postMessage({
command: "vcdInfo",
containerId: containerId,
vcdInfo: {
signalCount: "N/A",
timeRange: "N/A",
fileSize: "N/A",
error: error instanceof Error ? error.message : "未知错误",
},
});
}
}
/**
* 解析 VCD 文件中的信号数据
*/
function parseVCDSignals(content: string, maxSignals: number = 3) {
const signals: Array<{
name: string;
identifier: string;
width: number;
values: Array<{ time: number; value: string }>;
}> = [];
try {
// 1. 解析信号定义部分
const varRegex = /\$var\s+(\w+)\s+(\d+)\s+(\S+)\s+([^\$]+?)\s+\$end/g;
let match;
const signalDefs: Array<{
name: string;
identifier: string;
width: number;
}> = [];
while (
(match = varRegex.exec(content)) !== null &&
signalDefs.length < maxSignals
) {
const width = parseInt(match[2]);
const identifier = match[3];
const name = match[4].trim();
signalDefs.push({ name, identifier, width });
}
// 2. 找到数据变化部分的起始位置
const dumpvarsIndex = content.indexOf("$dumpvars");
if (dumpvarsIndex === -1) {
return signals;
}
const dataSection = content.substring(dumpvarsIndex);
// 3. 解析每个信号的值变化
for (const signalDef of signalDefs) {
const values: Array<{ time: number; value: string }> = [];
let currentTime = 0;
// 分行处理数据
const lines = dataSection.split("\n");
for (const line of lines) {
const trimmedLine = line.trim();
// 解析时间戳
if (trimmedLine.startsWith("#")) {
currentTime = parseInt(trimmedLine.substring(1));
continue;
}
// 解析信号值变化
// 格式1: 单比特信号 "0!" 或 "1!"
// 格式2: 多比特信号 "b1010 !"
if (signalDef.width === 1) {
// 单比特信号
const singleBitMatch = trimmedLine.match(
new RegExp(`^([01xz])${signalDef.identifier}$`)
);
if (singleBitMatch) {
values.push({ time: currentTime, value: singleBitMatch[1] });
}
} else {
// 多比特信号
const multiBitMatch = trimmedLine.match(
new RegExp(`^b([01xz]+)\\s+${signalDef.identifier}$`)
);
if (multiBitMatch) {
values.push({ time: currentTime, value: multiBitMatch[1] });
}
}
// 限制采样点数量,避免数据过多
if (values.length >= 50) {
break;
}
}
signals.push({
name: signalDef.name,
identifier: signalDef.identifier,
width: signalDef.width,
values: values,
});
}
} catch (error) {
console.error("解析 VCD 信号数据失败:", error);
}
return signals;
}