diff --git a/.gitignore b/.gitignore index f2ae135..431fed4 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,5 @@ out-js/ resources/hdlParser/parser.js resources/hdlParser/parser.wasm resources/dide-viewer/view/* -resources/dide-lsp/server/* \ No newline at end of file +resources/dide-lsp/server/* +resources/dide-lsp/static/* \ No newline at end of file diff --git a/l10n/bundle.l10n.de.json b/l10n/bundle.l10n.de.json index c34e26c..5298979 100644 --- a/l10n/bundle.l10n.de.json +++ b/l10n/bundle.l10n.de.json @@ -28,5 +28,6 @@ "info.progress.build-ip-module-tree": "构建 IP 模块树", "info.treeview.ip-no-active.message": "当前 IP 还未激活,请通过 Xilinx 工具链将 XCI 文件生成完整的 IP 核", "info.progress.initialize-configure": "初始化项目配置", - "info.treeview.item.tooltip": "can't find the module of this instance" + "info.pl.xilinx.launch.pick-project-placeholder": "Which project you want to open ?", + "error.common.not-valid-hdl-file": "is not a valid hdl file in our parse list, check your property.json to see if arch.hardware.src is set correctly!\\ncurrent parse list: \\n" } \ No newline at end of file diff --git a/l10n/bundle.l10n.en.json b/l10n/bundle.l10n.en.json index 4b965f3..a0ea9b5 100644 --- a/l10n/bundle.l10n.en.json +++ b/l10n/bundle.l10n.en.json @@ -28,5 +28,6 @@ "info.progress.build-ip-module-tree": "构建 IP 模块树", "info.treeview.ip-no-active.message": "当前 IP 还未激活,请通过 Xilinx 工具链将 XCI 文件生成完整的 IP 核", "info.progress.initialize-configure": "初始化项目配置", - "info.treeview.item.tooltip": "can't find the module of this instance" + "info.pl.xilinx.launch.pick-project-placeholder": "Which project you want to open ?", + "error.common.not-valid-hdl-file": "is not a valid hdl file in our parse list, check your property.json to see if arch.hardware.src is set correctly!\\ncurrent parse list: \\n" } \ No newline at end of file diff --git a/l10n/bundle.l10n.ja.json b/l10n/bundle.l10n.ja.json index 1e47086..844ce85 100644 --- a/l10n/bundle.l10n.ja.json +++ b/l10n/bundle.l10n.ja.json @@ -28,5 +28,6 @@ "info.progress.build-ip-module-tree": "构建 IP 模块树", "info.treeview.ip-no-active.message": "当前 IP 还未激活,请通过 Xilinx 工具链将 XCI 文件生成完整的 IP 核", "info.progress.initialize-configure": "初始化项目配置", - "info.treeview.item.tooltip": "can't find the module of this instance" + "info.pl.xilinx.launch.pick-project-placeholder": "Which project you want to open ?", + "error.common.not-valid-hdl-file": "is not a valid hdl file in our parse list, check your property.json to see if arch.hardware.src is set correctly!\\ncurrent parse list: \\n" } \ No newline at end of file diff --git a/l10n/bundle.l10n.zh-cn.json b/l10n/bundle.l10n.zh-cn.json index 19b4661..4fde85c 100644 --- a/l10n/bundle.l10n.zh-cn.json +++ b/l10n/bundle.l10n.zh-cn.json @@ -28,5 +28,6 @@ "info.progress.build-ip-module-tree": "构建 IP 模块树", "info.treeview.ip-no-active.message": "当前 IP 还未激活,请通过 Xilinx 工具链将 XCI 文件生成完整的 IP 核", "info.progress.initialize-configure": "初始化项目配置", - "info.treeview.item.tooltip": "无法找到当前实例的模块" + "info.pl.xilinx.launch.pick-project-placeholder": "请选择需要打开的工程", + "error.common.not-valid-hdl-file": "并不在系统的解析列表中,请检查你的 property.json 配置文件中的 arch.hardware.src 是否被正确设置。当前的解析路径为:" } \ No newline at end of file diff --git a/l10n/bundle.l10n.zh-tw.json b/l10n/bundle.l10n.zh-tw.json index 14ca278..f820a42 100644 --- a/l10n/bundle.l10n.zh-tw.json +++ b/l10n/bundle.l10n.zh-tw.json @@ -28,5 +28,6 @@ "info.progress.build-ip-module-tree": "构建 IP 模块树", "info.treeview.ip-no-active.message": "当前 IP 还未激活,请通过 Xilinx 工具链将 XCI 文件生成完整的 IP 核", "info.progress.initialize-configure": "初始化项目配置", - "info.treeview.item.tooltip": "can't find the module of this instance" + "info.pl.xilinx.launch.pick-project-placeholder": "Which project you want to open ?", + "error.common.not-valid-hdl-file": "is not a valid hdl file in our parse list, check your property.json to see if arch.hardware.src is set correctly!\\ncurrent parse list: \\n" } \ No newline at end of file diff --git a/src/extension.ts b/src/extension.ts index 2595aa1..b46a3c7 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,7 +1,7 @@ import * as vscode from 'vscode'; import * as fs from 'fs'; -import { opeParam, MainOutput, AbsPath, ReportType, LspClient, IProgress } from './global'; +import { MainOutput, ReportType, IProgress } from './global'; import { hdlParam } from './hdlParser'; import * as manager from './manager'; import * as func from './function'; @@ -13,6 +13,8 @@ import { refreshArchTree } from './function/treeView'; async function registerCommand(context: vscode.ExtensionContext, packageJson: any) { func.registerFunctionCommands(context); + func.registerTreeViewDataProvider(context); + func.registerLsp(context, packageJson.version); func.registerToolCommands(context); func.registerFSM(context); diff --git a/src/function/hdlDoc/markdown.ts b/src/function/hdlDoc/markdown.ts index 2c1d942..21d67f4 100644 --- a/src/function/hdlDoc/markdown.ts +++ b/src/function/hdlDoc/markdown.ts @@ -3,7 +3,7 @@ import * as fs from 'fs'; import * as fspath from 'path'; import { AbsPath, opeParam, MainOutput, ReportType } from '../../global'; -import { hdlParam, HdlModule } from '../../hdlParser/core'; +import { hdlParam, HdlModule, HdlFile } from '../../hdlParser/core'; import { HdlModulePort, HdlModuleParam } from '../../hdlParser/common'; import { MarkdownString, RenderString, RenderType, @@ -13,6 +13,7 @@ import { hdlPath, hdlFile } from '../../hdlFs'; import { getSymbolComments } from '../lsp/util/feature'; import { HdlLangID, ThemeType } from '../../global/enum'; import { makeDiagram } from './diagram'; +import { defaultMacro, doFastApi } from '../../hdlParser/util'; function makeSVGElementByLink(link: AbsPath, caption?: string) { @@ -179,16 +180,27 @@ async function getDocsFromModule(module: HdlModule): Promise { * @param path absolute path of the file */ async function getDocsFromFile(path: AbsPath): Promise { - const moduleFile = hdlParam.getHdlFile(path); - if (!moduleFile) { - MainOutput.report('Fail to export documentation of ' + path, - ReportType.Error); + const { t } = vscode.l10n; - const errorMsg = `${path} is not a valid hdl file in our parse list, check your property.json to see if arch.hardware.src is set correctly! - \ncurrent parse list: \n${opeParam.prjInfo.hardwareSrcPath}\n${opeParam.prjInfo.hardwareSimPath}`; - vscode.window.showErrorMessage(errorMsg); - - return undefined; + let moduleFile = hdlParam.getHdlFile(path); + // 没有说明是单文件模式,直接打开解析 + if (!moduleFile) { + const standardPath = hdlPath.toSlash(path); + const response = await doFastApi(standardPath, 'common'); + const langID = hdlFile.getLanguageId(standardPath); + moduleFile = new HdlFile( + standardPath, langID, + response?.macro || defaultMacro, + response?.content || [], + 'common' + ); + // 从 hdlParam 中去除,避免干扰全局 + hdlParam.removeFromHdlFile(moduleFile); + + // const message = t('error.common.not-valid-hdl-file'); + // const errorMsg = path + ' ' + message + ' ' + opeParam.prjInfo.hardwareSrcPath + '\n' + opeParam.prjInfo.hardwareSimPath; + // vscode.window.showErrorMessage(errorMsg); + // return undefined; } const markdownStringPromises = []; for (const module of moduleFile.getAllHdlModules()) { diff --git a/src/function/index.ts b/src/function/index.ts index ad2d592..061ea2c 100644 --- a/src/function/index.ts +++ b/src/function/index.ts @@ -28,7 +28,7 @@ function registerDocumentation(context: vscode.ExtensionContext) { function registerSimulation(context: vscode.ExtensionContext) { vscode.commands.registerCommand('digital-ide.tool.instance', sim.instantiation); vscode.commands.registerCommand('digital-ide.tool.testbench', sim.testbench); - vscode.commands.registerCommand('digital-ide.tool.icarus.simulateFile', (view: ModuleDataItem) => { + vscode.commands.registerCommand('digital-ide.tool.icarus.simulateFile', (view: ModuleDataItem) => { sim.Icarus.simulateFile(view); }); } @@ -39,13 +39,15 @@ function registerFunctionCommands(context: vscode.ExtensionContext) { registerTreeView(context); } -function registerTreeView(context: vscode.ExtensionContext) { - // register normal tree - vscode.window.registerTreeDataProvider('digital-ide-treeView-arch', treeView.moduleTreeProvider); - // vscode.window.registerTreeDataProvider('digital-ide-treeView-tool', treeView.toolTreeProvider); +function registerTreeViewDataProvider(context: vscode.ExtensionContext) { vscode.window.registerTreeDataProvider('digital-ide-treeView-hardware', treeView.hardwareTreeProvider); // vscode.window.registerTreeDataProvider('digital-ide-treeView-software', treeView.softwareTreeProvider); + + vscode.window.registerTreeDataProvider('digital-ide-treeView-arch', treeView.moduleTreeProvider); + // vscode.window.registerTreeDataProvider('digital-ide-treeView-tool', treeView.toolTreeProvider); +} +function registerTreeView(context: vscode.ExtensionContext) { // constant used in tree vscode.commands.executeCommand('setContext', 'TOOL-tree-expand', false); @@ -125,7 +127,13 @@ function registerFSM(context: vscode.ExtensionContext) { } function registerNetlist(context: vscode.ExtensionContext) { - vscode.commands.registerCommand('digital-ide.netlist.show', uri => Netlist.openNetlistViewer(context, uri)); + vscode.commands.registerCommand('digital-ide.netlist.show', uri => { + if (typeof uri === 'string') { + uri = vscode.Uri.file(uri); + } + console.log('get uri: ', uri); + Netlist.openNetlistViewer(context, uri); + }); } function registerWaveViewer(context: vscode.ExtensionContext) { @@ -149,5 +157,6 @@ export { registerToolCommands, registerFSM, registerNetlist, - registerWaveViewer + registerWaveViewer, + registerTreeViewDataProvider }; \ No newline at end of file diff --git a/src/function/netlist/index.ts b/src/function/netlist/index.ts index 5f8c87e..78ff679 100644 --- a/src/function/netlist/index.ts +++ b/src/function/netlist/index.ts @@ -5,6 +5,8 @@ import { NetlistKernel } from '../../../resources/netlist'; import { opeParam, ReportType, YosysOutput } from '../../global'; import { hdlParam } from '../../hdlParser'; import { hdlFile, hdlPath } from '../../hdlFs'; +import { defaultMacro, doFastApi } from '../../hdlParser/util'; +import { HdlFile } from '../../hdlParser/core'; class Netlist { @@ -17,19 +19,34 @@ class Netlist { } public async open(uri: vscode.Uri) { + const { t } = vscode.l10n; + // get dependence of the current uri const prjFiles = []; const path = hdlPath.toSlash(uri.fsPath); - const hdlFile = hdlParam.getHdlFile(path); - if (!hdlFile) { - const errorMsg = `${path} is not a valid hdl file in our parse list, check your property.json to see if arch.hardware.src is set correctly! - \ncurrent parse list: \n${opeParam.prjInfo.hardwareSrcPath}\n${opeParam.prjInfo.hardwareSimPath}`; - vscode.window.showErrorMessage(errorMsg); - return; + let moduleFile = hdlParam.getHdlFile(path); + // 没有说明是单文件模式,直接打开解析 + if (!moduleFile) { + const standardPath = hdlPath.toSlash(path); + const response = await doFastApi(standardPath, 'common'); + const langID = hdlFile.getLanguageId(standardPath); + moduleFile = new HdlFile( + standardPath, langID, + response?.macro || defaultMacro, + response?.content || [], + 'common' + ); + // 从 hdlParam 中去除,避免干扰全局 + hdlParam.removeFromHdlFile(moduleFile); + + // const message = t('error.common.not-valid-hdl-file'); + // const errorMsg = path + ' ' + message + ' ' + opeParam.prjInfo.hardwareSrcPath + '\n' + opeParam.prjInfo.hardwareSimPath; + // vscode.window.showErrorMessage(errorMsg); + // return undefined; } - for (const hdlModule of hdlFile.getAllHdlModules()) { + for (const hdlModule of moduleFile.getAllHdlModules()) { const hdlDependence = hdlParam.getAllDependences(path, hdlModule.name); if (hdlDependence) { // kernel supports `include, so only others are needed diff --git a/src/function/sim/simulate.ts b/src/function/sim/simulate.ts index e0fd3d6..855da58 100644 --- a/src/function/sim/simulate.ts +++ b/src/function/sim/simulate.ts @@ -6,9 +6,10 @@ import { hdlParam } from '../../hdlParser'; import { AbsPath, MainOutput, opeParam, ReportType } from '../../global'; import { hdlDir, hdlFile, hdlPath } from '../../hdlFs'; import { getSelectItem } from './instance'; -import { ToolChainType } from '../../global/enum'; -import { HdlModule } from '../../hdlParser/core'; +import { HdlLangID, ToolChainType } from '../../global/enum'; +import { HdlFile, HdlModule } from '../../hdlParser/core'; import { ModuleDataItem } from '../treeView/tree'; +import { defaultMacro, doFastApi } from '../../hdlParser/util'; type Path = string; @@ -334,7 +335,7 @@ class IcarusSimulate extends Simulate { if (deps) { return deps.others; } else { - MainOutput.report('Fail to get dependences of path: ' + path + ' name: ' + name, ReportType.Warn); + // MainOutput.report('Fail to get dependences of path: ' + path + ' name: ' + name, ReportType.Warn); return []; } } @@ -342,11 +343,11 @@ class IcarusSimulate extends Simulate { private simulateByHdlModule(hdlModule: HdlModule) { const name = hdlModule.name; const path = hdlModule.path; - if (!hdlParam.isTopModule(path, name, false)) { - const warningMsg = name + ' in ' + path + ' is not top module'; - MainOutput.report(warningMsg, ReportType.Warn, true); - return; - } + // if (!hdlParam.isTopModule(path, name, false)) { + // const warningMsg = name + ' in ' + path + ' is not top module'; + // MainOutput.report(warningMsg, ReportType.Warn, true); + // return; + // } const dependences = this.getAllOtherDependences(path, name); const simulationCommand = this.getCommand(name, path, dependences); if (simulationCommand) { @@ -364,19 +365,56 @@ class IcarusSimulate extends Simulate { this.simulateByHdlModule(hdlModule); } + public async tryGetModuleFromView(view: ModuleDataItem): Promise { + if (view.path) { + const path = hdlPath.toEscapePath(view.path); + const currentFile = hdlParam.getHdlFile(path); + if (currentFile) { + const modules = currentFile.getAllHdlModules(); + const targetModule = view.name === undefined ? + modules[0] : + modules.filter(mod => mod.name === view.name)[0]; + + if (targetModule) { + return targetModule; + } + } + // 没有获取有效的 module 则重新解析 + const langID = hdlFile.getLanguageId(path); + if (langID === HdlLangID.Unknown) { + return undefined; + } + const standardPath = hdlPath.toSlash(path); + + console.log('enter [doFastApi]'); + const response = await doFastApi(standardPath, 'common'); + console.log('response result: '); + console.log(response); + + const moduleFile = new HdlFile( + standardPath, langID, + response?.macro || defaultMacro, + response?.content || [], + 'common' + ); + // 从 hdlParam 中去除,避免干扰全局 + hdlParam.removeFromHdlFile(moduleFile); + const modules = moduleFile.getAllHdlModules(); + const targetModule = view.name === undefined ? + modules[0] : + modules.filter(mod => mod.name === view.name)[0]; + + if (targetModule) { + return targetModule; + } + } else { + return undefined; + } + } + public async simulateFile(view: ModuleDataItem) { - if (!view.path) { - MainOutput.report('module ' + view.name + ' is not a hdlFile', ReportType.Error, true); - return; - } + const targetModule = await this.tryGetModuleFromView(view); - const currentFile = hdlParam.getHdlFile(view.path); - if (!currentFile) { - MainOutput.report('path ' + view.path + ' is not a hdlFile', ReportType.Error, true); - return; - } - - const targetModule = currentFile.getAllHdlModules().filter(mod => mod.name === view.name)[0]; if (targetModule !== undefined) { this.simulateByHdlModule(targetModule); } else { diff --git a/src/global/opeParam.ts b/src/global/opeParam.ts index aa5ab9d..79d56b5 100644 --- a/src/global/opeParam.ts +++ b/src/global/opeParam.ts @@ -53,6 +53,7 @@ class OpeParam { private _firstSrcTopModule: FirstTopModuleDesc = OpeParamDefaults.topModule; private _firstSimTopModule: FirstTopModuleDesc = OpeParamDefaults.topModule; + private _openMode: 'folder' | 'file' = 'folder'; public get os() : string { return this._os; @@ -103,6 +104,10 @@ class OpeParam { return this._prjInfo.arch; } + public get openMode(): 'file' | 'folder' { + return this._openMode; + } + public setBasicInfo(os: string, extensionPath: AbsPath, workspacePath: AbsPath, @@ -112,7 +117,6 @@ class OpeParam { this._os = os; assert(fs.existsSync(extensionPath), 'extensionPath ' + extensionPath + ' not exist!'); - assert(fs.existsSync(workspacePath), 'workspacePath ' + workspacePath + ' not exist!'); assert(fs.existsSync(propertySchemaPath), 'propertySchemaPath ' + propertySchemaPath + ' not exist!'); assert(fs.existsSync(propertyInitPath), 'propertyInitPath ' + propertyInitPath + ' not exist!'); @@ -121,6 +125,13 @@ class OpeParam { this._propertyJsonPath = propertyJsonPath; this._propertySchemaPath = propertySchemaPath; this._propertyInitPath = propertyInitPath; + + // 如果 workspacePath 为空,说明当前是以单文件形式打开的 + if (fs.existsSync(workspacePath)) { + this._openMode = 'folder'; + } else { + this._openMode = 'file'; + } } public setFirstSrcTopModule(name: string | null, path: AbsPath | null) { diff --git a/src/hdlFs/path.ts b/src/hdlFs/path.ts index 4e46163..46d2983 100644 --- a/src/hdlFs/path.ts +++ b/src/hdlFs/path.ts @@ -1,7 +1,8 @@ import * as fspath from 'path'; import * as fs from 'fs'; +import * as os from 'os'; -import { AbsPath, RelPath } from '../global'; +import { AbsPath, opeParam, RelPath } from '../global'; /** * @param path @@ -93,6 +94,14 @@ function exist(path: AbsPath | undefined): boolean { return fs.existsSync(path); } +function toEscapePath(path: AbsPath): AbsPath { + if (os.platform() === 'win32') { + return path.startsWith('/') ? toSlash(path.slice(1)) : toSlash(path); + } else { + return toSlash(path); + } +} + export { toSlash, rel2abs, @@ -102,5 +111,6 @@ export { filename, extname, basename, - exist + exist, + toEscapePath }; \ No newline at end of file diff --git a/src/hdlParser/core.ts b/src/hdlParser/core.ts index 37295ae..5f13a12 100644 --- a/src/hdlParser/core.ts +++ b/src/hdlParser/core.ts @@ -370,6 +370,9 @@ class HdlParam { return moduleFiles; } + public removeFromHdlFile(hdlFile: HdlFile) { + this.pathToHdlFiles.delete(hdlFile.path); + } public deleteHdlFile(path: AbsPath) { path = hdlPath.toSlash(path); @@ -865,7 +868,7 @@ class HdlModule { } }; -class HdlFile { +export class HdlFile { public path: string; public languageId: HdlLangID; public type: common.HdlFileType; diff --git a/src/manager/PL/xilinx.ts b/src/manager/PL/xilinx.ts index 203df66..195fab7 100644 --- a/src/manager/PL/xilinx.ts +++ b/src/manager/PL/xilinx.ts @@ -131,6 +131,8 @@ class XilinxOperation { * @param config */ async launch(config: PLConfig): Promise { + const { t } = vscode.l10n; + this.guiLaunched = false; const vivadoTerminal = config.terminal; if (!vivadoTerminal) { @@ -140,12 +142,17 @@ class XilinxOperation { let scripts: string[] = []; let prjFilePath = this.prjPath as AbsPath; + // 找到所有的 xilinx 工程文件 const prjFiles = hdlFile.pickFileRecursive(prjFilePath, [], - filePath => filePath.endsWith('.xpr')); + filePath => filePath.endsWith('.xpr') + ); if (prjFiles.length) { if (prjFiles.length > 1) { - const selection = await vscode.window.showQuickPick(prjFiles, { placeHolder : "Which project you want to open?" }); + const selection = await vscode.window.showQuickPick(prjFiles, { + placeHolder : t('info.pl.xilinx.launch.pick-project-placeholder'), + canPickMany: false + }); if (selection) { this.open(selection, scripts); } diff --git a/src/manager/prj.ts b/src/manager/prj.ts index 6e8d84c..40dc8d4 100644 --- a/src/manager/prj.ts +++ b/src/manager/prj.ts @@ -106,18 +106,24 @@ class PrjManage { const searchPathSet = new PathSet(); const prjInfo = opeParam.prjInfo; const hardwareInfo = prjInfo.arch.hardware; - - // handle library first - const fileChange = await libManage.processLibFiles(prjInfo.library); - MainOutput.report(`libManage finish process, add ${fileChange.add.length} files, del ${fileChange.del.length} files`, ReportType.Info); - // add possible folder to search - searchPathSet.checkAdd(prjInfo.hardwareSrcPath); - searchPathSet.checkAdd(prjInfo.hardwareSimPath); - searchPathSet.checkAdd(hardwareInfo.sim); - searchPathSet.checkAdd(prjInfo.getLibraryCommonPaths()); - searchPathSet.checkAdd(prjInfo.getLibraryCustomPaths()); - + // 根据当前的打开模式来判断 + if (opeParam.openMode === 'file') { + // 如果是单文件模式,需要的操作 + } else { + // 先处理 lib 文件 + const fileChange = await libManage.processLibFiles(prjInfo.library); + MainOutput.report(`libManage finish process, add ${fileChange.add.length} files, del ${fileChange.del.length} files`, ReportType.Info); + + // 默认搜索路径包括: + // src, sim, lib + searchPathSet.checkAdd(prjInfo.hardwareSrcPath); + searchPathSet.checkAdd(prjInfo.hardwareSimPath); + searchPathSet.checkAdd(hardwareInfo.sim); + searchPathSet.checkAdd(prjInfo.getLibraryCommonPaths()); + searchPathSet.checkAdd(prjInfo.getLibraryCustomPaths()); + } + MainOutput.report(' search folders: ', ReportType.Debug); searchPathSet.files.forEach(p => MainOutput.report(p, ReportType.Debug)); @@ -126,7 +132,6 @@ class PrjManage { // do search const searchPaths = searchPathSet.files; - const hdlFiles = hdlFile.getHDLFiles(searchPaths, ignores); return hdlFiles; } @@ -177,7 +182,7 @@ class PrjManage { // 解析 hdl 文件,构建 hdlParam - const hdlFiles = await this.getPrjHardwareFiles(); + const hdlFiles = await this.getPrjHardwareFiles(); await hdlParam.initializeHdlFiles(hdlFiles, progress); // 根据 toolchain 解析合法的 IP,构建 hdlParam