diff --git a/.eslintrc.json b/.eslintrc.json index 7601b2d2c..1bfd55d86 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -50,6 +50,22 @@ "block", { "pattern": "MIT License|DO NOT EDIT MANUALLY!" } ], + "no-restricted-imports": ["error", { + "paths": [{ + "name": "vscode-jsonrpc", + "importNames": [ "CancellationToken" ], + "message": "Import 'CancellationToken' via 'Cancellation.CancellationToken' from 'langium', or directly from './utils/cancellation.ts' within Langium." + }, { + "name": "vscode-jsonrpc/", + "importNames": [ "CancellationToken"], + "message": "Import 'CancellationToken' via 'Cancellation.CancellationToken' from 'langium', or directly from './utils/cancellation.ts' within Langium." + }], + "patterns": [ { + "group": [ "vscode-jsonrpc" ], + "importNamePattern": "^(?!CancellationToken)", + "message": "Don't import types or symbols from 'vscode-jsonrpc' (package index), as that brings a large overhead in bundle size. Import from 'vscode-jsonrpc/lib/common/...js' and add a // eslint-disable..., if really necessary." + }] + }], // List of [@typescript-eslint rules](https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin#supported-rules) "@typescript-eslint/adjacent-overload-signatures": "error", // grouping same method names "@typescript-eslint/array-type": ["error", { // string[] instead of Array diff --git a/examples/arithmetics/src/cli/cli-util.ts b/examples/arithmetics/src/cli/cli-util.ts index 73420a8d6..bf96dd99d 100644 --- a/examples/arithmetics/src/cli/cli-util.ts +++ b/examples/arithmetics/src/cli/cli-util.ts @@ -4,13 +4,13 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { AstNode, LangiumDocument, LangiumServices } from 'langium'; +import type { AstNode, LangiumDocument, LangiumCoreServices } from 'langium'; import { URI } from 'langium'; import * as fs from 'node:fs'; import * as path from 'node:path'; import chalk from 'chalk'; -export async function extractDocument(fileName: string, extensions: readonly string[], services: LangiumServices): Promise> { +export async function extractDocument(fileName: string, extensions: readonly string[], services: LangiumCoreServices): Promise> { if (!extensions.includes(path.extname(fileName))) { console.error(chalk.yellow(`Please, choose a file with one of these extensions: ${extensions}.`)); process.exit(1); @@ -38,6 +38,6 @@ export async function extractDocument(fileName: string, exten return document as LangiumDocument; } -export async function extractAstNode(fileName: string, extensions: string[], services: LangiumServices): Promise { +export async function extractAstNode(fileName: string, extensions: string[], services: LangiumCoreServices): Promise { return (await extractDocument(fileName, extensions, services)).parseResult.value as T; } diff --git a/examples/arithmetics/src/language-server/arithmetics-module.ts b/examples/arithmetics/src/language-server/arithmetics-module.ts index cbbf0cca3..11c4390f5 100644 --- a/examples/arithmetics/src/language-server/arithmetics-module.ts +++ b/examples/arithmetics/src/language-server/arithmetics-module.ts @@ -4,11 +4,11 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { DefaultSharedModuleContext, LangiumServices, LangiumSharedServices, Module, PartialLangiumServices } from 'langium'; -import { createDefaultModule, createDefaultSharedModule, inject } from 'langium'; -import { ArithmeticsGeneratedModule, ArithmeticsGeneratedSharedModule } from './generated/module.js'; -import { ArithmeticsValidator, registerValidationChecks } from './arithmetics-validator.js'; +import { type Module, inject } from 'langium'; +import { createDefaultModule, createDefaultSharedModule, type DefaultSharedModuleContext, type LangiumServices, type LangiumSharedServices, type PartialLangiumServices } from 'langium/lsp'; import { ArithmeticsScopeProvider } from './arithmetics-scope-provider.js'; +import { ArithmeticsValidator, registerValidationChecks } from './arithmetics-validator.js'; +import { ArithmeticsGeneratedModule, ArithmeticsGeneratedSharedModule } from './generated/module.js'; /** * Declaration of custom services - add your own service classes here. diff --git a/examples/arithmetics/src/language-server/generated/module.ts b/examples/arithmetics/src/language-server/generated/module.ts index d05a1e7a7..cda4e6e42 100644 --- a/examples/arithmetics/src/language-server/generated/module.ts +++ b/examples/arithmetics/src/language-server/generated/module.ts @@ -3,7 +3,8 @@ * DO NOT EDIT MANUALLY! ******************************************************************************/ -import type { LangiumGeneratedServices, LangiumGeneratedSharedServices, LangiumSharedServices, LangiumServices, LanguageMetaData, Module } from 'langium'; +import type { LangiumGeneratedCoreServices, LangiumGeneratedSharedCoreServices, LanguageMetaData, Module } from 'langium'; +import type { LangiumSharedServices, LangiumServices } from 'langium/lsp'; import { ArithmeticsAstReflection } from './ast.js'; import { ArithmeticsGrammar } from './grammar.js'; @@ -13,11 +14,11 @@ export const ArithmeticsLanguageMetaData = { caseInsensitive: true } as const satisfies LanguageMetaData; -export const ArithmeticsGeneratedSharedModule: Module = { +export const ArithmeticsGeneratedSharedModule: Module = { AstReflection: () => new ArithmeticsAstReflection() }; -export const ArithmeticsGeneratedModule: Module = { +export const ArithmeticsGeneratedModule: Module = { Grammar: () => ArithmeticsGrammar(), LanguageMetaData: () => ArithmeticsLanguageMetaData, parser: {} diff --git a/examples/arithmetics/src/language-server/main-browser.ts b/examples/arithmetics/src/language-server/main-browser.ts index dfef00077..a792cb404 100644 --- a/examples/arithmetics/src/language-server/main-browser.ts +++ b/examples/arithmetics/src/language-server/main-browser.ts @@ -5,7 +5,8 @@ ******************************************************************************/ import type { Diagnostic, Range } from 'vscode-languageserver/browser.js'; -import { startLanguageServer, EmptyFileSystem, DocumentState } from 'langium'; +import { EmptyFileSystem, DocumentState } from 'langium'; +import { startLanguageServer } from 'langium/lsp'; import { BrowserMessageReader, BrowserMessageWriter, createConnection, NotificationType } from 'vscode-languageserver/browser.js'; import { createArithmeticsServices } from './arithmetics-module.js'; import { interpretEvaluations } from './arithmetics-evaluator.js'; @@ -53,4 +54,4 @@ shared.workspace.DocumentBuilder.onBuildPhase(DocumentState.Validated, documents diagnostics: document.diagnostics ?? [] }); } -}); \ No newline at end of file +}); diff --git a/examples/arithmetics/src/language-server/main.ts b/examples/arithmetics/src/language-server/main.ts index df9bef875..620f06312 100644 --- a/examples/arithmetics/src/language-server/main.ts +++ b/examples/arithmetics/src/language-server/main.ts @@ -4,7 +4,7 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import { startLanguageServer } from 'langium'; +import { startLanguageServer } from 'langium/lsp'; import { NodeFileSystem } from 'langium/node'; import { createConnection, ProposedFeatures } from 'vscode-languageserver/node.js'; import { createArithmeticsServices } from './arithmetics-module.js'; diff --git a/examples/domainmodel/src/cli/cli-util.ts b/examples/domainmodel/src/cli/cli-util.ts index f99c762bd..a18bfff07 100644 --- a/examples/domainmodel/src/cli/cli-util.ts +++ b/examples/domainmodel/src/cli/cli-util.ts @@ -4,14 +4,13 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { AstNode, LangiumDocument, LangiumServices } from 'langium'; -import type { WorkspaceFolder } from 'vscode-languageserver'; -import * as fs from 'node:fs'; -import * as path from 'node:path'; import chalk from 'chalk'; +import type { AstNode, LangiumCoreServices, LangiumDocument, WorkspaceFolder } from 'langium'; import { URI } from 'langium'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; -export async function extractDocument(fileName: string, extensions: readonly string[], services: LangiumServices): Promise> { +export async function extractDocument(fileName: string, extensions: readonly string[], services: LangiumCoreServices): Promise> { if (!extensions.includes(path.extname(fileName))) { console.error(chalk.yellow(`Please, choose a file with one of these extensions: ${extensions}.`)); process.exit(1); @@ -39,11 +38,11 @@ export async function extractDocument(fileName: string, exten return document as LangiumDocument; } -export async function extractAstNode(fileName: string, extensions: readonly string[], services: LangiumServices): Promise { +export async function extractAstNode(fileName: string, extensions: readonly string[], services: LangiumCoreServices): Promise { return (await extractDocument(fileName, extensions, services)).parseResult.value as T; } -export async function setRootFolder(fileName: string, services: LangiumServices, root?: string): Promise { +export async function setRootFolder(fileName: string, services: LangiumCoreServices, root?: string): Promise { if (!root) { root = path.dirname(fileName); } diff --git a/examples/domainmodel/src/language-server/domain-model-formatter.ts b/examples/domainmodel/src/language-server/domain-model-formatter.ts index 2e72eddd6..5817fa18f 100644 --- a/examples/domainmodel/src/language-server/domain-model-formatter.ts +++ b/examples/domainmodel/src/language-server/domain-model-formatter.ts @@ -5,7 +5,7 @@ ******************************************************************************/ import type { AstNode } from 'langium'; -import { AbstractFormatter, Formatting } from 'langium'; +import { AbstractFormatter, Formatting } from 'langium/lsp'; import * as ast from './generated/ast.js'; export class DomainModelFormatter extends AbstractFormatter { diff --git a/examples/domainmodel/src/language-server/domain-model-module.ts b/examples/domainmodel/src/language-server/domain-model-module.ts index d8cc75322..ec6fdfe90 100644 --- a/examples/domainmodel/src/language-server/domain-model-module.ts +++ b/examples/domainmodel/src/language-server/domain-model-module.ts @@ -4,14 +4,15 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { LangiumServices, Module, PartialLangiumServices, LangiumSharedServices, DefaultSharedModuleContext } from 'langium'; -import { inject, createDefaultSharedModule, createDefaultModule } from 'langium'; -import { DomainModelGeneratedModule, DomainModelGeneratedSharedModule } from './generated/module.js'; -import { DomainModelValidator, registerValidationChecks } from './domain-model-validator.js'; -import { DomainModelScopeComputation } from './domain-model-scope.js'; -import { QualifiedNameProvider } from './domain-model-naming.js'; +import { type Module, inject } from 'langium'; +import type { LangiumServices, LangiumSharedServices, PartialLangiumServices } from 'langium/lsp'; +import { createDefaultModule, createDefaultSharedModule, type DefaultSharedModuleContext } from 'langium/lsp'; import { DomainModelFormatter } from './domain-model-formatter.js'; +import { QualifiedNameProvider } from './domain-model-naming.js'; import { DomainModelRenameProvider } from './domain-model-rename-refactoring.js'; +import { DomainModelScopeComputation } from './domain-model-scope.js'; +import { DomainModelValidator, registerValidationChecks } from './domain-model-validator.js'; +import { DomainModelGeneratedModule, DomainModelGeneratedSharedModule } from './generated/module.js'; export type DomainModelAddedServices = { references: { @@ -22,7 +23,7 @@ export type DomainModelAddedServices = { } } -export type DomainModelServices = LangiumServices & DomainModelAddedServices +export type DomainModelServices = LangiumServices & DomainModelAddedServices; export const DomainModelModule: Module = { references: { diff --git a/examples/domainmodel/src/language-server/domain-model-rename-refactoring.ts b/examples/domainmodel/src/language-server/domain-model-rename-refactoring.ts index 106905207..1b647b978 100644 --- a/examples/domainmodel/src/language-server/domain-model-rename-refactoring.ts +++ b/examples/domainmodel/src/language-server/domain-model-rename-refactoring.ts @@ -5,13 +5,12 @@ ******************************************************************************/ import type { AstNode, LangiumDocument, LangiumDocuments, ReferenceDescription, URI } from 'langium'; -import type { Range, WorkspaceEdit } from 'vscode-languageserver'; +import { AstUtils, CstUtils, isNamed } from 'langium'; +import { DefaultRenameProvider } from 'langium/lsp'; import type { RenameParams } from 'vscode-languageserver-protocol'; +import { Location, TextEdit, type Range, type WorkspaceEdit } from 'vscode-languageserver-types'; import type { DomainModelServices } from './domain-model-module.js'; import type { QualifiedNameProvider } from './domain-model-naming.js'; -import { AstUtils, CstUtils, DefaultRenameProvider, isNamed } from 'langium'; -import { Location } from 'vscode-languageserver'; -import { TextEdit } from 'vscode-languageserver-types'; import { isPackageDeclaration } from './generated/ast.js'; export class DomainModelRenameProvider extends DefaultRenameProvider { diff --git a/examples/domainmodel/src/language-server/domain-model-scope.ts b/examples/domainmodel/src/language-server/domain-model-scope.ts index 02fa7dcaf..9e067afab 100644 --- a/examples/domainmodel/src/language-server/domain-model-scope.ts +++ b/examples/domainmodel/src/language-server/domain-model-scope.ts @@ -8,8 +8,7 @@ import type { AstNode, AstNodeDescription, LangiumDocument, PrecomputedScopes } import type { DomainModelServices } from './domain-model-module.js'; import type { QualifiedNameProvider } from './domain-model-naming.js'; import type { Domainmodel, PackageDeclaration } from './generated/ast.js'; -import { AstUtils, DefaultScopeComputation, interruptAndCheck, MultiMap } from 'langium'; -import { CancellationToken } from 'vscode-jsonrpc'; +import { AstUtils, Cancellation, DefaultScopeComputation, interruptAndCheck, MultiMap } from 'langium'; import { isType, isPackageDeclaration } from './generated/ast.js'; export class DomainModelScopeComputation extends DefaultScopeComputation { @@ -24,7 +23,7 @@ export class DomainModelScopeComputation extends DefaultScopeComputation { /** * Exports only types (`DataType or `Entity`) with their qualified names. */ - override async computeExports(document: LangiumDocument, cancelToken = CancellationToken.None): Promise { + override async computeExports(document: LangiumDocument, cancelToken = Cancellation.CancellationToken.None): Promise { const descr: AstNodeDescription[] = []; for (const modelNode of AstUtils.streamAllContents(document.parseResult.value)) { await interruptAndCheck(cancelToken); @@ -41,14 +40,14 @@ export class DomainModelScopeComputation extends DefaultScopeComputation { return descr; } - override async computeLocalScopes(document: LangiumDocument, cancelToken = CancellationToken.None): Promise { + override async computeLocalScopes(document: LangiumDocument, cancelToken = Cancellation.CancellationToken.None): Promise { const model = document.parseResult.value as Domainmodel; const scopes = new MultiMap(); await this.processContainer(model, scopes, document, cancelToken); return scopes; } - protected async processContainer(container: Domainmodel | PackageDeclaration, scopes: PrecomputedScopes, document: LangiumDocument, cancelToken: CancellationToken): Promise { + protected async processContainer(container: Domainmodel | PackageDeclaration, scopes: PrecomputedScopes, document: LangiumDocument, cancelToken: Cancellation.CancellationToken): Promise { const localDescriptions: AstNodeDescription[] = []; for (const element of container.elements) { await interruptAndCheck(cancelToken); diff --git a/examples/domainmodel/src/language-server/generated/module.ts b/examples/domainmodel/src/language-server/generated/module.ts index 3f1b3abce..a5636cd71 100644 --- a/examples/domainmodel/src/language-server/generated/module.ts +++ b/examples/domainmodel/src/language-server/generated/module.ts @@ -3,7 +3,8 @@ * DO NOT EDIT MANUALLY! ******************************************************************************/ -import type { LangiumGeneratedServices, LangiumGeneratedSharedServices, LangiumSharedServices, LangiumServices, LanguageMetaData, Module, IParserConfig } from 'langium'; +import type { LangiumGeneratedCoreServices, LangiumGeneratedSharedCoreServices, LanguageMetaData, Module, IParserConfig } from 'langium'; +import type { LangiumSharedServices, LangiumServices } from 'langium/lsp'; import { DomainModelAstReflection } from './ast.js'; import { DomainModelGrammar } from './grammar.js'; @@ -19,11 +20,11 @@ export const parserConfig: IParserConfig = { maxLookahead: 3, }; -export const DomainModelGeneratedSharedModule: Module = { +export const DomainModelGeneratedSharedModule: Module = { AstReflection: () => new DomainModelAstReflection() }; -export const DomainModelGeneratedModule: Module = { +export const DomainModelGeneratedModule: Module = { Grammar: () => DomainModelGrammar(), LanguageMetaData: () => DomainModelLanguageMetaData, parser: { diff --git a/examples/domainmodel/src/language-server/main-browser.ts b/examples/domainmodel/src/language-server/main-browser.ts index c050de6f6..c0fba0d06 100644 --- a/examples/domainmodel/src/language-server/main-browser.ts +++ b/examples/domainmodel/src/language-server/main-browser.ts @@ -5,7 +5,8 @@ ******************************************************************************/ import type { Diagnostic } from 'vscode-languageserver/browser.js'; -import { startLanguageServer, EmptyFileSystem, DocumentState } from 'langium'; +import { EmptyFileSystem, DocumentState } from 'langium'; +import { startLanguageServer } from 'langium/lsp'; import { BrowserMessageReader, BrowserMessageWriter, createConnection, NotificationType } from 'vscode-languageserver/browser.js'; import { createDomainModelServices } from './domain-model-module.js'; diff --git a/examples/domainmodel/src/language-server/main.ts b/examples/domainmodel/src/language-server/main.ts index 6c997083a..45650e18a 100644 --- a/examples/domainmodel/src/language-server/main.ts +++ b/examples/domainmodel/src/language-server/main.ts @@ -4,7 +4,7 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import { startLanguageServer } from 'langium'; +import { startLanguageServer } from 'langium/lsp'; import { NodeFileSystem } from 'langium/node'; import { createConnection, ProposedFeatures } from 'vscode-languageserver/node.js'; import { createDomainModelServices } from './domain-model-module.js'; diff --git a/examples/domainmodel/test/refs-index.test.ts b/examples/domainmodel/test/refs-index.test.ts index d26eb043e..3c621bfc6 100644 --- a/examples/domainmodel/test/refs-index.test.ts +++ b/examples/domainmodel/test/refs-index.test.ts @@ -5,14 +5,13 @@ ******************************************************************************/ import type { AstNode, LangiumDocument, ReferenceDescription, URI } from 'langium'; -import type { Domainmodel } from '../src/language-server/generated/ast.js'; -import { describe, expect, test } from 'vitest'; -import { AstUtils, EmptyFileSystem } from 'langium'; +import { AstUtils, EmptyFileSystem, TextDocument } from 'langium'; import { parseDocument, setTextDocument } from 'langium/test'; -import { TextDocument } from 'vscode-languageserver-textdocument'; +import { describe, expect, test } from 'vitest'; import { createDomainModelServices } from '../src/language-server/domain-model-module.js'; +import type { Domainmodel } from '../src/language-server/generated/ast.js'; -const services = createDomainModelServices(EmptyFileSystem).domainmodel; +const { shared, domainmodel } = createDomainModelServices(EmptyFileSystem); describe('Cross references indexed after affected process', () => { test('Fixed reference is in index', async () => { @@ -22,7 +21,7 @@ describe('Cross references indexed after affected process', () => { expect(allRefs.length).toEqual(0); // linking error setTextDocument( - services, + shared, TextDocument.create( superDoc.textDocument.uri.toString(), superDoc.textDocument.languageId, @@ -30,9 +29,9 @@ describe('Cross references indexed after affected process', () => { 'entity SuperEntity {}' ) ); - await services.shared.workspace.DocumentBuilder.update([superDoc.uri], []); + await shared.workspace.DocumentBuilder.update([superDoc.uri], []); - const updatedSuperDoc = await services.shared.workspace.LangiumDocuments.getOrCreateDocument(superDoc.uri); + const updatedSuperDoc = await shared.workspace.LangiumDocuments.getOrCreateDocument(superDoc.uri); const superEntity = (updatedSuperDoc.parseResult.value as Domainmodel).elements[0]; allRefs = await getReferences(superEntity); expect(allRefs.length).toEqual(1); // re-linked @@ -43,16 +42,16 @@ describe('Cross references indexed after affected process', () => { }); async function updateDocuments(extendsFile: string, superFile: string): Promise<{ 'super': LangiumDocument, 'extends': LangiumDocument }> { - const superDoc: LangiumDocument = await parseDocument(services, superFile); - const extendsDoc: LangiumDocument = await parseDocument(services, extendsFile); + const superDoc: LangiumDocument = await parseDocument(domainmodel, superFile); + const extendsDoc: LangiumDocument = await parseDocument(domainmodel, extendsFile); - await services.shared.workspace.DocumentBuilder.build([extendsDoc, superDoc]); + await shared.workspace.DocumentBuilder.build([extendsDoc, superDoc]); return { 'super': superDoc, 'extends': extendsDoc }; } async function getReferences(node: AstNode): Promise { const allRefs: ReferenceDescription[] = []; - services.shared.workspace.IndexManager.findAllReferences(node, createPath(node)) + shared.workspace.IndexManager.findAllReferences(node, createPath(node)) .forEach((ref) => allRefs.push(ref)); return allRefs; } @@ -66,7 +65,7 @@ function nodeRefString(from: AstNode, to: AstNode): string { } function createPath(node: AstNode): string { - return services.workspace.AstNodeLocator.getAstNodePath(node); + return domainmodel.workspace.AstNodeLocator.getAstNodePath(node); } function asString(fromUri: URI, fromPath: string, toUri: URI, toPath: string): string { diff --git a/examples/requirements/src/cli/cli-util.ts b/examples/requirements/src/cli/cli-util.ts index 2ee7754e9..8013275aa 100644 --- a/examples/requirements/src/cli/cli-util.ts +++ b/examples/requirements/src/cli/cli-util.ts @@ -4,9 +4,8 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { LangiumDocument, LangiumServices } from 'langium'; +import type { LangiumDocument, LangiumCoreServices, WorkspaceFolder } from 'langium'; import type { RequirementModel, TestModel } from '../language-server/generated/ast.js'; -import type { WorkspaceFolder } from 'vscode-languageclient'; import chalk from 'chalk'; import * as path from 'node:path'; import * as fs from 'node:fs'; @@ -21,7 +20,7 @@ import { isTestModel } from '../language-server/generated/ast.js'; * @returns a tuple with the document indicated by the fileName and a list of * documents from the workspace. */ -export async function extractDocuments(fileName: string, services: LangiumServices): Promise<[LangiumDocument, LangiumDocument[]]> { +export async function extractDocuments(fileName: string, services: LangiumCoreServices): Promise<[LangiumDocument, LangiumDocument[]]> { const extensions = services.LanguageMetaData.fileExtensions; if (!extensions.includes(path.extname(fileName))) { console.error(chalk.yellow(`Please choose a file with one of these extensions: ${extensions}.`)); @@ -66,7 +65,7 @@ export async function extractDocuments(fileName: string, services: LangiumServic * @returns a tuple with the model indicated by the fileName and a list of * test models from the workspace. chr */ -export async function extractRequirementModelWithTestModels(fileName: string, services: LangiumServices): Promise<[RequirementModel, TestModel[]]> { +export async function extractRequirementModelWithTestModels(fileName: string, services: LangiumCoreServices): Promise<[RequirementModel, TestModel[]]> { const [mainDocument, allDocuments] = await extractDocuments(fileName, services); return [ mainDocument.parseResult?.value as RequirementModel, diff --git a/examples/requirements/src/language-server/generated/module.ts b/examples/requirements/src/language-server/generated/module.ts index 8d12c8ada..40cb76260 100644 --- a/examples/requirements/src/language-server/generated/module.ts +++ b/examples/requirements/src/language-server/generated/module.ts @@ -3,7 +3,8 @@ * DO NOT EDIT MANUALLY! ******************************************************************************/ -import type { LangiumGeneratedServices, LangiumGeneratedSharedServices, LangiumSharedServices, LangiumServices, LanguageMetaData, Module } from 'langium'; +import type { LangiumGeneratedCoreServices, LangiumGeneratedSharedCoreServices, LanguageMetaData, Module } from 'langium'; +import type { LangiumSharedServices, LangiumServices } from 'langium/lsp'; import { RequirementsAndTestsAstReflection } from './ast.js'; import { RequirementsGrammar, TestsGrammar } from './grammar.js'; @@ -19,17 +20,17 @@ export const TestsLanguageMetaData = { caseInsensitive: false } as const satisfies LanguageMetaData; -export const RequirementsAndTestsGeneratedSharedModule: Module = { +export const RequirementsAndTestsGeneratedSharedModule: Module = { AstReflection: () => new RequirementsAndTestsAstReflection() }; -export const RequirementsGeneratedModule: Module = { +export const RequirementsGeneratedModule: Module = { Grammar: () => RequirementsGrammar(), LanguageMetaData: () => RequirementsLanguageMetaData, parser: {} }; -export const TestsGeneratedModule: Module = { +export const TestsGeneratedModule: Module = { Grammar: () => TestsGrammar(), LanguageMetaData: () => TestsLanguageMetaData, parser: {} diff --git a/examples/requirements/src/language-server/main.ts b/examples/requirements/src/language-server/main.ts index 520564e2c..16b633f09 100644 --- a/examples/requirements/src/language-server/main.ts +++ b/examples/requirements/src/language-server/main.ts @@ -4,7 +4,7 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import { startLanguageServer } from 'langium'; +import { startLanguageServer } from 'langium/lsp'; import { createConnection, ProposedFeatures } from 'vscode-languageserver/node.js'; import { createRequirementsAndTestsLangServices } from './requirements-and-tests-lang-module.js'; import { NodeFileSystem } from 'langium/node'; diff --git a/examples/requirements/src/language-server/requirements-and-tests-lang-module.ts b/examples/requirements/src/language-server/requirements-and-tests-lang-module.ts index e175768a2..e1bb4a15d 100644 --- a/examples/requirements/src/language-server/requirements-and-tests-lang-module.ts +++ b/examples/requirements/src/language-server/requirements-and-tests-lang-module.ts @@ -4,13 +4,13 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { DefaultSharedModuleContext, LangiumSharedServices } from 'langium'; -import type { RequirementsLangServices } from './requirements-lang-module.js'; -import type { TestsLangServices } from './tests-lang-module.js'; -import { createDefaultModule, createDefaultSharedModule, inject } from 'langium'; +import { inject } from 'langium'; +import { createDefaultModule, createDefaultSharedModule, type DefaultSharedModuleContext, type LangiumSharedServices } from 'langium/lsp'; import { RequirementsAndTestsGeneratedSharedModule, RequirementsGeneratedModule, TestsGeneratedModule } from './generated/module.js'; +import type { RequirementsLangServices } from './requirements-lang-module.js'; import { RequirementsLangModule } from './requirements-lang-module.js'; import { registerRequirementsValidationChecks } from './requirements-lang-validator.js'; +import type { TestsLangServices } from './tests-lang-module.js'; import { TestsLangModule } from './tests-lang-module.js'; import { registerTestsValidationChecks } from './tests-lang-validator.js'; diff --git a/examples/requirements/src/language-server/requirements-lang-module.ts b/examples/requirements/src/language-server/requirements-lang-module.ts index 546fe82d8..c1deb2547 100644 --- a/examples/requirements/src/language-server/requirements-lang-module.ts +++ b/examples/requirements/src/language-server/requirements-lang-module.ts @@ -4,7 +4,8 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { LangiumServices, Module, PartialLangiumServices } from 'langium'; +import type { Module } from 'langium'; +import type { LangiumServices, PartialLangiumServices } from 'langium/lsp'; import { RequirementsLangValidator } from './requirements-lang-validator.js'; /** diff --git a/examples/requirements/src/language-server/tests-lang-module.ts b/examples/requirements/src/language-server/tests-lang-module.ts index 0cf22ea8c..c628cb253 100644 --- a/examples/requirements/src/language-server/tests-lang-module.ts +++ b/examples/requirements/src/language-server/tests-lang-module.ts @@ -4,8 +4,9 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { LangiumServices, Module, PartialLangiumServices } from 'langium'; +import type { Module } from 'langium'; import { TestsLangValidator } from './tests-lang-validator.js'; +import type { LangiumServices, PartialLangiumServices } from 'langium/lsp'; /** * Declaration of custom services - add your own service classes here. diff --git a/examples/statemachine/src/cli/cli-util.ts b/examples/statemachine/src/cli/cli-util.ts index c72ef88fa..4b1d61b40 100644 --- a/examples/statemachine/src/cli/cli-util.ts +++ b/examples/statemachine/src/cli/cli-util.ts @@ -7,10 +7,10 @@ import * as fs from 'node:fs'; import * as path from 'node:path'; import chalk from 'chalk'; -import type { AstNode, LangiumDocument, LangiumServices } from 'langium'; +import type { AstNode, LangiumDocument, LangiumCoreServices } from 'langium'; import { URI } from 'langium'; -export async function extractDocument(fileName: string, extensions: readonly string[], services: LangiumServices): Promise { +export async function extractDocument(fileName: string, extensions: readonly string[], services: LangiumCoreServices): Promise { if (!extensions.includes(path.extname(fileName))) { console.error(chalk.yellow(`Please, choose a file with one of these extensions: ${extensions}.`)); process.exit(1); @@ -38,7 +38,7 @@ export async function extractDocument(fileName: string, extensions: readonly str return document; } -export async function extractAstNode(fileName: string, extensions: readonly string[], services: LangiumServices): Promise { +export async function extractAstNode(fileName: string, extensions: readonly string[], services: LangiumCoreServices): Promise { return (await extractDocument(fileName, extensions, services)).parseResult?.value as T; } diff --git a/examples/statemachine/src/language-server/generated/module.ts b/examples/statemachine/src/language-server/generated/module.ts index e96d38508..0b45d72d0 100644 --- a/examples/statemachine/src/language-server/generated/module.ts +++ b/examples/statemachine/src/language-server/generated/module.ts @@ -3,7 +3,8 @@ * DO NOT EDIT MANUALLY! ******************************************************************************/ -import type { LangiumGeneratedServices, LangiumGeneratedSharedServices, LangiumSharedServices, LangiumServices, LanguageMetaData, Module } from 'langium'; +import type { LangiumGeneratedCoreServices, LangiumGeneratedSharedCoreServices, LanguageMetaData, Module } from 'langium'; +import type { LangiumSharedServices, LangiumServices } from 'langium/lsp'; import { StatemachineAstReflection } from './ast.js'; import { StatemachineGrammar } from './grammar.js'; @@ -13,11 +14,11 @@ export const StatemachineLanguageMetaData = { caseInsensitive: false } as const satisfies LanguageMetaData; -export const StatemachineGeneratedSharedModule: Module = { +export const StatemachineGeneratedSharedModule: Module = { AstReflection: () => new StatemachineAstReflection() }; -export const StatemachineGeneratedModule: Module = { +export const StatemachineGeneratedModule: Module = { Grammar: () => StatemachineGrammar(), LanguageMetaData: () => StatemachineLanguageMetaData, parser: {} diff --git a/examples/statemachine/src/language-server/main-browser.ts b/examples/statemachine/src/language-server/main-browser.ts index dae1a4b37..17791d10a 100644 --- a/examples/statemachine/src/language-server/main-browser.ts +++ b/examples/statemachine/src/language-server/main-browser.ts @@ -5,7 +5,8 @@ ******************************************************************************/ import type { Diagnostic } from 'vscode-languageserver/browser.js'; -import { startLanguageServer, EmptyFileSystem, DocumentState } from 'langium'; +import { EmptyFileSystem, DocumentState } from 'langium'; +import { startLanguageServer } from 'langium/lsp'; import { BrowserMessageReader, BrowserMessageWriter, createConnection, NotificationType } from 'vscode-languageserver/browser.js'; import { createStatemachineServices } from './statemachine-module.js'; diff --git a/examples/statemachine/src/language-server/main.ts b/examples/statemachine/src/language-server/main.ts index df8ee71d7..d31ba15bc 100644 --- a/examples/statemachine/src/language-server/main.ts +++ b/examples/statemachine/src/language-server/main.ts @@ -4,7 +4,7 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import { startLanguageServer } from 'langium'; +import { startLanguageServer } from 'langium/lsp'; import { NodeFileSystem } from 'langium/node'; import { createConnection, ProposedFeatures } from 'vscode-languageserver/node.js'; import { createStatemachineServices } from './statemachine-module.js'; diff --git a/examples/statemachine/src/language-server/statemachine-module.ts b/examples/statemachine/src/language-server/statemachine-module.ts index e7f5e8299..12fed8c82 100644 --- a/examples/statemachine/src/language-server/statemachine-module.ts +++ b/examples/statemachine/src/language-server/statemachine-module.ts @@ -4,10 +4,11 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { DefaultSharedModuleContext, LangiumServices, LangiumSharedServices, Module, PartialLangiumServices } from 'langium'; -import { createDefaultModule, createDefaultSharedModule, inject } from 'langium'; +import { type Module, inject } from 'langium'; +import type { LangiumServices, LangiumSharedServices, PartialLangiumServices } from 'langium/lsp'; +import { createDefaultModule, createDefaultSharedModule, type DefaultSharedModuleContext } from 'langium/lsp'; import { StatemachineGeneratedModule, StatemachineGeneratedSharedModule } from './generated/module.js'; -import { registerValidationChecks, StatemachineValidator } from './statemachine-validator.js'; +import { StatemachineValidator, registerValidationChecks } from './statemachine-validator.js'; /** * Declaration of custom services - add your own service classes here. diff --git a/package-lock.json b/package-lock.json index c1aaed523..e1c8045e1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,7 +27,7 @@ "concurrently": "~8.2.1", "editorconfig": "~2.0.0", "esbuild": "~0.19.2", - "eslint": "~8.47.0", + "eslint": "~8.56.0", "eslint-plugin-header": "~3.1.1", "shx": "~0.3.4", "typescript": "~5.1.6", @@ -748,9 +748,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", - "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -771,22 +771,22 @@ } }, "node_modules/@eslint/js": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.47.0.tgz", - "integrity": "sha512-P6omY1zv5MItm93kLM8s2vr1HICJH8v0dvddDhysbIuZ+vcjOHg5Zbkf1mTkcmi2JA9oBG2anOkRnW8WJTS8Og==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", + "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", - "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", "minimatch": "^3.0.5" }, "engines": { @@ -807,9 +807,9 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", "dev": true }, "node_modules/@isaacs/cliui": { @@ -1858,6 +1858,12 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, "node_modules/@vitest/coverage-v8": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-1.0.4.tgz", @@ -3172,18 +3178,19 @@ } }, "node_modules/eslint": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.47.0.tgz", - "integrity": "sha512-spUQWrdPt+pRVP1TTJLmfRNJJHHZryFmptzcafwSvHsceV81djHOdnEeDmkdotZyLNjDhrOasNK8nikkoG1O8Q==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", + "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "^8.47.0", - "@humanwhocodes/config-array": "^0.11.10", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.56.0", + "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -4823,9 +4830,9 @@ } }, "node_modules/globals": { - "version": "13.21.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", - "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -6386,9 +6393,9 @@ "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==" }, "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "engines": { "node": ">=6" diff --git a/package.json b/package.json index 1a57d6884..160863b91 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "@vitest/ui": "~1.0.0", "concurrently": "~8.2.1", "esbuild": "~0.19.2", - "eslint": "~8.47.0", + "eslint": "~8.56.0", "eslint-plugin-header": "~3.1.1", "editorconfig": "~2.0.0", "shx": "~0.3.4", diff --git a/packages/generator-langium/templates/cli/src/cli/cli-util.ts b/packages/generator-langium/templates/cli/src/cli/cli-util.ts index de816856c..bdae76c6e 100644 --- a/packages/generator-langium/templates/cli/src/cli/cli-util.ts +++ b/packages/generator-langium/templates/cli/src/cli/cli-util.ts @@ -1,10 +1,10 @@ -import type { AstNode, LangiumDocument, LangiumServices } from 'langium'; +import type { AstNode, LangiumCoreServices, LangiumDocument } from 'langium'; import chalk from 'chalk'; import * as path from 'node:path'; import * as fs from 'node:fs'; import { URI } from 'langium'; -export async function extractDocument(fileName: string, services: LangiumServices): Promise { +export async function extractDocument(fileName: string, services: LangiumCoreServices): Promise { const extensions = services.LanguageMetaData.fileExtensions; if (!extensions.includes(path.extname(fileName))) { console.error(chalk.yellow(`Please choose a file with one of these extensions: ${extensions}.`)); @@ -33,7 +33,7 @@ export async function extractDocument(fileName: string, services: LangiumService return document; } -export async function extractAstNode(fileName: string, services: LangiumServices): Promise { +export async function extractAstNode(fileName: string, services: LangiumCoreServices): Promise { return (await extractDocument(fileName, services)).parseResult?.value as T; } diff --git a/packages/generator-langium/templates/core/src/language/language-id-module.ts b/packages/generator-langium/templates/core/src/language/language-id-module.ts index 11bb53e14..c38981ef6 100644 --- a/packages/generator-langium/templates/core/src/language/language-id-module.ts +++ b/packages/generator-langium/templates/core/src/language/language-id-module.ts @@ -1,5 +1,5 @@ -import type { DefaultSharedModuleContext, LangiumServices, LangiumSharedServices, Module, PartialLangiumServices } from 'langium'; -import { createDefaultModule, createDefaultSharedModule, inject } from 'langium'; +import { type Module, inject } from 'langium'; +import { createDefaultModule, createDefaultSharedModule, type DefaultSharedModuleContext, type LangiumServices, type LangiumSharedServices, type PartialLangiumServices } from 'langium/lsp'; import { <%= LanguageName %>GeneratedModule, <%= LanguageName %>GeneratedSharedModule } from './generated/module.js'; import { <%= LanguageName %>Validator, registerValidationChecks } from './<%= language-id %>-validator.js'; diff --git a/packages/generator-langium/templates/vscode/src/language/main.ts b/packages/generator-langium/templates/vscode/src/language/main.ts index 31f656171..90f7d48eb 100644 --- a/packages/generator-langium/templates/vscode/src/language/main.ts +++ b/packages/generator-langium/templates/vscode/src/language/main.ts @@ -1,4 +1,4 @@ -import { startLanguageServer } from 'langium'; +import { startLanguageServer } from 'langium/lsp'; import { NodeFileSystem } from 'langium/node'; import { createConnection, ProposedFeatures } from 'vscode-languageserver/node.js'; import { create<%= LanguageName %>Services } from './<%= language-id %>-module.js'; diff --git a/packages/generator-langium/templates/web/src/language/main-browser.ts b/packages/generator-langium/templates/web/src/language/main-browser.ts index e81288227..73a3350d4 100644 --- a/packages/generator-langium/templates/web/src/language/main-browser.ts +++ b/packages/generator-langium/templates/web/src/language/main-browser.ts @@ -1,4 +1,5 @@ -import { EmptyFileSystem, startLanguageServer } from 'langium'; +import { EmptyFileSystem } from 'langium'; +import { startLanguageServer } from 'langium/lsp'; import { BrowserMessageReader, BrowserMessageWriter, createConnection } from 'vscode-languageserver/browser.js'; import { create<%= LanguageName %>Services } from './<%= language-id %>-module.js'; diff --git a/packages/langium-cli/src/generator/ast-generator.ts b/packages/langium-cli/src/generator/ast-generator.ts index ce6a01fdb..b06dd4b26 100644 --- a/packages/langium-cli/src/generator/ast-generator.ts +++ b/packages/langium-cli/src/generator/ast-generator.ts @@ -3,7 +3,7 @@ * This program and the accompanying materials are made available under the * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { Grammar, LangiumServices } from 'langium'; +import type { Grammar, LangiumCoreServices } from 'langium'; import { type Generated, expandToNode, joinToNode, toString } from 'langium/generate'; import type { AstTypes, Property, PropertyDefaultValue } from 'langium/grammar'; import type { LangiumConfig } from '../package.js'; @@ -11,7 +11,7 @@ import { AstUtils, MultiMap, GrammarAST } from 'langium'; import { collectAst, collectTypeHierarchy, findReferenceTypes, isAstType, mergeTypesAndInterfaces } from 'langium/grammar'; import { collectTerminalRegexps, generatedHeader } from './util.js'; -export function generateAst(services: LangiumServices, grammars: Grammar[], config: LangiumConfig): string { +export function generateAst(services: LangiumCoreServices, grammars: Grammar[], config: LangiumConfig): string { const astTypes = collectAst(grammars, services.shared.workspace.LangiumDocuments); const crossRef = grammars.some(grammar => hasCrossReferences(grammar)); const importFrom = config.langiumInternal ? `../../syntax-tree${config.importExtension}` : 'langium'; diff --git a/packages/langium-cli/src/generator/grammar-serializer.ts b/packages/langium-cli/src/generator/grammar-serializer.ts index 856126533..5478a2f3f 100644 --- a/packages/langium-cli/src/generator/grammar-serializer.ts +++ b/packages/langium-cli/src/generator/grammar-serializer.ts @@ -4,13 +4,13 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { Grammar, LangiumServices, Reference } from 'langium'; +import type { Grammar, LangiumCoreServices, Reference } from 'langium'; import { expandToNode, joinToNode, normalizeEOL, toString } from 'langium/generate'; import type { URI } from 'vscode-uri'; import type { LangiumConfig } from '../package.js'; import { generatedHeader } from './util.js'; -export function serializeGrammar(services: LangiumServices, grammars: Grammar[], config: LangiumConfig): string { +export function serializeGrammar(services: LangiumCoreServices, grammars: Grammar[], config: LangiumConfig): string { const node = expandToNode` ${generatedHeader} `.appendNewLine( diff --git a/packages/langium-cli/src/generator/module-generator.ts b/packages/langium-cli/src/generator/module-generator.ts index 182f3eec3..ff299d5aa 100644 --- a/packages/langium-cli/src/generator/module-generator.ts +++ b/packages/langium-cli/src/generator/module-generator.ts @@ -25,14 +25,16 @@ export function generateModule(grammars: Grammar[], config: LangiumConfig, gramm import type { LanguageMetaData } from '../../languages/language-meta-data${config.importExtension}'; import { ${config.projectName}AstReflection } from '../../languages/generated/ast${config.importExtension}'; import type { Module } from '../../dependency-injection${config.importExtension}'; - import type { LangiumGeneratedServices, LangiumGeneratedSharedServices, LangiumSharedServices, LangiumServices } from '../../services${config.importExtension}'; + import type { LangiumGeneratedCoreServices, LangiumGeneratedSharedCoreServices } from '../../services${config.importExtension}'; + import type { LangiumSharedServices, LangiumServices } from '../../lsp/lsp-services${config.importExtension}'; `.appendTemplateIf(hasIParserConfigImport)` import type { IParserConfig } from '../../parser/parser-config${config.importExtension}'; ` ).appendTemplateIf(!config.langiumInternal)` - import type { LangiumGeneratedServices, LangiumGeneratedSharedServices, LangiumSharedServices, LangiumServices, LanguageMetaData, Module${hasIParserConfigImport ? ', IParserConfig' : ''} } from 'langium'; + import type { LangiumGeneratedCoreServices, LangiumGeneratedSharedCoreServices, LanguageMetaData, Module${hasIParserConfigImport ? ', IParserConfig' : ''} } from 'langium'; + import type { LangiumSharedServices, LangiumServices } from 'langium/lsp'; import { ${config.projectName}AstReflection } from './ast${config.importExtension}'; `.appendTemplate` @@ -77,7 +79,7 @@ export function generateModule(grammars: Grammar[], config: LangiumConfig, gramm }; `} - export const ${config.projectName}GeneratedSharedModule: Module = { + export const ${config.projectName}GeneratedSharedModule: Module = { AstReflection: () => new ${config.projectName}AstReflection() }; ${joinToNode( @@ -86,7 +88,7 @@ export function generateModule(grammars: Grammar[], config: LangiumConfig, gramm const grammarConfig = grammarConfigMap.get(grammar)!; return expandToNode` - export const ${grammar.name}GeneratedModule: Module = { + export const ${grammar.name}GeneratedModule: Module = { Grammar: () => ${grammar.name}Grammar(), LanguageMetaData: () => ${grammar.name}LanguageMetaData, parser: {${(grammarConfig.chevrotainParserConfig || parserConfig) && expandToNode` diff --git a/packages/langium-cli/src/generator/types-generator.ts b/packages/langium-cli/src/generator/types-generator.ts index 1f4cd116b..96f21082d 100644 --- a/packages/langium-cli/src/generator/types-generator.ts +++ b/packages/langium-cli/src/generator/types-generator.ts @@ -3,12 +3,12 @@ * This program and the accompanying materials are made available under the * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { Grammar, LangiumServices } from 'langium'; +import type { Grammar, LangiumCoreServices } from 'langium'; import { joinToNode, toString } from 'langium/generate'; import { collectAst, LangiumGrammarGrammar } from 'langium/grammar'; import { collectKeywords } from './util.js'; -export function generateTypesFile(services: LangiumServices, grammars: Grammar[]): string { +export function generateTypesFile(services: LangiumCoreServices, grammars: Grammar[]): string { const { unions, interfaces } = collectAst(grammars, services.shared.workspace.LangiumDocuments); const reservedWords = new Set(collectKeywords(LangiumGrammarGrammar())); diff --git a/packages/langium-sprotty/src/default-module.ts b/packages/langium-sprotty/src/default-module.ts index 7bf02077e..21296d551 100644 --- a/packages/langium-sprotty/src/default-module.ts +++ b/packages/langium-sprotty/src/default-module.ts @@ -4,7 +4,8 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { Module, PartialLangiumServices } from 'langium'; +import type { Module } from 'langium'; +import type { PartialLangiumServices } from 'langium/lsp'; import type { DiagramOptions } from 'sprotty-protocol'; import type { LangiumSprottyServices, LangiumSprottySharedServices, SprottyDefaultServices, SprottySharedServices } from './sprotty-services.js'; import { DiagramServer } from 'sprotty-protocol'; diff --git a/packages/langium-sprotty/src/position-tracker.ts b/packages/langium-sprotty/src/position-tracker.ts index 5c4078437..9abd72c80 100644 --- a/packages/langium-sprotty/src/position-tracker.ts +++ b/packages/langium-sprotty/src/position-tracker.ts @@ -8,7 +8,7 @@ import type { LangiumDocument, MaybePromise } from 'langium'; import type { Position } from 'vscode-languageserver'; import type { DocumentHighlight, DocumentHighlightParams } from 'vscode-languageserver'; import type { LangiumSprottyServices } from './sprotty-services.js'; -import { DefaultDocumentHighlightProvider } from 'langium'; +import { DefaultDocumentHighlightProvider } from 'langium/lsp'; /** * This service provides access to the user's current cursor position. diff --git a/packages/langium-sprotty/src/sprotty-services.ts b/packages/langium-sprotty/src/sprotty-services.ts index ddbd5d9ea..31e69069b 100644 --- a/packages/langium-sprotty/src/sprotty-services.ts +++ b/packages/langium-sprotty/src/sprotty-services.ts @@ -4,7 +4,7 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { LangiumServices, LangiumSharedServices } from 'langium'; +import type { LangiumServices, LangiumSharedServices } from 'langium/lsp'; import type { DiagramOptions, DiagramServer, DiagramServices } from 'sprotty-protocol'; import type { ServerActionHandlerRegistry } from 'sprotty-protocol/lib/action-handler.js'; import type { DiagnosticMarkerProvider } from './diagnostic-marker-provider.js'; diff --git a/packages/langium-vscode/src/language-server/grammar-workspace-manager.ts b/packages/langium-vscode/src/language-server/grammar-workspace-manager.ts index b7fdf7c57..bc31efc73 100644 --- a/packages/langium-vscode/src/language-server/grammar-workspace-manager.ts +++ b/packages/langium-vscode/src/language-server/grammar-workspace-manager.ts @@ -5,12 +5,11 @@ ******************************************************************************/ import type { Ignore } from 'ignore'; -import type { LangiumSharedServices, ConfigurationProvider, FileSystemNode } from 'langium'; -import type { WorkspaceFolder } from 'vscode-languageserver-protocol'; import ignore from 'ignore'; -import { DefaultWorkspaceManager, URI, UriUtils } from 'langium'; +import type { ConfigurationProvider, FileSystemNode, WorkspaceFolder } from 'langium'; +import { Cancellation, DefaultWorkspaceManager, URI, UriUtils } from 'langium'; +import type { LangiumSharedServices } from 'langium/lsp'; import * as path from 'path'; -import { CancellationToken } from 'vscode-languageserver-protocol'; const CONFIG_KEY = 'build'; @@ -31,7 +30,7 @@ export class LangiumGrammarWorkspaceManager extends DefaultWorkspaceManager { this.configurationProvider = services.workspace.ConfigurationProvider; } - override async initializeWorkspace(folders: WorkspaceFolder[], cancelToken = CancellationToken.None): Promise { + override async initializeWorkspace(folders: WorkspaceFolder[], cancelToken = Cancellation.CancellationToken.None): Promise { const buildConf: WorkspaceManagerConf = await this.configurationProvider.getConfiguration('langium', CONFIG_KEY); const ignorePatterns = buildConf.ignorePatterns?.split(',')?.map(pattern => pattern.trim())?.filter(pattern => pattern.length > 0); this.matcher = ignorePatterns ? ignore.default().add(ignorePatterns) : undefined; diff --git a/packages/langium-vscode/src/language-server/main.ts b/packages/langium-vscode/src/language-server/main.ts index b2f19eb49..5618a482b 100644 --- a/packages/langium-vscode/src/language-server/main.ts +++ b/packages/langium-vscode/src/language-server/main.ts @@ -4,11 +4,11 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { LangiumSharedServices, Module, PartialLangiumSharedServices } from 'langium'; -import { startLanguageServer } from 'langium'; +import type { Module } from 'langium'; import { createLangiumGrammarServices } from 'langium/grammar'; +import { startLanguageServer, type LangiumSharedServices, type PartialLangiumSharedServices } from 'langium/lsp'; import { NodeFileSystem } from 'langium/node'; -import { createConnection, ProposedFeatures } from 'vscode-languageserver/node.js'; +import { ProposedFeatures, createConnection } from 'vscode-languageserver/node.js'; import { LangiumGrammarWorkspaceManager } from './grammar-workspace-manager.js'; import { registerRailroadConnectionHandler } from './railroad-handler.js'; diff --git a/packages/langium-vscode/src/language-server/railroad-handler.ts b/packages/langium-vscode/src/language-server/railroad-handler.ts index 297806117..75930e6fd 100644 --- a/packages/langium-vscode/src/language-server/railroad-handler.ts +++ b/packages/langium-vscode/src/language-server/railroad-handler.ts @@ -4,11 +4,11 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { Grammar, LangiumServices } from 'langium'; -import { DocumentState, GrammarAST, URI } from 'langium'; +import { DocumentState, GrammarAST, URI, type Grammar } from 'langium'; import { createGrammarDiagramHtml } from 'langium-railroad'; import { expandToString } from 'langium/generate'; import { resolveTransitiveImports } from 'langium/grammar'; +import type { LangiumServices } from 'langium/lsp'; import type { Connection } from 'vscode-languageserver'; import { DiagnosticSeverity } from 'vscode-languageserver'; import { DOCUMENTS_VALIDATED_NOTIFICATION, RAILROAD_DIAGRAM_REQUEST } from './messages.js'; diff --git a/packages/langium/package.json b/packages/langium/package.json index 623fc35c2..cd234991e 100644 --- a/packages/langium/package.json +++ b/packages/langium/package.json @@ -45,6 +45,10 @@ "./grammar": { "types": "./lib/grammar/index.d.ts", "import": "./lib/grammar/index.js" + }, + "./lsp": { + "types": "./lib/lsp/index.d.ts", + "import": "./lib/lsp/index.js" } }, "scripts": { diff --git a/packages/langium/src/default-module.ts b/packages/langium/src/default-module.ts index 6224e0e73..a9e8b8217 100644 --- a/packages/langium/src/default-module.ts +++ b/packages/langium/src/default-module.ts @@ -4,27 +4,11 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { Connection } from 'vscode-languageserver'; import type { Module } from './dependency-injection.js'; -import type { LangiumDefaultServices, LangiumDefaultSharedServices, LangiumServices, LangiumSharedServices } from './services.js'; +import type { LangiumDefaultCoreServices, LangiumDefaultSharedCoreServices, LangiumCoreServices, LangiumSharedCoreServices } from './services.js'; import type { FileSystemProvider } from './workspace/file-system-provider.js'; -import { TextDocuments } from 'vscode-languageserver'; -import { TextDocument } from 'vscode-languageserver-textdocument'; import { createGrammarConfig } from './languages/grammar-config.js'; import { createCompletionParser } from './parser/completion-parser-builder.js'; -import { DefaultCompletionProvider } from './lsp/completion/completion-provider.js'; -import { DefaultDocumentHighlightProvider } from './lsp/document-highlight-provider.js'; -import { DefaultDocumentSymbolProvider } from './lsp/document-symbol-provider.js'; -import { DefaultDocumentUpdateHandler } from './lsp/document-update-handler.js'; -import { DefaultFoldingRangeProvider } from './lsp/folding-range-provider.js'; -import { DefaultFuzzyMatcher } from './lsp/fuzzy-matcher.js'; -import { DefaultDefinitionProvider } from './lsp/definition-provider.js'; -import { MultilineCommentHoverProvider } from './lsp/hover-provider.js'; -import { DefaultLanguageServer } from './lsp/language-server.js'; -import { DefaultNodeKindProvider } from './lsp/node-kind-provider.js'; -import { DefaultReferencesProvider } from './lsp/references-provider.js'; -import { DefaultRenameProvider } from './lsp/rename-provider.js'; -import { DefaultWorkspaceSymbolProvider } from './lsp/workspace-symbol-provider.js'; import { createLangiumParser } from './parser/langium-parser-builder.js'; import { DefaultTokenBuilder } from './parser/token-builder.js'; import { DefaultValueConverter } from './parser/value-converter.js'; @@ -54,15 +38,15 @@ import { DefaultWorkspaceLock } from './workspace/workspace-lock.js'; /** * Context required for creating the default language-specific dependency injection module. */ -export interface DefaultModuleContext { - shared: LangiumSharedServices; +export interface DefaultCoreModuleContext { + shared: LangiumSharedCoreServices; } /** - * Create a dependency injection module for the default language-specific services. This is a - * set of services that are used by exactly one language. + * Creates a dependency injection module configuring the default core services. + * This is a set of services that are dedicated to a specific language. */ -export function createDefaultModule(context: DefaultModuleContext): Module { +export function createDefaultCoreModule(context: DefaultCoreModuleContext): Module { return { documentation: { CommentProvider: (services) => new DefaultCommentProvider(services), @@ -78,16 +62,6 @@ export function createDefaultModule(context: DefaultModuleContext): Module new DefaultLexer(services), ParserErrorMessageProvider: () => new LangiumParserErrorMessageProvider() }, - lsp: { - CompletionProvider: (services) => new DefaultCompletionProvider(services), - DocumentSymbolProvider: (services) => new DefaultDocumentSymbolProvider(services), - HoverProvider: (services) => new MultilineCommentHoverProvider(services), - FoldingRangeProvider: (services) => new DefaultFoldingRangeProvider(services), - ReferencesProvider: (services) => new DefaultReferencesProvider(services), - DefinitionProvider: (services) => new DefaultDefinitionProvider(services), - DocumentHighlightProvider: (services) => new DefaultDocumentHighlightProvider(services), - RenameProvider: (services) => new DefaultRenameProvider(services) - }, workspace: { AstNodeLocator: () => new DefaultAstNodeLocator(), AstNodeDescriptionProvider: (services) => new DefaultAstNodeDescriptionProvider(services), @@ -114,11 +88,7 @@ export function createDefaultModule(context: DefaultModuleContext): Module FileSystemProvider; + fileSystemProvider: (services: LangiumSharedCoreServices) => FileSystemProvider; } /** - * Create a dependency injection module for the default shared services. This is the set of - * services that are shared between multiple languages. + * Creates a dependency injection module configuring the default shared core services. + * This is the set of services that are shared between multiple languages. */ -export function createDefaultSharedModule(context: DefaultSharedModuleContext): Module { +export function createDefaultSharedCoreModule(context: DefaultSharedCoreModuleContext): Module { return { ServiceRegistry: () => new DefaultServiceRegistry(), - lsp: { - Connection: () => context.connection, - LanguageServer: (services) => new DefaultLanguageServer(services), - DocumentUpdateHandler: (services) => new DefaultDocumentUpdateHandler(services), - WorkspaceSymbolProvider: (services) => new DefaultWorkspaceSymbolProvider(services), - NodeKindProvider: () => new DefaultNodeKindProvider(), - FuzzyMatcher: () => new DefaultFuzzyMatcher() - }, workspace: { LangiumDocuments: (services) => new DefaultLangiumDocuments(services), LangiumDocumentFactory: (services) => new DefaultLangiumDocumentFactory(services), DocumentBuilder: (services) => new DefaultDocumentBuilder(services), - TextDocuments: () => new TextDocuments(TextDocument), IndexManager: (services) => new DefaultIndexManager(services), WorkspaceManager: (services) => new DefaultWorkspaceManager(services), FileSystemProvider: (services) => context.fileSystemProvider(services), diff --git a/packages/langium/src/dependency-injection.ts b/packages/langium/src/dependency-injection.ts index b99b39702..2c02b9c05 100644 --- a/packages/langium/src/dependency-injection.ts +++ b/packages/langium/src/dependency-injection.ts @@ -19,8 +19,12 @@ export type Module = { [K in keyof T]: Module | ((injector: I) => T[K]) } +export namespace Module { + export const merge = (m1: Module, m2: Module) => (_merge(_merge({}, m1), m2) as Module); +} + /** - * Given a set of modules, the inject function returns a lazily evaluted injector + * Given a set of modules, the inject function returns a lazily evaluated injector * that injects dependencies into the requested service when it is requested the * first time. Subsequent requests will return the same service. * @@ -34,10 +38,17 @@ export type Module = { * @param module2 (optional) second Module * @param module3 (optional) third Module * @param module4 (optional) fourth Module + * @param module5 (optional) fifth Module + * @param module6 (optional) sixth Module + * @param module7 (optional) seventh Module + * @param module8 (optional) eighth Module + * @param module9 (optional) ninth Module * @returns a new object of type I */ -export function inject(module1: Module, module2?: Module, module3?: Module, module4?: Module): I { - const module = [module1, module2, module3, module4].reduce(_merge, {}) as Module; +export function inject( + module1: Module, module2?: Module, module3?: Module, module4?: Module, module5?: Module, module6?: Module, module7?: Module, module8?: Module, module9?: Module +): I { + const module = [module1, module2, module3, module4, module5, module6, module7, module8, module9].reduce(_merge, {}) as Module; return _inject(module); } diff --git a/packages/langium/src/documentation/comment-provider.ts b/packages/langium/src/documentation/comment-provider.ts index af0750e89..1d9c58d15 100644 --- a/packages/langium/src/documentation/comment-provider.ts +++ b/packages/langium/src/documentation/comment-provider.ts @@ -6,7 +6,7 @@ import type { GrammarConfig } from '../languages/grammar-config.js'; import { isAstNodeWithComment } from '../serializer/json-serializer.js'; -import type { LangiumServices } from '../services.js'; +import type { LangiumCoreServices } from '../services.js'; import type { AstNode } from '../syntax-tree.js'; import { findCommentNode } from '../utils/cst-utils.js'; @@ -24,7 +24,7 @@ export interface CommentProvider { export class DefaultCommentProvider implements CommentProvider { protected readonly grammarConfig: () => GrammarConfig; - constructor(services: LangiumServices) { + constructor(services: LangiumCoreServices) { this.grammarConfig = () => services.parser.GrammarConfig; } getComment(node: AstNode): string | undefined { diff --git a/packages/langium/src/documentation/documentation-provider.ts b/packages/langium/src/documentation/documentation-provider.ts index b44effe3e..70c474091 100644 --- a/packages/langium/src/documentation/documentation-provider.ts +++ b/packages/langium/src/documentation/documentation-provider.ts @@ -4,7 +4,7 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { LangiumServices } from '../services.js'; +import type { LangiumCoreServices } from '../services.js'; import type { AstNode, AstNodeDescription } from '../syntax-tree.js'; import type { IndexManager } from '../workspace/index-manager.js'; import type { CommentProvider } from './comment-provider.js'; @@ -29,7 +29,7 @@ export class JSDocDocumentationProvider implements DocumentationProvider { protected readonly indexManager: IndexManager; protected readonly commentProvider: CommentProvider; - constructor(services: LangiumServices) { + constructor(services: LangiumCoreServices) { this.indexManager = services.shared.workspace.IndexManager; this.commentProvider = services.documentation.CommentProvider; } diff --git a/packages/langium/src/documentation/jsdoc.ts b/packages/langium/src/documentation/jsdoc.ts index 32ae2202f..29d4d58a1 100644 --- a/packages/langium/src/documentation/jsdoc.ts +++ b/packages/langium/src/documentation/jsdoc.ts @@ -4,8 +4,8 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ +import { Position, Range } from 'vscode-languageserver-types'; import type { CstNode } from '../syntax-tree.js'; -import { Position, Range } from 'vscode-languageserver'; import { NEWLINE_REGEXP, escapeRegExp } from '../utils/regexp-utils.js'; import { URI } from '../utils/uri-utils.js'; diff --git a/packages/langium/src/grammar/generated/module.ts b/packages/langium/src/grammar/generated/module.ts index eb9184bad..952ac718d 100644 --- a/packages/langium/src/grammar/generated/module.ts +++ b/packages/langium/src/grammar/generated/module.ts @@ -6,7 +6,8 @@ import type { LanguageMetaData } from '../../languages/language-meta-data.js'; import { LangiumGrammarAstReflection } from '../../languages/generated/ast.js'; import type { Module } from '../../dependency-injection.js'; -import type { LangiumGeneratedServices, LangiumGeneratedSharedServices, LangiumSharedServices, LangiumServices } from '../../services.js'; +import type { LangiumGeneratedCoreServices, LangiumGeneratedSharedCoreServices } from '../../services.js'; +import type { LangiumSharedServices, LangiumServices } from '../../lsp/lsp-services.js'; import type { IParserConfig } from '../../parser/parser-config.js'; import { LangiumGrammarGrammar } from './grammar.js'; @@ -20,11 +21,11 @@ export const LangiumGrammarParserConfig: IParserConfig = { maxLookahead: 3, }; -export const LangiumGrammarGeneratedSharedModule: Module = { +export const LangiumGrammarGeneratedSharedModule: Module = { AstReflection: () => new LangiumGrammarAstReflection() }; -export const LangiumGrammarGeneratedModule: Module = { +export const LangiumGrammarGeneratedModule: Module = { Grammar: () => LangiumGrammarGrammar(), LanguageMetaData: () => LangiumGrammarLanguageMetaData, parser: { diff --git a/packages/langium/src/grammar/internal-grammar-util.ts b/packages/langium/src/grammar/internal-grammar-util.ts index d27ed6a2c..e3b7bcc97 100644 --- a/packages/langium/src/grammar/internal-grammar-util.ts +++ b/packages/langium/src/grammar/internal-grammar-util.ts @@ -16,10 +16,11 @@ import type { IParserConfig } from '../parser/parser-config.js'; import type { LanguageMetaData } from '../languages/language-meta-data.js'; import type { Module} from '../dependency-injection.js'; import { inject } from '../dependency-injection.js'; -import type { LangiumGeneratedServices, LangiumGeneratedSharedServices, LangiumServices, LangiumSharedServices } from '../services.js'; +import type { LangiumGeneratedCoreServices, LangiumGeneratedSharedCoreServices } from '../services.js'; +import type { LangiumServices, LangiumSharedServices } from '../lsp/lsp-services.js'; +import { createDefaultModule, createDefaultSharedModule } from '../lsp/default-lsp-module.js'; import { EmptyFileSystem } from '../workspace/file-system-provider.js'; import { interpretAstReflection } from './ast-reflection-interpreter.js'; -import { createDefaultModule, createDefaultSharedModule } from '../default-module.js'; import { getTypeName, isDataType } from '../utils/grammar-utils.js'; export function hasDataTypeReturn(rule: ast.ParserRule): boolean { @@ -183,10 +184,10 @@ export async function createServicesForGrammar = { + const generatedSharedModule: Module = { AstReflection: () => interpretAstReflection(grammarNode), }; - const generatedModule: Module = { + const generatedModule: Module = { Grammar: () => grammarNode, LanguageMetaData: () => languageMetaData, parser: { diff --git a/packages/langium/src/grammar/langium-grammar-module.ts b/packages/langium/src/grammar/langium-grammar-module.ts index c3dea89ab..5cf7d9a33 100644 --- a/packages/langium/src/grammar/langium-grammar-module.ts +++ b/packages/langium/src/grammar/langium-grammar-module.ts @@ -4,13 +4,12 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { DefaultSharedModuleContext } from '../default-module.js'; import type { Module } from '../dependency-injection.js'; -import type { LangiumServices, LangiumSharedServices, PartialLangiumServices, PartialLangiumSharedServices } from '../services.js'; +import type { LangiumServices, LangiumSharedServices, PartialLangiumServices, PartialLangiumSharedServices } from '../lsp/lsp-services.js'; import { LangiumGrammarTypeHierarchyProvider } from './lsp/grammar-type-hierarchy.js'; import type { LangiumGrammarDocument } from './workspace/documents.js'; import type { Grammar } from '../languages/generated/ast.js'; -import { createDefaultModule, createDefaultSharedModule } from '../default-module.js'; +import { type DefaultSharedModuleContext, createDefaultModule, createDefaultSharedModule } from '../lsp/default-lsp-module.js'; import { inject } from '../dependency-injection.js'; import { LangiumGrammarGeneratedModule, LangiumGrammarGeneratedSharedModule } from './generated/module.js'; import { LangiumGrammarScopeComputation, LangiumGrammarScopeProvider } from './references/grammar-scope.js'; @@ -63,6 +62,13 @@ export const LangiumGrammarModule: Module): { shared: LangiumSharedServices, diff --git a/packages/langium/src/grammar/lsp/grammar-code-actions.ts b/packages/langium/src/grammar/lsp/grammar-code-actions.ts index 3bfbd86cb..c4baaddf9 100644 --- a/packages/langium/src/grammar/lsp/grammar-code-actions.ts +++ b/packages/langium/src/grammar/lsp/grammar-code-actions.ts @@ -9,7 +9,7 @@ import type { CodeActionParams } from 'vscode-languageserver-protocol'; import type { CodeAction, Command, Position, TextEdit } from 'vscode-languageserver-types'; import type { URI } from '../../utils/uri-utils.js'; import type { CodeActionProvider } from '../../lsp/code-action.js'; -import type { LangiumServices } from '../../services.js'; +import type { LangiumServices } from '../../lsp/lsp-services.js'; import type { AstReflection, Reference, ReferenceInfo } from '../../syntax-tree.js'; import type { MaybePromise } from '../../utils/promise-utils.js'; import type { LinkingErrorData } from '../../validation/document-validator.js'; diff --git a/packages/langium/src/grammar/lsp/grammar-completion-provider.ts b/packages/langium/src/grammar/lsp/grammar-completion-provider.ts index 362375b55..16da25557 100644 --- a/packages/langium/src/grammar/lsp/grammar-completion-provider.ts +++ b/packages/langium/src/grammar/lsp/grammar-completion-provider.ts @@ -7,15 +7,14 @@ import type { Range } from 'vscode-languageserver-types'; import { CompletionItemKind } from 'vscode-languageserver-types'; import type { NextFeature } from '../../lsp/completion/follow-element-computation.js'; -import type { CompletionAcceptor, CompletionContext } from '../../lsp/completion/completion-provider.js'; -import { DefaultCompletionProvider } from '../../lsp/completion/completion-provider.js'; -import type { LangiumServices } from '../../services.js'; +import { DefaultCompletionProvider, type CompletionAcceptor, type CompletionContext } from '../../lsp/completion/completion-provider.js'; import type { MaybePromise } from '../../utils/promise-utils.js'; import { getContainerOfType } from '../../utils/ast-utils.js'; import type { LangiumDocument, LangiumDocuments } from '../../workspace/documents.js'; import type { AbstractElement } from '../../languages/generated/ast.js'; import { isAssignment } from '../../languages/generated/ast.js'; import { UriUtils } from '../../utils/uri-utils.js'; +import type { LangiumServices } from '../../lsp/lsp-services.js'; export class LangiumGrammarCompletionProvider extends DefaultCompletionProvider { diff --git a/packages/langium/src/grammar/lsp/grammar-definition.ts b/packages/langium/src/grammar/lsp/grammar-definition.ts index 6c3333ebc..938e64111 100644 --- a/packages/langium/src/grammar/lsp/grammar-definition.ts +++ b/packages/langium/src/grammar/lsp/grammar-definition.ts @@ -5,7 +5,7 @@ ******************************************************************************/ import type { DefinitionParams } from 'vscode-languageserver'; -import type { LangiumServices } from '../../services.js'; +import type { LangiumServices } from '../../lsp/lsp-services.js'; import type { AstNode, LeafCstNode, Properties } from '../../syntax-tree.js'; import type { MaybePromise } from '../../utils/promise-utils.js'; import type { LangiumDocuments } from '../../workspace/documents.js'; diff --git a/packages/langium/src/grammar/references/grammar-references.ts b/packages/langium/src/grammar/references/grammar-references.ts index 06e3d54d7..a96697d1e 100644 --- a/packages/langium/src/grammar/references/grammar-references.ts +++ b/packages/langium/src/grammar/references/grammar-references.ts @@ -4,7 +4,7 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { LangiumServices } from '../../services.js'; +import type { LangiumCoreServices } from '../../services.js'; import type { AstNode, CstNode } from '../../syntax-tree.js'; import type { Stream } from '../../utils/stream.js'; import type { ReferenceDescription } from '../../workspace/ast-descriptions.js'; @@ -24,7 +24,7 @@ import { collectChildrenTypes, collectSuperTypes } from '../type-system/types-ut export class LangiumGrammarReferences extends DefaultReferences { protected readonly documents: LangiumDocuments; - constructor(services: LangiumServices) { + constructor(services: LangiumCoreServices) { super(services); this.documents = services.shared.workspace.LangiumDocuments; } diff --git a/packages/langium/src/grammar/references/grammar-scope.ts b/packages/langium/src/grammar/references/grammar-scope.ts index 9cf11196b..6f32d1a9a 100644 --- a/packages/langium/src/grammar/references/grammar-scope.ts +++ b/packages/langium/src/grammar/references/grammar-scope.ts @@ -5,7 +5,7 @@ ******************************************************************************/ import type { Scope } from '../../references/scope.js'; -import type { LangiumServices } from '../../services.js'; +import type { LangiumCoreServices } from '../../services.js'; import type { AstNode, AstNodeDescription, ReferenceInfo } from '../../syntax-tree.js'; import type { Stream } from '../../utils/stream.js'; import type { AstNodeLocator } from '../../workspace/ast-node-locator.js'; @@ -25,7 +25,7 @@ export class LangiumGrammarScopeProvider extends DefaultScopeProvider { protected readonly langiumDocuments: LangiumDocuments; - constructor(services: LangiumServices) { + constructor(services: LangiumCoreServices) { super(services); this.langiumDocuments = services.shared.workspace.LangiumDocuments; } @@ -93,7 +93,7 @@ export class LangiumGrammarScopeProvider extends DefaultScopeProvider { export class LangiumGrammarScopeComputation extends DefaultScopeComputation { protected readonly astNodeLocator: AstNodeLocator; - constructor(services: LangiumServices) { + constructor(services: LangiumCoreServices) { super(services); this.astNodeLocator = services.workspace.AstNodeLocator; } diff --git a/packages/langium/src/index.ts b/packages/langium/src/index.ts index e7e5492ea..654c6fb90 100644 --- a/packages/langium/src/index.ts +++ b/packages/langium/src/index.ts @@ -11,7 +11,6 @@ export * from './services.js'; export * from './syntax-tree.js'; export * from './documentation/index.js'; export * from './languages/index.js'; -export * from './lsp/index.js'; export * from './parser/index.js'; export * from './references/index.js'; export * from './serializer/index.js'; diff --git a/packages/langium/src/languages/grammar-config.ts b/packages/langium/src/languages/grammar-config.ts index 4dcd160b2..ca6e56a9b 100644 --- a/packages/langium/src/languages/grammar-config.ts +++ b/packages/langium/src/languages/grammar-config.ts @@ -4,12 +4,11 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { LangiumServices } from '../services.js'; +import type { LangiumCoreServices } from '../services.js'; import { DefaultNameRegexp } from '../utils/cst-utils.js'; -import { isCommentTerminal } from '../utils/grammar-utils.js'; +import { isCommentTerminal, terminalRegex } from '../utils/grammar-utils.js'; import { isMultilineComment } from '../utils/regexp-utils.js'; import { isTerminalRule } from './generated/ast.js'; -import { terminalRegex } from '../utils/grammar-utils.js'; export interface GrammarConfig { /** @@ -26,7 +25,7 @@ export interface GrammarConfig { * Create the default grammar configuration (used by `createDefaultModule`). This can be overridden in a * language-specific module. */ -export function createGrammarConfig(services: LangiumServices): GrammarConfig { +export function createGrammarConfig(services: LangiumCoreServices): GrammarConfig { const rules: string[] = []; const grammar = services.Grammar; for (const rule of grammar.rules) { diff --git a/packages/langium/src/lsp/call-hierarchy-provider.ts b/packages/langium/src/lsp/call-hierarchy-provider.ts index bde3e454a..3c509ee43 100644 --- a/packages/langium/src/lsp/call-hierarchy-provider.ts +++ b/packages/langium/src/lsp/call-hierarchy-provider.ts @@ -4,11 +4,12 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem, CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams, CancellationToken } from 'vscode-languageserver'; +import type { CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem, CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams, } from 'vscode-languageserver'; +import type { CancellationToken } from '../utils/cancellation.js'; import type { GrammarConfig } from '../languages/grammar-config.js'; import type { NameProvider } from '../references/name-provider.js'; import type { References } from '../references/references.js'; -import type { LangiumServices } from '../services.js'; +import type { LangiumServices } from './lsp-services.js'; import type { AstNode } from '../syntax-tree.js'; import type { Stream } from '../utils/stream.js'; import type { ReferenceDescription } from '../workspace/ast-descriptions.js'; diff --git a/packages/langium/src/lsp/code-action.ts b/packages/langium/src/lsp/code-action.ts index 536307b79..0ac16f903 100644 --- a/packages/langium/src/lsp/code-action.ts +++ b/packages/langium/src/lsp/code-action.ts @@ -4,7 +4,8 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { CancellationToken, CodeAction, CodeActionParams, Command } from 'vscode-languageserver'; +import type { CodeAction, CodeActionParams, Command } from 'vscode-languageserver'; +import type { CancellationToken } from '../utils/cancellation.js'; import type { MaybePromise } from '../utils/promise-utils.js'; import type { LangiumDocument } from '../workspace/documents.js'; diff --git a/packages/langium/src/lsp/code-lens-provider.ts b/packages/langium/src/lsp/code-lens-provider.ts index 9b0e99351..b3bb359c2 100644 --- a/packages/langium/src/lsp/code-lens-provider.ts +++ b/packages/langium/src/lsp/code-lens-provider.ts @@ -4,7 +4,8 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { CancellationToken, CodeLens, CodeLensParams } from 'vscode-languageserver'; +import type { CodeLens, CodeLensParams } from 'vscode-languageserver'; +import type { CancellationToken } from '../utils/cancellation.js'; import type { MaybePromise } from '../utils/promise-utils.js'; import type { LangiumDocument } from '../workspace/documents.js'; diff --git a/packages/langium/src/lsp/completion/completion-provider.ts b/packages/langium/src/lsp/completion/completion-provider.ts index 8d615ca32..4b00dac28 100644 --- a/packages/langium/src/lsp/completion/completion-provider.ts +++ b/packages/langium/src/lsp/completion/completion-provider.ts @@ -4,15 +4,15 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { CancellationToken, CompletionItem, CompletionParams } from 'vscode-languageserver'; -import type { TextDocument, TextEdit } from 'vscode-languageserver-textdocument'; +import type { CompletionItem, CompletionParams, TextEdit } from 'vscode-languageserver-protocol'; import type { LangiumCompletionParser } from '../../parser/langium-parser.js'; import type { NameProvider } from '../../references/name-provider.js'; import type { ScopeProvider } from '../../references/scope-provider.js'; -import type { LangiumServices } from '../../services.js'; +import type { LangiumServices } from '../lsp-services.js'; import type { AstNode, AstNodeDescription, AstReflection, CstNode, ReferenceInfo } from '../../syntax-tree.js'; +import type { CancellationToken } from '../../utils/cancellation.js'; import type { MaybePromise } from '../../utils/promise-utils.js'; -import type { LangiumDocument } from '../../workspace/documents.js'; +import type { LangiumDocument, TextDocument } from '../../workspace/documents.js'; import type { NextFeature } from './follow-element-computation.js'; import type { NodeKindProvider } from '../node-kind-provider.js'; import type { FuzzyMatcher } from '../fuzzy-matcher.js'; diff --git a/packages/langium/src/lsp/declaration-provider.ts b/packages/langium/src/lsp/declaration-provider.ts index a92e905b0..7c1e6f0b2 100644 --- a/packages/langium/src/lsp/declaration-provider.ts +++ b/packages/langium/src/lsp/declaration-provider.ts @@ -4,7 +4,8 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { CancellationToken, DeclarationParams, LocationLink } from 'vscode-languageserver'; +import type { DeclarationParams, LocationLink } from 'vscode-languageserver'; +import type { CancellationToken } from '../utils/cancellation.js'; import type { MaybePromise } from '../utils/promise-utils.js'; import type { LangiumDocument } from '../workspace/documents.js'; diff --git a/packages/langium/src/lsp/default-lsp-module.ts b/packages/langium/src/lsp/default-lsp-module.ts new file mode 100644 index 000000000..2a11efe36 --- /dev/null +++ b/packages/langium/src/lsp/default-lsp-module.ts @@ -0,0 +1,101 @@ +/****************************************************************************** + * Copyright 2023 TypeFox GmbH + * This program and the accompanying materials are made available under the + * terms of the MIT License, which is available in the project root. +******************************************************************************/ + +import { type Connection, TextDocuments } from 'vscode-languageserver'; +import { createDefaultCoreModule, createDefaultSharedCoreModule, type DefaultCoreModuleContext, type DefaultSharedCoreModuleContext } from '../default-module.js'; +import { Module } from '../dependency-injection.js'; +import type { LangiumDefaultCoreServices, LangiumDefaultSharedCoreServices } from '../services.js'; +import { TextDocument } from '../workspace/documents.js'; +import { DefaultCompletionProvider } from './completion/completion-provider.js'; +import { DefaultDefinitionProvider } from './definition-provider.js'; +import { DefaultDocumentHighlightProvider } from './document-highlight-provider.js'; +import { DefaultDocumentSymbolProvider } from './document-symbol-provider.js'; +import { DefaultDocumentUpdateHandler } from './document-update-handler.js'; +import { DefaultFoldingRangeProvider } from './folding-range-provider.js'; +import { DefaultFuzzyMatcher } from './fuzzy-matcher.js'; +import { MultilineCommentHoverProvider } from './hover-provider.js'; +import { DefaultLanguageServer } from './language-server.js'; +import type { LangiumLSPServices, LangiumServices, LangiumSharedLSPServices, LangiumSharedServices } from './lsp-services.js'; +import { DefaultNodeKindProvider } from './node-kind-provider.js'; +import { DefaultReferencesProvider } from './references-provider.js'; +import { DefaultRenameProvider } from './rename-provider.js'; +import { DefaultWorkspaceSymbolProvider } from './workspace-symbol-provider.js'; + +/** + * Context required for creating the default language-specific dependency injection module. + */ +export interface DefaultModuleContext extends DefaultCoreModuleContext { + shared: LangiumSharedServices; +} + +/** + * Creates a dependency injection module configuring the default Core & LSP services for a Langium-based language implementation. + * This is a set of services that are dedicated to a specific language. + */ +export function createDefaultModule(context: DefaultModuleContext): Module { + return Module.merge( + createDefaultCoreModule(context), + createDefaultLSPModule(context) + ); +} + +/** + * Creates a dependency injection module configuring the default LSP services. + * This is a set of services that are dedicated to a specific language. + */ +export function createDefaultLSPModule(context: DefaultModuleContext): Module { + return { + lsp: { + CompletionProvider: (services) => new DefaultCompletionProvider(services), + DocumentSymbolProvider: (services) => new DefaultDocumentSymbolProvider(services), + HoverProvider: (services) => new MultilineCommentHoverProvider(services), + FoldingRangeProvider: (services) => new DefaultFoldingRangeProvider(services), + ReferencesProvider: (services) => new DefaultReferencesProvider(services), + DefinitionProvider: (services) => new DefaultDefinitionProvider(services), + DocumentHighlightProvider: (services) => new DefaultDocumentHighlightProvider(services), + RenameProvider: (services) => new DefaultRenameProvider(services) + }, + shared: () => context.shared + }; +} + +export interface DefaultSharedModuleContext extends DefaultSharedCoreModuleContext { + /** + * Represents an abstract language server connection + */ + connection?: Connection; +} + +/** + * Creates a dependency injection module configuring the default core & LSP services shared among languages supported by a Langium-based language server. + * This is the set of services that are shared between multiple languages. + */ +export function createDefaultSharedModule(context: DefaultSharedModuleContext): Module { + return Module.merge( + createDefaultSharedCoreModule(context), + createDefaultSharedLSPModule(context) + ); +} + +/** + * Creates a dependency injection module configuring the default shared LSP services. + * This is the set of services that are shared between multiple languages. + */ +export function createDefaultSharedLSPModule(context: DefaultSharedModuleContext): Module { + return { + lsp: { + Connection: () => context.connection, + LanguageServer: (services) => new DefaultLanguageServer(services), + DocumentUpdateHandler: (services) => new DefaultDocumentUpdateHandler(services), + WorkspaceSymbolProvider: (services) => new DefaultWorkspaceSymbolProvider(services), + NodeKindProvider: () => new DefaultNodeKindProvider(), + FuzzyMatcher: () => new DefaultFuzzyMatcher(), + }, + workspace: { + TextDocuments: () => new TextDocuments(TextDocument) + } + }; +} diff --git a/packages/langium/src/lsp/definition-provider.ts b/packages/langium/src/lsp/definition-provider.ts index 9b309ed76..a9edab761 100644 --- a/packages/langium/src/lsp/definition-provider.ts +++ b/packages/langium/src/lsp/definition-provider.ts @@ -4,11 +4,12 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { CancellationToken, DefinitionParams } from 'vscode-languageserver'; +import type { DefinitionParams } from 'vscode-languageserver'; +import type { CancellationToken } from '../utils/cancellation.js'; import type { GrammarConfig } from '../languages/grammar-config.js'; import type { NameProvider } from '../references/name-provider.js'; import type { References } from '../references/references.js'; -import type { LangiumServices } from '../services.js'; +import type { LangiumServices } from './lsp-services.js'; import type { CstNode } from '../syntax-tree.js'; import type { MaybePromise } from '../utils/promise-utils.js'; import type { LangiumDocument } from '../workspace/documents.js'; diff --git a/packages/langium/src/lsp/document-highlight-provider.ts b/packages/langium/src/lsp/document-highlight-provider.ts index 8275faded..13859cd33 100644 --- a/packages/langium/src/lsp/document-highlight-provider.ts +++ b/packages/langium/src/lsp/document-highlight-provider.ts @@ -4,11 +4,12 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { CancellationToken, DocumentHighlightParams } from 'vscode-languageserver'; +import type { DocumentHighlightParams } from 'vscode-languageserver'; +import type { CancellationToken } from '../utils/cancellation.js'; import type { GrammarConfig } from '../languages/grammar-config.js'; import type { NameProvider } from '../references/name-provider.js'; import type { FindReferencesOptions, References } from '../references/references.js'; -import type { LangiumServices } from '../services.js'; +import type { LangiumServices } from './lsp-services.js'; import type { MaybePromise } from '../utils/promise-utils.js'; import type { ReferenceDescription } from '../workspace/ast-descriptions.js'; import type { LangiumDocument } from '../workspace/documents.js'; diff --git a/packages/langium/src/lsp/document-link-provider.ts b/packages/langium/src/lsp/document-link-provider.ts index a15455045..619b4b9eb 100644 --- a/packages/langium/src/lsp/document-link-provider.ts +++ b/packages/langium/src/lsp/document-link-provider.ts @@ -4,7 +4,8 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { CancellationToken, DocumentLink, DocumentLinkParams } from 'vscode-languageserver'; +import type { DocumentLink, DocumentLinkParams } from 'vscode-languageserver'; +import type { CancellationToken } from '../utils/cancellation.js'; import type { MaybePromise } from '../utils/promise-utils.js'; import type { LangiumDocument } from '../workspace/documents.js'; diff --git a/packages/langium/src/lsp/document-symbol-provider.ts b/packages/langium/src/lsp/document-symbol-provider.ts index 72897ec5d..6cd9f08fb 100644 --- a/packages/langium/src/lsp/document-symbol-provider.ts +++ b/packages/langium/src/lsp/document-symbol-provider.ts @@ -4,9 +4,10 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { CancellationToken, DocumentSymbol, DocumentSymbolParams} from 'vscode-languageserver'; +import type { DocumentSymbol, DocumentSymbolParams } from 'vscode-languageserver'; +import type { CancellationToken } from '../utils/cancellation.js'; import type { NameProvider } from '../references/name-provider.js'; -import type { LangiumServices } from '../services.js'; +import type { LangiumServices } from './lsp-services.js'; import type { AstNode } from '../syntax-tree.js'; import { streamContents } from '../utils/ast-utils.js'; import type { MaybePromise } from '../utils/promise-utils.js'; diff --git a/packages/langium/src/lsp/document-update-handler.ts b/packages/langium/src/lsp/document-update-handler.ts index ed1dd153b..19d75c434 100644 --- a/packages/langium/src/lsp/document-update-handler.ts +++ b/packages/langium/src/lsp/document-update-handler.ts @@ -4,14 +4,13 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { DidChangeWatchedFilesParams, DidChangeWatchedFilesRegistrationOptions, TextDocumentChangeEvent } from 'vscode-languageserver'; -import type { TextDocument } from 'vscode-languageserver-textdocument'; -import type { LangiumSharedServices } from '../services.js'; -import type { WorkspaceLock } from '../workspace/workspace-lock.js'; -import type { DocumentBuilder } from '../workspace/document-builder.js'; -import { DidChangeWatchedFilesNotification, FileChangeType } from 'vscode-languageserver'; -import { URI } from '../utils/uri-utils.js'; +import { DidChangeWatchedFilesNotification, FileChangeType, type DidChangeWatchedFilesParams, type DidChangeWatchedFilesRegistrationOptions, type TextDocumentChangeEvent } from 'vscode-languageserver'; import { stream } from '../utils/stream.js'; +import { URI } from '../utils/uri-utils.js'; +import type { DocumentBuilder } from '../workspace/document-builder.js'; +import type { TextDocument } from '../workspace/documents.js'; +import type { WorkspaceLock } from '../workspace/workspace-lock.js'; +import type { LangiumSharedServices } from './lsp-services.js'; /** * Shared service for handling text document changes and watching relevant files. diff --git a/packages/langium/src/lsp/execute-command-handler.ts b/packages/langium/src/lsp/execute-command-handler.ts index 183f7b820..b15cfef2a 100644 --- a/packages/langium/src/lsp/execute-command-handler.ts +++ b/packages/langium/src/lsp/execute-command-handler.ts @@ -7,7 +7,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import type { MaybePromise } from '../utils/promise-utils.js'; -import { CancellationToken } from 'vscode-languageserver'; +import { CancellationToken } from '../utils/cancellation.js'; export interface ExecuteCommandHandler { get commands(): string[] diff --git a/packages/langium/src/lsp/folding-range-provider.ts b/packages/langium/src/lsp/folding-range-provider.ts index fd2f35a5c..139bb46d3 100644 --- a/packages/langium/src/lsp/folding-range-provider.ts +++ b/packages/langium/src/lsp/folding-range-provider.ts @@ -4,8 +4,9 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { CancellationToken, FoldingRangeParams } from 'vscode-languageserver'; -import type { LangiumServices } from '../services.js'; +import type { FoldingRangeParams } from 'vscode-languageserver'; +import type { CancellationToken } from '../utils/cancellation.js'; +import type { LangiumServices } from './lsp-services.js'; import type { AstNode, CstNode } from '../syntax-tree.js'; import type { MaybePromise } from '../utils/promise-utils.js'; import type { LangiumDocument } from '../workspace/documents.js'; diff --git a/packages/langium/src/lsp/formatter.ts b/packages/langium/src/lsp/formatter.ts index c90d87778..bd489aef2 100644 --- a/packages/langium/src/lsp/formatter.ts +++ b/packages/langium/src/lsp/formatter.ts @@ -4,12 +4,12 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { CancellationToken, DocumentFormattingParams, DocumentOnTypeFormattingOptions, DocumentOnTypeFormattingParams, DocumentRangeFormattingParams, FormattingOptions, Range, TextEdit } from 'vscode-languageserver'; -import type { TextDocument } from 'vscode-languageserver-textdocument'; +import type { DocumentFormattingParams, DocumentOnTypeFormattingOptions, DocumentOnTypeFormattingParams, DocumentRangeFormattingParams, FormattingOptions, Range, TextEdit } from 'vscode-languageserver-protocol'; +import type { CancellationToken } from '../utils/cancellation.js'; import type { AstNode, CstNode, Properties } from '../syntax-tree.js'; import type { MaybePromise } from '../utils/promise-utils.js'; import type { Stream } from '../utils/stream.js'; -import type { LangiumDocument } from '../workspace/documents.js'; +import type { LangiumDocument, TextDocument } from '../workspace/documents.js'; import { findNodeForKeyword, findNodesForKeyword, findNodeForProperty, findNodesForProperty } from '../utils/grammar-utils.js'; import { isCompositeCstNode, isLeafCstNode } from '../syntax-tree.js'; import { streamAllContents } from '../utils/ast-utils.js'; diff --git a/packages/langium/src/lsp/hover-provider.ts b/packages/langium/src/lsp/hover-provider.ts index e7a2b6edd..e557d5efb 100644 --- a/packages/langium/src/lsp/hover-provider.ts +++ b/packages/langium/src/lsp/hover-provider.ts @@ -4,10 +4,11 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { CancellationToken, Hover, HoverParams } from 'vscode-languageserver'; +import type { Hover, HoverParams } from 'vscode-languageserver'; +import type { CancellationToken } from '../utils/cancellation.js'; import type { GrammarConfig } from '../languages/grammar-config.js'; import type { References } from '../references/references.js'; -import type { LangiumServices } from '../services.js'; +import type { LangiumServices } from './lsp-services.js'; import type { AstNode } from '../syntax-tree.js'; import type { MaybePromise } from '../utils/promise-utils.js'; import type { LangiumDocument } from '../workspace/documents.js'; diff --git a/packages/langium/src/lsp/implementation-provider.ts b/packages/langium/src/lsp/implementation-provider.ts index 89fd82eb4..442bffdcd 100644 --- a/packages/langium/src/lsp/implementation-provider.ts +++ b/packages/langium/src/lsp/implementation-provider.ts @@ -7,11 +7,11 @@ import type { ImplementationParams, LocationLink } from 'vscode-languageserver'; import type { GrammarConfig } from '../languages/grammar-config.js'; import type { References } from '../references/references.js'; -import type { LangiumServices } from '../services.js'; +import type { LangiumServices } from './lsp-services.js'; import type { AstNode } from '../syntax-tree.js'; import type { MaybePromise } from '../utils/promise-utils.js'; import type { LangiumDocument } from '../workspace/documents.js'; -import { CancellationToken } from 'vscode-languageserver'; +import { CancellationToken } from '../utils/cancellation.js'; import { findDeclarationNodeAtOffset } from '../utils/cst-utils.js'; /** diff --git a/packages/langium/src/lsp/index.ts b/packages/langium/src/lsp/index.ts index ed4ad7f0c..830e39732 100644 --- a/packages/langium/src/lsp/index.ts +++ b/packages/langium/src/lsp/index.ts @@ -11,6 +11,7 @@ export * from './code-action.js'; export * from './code-lens-provider.js'; export * from './declaration-provider.js'; export * from './definition-provider.js'; +export * from './default-lsp-module.js'; export * from './document-highlight-provider.js'; export * from './document-link-provider.js'; export * from './document-symbol-provider.js'; @@ -22,6 +23,7 @@ export * from './hover-provider.js'; export * from './implementation-provider.js'; export * from './inlay-hint-provider.js'; export * from './language-server.js'; +export * from './lsp-services.js'; export * from './node-kind-provider.js'; export * from './references-provider.js'; export * from './rename-provider.js'; diff --git a/packages/langium/src/lsp/inlay-hint-provider.ts b/packages/langium/src/lsp/inlay-hint-provider.ts index 0f6a0be09..9078abbec 100644 --- a/packages/langium/src/lsp/inlay-hint-provider.ts +++ b/packages/langium/src/lsp/inlay-hint-provider.ts @@ -6,7 +6,7 @@ import type { InlayHint, InlayHintParams } from 'vscode-languageserver'; import type { AstNode } from '../syntax-tree.js'; -import { CancellationToken } from 'vscode-languageserver'; +import { CancellationToken } from '../utils/cancellation.js'; import type { MaybePromise } from '../utils/promise-utils.js'; import type { LangiumDocument } from '../workspace/documents.js'; import { streamAst } from '../utils/ast-utils.js'; diff --git a/packages/langium/src/lsp/language-server.ts b/packages/langium/src/lsp/language-server.ts index 9c9e4efdc..6df5f8bfa 100644 --- a/packages/langium/src/lsp/language-server.ts +++ b/packages/langium/src/lsp/language-server.ts @@ -28,16 +28,17 @@ import type { TypeHierarchySubtypesParams, TypeHierarchySupertypesParams } from 'vscode-languageserver'; -import type { LangiumServices, LangiumSharedServices } from '../services.js'; -import type { LangiumDocument } from '../workspace/documents.js'; -import { Emitter, LSPErrorCodes, ResponseError, TextDocumentSyncKind } from 'vscode-languageserver'; +import { DidChangeConfigurationNotification, Emitter, LSPErrorCodes, ResponseError, TextDocumentSyncKind } from 'vscode-languageserver-protocol'; import { eagerLoad } from '../dependency-injection.js'; +import type { LangiumCoreServices } from '../services.js'; import { isOperationCancelled } from '../utils/promise-utils.js'; -import { DocumentState } from '../workspace/documents.js'; +import { URI } from '../utils/uri-utils.js'; +import type { ConfigurationInitializedParams } from '../workspace/configuration.js'; +import { DocumentState, type LangiumDocument } from '../workspace/documents.js'; import { mergeCompletionProviderOptions } from './completion/completion-provider.js'; +import type { LangiumSharedServices, PartialLangiumLSPServices } from './lsp-services.js'; import { DefaultSemanticTokenOptions } from './semantic-token-provider.js'; import { mergeSignatureHelpOptions } from './signature-help-provider.js'; -import { URI } from '../utils/uri-utils.js'; export interface LanguageServer { initialize(params: InitializeParams): Promise @@ -46,6 +47,13 @@ export interface LanguageServer { onInitialized(callback: (params: InitializedParams) => void): Disposable } +/** + * Language-specific core and optional LSP services. + * To be used while accessing the language-specific services via the service registry without a-priori knowledge about the presence of LSP services for the particular languages. + * Shared services should be accessed via the language server's `services` property. + */ +export type LangiumCoreAndPartialLSPServices = Omit + export class DefaultLanguageServer implements LanguageServer { protected onInitializeEmitter = new Emitter(); @@ -67,6 +75,9 @@ export class DefaultLanguageServer implements LanguageServer { async initialize(params: InitializeParams): Promise { this.eagerLoadServices(); + + this.fireInitializeOnDefaultServices(params); + this.onInitializeEmitter.fire(params); this.onInitializeEmitter.dispose(); return this.buildInitializeResult(params); @@ -81,37 +92,38 @@ export class DefaultLanguageServer implements LanguageServer { this.services.ServiceRegistry.all.forEach(language => eagerLoad(language)); } - protected hasService(callback: (language: LangiumServices) => object | undefined): boolean { - return this.services.ServiceRegistry.all.some(language => callback(language) !== undefined); + protected hasService(callback: (language: LangiumCoreAndPartialLSPServices) => object | undefined): boolean { + const allServices: readonly LangiumCoreAndPartialLSPServices[] = this.services.ServiceRegistry.all; + return allServices.some(services => callback(services) !== undefined); } protected buildInitializeResult(_params: InitializeParams): InitializeResult { - const languages = this.services.ServiceRegistry.all; const fileOperationOptions = this.services.lsp.FileOperationHandler?.fileOperationOptions; - const hasFormattingService = this.hasService(e => e.lsp.Formatter); - const formattingOnTypeOptions = languages.map(e => e.lsp.Formatter?.formatOnTypeOptions).find(e => Boolean(e)); - const hasCodeActionProvider = this.hasService(e => e.lsp.CodeActionProvider); - const hasSemanticTokensProvider = this.hasService(e => e.lsp.SemanticTokenProvider); - const commandNames = this.services.lsp.ExecuteCommandHandler?.commands; - const hasDocumentLinkProvider = this.hasService(e => e.lsp.DocumentLinkProvider); - const signatureHelpOptions = mergeSignatureHelpOptions(languages.map(e => e.lsp.SignatureHelp?.signatureHelpOptions)); - const hasGoToTypeProvider = this.hasService(e => e.lsp.TypeProvider); - const hasGoToImplementationProvider = this.hasService(e => e.lsp.ImplementationProvider); - const hasCompletionProvider = this.hasService(e => e.lsp.CompletionProvider); - const completionOptions = mergeCompletionProviderOptions(languages.map(e => e.lsp.CompletionProvider?.completionOptions)); - const hasReferencesProvider = this.hasService(e => e.lsp.ReferencesProvider); - const hasDocumentSymbolProvider = this.hasService(e => e.lsp.DocumentSymbolProvider); - const hasDefinitionProvider = this.hasService(e => e.lsp.DefinitionProvider); - const hasDocumentHighlightProvider = this.hasService(e => e.lsp.DocumentHighlightProvider); - const hasFoldingRangeProvider = this.hasService(e => e.lsp.FoldingRangeProvider); - const hasHoverProvider = this.hasService(e => e.lsp.HoverProvider); - const hasRenameProvider = this.hasService(e => e.lsp.RenameProvider); - const hasCallHierarchyProvider = this.hasService(e => e.lsp.CallHierarchyProvider); - const hasTypeHierarchyProvider = this.hasService((e) => e.lsp.TypeHierarchyProvider); - const hasCodeLensProvider = this.hasService(e => e.lsp.CodeLensProvider); - const hasDeclarationProvider = this.hasService(e => e.lsp.DeclarationProvider); - const hasInlayHintProvider = this.hasService(e => e.lsp.InlayHintProvider); - const workspaceSymbolProvider = this.services.lsp.WorkspaceSymbolProvider; + const allServices: readonly LangiumCoreAndPartialLSPServices[] = this.services.ServiceRegistry.all; + const hasFormattingService = this.hasService(e => e.lsp?.Formatter); + const formattingOnTypeOptions = allServices.map(e => e.lsp?.Formatter?.formatOnTypeOptions).find(e => Boolean(e)); + const hasCodeActionProvider = this.hasService(e => e.lsp?.CodeActionProvider); + const hasSemanticTokensProvider = this.hasService(e => e.lsp?.SemanticTokenProvider); + const commandNames = this.services.lsp?.ExecuteCommandHandler?.commands; + const hasDocumentLinkProvider = this.hasService(e => e.lsp?.DocumentLinkProvider); + const signatureHelpOptions = mergeSignatureHelpOptions(allServices.map(e => e.lsp?.SignatureHelp?.signatureHelpOptions)); + const hasGoToTypeProvider = this.hasService(e => e.lsp?.TypeProvider); + const hasGoToImplementationProvider = this.hasService(e => e.lsp?.ImplementationProvider); + const hasCompletionProvider = this.hasService(e => e.lsp?.CompletionProvider); + const completionOptions = mergeCompletionProviderOptions(allServices.map(e => e.lsp?.CompletionProvider?.completionOptions)); + const hasReferencesProvider = this.hasService(e => e.lsp?.ReferencesProvider); + const hasDocumentSymbolProvider = this.hasService(e => e.lsp?.DocumentSymbolProvider); + const hasDefinitionProvider = this.hasService(e => e.lsp?.DefinitionProvider); + const hasDocumentHighlightProvider = this.hasService(e => e.lsp?.DocumentHighlightProvider); + const hasFoldingRangeProvider = this.hasService(e => e.lsp?.FoldingRangeProvider); + const hasHoverProvider = this.hasService(e => e.lsp?.HoverProvider); + const hasRenameProvider = this.hasService(e => e.lsp?.RenameProvider); + const hasCallHierarchyProvider = this.hasService(e => e.lsp?.CallHierarchyProvider); + const hasTypeHierarchyProvider = this.hasService((e) => e.lsp?.TypeHierarchyProvider); + const hasCodeLensProvider = this.hasService(e => e.lsp?.CodeLensProvider); + const hasDeclarationProvider = this.hasService(e => e.lsp?.DeclarationProvider); + const hasInlayHintProvider = this.hasService(e => e.lsp?.InlayHintProvider); + const workspaceSymbolProvider = this.services.lsp?.WorkspaceSymbolProvider; const result: InitializeResult = { capabilities: { @@ -171,9 +183,28 @@ export class DefaultLanguageServer implements LanguageServer { } async initialized(params: InitializedParams): Promise { + await this.fireInitializedOnDefaultServices(params); + this.onInitializedEmitter.fire(params); this.onInitializedEmitter.dispose(); } + + protected fireInitializeOnDefaultServices(params: InitializeParams): void { + this.services.workspace.ConfigurationProvider.initialize(params); + this.services.workspace.WorkspaceManager.initialize(params); + } + + protected async fireInitializedOnDefaultServices(params: InitializedParams): Promise { + const connection = this.services.lsp.Connection; + const configurationParams = connection ? { + ...params, + register: params => connection.client.register(DidChangeConfigurationNotification.type, params), + getConfiguration: params => connection.workspace.getConfiguration(params) + } : params; + + await this.services.workspace.ConfigurationProvider.initialized(configurationParams); + await this.services.workspace.WorkspaceManager.initialized(params); + } } export function startLanguageServer(services: LangiumSharedServices): void { @@ -224,6 +255,10 @@ export function startLanguageServer(services: LangiumSharedServices): void { connection.listen(); } +/** + * Adds a handler for document updates when content changes, or watch catches a change. + * In the case there is no handler service registered, this function does nothing. + */ export function addDocumentUpdateHandler(connection: Connection, services: LangiumSharedServices): void { const handler = services.lsp.DocumentUpdateHandler; const documents = services.workspace.TextDocuments; @@ -276,7 +311,7 @@ export function addDiagnosticsHandler(connection: Connection, services: LangiumS export function addCompletionHandler(connection: Connection, services: LangiumSharedServices): void { connection.onCompletion(createRequestHandler( (services, document, params, cancelToken) => { - return services.lsp.CompletionProvider?.getCompletion(document, params, cancelToken); + return services.lsp?.CompletionProvider?.getCompletion(document, params, cancelToken); }, services )); @@ -284,103 +319,103 @@ export function addCompletionHandler(connection: Connection, services: LangiumSh export function addFindReferencesHandler(connection: Connection, services: LangiumSharedServices): void { connection.onReferences(createRequestHandler( - (services, document, params, cancelToken) => services.lsp.ReferencesProvider?.findReferences(document, params, cancelToken), + (services, document, params, cancelToken) => services.lsp?.ReferencesProvider?.findReferences(document, params, cancelToken), services )); } export function addCodeActionHandler(connection: Connection, services: LangiumSharedServices): void { connection.onCodeAction(createRequestHandler( - (services, document, params, cancelToken) => services.lsp.CodeActionProvider?.getCodeActions(document, params, cancelToken), + (services, document, params, cancelToken) => services.lsp?.CodeActionProvider?.getCodeActions(document, params, cancelToken), services )); } export function addDocumentSymbolHandler(connection: Connection, services: LangiumSharedServices): void { connection.onDocumentSymbol(createRequestHandler( - (services, document, params, cancelToken) => services.lsp.DocumentSymbolProvider?.getSymbols(document, params, cancelToken), + (services, document, params, cancelToken) => services.lsp?.DocumentSymbolProvider?.getSymbols(document, params, cancelToken), services )); } export function addGotoDefinitionHandler(connection: Connection, services: LangiumSharedServices): void { connection.onDefinition(createRequestHandler( - (services, document, params, cancelToken) => services.lsp.DefinitionProvider?.getDefinition(document, params, cancelToken), + (services, document, params, cancelToken) => services.lsp?.DefinitionProvider?.getDefinition(document, params, cancelToken), services )); } export function addGoToTypeDefinitionHandler(connection: Connection, services: LangiumSharedServices): void { connection.onTypeDefinition(createRequestHandler( - (services, document, params, cancelToken) => services.lsp.TypeProvider?.getTypeDefinition(document, params, cancelToken), + (services, document, params, cancelToken) => services.lsp?.TypeProvider?.getTypeDefinition(document, params, cancelToken), services )); } export function addGoToImplementationHandler(connection: Connection, services: LangiumSharedServices) { connection.onImplementation(createRequestHandler( - (services, document, params, cancelToken) => services.lsp.ImplementationProvider?.getImplementation(document, params, cancelToken), + (services, document, params, cancelToken) => services.lsp?.ImplementationProvider?.getImplementation(document, params, cancelToken), services )); } export function addGoToDeclarationHandler(connection: Connection, services: LangiumSharedServices) { connection.onDeclaration(createRequestHandler( - (services, document, params, cancelToken) => services.lsp.DeclarationProvider?.getDeclaration(document, params, cancelToken), + (services, document, params, cancelToken) => services.lsp?.DeclarationProvider?.getDeclaration(document, params, cancelToken), services )); } export function addDocumentHighlightsHandler(connection: Connection, services: LangiumSharedServices): void { connection.onDocumentHighlight(createRequestHandler( - (services, document, params, cancelToken) => services.lsp.DocumentHighlightProvider?.getDocumentHighlight(document, params, cancelToken), + (services, document, params, cancelToken) => services.lsp?.DocumentHighlightProvider?.getDocumentHighlight(document, params, cancelToken), services )); } export function addHoverHandler(connection: Connection, services: LangiumSharedServices): void { connection.onHover(createRequestHandler( - (services, document, params, cancelToken) => services.lsp.HoverProvider?.getHoverContent(document, params, cancelToken), + (services, document, params, cancelToken) => services.lsp?.HoverProvider?.getHoverContent(document, params, cancelToken), services )); } export function addFoldingRangeHandler(connection: Connection, services: LangiumSharedServices): void { connection.onFoldingRanges(createRequestHandler( - (services, document, params, cancelToken) => services.lsp.FoldingRangeProvider?.getFoldingRanges(document, params, cancelToken), + (services, document, params, cancelToken) => services.lsp?.FoldingRangeProvider?.getFoldingRanges(document, params, cancelToken), services )); } export function addFormattingHandler(connection: Connection, services: LangiumSharedServices): void { connection.onDocumentFormatting(createRequestHandler( - (services, document, params, cancelToken) => services.lsp.Formatter?.formatDocument(document, params, cancelToken), + (services, document, params, cancelToken) => services.lsp?.Formatter?.formatDocument(document, params, cancelToken), services )); connection.onDocumentRangeFormatting(createRequestHandler( - (services, document, params, cancelToken) => services.lsp.Formatter?.formatDocumentRange(document, params, cancelToken), + (services, document, params, cancelToken) => services.lsp?.Formatter?.formatDocumentRange(document, params, cancelToken), services )); connection.onDocumentOnTypeFormatting(createRequestHandler( - (services, document, params, cancelToken) => services.lsp.Formatter?.formatDocumentOnType(document, params, cancelToken), + (services, document, params, cancelToken) => services.lsp?.Formatter?.formatDocumentOnType(document, params, cancelToken), services )); } export function addRenameHandler(connection: Connection, services: LangiumSharedServices): void { connection.onRenameRequest(createRequestHandler( - (services, document, params, cancelToken) => services.lsp.RenameProvider?.rename(document, params, cancelToken), + (services, document, params, cancelToken) => services.lsp?.RenameProvider?.rename(document, params, cancelToken), services )); connection.onPrepareRename(createRequestHandler( - (services, document, params, cancelToken) => services.lsp.RenameProvider?.prepareRename(document, params, cancelToken), + (services, document, params, cancelToken) => services.lsp?.RenameProvider?.prepareRename(document, params, cancelToken), services )); } export function addInlayHintHandler(connection: Connection, services: LangiumSharedServices): void { connection.languages.inlayHint.on(createServerRequestHandler( - (services, document, params, cancelToken) => services.lsp.InlayHintProvider?.getInlayHints(document, params, cancelToken), + (services, document, params, cancelToken) => services.lsp?.InlayHintProvider?.getInlayHints(document, params, cancelToken), services )); } @@ -390,7 +425,7 @@ export function addSemanticTokenHandler(connection: Connection, services: Langiu const emptyResult: SemanticTokens = { data: [] }; connection.languages.semanticTokens.on(createServerRequestHandler( (services, document, params, cancelToken) => { - if (services.lsp.SemanticTokenProvider) { + if (services.lsp?.SemanticTokenProvider) { return services.lsp.SemanticTokenProvider.semanticHighlight(document, params, cancelToken); } return emptyResult; @@ -399,7 +434,7 @@ export function addSemanticTokenHandler(connection: Connection, services: Langiu )); connection.languages.semanticTokens.onDelta(createServerRequestHandler( (services, document, params, cancelToken) => { - if (services.lsp.SemanticTokenProvider) { + if (services.lsp?.SemanticTokenProvider) { return services.lsp.SemanticTokenProvider.semanticHighlightDelta(document, params, cancelToken); } return emptyResult; @@ -408,7 +443,7 @@ export function addSemanticTokenHandler(connection: Connection, services: Langiu )); connection.languages.semanticTokens.onRange(createServerRequestHandler( (services, document, params, cancelToken) => { - if (services.lsp.SemanticTokenProvider) { + if (services.lsp?.SemanticTokenProvider) { return services.lsp.SemanticTokenProvider.semanticHighlightRange(document, params, cancelToken); } return emptyResult; @@ -439,21 +474,21 @@ export function addExecuteCommandHandler(connection: Connection, services: Langi export function addDocumentLinkHandler(connection: Connection, services: LangiumSharedServices): void { connection.onDocumentLinks(createServerRequestHandler( - (services, document, params, cancelToken) => services.lsp.DocumentLinkProvider?.getDocumentLinks(document, params, cancelToken), + (services, document, params, cancelToken) => services.lsp?.DocumentLinkProvider?.getDocumentLinks(document, params, cancelToken), services )); } export function addSignatureHelpHandler(connection: Connection, services: LangiumSharedServices): void { connection.onSignatureHelp(createServerRequestHandler( - (services, document, params, cancelToken) => services.lsp.SignatureHelp?.provideSignatureHelp(document, params, cancelToken), + (services, document, params, cancelToken) => services.lsp?.SignatureHelp?.provideSignatureHelp(document, params, cancelToken), services )); } export function addCodeLensHandler(connection: Connection, services: LangiumSharedServices): void { connection.onCodeLens(createServerRequestHandler( - (services, document, params, cancelToken) => services.lsp.CodeLensProvider?.provideCodeLens(document, params, cancelToken), + (services, document, params, cancelToken) => services.lsp?.CodeLensProvider?.provideCodeLens(document, params, cancelToken), services )); } @@ -484,7 +519,7 @@ export function addWorkspaceSymbolHandler(connection: Connection, services: Lang export function addCallHierarchyHandler(connection: Connection, services: LangiumSharedServices): void { connection.languages.callHierarchy.onPrepare(createServerRequestHandler( async (services, document, params, cancelToken) => { - if (services.lsp.CallHierarchyProvider) { + if (services.lsp?.CallHierarchyProvider) { const result = await services.lsp.CallHierarchyProvider.prepareCallHierarchy(document, params, cancelToken); return result ?? null; } @@ -495,7 +530,7 @@ export function addCallHierarchyHandler(connection: Connection, services: Langiu connection.languages.callHierarchy.onIncomingCalls(createHierarchyRequestHandler( async (services, params, cancelToken) => { - if (services.lsp.CallHierarchyProvider) { + if (services.lsp?.CallHierarchyProvider) { const result = await services.lsp.CallHierarchyProvider.incomingCalls(params, cancelToken); return result ?? null; } @@ -506,7 +541,7 @@ export function addCallHierarchyHandler(connection: Connection, services: Langiu connection.languages.callHierarchy.onOutgoingCalls(createHierarchyRequestHandler( async (services, params, cancelToken) => { - if (services.lsp.CallHierarchyProvider) { + if (services.lsp?.CallHierarchyProvider) { const result = await services.lsp.CallHierarchyProvider.outgoingCalls(params, cancelToken); return result ?? null; } @@ -518,34 +553,34 @@ export function addCallHierarchyHandler(connection: Connection, services: Langiu export function addTypeHierarchyHandler(connection: Connection, sharedServices: LangiumSharedServices): void { // Don't register type hierarchy handlers if no type hierarchy provider is registered - if (!sharedServices.ServiceRegistry.all.some(services => services.lsp.TypeHierarchyProvider)) { + if (!sharedServices.ServiceRegistry.all.some((services: LangiumCoreAndPartialLSPServices) => services.lsp?.TypeHierarchyProvider)) { return; } connection.languages.typeHierarchy.onPrepare( createServerRequestHandler(async (services, document, params, cancelToken) => { - const result = await services.lsp.TypeHierarchyProvider?.prepareTypeHierarchy(document, params, cancelToken); + const result = await services.lsp?.TypeHierarchyProvider?.prepareTypeHierarchy(document, params, cancelToken); return result ?? null; }, sharedServices), ); connection.languages.typeHierarchy.onSupertypes( createHierarchyRequestHandler(async (services, params, cancelToken) => { - const result = await services.lsp.TypeHierarchyProvider?.supertypes(params, cancelToken); + const result = await services.lsp?.TypeHierarchyProvider?.supertypes(params, cancelToken); return result ?? null; }, sharedServices), ); connection.languages.typeHierarchy.onSubtypes( createHierarchyRequestHandler(async (services, params, cancelToken) => { - const result = await services.lsp.TypeHierarchyProvider?.subtypes(params, cancelToken); + const result = await services.lsp?.TypeHierarchyProvider?.subtypes(params, cancelToken); return result ?? null; }, sharedServices), ); } export function createHierarchyRequestHandler

( - serviceCall: (services: LangiumServices, params: P, cancelToken: CancellationToken) => HandlerResult, + serviceCall: (services: LangiumCoreAndPartialLSPServices, params: P, cancelToken: CancellationToken) => HandlerResult, sharedServices: LangiumSharedServices, ): ServerRequestHandler { const serviceRegistry = sharedServices.ServiceRegistry; @@ -566,7 +601,7 @@ export function createHierarchyRequestHandler

( - serviceCall: (services: LangiumServices, document: LangiumDocument, params: P, cancelToken: CancellationToken) => HandlerResult, + serviceCall: (services: LangiumCoreAndPartialLSPServices, document: LangiumDocument, params: P, cancelToken: CancellationToken) => HandlerResult, sharedServices: LangiumSharedServices ): ServerRequestHandler { const documents = sharedServices.workspace.LangiumDocuments; @@ -589,7 +624,7 @@ export function createServerRequestHandler

( - serviceCall: (services: LangiumServices, document: LangiumDocument, params: P, cancelToken: CancellationToken) => HandlerResult, + serviceCall: (services: LangiumCoreAndPartialLSPServices, document: LangiumDocument, params: P, cancelToken: CancellationToken) => HandlerResult, sharedServices: LangiumSharedServices ): RequestHandler { const documents = sharedServices.workspace.LangiumDocuments; diff --git a/packages/langium/src/lsp/lsp-services.ts b/packages/langium/src/lsp/lsp-services.ts new file mode 100644 index 000000000..21b32f9a7 --- /dev/null +++ b/packages/langium/src/lsp/lsp-services.ts @@ -0,0 +1,114 @@ +/****************************************************************************** + * Copyright 2023 TypeFox GmbH + * This program and the accompanying materials are made available under the + * terms of the MIT License, which is available in the project root. + ******************************************************************************/ + +import type { Connection, TextDocuments } from 'vscode-languageserver'; +import type { DeepPartial, LangiumCoreServices, LangiumSharedCoreServices } from '../services.js'; +import type { TextDocument } from '../workspace/documents.js'; +import type { CallHierarchyProvider } from './call-hierarchy-provider.js'; +import type { CodeActionProvider } from './code-action.js'; +import type { CodeLensProvider } from './code-lens-provider.js'; +import type { CompletionProvider } from './completion/completion-provider.js'; +import type { DeclarationProvider } from './declaration-provider.js'; +import type { DefinitionProvider } from './definition-provider.js'; +import type { DocumentHighlightProvider } from './document-highlight-provider.js'; +import type { DocumentLinkProvider } from './document-link-provider.js'; +import type { DocumentSymbolProvider } from './document-symbol-provider.js'; +import type { DocumentUpdateHandler } from './document-update-handler.js'; +import type { ExecuteCommandHandler } from './execute-command-handler.js'; +import type { FileOperationHandler } from './file-operation-handler.js'; +import type { FoldingRangeProvider } from './folding-range-provider.js'; +import type { Formatter } from './formatter.js'; +import type { FuzzyMatcher } from './fuzzy-matcher.js'; +import type { HoverProvider } from './hover-provider.js'; +import type { ImplementationProvider } from './implementation-provider.js'; +import type { InlayHintProvider } from './inlay-hint-provider.js'; +import type { LanguageServer } from './language-server.js'; +import type { NodeKindProvider } from './node-kind-provider.js'; +import type { ReferencesProvider } from './references-provider.js'; +import type { RenameProvider } from './rename-provider.js'; +import type { SemanticTokenProvider } from './semantic-token-provider.js'; +import type { SignatureHelpProvider } from './signature-help-provider.js'; +import type { TypeHierarchyProvider } from './type-hierarchy-provider.js'; +import type { TypeDefinitionProvider } from './type-provider.js'; +import type { WorkspaceSymbolProvider } from './workspace-symbol-provider.js'; + +/** + * Combined Core + LSP services of Langium (total services) + */ +export type LangiumServices = LangiumCoreServices & LangiumLSPServices; + +/** + * Combined Core + LSP shared services of Langium (total services) + */ +export type LangiumSharedServices = LangiumSharedCoreServices & LangiumSharedLSPServices; + +/** + * LSP services for a specific language of which Langium provides default implementations. + */ +export type LangiumLSPServices = { + lsp: { + CompletionProvider?: CompletionProvider + DocumentHighlightProvider?: DocumentHighlightProvider + DocumentSymbolProvider?: DocumentSymbolProvider + HoverProvider?: HoverProvider + FoldingRangeProvider?: FoldingRangeProvider + DefinitionProvider?: DefinitionProvider + TypeProvider?: TypeDefinitionProvider + ImplementationProvider?: ImplementationProvider + ReferencesProvider?: ReferencesProvider + CodeActionProvider?: CodeActionProvider + SemanticTokenProvider?: SemanticTokenProvider + RenameProvider?: RenameProvider + Formatter?: Formatter + SignatureHelp?: SignatureHelpProvider + CallHierarchyProvider?: CallHierarchyProvider + TypeHierarchyProvider?: TypeHierarchyProvider + DeclarationProvider?: DeclarationProvider + InlayHintProvider?: InlayHintProvider + CodeLensProvider?: CodeLensProvider + DocumentLinkProvider?: DocumentLinkProvider + }, + shared: LangiumSharedServices +}; + +/** + * LSP services shared between multiple languages of which Langium provides default implementations. + */ +export type LangiumSharedLSPServices = { + lsp: { + Connection?: Connection + DocumentUpdateHandler: DocumentUpdateHandler + ExecuteCommandHandler?: ExecuteCommandHandler + FileOperationHandler?: FileOperationHandler + FuzzyMatcher: FuzzyMatcher + LanguageServer: LanguageServer + NodeKindProvider: NodeKindProvider + WorkspaceSymbolProvider?: WorkspaceSymbolProvider + }, + workspace: { + TextDocuments: TextDocuments + } +}; + +/** + * Language-specific LSP services to be partially overridden via dependency injection. + */ +export type PartialLangiumLSPServices = DeepPartial + +/** + * Language-specific services to be partially overridden via dependency injection. + */ +export type PartialLangiumServices = DeepPartial + +/** + * Shared LSP services to be partially overridden via dependency injection. + */ +export type PartialLangiumSharedLSPServices = DeepPartial + +/** + * Shared services to be partially overridden via dependency injection. + */ +export type PartialLangiumSharedServices = DeepPartial diff --git a/packages/langium/src/lsp/references-provider.ts b/packages/langium/src/lsp/references-provider.ts index f23d1cbbb..0e4ca3eef 100644 --- a/packages/langium/src/lsp/references-provider.ts +++ b/packages/langium/src/lsp/references-provider.ts @@ -4,11 +4,12 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { CancellationToken, ReferenceParams } from 'vscode-languageserver'; +import type { ReferenceParams } from 'vscode-languageserver'; +import type { CancellationToken } from '../utils/cancellation.js'; import type { NameProvider } from '../references/name-provider.js'; import type { References } from '../references/references.js'; import type { LeafCstNode } from '../syntax-tree.js'; -import type { LangiumServices } from '../services.js'; +import type { LangiumServices } from './lsp-services.js'; import type { MaybePromise } from '../utils/promise-utils.js'; import type { LangiumDocument } from '../workspace/documents.js'; import type { GrammarConfig } from '../languages/grammar-config.js'; diff --git a/packages/langium/src/lsp/rename-provider.ts b/packages/langium/src/lsp/rename-provider.ts index 848989744..1bb9b3f4e 100644 --- a/packages/langium/src/lsp/rename-provider.ts +++ b/packages/langium/src/lsp/rename-provider.ts @@ -4,15 +4,16 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { CancellationToken, Position, Range, RenameParams, TextDocumentPositionParams, WorkspaceEdit } from 'vscode-languageserver'; +import type { Position, Range, RenameParams, TextDocumentPositionParams, WorkspaceEdit } from 'vscode-languageserver-protocol'; +import type { CancellationToken } from '../utils/cancellation.js'; import type { GrammarConfig } from '../languages/grammar-config.js'; import type { NameProvider } from '../references/name-provider.js'; import type { References } from '../references/references.js'; -import type { LangiumServices } from '../services.js'; +import type { LangiumServices } from './lsp-services.js'; import type { CstNode } from '../syntax-tree.js'; import type { MaybePromise } from '../utils/promise-utils.js'; import type { LangiumDocument } from '../workspace/documents.js'; -import { TextEdit } from 'vscode-languageserver'; +import { TextEdit } from 'vscode-languageserver-types'; import { isNamed } from '../references/name-provider.js'; import { findDeclarationNodeAtOffset } from '../utils/cst-utils.js'; diff --git a/packages/langium/src/lsp/semantic-token-provider.ts b/packages/langium/src/lsp/semantic-token-provider.ts index f00afa963..cada94f27 100644 --- a/packages/langium/src/lsp/semantic-token-provider.ts +++ b/packages/langium/src/lsp/semantic-token-provider.ts @@ -7,15 +7,16 @@ /* eslint-disable no-bitwise */ import type { Range, SemanticTokens, SemanticTokensClientCapabilities, SemanticTokensDelta, SemanticTokensDeltaParams, SemanticTokensOptions, SemanticTokensParams, SemanticTokensRangeParams } from 'vscode-languageserver'; -import type { LangiumServices } from '../services.js'; +import { SemanticTokensBuilder as BaseSemanticTokensBuilder, SemanticTokenModifiers, SemanticTokenTypes } from 'vscode-languageserver'; +import { CancellationToken } from '../utils/cancellation.js'; import type { AstNode, CstNode, Properties } from '../syntax-tree.js'; -import type { LangiumDocument } from '../workspace/documents.js'; -import type { MaybePromise } from '../utils/promise-utils.js'; -import { CancellationToken, SemanticTokenModifiers, SemanticTokensBuilder as BaseSemanticTokensBuilder, SemanticTokenTypes } from 'vscode-languageserver'; -import { findNodesForKeyword, findNodeForProperty, findNodesForProperty, findNodeForKeyword } from '../utils/grammar-utils.js'; import { streamAst } from '../utils/ast-utils.js'; -import { interruptAndCheck } from '../utils/promise-utils.js'; import { inRange } from '../utils/cst-utils.js'; +import { findNodeForKeyword, findNodeForProperty, findNodesForKeyword, findNodesForProperty } from '../utils/grammar-utils.js'; +import type { MaybePromise } from '../utils/promise-utils.js'; +import { interruptAndCheck } from '../utils/promise-utils.js'; +import type { LangiumDocument } from '../workspace/documents.js'; +import type { LangiumServices } from './lsp-services.js'; export const AllSemanticTokenTypes: Record = { [SemanticTokenTypes.class]: 0, diff --git a/packages/langium/src/lsp/signature-help-provider.ts b/packages/langium/src/lsp/signature-help-provider.ts index 37ac7ce43..6eca706f7 100644 --- a/packages/langium/src/lsp/signature-help-provider.ts +++ b/packages/langium/src/lsp/signature-help-provider.ts @@ -5,7 +5,7 @@ ******************************************************************************/ import type { SignatureHelp, SignatureHelpOptions, SignatureHelpParams } from 'vscode-languageserver'; -import { CancellationToken } from 'vscode-languageserver'; +import { CancellationToken } from '../utils/cancellation.js'; import type { AstNode } from '../syntax-tree.js'; import { findLeafNodeAtOffset } from '../utils/cst-utils.js'; import type { MaybePromise } from '../utils/promise-utils.js'; diff --git a/packages/langium/src/lsp/type-hierarchy-provider.ts b/packages/langium/src/lsp/type-hierarchy-provider.ts index 431210e07..a9eec8308 100644 --- a/packages/langium/src/lsp/type-hierarchy-provider.ts +++ b/packages/langium/src/lsp/type-hierarchy-provider.ts @@ -15,7 +15,7 @@ import { SymbolKind } from 'vscode-languageserver'; import type { GrammarConfig } from '../languages/grammar-config.js'; import type { NameProvider } from '../references/name-provider.js'; import type { References } from '../references/references.js'; -import type { LangiumServices } from '../services.js'; +import type { LangiumServices } from './lsp-services.js'; import type { AstNode } from '../syntax-tree.js'; import { findDeclarationNodeAtOffset } from '../utils/cst-utils.js'; import { URI } from '../utils/uri-utils.js'; diff --git a/packages/langium/src/lsp/type-provider.ts b/packages/langium/src/lsp/type-provider.ts index 08a543e2b..19b72a42d 100644 --- a/packages/langium/src/lsp/type-provider.ts +++ b/packages/langium/src/lsp/type-provider.ts @@ -6,11 +6,11 @@ import type { LocationLink, TypeDefinitionParams } from 'vscode-languageserver'; import type { References } from '../references/references.js'; -import type { LangiumServices } from '../services.js'; +import type { LangiumServices } from './lsp-services.js'; import type { AstNode } from '../syntax-tree.js'; import type { MaybePromise } from '../utils/promise-utils.js'; import type { LangiumDocument } from '../workspace/documents.js'; -import { CancellationToken } from 'vscode-languageserver'; +import { CancellationToken } from '../utils/cancellation.js'; import { findDeclarationNodeAtOffset } from '../utils/cst-utils.js'; /** diff --git a/packages/langium/src/lsp/workspace-symbol-provider.ts b/packages/langium/src/lsp/workspace-symbol-provider.ts index 1a6d50ed0..742c65c04 100644 --- a/packages/langium/src/lsp/workspace-symbol-provider.ts +++ b/packages/langium/src/lsp/workspace-symbol-provider.ts @@ -5,13 +5,13 @@ ******************************************************************************/ import type { WorkspaceSymbol, WorkspaceSymbolParams } from 'vscode-languageserver'; -import type { LangiumSharedServices } from '../services.js'; +import type { LangiumSharedServices } from './lsp-services.js'; import type { IndexManager } from '../workspace/index-manager.js'; import type { MaybePromise} from '../utils/promise-utils.js'; import type { AstNodeDescription } from '../syntax-tree.js'; import type { NodeKindProvider } from './node-kind-provider.js'; import type { FuzzyMatcher } from './fuzzy-matcher.js'; -import { CancellationToken } from 'vscode-languageserver'; +import { CancellationToken } from '../utils/cancellation.js'; import { interruptAndCheck } from '../utils/promise-utils.js'; /** diff --git a/packages/langium/src/parser/async-parser.ts b/packages/langium/src/parser/async-parser.ts index 92da927fe..31b445f27 100644 --- a/packages/langium/src/parser/async-parser.ts +++ b/packages/langium/src/parser/async-parser.ts @@ -4,10 +4,10 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { CancellationToken } from 'vscode-languageserver'; -import type { LangiumParser, ParseResult } from './langium-parser.js'; -import type { LangiumServices } from '../services.js'; +import type { CancellationToken } from '../utils/cancellation.js'; +import type { LangiumCoreServices } from '../services.js'; import type { AstNode } from '../syntax-tree.js'; +import type { LangiumParser, ParseResult } from './langium-parser.js'; /** * Async parser that allows to cancel the current parsing process. @@ -29,7 +29,7 @@ export class DefaultAsyncParser implements AsyncParser { protected readonly syncParser: LangiumParser; - constructor(services: LangiumServices) { + constructor(services: LangiumCoreServices) { this.syncParser = services.parser.LangiumParser; } diff --git a/packages/langium/src/parser/completion-parser-builder.ts b/packages/langium/src/parser/completion-parser-builder.ts index 50de29d69..9c9230ec5 100644 --- a/packages/langium/src/parser/completion-parser-builder.ts +++ b/packages/langium/src/parser/completion-parser-builder.ts @@ -4,11 +4,11 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { LangiumServices } from '../services.js'; +import type { LangiumCoreServices } from '../services.js'; import { LangiumCompletionParser } from './langium-parser.js'; import { createParser } from './parser-builder-base.js'; -export function createCompletionParser(services: LangiumServices): LangiumCompletionParser { +export function createCompletionParser(services: LangiumCoreServices): LangiumCompletionParser { const grammar = services.Grammar; const lexer = services.parser.Lexer; const parser = new LangiumCompletionParser(services); diff --git a/packages/langium/src/parser/langium-parser-builder.ts b/packages/langium/src/parser/langium-parser-builder.ts index 60ed2ec7d..b370acd67 100644 --- a/packages/langium/src/parser/langium-parser-builder.ts +++ b/packages/langium/src/parser/langium-parser-builder.ts @@ -4,7 +4,7 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { LangiumServices } from '../services.js'; +import type { LangiumCoreServices } from '../services.js'; import { LangiumParser } from './langium-parser.js'; import { createParser } from './parser-builder-base.js'; @@ -12,7 +12,7 @@ import { createParser } from './parser-builder-base.js'; * Create and finalize a Langium parser. The parser rules are derived from the grammar, which is * available at `services.Grammar`. */ -export function createLangiumParser(services: LangiumServices): LangiumParser { +export function createLangiumParser(services: LangiumCoreServices): LangiumParser { const parser = prepareLangiumParser(services); parser.finalize(); return parser; @@ -22,7 +22,7 @@ export function createLangiumParser(services: LangiumServices): LangiumParser { * Create a Langium parser without finalizing it. This is used to extract more detailed error * information when the parser is initially validated. */ -export function prepareLangiumParser(services: LangiumServices): LangiumParser { +export function prepareLangiumParser(services: LangiumCoreServices): LangiumParser { const grammar = services.Grammar; const lexer = services.parser.Lexer; const parser = new LangiumParser(services); diff --git a/packages/langium/src/parser/langium-parser.ts b/packages/langium/src/parser/langium-parser.ts index 9ddc7557c..308950242 100644 --- a/packages/langium/src/parser/langium-parser.ts +++ b/packages/langium/src/parser/langium-parser.ts @@ -8,7 +8,7 @@ import type { DSLMethodOpts, ILexingError, IOrAlt, IParserErrorMessageProvider, IRecognitionException, IToken, TokenType, TokenVocabulary } from 'chevrotain'; import type { AbstractElement, Action, Assignment, ParserRule } from '../languages/generated/ast.js'; import type { Linker } from '../references/linker.js'; -import type { LangiumServices } from '../services.js'; +import type { LangiumCoreServices } from '../services.js'; import type { AstNode, AstReflection, CompositeCstNode, CstNode } from '../syntax-tree.js'; import type { Lexer } from './lexer.js'; import type { IParserConfig } from './parser-config.js'; @@ -75,7 +75,7 @@ export abstract class AbstractLangiumParser implements BaseParser { protected readonly wrapper: ChevrotainWrapper; protected _unorderedGroups: Map = new Map(); - constructor(services: LangiumServices) { + constructor(services: LangiumCoreServices) { this.lexer = services.parser.Lexer; const tokens = this.lexer.definition; this.wrapper = new ChevrotainWrapper(tokens, { @@ -136,7 +136,7 @@ export class LangiumParser extends AbstractLangiumParser { return this.stack[this.stack.length - 1]; } - constructor(services: LangiumServices) { + constructor(services: LangiumCoreServices) { super(services); this.linker = services.references.Linker; this.converter = services.parser.ValueConverter; diff --git a/packages/langium/src/parser/lexer.ts b/packages/langium/src/parser/lexer.ts index 538511278..eec23ea12 100644 --- a/packages/langium/src/parser/lexer.ts +++ b/packages/langium/src/parser/lexer.ts @@ -5,7 +5,7 @@ ******************************************************************************/ import type { ILexingError, IMultiModeLexerDefinition, IToken, TokenType, TokenTypeDictionary, TokenVocabulary } from 'chevrotain'; -import type { LangiumServices } from '../services.js'; +import type { LangiumCoreServices } from '../services.js'; import { Lexer as ChevrotainLexer } from 'chevrotain'; export interface LexerResult { @@ -33,7 +33,7 @@ export class DefaultLexer implements Lexer { protected chevrotainLexer: ChevrotainLexer; protected tokenTypes: TokenTypeDictionary; - constructor(services: LangiumServices) { + constructor(services: LangiumCoreServices) { const tokens = services.parser.TokenBuilder.buildTokens(services.Grammar, { caseInsensitive: services.LanguageMetaData.caseInsensitive }); diff --git a/packages/langium/src/references/linker.ts b/packages/langium/src/references/linker.ts index d7995d4ad..8e0cb803f 100644 --- a/packages/langium/src/references/linker.ts +++ b/packages/langium/src/references/linker.ts @@ -4,12 +4,12 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { LangiumServices } from '../services.js'; +import type { LangiumCoreServices } from '../services.js'; import type { AstNode, AstNodeDescription, AstReflection, CstNode, LinkingError, Reference, ReferenceInfo } from '../syntax-tree.js'; import type { AstNodeLocator } from '../workspace/ast-node-locator.js'; import type { LangiumDocument, LangiumDocuments } from '../workspace/documents.js'; import type { ScopeProvider } from './scope-provider.js'; -import { CancellationToken } from 'vscode-languageserver'; +import { CancellationToken } from '../utils/cancellation.js'; import { isAstNode, isAstNodeDescription, isLinkingError } from '../syntax-tree.js'; import { getDocument, streamAst, streamReferences } from '../utils/ast-utils.js'; import { interruptAndCheck } from '../utils/promise-utils.js'; @@ -78,7 +78,7 @@ export class DefaultLinker implements Linker { protected readonly astNodeLocator: AstNodeLocator; protected readonly langiumDocuments: () => LangiumDocuments; - constructor(services: LangiumServices) { + constructor(services: LangiumCoreServices) { this.reflection = services.shared.AstReflection; this.langiumDocuments = () => services.shared.workspace.LangiumDocuments; this.scopeProvider = services.references.ScopeProvider; diff --git a/packages/langium/src/references/references.ts b/packages/langium/src/references/references.ts index 2f3015e28..34c9089eb 100644 --- a/packages/langium/src/references/references.ts +++ b/packages/langium/src/references/references.ts @@ -4,7 +4,7 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { LangiumServices } from '../services.js'; +import type { LangiumCoreServices } from '../services.js'; import type { AstNode, CstNode, GenericAstNode } from '../syntax-tree.js'; import type { Stream } from '../utils/stream.js'; import type { ReferenceDescription } from '../workspace/ast-descriptions.js'; @@ -68,7 +68,7 @@ export class DefaultReferences implements References { protected readonly index: IndexManager; protected readonly nodeLocator: AstNodeLocator; - constructor(services: LangiumServices) { + constructor(services: LangiumCoreServices) { this.nameProvider = services.references.NameProvider; this.index = services.shared.workspace.IndexManager; this.nodeLocator = services.workspace.AstNodeLocator; diff --git a/packages/langium/src/references/scope-computation.ts b/packages/langium/src/references/scope-computation.ts index 9fffcebc5..f2dc81cd8 100644 --- a/packages/langium/src/references/scope-computation.ts +++ b/packages/langium/src/references/scope-computation.ts @@ -4,12 +4,12 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { LangiumServices } from '../services.js'; +import type { LangiumCoreServices } from '../services.js'; import type { AstNode, AstNodeDescription } from '../syntax-tree.js'; import type { AstNodeDescriptionProvider } from '../workspace/ast-descriptions.js'; import type { LangiumDocument, PrecomputedScopes } from '../workspace/documents.js'; import type { NameProvider } from './name-provider.js'; -import { CancellationToken } from 'vscode-jsonrpc'; +import { CancellationToken } from '../utils/cancellation.js'; import { streamAllContents, streamContents } from '../utils/ast-utils.js'; import { MultiMap } from '../utils/collections.js'; import { interruptAndCheck } from '../utils/promise-utils.js'; @@ -68,7 +68,7 @@ export class DefaultScopeComputation implements ScopeComputation { protected readonly nameProvider: NameProvider; protected readonly descriptions: AstNodeDescriptionProvider; - constructor(services: LangiumServices) { + constructor(services: LangiumCoreServices) { this.nameProvider = services.references.NameProvider; this.descriptions = services.workspace.AstNodeDescriptionProvider; } diff --git a/packages/langium/src/references/scope-provider.ts b/packages/langium/src/references/scope-provider.ts index 253e9aaac..1dd6573a4 100644 --- a/packages/langium/src/references/scope-provider.ts +++ b/packages/langium/src/references/scope-provider.ts @@ -4,7 +4,7 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { LangiumServices } from '../services.js'; +import type { LangiumCoreServices } from '../services.js'; import type { AstNode, AstNodeDescription, AstReflection, ReferenceInfo } from '../syntax-tree.js'; import type { Stream } from '../utils/stream.js'; import type { AstNodeDescriptionProvider } from '../workspace/ast-descriptions.js'; @@ -40,7 +40,7 @@ export class DefaultScopeProvider implements ScopeProvider { protected readonly globalScopeCache: WorkspaceCache; - constructor(services: LangiumServices) { + constructor(services: LangiumCoreServices) { this.reflection = services.shared.AstReflection; this.nameProvider = services.references.NameProvider; this.descriptions = services.workspace.AstNodeDescriptionProvider; diff --git a/packages/langium/src/serializer/json-serializer.ts b/packages/langium/src/serializer/json-serializer.ts index 18f6f6b0e..4197318d9 100644 --- a/packages/langium/src/serializer/json-serializer.ts +++ b/packages/langium/src/serializer/json-serializer.ts @@ -4,16 +4,16 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ +import { URI } from 'vscode-uri'; +import type { CommentProvider } from '../documentation/comment-provider.js'; import type { NameProvider } from '../references/name-provider.js'; -import type { LangiumServices } from '../services.js'; +import type { LangiumCoreServices } from '../services.js'; import type { AstNode, CstNode, GenericAstNode, Mutable, Reference } from '../syntax-tree.js'; -import type { AstNodeLocator } from '../workspace/ast-node-locator.js'; -import type { DocumentSegment, LangiumDocument, LangiumDocuments } from '../workspace/documents.js'; -import { URI } from 'vscode-uri'; import { isAstNode, isReference } from '../syntax-tree.js'; import { getDocument } from '../utils/ast-utils.js'; import { findNodesForProperty } from '../utils/grammar-utils.js'; -import type { CommentProvider } from '../documentation/comment-provider.js'; +import type { AstNodeLocator } from '../workspace/ast-node-locator.js'; +import type { DocumentSegment, LangiumDocument, LangiumDocuments } from '../workspace/documents.js'; export interface JsonSerializeOptions { /** The space parameter for `JSON.stringify`, controlling whether and how to pretty-print the output. */ @@ -119,7 +119,7 @@ export class DefaultJsonSerializer implements JsonSerializer { protected readonly nameProvider: NameProvider; protected readonly commentProvider: CommentProvider; - constructor(services: LangiumServices) { + constructor(services: LangiumCoreServices) { this.langiumDocuments = services.shared.workspace.LangiumDocuments; this.astNodeLocator = services.workspace.AstNodeLocator; this.nameProvider = services.references.NameProvider; diff --git a/packages/langium/src/service-registry.ts b/packages/langium/src/service-registry.ts index 528c5256c..3b41bd4a5 100644 --- a/packages/langium/src/service-registry.ts +++ b/packages/langium/src/service-registry.ts @@ -4,38 +4,41 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { LangiumServices } from './services.js'; +import type { LangiumCoreServices } from './services.js'; import { UriUtils, type URI } from './utils/uri-utils.js'; /** - * The service registry provides access to the language-specific services. These are resolved - * via the URI of a text document. + * The service registry provides access to the language-specific {@link LangiumCoreServices} optionally including LSP-related services. + * These are resolved via the URI of a text document. */ export interface ServiceRegistry { /** * Register a language via its injected services. */ - register(language: LangiumServices): void; + register(language: LangiumCoreServices): void; /** * Retrieve the language-specific services for the given URI. In case only one language is * registered, it may be used regardless of the URI format. */ - getServices(uri: URI): LangiumServices; + getServices(uri: URI): LangiumCoreServices; /** * The full set of registered language services. */ - readonly all: readonly LangiumServices[]; + readonly all: readonly LangiumCoreServices[]; } +/** + * Generic registry for Langium services, but capable of being used with extending service sets as well (such as the lsp-complete LangiumCoreServices set) + */ export class DefaultServiceRegistry implements ServiceRegistry { - protected singleton?: LangiumServices; - protected map?: Record; + protected singleton?: LangiumCoreServices; + protected map?: Record; - register(language: LangiumServices): void { + register(language: LangiumCoreServices): void { if (!this.singleton && !this.map) { // This is the first language to be registered; store it as singleton. this.singleton = language; @@ -60,7 +63,7 @@ export class DefaultServiceRegistry implements ServiceRegistry { } } - getServices(uri: URI): LangiumServices { + getServices(uri: URI): LangiumCoreServices { if (this.singleton !== undefined) { return this.singleton; } @@ -75,7 +78,7 @@ export class DefaultServiceRegistry implements ServiceRegistry { return services; } - get all(): readonly LangiumServices[] { + get all(): readonly LangiumCoreServices[] { if (this.singleton !== undefined) { return [this.singleton]; } diff --git a/packages/langium/src/services.ts b/packages/langium/src/services.ts index ff853bdae..44c669757 100644 --- a/packages/langium/src/services.ts +++ b/packages/langium/src/services.ts @@ -5,27 +5,18 @@ ******************************************************************************/ // Ensure that all imports are erased at runtime to avoid circular dependencies. -import type { Connection, TextDocuments } from 'vscode-languageserver'; -import type { TextDocument } from 'vscode-languageserver-textdocument'; +import type { IParserErrorMessageProvider } from 'chevrotain'; +import type { InitializeParams, InitializedParams } from 'vscode-languageserver-protocol'; +import type { CommentProvider } from './documentation/comment-provider.js'; +import type { DocumentationProvider } from './documentation/documentation-provider.js'; import type { Grammar } from './languages/generated/ast.js'; import type { GrammarConfig } from './languages/grammar-config.js'; import type { LanguageMetaData } from './languages/language-meta-data.js'; -import type { ExecuteCommandHandler } from './lsp/execute-command-handler.js'; -import type { CodeActionProvider } from './lsp/code-action.js'; -import type { CompletionProvider } from './lsp/completion/completion-provider.js'; -import type { DocumentHighlightProvider } from './lsp/document-highlight-provider.js'; -import type { DocumentSymbolProvider } from './lsp/document-symbol-provider.js'; -import type { FoldingRangeProvider } from './lsp/folding-range-provider.js'; -import type { Formatter } from './lsp/formatter.js'; -import type { DefinitionProvider } from './lsp/definition-provider.js'; -import type { HoverProvider } from './lsp/hover-provider.js'; -import type { ReferencesProvider } from './lsp/references-provider.js'; -import type { RenameProvider } from './lsp/rename-provider.js'; -import type { SemanticTokenProvider } from './lsp/semantic-token-provider.js'; +import type { AsyncParser } from './parser/async-parser.js'; import type { LangiumCompletionParser, LangiumParser } from './parser/langium-parser.js'; +import type { Lexer } from './parser/lexer.js'; import type { IParserConfig } from './parser/parser-config.js'; import type { TokenBuilder } from './parser/token-builder.js'; -import type { Lexer } from './parser/lexer.js'; import type { ValueConverter } from './parser/value-converter.js'; import type { Linker } from './references/linker.js'; import type { NameProvider } from './references/name-provider.js'; @@ -35,42 +26,33 @@ import type { ScopeProvider } from './references/scope-provider.js'; import type { JsonSerializer } from './serializer/json-serializer.js'; import type { ServiceRegistry } from './service-registry.js'; import type { AstReflection } from './syntax-tree.js'; +import type { MaybePromise } from './utils/promise-utils.js'; import type { DocumentValidator } from './validation/document-validator.js'; import type { ValidationRegistry } from './validation/validation-registry.js'; import type { AstNodeDescriptionProvider, ReferenceDescriptionProvider } from './workspace/ast-descriptions.js'; import type { AstNodeLocator } from './workspace/ast-node-locator.js'; import type { ConfigurationProvider } from './workspace/configuration.js'; import type { DocumentBuilder } from './workspace/document-builder.js'; -import type { LangiumDocumentFactory, LangiumDocuments } from './workspace/documents.js'; +import type { LangiumDocumentFactory, LangiumDocuments, TextDocumentProvider } from './workspace/documents.js'; import type { FileSystemProvider } from './workspace/file-system-provider.js'; import type { IndexManager } from './workspace/index-manager.js'; -import type { WorkspaceManager } from './workspace/workspace-manager.js'; -import type { LanguageServer } from './lsp/language-server.js'; -import type { SignatureHelpProvider } from './lsp/signature-help-provider.js'; -import type { TypeDefinitionProvider } from './lsp/type-provider.js'; -import type { ImplementationProvider } from './lsp/implementation-provider.js'; -import type { CallHierarchyProvider } from './lsp/call-hierarchy-provider.js'; -import type { CodeLensProvider } from './lsp/code-lens-provider.js'; -import type { DeclarationProvider } from './lsp/declaration-provider.js'; -import type { DocumentLinkProvider } from './lsp/document-link-provider.js'; -import type { DocumentUpdateHandler } from './lsp/document-update-handler.js'; -import type { DocumentationProvider } from './documentation/documentation-provider.js'; -import type { FileOperationHandler } from './lsp/file-operation-handler.js'; -import type { InlayHintProvider } from './lsp/inlay-hint-provider.js'; -import type { CommentProvider } from './documentation/comment-provider.js'; -import type { WorkspaceSymbolProvider } from './lsp/workspace-symbol-provider.js'; -import type { NodeKindProvider } from './lsp/node-kind-provider.js'; -import type { FuzzyMatcher } from './lsp/fuzzy-matcher.js'; -import type { IParserErrorMessageProvider } from 'chevrotain'; -import type { TypeHierarchyProvider } from './lsp/type-hierarchy-provider.js'; -import type { AsyncParser } from './parser/async-parser.js'; import type { WorkspaceLock } from './workspace/workspace-lock.js'; +import type { WorkspaceManager } from './workspace/workspace-manager.js'; + +export type { + InitializeParams, InitializedParams +}; + +export interface InitializableService { + initialize(params: InitializeParams): void + initialized(params: InitializedParams): MaybePromise +} /** - * The services generated by `langium-cli` for a single language. These are derived from the + * The services generated by `langium-cli` for a specific language. These are derived from the * grammar definition and the language configuration. */ -export type LangiumGeneratedServices = { +export type LangiumGeneratedCoreServices = { Grammar: Grammar LanguageMetaData: LanguageMetaData parser: { @@ -79,36 +61,9 @@ export type LangiumGeneratedServices = { } /** - * Services related to the Language Server Protocol (LSP). + * Core services for a specific language of which Langium provides default implementations. */ -export type LangiumLspServices = { - CallHierarchyProvider?: CallHierarchyProvider - CodeActionProvider?: CodeActionProvider - CodeLensProvider?: CodeLensProvider - CompletionProvider?: CompletionProvider - DeclarationProvider?: DeclarationProvider - DefinitionProvider?: DefinitionProvider - DocumentHighlightProvider?: DocumentHighlightProvider - DocumentLinkProvider?: DocumentLinkProvider - DocumentSymbolProvider?: DocumentSymbolProvider - FoldingRangeProvider?: FoldingRangeProvider - Formatter?: Formatter - HoverProvider?: HoverProvider - ImplementationProvider?: ImplementationProvider - InlayHintProvider?: InlayHintProvider - ReferencesProvider?: ReferencesProvider - RenameProvider?: RenameProvider - SemanticTokenProvider?: SemanticTokenProvider - SignatureHelp?: SignatureHelpProvider - TypeHierarchyProvider?: TypeHierarchyProvider; - TypeProvider?: TypeDefinitionProvider -} - -/** - * Services for a single language where Langium provides default implementations. - */ -export type LangiumDefaultServices = { - lsp: LangiumLspServices +export type LangiumDefaultCoreServices = { parser: { AsyncParser: AsyncParser GrammarConfig: GrammarConfig @@ -142,38 +97,28 @@ export type LangiumDefaultServices = { AstNodeDescriptionProvider: AstNodeDescriptionProvider ReferenceDescriptionProvider: ReferenceDescriptionProvider } - shared: LangiumSharedServices + shared: LangiumSharedCoreServices } /** - * The full set of services available for a language. These are either generated by `langium-cli` + * The core set of services available for a language. These are either generated by `langium-cli` * or provided as default implementations. */ -export type LangiumServices = LangiumGeneratedServices & LangiumDefaultServices +export type LangiumCoreServices = LangiumGeneratedCoreServices & LangiumDefaultCoreServices /** * The services generated by `langium-cli` that are shared between multiple languages. These are * derived from the grammar definition. */ -export type LangiumGeneratedSharedServices = { +export type LangiumGeneratedSharedCoreServices = { AstReflection: AstReflection } /** - * Services shared between multiple languages where Langium provides default implementations. + * Core services shared between multiple languages where Langium provides default implementations. */ -export type LangiumDefaultSharedServices = { +export type LangiumDefaultSharedCoreServices = { ServiceRegistry: ServiceRegistry - lsp: { - Connection?: Connection - DocumentUpdateHandler: DocumentUpdateHandler - ExecuteCommandHandler?: ExecuteCommandHandler - FileOperationHandler?: FileOperationHandler - FuzzyMatcher: FuzzyMatcher - LanguageServer: LanguageServer - NodeKindProvider: NodeKindProvider - WorkspaceSymbolProvider?: WorkspaceSymbolProvider - } workspace: { ConfigurationProvider: ConfigurationProvider DocumentBuilder: DocumentBuilder @@ -181,17 +126,17 @@ export type LangiumDefaultSharedServices = { IndexManager: IndexManager LangiumDocuments: LangiumDocuments LangiumDocumentFactory: LangiumDocumentFactory - TextDocuments: TextDocuments + TextDocuments?: TextDocumentProvider WorkspaceLock: WorkspaceLock WorkspaceManager: WorkspaceManager } } /** - * The shared services are a set of services that are used by every language within a Langium project. + * The shared core services are a set of services that are used by every language within a Langium project (excluding LSP services) * This is necessary to enable features like cross references across different languages. */ -export type LangiumSharedServices = LangiumDefaultSharedServices & LangiumGeneratedSharedServices +export type LangiumSharedCoreServices = LangiumDefaultSharedCoreServices & LangiumGeneratedSharedCoreServices /** * A deep partial type definition for services. We look into T to see whether its type definition contains @@ -203,11 +148,11 @@ export type DeepPartial = T[keyof T] extends Function ? T : { } /** - * Language-specific services to be partially overridden via dependency injection. + * Language-specific core services to be partially overridden via dependency injection. */ -export type PartialLangiumServices = DeepPartial +export type PartialLangiumCoreServices = DeepPartial /** - * Shared services to be partially overridden via dependency injection. + * Shared core services to be partially overridden via dependency injection. */ -export type PartialLangiumSharedServices = DeepPartial +export type PartialLangiumSharedCoreServices = DeepPartial diff --git a/packages/langium/src/test/langium-test.ts b/packages/langium/src/test/langium-test.ts index 6dab85486..b523c3f8e 100644 --- a/packages/langium/src/test/langium-test.ts +++ b/packages/langium/src/test/langium-test.ts @@ -4,22 +4,22 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { CompletionItem, CompletionList, Diagnostic, DocumentSymbol, FoldingRange, FormattingOptions, Range, ReferenceParams, SemanticTokensParams, SemanticTokenTypes, TextDocumentIdentifier, TextDocumentPositionParams, WorkspaceSymbol } from 'vscode-languageserver'; -import type { LangiumServices, LangiumSharedServices } from '../services.js'; +import type { CompletionItem, CompletionList, Diagnostic, DocumentSymbol, FoldingRange, FormattingOptions, Range, ReferenceParams, SemanticTokensParams, SemanticTokenTypes, TextDocumentIdentifier, TextDocumentPositionParams, WorkspaceSymbol } from 'vscode-languageserver-protocol'; +import type { LangiumCoreServices, LangiumSharedCoreServices } from '../services.js'; import type { AstNode, CstNode, Properties } from '../syntax-tree.js'; -import type { LangiumDocument } from '../workspace/documents.js'; +import { type LangiumDocument, TextDocument } from '../workspace/documents.js'; import type { BuildOptions } from '../workspace/document-builder.js'; -import { DiagnosticSeverity, MarkupContent } from 'vscode-languageserver'; +import { DiagnosticSeverity, MarkupContent } from 'vscode-languageserver-types'; import { escapeRegExp } from '../utils/regexp-utils.js'; import { URI } from '../utils/uri-utils.js'; import { findNodeForProperty } from '../utils/grammar-utils.js'; import { SemanticTokensDecoder } from '../lsp/semantic-token-provider.js'; -import { TextDocument } from 'vscode-languageserver-textdocument'; import * as assert from 'node:assert'; import { stream } from '../utils/stream.js'; import type { AsyncDisposable } from '../utils/disposable.js'; import { Disposable } from '../utils/disposable.js'; import { normalizeEOL } from '../generate/template-string.js'; +import type { LangiumServices, LangiumSharedLSPServices } from '../lsp/lsp-services.js'; export interface ParseHelperOptions extends BuildOptions { /** @@ -30,7 +30,7 @@ export interface ParseHelperOptions extends BuildOptions { let nextDocumentId = 1; -export function parseHelper(services: LangiumServices): (input: string, options?: ParseHelperOptions) => Promise> { +export function parseHelper(services: LangiumCoreServices): (input: string, options?: ParseHelperOptions) => Promise> { const metaData = services.LanguageMetaData; const documentBuilder = services.shared.workspace.DocumentBuilder; return async (input, options) => { @@ -202,7 +202,7 @@ export interface ExpectedWorkspaceSymbolsCallback extends ExpectedWorkspaceSymbo export type ExpectedWorkspaceSymbols = ExpectedWorkspaceSymbolsList | ExpectedWorkspaceSymbolsCallback; -export function expectWorkspaceSymbols(services: LangiumSharedServices): (input: ExpectedWorkspaceSymbols) => Promise { +export function expectWorkspaceSymbols(services: LangiumSharedLSPServices): (input: ExpectedWorkspaceSymbols) => Promise { return async input => { const symbolProvider = services.lsp.WorkspaceSymbolProvider; const symbols = await symbolProvider?.getSymbols({ @@ -494,7 +494,7 @@ export function textDocumentPositionParams(document: LangiumDocument, offset: nu return { textDocument: { uri: document.textDocument.uri }, position: document.textDocument.positionAt(offset) }; } -export async function parseDocument(services: LangiumServices, input: string, options?: ParseHelperOptions): Promise> { +export async function parseDocument(services: LangiumCoreServices, input: string, options?: ParseHelperOptions): Promise> { const document = await parseHelper(services)(input, options); if (!document.parseResult) { throw new Error('Could not parse document'); @@ -545,7 +545,7 @@ export interface ValidationResult extends AsyncDisp document: LangiumDocument; } -export function validationHelper(services: LangiumServices): (input: string, options?: ParseHelperOptions) => Promise> { +export function validationHelper(services: LangiumCoreServices): (input: string, options?: ParseHelperOptions) => Promise> { const parse = parseHelper(services); return async (input, options) => { const document = await parse(input, { @@ -697,7 +697,7 @@ export function expectWarning { +export function clearDocuments(services: LangiumCoreServices | LangiumSharedCoreServices, documents?: LangiumDocument[]): Promise { const shared = 'shared' in services ? services.shared : services; const allDocs = (documents ? stream(documents) : shared.workspace.LangiumDocuments.all).map(x => x.uri).toArray(); return shared.workspace.DocumentBuilder.update([], allDocs); diff --git a/packages/langium/src/utils/ast-utils.ts b/packages/langium/src/utils/ast-utils.ts index cb915be82..92030e945 100644 --- a/packages/langium/src/utils/ast-utils.ts +++ b/packages/langium/src/utils/ast-utils.ts @@ -4,7 +4,7 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { Range } from 'vscode-languageserver'; +import type { Range } from 'vscode-languageserver-types'; import type { AstNode, AstReflection, CstNode, GenericAstNode, Mutable, PropertyType, Reference, ReferenceInfo } from '../syntax-tree.js'; import type { Stream, TreeStream } from './stream.js'; import type { LangiumDocument } from '../workspace/documents.js'; diff --git a/packages/langium/src/utils/caching.ts b/packages/langium/src/utils/caching.ts index e42421ae7..6c26227f9 100644 --- a/packages/langium/src/utils/caching.ts +++ b/packages/langium/src/utils/caching.ts @@ -6,7 +6,7 @@ import type { Disposable } from './disposable.js'; import type { URI } from './uri-utils.js'; -import type { LangiumSharedServices } from '../services.js'; +import type { LangiumSharedCoreServices } from '../services.js'; export abstract class DisposableCache implements Disposable { @@ -141,7 +141,7 @@ export class ContextCache extends Dis * If this document is changed or deleted, all associated key/value pairs are deleted. */ export class DocumentCache extends ContextCache { - constructor(sharedServices: LangiumSharedServices) { + constructor(sharedServices: LangiumSharedCoreServices) { super(uri => uri.toString()); this.onDispose(sharedServices.workspace.DocumentBuilder.onUpdate((changed, deleted) => { const allUris = changed.concat(deleted); @@ -157,7 +157,7 @@ export class DocumentCache extends ContextCache extends SimpleCache { - constructor(sharedServices: LangiumSharedServices) { + constructor(sharedServices: LangiumSharedCoreServices) { super(); this.onDispose(sharedServices.workspace.DocumentBuilder.onUpdate(() => { this.clear(); diff --git a/packages/langium/src/utils/cancellation.ts b/packages/langium/src/utils/cancellation.ts new file mode 100644 index 000000000..cbf3fc30a --- /dev/null +++ b/packages/langium/src/utils/cancellation.ts @@ -0,0 +1,8 @@ +/****************************************************************************** + * Copyright 2024 TypeFox GmbH + * This program and the accompanying materials are made available under the + * terms of the MIT License, which is available in the project root. + ******************************************************************************/ + +// eslint-disable-next-line no-restricted-imports +export * from 'vscode-jsonrpc/lib/common/cancellation.js'; \ No newline at end of file diff --git a/packages/langium/src/utils/cst-utils.ts b/packages/langium/src/utils/cst-utils.ts index 59e6b1a5c..21135516c 100644 --- a/packages/langium/src/utils/cst-utils.ts +++ b/packages/langium/src/utils/cst-utils.ts @@ -5,7 +5,7 @@ ******************************************************************************/ import type { IToken } from '@chevrotain/types'; -import type { Range } from 'vscode-languageserver'; +import type { Range } from 'vscode-languageserver-types'; import type { CstNode, CompositeCstNode, LeafCstNode } from '../syntax-tree.js'; import type { DocumentSegment } from '../workspace/documents.js'; import type { Stream, TreeStream } from './stream.js'; diff --git a/packages/langium/src/utils/grammar-loader.ts b/packages/langium/src/utils/grammar-loader.ts index 8ab590f7f..02ed4c7a5 100644 --- a/packages/langium/src/utils/grammar-loader.ts +++ b/packages/langium/src/utils/grammar-loader.ts @@ -4,16 +4,16 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ +import { createDefaultCoreModule, createDefaultSharedCoreModule } from '../default-module.js'; import type { Module } from '../dependency-injection.js'; -import type { LangiumServices, LangiumSharedServices, PartialLangiumServices, PartialLangiumSharedServices } from '../services.js'; -import type { Mutable } from '../syntax-tree.js'; -import * as ast from '../languages/generated/ast.js'; import { inject } from '../dependency-injection.js'; -import { createDefaultModule, createDefaultSharedModule } from '../default-module.js'; +import * as ast from '../languages/generated/ast.js'; +import type { LangiumCoreServices, LangiumSharedCoreServices, PartialLangiumCoreServices, PartialLangiumSharedCoreServices } from '../services.js'; +import type { Mutable } from '../syntax-tree.js'; import { EmptyFileSystem } from '../workspace/file-system-provider.js'; import { URI } from './uri-utils.js'; -const minimalGrammarModule: Module = { +const minimalGrammarModule: Module = { Grammar: () => undefined as unknown as ast.Grammar, LanguageMetaData: () => ({ caseInsensitive: false, @@ -22,17 +22,17 @@ const minimalGrammarModule: Module = { }) }; -const minimalSharedGrammarModule: Module = { +const minimalSharedGrammarModule: Module = { AstReflection: () => new ast.LangiumGrammarAstReflection() }; -function createMinimalGrammarServices(): LangiumServices { +function createMinimalGrammarServices(): LangiumCoreServices { const shared = inject( - createDefaultSharedModule(EmptyFileSystem), + createDefaultSharedCoreModule(EmptyFileSystem), minimalSharedGrammarModule ); const grammar = inject( - createDefaultModule({ shared }), + createDefaultCoreModule({ shared }), minimalGrammarModule ); shared.ServiceRegistry.register(grammar); diff --git a/packages/langium/src/utils/index.ts b/packages/langium/src/utils/index.ts index 123e84539..8f42d52b1 100644 --- a/packages/langium/src/utils/index.ts +++ b/packages/langium/src/utils/index.ts @@ -14,7 +14,8 @@ export * from './stream.js'; export * from './uri-utils.js'; import * as AstUtils from './ast-utils.js'; +import * as Cancellation from './cancellation.js'; import * as CstUtils from './cst-utils.js'; import * as GrammarUtils from './grammar-utils.js'; import * as RegExpUtils from './regexp-utils.js'; -export { AstUtils, CstUtils, GrammarUtils, RegExpUtils }; +export { AstUtils, Cancellation, CstUtils, GrammarUtils, RegExpUtils }; diff --git a/packages/langium/src/utils/promise-utils.ts b/packages/langium/src/utils/promise-utils.ts index 8ddad3954..13198092e 100644 --- a/packages/langium/src/utils/promise-utils.ts +++ b/packages/langium/src/utils/promise-utils.ts @@ -4,8 +4,7 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { AbstractCancellationTokenSource } from 'vscode-jsonrpc'; -import { CancellationToken, CancellationTokenSource } from 'vscode-jsonrpc'; +import { CancellationToken, CancellationTokenSource, type AbstractCancellationTokenSource } from '../utils/cancellation.js'; export type MaybePromise = T | Promise diff --git a/packages/langium/src/validation/document-validator.ts b/packages/langium/src/validation/document-validator.ts index 4ca0be16b..e5e1d56d5 100644 --- a/packages/langium/src/validation/document-validator.ts +++ b/packages/langium/src/validation/document-validator.ts @@ -5,14 +5,14 @@ ******************************************************************************/ import type { MismatchedTokenException } from 'chevrotain'; -import type { Diagnostic } from 'vscode-languageserver'; +import type { DiagnosticSeverity, Position, Range, Diagnostic } from 'vscode-languageserver-types'; import type { LanguageMetaData } from '../languages/language-meta-data.js'; import type { ParseResult } from '../parser/langium-parser.js'; -import type { LangiumServices } from '../services.js'; +import type { LangiumCoreServices } from '../services.js'; import type { AstNode, CstNode } from '../syntax-tree.js'; import type { LangiumDocument } from '../workspace/documents.js'; import type { DiagnosticData, DiagnosticInfo, ValidationAcceptor, ValidationCategory, ValidationRegistry } from './validation-registry.js'; -import { CancellationToken, DiagnosticSeverity, Position, Range } from 'vscode-languageserver'; +import { CancellationToken } from '../utils/cancellation.js'; import { findNodeForKeyword, findNodeForProperty } from '../utils/grammar-utils.js'; import { streamAst } from '../utils/ast-utils.js'; import { tokenToRange } from '../utils/cst-utils.js'; @@ -53,7 +53,7 @@ export class DefaultDocumentValidator implements DocumentValidator { protected readonly validationRegistry: ValidationRegistry; protected readonly metadata: LanguageMetaData; - constructor(services: LangiumServices) { + constructor(services: LangiumCoreServices) { this.validationRegistry = services.validation.ValidationRegistry; this.metadata = services.LanguageMetaData; } @@ -99,7 +99,7 @@ export class DefaultDocumentValidator implements DocumentValidator { protected processLexingErrors(parseResult: ParseResult, diagnostics: Diagnostic[], _options: ValidationOptions): void { for (const lexerError of parseResult.lexerErrors) { const diagnostic: Diagnostic = { - severity: DiagnosticSeverity.Error, + severity: toDiagnosticSeverity('error'), range: { start: { line: lexerError.line! - 1, @@ -130,12 +130,13 @@ export class DefaultDocumentValidator implements DocumentValidator { if ('previousToken' in parserError) { const token = (parserError as MismatchedTokenException).previousToken; if (!isNaN(token.startOffset)) { - const position = Position.create(token.endLine! - 1, token.endColumn!); - range = Range.create(position, position); + const position: Position = { line: token.endLine! - 1, character: token.endColumn! }; + range = { start: position, end: position}; } else { // No valid prev token. Might be empty document or containing only hidden tokens. // Point to document start - range = Range.create(0, 0, 0, 0); + const position: Position = { line: 0, character: 0 }; + range = { start: position, end: position}; } } } else { @@ -143,7 +144,7 @@ export class DefaultDocumentValidator implements DocumentValidator { } if (range) { const diagnostic: Diagnostic = { - severity: DiagnosticSeverity.Error, + severity: toDiagnosticSeverity('error'), range, message: parserError.message, data: diagnosticData(DocumentValidator.ParsingError), @@ -210,7 +211,7 @@ export class DefaultDocumentValidator implements DocumentValidator { } export function getDiagnosticRange(info: DiagnosticInfo): Range { - if (Range.is(info.range)) { + if (info.range) { return info.range; } let cstNode: CstNode | undefined; @@ -232,13 +233,13 @@ export function getDiagnosticRange(info: DiagnosticInfo(); private readonly reflection: AstReflection; - constructor(services: LangiumServices) { + constructor(services: LangiumCoreServices) { this.reflection = services.shared.AstReflection; } diff --git a/packages/langium/src/workspace/ast-descriptions.ts b/packages/langium/src/workspace/ast-descriptions.ts index a378fafa2..277238d11 100644 --- a/packages/langium/src/workspace/ast-descriptions.ts +++ b/packages/langium/src/workspace/ast-descriptions.ts @@ -6,11 +6,11 @@ import type { URI } from '../utils/uri-utils.js'; import type { NameProvider } from '../references/name-provider.js'; -import type { LangiumServices } from '../services.js'; +import type { LangiumCoreServices } from '../services.js'; import type { AstNode, AstNodeDescription, ReferenceInfo } from '../syntax-tree.js'; import type { AstNodeLocator } from './ast-node-locator.js'; import type { DocumentSegment, LangiumDocument } from './documents.js'; -import { CancellationToken } from 'vscode-languageserver'; +import { CancellationToken } from '../utils/cancellation.js'; import { isLinkingError } from '../syntax-tree.js'; import { getDocument, streamAst, streamReferences } from '../utils/ast-utils.js'; import { toDocumentSegment } from '../utils/cst-utils.js'; @@ -41,7 +41,7 @@ export class DefaultAstNodeDescriptionProvider implements AstNodeDescriptionProv protected readonly astNodeLocator: AstNodeLocator; protected readonly nameProvider: NameProvider; - constructor(services: LangiumServices) { + constructor(services: LangiumCoreServices) { this.astNodeLocator = services.workspace.AstNodeLocator; this.nameProvider = services.references.NameProvider; } @@ -108,7 +108,7 @@ export class DefaultReferenceDescriptionProvider implements ReferenceDescription protected readonly nodeLocator: AstNodeLocator; - constructor(services: LangiumServices) { + constructor(services: LangiumCoreServices) { this.nodeLocator = services.workspace.AstNodeLocator; } diff --git a/packages/langium/src/workspace/configuration.ts b/packages/langium/src/workspace/configuration.ts index b4c93304e..2d1ab2689 100644 --- a/packages/langium/src/workspace/configuration.ts +++ b/packages/langium/src/workspace/configuration.ts @@ -4,21 +4,19 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { Connection, DidChangeConfigurationParams } from 'vscode-languageserver'; -import type { ConfigurationItem } from 'vscode-languageserver-protocol'; +import type { ConfigurationItem, DidChangeConfigurationParams, DidChangeConfigurationRegistrationOptions } from 'vscode-languageserver-protocol'; import type { ServiceRegistry } from '../service-registry.js'; -import type { LangiumSharedServices } from '../services.js'; -import { DidChangeConfigurationNotification } from 'vscode-languageserver-protocol'; +import type { InitializableService, InitializeParams, InitializedParams, LangiumSharedCoreServices } from '../services.js'; /* eslint-disable @typescript-eslint/no-explicit-any */ -export interface ConfigurationProvider { +export interface ConfigurationProvider extends InitializableService { /** - * Returns a configuration value stored for the given language. - * - * @param language The language id - * @param configuration Configuration name - */ + * Returns a configuration value stored for the given language. + * + * @param language The language id + * @param configuration Configuration name + */ getConfiguration(language: string, configuration: string): Promise; /** @@ -30,42 +28,64 @@ export interface ConfigurationProvider { updateConfiguration(change: DidChangeConfigurationParams): void; } +export interface ConfigurationInitializedParams extends InitializedParams { + register?: (params: DidChangeConfigurationRegistrationOptions) => void, + getConfiguration?: (configuration: ConfigurationItem[]) => Promise +} + +/** + * Base configuration provider for building up other configuration providers + */ export class DefaultConfigurationProvider implements ConfigurationProvider { + protected readonly serviceRegistry: ServiceRegistry; protected settings: Record> = {}; protected workspaceConfig = false; - protected initialized = false; - protected readonly serviceRegistry: ServiceRegistry; - protected readonly connection: Connection | undefined; - constructor(services: LangiumSharedServices) { + constructor(services: LangiumSharedCoreServices) { this.serviceRegistry = services.ServiceRegistry; - this.connection = services.lsp.Connection; - services.lsp.LanguageServer.onInitialize(params => { - this.workspaceConfig = params.capabilities.workspace?.configuration ?? false; - }); - services.lsp.LanguageServer.onInitialized(_params => { - const languages = this.serviceRegistry.all; - services.lsp.Connection?.client.register(DidChangeConfigurationNotification.type, { - // Listen to configuration changes for all languages - section: languages.map(lang => this.toSectionName(lang.LanguageMetaData.languageId)) - }); - }); } - protected async initialize(): Promise { - if (this.workspaceConfig && this.connection) { - const languages = this.serviceRegistry.all; - const configToUpdate: ConfigurationItem[] = languages.map(lang => { return { section: this.toSectionName(lang.LanguageMetaData.languageId) }; }); - // get workspace configurations (default scope URI) - const configs = await this.connection.workspace.getConfiguration(configToUpdate); - configToUpdate.forEach((conf, idx) => { - this.updateSectionConfiguration(conf.section!, configs[idx]); - }); + initialize(params: InitializeParams): void { + this.workspaceConfig = params.capabilities.workspace?.configuration ?? false; + } + + async initialized(params: ConfigurationInitializedParams): Promise { + if (this.workspaceConfig) { + if (params.register) { + // params.register(...) is a function to be provided by the calling language server for the sake of + // decoupling this implementation from the concrete LSP implementations, specifically the LSP Connection + + const languages = this.serviceRegistry.all; + params.register({ + // Listen to configuration changes for all languages + section: languages.map(lang => this.toSectionName(lang.LanguageMetaData.languageId)) + }); + } + + if (params.getConfiguration) { + // params.getConfiguration(...) is a function to be provided by the calling language server for the sake of + // decoupling this implementation from the concrete LSP implementations, specifically the LSP Connection + + const configToUpdate = this.serviceRegistry.all.map(lang => { + // Fetch the configuration changes for all languages + section: this.toSectionName(lang.LanguageMetaData.languageId) + }); + // get workspace configurations (default scope URI) + const configs = await params.getConfiguration(configToUpdate); + configToUpdate.forEach((conf, idx) => { + this.updateSectionConfiguration(conf.section!, configs[idx]); + }); + } } - this.initialized = true; } + /** + * Updates the cached configurations using the `change` notification parameters. + * + * @param change The parameters of a change configuration notification. + * `settings` property of the change object could be expressed as `Record>` + */ updateConfiguration(change: DidChangeConfigurationParams): void { if (!change.settings) { return; @@ -79,10 +99,13 @@ export class DefaultConfigurationProvider implements ConfigurationProvider { this.settings[section] = configuration; } + /** + * Returns a configuration value stored for the given language. + * + * @param language The language id + * @param configuration Configuration name + */ async getConfiguration(language: string, configuration: string): Promise { - if (!this.initialized) { - await this.initialize(); - } const sectionName = this.toSectionName(language); if (this.settings[sectionName]) { return this.settings[sectionName][configuration]; @@ -93,4 +116,3 @@ export class DefaultConfigurationProvider implements ConfigurationProvider { return `${languageId}`; } } - diff --git a/packages/langium/src/workspace/document-builder.ts b/packages/langium/src/workspace/document-builder.ts index b602abd8a..79c32010c 100644 --- a/packages/langium/src/workspace/document-builder.ts +++ b/packages/langium/src/workspace/document-builder.ts @@ -4,19 +4,20 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { URI } from '../utils/uri-utils.js'; +import { CancellationToken } from '../utils/cancellation.js'; +import { Disposable } from '../utils/disposable.js'; import type { ServiceRegistry } from '../service-registry.js'; -import type { LangiumSharedServices } from '../services.js'; +import type { LangiumSharedCoreServices } from '../services.js'; import type { AstNode } from '../syntax-tree.js'; -import type { MaybePromise } from '../utils/promise-utils.js'; -import type { ValidationOptions } from '../validation/document-validator.js'; -import type { IndexManager } from '../workspace/index-manager.js'; -import type { LangiumDocument, LangiumDocuments, LangiumDocumentFactory } from './documents.js'; -import { CancellationToken, Disposable } from 'vscode-languageserver'; import { MultiMap } from '../utils/collections.js'; +import type { MaybePromise } from '../utils/promise-utils.js'; import { interruptAndCheck } from '../utils/promise-utils.js'; import { stream } from '../utils/stream.js'; +import type { URI } from '../utils/uri-utils.js'; +import type { ValidationOptions } from '../validation/document-validator.js'; import { ValidationCategory } from '../validation/validation-registry.js'; +import type { IndexManager } from '../workspace/index-manager.js'; +import type { LangiumDocument, LangiumDocumentFactory, LangiumDocuments } from './documents.js'; import { DocumentState } from './documents.js'; export interface BuildOptions { @@ -100,7 +101,7 @@ export class DefaultDocumentBuilder implements DocumentBuilder { protected readonly buildPhaseListeners: MultiMap = new MultiMap(); protected readonly buildState: Map = new Map(); - constructor(services: LangiumSharedServices) { + constructor(services: LangiumSharedCoreServices) { this.langiumDocuments = services.workspace.LangiumDocuments; this.langiumDocumentFactory = services.workspace.LangiumDocumentFactory; this.indexManager = services.workspace.IndexManager; diff --git a/packages/langium/src/workspace/documents.ts b/packages/langium/src/workspace/documents.ts index 999a01942..dd8203535 100644 --- a/packages/langium/src/workspace/documents.ts +++ b/packages/langium/src/workspace/documents.ts @@ -4,18 +4,27 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { Diagnostic, Range, TextDocuments } from 'vscode-languageserver'; -import { CancellationToken } from 'vscode-languageserver'; +/** + * Re-export 'TextDocument' from 'vscode-languageserver-textdocument' for convenience, + * including both type _and_ symbol (namespace), as we here and there also refer to the symbol, + * the overhead is very small, just a few kilobytes. + * Everything else of that package (at the time contributing) is also defined + * in 'vscode-languageserver-protocol' or 'vscode-languageserver-types'. + */ +export { TextDocument } from 'vscode-languageserver-textdocument'; + +import type { Diagnostic, Range } from 'vscode-languageserver-types'; +import type { FileSystemProvider } from './file-system-provider.js'; import type { ParseResult } from '../parser/langium-parser.js'; import type { ServiceRegistry } from '../service-registry.js'; -import type { LangiumSharedServices } from '../services.js'; +import type { LangiumSharedCoreServices } from '../services.js'; import type { AstNode, AstNodeDescription, Mutable, Reference } from '../syntax-tree.js'; import type { MultiMap } from '../utils/collections.js'; import type { Stream } from '../utils/stream.js'; -import type { FileSystemProvider } from './file-system-provider.js'; -import { URI } from '../utils/uri-utils.js'; -import { TextDocument } from 'vscode-languageserver-textdocument'; +import { TextDocument } from './documents.js'; +import { CancellationToken } from '../utils/cancellation.js'; import { stream } from '../utils/stream.js'; +import { URI } from '../utils/uri-utils.js'; /** * A Langium document holds the parse result (AST and CST) and any additional state that is derived @@ -98,6 +107,14 @@ export interface DocumentSegment { readonly end: number } +/** + * Surrogate definition of the `TextDocuments` interface from the `vscode-languageserver` package. + * No implementation object is expected to be offered by `LangiumCoreServices`, but only by `LangiumLSPServices`. + */ +export type TextDocumentProvider = { + get(uri: string): TextDocument | undefined +} + /** * Shared service for creating `LangiumDocument` instances. * @@ -136,7 +153,7 @@ export interface LangiumDocumentFactory { /** * Update the given document after changes in the corresponding textual representation. - * Method is called by the document builder after it has been requested to build an exisiting + * Method is called by the document builder after it has been requested to build an existing * document and the document's state is {@link DocumentState.Changed}. * The text parsing is expected to be done the same way as in {@link fromTextDocument} * and {@link fromString}. @@ -147,10 +164,10 @@ export interface LangiumDocumentFactory { export class DefaultLangiumDocumentFactory implements LangiumDocumentFactory { protected readonly serviceRegistry: ServiceRegistry; - protected readonly textDocuments: TextDocuments; + protected readonly textDocuments?: TextDocumentProvider; protected readonly fileSystemProvider: FileSystemProvider; - constructor(services: LangiumSharedServices) { + constructor(services: LangiumSharedCoreServices) { this.serviceRegistry = services.ServiceRegistry; this.textDocuments = services.workspace.TextDocuments; this.fileSystemProvider = services.workspace.FileSystemProvider; @@ -251,7 +268,7 @@ export class DefaultLangiumDocumentFactory implements LangiumDocumentFactory { async update(document: Mutable>, cancellationToken: CancellationToken): Promise> { // The CST full text property contains the original text that was used to create the AST. const oldText = document.parseResult.value.$cstNode?.root.fullText; - const textDocument = this.textDocuments.get(document.uri.toString()); + const textDocument = this.textDocuments?.get(document.uri.toString()); const text = textDocument ? textDocument.getText() : await this.fileSystemProvider.readFile(document.uri); if (textDocument) { @@ -378,7 +395,7 @@ export class DefaultLangiumDocuments implements LangiumDocuments { protected readonly documentMap: Map = new Map(); - constructor(services: LangiumSharedServices) { + constructor(services: LangiumSharedCoreServices) { this.langiumDocumentFactory = services.workspace.LangiumDocumentFactory; } diff --git a/packages/langium/src/workspace/index-manager.ts b/packages/langium/src/workspace/index-manager.ts index d4a769de7..5ab7a0bac 100644 --- a/packages/langium/src/workspace/index-manager.ts +++ b/packages/langium/src/workspace/index-manager.ts @@ -4,18 +4,18 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { URI } from '../utils/uri-utils.js'; import type { ServiceRegistry } from '../service-registry.js'; -import type { LangiumSharedServices } from '../services.js'; +import type { LangiumSharedCoreServices } from '../services.js'; import type { AstNode, AstNodeDescription, AstReflection } from '../syntax-tree.js'; -import type { Stream } from '../utils/stream.js'; -import type { ReferenceDescription } from './ast-descriptions.js'; -import type { LangiumDocument, LangiumDocuments } from './documents.js'; -import { CancellationToken } from 'vscode-languageserver'; import { getDocument } from '../utils/ast-utils.js'; +import { ContextCache } from '../utils/caching.js'; +import { CancellationToken } from '../utils/cancellation.js'; +import type { Stream } from '../utils/stream.js'; import { stream } from '../utils/stream.js'; +import type { URI } from '../utils/uri-utils.js'; import { UriUtils } from '../utils/uri-utils.js'; -import { ContextCache } from '../utils/caching.js'; +import type { ReferenceDescription } from './ast-descriptions.js'; +import type { LangiumDocument, LangiumDocuments } from './documents.js'; /** * The index manager is responsible for keeping metadata about symbols and cross-references @@ -104,7 +104,7 @@ export class DefaultIndexManager implements IndexManager { */ protected readonly referenceIndex = new Map(); - constructor(services: LangiumSharedServices) { + constructor(services: LangiumSharedCoreServices) { this.documents = services.workspace.LangiumDocuments; this.serviceRegistry = services.ServiceRegistry; this.astReflection = services.AstReflection; diff --git a/packages/langium/src/workspace/workspace-lock.ts b/packages/langium/src/workspace/workspace-lock.ts index cbf3fa9c5..795de45c5 100644 --- a/packages/langium/src/workspace/workspace-lock.ts +++ b/packages/langium/src/workspace/workspace-lock.ts @@ -4,9 +4,8 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import { CancellationToken, CancellationTokenSource } from 'vscode-languageserver'; -import type { MaybePromise } from '../utils/promise-utils.js'; -import { Deferred, isOperationCancelled } from '../utils/promise-utils.js'; +import { CancellationToken, CancellationTokenSource } from '../utils/cancellation.js'; +import { Deferred, isOperationCancelled, type MaybePromise } from '../utils/promise-utils.js'; /** * Utility service to execute mutually exclusive actions. diff --git a/packages/langium/src/workspace/workspace-manager.ts b/packages/langium/src/workspace/workspace-manager.ts index d9d4b9e59..730b351ba 100644 --- a/packages/langium/src/workspace/workspace-manager.ts +++ b/packages/langium/src/workspace/workspace-manager.ts @@ -4,22 +4,26 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import { CancellationToken } from 'vscode-languageserver'; +import type { WorkspaceFolder } from 'vscode-languageserver-types'; +import type { ServiceRegistry } from '../service-registry.js'; +import type { InitializableService, InitializeParams, InitializedParams, LangiumSharedCoreServices } from '../services.js'; +import { CancellationToken } from '../utils/cancellation.js'; import { interruptAndCheck } from '../utils/promise-utils.js'; import { URI, UriUtils } from '../utils/uri-utils.js'; -import type { WorkspaceFolder } from 'vscode-languageserver'; -import type { ServiceRegistry } from '../service-registry.js'; -import type { LangiumSharedServices } from '../services.js'; import type { BuildOptions, DocumentBuilder } from './document-builder.js'; import type { LangiumDocument, LangiumDocuments } from './documents.js'; import type { FileSystemNode, FileSystemProvider } from './file-system-provider.js'; import type { WorkspaceLock } from './workspace-lock.js'; +// export type WorkspaceFolder from 'vscode-languageserver-types' for convenience, +// is supposed to avoid confusion as 'WorkspaceFolder' might accidentally be imported via 'vscode-languageclient' +export type { WorkspaceFolder }; + /** * The workspace manager is responsible for finding source files in the workspace. * This service is shared between all languages of a language server. */ -export interface WorkspaceManager { +export interface WorkspaceManager extends InitializableService { /** The options used for the initial workspace build. */ initialBuildOptions: BuildOptions | undefined; @@ -46,22 +50,22 @@ export class DefaultWorkspaceManager implements WorkspaceManager { protected readonly mutex: WorkspaceLock; protected folders?: WorkspaceFolder[]; - constructor(services: LangiumSharedServices) { + constructor(services: LangiumSharedCoreServices) { this.serviceRegistry = services.ServiceRegistry; this.langiumDocuments = services.workspace.LangiumDocuments; this.documentBuilder = services.workspace.DocumentBuilder; this.fileSystemProvider = services.workspace.FileSystemProvider; this.mutex = services.workspace.WorkspaceLock; + } - services.lsp.LanguageServer.onInitialize(params => { - this.folders = params.workspaceFolders ?? undefined; - }); + initialize(params: InitializeParams): void { + this.folders = params.workspaceFolders ?? undefined; + } - services.lsp.LanguageServer.onInitialized(_params => { - // Initialize the workspace even if there are no workspace folders - // We still want to load additional documents (language library or similar) during initialization - this.mutex.write(token => this.initializeWorkspace(this.folders ?? [], token)); - }); + initialized(_params: InitializedParams): Promise { + // Initialize the workspace even if there are no workspace folders + // We still want to load additional documents (language library or similar) during initialization + return this.mutex.write(token => this.initializeWorkspace(this.folders ?? [], token)); } async initializeWorkspace(folders: WorkspaceFolder[], cancelToken = CancellationToken.None): Promise { @@ -126,7 +130,7 @@ export class DefaultWorkspaceManager implements WorkspaceManager { /** * Determine whether the given folder entry shall be included while indexing the workspace. */ - protected includeEntry(workspaceFolder: WorkspaceFolder, entry: FileSystemNode, fileExtensions: string[]): boolean { + protected includeEntry(_workspaceFolder: WorkspaceFolder, entry: FileSystemNode, fileExtensions: string[]): boolean { const name = UriUtils.basename(entry.uri); if (name.startsWith('.')) { return false; diff --git a/packages/langium/test/lsp/completion-provider.test.ts b/packages/langium/test/lsp/completion-provider.test.ts index c80d17cba..485552f2d 100644 --- a/packages/langium/test/lsp/completion-provider.test.ts +++ b/packages/langium/test/lsp/completion-provider.test.ts @@ -5,9 +5,11 @@ ******************************************************************************/ import { describe, test, beforeEach } from 'vitest'; -import type { AstNode, AstNodeDescription, LangiumDocument, LangiumServices, Module, PartialLangiumServices } from 'langium'; -import { DefaultAstNodeDescriptionProvider, DefaultCompletionProvider, EmptyFileSystem } from 'langium'; +import type { AstNode, AstNodeDescription, LangiumDocument, Module } from 'langium'; +import { DefaultAstNodeDescriptionProvider, EmptyFileSystem } from 'langium'; import { createLangiumGrammarServices, createServicesForGrammar } from 'langium/grammar'; +import { DefaultCompletionProvider } from 'langium/lsp'; +import type { LangiumServices, PartialLangiumServices } from 'langium/lsp'; import { clearDocuments, expectCompletion, parseHelper } from 'langium/test'; describe('Langium completion provider', () => { diff --git a/packages/langium/test/lsp/execute-command-handler.test.ts b/packages/langium/test/lsp/execute-command-handler.test.ts index 660847346..12472e15a 100644 --- a/packages/langium/test/lsp/execute-command-handler.test.ts +++ b/packages/langium/test/lsp/execute-command-handler.test.ts @@ -4,9 +4,8 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { ExecuteCommandAcceptor } from 'langium'; +import { AbstractExecuteCommandHandler, type ExecuteCommandAcceptor } from 'langium/lsp'; import { describe, expect, test } from 'vitest'; -import { AbstractExecuteCommandHandler } from 'langium'; import { createServicesForGrammar } from 'langium/grammar'; describe('AbstractExecuteCommandHandler', () => { diff --git a/packages/langium/test/lsp/fuzzy-matcher.test.ts b/packages/langium/test/lsp/fuzzy-matcher.test.ts index 493dac77b..773b662a8 100644 --- a/packages/langium/test/lsp/fuzzy-matcher.test.ts +++ b/packages/langium/test/lsp/fuzzy-matcher.test.ts @@ -5,7 +5,7 @@ ******************************************************************************/ import { describe, expect, test } from 'vitest'; -import { DefaultFuzzyMatcher } from 'langium'; +import { DefaultFuzzyMatcher } from 'langium/lsp'; const matcher = new DefaultFuzzyMatcher(); diff --git a/packages/langium/test/lsp/signatureHelpProvider.test.ts b/packages/langium/test/lsp/signatureHelpProvider.test.ts index 873037350..c23b11396 100644 --- a/packages/langium/test/lsp/signatureHelpProvider.test.ts +++ b/packages/langium/test/lsp/signatureHelpProvider.test.ts @@ -6,7 +6,7 @@ import type { SignatureHelpOptions } from 'vscode-languageserver'; import { describe, expect, test } from 'vitest'; -import { mergeSignatureHelpOptions } from 'langium'; +import { mergeSignatureHelpOptions } from 'langium/lsp'; describe('MergeSignatureHelpOptions', () => { test('Must merge SignatureHelpOptions triggerCharacters', async () => { diff --git a/packages/langium/test/service-registry.test.ts b/packages/langium/test/service-registry.test.ts index 92fe8eba0..00234cb9f 100644 --- a/packages/langium/test/service-registry.test.ts +++ b/packages/langium/test/service-registry.test.ts @@ -6,14 +6,14 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import type { LangiumServices } from 'langium'; +import type { LangiumCoreServices } from 'langium'; import { describe, expect, test } from 'vitest'; import { DefaultServiceRegistry, URI } from 'langium'; describe('DefaultServiceRegistry', () => { test('should work with a single language', () => { - const language: LangiumServices = { foo: 'bar' } as any; + const language: LangiumCoreServices = { foo: 'bar' } as any; const registry = new DefaultServiceRegistry(); registry.register(language); expect(registry.getServices(URI.parse('file:/foo.bar'))).toBe(language); @@ -21,8 +21,8 @@ describe('DefaultServiceRegistry', () => { }); test('should work with two languages', () => { - const language1: LangiumServices = { LanguageMetaData: { fileExtensions: ['.foo'] } } as any; - const language2: LangiumServices = { LanguageMetaData: { fileExtensions: ['.bar'] } } as any; + const language1: LangiumCoreServices = { LanguageMetaData: { fileExtensions: ['.foo'] } } as any; + const language2: LangiumCoreServices = { LanguageMetaData: { fileExtensions: ['.bar'] } } as any; const registry = new DefaultServiceRegistry(); registry.register(language1); registry.register(language2); diff --git a/packages/langium/test/tsconfig.export-main.json b/packages/langium/test/tsconfig.export-main.json index 06f73caae..e8678a0b8 100644 --- a/packages/langium/test/tsconfig.export-main.json +++ b/packages/langium/test/tsconfig.export-main.json @@ -7,6 +7,7 @@ "exclude": [ "../src/generate/**/*", "../src/grammar/**/*", + "../src/lsp/**/*", "../src/test/**/*", "../src/node/**/*" ] diff --git a/packages/langium/test/workspace/document-builder.test.ts b/packages/langium/test/workspace/document-builder.test.ts index 688cc1c92..a332b3780 100644 --- a/packages/langium/test/workspace/document-builder.test.ts +++ b/packages/langium/test/workspace/document-builder.test.ts @@ -5,15 +5,13 @@ ******************************************************************************/ import type { AstNode, Reference, ValidationChecks } from 'langium'; +import { DocumentState, TextDocument, URI, isOperationCancelled } from 'langium'; +import { createServicesForGrammar } from 'langium/grammar'; +import { setTextDocument } from 'langium/test'; import { describe, expect, test } from 'vitest'; import { CancellationTokenSource } from 'vscode-languageserver'; -import { TextDocument } from 'vscode-languageserver-textdocument'; -import { isOperationCancelled, DocumentState, EmptyFileSystem, URI } from 'langium'; -import { createLangiumGrammarServices, createServicesForGrammar } from 'langium/grammar'; -import { setTextDocument } from 'langium/test'; describe('DefaultDocumentBuilder', () => { - const grammarServices = createLangiumGrammarServices(EmptyFileSystem).grammar; async function createServices() { const grammar = ` grammar Test @@ -27,7 +25,7 @@ describe('DefaultDocumentBuilder', () => { terminal ID: /[_a-zA-Z][\\w_]*/; hidden terminal WS: /\\s+/; `; - const services = await createServicesForGrammar({ grammar, grammarServices }); + const services = await createServicesForGrammar({ grammar }); const fastChecks: ValidationChecks = { Foo: (node, accept) => { if (node.value > 10) { diff --git a/packages/langium/test/workspace/document-factory.test.ts b/packages/langium/test/workspace/document-factory.test.ts index c5c9acedf..7e8c5c126 100644 --- a/packages/langium/test/workspace/document-factory.test.ts +++ b/packages/langium/test/workspace/document-factory.test.ts @@ -4,10 +4,10 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { Grammar, LangiumServices } from 'langium'; +import type { Grammar } from 'langium'; +import type { LangiumServices } from 'langium/lsp'; import { describe, expect, test } from 'vitest'; -import { TextDocument } from 'vscode-languageserver-textdocument'; -import { DocumentState, EmptyFileSystem } from 'langium'; +import { DocumentState, EmptyFileSystem, TextDocument } from 'langium'; import { createLangiumGrammarServices } from 'langium/grammar'; import { setTextDocument } from 'langium/test'; import { CancellationToken } from 'vscode-languageserver'; diff --git a/packages/langium/test/workspace/validation-registry.test.ts b/packages/langium/test/workspace/validation-registry.test.ts index 95cdd4390..a7c935639 100644 --- a/packages/langium/test/workspace/validation-registry.test.ts +++ b/packages/langium/test/workspace/validation-registry.test.ts @@ -4,7 +4,7 @@ * terms of the MIT License, which is available in the project root. ******************************************************************************/ -import type { GrammarAST as GrammarTypes, LangiumServices, ValidationChecks } from 'langium'; +import type { GrammarAST as GrammarTypes, LangiumCoreServices, ValidationChecks } from 'langium'; import { describe, expect, test } from 'vitest'; import { GrammarAST, ValidationRegistry } from 'langium'; @@ -15,7 +15,7 @@ describe('ValidationRegistry', () => { shared: { AstReflection: new GrammarAST.LangiumGrammarAstReflection() } - } as unknown as LangiumServices; + } as unknown as LangiumCoreServices; return new ValidationRegistry(services); }