import * as vscode from "vscode" import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind } from "vscode-languageclient/node" import { formatCdlFile, completionHandlerCdl, hoverCdlHandler, formatDefFile, isFirstLineMachine, diagnosticHandler, tclDocumentSymbolProvider } from "./common/handlers" import { registerLogger, traceError, traceLog, traceVerbose } from "./common/log/logging" import { checkVersion, getInterpreterDetails, initializePython, onDidChangePythonInterpreter, resolveInterpreter } from "./common/python" import { restartServer } from "./common/server" import { checkIfConfigurationChanged, getInterpreterFromSetting } from "./common/settings" import { loadServerDefaults } from "./common/setup" import { getLSClientTraceLevel } from "./common/utilities" import { createOutputChannel, onDidChangeConfiguration, registerCommand } from "./common/vscodeapi" let client: LanguageClient export async function activate(context: vscode.ExtensionContext) { // This is required to get server name and module. This should be // the first thing that we do in this extension. const serverInfo = loadServerDefaults() const serverName = serverInfo.name const serverId = serverInfo.module // Setup logging const outputChannel = createOutputChannel(serverName) context.subscriptions.push(outputChannel, registerLogger(outputChannel)) const changeLogLevel = async (c: vscode.LogLevel, g: vscode.LogLevel) => { const level = getLSClientTraceLevel(c, g) await client?.setTrace(level) } context.subscriptions.push( outputChannel.onDidChangeLogLevel(async (e) => { await changeLogLevel(e, vscode.env.logLevel) }), vscode.env.onDidChangeLogLevel(async (e) => { await changeLogLevel(outputChannel.logLevel, e) }) ) // Log Server information traceLog(`Name: ${serverInfo.name}`) traceLog(`Module: ${serverInfo.module}`) traceVerbose(`Full Server Info: ${JSON.stringify(serverInfo)}`) const runServer = async () => { const interpreter = getInterpreterFromSetting(serverId) if (interpreter && interpreter.length > 0) { if (checkVersion(await resolveInterpreter(interpreter))) { traceVerbose( `Using interpreter from ${serverInfo.module}.interpreter: ${interpreter.join(" ")}` ) client = await restartServer(serverId, serverName, outputChannel, client) } return } const interpreterDetails = await getInterpreterDetails() if (interpreterDetails.path) { traceVerbose( `Using interpreter from Python extension: ${interpreterDetails.path.join(" ")}` ) client = await restartServer(serverId, serverName, outputChannel, client) return } traceError( "Python interpreter missing:\r\n" + "[Option 1] Select python interpreter using the ms-python.python.\r\n" + `[Option 2] Set an interpreter using "${serverId}.interpreter" setting.\r\n` + "Please use Python 3.8 or greater." ) } context.subscriptions.push( onDidChangePythonInterpreter(async () => { await runServer() }), onDidChangeConfiguration(async (e: vscode.ConfigurationChangeEvent) => { if (checkIfConfigurationChanged(e, serverId)) { await runServer() } }), registerCommand(`${serverId}.restart`, async () => { await runServer() }) ) setImmediate(async () => { const interpreter = getInterpreterFromSetting(serverId) if (interpreter === undefined || interpreter.length === 0) { traceLog(`Python extension loading`) await initializePython(context.subscriptions) traceLog(`Python extension loaded`) } else { await runServer() } }) // const formatCdlProvider = vscode.languages.registerDocumentFormattingEditProvider( { scheme: "file", language: "cdl" }, { provideDocumentFormattingEdits(document: vscode.TextDocument): vscode.TextEdit[] { const text = document.getText() const formattedText = formatCdlFile(text) const fullRange = new vscode.Range( document.positionAt(0), document.positionAt(text.length) ) return [vscode.TextEdit.replace(fullRange, formattedText)] } } ) context.subscriptions.push(formatCdlProvider) const completionCdlProvider = vscode.languages.registerCompletionItemProvider( { scheme: "file", language: "cdl" }, { provideCompletionItems( document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext ) { return completionHandlerCdl(document, position) } }, " " // Trigger completion on space ) context.subscriptions.push(completionCdlProvider) const hoverCdlProvider = vscode.languages.registerHoverProvider( { scheme: "file", language: "cdl" }, { provideHover( document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken ) { return hoverCdlHandler(document, position) } } ) context.subscriptions.push(hoverCdlProvider) const formatDefProvider = vscode.languages.registerDocumentFormattingEditProvider( { scheme: "file", language: "def" }, { provideDocumentFormattingEdits(document: vscode.TextDocument): vscode.TextEdit[] { const text = document.getText() const formattedText = formatDefFile(text) const fullRange = new vscode.Range( document.positionAt(0), document.positionAt(text.length) ) return [vscode.TextEdit.replace(fullRange, formattedText)] } } ) context.subscriptions.push(formatDefProvider) const tclOutlineProvider = vscode.languages.registerDocumentSymbolProvider( { scheme: "file", language: "tcl" }, { provideDocumentSymbols: tclDocumentSymbolProvider } ) context.subscriptions.push(tclOutlineProvider) // Diagnostics collection const diagnosticCollectionCdl = vscode.languages.createDiagnosticCollection("cdl") const diagnosticCollectionDef = vscode.languages.createDiagnosticCollection("def") context.subscriptions.push(diagnosticCollectionCdl, diagnosticCollectionDef) // Check if the first line of the CDL file contains "MACHINE" vscode.workspace.onDidOpenTextDocument((document) => { if (document.languageId === "cdl" || document.languageId === "def") { if (document.languageId === "cdl") { diagnosticCollectionCdl.set(document.uri, diagnosticHandler(document)) } else if (document.languageId === "def") { diagnosticCollectionDef.set(document.uri, diagnosticHandler(document)) } } }) vscode.workspace.onDidChangeTextDocument((event) => { const document = event.document if (document.languageId === "cdl" || document.languageId === "def") { if (document.languageId === "cdl") { diagnosticCollectionCdl.set(document.uri, diagnosticHandler(document)) } else if (document.languageId === "def") { diagnosticCollectionDef.set(document.uri, diagnosticHandler(document)) } } }) } export function deactivate(): Thenable | undefined { if (!client) { return undefined } return client.stop() }