From fe90ed730ca8218597978c404eba353ccfa25f79 Mon Sep 17 00:00:00 2001 From: Kirigaya <1193466151@qq.com> Date: Mon, 11 Dec 2023 23:04:22 +0800 Subject: [PATCH] finish linter for sv --- .vscodeignore | 3 +- design/lsp.drawio | 120 ++++++++++++++++++ package.json | 20 +++ package.nls.json | 1 + package.nls.zh-cn.json | 1 + package.nls.zh-tw.json | 1 + script/test/svlogAll.js | 8 ++ src/function/index.ts | 2 + src/function/lsp/linter/command.ts | 39 +++++- src/function/lsp/linter/index.ts | 7 +- src/function/lsp/linter/svlog.ts | 192 +++++++++++++++++++++++++++++ src/monitor/event.ts | 7 +- 12 files changed, 394 insertions(+), 7 deletions(-) create mode 100644 design/lsp.drawio create mode 100644 script/test/svlogAll.js create mode 100644 src/function/lsp/linter/svlog.ts diff --git a/.vscodeignore b/.vscodeignore index 3a191d2..ce086d0 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -13,4 +13,5 @@ script resources/**/*.js resources/**/*.d.ts resources/**/*.wasm -tsconfig.json \ No newline at end of file +tsconfig.json +design \ No newline at end of file diff --git a/design/lsp.drawio b/design/lsp.drawio new file mode 100644 index 0000000..d39d93f --- /dev/null +++ b/design/lsp.drawio @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/package.json b/package.json index ca3f4a9..2bafa7b 100644 --- a/package.json +++ b/package.json @@ -238,6 +238,21 @@ "default": "default", "description": "choose diagnostor to do linter in editing verilog" }, + "digital-ide.function.lsp.linter.svlog.diagnostor": { + "type": "string", + "enumDescriptions": [ + "use diagnostor in vivado", + "use diagnostor in modelsim", + "use our buildin diagnostor" + ], + "enum": [ + "vivado", + "modelsim", + "default" + ], + "default": "default", + "description": "choose diagnostor to do linter in editing verilog" + }, "digital-ide.function.lsp.linter.vhdl.diagnostor": { "type": "string", "enumDescriptions": [ @@ -504,6 +519,11 @@ "category": "Digital-IDE", "title": "%digital-ide.lsp.vlog.linter.pick.title%" }, + { + "command": "digital-ide.lsp.svlog.linter.pick", + "category": "Digital-IDE", + "title": "%digital-ide.lsp.svlog.linter.pick.title%" + }, { "command": "digital-ide.lsp.vhdl.linter.pick", "category": "Digital-IDE", diff --git a/package.nls.json b/package.nls.json index 8c7d739..89c3d6c 100644 --- a/package.nls.json +++ b/package.nls.json @@ -42,6 +42,7 @@ "digital-ide.fsm.show.title": "Show FSM graph of current file", "digital-ide.netlist.show.title": "Show netlist of current file", "digital-ide.lsp.vlog.linter.pick.title": "select a diagnostic for verilog", + "digital-ide.lsp.svlog.linter.pick.title": "select a diagnostic for systemverilog verilog", "digital-ide.lsp.vhdl.linter.pick.title": "select a diagnostic for vhdl", "digital-ide.lsp.systemverilog.linter.pick.title": "select a diagnostic for systemverilog" } \ No newline at end of file diff --git a/package.nls.zh-cn.json b/package.nls.zh-cn.json index ed5abd0..3e4cd00 100644 --- a/package.nls.zh-cn.json +++ b/package.nls.zh-cn.json @@ -42,6 +42,7 @@ "digital-ide.fsm.show.title": "显示当前文件的FSM图", "digital-ide.netlist.show.title": "显示当前文件的netlist", "digital-ide.lsp.vlog.linter.pick.title": "选择 Verilog 的诊断", + "digital-ide.lsp.svlog.linter.pick.title": "选择 System Verilog 的诊断", "digital-ide.lsp.vhdl.linter.pick.title": "选择 VHDL 的诊断", "digital-ide.lsp.systemverilog.linter.pick.title": "选择 SystemVerilog 的诊断" } \ No newline at end of file diff --git a/package.nls.zh-tw.json b/package.nls.zh-tw.json index 9670943..5404e02 100644 --- a/package.nls.zh-tw.json +++ b/package.nls.zh-tw.json @@ -42,6 +42,7 @@ "digital-ide.fsm.show.title": "顯示當前文件的FSM圖", "digital-ide.netlist.show.title": "顯示當前文件的netlist", "digital-ide.lsp.vlog.linter.pick.title": "選擇 Verilog 的診斷", + "digital-ide.lsp.svlog.linter.pick.title": "選擇 System Verilog 的診斷", "digital-ide.lsp.vhdl.linter.pick.title": "選擇 VHDL 的診斷", "digital-ide.lsp.systemverilog.linter.pick.title": "選擇 SystemVerilog 的診斷" } \ No newline at end of file diff --git a/script/test/svlogAll.js b/script/test/svlogAll.js new file mode 100644 index 0000000..e545415 --- /dev/null +++ b/script/test/svlogAll.js @@ -0,0 +1,8 @@ +const { svAll } = require('../../resources/hdlParser'); + +const testFile = '../Digital-Test/svlog/user/src/hello.sv'; + +(async () => { + const all = await svAll(testFile); + console.log(JSON.stringify(all, null, ' ')); +})(); \ No newline at end of file diff --git a/src/function/index.ts b/src/function/index.ts index efb542f..ad2be4f 100644 --- a/src/function/index.ts +++ b/src/function/index.ts @@ -97,9 +97,11 @@ function registerLsp(context: vscode.ExtensionContext) { lspCore.hdlSymbolStorage.initialise(); lspLinter.vlogLinterManager.initialise(); lspLinter.vhdlLinterManager.initialise(); + lspLinter.svlogLinterManager.initialise(); vscode.commands.registerCommand('digital-ide.lsp.vlog.linter.pick', lspLinter.pickVlogLinter); vscode.commands.registerCommand('digital-ide.lsp.vhdl.linter.pick', lspLinter.pickVhdlLinter); + vscode.commands.registerCommand('digital-ide.lsp.svlog.linter.pick', lspLinter.pickSvlogLinter); } diff --git a/src/function/lsp/linter/command.ts b/src/function/lsp/linter/command.ts index a2e572f..3c07979 100644 --- a/src/function/lsp/linter/command.ts +++ b/src/function/lsp/linter/command.ts @@ -108,6 +108,42 @@ async function pickVlogLinter() { pickWidget.show(); } + +async function pickSvlogLinter() { + const pickWidget = vscode.window.createQuickPick(); + pickWidget.placeholder = 'select a linter for verilog code diagnostic'; + pickWidget.canSelectMany = false; + + await vscode.window.withProgress({ + location: vscode.ProgressLocation.Notification, + title: 'Parsing local environment ...', + cancellable: true + }, async () => { + pickWidget.items = [ + // TODO : add this if system verilog is supported + // await makeDefaultPickItem(), + await makeVivadoPickItem(HdlLangID.Verilog), + await makeModelsimPickItem(HdlLangID.Verilog) + ]; + }); + + pickWidget.onDidChangeSelection(items => { + const selectedItem = items[0]; + _selectVlogLinter = selectedItem.name; + }); + + pickWidget.onDidAccept(() => { + if (_selectVlogLinter) { + const vlogLspConfig = vscode.workspace.getConfiguration('digital-ide.function.lsp.linter.svlog'); + vlogLspConfig.update('diagnostor', _selectVlogLinter); + pickWidget.hide(); + } + }); + + pickWidget.show(); +} + + async function pickVhdlLinter() { const pickWidget = vscode.window.createQuickPick(); pickWidget.placeholder = 'select a linter for code diagnostic'; @@ -145,5 +181,6 @@ async function pickVhdlLinter() { export { pickVlogLinter, - pickVhdlLinter + pickVhdlLinter, + pickSvlogLinter }; \ No newline at end of file diff --git a/src/function/lsp/linter/index.ts b/src/function/lsp/linter/index.ts index 1d2b5ee..2c70be1 100644 --- a/src/function/lsp/linter/index.ts +++ b/src/function/lsp/linter/index.ts @@ -1,11 +1,14 @@ import { vlogLinterManager } from './vlog'; import { vhdlLinterManager } from './vhdl'; +import { svlogLinterManager } from './svlog'; -import { pickVlogLinter, pickVhdlLinter } from './command'; +import { pickVlogLinter, pickVhdlLinter, pickSvlogLinter } from './command'; export { vlogLinterManager, vhdlLinterManager, + svlogLinterManager, pickVlogLinter, - pickVhdlLinter + pickVhdlLinter, + pickSvlogLinter, }; \ No newline at end of file diff --git a/src/function/lsp/linter/svlog.ts b/src/function/lsp/linter/svlog.ts new file mode 100644 index 0000000..b2dc942 --- /dev/null +++ b/src/function/lsp/linter/svlog.ts @@ -0,0 +1,192 @@ +import * as vscode from 'vscode'; +import { LspOutput, ReportType } from '../../../global'; +import { HdlLangID } from '../../../global/enum'; +import { BaseLinter, BaseManager } from './base'; +import { defaultVlogLinter } from './default'; +import { modelsimLinter } from './modelsim'; +import { vivadoLinter } from './vivado'; +import { hdlFile, hdlPath } from '../../../hdlFs'; + +class SvlogLinterManager implements BaseManager { + currentLinter: BaseLinter | undefined; + activateLinterName: string; + statusBarItem: vscode.StatusBarItem; + initialized: boolean; + + constructor() { + this.activateLinterName = 'default'; + this.initialized = false; + + // make a status bar for rendering + this.statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right); + this.statusBarItem.command = 'digital-ide.lsp.svlog.linter.pick'; + + // when changing file, hide if langID is not verilog + vscode.window.onDidChangeActiveTextEditor(editor => { + if (!editor) { + return; + } + const currentFileName = hdlPath.toSlash(editor.document.fileName); + + if (hdlFile.isSystemVerilogFile(currentFileName)) { + this.statusBarItem.show(); + } else { + this.statusBarItem.hide(); + } + }); + + // update when user's config is changed + vscode.workspace.onDidChangeConfiguration(() => { + this.updateLinter(); + }); + } + + async initialise(): Promise { + const success = await this.updateLinter(); + + if (!success) { + return; + } + + this.initialized = true; + + for (const doc of vscode.workspace.textDocuments) { + const fileName = hdlPath.toSlash(doc.fileName); + if (hdlFile.isSystemVerilogFile(fileName)) { + await this.lint(doc); + } + } + LspOutput.report(' finish initialization of svlog linter. Linter name: ' + this.activateLinterName, ReportType.Launch); + + // hide it if current window is not verilog + const editor = vscode.window.activeTextEditor; + if (editor && hdlFile.isSystemVerilogFile(editor.document.fileName)) { + this.statusBarItem.show(); + } else { + this.statusBarItem.hide(); + } + } + + async lint(document: vscode.TextDocument) { + this.currentLinter?.remove(document.uri); + await this.currentLinter?.lint(document); + } + + async remove(uri: vscode.Uri): Promise { + this.currentLinter?.remove(uri); + } + + public getUserDiagnostorSelection() { + const vlogLspConfig = vscode.workspace.getConfiguration('digital-ide.function.lsp.linter.svlog'); + const diagnostor = vlogLspConfig.get('diagnostor', 'xxx'); + return diagnostor; + } + + public async updateLinter(): Promise { + const diagnostorName = this.getUserDiagnostorSelection(); + + const lastDiagnostorName = this.activateLinterName; + const lastDiagnostor = this.currentLinter; + + if (this.initialized && diagnostorName === lastDiagnostorName) { + // no need for update + return true; + } + LspOutput.report(` detect linter setting changes, switch from ${lastDiagnostorName} to ${diagnostorName}.`, ReportType.Launch); + + let launch = false; + switch (diagnostorName) { + case 'vivado': launch = await this.activateVivado(); break; + case 'modelsim': launch = await this.activateModelsim(); break; + case 'default': launch = await this.activateDefault(); break; + default: launch = await this.activateDefault(); break; + } + + for (const doc of vscode.workspace.textDocuments) { + const fileName = hdlPath.toSlash(doc.fileName); + if (hdlFile.isSystemVerilogFile(fileName)) { + lastDiagnostor?.remove(doc.uri); + await this.lint(doc); + } + } + + return launch; + } + + public async activateVivado(): Promise { + const selectedLinter = vivadoLinter; + let launch = true; + + launch = await selectedLinter.initialise(HdlLangID.SystemVerilog); + if (launch) { + this.statusBarItem.text = '$(getting-started-beginner) Linter(vivado)'; + + LspOutput.report(' vivado linter has been activated', ReportType.Info); + } else { + this.statusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.warningBackground'); + this.statusBarItem.tooltip = 'Fail to launch vivado linter'; + this.statusBarItem.text = '$(extensions-warning-message) Linter(vivado)'; + + LspOutput.report(' Fail to launch vivado linter', ReportType.Error); + } + + this.currentLinter = selectedLinter; + this.activateLinterName = 'vivado'; + this.statusBarItem.show(); + + return launch; + } + + public async activateModelsim(): Promise { + const selectedLinter = modelsimLinter; + let launch = true; + + launch = await selectedLinter.initialise(HdlLangID.SystemVerilog); + if (launch) { + this.statusBarItem.text = '$(getting-started-beginner) Linter(modelsim)'; + + LspOutput.report(' modelsim linter has been activated', ReportType.Info); + } else { + this.statusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.warningBackground'); + this.statusBarItem.tooltip = 'Fail to launch modelsim linter'; + this.statusBarItem.text = '$(extensions-warning-message) Linter(modelsim)'; + + LspOutput.report(' Fail to launch modelsim linter', ReportType.Error); + } + + this.currentLinter = selectedLinter; + this.activateLinterName = 'modelsim'; + this.statusBarItem.show(); + + return launch; + } + + public async activateDefault(): Promise { + const selectedLinter = defaultVlogLinter; + let launch = true; + + if (launch) { + this.statusBarItem.text = '$(getting-started-beginner) Linter(default)'; + + LspOutput.report(' default build-in linter has been activated', ReportType.Info); + } else { + this.statusBarItem.backgroundColor = undefined; + this.statusBarItem.tooltip = 'Fail to launch default linter'; + this.statusBarItem.text = '$(extensions-warning-message) Linter(default)'; + + LspOutput.report(' Fail to launch default linter', ReportType.Error); + } + + this.currentLinter = selectedLinter; + this.activateLinterName = 'default'; + this.statusBarItem.show(); + + return launch; + } +} + +const svlogLinterManager = new SvlogLinterManager(); + +export { + svlogLinterManager +}; diff --git a/src/monitor/event.ts b/src/monitor/event.ts index e4019f5..2aee56f 100644 --- a/src/monitor/event.ts +++ b/src/monitor/event.ts @@ -14,8 +14,7 @@ import { libManage } from '../manager/lib'; import type { HdlMonitor } from './index'; import { HdlLangID, ToolChainType } from '../global/enum'; import { hdlSymbolStorage } from '../function/lsp/core'; -import { vlogLinterManager, vhdlLinterManager } from '../function/lsp/linter'; -import { isVerilogFile } from '../hdlFs/file'; +import { vlogLinterManager, vhdlLinterManager, svlogLinterManager } from '../function/lsp/linter'; enum Event { Add = 'add', // emit when add file @@ -102,6 +101,8 @@ class HdlAction extends BaseAction { vlogLinterManager.remove(uri); } else if (langID === HdlLangID.Vhdl) { vhdlLinterManager.remove(uri); + } else if (langID === HdlLangID.SystemVerilog) { + svlogLinterManager.remove(uri); } } @@ -141,7 +142,7 @@ class HdlAction extends BaseAction { } else if (langID === HdlLangID.Vhdl) { vhdlLinterManager.lint(document); } else if (langID === HdlLangID.SystemVerilog) { - // TODO + svlogLinterManager.lint(document); } }