diff --git a/package.json b/package.json index a5c0010..3d1dc4f 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "engines": { "vscode": "^1.106.3" }, - "icon": "media/ICCoder主页标志.png", + "icon": "media/图案(方底).png", "categories": [ "Other" ], diff --git a/src/utils/createFiles.ts b/src/utils/createFiles.ts new file mode 100644 index 0000000..d992738 --- /dev/null +++ b/src/utils/createFiles.ts @@ -0,0 +1,196 @@ +import * as vscode from "vscode"; +import * as fs from "fs"; +import * as path from "path"; + +/** + * 创建文件(本来不存在的情况) + */ +export async function createFile( + filePath: string, + content: string = "" +): Promise { + try { + // 如果是相对路径,转换为绝对路径 + let absolutePath = filePath; + if (!path.isAbsolute(filePath)) { + const workspaceFolders = vscode.workspace.workspaceFolders; + if (workspaceFolders && workspaceFolders.length > 0) { + absolutePath = path.join(workspaceFolders[0].uri.fsPath, filePath); + } else { + throw new Error("没有打开的工作区,无法创建相对路径的文件"); + } + } + + // 检测文件是否已存在 + if (fs.existsSync(absolutePath)) { + throw new Error(`文件已存在: ${absolutePath}`); + } + + // 确保目录存在 + const dirPath = path.dirname(absolutePath); + if (!fs.existsSync(dirPath)) { + fs.mkdirSync(dirPath, { + recursive: true, + }); + } + + // 创建文件 + fs.writeFileSync(absolutePath, content, "utf-8"); + } catch (error) { + throw error; + } +} + +/** + * 创建文件(如果存在则覆盖) + */ +export async function createOrOverwriteFile( + filePath: string, + content: string = "" +): Promise { + try { + // 如果是相对路径,转换为绝对路径 + let absolutePath = filePath; + if (!path.isAbsolute(filePath)) { + const workspaceFolders = vscode.workspace.workspaceFolders; + if (workspaceFolders && workspaceFolders.length > 0) { + absolutePath = path.join(workspaceFolders[0].uri.fsPath, filePath); + } else { + throw new Error("没有打开的工作区,无法创建相对路径的文件"); + } + } + + // 确保目录存在 + const dirPath = path.dirname(absolutePath); + if (!fs.existsSync(dirPath)) { + fs.mkdirSync(dirPath, { + recursive: true, + }); + } + + // 创建或覆盖文件 + fs.writeFileSync(absolutePath, content, "utf-8"); + } catch (error) { + throw error; + } +} + +/** + * 创建目录 + */ +export async function createDirectory(dirPath: string): Promise { + try { + // 如果是相对路径,转换为绝对路径 + let absolutePath = dirPath; + if (!path.isAbsolute(dirPath)) { + const workspaceFolders = vscode.workspace.workspaceFolders; + if (workspaceFolders && workspaceFolders.length > 0) { + absolutePath = path.join(workspaceFolders[0].uri.fsPath, dirPath); + } else { + throw new Error("没有打开的工作区,无法创建相对路径的目录"); + } + } + + // 检测创建目录是否存在 + if (fs.existsSync(absolutePath)) { + const state = fs.statSync(absolutePath); + if (state.isDirectory()) { + throw new Error(`目录已存在: ${absolutePath}`); + } else { + throw new Error(`路径已存在且不是目录: ${absolutePath}`); + } + } + + // 创建目录 + fs.mkdirSync(absolutePath, { recursive: true }); + } catch (error) { + throw error; + } +} + +/** + * 批量创建文件 + */ +export async function createMultipleFiles( + files: { path: string; content: string }[] +): Promise<{ path: string; success: boolean; error?: string }[]> { + const results = []; + + for (const file of files) { + try { + await createFile(file.path, file.content); + results.push({ path: file.path, success: true }); + } catch (error) { + results.push({ + path: file.path, + success: false, + error: error instanceof Error ? error.message : "未知错误", + }); + } + } + + return results; +} + +/** + * 追加文件内容 + */ +export async function appendToFile( + filePath: string, + content: string +): Promise { + try { + // 如果是相对路径,转换为绝对路径 + let absolutePath = filePath; + if (!path.isAbsolute(filePath)) { + const workspaceFolders = vscode.workspace.workspaceFolders; + if (workspaceFolders && workspaceFolders.length > 0) { + absolutePath = path.join(workspaceFolders[0].uri.fsPath, filePath); + } else { + throw new Error("没有打开的工作区,无法追加相对路径的文件"); + } + } + + // 检查文件是否存在 + if (!fs.existsSync(absolutePath)) { + throw new Error(`文件不存在: ${absolutePath}`); + } + + // 追加内容 + fs.appendFileSync(absolutePath, content, "utf-8"); + } catch (error) { + throw error; + } +} + +// 删除文件 +export async function deleteFile(filePath: string): Promise { + try { + // 如果是相对路径,转换为绝对路径 + let absolutePath = filePath; + if (!path.isAbsolute(filePath)) { + const workspaceFolders = vscode.workspace.workspaceFolders; + if (workspaceFolders && workspaceFolders.length > 0) { + absolutePath = path.join(workspaceFolders[0].uri.fsPath, filePath); + } else { + throw new Error("没有打开的工作区,无法删除相对路径的文件"); + } + } + + // 检查文件是否存在 + if (!fs.existsSync(absolutePath)) { + throw new Error(`文件不存在: ${absolutePath}`); + } + + // 检查是否是文件 + const stats = fs.statSync(absolutePath); + if (!stats.isFile()) { + throw new Error(`路径不是文件: ${absolutePath}`); + } + + // 删除文件 + fs.unlinkSync(absolutePath); + } catch (error) { + throw error; + } +} diff --git a/src/utils/messageHandler.ts b/src/utils/messageHandler.ts index e2909c7..4390b90 100644 --- a/src/utils/messageHandler.ts +++ b/src/utils/messageHandler.ts @@ -1,14 +1,21 @@ import * as vscode from "vscode"; import { readFileContent } from "./readFiles"; +import { createFile, createOrOverwriteFile, deleteFile } from "./createFiles"; /** * 处理用户消息 */ -export function handleUserMessage(panel: vscode.WebviewPanel, text: string) { - // 模拟AI回复 - const reply = getMockReply(text); +export async function handleUserMessage(panel: vscode.WebviewPanel, text: string) { + // 检查是否是文件操作命令 + const fileOperation = parseFileOperation(text); - // 延迟回复,模拟AI思考 + if (fileOperation) { + await handleFileOperation(panel, fileOperation); + return; + } + + // 普通消息处理 + const reply = getMockReply(text); setTimeout(() => { panel.webview.postMessage({ command: "receiveMessage", @@ -17,6 +24,133 @@ export function handleUserMessage(panel: vscode.WebviewPanel, text: string) { }, 500); } +/** + * 解析文件操作命令 + */ +function parseFileOperation(text: string): { + type: 'create' | 'delete' | 'read'; + filePath: string; + content?: 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 文件 或 打开 xxx.ts + const readMatch = lowerText.match(/(?:读取|打开)(.+?\.\w+)(?:文件)?/); + if (readMatch) { + const filePath = readMatch[1].trim(); + return { + type: 'read', + filePath: filePath + }; + } + + return null; +} + +/** + * 处理文件操作 + */ +async function handleFileOperation( + panel: vscode.WebviewPanel, + operation: { type: 'create' | 'delete' | 'read'; filePath: string; content?: 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; + } + } 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 ` + + + + + Document + + + + +`; + case 'css': + return `/* ${filePath} */\n\n`; + case 'v': + case 'sv': + return `// ${filePath}\n\nmodule ${filePath.split('.')[0]} (\n \n);\n\nendmodule\n`; + default: + return ''; + } +} + /** * 处理文件读取请求 */ @@ -39,6 +173,39 @@ export async function handleReadFile( } } +/** + * 处理文件创建请求 + */ +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 : "未知错误"}` + ); + } +} + /** * 获取模拟回复 */ diff --git a/src/views/ICViewProvider.ts b/src/views/ICViewProvider.ts index 287e2f3..4bc4f1d 100644 --- a/src/views/ICViewProvider.ts +++ b/src/views/ICViewProvider.ts @@ -1,4 +1,72 @@ import * as vscode from "vscode"; +import { getWebviewContent } from "./webviewContent"; +import { + handleUserMessage, + insertCodeToEditor, + handleReadFile, + handleCreateFile, +} from "../utils/messageHandler"; + +/** + * 创建并显示IC 侧边栏视图 + */ +export function showICHelperPanel(content: vscode.ExtensionContext) { + // 创建WebView面板 + const panel = vscode.window.createWebviewPanel( + "icCoder", // 面板ID + "IC Coder", // 面板标题 + vscode.ViewColumn.Beside, // 显示在旁边 + { + enableScripts: true, + retainContextWhenHidden: true, + localResourceRoots: [vscode.Uri.joinPath(content.extensionUri, "media")], + } + ); + + // 设置标签页图标 + panel.iconPath = vscode.Uri.joinPath( + content.extensionUri, + "media", + "图案(方底).png" + ); + + // 获取页面内图标URI + const iconUri = panel.webview.asWebviewUri( + vscode.Uri.joinPath(content.extensionUri, "media", "图案(方底).png") + ); + // 设置HTML内容 + panel.webview.html = getWebviewContent(iconUri.toString()); + + // 处理消息 + panel.webview.onDidReceiveMessage( + (message) => { + switch (message.command) { + case "sendMessage": + handleUserMessage(panel, message.text); + break; + case "readFile": + handleReadFile(panel, message.filePath); + break; + case "insertCode": + insertCodeToEditor(message.code); + break; + case "createFile": + handleCreateFile( + panel, + message.filePath, + message.content, + message.overwrite + ); + break; + case "showInfo": + vscode.window.showInformationMessage(message.text); + break; + } + }, + undefined, + content.subscriptions + ); +} /** * 侧边栏视图提供者