diff --git a/src/language-server/tiny-dsl-module.ts b/src/language-server/tiny-dsl-module.ts index b362722..497b113 100644 --- a/src/language-server/tiny-dsl-module.ts +++ b/src/language-server/tiny-dsl-module.ts @@ -1,30 +1,30 @@ import { - createDefaultModule, - createDefaultSharedModule, - DefaultSharedModuleContext, - inject, - LangiumServices, - LangiumSharedServices, - Module, - PartialLangiumServices, - PartialLangiumSharedServices, + createDefaultModule, + createDefaultSharedModule, + DefaultSharedModuleContext, + inject, + LangiumServices, + LangiumSharedServices, + Module, + PartialLangiumServices, + PartialLangiumSharedServices, } from 'langium'; import { TinyDslDocumentSymbolProvider } from '../outline/tiny-dsl-document-symbol-provicer'; import { TinyDslScopeComputation } from '../scoping/scope-computation'; import { TinyDslScopeProvider } from '../scoping/scope-provider'; -import { - TinyDslGeneratedModule, - TinyDslGeneratedSharedModule, -} from './generated/module'; +import { TinyDslGeneratedModule, TinyDslGeneratedSharedModule } from './generated/module'; import { TinyDslActionProvider } from './tiny-dsl-actions'; import { TinyDslCompletionProvider } from './tiny-dsl-completions'; import { TinyDslFormatter } from './tiny-dsl-formatter'; -import { IndexAccess, TinyDslIndexManager } from './tiny-dsl-services'; import { - registerValidationChecks, - TinyDslValidator, -} from './tiny-dsl-validator'; + IndexAccess, + TinyDslIndexManager, + TinyDslLanguageServer, + TinyDslWorkspaceSymbolProvider, + WorkspaceSymbolProvider, +} from './tiny-dsl-services'; +import { registerValidationChecks, TinyDslValidator } from './tiny-dsl-validator'; /** * Declaration of custom services - add your own service classes here. @@ -35,6 +35,7 @@ export type TinyDslAddedServices = { }; workspace: { IndexAccess: IndexAccess; + WorkspaceSymbolProvider: WorkspaceSymbolProvider; }; }; @@ -65,10 +66,14 @@ export const TinyDslModule: Module new IndexAccess(services), + WorkspaceSymbolProvider: (services) => new TinyDslWorkspaceSymbolProvider(services), }, }; export const TinyDslSharedModule: Module = { + lsp: { + LanguageServer: (services) => new TinyDslLanguageServer(services), + }, workspace: { IndexManager: (services) => new TinyDslIndexManager(services), }, diff --git a/src/language-server/tiny-dsl-services.ts b/src/language-server/tiny-dsl-services.ts index 7e0020d..aad8732 100644 --- a/src/language-server/tiny-dsl-services.ts +++ b/src/language-server/tiny-dsl-services.ts @@ -1,12 +1,22 @@ import { - AstNode, - AstNodeDescription, - AstNodeLocator, - DefaultIndexManager, - IndexManager, - LangiumDocument, - LangiumDocuments, + AstNode, + AstNodeDescription, + AstNodeLocator, + DefaultIndexManager, + DefaultLanguageServer, + IndexManager, + LangiumDocument, + LangiumDocuments, + MaybePromise, } from 'langium'; +import { + CancellationToken, + InitializeParams, + InitializeResult, + SymbolKind, + WorkspaceSymbol, + WorkspaceSymbolParams, +} from 'vscode-languageserver'; import { URI } from 'vscode-uri'; import { TinyDslScopeComputation } from '../scoping/scope-computation'; @@ -70,3 +80,55 @@ export class TinyDslIndexManager extends DefaultIndexManager { return thisDocument.package === otherDocument.package; } } + +export class TinyDslLanguageServer extends DefaultLanguageServer { + override buildInitializeResult(_params: InitializeParams): InitializeResult { + const result = super.buildInitializeResult(_params); + result.capabilities.workspaceSymbolProvider = true; + return result; + } +} + +export interface WorkspaceSymbolProvider { + provideSymbols( + params: WorkspaceSymbolParams, + cancelToken?: CancellationToken, + ): MaybePromise; +} + +export class TinyDslWorkspaceSymbolProvider implements WorkspaceSymbolProvider { + constructor(protected services: TinyDslServices) { + services.shared.lsp.Connection!.onWorkspaceSymbol((params: any, token: any) => + this.provideSymbols(params, token), + ); + } + + provideSymbols(_params: WorkspaceSymbolParams, _cancelToken?: CancellationToken) { + const result: WorkspaceSymbol[] = []; + for (const element of this.services.shared.workspace.IndexManager.allElements()) { + result.push({ + name: element.name, + kind: getSymbolKind(element.type), + location: { + uri: element.documentUri.toString(), + }, + }); + } + return result; + } +} + +export function getSymbolKind(type: string): SymbolKind { + switch (type) { + case 'Import': + return SymbolKind.Package; + case 'Entity': + return SymbolKind.Class; + case 'Field': + return SymbolKind.Field; + case 'Connection': + return SymbolKind.Method; + default: + return SymbolKind.Field; + } +}