diff --git a/src/utils/createFiles.ts b/src/utils/createFiles.ts index 18a1d2f..cf1d8a5 100644 --- a/src/utils/createFiles.ts +++ b/src/utils/createFiles.ts @@ -1,5 +1,4 @@ import * as vscode from "vscode"; -import * as fs from "fs"; import * as path from "path"; /** @@ -21,21 +20,31 @@ export async function createFile( } } + const fileUri = vscode.Uri.file(absolutePath); + // 检测文件是否已存在 - if (fs.existsSync(absolutePath)) { + try { + await vscode.workspace.fs.stat(fileUri); throw new Error(`文件已存在: ${absolutePath}`); + } catch (error: any) { + // 如果文件不存在,继续创建 + if (error.code !== 'FileNotFound') { + throw error; + } } // 确保目录存在 const dirPath = path.dirname(absolutePath); - if (!fs.existsSync(dirPath)) { - fs.mkdirSync(dirPath, { - recursive: true, - }); + const dirUri = vscode.Uri.file(dirPath); + try { + await vscode.workspace.fs.stat(dirUri); + } catch { + await vscode.workspace.fs.createDirectory(dirUri); } // 创建文件 - fs.writeFileSync(absolutePath, content, "utf-8"); + const contentBytes = Buffer.from(content, "utf-8"); + await vscode.workspace.fs.writeFile(fileUri, contentBytes); } catch (error) { throw error; } @@ -62,14 +71,17 @@ export async function createOrOverwriteFile( // 确保目录存在 const dirPath = path.dirname(absolutePath); - if (!fs.existsSync(dirPath)) { - fs.mkdirSync(dirPath, { - recursive: true, - }); + const dirUri = vscode.Uri.file(dirPath); + try { + await vscode.workspace.fs.stat(dirUri); + } catch { + await vscode.workspace.fs.createDirectory(dirUri); } // 创建或覆盖文件 - fs.writeFileSync(absolutePath, content, "utf-8"); + const fileUri = vscode.Uri.file(absolutePath); + const contentBytes = Buffer.from(content, "utf-8"); + await vscode.workspace.fs.writeFile(fileUri, contentBytes); } catch (error) { throw error; } @@ -91,18 +103,25 @@ export async function createDirectory(dirPath: string): Promise { } } + const dirUri = vscode.Uri.file(absolutePath); + // 检测创建目录是否存在 - if (fs.existsSync(absolutePath)) { - const state = fs.statSync(absolutePath); - if (state.isDirectory()) { + try { + const stat = await vscode.workspace.fs.stat(dirUri); + if (stat.type === vscode.FileType.Directory) { throw new Error(`目录已存在: ${absolutePath}`); } else { throw new Error(`路径已存在且不是目录: ${absolutePath}`); } + } catch (error: any) { + // 如果目录不存在,继续创建 + if (error.code !== 'FileNotFound') { + throw error; + } } // 创建目录 - fs.mkdirSync(absolutePath, { recursive: true }); + await vscode.workspace.fs.createDirectory(dirUri); } catch (error) { throw error; } @@ -146,19 +165,20 @@ export async function deleteFile(filePath: string): Promise { } } + const fileUri = vscode.Uri.file(absolutePath); + // 检查文件是否存在 - if (!fs.existsSync(absolutePath)) { + try { + const stat = await vscode.workspace.fs.stat(fileUri); + if (stat.type !== vscode.FileType.File) { + throw new Error(`路径不是文件: ${absolutePath}`); + } + } catch (error) { throw new Error(`文件不存在: ${absolutePath}`); } - // 检查是否是文件 - const stats = fs.statSync(absolutePath); - if (!stats.isFile()) { - throw new Error(`路径不是文件: ${absolutePath}`); - } - // 删除文件 - fs.unlinkSync(absolutePath); + await vscode.workspace.fs.delete(fileUri); } catch (error) { throw error; } @@ -181,19 +201,21 @@ export async function updateFile( } } + const fileUri = vscode.Uri.file(absolutePath); + // 检查文件是否存在 - if (!fs.existsSync(absolutePath)) { + try { + const stat = await vscode.workspace.fs.stat(fileUri); + if (stat.type !== vscode.FileType.File) { + throw new Error(`路径不是文件: ${absolutePath}`); + } + } catch (error) { throw new Error(`文件不存在: ${absolutePath}`); } - // 检查是否是文件内容 - const state = fs.statSync(absolutePath); - if (!state.isFile()) { - throw new Error(`路径不是文件: ${absolutePath}`); - } - // 修改文件内容 - fs.writeFileSync(absolutePath, content, "utf-8"); + const contentBytes = Buffer.from(content, "utf-8"); + await vscode.workspace.fs.writeFile(fileUri, contentBytes); } catch (error) { throw error; } @@ -218,13 +240,21 @@ export async function appendToFile( } } - // 检查文件是否存在 - if (!fs.existsSync(absolutePath)) { + const fileUri = vscode.Uri.file(absolutePath); + + // 检查文件是否存在并读取原内容 + let existingContent = ""; + try { + const contentBytes = await vscode.workspace.fs.readFile(fileUri); + existingContent = Buffer.from(contentBytes).toString("utf-8"); + } catch (error) { throw new Error(`文件不存在: ${absolutePath}`); } // 追加内容 - fs.appendFileSync(absolutePath, content, "utf-8"); + const newContent = existingContent + content; + const contentBytes = Buffer.from(newContent, "utf-8"); + await vscode.workspace.fs.writeFile(fileUri, contentBytes); } catch (error) { throw error; } @@ -248,13 +278,16 @@ export async function replaceFile( } } - // 检查文件是否存在 - if (!fs.existsSync(absolutePath)) { - throw new Error(`文件不存在: ${absolutePath}`); - } + const fileUri = vscode.Uri.file(absolutePath); // 读取文件内容 - const fileContent = fs.readFileSync(absolutePath, "utf-8"); + let fileContent: string; + try { + const contentBytes = await vscode.workspace.fs.readFile(fileUri); + fileContent = Buffer.from(contentBytes).toString("utf-8"); + } catch (error) { + throw new Error(`文件不存在: ${absolutePath}`); + } // 转义特殊字符,将字符串作为字面量处理 const escapeRegExp = (str: string) => { @@ -276,7 +309,8 @@ export async function replaceFile( } // 写回文件 - fs.writeFileSync(absolutePath, newContent, "utf-8"); + const contentBytes = Buffer.from(newContent, "utf-8"); + await vscode.workspace.fs.writeFile(fileUri, contentBytes); } catch (error) { throw error; } @@ -300,20 +334,26 @@ export async function insertAtLine( } } - // 检查文件是否存在 - if (!fs.existsSync(absolutePath)) { + const fileUri = vscode.Uri.file(absolutePath); + + // 读取文件内容 + let fileContent: string; + try { + const contentBytes = await vscode.workspace.fs.readFile(fileUri); + fileContent = Buffer.from(contentBytes).toString("utf-8"); + } catch (error) { throw new Error(`文件不存在: ${absolutePath}`); } - // 读取文件内容 - const fileContent = fs.readFileSync(absolutePath, "utf-8"); const lines = fileContent.split("\n"); // 插入内容 lines.splice(lineNumber, 0, content); // 写回文件 - fs.writeFileSync(absolutePath, lines.join("\n"), "utf-8"); + const newContent = lines.join("\n"); + const newContentBytes = Buffer.from(newContent, "utf-8"); + await vscode.workspace.fs.writeFile(fileUri, newContentBytes); } catch (error) { throw error; } @@ -345,24 +385,41 @@ export async function renameFile( throw new Error("没有打开的工作区,无法重命名相对路径的文件"); } + const oldUri = vscode.Uri.file(absoluteOldPath); + const newUri = vscode.Uri.file(absoluteNewPath); + // 检查原文件是否存在 - if (!fs.existsSync(absoluteOldPath)) { + try { + await vscode.workspace.fs.stat(oldUri); + } catch (error) { throw new Error(`文件不存在: ${absoluteOldPath}`); } // 检查新文件名是否已存在 - if (fs.existsSync(absoluteNewPath)) { + try { + await vscode.workspace.fs.stat(newUri); throw new Error(`目标文件已存在: ${absoluteNewPath}`); + } catch (error: any) { + // 如果文件不存在,继续重命名 + if (error.code !== 'FileNotFound' && !error.message.includes('目标文件已存在')) { + throw error; + } + if (error.message.includes('目标文件已存在')) { + throw error; + } } // 确保目标目录存在 const newDir = path.dirname(absoluteNewPath); - if (!fs.existsSync(newDir)) { - fs.mkdirSync(newDir, { recursive: true }); + const newDirUri = vscode.Uri.file(newDir); + try { + await vscode.workspace.fs.stat(newDirUri); + } catch { + await vscode.workspace.fs.createDirectory(newDirUri); } // 重命名文件 - fs.renameSync(absoluteOldPath, absoluteNewPath); + await vscode.workspace.fs.rename(oldUri, newUri, { overwrite: false }); } catch (error) { throw error; } diff --git a/src/utils/iverilogRunner.ts b/src/utils/iverilogRunner.ts index 40b5a76..84246e0 100644 --- a/src/utils/iverilogRunner.ts +++ b/src/utils/iverilogRunner.ts @@ -1,5 +1,4 @@ import * as vscode from "vscode"; -import * as fs from "fs"; import * as path from "path"; import { spawn } from "child_process"; import { promisify } from "util"; @@ -107,13 +106,16 @@ export async function checkVerilogProject( try { // 检查项目路径是否存在 - if (!fs.existsSync(projectPath)) { + const projectUri = vscode.Uri.file(projectPath); + try { + await vscode.workspace.fs.stat(projectUri); + } catch (error) { result.errors.push(`项目路径不存在: ${projectPath}`); return result; } // 查找所有 Verilog 文件 (.v, .sv) - const verilogFiles = findVerilogFiles(projectPath); + const verilogFiles = await findVerilogFiles(projectPath); result.allVerilogFiles = verilogFiles; if (verilogFiles.length === 0) { @@ -123,7 +125,9 @@ export async function checkVerilogProject( // 分析文件内容,查找 top module 和 testbench for (const file of verilogFiles) { - const content = fs.readFileSync(file, "utf-8"); + const fileUri = vscode.Uri.file(file); + const contentBytes = await vscode.workspace.fs.readFile(fileUri); + const content = Buffer.from(contentBytes).toString("utf-8"); const fileName = path.basename(file).toLowerCase(); // 检查是否是 testbench 文件 @@ -169,23 +173,23 @@ export async function checkVerilogProject( /** * 递归查找目录下所有 Verilog 文件 */ -function findVerilogFiles(dir: string): string[] { +async function findVerilogFiles(dir: string): Promise { const verilogFiles: string[] = []; - function searchDir(currentDir: string) { - const files = fs.readdirSync(currentDir); + async function searchDir(currentDir: string) { + const dirUri = vscode.Uri.file(currentDir); + const entries = await vscode.workspace.fs.readDirectory(dirUri); - for (const file of files) { - const filePath = path.join(currentDir, file); - const stat = fs.statSync(filePath); + for (const [fileName, fileType] of entries) { + const filePath = path.join(currentDir, fileName); - if (stat.isDirectory()) { + if (fileType === vscode.FileType.Directory) { // 跳过 node_modules 等目录 - if (!file.startsWith(".") && file !== "node_modules") { - searchDir(filePath); + if (!fileName.startsWith(".") && fileName !== "node_modules") { + await searchDir(filePath); } - } else if (stat.isFile()) { - const ext = path.extname(file).toLowerCase(); + } else if (fileType === vscode.FileType.File) { + const ext = path.extname(fileName).toLowerCase(); if (ext === ".v" || ext === ".sv") { verilogFiles.push(filePath); } @@ -193,14 +197,14 @@ function findVerilogFiles(dir: string): string[] { } } - searchDir(dir); + await searchDir(dir); return verilogFiles; } /** * 获取 iverilog 可执行文件路径 */ -function getIverilogPath(extensionPath: string): string { +async function getIverilogPath(extensionPath: string): Promise { const platform = process.platform; let iverilogBin = ""; @@ -214,17 +218,19 @@ function getIverilogPath(extensionPath: string): string { } // 如果插件包中没有,尝试使用系统安装的 iverilog - if (!fs.existsSync(iverilogBin)) { + const iverilogUri = vscode.Uri.file(iverilogBin); + try { + await vscode.workspace.fs.stat(iverilogUri); + return iverilogBin; + } catch { return "iverilog"; // 使用系统 PATH 中的 iverilog } - - return iverilogBin; } /** * 获取 vvp 可执行文件路径 */ -function getVvpPath(extensionPath: string): string { +async function getVvpPath(extensionPath: string): Promise { const platform = process.platform; let vvpBin = ""; @@ -238,11 +244,13 @@ function getVvpPath(extensionPath: string): string { } // 如果插件包中没有,尝试使用系统安装的 vvp - if (!fs.existsSync(vvpBin)) { + const vvpUri = vscode.Uri.file(vvpBin); + try { + await vscode.workspace.fs.stat(vvpUri); + return vvpBin; + } catch { return "vvp"; // 使用系统 PATH 中的 vvp } - - return vvpBin; } /** @@ -264,8 +272,8 @@ export async function generateVCD( } // 2. 获取 iverilog 和 vvp 路径 - const iverilogPath = getIverilogPath(extensionPath); - const vvpPath = getVvpPath(extensionPath); + const iverilogPath = await getIverilogPath(extensionPath); + const vvpPath = await getVvpPath(extensionPath); // 3. 准备输出路径 const outputDir = projectPath; @@ -320,7 +328,11 @@ export async function generateVCD( } // 8. 查找生成的 VCD 文件 - const vcdFiles = fs.readdirSync(projectPath).filter(file => file.endsWith('.vcd')); + const projectUri = vscode.Uri.file(projectPath); + const entries = await vscode.workspace.fs.readDirectory(projectUri); + const vcdFiles = entries + .filter(([fileName, fileType]) => fileType === vscode.FileType.File && fileName.endsWith('.vcd')) + .map(([fileName]) => fileName); if (vcdFiles.length === 0) { return { @@ -335,9 +347,9 @@ export async function generateVCD( // 9. 清理中间文件 try { - if (fs.existsSync(outputFile)) { - fs.unlinkSync(outputFile); - } + const outputUri = vscode.Uri.file(outputFile); + await vscode.workspace.fs.stat(outputUri); + await vscode.workspace.fs.delete(outputUri); } catch (error) { // 忽略清理错误 } @@ -364,10 +376,13 @@ export async function checkIverilogAvailable( extensionPath: string ): Promise<{ available: boolean; version?: string; message: string }> { try { - const iverilogPath = getIverilogPath(extensionPath); + const iverilogPath = await getIverilogPath(extensionPath); // 检查文件是否存在 - if (!fs.existsSync(iverilogPath)) { + const iverilogUri = vscode.Uri.file(iverilogPath); + try { + await vscode.workspace.fs.stat(iverilogUri); + } catch (error) { return { available: false, message: `iverilog 不可用。未找到文件: ${iverilogPath}`, diff --git a/src/utils/readFiles.ts b/src/utils/readFiles.ts index 2ef5b3c..133cb16 100644 --- a/src/utils/readFiles.ts +++ b/src/utils/readFiles.ts @@ -1,5 +1,4 @@ import * as vscode from "vscode"; -import * as fs from "fs"; import * as path from "path"; /** @@ -16,19 +15,21 @@ export async function readFileContent(filePath: string): Promise { } } - // 检查文件是否存在 - if (!fs.existsSync(absolutePath)) { + const fileUri = vscode.Uri.file(absolutePath); + + // 检查文件是否存在并获取文件类型 + try { + const stat = await vscode.workspace.fs.stat(fileUri); + if (stat.type !== vscode.FileType.File) { + throw new Error(`路径不是文件: ${absolutePath}`); + } + } catch (error) { throw new Error(`文件不存在: ${absolutePath}`); } - // 检查是否是文件 - const stats = fs.statSync(absolutePath); - if (!stats.isFile()) { - throw new Error(`路径不是文件: ${absolutePath}`); - } - // 读取文件内容 - const content = fs.readFileSync(absolutePath, "utf-8"); + const contentBytes = await vscode.workspace.fs.readFile(fileUri); + const content = Buffer.from(contentBytes).toString("utf-8"); return content; } catch (error) { throw error; @@ -76,36 +77,38 @@ export async function readDirectory( } } + const dirUri = vscode.Uri.file(absolutePath); + // 检查目录是否存在 - if (!fs.existsSync(absolutePath)) { + try { + const stat = await vscode.workspace.fs.stat(dirUri); + if (stat.type !== vscode.FileType.Directory) { + throw new Error(`路径不是目录: ${absolutePath}`); + } + } catch (error) { throw new Error(`目录不存在: ${absolutePath}`); } - const stats = fs.statSync(absolutePath); - if (!stats.isDirectory()) { - throw new Error(`路径不是目录: ${absolutePath}`); - } - // 读取目录内容 - const files = fs.readdirSync(absolutePath); + const entries = await vscode.workspace.fs.readDirectory(dirUri); const results = []; - for (const file of files) { - const filePath = path.join(absolutePath, file); - const fileStats = fs.statSync(filePath); - - if (fileStats.isFile()) { + for (const [fileName, fileType] of entries) { + if (fileType === vscode.FileType.File) { // 如果指定了扩展名过滤 if (extensions && extensions.length > 0) { - const ext = path.extname(file); + const ext = path.extname(fileName); if (!extensions.includes(ext)) { continue; } } try { - const content = fs.readFileSync(filePath, "utf-8"); - results.push({ path: file, content }); + const filePath = path.join(absolutePath, fileName); + const fileUri = vscode.Uri.file(filePath); + const contentBytes = await vscode.workspace.fs.readFile(fileUri); + const content = Buffer.from(contentBytes).toString("utf-8"); + results.push({ path: fileName, content }); } catch (error) { // 跳过无法读取的文件 continue; @@ -122,13 +125,13 @@ export async function readDirectory( /** * 获取文件信息 */ -export function getFileInfo(filePath: string): { +export async function getFileInfo(filePath: string): Promise<{ exists: boolean; isFile: boolean; isDirectory: boolean; size?: number; extension?: string; -} { +}> { try { let absolutePath = filePath; if (!path.isAbsolute(filePath)) { @@ -138,22 +141,24 @@ export function getFileInfo(filePath: string): { } } - if (!fs.existsSync(absolutePath)) { + const fileUri = vscode.Uri.file(absolutePath); + + try { + const stat = await vscode.workspace.fs.stat(fileUri); + return { + exists: true, + isFile: stat.type === vscode.FileType.File, + isDirectory: stat.type === vscode.FileType.Directory, + size: stat.size, + extension: path.extname(absolutePath), + }; + } catch (error) { 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,