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