From ab24f6c67027d84fcb3ed75b480b92b9a5d3b65d Mon Sep 17 00:00:00 2001 From: LSTM-Kirigaya <1193466151@qq.com> Date: Sun, 1 Dec 2024 01:09:28 +0800 Subject: [PATCH] =?UTF-8?q?0.4.0=20=E7=AC=AC=E4=B8=89=E6=AC=A1=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E8=BF=AD=E4=BB=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- l10n/bundle.l10n.de.json | 9 +- l10n/bundle.l10n.en.json | 9 +- l10n/bundle.l10n.ja.json | 9 +- l10n/bundle.l10n.zh-cn.json | 9 +- l10n/bundle.l10n.zh-tw.json | 9 +- src/function/sim/simulate.ts | 207 +++++++++++++++++++++++++---------- src/function/tool.ts | 2 +- src/hdlFs/file.ts | 3 - src/hdlFs/path.ts | 1 + src/hdlParser/core.ts | 151 +++++++++++++++++++------ src/manager/ignore.ts | 22 +++- src/monitor/hdl.ts | 2 +- src/monitor/index.ts | 11 +- 13 files changed, 340 insertions(+), 104 deletions(-) diff --git a/l10n/bundle.l10n.de.json b/l10n/bundle.l10n.de.json index 19c82ec..7d437cd 100644 --- a/l10n/bundle.l10n.de.json +++ b/l10n/bundle.l10n.de.json @@ -71,5 +71,12 @@ "info.pl.xilinx.no-need-add-files": "Keine Dateien zum Hinzufügen zum Xilinx-Projekt", "info.pl.xilinx.no-need-del-files": "Es müssen keine Dateien aus Xilinx gelöscht werden.", "error.pl.launch.not-valid-vivado-path": "Fehler beim Starten des Vivado TCL-Skriptinterpreters: {0}. Bitte überprüfen Sie, ob der Startpfad für Vivado korrekt ist. Derzeit eingestellter Startordnerpfad für Vivado: {1}", - "info.pl.launch.set-vivado-path": "Zur Einstellung des Vivado-Installationspfads gehen" + "info.pl.launch.set-vivado-path": "Zur Einstellung des Vivado-Installationspfads gehen", + "info.monitor.current-mode": "Aktueller Monitor-Modus: {0}", + "info.simulation.create-vvp": "VVP-Datei in {0} erstellen", + "error.simulation.reason": "Grund: {0}", + "info.simulate.vvp.vcd-generate": "vcd-Datei wurde erstellt in {0}", + "error.simluate.icarus.use-primitives": "Es wurde ein Primitiv {0} erkannt, aber Icarus iverilog unterstützt keine Primitiven.", + "error.simluate.icarus.use-ip": "Es wurde die IP {0} verwendet, aber Icarus iverilog unterstützt keine IP.", + "error.simulation.error-happen-run-command": "Fehler bei der Icarus-Simulation:" } \ No newline at end of file diff --git a/l10n/bundle.l10n.en.json b/l10n/bundle.l10n.en.json index ac91e50..d328292 100644 --- a/l10n/bundle.l10n.en.json +++ b/l10n/bundle.l10n.en.json @@ -71,5 +71,12 @@ "info.pl.xilinx.no-need-add-files": "No files need to be added to the Xilinx project", "info.pl.xilinx.no-need-del-files": "There are no files to be deleted from Xilinx.", "error.pl.launch.not-valid-vivado-path": "Error encountered while starting the Vivado TCL script interpreter: {0}. Please check if your Vivado startup path is correct. Currently set Vivado startup folder path: {1}", - "info.pl.launch.set-vivado-path": "Go to set the Vivado installation path" + "info.pl.launch.set-vivado-path": "Go to set the Vivado installation path", + "info.monitor.current-mode": "Current monitor mode: {0}", + "info.simulation.create-vvp": "Create VVP file in {0}", + "error.simulation.reason": "Reason: {0}", + "info.simulate.vvp.vcd-generate": "vcd file has been generated to {0}", + "error.simluate.icarus.use-primitives": "Primitive {0} detected, but Icarus iverilog does not support primitives.", + "error.simluate.icarus.use-ip": "Detected the use of IP {0}, but Icarus iverilog does not support IP.", + "error.simulation.error-happen-run-command": "Error during Icarus simulation:" } \ No newline at end of file diff --git a/l10n/bundle.l10n.ja.json b/l10n/bundle.l10n.ja.json index a30cc52..49eeed1 100644 --- a/l10n/bundle.l10n.ja.json +++ b/l10n/bundle.l10n.ja.json @@ -71,5 +71,12 @@ "info.pl.xilinx.no-need-add-files": "Xilinx プロジェクトに追加するファイルはありません", "info.pl.xilinx.no-need-del-files": "Xilinx から削除するファイルはありません。", "error.pl.launch.not-valid-vivado-path": "Vivado TCL スクリプトインタプリタの起動中にエラーが発生しました:{0}。Vivado の起動パスが正しいか確認してください。現在設定されている Vivado 起動フォルダパス:{1}", - "info.pl.launch.set-vivado-path": "Vivado インストールパスの設定に移動" + "info.pl.launch.set-vivado-path": "Vivado インストールパスの設定に移動", + "info.monitor.current-mode": "現在のモニターモード:{0}", + "info.simulation.create-vvp": "{0} で VVP ファイルを作成", + "error.simulation.reason": "理由: {0}", + "info.simulate.vvp.vcd-generate": "vcdファイルが生成されました: {0}", + "error.simluate.icarus.use-primitives": "プリミティブ {0} が検出されましたが、Icarus iverilog はプリミティブをサポートしていません。", + "error.simluate.icarus.use-ip": "IP {0} が使用されていますが、Icarus iverilog は IP をサポートしていません。", + "error.simulation.error-happen-run-command": "Icarusシミュレーション中にエラーが発生しました:" } \ No newline at end of file diff --git a/l10n/bundle.l10n.zh-cn.json b/l10n/bundle.l10n.zh-cn.json index 02418ba..77dc01a 100644 --- a/l10n/bundle.l10n.zh-cn.json +++ b/l10n/bundle.l10n.zh-cn.json @@ -71,5 +71,12 @@ "info.pl.xilinx.no-need-add-files": "没有需要添加到 Xilinx 工程的文件", "info.pl.xilinx.no-need-del-files": "没有需要从 Xilinx 中删除的文件", "error.pl.launch.not-valid-vivado-path": "启动 Vivado TCL 脚本解释器遇到错误:{0} 。请检查你的 Vivado 启动路径是否正确,当前设置的 Vivado 启动文件夹路径:{1}", - "info.pl.launch.set-vivado-path": "前往设置 Vivado 安装路径" + "info.pl.launch.set-vivado-path": "前往设置 Vivado 安装路径", + "info.monitor.current-mode": "当前监视器模式:{0}", + "info.simulation.create-vvp": "在 {0} 创建 VVP 文件", + "error.simulation.reason": "原因: {0}", + "info.simulate.vvp.vcd-generate": "vcd 文件已经生成至 {0}", + "error.simluate.icarus.use-primitives": "检测到使用了原语 {0},但是 Icarus iverilog 并不支持原语", + "error.simluate.icarus.use-ip": "检测到使用了 IP {0},但是 Icarus iverilog 并不支持 IP", + "error.simulation.error-happen-run-command": "Icarus 仿真时,出现错误:" } \ No newline at end of file diff --git a/l10n/bundle.l10n.zh-tw.json b/l10n/bundle.l10n.zh-tw.json index 1783f64..bd9ff8a 100644 --- a/l10n/bundle.l10n.zh-tw.json +++ b/l10n/bundle.l10n.zh-tw.json @@ -71,5 +71,12 @@ "info.pl.xilinx.no-need-add-files": "沒有需要添加到 Xilinx 工程的文件", "info.pl.xilinx.no-need-del-files": "沒有需要從 Xilinx 中刪除的檔案。", "error.pl.launch.not-valid-vivado-path": "啟動 Vivado TCL 腳本解釋器遇到錯誤:{0} 。請檢查你的 Vivado 啟動路徑是否正確,目前設定的 Vivado 啟動資料夾路徑:{1}", - "info.pl.launch.set-vivado-path": "前往設定 Vivado 安裝路徑" + "info.pl.launch.set-vivado-path": "前往設定 Vivado 安裝路徑", + "info.monitor.current-mode": "目前監視器模式:{0}", + "info.simulation.create-vvp": "在 {0} 建立 VVP 檔案", + "error.simulation.reason": "原因: {0}", + "info.simulate.vvp.vcd-generate": "vcd 檔案已生成至 {0}", + "error.simluate.icarus.use-primitives": "偵測到使用了原語 {0},但是 Icarus iverilog 並不支援原語。", + "error.simluate.icarus.use-ip": "偵測到使用了 IP {0},但是 Icarus iverilog 並不支援 IP。", + "error.simulation.error-happen-run-command": "Icarus 模擬時,出現錯誤:" } \ No newline at end of file diff --git a/src/function/sim/simulate.ts b/src/function/sim/simulate.ts index 47d4d26..9e523d3 100644 --- a/src/function/sim/simulate.ts +++ b/src/function/sim/simulate.ts @@ -1,5 +1,6 @@ import * as vscode from 'vscode'; import * as fs from 'fs'; +import * as fspath from 'path'; import * as child_process from 'child_process'; import { hdlParam } from '../../hdlParser'; @@ -10,6 +11,7 @@ import { HdlLangID, ToolChainType } from '../../global/enum'; import { HdlFile, HdlModule } from '../../hdlParser/core'; import { ModuleDataItem } from '../treeView/tree'; import { defaultMacro, doFastApi } from '../../hdlParser/util'; +import { t } from '../../i18n'; type Path = string; @@ -185,17 +187,35 @@ class IcarusSimulate extends Simulate { return args.join(' ').trim(); } + /** + * @description 生成用于进行仿真的依赖项相关的参数 + * @param dependences + * @returns + */ private makeDependenceArguments(dependences: string[]): string { // 去重 const visitedPath = new Set; const args = []; for (const dep of dependences) { + // 去重 if (visitedPath.has(dep)) { continue; } + // icarus 不支持 原语 + if (dep === 'xilinx-primitives') { + MainOutput.report(t('error.simluate.icarus.use-primitives', dep), { level: ReportType.Error }); + continue; + } + // icarus 不支持 IP + if (dep.startsWith(opeParam.prjInfo.ipPath)) { + MainOutput.report(t('error.simluate.icarus.use-ip', dep), { level: ReportType.Error }); + continue; + } + args.push(makeSafeArgPath(dep)); visitedPath.add(dep); } + return args.join(' ').trim(); } @@ -215,13 +235,15 @@ class IcarusSimulate extends Simulate { } /** - * generate acutal iverlog simulation command + * @description 获取 iverilog 仿真的命令 * @param name name of top module * @param path path of the simulated file * @param dependences dependence that not specified in `include macro * @returns */ private getCommand(name: string, path: AbsPath, dependences: string[]): string | undefined { + MainOutput.clear(); + const simConfig = this.getConfig(path, 'iverilog'); if (!simConfig) { return; @@ -252,22 +274,14 @@ class IcarusSimulate extends Simulate { const iverilogPath = simConfig.iverilogPath; // default is -g2012 const argu = '-g' + iverilogCompileOptions.standard; - const outVvpPath = makeSafeArgPath(hdlPath.join(simConfig.simulationHome, 'out.vvp')); + const outVvpPath = makeSafeArgPath(hdlPath.join(simConfig.simulationHome, name + '.vvp')); const mainPath = makeSafeArgPath(path); - - // console.log(macroIncludeArgs); - // console.log(thirdLibraryDirArgs); - // console.log(dependenceArgs); - // console.log(thirdLibraryFileArgs); const cmd = `${iverilogPath} ${argu} -o ${outVvpPath} -s ${name} ${macroIncludeArgs} ${thirdLibraryDirArgs} ${mainPath} ${dependenceArgs} ${thirdLibraryFileArgs}`; - MainOutput.report(cmd, { - level: ReportType.Run - }); return cmd; } - private execInTerminal(command: string, cwd: AbsPath) { + private execInTerminal(command: string, cwd: AbsPath, hdlModule: HdlModule) { // let vvp: vscode.Terminal; // const targetTerminals = vscode.window.terminals.filter(t => t.name === 'vvp'); // if (targetTerminals.length > 0) { @@ -291,56 +305,136 @@ class IcarusSimulate extends Simulate { // } } - private execInOutput(command: string, cwd: AbsPath) { + /** + * @description 在 Digital IDE 窗口中运行 iverilog 的快速仿真 + * @param command + * @param cwd + * @param hdlModule + * @returns + */ + private execInOutput(command: string, cwd: AbsPath, hdlModule: HdlModule) { const simConfig = this.simConfig; if (!simConfig) { return; } - child_process.exec(command, { cwd }, (error, stdout, stderr) => { - if (error) { - MainOutput.report('Error took place when run ' + command, { - level: ReportType.Error - }); - MainOutput.report('Reason: ' + stderr, { - level: ReportType.Error - }); - } else { - MainOutput.report(stdout, { - level: ReportType.Info - }); - const vvpOutFile = hdlPath.join(simConfig.simulationHome, 'out.vvp'); - MainOutput.report("Create vvp to " + vvpOutFile, { - level: ReportType.Run - }); - - const outVvpPath = hdlPath.join(simConfig.simulationHome, 'out.vvp'); - const vvpPath = simConfig.vvpPath; - // run vvp to interrupt script - const vvpCommand = `${vvpPath} ${outVvpPath}`; - MainOutput.report(vvpCommand, { - level: ReportType.Run - }); - - child_process.exec(vvpCommand, { cwd }, (error, stdout, stderr) => { - if (error) { - MainOutput.report('Error took place when run ' + vvpCommand, { - level: ReportType.Error - }); - MainOutput.report('Reason: ' + stderr, { - level: ReportType.Error - }); - } else { - MainOutput.report(stdout, { - level: ReportType.Info - }); - } - }); - } + this.runIverilog(simConfig, command, cwd, hdlModule); + } + + private reportCommandError(command: string, stderr: string) { + MainOutput.report(t('error.simulation.error-happen-run-command') + command, { + level: ReportType.Error + }); + MainOutput.report(t('error.simulation.reason', stderr), { + level: ReportType.Error }); } - private exec(command: string, cwd: AbsPath) { + /** + * @description 运行 iverilog xxx 的命令 + * @param simConfig + * @param command + * @param cwd + * @param hdlModule + */ + private runIverilog(simConfig: SimulateConfig, command: string, cwd: string, hdlModule: HdlModule) { + child_process.exec(command, (error, stdout, stderr) => { + if (error) { + this.reportCommandError(command, stderr); + return; + } + + // 准备执行 vvp + MainOutput.report(stdout); + const generateVvpName = hdlModule.name + '.vvp'; + + const outVvpPath = hdlPath.join(simConfig.simulationHome, generateVvpName); + MainOutput.report(t('info.simulation.create-vvp', outVvpPath), { + level: ReportType.Run + }); + + const vvpPath = simConfig.vvpPath; + + // 运行 vvp 文件,执行目录在生成的 vcd 的同级目录 + // 对于 vvp 执行的 cwd,为了方便用户可以调用 $readmemb $fopen $dumpfile + // 这些系统调用进行 IO,所以选择 {workspace} 作为执行 vvp 的 cwd + const vvpCwd = opeParam.openMode === 'file' ? cwd: opeParam.workspacePath; + + const vvpCommand = `${vvpPath} ${outVvpPath}`; + MainOutput.report(vvpCommand, { level: ReportType.Run }); + + this.runVvp(vvpCommand, vvpCwd); + }); + } + + /** + * @description 陨星 vvp xxx 的命令 + * @param command + * @param cwd + */ + private runVvp(command: string, cwd: string) { + child_process.exec(command, { cwd }, (error, stdout, stderr) => { + if (error) { + this.reportCommandError(command, stderr); + return; + } + + // 对于 vvp 的输出结果,特殊处理 + this.handleVvpStdOutput(stdout, command, cwd); + }); + } + + /** + * @description 处理 vvp xxx.vvp 执行后输出的标准输出 + * vvp 的标准输出似乎总是一行一个的 + * @param stdoutMessage vvp 执行后的标准输出窗口 + * @param command 用于重新执行 + * @param cwd 用于重新执行 + */ + private handleVvpStdOutput(stdoutMessage: string, command: string, cwd: string) { + for (const line of stdoutMessage.split('\n').map(line => line.trim())) { + if (line.startsWith('WARNING:')) { + // 运行时警告 + MainOutput.report(line.slice(8).trim(), { level: ReportType.Warn }); + + } else if (line.startsWith('ERROR:')) { + // 运行时错误,比如用户 $readmemb 读取的文件并不存在 + MainOutput.report(line.slice(6).trim(), { level: ReportType.Error }); + + } else if (line.startsWith('VCD info:')) { + // 导出 VCD 的信息,用于输出 + // 此处尝试提取 vcd 导出的信息,然后转换内部信息导出到屏幕上 + const match = line.match(/dumpfile (.+) opened for output/); + if (match) { + const vcdPath = match[1]; + const absVcdPath = hdlPath.resolve(cwd, vcdPath); + MainOutput.report(t('info.simulate.vvp.vcd-generate', absVcdPath)); + } else { + MainOutput.report(line.slice(9).trim()); + } + + } else if (line.startsWith('VCD Error:')) { + // 出现 VCD Error 可能是因为生成地点的目录不存在,创建目录,然后再运行 + const match = line.match(/Unable to open (.+) for output\./); + if (match) { + const vcdPath = match[1]; + const absVcdPath = hdlPath.resolve(cwd, vcdPath); + const parentFolderPath = fspath.dirname(absVcdPath); + hdlDir.mkdir(parentFolderPath); + // 清除输出,准备第二次运行 + MainOutput.clear(); + this.runVvp(command, cwd); + } else { + // 没有匹配到,说明是其他错误,直接按照错误输出 + MainOutput.report(line.slice(10).trim(), { level: ReportType.Error }); + } + } else { + MainOutput.report(line, { level: ReportType.Info }); + } + } + } + + private exec(command: string, cwd: AbsPath, hdlModule: HdlModule) { const simConfig = this.simConfig; if (!simConfig) { MainOutput.report('this.simConfig is empty when exec'); @@ -350,10 +444,10 @@ class IcarusSimulate extends Simulate { const runInTerminal = vscode.workspace.getConfiguration().get('digital-ide.function.simulate.runInTerminal'); if (runInTerminal) { - this.execInTerminal(command, cwd); + this.execInTerminal(command, cwd, hdlModule); } else { MainOutput.show(); - this.execInOutput(command, cwd); + this.execInOutput(command, cwd, hdlModule); } } @@ -375,11 +469,12 @@ class IcarusSimulate extends Simulate { // MainOutput.report(warningMsg, ReportType.Warn, true); // return; // } + const dependences = this.getAllOtherDependences(path, name); const simulationCommand = this.getCommand(name, path, dependences); if (simulationCommand) { const cwd = hdlPath.resolve(path, '..'); - this.exec(simulationCommand, cwd); + this.exec(simulationCommand, cwd, hdlModule); } else { const errorMsg = 'Fail to generate command'; MainOutput.report(errorMsg, { diff --git a/src/function/tool.ts b/src/function/tool.ts index 2fe7cdf..8746649 100644 --- a/src/function/tool.ts +++ b/src/function/tool.ts @@ -133,7 +133,7 @@ async function askUserToSaveFilelist(filelist: string[]) { if (uri === undefined) { return; } - const filePath = uri.path; + const filePath = uri.fsPath; const fileContent = filelist.join('\n'); try { diff --git a/src/hdlFs/file.ts b/src/hdlFs/file.ts index 7d2d7d3..9933e14 100644 --- a/src/hdlFs/file.ts +++ b/src/hdlFs/file.ts @@ -67,9 +67,6 @@ export function isSystemVerilogFile(path: AbsPath): boolean { } export function isHDLFile(path: AbsPath): boolean { - if (!isFile(path)) { - return false; - } const ext = hdlPath.extname(path, false); return hdlExts.includes(ext); } diff --git a/src/hdlFs/path.ts b/src/hdlFs/path.ts index 020a1c7..b72a308 100644 --- a/src/hdlFs/path.ts +++ b/src/hdlFs/path.ts @@ -103,6 +103,7 @@ function toEscapePath(path: AbsPath): AbsPath { } function toPureRelativePath(path: RelPath): RelPath { + if (path.startsWith('./') || path.startsWith('.\\')) { return path.slice(2); } diff --git a/src/hdlParser/core.ts b/src/hdlParser/core.ts index cffd5d8..d5b5f86 100644 --- a/src/hdlParser/core.ts +++ b/src/hdlParser/core.ts @@ -169,6 +169,10 @@ class HdlParam { return undefined; } + if (this.isTopModule(path, name)) { + console.log(module); + } + const dependencies : common.HdlDependence = { current: [], include: [], @@ -497,15 +501,93 @@ class HdlParam { const hdlParam = new HdlParam(); class HdlInstance { - name: string; // name of the instance - type: string; // type + /** + * @description 例化的名字 + * + * 对于下面的例子,唯一例化 的 name 就是 `u_tool` + * @example + * module hello() + * tool u_tool(); + * endmodule + * + */ + name: string; + + /** + * @description 例化的模块名 + * + * 对于下面的例子,唯一例化 的 type 就是 `tool` + * @example + * module hello() + * tool u_tool(); + * endmodule + * + */ + type: string; + + /** + * @description 例化的 range + */ range: common.Range; // range of instance - instModPath: AbsPath | undefined; // path of the definition - instModPathStatus: common.InstModPathStatus; // status of the instance (current, include, others) - instparams: common.InstRange; // range of params - instports: common.InstRange; // range of ports - parentMod: HdlModule; // 例化模块例化地点的外层 module - module: HdlModule | undefined; // 例化模块的定义模块 + + /** + * @description 例化的模块的定义路径 + * + * 对于下面的例子,唯一例化 的 instModPath 就是 `tool` 这个模块 `module tool` 申明所在的文件的路径 + * @example + * module hello() + * tool u_tool(); + * endmodule + * + */ + instModPath: AbsPath | undefined; + + /** + * @description 用于描述当前例化是如何被引入的,以下是三类枚举 + * - current: 例化对应的模块就在当前文件中 + * - include: 通过 `include + * - others: 其他 + */ + instModPathStatus: common.InstModPathStatus; + + /** + * @description 例化 params 部分的 range. + * 如果是 vhdl,则是 generic map 部分的 range + */ + instparams: common.InstRange; + + /** + * @description 例化 ports 部分的 range. + * 如果是 vhdl,则是 port map 部分的 range + */ + instports: common.InstRange; + + /** + * @description 例化模块例化地点的外层 module + * + * 对于下面的例子, 例化 `u_tool` 的 parentMod 就是 `hello` + * @example + * module hello() + * tool u_tool(); + * endmodule + * + */ + parentMod: HdlModule; + + /** + * @description 例化模块的定义模块 + * + * 对于下面的例子, 例化 `u_tool` 的 `module` 就是 tool + * @example + * module hello(); + * tool u_tool(); + * endmodule + * + * module tool(); + * ... + * endmodule + */ + module: HdlModule | undefined; constructor(name: string, type: string, @@ -611,7 +693,34 @@ class HdlInstance { this.instports = newInstance.instports; this.instModPath = this.module?.path || ''; - this.instModPathStatus = this.parentMod.solveInstModPathStatus(); + this.updateInstModPathStatus(); + } + + /** + * @description 用于解决例化的路径引入状态,对于 A 模块,它的两个例化 u_A1 和 u_A2 + * 使用 u_A1 和 u_A2 的模块需要知道 u_A1 是如何被引入的,此时需要调用 u_A1.updateInstModPathStatus() 来更新 + * u_A1 的 instModPathStatus + */ + public updateInstModPathStatus() { + const module = this.module; + if (module) { + const userModule = this.parentMod; + if (userModule.path === module.path) { + this.instModPathStatus = common.InstModPathStatus.Current; + } else { + const userIncludePaths = userModule.file.macro.includes.map( + include => hdlPath.rel2abs(userModule.path, include.path) + ); + + if (userIncludePaths.includes(module.path)) { + this.instModPathStatus = common.InstModPathStatus.Include; + } else { + this.instModPathStatus = common.InstModPathStatus.Others; + } + } + } else { + this.instModPathStatus = common.InstModPathStatus.Unknown; + } } public get getDoFastFileType(): DoFastFileType | undefined { @@ -882,28 +991,6 @@ class HdlModule { } } - public solveInstModPathStatus(): common.InstModPathStatus { - // TODO: 修改这套系统,因为现在只是拿第一个例化来判断的,这是不合理的 - // 应该把 common.InstModPathStatus 修改成一个可以通过析取来表示的变量 - const inst = hdlParam.getUnhandleInstancesByModuleName(this.name)[0]; - if (!inst) { - return common.InstModPathStatus.Unknown; - } - const userModule = inst.parentMod; - if (userModule.path === this.path) { - return common.InstModPathStatus.Current; - } else { - const userIncludePaths = userModule.file.macro.includes.map( - include => hdlPath.rel2abs(userModule.path, include.path)); - - if (userIncludePaths.includes(this.path)) { - return common.InstModPathStatus.Include; - } else { - return common.InstModPathStatus.Others; - } - } - } - /** * @description 从全局寻找这个 module 的例化,并尝试修改它的状态 */ @@ -918,7 +1005,7 @@ class HdlModule { // 解决 instance.instModPath = this.path; - instance.instModPathStatus = this.solveInstModPathStatus(); + instance.updateInstModPathStatus(); // 找寻这个 instance 对应的真正的 module(也有可能是原语) // 并将这个 instance 加入这个 module 的计数器中 diff --git a/src/manager/ignore.ts b/src/manager/ignore.ts index d934d0e..d5e6fe9 100644 --- a/src/manager/ignore.ts +++ b/src/manager/ignore.ts @@ -1,8 +1,10 @@ import * as vscode from 'vscode'; import { AbsPath, opeParam } from '../global'; -import { hdlPath } from '../hdlFs'; +import { hdlFile, hdlPath } from '../hdlFs'; import * as fs from 'fs'; +import * as fspath from 'path'; import { minimatch } from 'minimatch'; +import { toPureRelativePath } from '../hdlFs/path'; class HdlIgnore { @@ -19,9 +21,8 @@ class HdlIgnore { const workspace = opeParam.workspacePath; // 转换成相对于 ws 的相对路径,形如 ./src/test.py let relativePath = hdlPath.toPureRelativePath(hdlPath.relative(workspace, path)); - console.log('current path:', relativePath); - for (const pattern of this.patterns.map(p => hdlPath.toPureRelativePath(p))) { + for (const pattern of this.patterns) { const matched = minimatch(relativePath, pattern); if (matched) { return true; @@ -55,11 +56,26 @@ class HdlIgnore { } } this.patterns = [...validGlobStrings]; + this.makeClearPattern(); } else { // .dideignore 不存在直接赋值为空 this.patterns = []; } } + + /** + * @description 构建可直接使用的 patterns + * 该操作是幂等的 + */ + private makeClearPattern() { + for (let i = 0; i < this.patterns.length; ++ i) { + let pattern = this.patterns[i]; + if (fspath.isAbsolute(pattern)) { + pattern = hdlPath.relative(opeParam.workspacePath, pattern); + } + this.patterns[i] = toPureRelativePath(pattern); + } + } } const hdlIgnore = new HdlIgnore(); diff --git a/src/monitor/hdl.ts b/src/monitor/hdl.ts index 66093c5..712fe8d 100644 --- a/src/monitor/hdl.ts +++ b/src/monitor/hdl.ts @@ -152,7 +152,7 @@ export class HdlAction extends BaseAction { * @param path */ private isvalid(path: AbsPath): boolean { - const prjInfo = opeParam.prjInfo; + const prjInfo = opeParam.prjInfo; if (path.startsWith(prjInfo.hardwareSrcPath) || path.startsWith(prjInfo.hardwareSimPath)) { if (!hdlIgnore.isignore(path) && hdlFile.isHDLFile(path)) { return true; diff --git a/src/monitor/index.ts b/src/monitor/index.ts index b133bdf..30ee339 100644 --- a/src/monitor/index.ts +++ b/src/monitor/index.ts @@ -44,7 +44,6 @@ class HdlMonitor{ */ public getHdlMonitor() { const prjInfo = opeParam.prjInfo; - const monitorPathSet = new PathSet(); // 在输出中展示当前的监视路径 @@ -57,8 +56,14 @@ class HdlMonitor{ level: ReportType.Launch }); - // chokidar 4.0.0 开始不支持 glob,需要在每一个入口自己判断 - return this.makeMonitor([opeParam.workspacePath, prjInfo.libCommonPath]); + MainOutput.report(t('info.monitor.current-mode', opeParam.openMode)); + + if (opeParam.openMode === 'file') { + return this.makeMonitor([prjInfo.libCommonPath]); + } else { + // chokidar 4.0.0 开始不支持 glob,需要在每一个入口自己判断 + return this.makeMonitor([opeParam.workspacePath, prjInfo.libCommonPath]); + } } public getIgnoreMonitor() {