Delegate TCL folding to server, fix bugs, and enhance stability

- Move TCL folding range computation from client to language server, avoiding duplicate regions.
- Serialize language server restarts to prevent multiple server instances running concurrently.
- Pin server-side Python dependencies to specific minor versions for improved stability and predictability.
- Make debug server connection non-fatal, allowing the language server to start even if the debugger isn't attached.
- Optimize semantic token generation by caching Tclint plugin commands.
This commit is contained in:
Christoph Brandau
2026-06-18 20:38:47 +02:00
parent 3ad3847045
commit f60c4563e4
7 changed files with 74 additions and 112 deletions
+34 -31
View File
@@ -15,7 +15,6 @@ import {
cdlDocumentSymbolProvider,
defDocumentSymbolProvider
} from "./common/handlers"
import { computeTclFoldingRanges } from "./common/folding"
import { registerLogger, traceError, traceLog, traceVerbose } from "./common/log/logging"
import {
checkVersion,
@@ -30,7 +29,7 @@ import { loadServerDefaults } from "./common/setup"
import { getLSClientTraceLevel } from "./common/utilities"
import { createOutputChannel, onDidChangeConfiguration, registerCommand } from "./common/vscodeapi"
let client: LanguageClient
let client: LanguageClient | undefined
export async function activate(context: vscode.ExtensionContext) {
// This is required to get server name and module. This should be
@@ -62,7 +61,7 @@ export async function activate(context: vscode.ExtensionContext) {
traceLog(`Module: ${serverInfo.module}`)
traceVerbose(`Full Server Info: ${JSON.stringify(serverInfo)}`)
const runServer = async () => {
const runServerImpl = async () => {
const interpreter = getInterpreterFromSetting(serverId)
if (interpreter && interpreter.length > 0) {
if (checkVersion(await resolveInterpreter(interpreter))) {
@@ -91,6 +90,16 @@ export async function activate(context: vscode.ExtensionContext) {
)
}
// Serialize server (re)starts. Overlapping triggers (interpreter change,
// config change, restart command, initial activation) would otherwise each
// read the stale module-level `client`, start a new server and leave the
// previous one running orphaned -> hints/hover shown multiple times.
let runServerQueue: Promise<void> = Promise.resolve()
const runServer = () => {
runServerQueue = runServerQueue.catch(() => undefined).then(() => runServerImpl())
return runServerQueue
}
context.subscriptions.push(
onDidChangePythonInterpreter(async () => {
await runServer()
@@ -116,16 +125,9 @@ export async function activate(context: vscode.ExtensionContext) {
}
})
// Folding ranges for TCL (brace based)
const tclFoldingProvider = vscode.languages.registerFoldingRangeProvider(
[{ language: "tcl" }],
{
provideFoldingRanges(document: vscode.TextDocument) {
return computeTclFoldingRanges(document)
}
}
)
context.subscriptions.push(tclFoldingProvider)
// Folding ranges for TCL are provided by the language server
// (folding_range_provider in lsp_server.py). No client-side provider here to
// avoid duplicate folding regions.
//
const formatCdlProvider = vscode.languages.registerDocumentFormattingEditProvider(
@@ -219,26 +221,27 @@ export async function activate(context: vscode.ExtensionContext) {
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))
context.subscriptions.push(
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))
}),
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<void> | undefined {