From 0e221a30f80a65eed3407cd5f60d5993f84b68db Mon Sep 17 00:00:00 2001 From: Marios Ntoulas Date: Wed, 4 Mar 2026 12:36:54 +0200 Subject: [PATCH 1/3] fix(debugger): update "Attach to server" configuration outFiles to include `/provider` --- .vscode/launch.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 445edf3..5ab8920 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -25,7 +25,7 @@ "address": "localhost", "restart": true, "outFiles": [ - "${workspaceFolder}/server/out/*.js" + "${workspaceFolder}/server/out/**/*.js" ] } ], From ba7acbfa6a9d35a0bfcb62c91fc52b439c3f35d4 Mon Sep 17 00:00:00 2001 From: Marios Ntoulas Date: Wed, 4 Mar 2026 12:39:46 +0200 Subject: [PATCH 2/3] fix(definition): implement jit symbol indexing on first interaction --- server/src/providers/definition.ts | 28 +++++++++++++++++++++------- server/src/server.ts | 5 ++--- server/src/utils.ts | 11 ++++++++++- 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/server/src/providers/definition.ts b/server/src/providers/definition.ts index 94f1ba0..8941527 100644 --- a/server/src/providers/definition.ts +++ b/server/src/providers/definition.ts @@ -4,7 +4,8 @@ import { URI } from 'vscode-uri'; import { DefinitionParams, DefinitionLink, Range } from 'vscode-languageserver/node'; import { TextDocument } from 'vscode-languageserver-textdocument'; import { JRefSymbol } from '../visitor'; -import { ServerContext } from '../utils'; +import { extractSymbols, ServerContext } from '../utils'; +import * as fs from 'fs'; const defaultTargetRange: Range = { start: { line: 0, character: 0 }, @@ -43,13 +44,26 @@ function createDefinitionLink( const uri = URI.parse(targetPath); const currentDir = path.dirname(URI.parse(document.uri).fsPath); const absolutePath = path.resolve(currentDir, uri.path.slice(1)); - const targetDocument = documents.get(URI.file(absolutePath).toString()); - const targetRange = getTargetRange(targetDocument); + const targetUri = URI.file(absolutePath).toString(); + const targetRange = getTargetRange(targetUri); - function getTargetRange(targetDocument: TextDocument | undefined): Range { - if (!targetDocument) return defaultTargetRange; - const targetSymbolTable = documentSymbols.get(targetDocument); - if (!targetSymbolTable) return defaultTargetRange; + function getTargetRange(targetUri: string): Range { + let targetDocument = documents.get(targetUri); + if (!targetDocument) { + try { + const filePath = URI.parse(targetUri).fsPath; + const content = fs.readFileSync(filePath, 'utf8'); + targetDocument = TextDocument.create(targetUri, 'jref', 1, content); + } catch (e) { + return defaultTargetRange; + } + } + let targetSymbolTable = documentSymbols.get(targetDocument); + if (!targetSymbolTable) { + const symbols = extractSymbols(targetDocument.getText()); + documentSymbols.set(targetDocument, symbols); + targetSymbolTable = symbols; + } const targetSymbol = targetSymbolTable?.get(uri.fragment); if (!targetSymbol) return defaultTargetRange; return { diff --git a/server/src/server.ts b/server/src/server.ts index 30a83c7..e7cd30f 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -16,6 +16,7 @@ import { createParseErrorDiagnostic } from './providers/diagnostics'; import { onDefinition } from './providers/definition'; import { SymbolTable, visit } from './visitor'; import { handleSemanticTokens, tokenTypes } from './providers/semanticTokens'; +import { extractSymbols } from './utils'; // Create a connection for the server, using Node's IPC as a transport. // Also include all preview / proposed LSP features. @@ -45,9 +46,7 @@ connection.onInitialize((params: InitializeParams) => { // when the text document first opened or when its content has changed. documents.onDidChangeContent((change: TextDocumentChangeEvent) => { const errors: ParseError[] = []; - const ast: Node | undefined = parseTree(change.document.getText(), errors); - const symbols: SymbolTable = new Map(); - visit(ast, symbols); + const symbols = extractSymbols(change.document.getText()); documentSymbols.set(change.document, symbols); sendDiagnostics(change.document, errors); }); diff --git a/server/src/utils.ts b/server/src/utils.ts index 6986815..973b8a9 100644 --- a/server/src/utils.ts +++ b/server/src/utils.ts @@ -1,8 +1,17 @@ import { TextDocuments } from 'vscode-languageserver/node'; -import { SymbolTable } from './visitor'; +import { SymbolTable, visit } from './visitor'; import { TextDocument } from 'vscode-languageserver-textdocument'; +import { ParseError, parseTree } from 'jsonc-parser'; export interface ServerContext { documents: TextDocuments; documentSymbols: WeakMap; } + +export function extractSymbols(content: string): SymbolTable { + const errors: ParseError[] = []; + const ast = parseTree(content, errors); + const symbols: SymbolTable = new Map(); + visit(ast, symbols); + return symbols; +} From 7a4aafa3b9db7bc02e1f47dafbb3079160ffcf46 Mon Sep 17 00:00:00 2001 From: Marios Ntoulas Date: Wed, 4 Mar 2026 13:14:10 +0200 Subject: [PATCH 3/3] fix: include errors in analysis result previously the `extractSymbols` was returning only symbols which broke diagnostics --- server/src/providers/definition.ts | 4 ++-- server/src/server.ts | 9 ++++----- server/src/utils.ts | 9 +++++++-- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/server/src/providers/definition.ts b/server/src/providers/definition.ts index 8941527..2c88530 100644 --- a/server/src/providers/definition.ts +++ b/server/src/providers/definition.ts @@ -4,7 +4,7 @@ import { URI } from 'vscode-uri'; import { DefinitionParams, DefinitionLink, Range } from 'vscode-languageserver/node'; import { TextDocument } from 'vscode-languageserver-textdocument'; import { JRefSymbol } from '../visitor'; -import { extractSymbols, ServerContext } from '../utils'; +import { analyze, ServerContext } from '../utils'; import * as fs from 'fs'; const defaultTargetRange: Range = { @@ -60,7 +60,7 @@ function createDefinitionLink( } let targetSymbolTable = documentSymbols.get(targetDocument); if (!targetSymbolTable) { - const symbols = extractSymbols(targetDocument.getText()); + const { symbols } = analyze(targetDocument.getText()); documentSymbols.set(targetDocument, symbols); targetSymbolTable = symbols; } diff --git a/server/src/server.ts b/server/src/server.ts index e7cd30f..e4508c9 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -10,13 +10,13 @@ import { import { TextDocument } from 'vscode-languageserver-textdocument'; -import { Node, ParseError, parseTree } from 'jsonc-parser'; +import { ParseError } from 'jsonc-parser'; import { createParseErrorDiagnostic } from './providers/diagnostics'; import { onDefinition } from './providers/definition'; -import { SymbolTable, visit } from './visitor'; +import { SymbolTable } from './visitor'; import { handleSemanticTokens, tokenTypes } from './providers/semanticTokens'; -import { extractSymbols } from './utils'; +import { analyze } from './utils'; // Create a connection for the server, using Node's IPC as a transport. // Also include all preview / proposed LSP features. @@ -45,8 +45,7 @@ connection.onInitialize((params: InitializeParams) => { // The content of a text document has changed. This event is emitted // when the text document first opened or when its content has changed. documents.onDidChangeContent((change: TextDocumentChangeEvent) => { - const errors: ParseError[] = []; - const symbols = extractSymbols(change.document.getText()); + const { symbols, errors } = analyze(change.document.getText()); documentSymbols.set(change.document, symbols); sendDiagnostics(change.document, errors); }); diff --git a/server/src/utils.ts b/server/src/utils.ts index 973b8a9..6785899 100644 --- a/server/src/utils.ts +++ b/server/src/utils.ts @@ -8,10 +8,15 @@ export interface ServerContext { documentSymbols: WeakMap; } -export function extractSymbols(content: string): SymbolTable { +export interface DocumentAnalysis { + symbols: SymbolTable; + errors: ParseError[]; +} + +export function analyze(content: string): DocumentAnalysis { const errors: ParseError[] = []; const ast = parseTree(content, errors); const symbols: SymbolTable = new Map(); visit(ast, symbols); - return symbols; + return { symbols, errors }; }