Files
IC-Coder-Plugin/src/utils/messageHandler.ts
Roe-xin 94225a3525 feat:对本地文件进行修改
- 对某一行进行修改
- 将文件中的某些词进行替换
- 将文件重命名
2025-12-12 09:57:33 +08:00

469 lines
12 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import * as vscode from "vscode";
import { readFileContent } from "./readFiles";
import {
createFile,
createOrOverwriteFile,
deleteFile,
updateFile,
renameFile,
replaceFile,
} from "./createFiles";
/**
* 处理用户消息
*/
export async function handleUserMessage(
panel: vscode.WebviewPanel,
text: string
) {
console.log("收到用户消息:", text);
// 检查是否是文件操作命令
const fileOperation = parseFileOperation(text);
console.log("解析结果:", fileOperation);
if (fileOperation) {
console.log("执行文件操作:", fileOperation.type, fileOperation.filePath);
await handleFileOperation(panel, fileOperation);
return;
}
// 普通消息处理
console.log("作为普通消息处理");
const reply = getMockReply(text);
setTimeout(() => {
panel.webview.postMessage({
command: "receiveMessage",
text: reply,
});
}, 500);
}
/**
* 解析文件操作命令
*/
function parseFileOperation(text: string): {
type: "create" | "delete" | "read" | "update" | "rename" | "replace";
filePath: string;
content?: string;
newPath?: string;
searchText?: string;
replaceText?: string;
} | null {
const lowerText = text.toLowerCase().trim();
// 匹配创建文件:创建一个 xxx.ts 文件
const createMatch = lowerText.match(/创建(?:一个)?(.+?\.\w+)(?:文件)?/);
if (createMatch) {
const filePath = createMatch[1].trim();
return {
type: "create",
filePath: filePath,
content: getDefaultContent(filePath),
};
}
// 匹配删除文件:删除 xxx.ts 文件
const deleteMatch = lowerText.match(/删除(.+?\.\w+)(?:文件)?/);
if (deleteMatch) {
const filePath = deleteMatch[1].trim();
return {
type: "delete",
filePath: filePath,
};
}
// 匹配重命名文件:将 xxx.ts 重命名为 yyy.ts 或 把 xxx.ts 改名为 yyy.ts优先匹配避免被修改匹配
const renameMatch = lowerText.match(/(?:将|把)\s*(.+?\.\w+)\s*(?:重命名|改名)\s*(?:为|成)\s*(.+?\.\w+)/);
if (renameMatch) {
const oldPath = renameMatch[1].trim();
const newPath = renameMatch[2].trim();
return {
type: "rename",
filePath: oldPath,
newPath: newPath,
};
}
// 匹配替换内容:支持多种格式
// 格式1: 在 xxx.ts 中将 "aaa" 替换为 "bbb"
// 格式2: 将 xxx.ts 文件 "aaa" 替换为 "bbb"
// 格式3: 将 xxx.ts 文件 'aaa' 替换为 'bbb'
const replaceMatch1 = lowerText.match(/在\s*(.+?\.\w+)\s*(?:文件)?中?\s*(?:将|把)\s*["'](.+?)["']\s*替换\s*(?:为|成)\s*["'](.+?)["']/);
if (replaceMatch1) {
const filePath = replaceMatch1[1].trim();
const searchText = replaceMatch1[2].trim();
const replaceText = replaceMatch1[3].trim();
return {
type: "replace",
filePath: filePath,
searchText: searchText,
replaceText: replaceText,
};
}
// 格式2: 将 xxx.ts 文件 "aaa" 替换为 "bbb"
const replaceMatch2 = lowerText.match(/(?:将|把)\s*(.+?\.\w+)\s*(?:文件)?\s*["'](.+?)["']\s*替换\s*(?:为|成)\s*["'](.+?)["']/);
if (replaceMatch2) {
const filePath = replaceMatch2[1].trim();
const searchText = replaceMatch2[2].trim();
const replaceText = replaceMatch2[3].trim();
return {
type: "replace",
filePath: filePath,
searchText: searchText,
replaceText: replaceText,
};
}
// 匹配读取文件:读取 xxx.ts 文件 或 打开 xxx.ts
const readMatch = lowerText.match(/(?:读取|打开)\s*(.+?\.\w+)\s*(?:文件)?/);
if (readMatch) {
const filePath = readMatch[1].trim();
return {
type: "read",
filePath: filePath,
};
}
// 匹配修改文件:修改 xxx.ts 文件(放在最后,避免误匹配)
const updateMatch = lowerText.match(/修改\s*(.+?\.\w+)\s*(?:文件)?/);
if (updateMatch) {
const filePath = updateMatch[1].trim();
return {
type: "update",
filePath: filePath,
};
}
return null;
}
/**
* 处理文件操作
*/
async function handleFileOperation(
panel: vscode.WebviewPanel,
operation: {
type: "create" | "delete" | "read" | "update" | "rename" | "replace";
filePath: string;
content?: string;
newPath?: string;
searchText?: string;
replaceText?: string;
}
) {
try {
switch (operation.type) {
case "create":
await createFile(operation.filePath, operation.content || "");
panel.webview.postMessage({
command: "receiveMessage",
text: `✅ 文件创建成功: ${operation.filePath}`,
});
vscode.window.showInformationMessage(
`文件创建成功: ${operation.filePath}`
);
break;
case "delete":
await deleteFile(operation.filePath);
panel.webview.postMessage({
command: "receiveMessage",
text: `✅ 文件删除成功: ${operation.filePath}`,
});
vscode.window.showInformationMessage(
`文件删除成功: ${operation.filePath}`
);
break;
case "read":
const content = await readFileContent(operation.filePath);
panel.webview.postMessage({
command: "fileContent",
content: content,
filePath: operation.filePath,
});
break;
case "update":
const currentContent = await readFileContent(operation.filePath);
panel.webview.postMessage({
command: "editFile",
content: currentContent,
filePath: operation.filePath,
});
break;
case "rename":
if (!operation.newPath) {
throw new Error("缺少新文件名");
}
await renameFile(operation.filePath, operation.newPath);
panel.webview.postMessage({
command: "receiveMessage",
text: `✅ 文件重命名成功: ${operation.filePath}${operation.newPath}`,
});
vscode.window.showInformationMessage(
`文件重命名成功: ${operation.filePath}${operation.newPath}`
);
break;
case "replace":
if (!operation.searchText || !operation.replaceText) {
throw new Error("缺少替换内容");
}
await replaceFile(
operation.filePath,
operation.searchText,
operation.replaceText
);
panel.webview.postMessage({
command: "receiveMessage",
text: `✅ 文件内容替换成功: ${operation.filePath}`,
});
vscode.window.showInformationMessage(
`文件内容替换成功: ${operation.filePath}`
);
break;
}
} catch (error) {
const errorMsg = error instanceof Error ? error.message : "操作失败";
panel.webview.postMessage({
command: "receiveMessage",
text: `${errorMsg}`,
});
vscode.window.showErrorMessage(errorMsg);
}
}
/**
* 根据文件扩展名生成默认内容
*/
function getDefaultContent(filePath: string): string {
const ext = filePath.split(".").pop()?.toLowerCase();
switch (ext) {
case "ts":
return `// ${filePath}\n\nexport {};\n`;
case "js":
return `// ${filePath}\n\n`;
case "json":
return "{\n \n}\n";
case "md":
return `# ${filePath}\n\n`;
case "html":
return `<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
</body>
</html>`;
case "css":
return `/* ${filePath} */\n\n`;
case "v":
case "sv":
return `// ${filePath}\n\nmodule ${
filePath.split(".")[0]
} (\n \n);\n\nendmodule\n`;
default:
return "";
}
}
/**
* 处理文件读取请求
*/
export async function handleReadFile(
panel: vscode.WebviewPanel,
filePath: string
) {
try {
const content = await readFileContent(filePath);
panel.webview.postMessage({
command: "fileContent",
content: content,
filePath: filePath,
});
} catch (error) {
panel.webview.postMessage({
command: "fileError",
error: error instanceof Error ? error.message : "读取文件失败",
});
}
}
/**
* 处理文件创建请求
*/
export async function handleCreateFile(
panel: vscode.WebviewPanel,
filePath: string,
content: string,
overwrite: boolean = false //是否覆盖
) {
try {
if (overwrite) {
await createOrOverwriteFile(filePath, content);
} else {
await createFile(filePath, content);
}
panel.webview.postMessage({
command: "fileCreated",
filePath: filePath,
message: " 文件创建成功",
});
vscode.window.showInformationMessage(`文件创建成功: ${filePath}`);
} catch (error) {
panel.webview.postMessage({
command: "fileCreateError",
error: error instanceof Error ? error.message : "创建文件失败",
});
vscode.window.showErrorMessage(
`创建文件失败: ${error instanceof Error ? error.message : "未知错误"}`
);
}
}
/**
* 处理文件更新请求
*/
export async function handleUpdateFile(
panel: vscode.WebviewPanel,
filePath: string,
content: string
) {
try {
await updateFile(filePath, content);
panel.webview.postMessage({
command: "fileUpdated",
filePath: filePath,
message: " 文件更新成功",
});
vscode.window.showInformationMessage(`文件更新成功: ${filePath}`);
} catch (error) {
panel.webview.postMessage({
command: "fileUpdateError",
error: error instanceof Error ? error.message : "更新文件失败",
});
vscode.window.showErrorMessage(
`更新文件失败: ${error instanceof Error ? error.message : "未知错误"}`
);
}
}
/**
* 处理文件重命名请求
*/
export async function handleRenameFile(
panel: vscode.WebviewPanel,
oldPath: string,
newPath: string
) {
try {
await renameFile(oldPath, newPath);
panel.webview.postMessage({
command: "fileRenamed",
oldPath: oldPath,
newPath: newPath,
message: "文件重命名成功",
});
vscode.window.showInformationMessage(
`文件重命名成功: ${oldPath}${newPath}`
);
} catch (error) {
panel.webview.postMessage({
command: "fileRenameError",
error: error instanceof Error ? error.message : "重命名文件失败",
});
vscode.window.showErrorMessage(
`重命名文件失败: ${error instanceof Error ? error.message : "未知错误"}`
);
}
}
/**
* 处理文件内容替换请求
*/
export async function handleReplaceInFile(
panel: vscode.WebviewPanel,
filePath: string,
searchText: string,
replaceText: string
) {
try {
await replaceFile(filePath, searchText, replaceText);
panel.webview.postMessage({
command: "fileReplaced",
filePath: filePath,
message: "文件内容替换成功",
});
vscode.window.showInformationMessage(`文件内容替换成功: ${filePath}`);
} catch (error) {
panel.webview.postMessage({
command: "fileReplaceError",
error: error instanceof Error ? error.message : "替换文件内容失败",
});
vscode.window.showErrorMessage(
`替换文件内容失败: ${error instanceof Error ? error.message : "未知错误"}`
);
}
}
/**
* 获取模拟回复
*/
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)];
}
/**
* 将代码插入到编辑器
*/
export function insertCodeToEditor(code: string) {
const editor = vscode.window.activeTextEditor;
if (editor) {
editor.edit((editBuilder) => {
editBuilder.insert(editor.selection.active, code);
});
vscode.window.showInformationMessage("代码已插入");
} else {
vscode.window.showWarningMessage("请先打开一个编辑器");
}
}