UNPKG

@imc-trading/svlangserver

Version:
388 lines (387 loc) 15.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); /* -------------------------------------------------------------------------------------------- * Licensed under the MIT License. See License.txt in the project root for license information. * ------------------------------------------------------------------------------------------ */ const node_1 = require("vscode-languageserver/node"); const vscode_languageserver_types_1 = require("vscode-languageserver-types"); const vscode_languageserver_textdocument_1 = require("vscode-languageserver-textdocument"); const svindexer_1 = require("./svindexer"); const svdefprovider_1 = require("./svdefprovider"); const diagnostics_1 = require("./diagnostics"); const svcompleter_1 = require("./svcompleter"); const svsignhelpprovider_1 = require("./svsignhelpprovider"); const svformatter_1 = require("./svformatter"); const svhier_1 = require("./svhier"); const genutils_1 = require("./genutils"); const svutils_1 = require("./svutils"); const BuildIndexCommand = "systemverilog.build_index"; const ReportHierarchyCommand = "systemverilog.report_hierarchy"; // Create a connection for the server, using Node's IPC as a transport. // Also include all preview / proposed LSP features. let connection = node_1.createConnection(node_1.ProposedFeatures.all); genutils_1.ConnectionLogger.setConnection(connection); // client capabilities let clientName; let hasConfigurationCapability = false; let hasShowWindowCapability = false; // Create a simple text document manager. let documents = new node_1.TextDocuments(vscode_languageserver_textdocument_1.TextDocument); let svindexer = new svindexer_1.SystemVerilogIndexer(); let svdefprovider = new svdefprovider_1.SystemVerilogDefinitionProvider(svindexer); let diagnostics = new diagnostics_1.VerilogDiagnostics(svindexer); let svcompleter = new svcompleter_1.SystemVerilogCompleter(svindexer); let svsignhelper = new svsignhelpprovider_1.SystemVerilogSignatureHelpProvider(svindexer); let svformatter = new svformatter_1.SystemVerilogFormatter(); let svhiercalculator = new svhier_1.SystemVerilogHierarchyCalculator(svindexer); let settings = svutils_1.default_settings; connection.onInitialize((params) => { hasConfigurationCapability = !!(params.capabilities.workspace && !!params.capabilities.workspace.configuration); hasShowWindowCapability = !!(params.capabilities.window && params.capabilities.window.showDocument); clientName = !!params.clientInfo ? params.clientInfo.name : undefined; try { svindexer.setRoot(genutils_1.uriToPath(params.rootUri)); if ((clientName.toLowerCase().startsWith("vscode")) || (clientName.toLowerCase().startsWith("visual studio code"))) { svindexer.setClientDir(".vscode"); } else if (clientName.toLowerCase().startsWith("coc.nvim")) { svindexer.setClientDir(".vim"); } else if (clientName.toLowerCase().startsWith("sublime")) { svindexer.setClientDir(".sublime"); } else if (clientName.toLowerCase().startsWith("emacs")) { svindexer.setClientDir(".emacs"); } else if (clientName.toLowerCase().startsWith("neovim")) { svindexer.setClientDir(".nvim"); } else { svindexer.setClientDir(".svlangserver"); } diagnostics.setOptionsFile(svindexer.getLinterOptionsFile()); } catch (error) { genutils_1.ConnectionLogger.error(error); } const result = { capabilities: { textDocumentSync: node_1.TextDocumentSyncKind.Incremental, // Tell the client that this server supports code completion. completionProvider: { resolveProvider: true }, documentSymbolProvider: true, workspaceSymbolProvider: true, definitionProvider: true, hoverProvider: true, signatureHelpProvider: { triggerCharacters: ['(', '[', ','], retriggerCharacters: [','] //TBD Not supported in CoC! }, executeCommandProvider: { commands: [ BuildIndexCommand, ReportHierarchyCommand, ] }, documentFormattingProvider: true, documentRangeFormattingProvider: true, } }; return result; }); function getCurrentSettings() { let currentSettings = new Object(); settings.forEach((val, prop) => { currentSettings[prop] = val; }); return { settings: currentSettings }; } function getSettings() { if (!hasConfigurationCapability) { return Promise.resolve(getCurrentSettings()); } else if (clientName == "coc.nvim") { return connection.workspace.getConfiguration().then(svSettings => { let initSettings = new Object(); settings.forEach((val, prop) => { initSettings[prop] = svSettings[prop] == undefined ? settings[prop] : svSettings[prop]; }); return { settings: initSettings }; }).catch(error => { genutils_1.ConnectionLogger.error(error); return getCurrentSettings(); }); } else { return connection.workspace.getConfiguration({ section: 'systemverilog' }).then(svSettings => { let initSettings = new Object(); settings.forEach((val, prop) => { let nprop = prop.substring("systemverilog.".length); initSettings[prop] = svSettings[nprop] == undefined ? settings[prop] : svSettings[nprop]; }); return { settings: initSettings }; }).catch(error => { genutils_1.ConnectionLogger.error(error); return getCurrentSettings(); }); } } let settingsInitialized = false; function updateSettings(change, updateIfNotInitialized = false) { let oldSettings = new Map(); for (let [prop, val] of settings.entries()) { oldSettings.set(prop, val); if (change.settings[prop] == undefined) { let hierParts = prop.split("."); let newVal = change.settings; for (let i = 0; i < hierParts.length; i++) { newVal = newVal[hierParts[i]]; if (newVal == undefined) { break; } } settings.set(prop, newVal == undefined ? val : newVal); } else { settings.set(prop, change.settings[prop]); } } for (let [prop, val] of settings.entries()) { genutils_1.ConnectionLogger.log(`INFO: settings[${prop}] = ${settings.get(prop)}`); } let forceUpdate = !settingsInitialized && updateIfNotInitialized; let definesChanged = forceUpdate || !genutils_1.isStringListEqual(oldSettings.get("systemverilog.defines"), settings.get("systemverilog.defines")); if (forceUpdate || definesChanged || !genutils_1.isStringListEqual(oldSettings.get("systemverilog.includeIndexing"), settings.get("systemverilog.includeIndexing")) || !genutils_1.isStringListEqual(oldSettings.get("systemverilog.mustIncludeIndexing"), settings.get("systemverilog.mustIncludeIndexing")) || !genutils_1.isStringListEqual(oldSettings.get("systemverilog.excludeIndexing"), settings.get("systemverilog.excludeIndexing"))) { if (definesChanged) { svindexer.setDefines(settings.get("systemverilog.defines")); } svindexer.index(settings.get("systemverilog.includeIndexing"), settings.get("systemverilog.mustIncludeIndexing"), settings.get("systemverilog.excludeIndexing")); } if (forceUpdate || !genutils_1.isStringListEqual(oldSettings.get("systemverilog.libraryIndexing"), settings.get("systemverilog.libraryIndexing"))) { svindexer.setLibraries(settings.get("systemverilog.libraryIndexing"), settings.get("systemverilog.excludeIndexing")); } diagnostics.setLinter(settings.get("systemverilog.linter")); diagnostics.setCommand(settings.get("systemverilog.launchConfiguration")); diagnostics.setDefines(settings.get("systemverilog.defines")); diagnostics.setWhitelistedMessages(settings.get("systemverilog.linterWhitelist")); svformatter.setCommand(settings.get("systemverilog.formatCommand")); settingsInitialized = true; } connection.onInitialized(() => { try { getSettings() .then(initSettings => updateSettings(initSettings, true)) .catch(error => { genutils_1.ConnectionLogger.error(error); }); } catch (error) { genutils_1.ConnectionLogger.error(error); } }); connection.onDidChangeConfiguration(change => { try { updateSettings(change); } catch (error) { genutils_1.ConnectionLogger.error(error); } }); documents.onDidChangeContent(change => { try { svindexer.processDocumentChanges(change.document); if (settings.get("systemverilog.lintOnUnsaved")) { lintDocument(change.document.uri, change.document.getText()); } } catch (error) { genutils_1.ConnectionLogger.error(error); } }); // This handler provides the initial list of the completion items. connection.onCompletion((_textDocumentPosition) => { try { if (settings.get("systemverilog.disableCompletionProvider")) { return []; } return svcompleter.completionItems(documents.get(_textDocumentPosition.textDocument.uri), _textDocumentPosition.position); //TBD try-catch } catch (error) { genutils_1.ConnectionLogger.error(error); return []; } }); connection.onCompletionResolve((item) => { return item; }); connection.onDocumentSymbol((documentSymbolParams) => { try { return svindexer.getDocumentSymbols(documents.get(documentSymbolParams.textDocument.uri)); } catch (error) { genutils_1.ConnectionLogger.error(error); return Promise.resolve([]); } }); connection.onWorkspaceSymbol((workspaceSymbolParams) => { try { return svindexer.getWorkspaceSymbols(workspaceSymbolParams.query); } catch (error) { genutils_1.ConnectionLogger.error(error); return Promise.resolve([]); } }); connection.onDefinition((textDocumentPosition) => { try { return svdefprovider.getDefinitionSymbolLocation(documents.get(textDocumentPosition.textDocument.uri), textDocumentPosition.position); } catch (error) { genutils_1.ConnectionLogger.error(error); return Promise.resolve([]); } }); connection.onHover((hoverParams) => { try { if (settings.get("systemverilog.disableHoverProvider")) { return Promise.resolve(undefined); } let defText = svdefprovider.getDefinitionText(documents.get(hoverParams.textDocument.uri), hoverParams.position); if ((defText[0] == undefined) || (defText[1] == undefined)) { return Promise.resolve(undefined); } return Promise.resolve({ contents: { kind: node_1.MarkupKind.Markdown, value: (defText[0].length > 0 ? [`*${defText[0]}*`] : []).concat([(clientName == "coc.nvim") ? "```systemverilog" : "```"]).concat(defText[1]).concat(["```"]).join('\n'), }, }); } catch (error) { genutils_1.ConnectionLogger.error(error); return Promise.resolve(undefined); } }); function lintDocument(uri, text) { if (settings.get("systemverilog.disableLinting")) { return; } diagnostics.lint(genutils_1.uriToPath(uri), text) .then((diagnostics) => { connection.sendDiagnostics({ uri: uri, diagnostics }); }) .catch((error) => { genutils_1.ConnectionLogger.error(error); }); } documents.onDidOpen((event) => { try { svindexer.indexOpenDocument(event.document); lintDocument(event.document.uri); } catch (error) { genutils_1.ConnectionLogger.error(error); } }); documents.onDidSave((event) => { try { svindexer.indexOpenDocument(event.document); svindexer.updateFileInfoOnSave(event.document); lintDocument(event.document.uri); } catch (error) { genutils_1.ConnectionLogger.error(error); } }); connection.onSignatureHelp((textDocumentPosition) => { try { if (settings.get("systemverilog.disableSignatureHelpProvider")) { return undefined; } return svsignhelper.getSignatures(documents.get(textDocumentPosition.textDocument.uri), textDocumentPosition.position.line, textDocumentPosition.position.character); } catch (error) { genutils_1.ConnectionLogger.error(error); return undefined; } }); connection.onExecuteCommand((commandParams) => { try { if (commandParams.command == BuildIndexCommand) { svindexer.index(settings.get("systemverilog.includeIndexing"), settings.get("systemverilog.mustIncludeIndexing"), settings.get("systemverilog.excludeIndexing")); } else if (commandParams.command == ReportHierarchyCommand) { if ((commandParams.arguments == undefined) || (commandParams.arguments.length != 1)) { genutils_1.ConnectionLogger.error(`${ReportHierarchyCommand} needs the module/interface name as an argument`); return; } const fileUri = svhiercalculator.calcHier(commandParams.arguments[0]); genutils_1.ConnectionLogger.log(`Hierarchy for ${commandParams.arguments[0]} available at ${fileUri}`); if (hasShowWindowCapability) { connection.sendRequest("window/showDocument", { uri: fileUri, takeFocus: true }); } else { const editParams = { label: "Hierarchy", edit: { documentChanges: [ vscode_languageserver_types_1.TextDocumentEdit.create({ uri: fileUri, version: null }, []), ] } }; connection.sendRequest("workspace/applyEdit", editParams); } } else { genutils_1.ConnectionLogger.error(`Unhandled command ${commandParams.command}`); } } catch (error) { genutils_1.ConnectionLogger.error(error); } }); connection.onDocumentFormatting((formatParams) => { try { return svformatter.format(documents.get(formatParams.textDocument.uri), null, formatParams.options); } catch (error) { genutils_1.ConnectionLogger.error(error); return Promise.resolve([]); } }); connection.onDocumentRangeFormatting((rangeFormatParams) => { try { return svformatter.format(documents.get(rangeFormatParams.textDocument.uri), rangeFormatParams.range, rangeFormatParams.options); } catch (error) { genutils_1.ConnectionLogger.error(error); return Promise.resolve([]); } }); connection.onShutdown((token) => { diagnostics.cleanupTmpFiles(); svindexer.saveIndexOnExit(); }); // Save index on exit connection.onExit(() => { diagnostics.cleanupTmpFiles(); svindexer.saveIndexOnExit(); }); process.on('exit', () => { diagnostics.cleanupTmpFiles(); svindexer.saveIndexOnExit(); }); process.on('SIGTERM', () => { diagnostics.cleanupTmpFiles(); svindexer.saveIndexOnExit(); }); // Make the text document manager listen on the connection // for open, change and close text document events documents.listen(connection); // Listen on the connection connection.listen();