From 49b3e341018e431690308d94ecd6959656d4cfa1 Mon Sep 17 00:00:00 2001 From: Roe-xin Date: Thu, 11 Dec 2025 14:29:56 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E5=AE=9E=E7=8E=B0=E8=AF=BB=E5=8F=96?= =?UTF-8?q?=E6=9C=AC=E5=9C=B0=E6=96=87=E4=BB=B6=E7=9A=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 4 +- src/panels/ICHelperPanel.ts | 7 +- src/utils/messageHandler.ts | 23 ++++ src/utils/readFiles.ts | 164 +++++++++++++++++++++++++ src/{utils => views}/webviewContent.ts | 124 ++++++++++++++++++- 5 files changed, 315 insertions(+), 7 deletions(-) create mode 100644 src/utils/readFiles.ts rename src/{utils => views}/webviewContent.ts (55%) diff --git a/package.json b/package.json index 893b45c..a5c0010 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "engines": { "vscode": "^1.106.3" }, - "icon": "media/IC Coder主页标志.png", + "icon": "media/ICCoder主页标志.png", "categories": [ "Other" ], @@ -52,7 +52,7 @@ "ic-coder-sidebar": [ { "id": "ic-coder.mainView", - "name": "IC 助手", + "name": "IC Coder", "type": "webview" } ] diff --git a/src/panels/ICHelperPanel.ts b/src/panels/ICHelperPanel.ts index d0224e0..d849dbc 100644 --- a/src/panels/ICHelperPanel.ts +++ b/src/panels/ICHelperPanel.ts @@ -1,6 +1,6 @@ import * as vscode from "vscode"; -import { getWebviewContent } from "../utils/webviewContent"; -import { handleUserMessage, insertCodeToEditor } from "../utils/messageHandler"; +import { getWebviewContent } from "../views/webviewContent"; +import { handleUserMessage, insertCodeToEditor, handleReadFile } from "../utils/messageHandler"; /** * 创建并显示 IC 助手面板 @@ -27,6 +27,9 @@ export function showICHelperPanel(context: vscode.ExtensionContext) { case "sendMessage": handleUserMessage(panel, message.text); break; + case "readFile": + handleReadFile(panel, message.filePath); + break; case "insertCode": insertCodeToEditor(message.code); break; diff --git a/src/utils/messageHandler.ts b/src/utils/messageHandler.ts index 19389f2..e2909c7 100644 --- a/src/utils/messageHandler.ts +++ b/src/utils/messageHandler.ts @@ -1,4 +1,5 @@ import * as vscode from "vscode"; +import { readFileContent } from "./readFiles"; /** * 处理用户消息 @@ -16,6 +17,28 @@ export function handleUserMessage(panel: vscode.WebviewPanel, text: string) { }, 500); } +/** + * 处理文件读取请求 + */ +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 : "读取文件失败", + }); + } +} + /** * 获取模拟回复 */ diff --git a/src/utils/readFiles.ts b/src/utils/readFiles.ts new file mode 100644 index 0000000..2ef5b3c --- /dev/null +++ b/src/utils/readFiles.ts @@ -0,0 +1,164 @@ +import * as vscode from "vscode"; +import * as fs from "fs"; +import * as path from "path"; + +/** + * 读取文件内容 + */ +export async function readFileContent(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); + } + } + + // 检查文件是否存在 + if (!fs.existsSync(absolutePath)) { + throw new Error(`文件不存在: ${absolutePath}`); + } + + // 检查是否是文件 + const stats = fs.statSync(absolutePath); + if (!stats.isFile()) { + throw new Error(`路径不是文件: ${absolutePath}`); + } + + // 读取文件内容 + const content = fs.readFileSync(absolutePath, "utf-8"); + return content; + } catch (error) { + throw error; + } +} + +/** + * 读取多个文件内容 + */ +export async function readMultipleFiles( + filePaths: string[] +): Promise<{ path: string; content: string; error?: string }[]> { + const results = []; + + for (const filePath of filePaths) { + try { + const content = await readFileContent(filePath); + results.push({ path: filePath, content }); + } catch (error) { + results.push({ + path: filePath, + content: "", + error: error instanceof Error ? error.message : "未知错误", + }); + } + } + + return results; +} + +/** + * 读取目录下所有文件 + */ +export async function readDirectory( + dirPath: string, + extensions?: string[] +): Promise<{ path: string; content: string }[]> { + 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); + } + } + + // 检查目录是否存在 + if (!fs.existsSync(absolutePath)) { + throw new Error(`目录不存在: ${absolutePath}`); + } + + const stats = fs.statSync(absolutePath); + if (!stats.isDirectory()) { + throw new Error(`路径不是目录: ${absolutePath}`); + } + + // 读取目录内容 + const files = fs.readdirSync(absolutePath); + const results = []; + + for (const file of files) { + const filePath = path.join(absolutePath, file); + const fileStats = fs.statSync(filePath); + + if (fileStats.isFile()) { + // 如果指定了扩展名过滤 + if (extensions && extensions.length > 0) { + const ext = path.extname(file); + if (!extensions.includes(ext)) { + continue; + } + } + + try { + const content = fs.readFileSync(filePath, "utf-8"); + results.push({ path: file, content }); + } catch (error) { + // 跳过无法读取的文件 + continue; + } + } + } + + return results; + } catch (error) { + throw error; + } +} + +/** + * 获取文件信息 + */ +export function getFileInfo(filePath: string): { + exists: boolean; + isFile: boolean; + isDirectory: boolean; + size?: number; + extension?: string; +} { + 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); + } + } + + if (!fs.existsSync(absolutePath)) { + return { + exists: false, + isFile: false, + isDirectory: false, + }; + } + + const stats = fs.statSync(absolutePath); + return { + exists: true, + isFile: stats.isFile(), + isDirectory: stats.isDirectory(), + size: stats.size, + extension: path.extname(absolutePath), + }; + } catch (error) { + return { + exists: false, + isFile: false, + isDirectory: false, + }; + } +} diff --git a/src/utils/webviewContent.ts b/src/views/webviewContent.ts similarity index 55% rename from src/utils/webviewContent.ts rename to src/views/webviewContent.ts index d893e63..ddf7b2a 100644 --- a/src/utils/webviewContent.ts +++ b/src/views/webviewContent.ts @@ -7,7 +7,7 @@ export function getWebviewContent(): string { - IC Coder 助手 + IC Coder @@ -104,6 +153,22 @@ export function getWebviewContent(): string {

专注于真实FPGA研发的Verilog智能体编程平台

+
+

📁 文件读取

+
+ + +
+
+ 文件内容将在这里显示... +
+ +
+
@@ -133,6 +198,9 @@ export function getWebviewContent(): string { const vscode = acquireVsCodeApi(); const messagesEl = document.getElementById('messages'); const messageInput = document.getElementById('messageInput'); + const filePathInput = document.getElementById('filePathInput'); + const fileContentEl = document.getElementById('fileContent'); + const errorMessageEl = document.getElementById('errorMessage'); function sendMessage() { const text = messageInput.value.trim(); @@ -144,6 +212,39 @@ export function getWebviewContent(): string { messageInput.focus(); } + function readFile() { + const filePath = filePathInput.value.trim(); + if (!filePath) { + showError('请输入文件路径'); + return; + } + + // 清空之前的内容和错误 + fileContentEl.textContent = '正在读取文件...'; + fileContentEl.className = 'file-content'; + errorMessageEl.style.display = 'none'; + + // 发送读取文件请求 + vscode.postMessage({ command: 'readFile', filePath: filePath }); + } + + function showError(message) { + errorMessageEl.textContent = message; + errorMessageEl.className = 'error-message'; + errorMessageEl.style.display = 'block'; + fileContentEl.textContent = '文件内容将在这里显示...'; + fileContentEl.className = 'file-content empty'; + } + + function displayFileContent(content, filePath) { + fileContentEl.textContent = content; + fileContentEl.className = 'file-content'; + errorMessageEl.style.display = 'none'; + + // 在消息区域也显示一条提示 + addMessage(\`已读取文件: \${filePath}\`, 'bot'); + } + function quickAction(type) { const questions = { counter: '生成一个4位同步计数器', @@ -165,8 +266,25 @@ export function getWebviewContent(): string { } window.addEventListener('message', event => { - if (event.data.command === 'receiveMessage') { - addMessage(event.data.text, 'bot'); + const message = event.data; + + switch (message.command) { + case 'receiveMessage': + addMessage(message.text, 'bot'); + break; + case 'fileContent': + displayFileContent(message.content, message.filePath); + break; + case 'fileError': + showError(message.error); + break; + } + }); + + // 支持回车键读取文件 + filePathInput.addEventListener('keydown', (event) => { + if (event.key === 'Enter') { + readFile(); } });