From 0574629904bf9e1481b464579b44b958195d419b Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Thu, 6 Nov 2025 13:29:58 -0800 Subject: [PATCH] cache it --- vscode-extension/server/src/diagnostics.ts | 10 ++-- vscode-extension/server/src/semanticTokens.ts | 6 +-- vscode-extension/server/src/server.ts | 47 +++++++++++++++---- 3 files changed, 43 insertions(+), 20 deletions(-) diff --git a/vscode-extension/server/src/diagnostics.ts b/vscode-extension/server/src/diagnostics.ts index 2f1a449..3c92368 100644 --- a/vscode-extension/server/src/diagnostics.ts +++ b/vscode-extension/server/src/diagnostics.ts @@ -1,12 +1,12 @@ import { TextDocument, Position } from 'vscode-languageserver-textdocument' import { Diagnostic, DiagnosticSeverity } from 'vscode-languageserver/node' -import { parser } from '../../../src/parser/shrimp' +import { Tree } from '@lezer/common' import { Compiler } from '../../../src/compiler/compiler' import { CompilerError } from '../../../src/compiler/compilerError' -export const buildDiagnostics = (textDocument: TextDocument): Diagnostic[] => { +export const buildDiagnostics = (textDocument: TextDocument, tree: Tree): Diagnostic[] => { const text = textDocument.getText() - const diagnostics = getParseErrors(textDocument) + const diagnostics = getParseErrors(textDocument, tree) if (diagnostics.length > 0) { return diagnostics @@ -59,9 +59,7 @@ const unknownDiagnostic = (message: string): Diagnostic => { return diagnostic } -const getParseErrors = (textDocument: TextDocument): Diagnostic[] => { - const tree = parser.parse(textDocument.getText()) - +const getParseErrors = (textDocument: TextDocument, tree: Tree): Diagnostic[] => { const ranges: { start: Position; end: Position }[] = [] tree.iterate({ enter(n) { diff --git a/vscode-extension/server/src/semanticTokens.ts b/vscode-extension/server/src/semanticTokens.ts index 3aaca34..3cd8079 100644 --- a/vscode-extension/server/src/semanticTokens.ts +++ b/vscode-extension/server/src/semanticTokens.ts @@ -1,6 +1,6 @@ import { parser } from '../../../src/parser/shrimp' import * as Terms from '../../../src/parser/shrimp.terms' -import { SyntaxNode } from '@lezer/common' +import { SyntaxNode, Tree } from '@lezer/common' import { TextDocument } from 'vscode-languageserver-textdocument' import { SemanticTokensBuilder, @@ -28,9 +28,7 @@ export const TOKEN_MODIFIERS = [ SemanticTokenModifiers.readonly, ] -export function buildSemanticTokens(document: TextDocument): number[] { - const text = document.getText() - const tree = parser.parse(text) +export function buildSemanticTokens(document: TextDocument, tree: Tree): number[] { const builder = new SemanticTokensBuilder() const scopeTracker = new EditorScopeAnalyzer(document) diff --git a/vscode-extension/server/src/server.ts b/vscode-extension/server/src/server.ts index 194b35e..a35bb60 100644 --- a/vscode-extension/server/src/server.ts +++ b/vscode-extension/server/src/server.ts @@ -3,6 +3,7 @@ import { buildDiagnostics } from './diagnostics' import { buildSemanticTokens, TOKEN_MODIFIERS, TOKEN_TYPES } from './semanticTokens' import { parser } from '../../../src/parser/shrimp' import { Compiler } from '../../../src/compiler/compiler' +import { Tree } from '@lezer/common' import { InitializeResult, TextDocuments, @@ -10,18 +11,23 @@ import { createConnection, ProposedFeatures, CompletionItemKind, + TextDocumentChangeEvent, } from 'vscode-languageserver/node' const connection = createConnection(ProposedFeatures.all) const documents = new TextDocuments(TextDocument) documents.listen(connection) +const documentTrees = new Map() + // Server capabilities connection.onInitialize(handleInitialize) // Language features connection.languages.semanticTokens.on(handleSemanticTokens) +documents.onDidOpen(handleDocumentOpen) documents.onDidChangeContent(handleDocumentChange) +documents.onDidClose(handleDocumentClose) connection.onCompletion(handleCompletion) // Debug commands @@ -31,10 +37,7 @@ connection.onRequest('shrimp/bytecode', handleBytecode) // Start listening connection.listen() -// ============================================================================ // Handler implementations -// ============================================================================ - function handleInitialize(): InitializeResult { connection.console.log('🦐 Server initialized with capabilities') const result: InitializeResult = { @@ -56,21 +59,40 @@ function handleInitialize(): InitializeResult { return result } +function handleDocumentOpen(event: TextDocumentChangeEvent) { + const document = event.document + const tree = parser.parse(document.getText()) + documentTrees.set(document.uri, tree) +} + function handleSemanticTokens(params: any) { const document = documents.get(params.textDocument.uri) if (!document) return { data: [] } - const data = buildSemanticTokens(document) + const tree = documentTrees.get(params.textDocument.uri) + if (!tree) return { data: [] } + + const data = buildSemanticTokens(document, tree) return { data } } -function handleDocumentChange(change: any) { - const textDocument = change.document - const diagnostics = buildDiagnostics(textDocument) - connection.sendDiagnostics({ uri: textDocument.uri, diagnostics }) +function handleDocumentChange(change: TextDocumentChangeEvent) { + const document = change.document + + // Parse and cache + const tree = parser.parse(document.getText()) + documentTrees.set(document.uri, tree) + + // Build diagnostics using cached tree + const diagnostics = buildDiagnostics(document, tree) + connection.sendDiagnostics({ uri: document.uri, diagnostics }) } -function handleCompletion(params: any) { +function handleDocumentClose(event: TextDocumentChangeEvent) { + documentTrees.delete(event.document.uri) +} + +function handleCompletion() { const keywords = ['if', 'else', 'do', 'end', 'and', 'or', 'true', 'false', 'null'] return keywords.map((keyword) => ({ @@ -84,8 +106,13 @@ function handleParseTree(params: { uri: string }) { const document = documents.get(params.uri) if (!document) return 'Document not found' + const tree = documentTrees.get(params.uri) + if (!tree) { + connection.console.error(`🦐 No cached tree for ${params.uri}`) + return 'No cached parse tree available' + } + const text = document.getText() - const tree = parser.parse(text) const cursor = tree.cursor() let formatted = ''