Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve unknown file type handling in language server #1455

Merged
merged 3 commits into from Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/langium/src/lsp/document-update-handler.ts
Expand Up @@ -12,6 +12,7 @@ import type { TextDocument } from '../workspace/documents.js';
import type { WorkspaceLock } from '../workspace/workspace-lock.js';
import type { LangiumSharedServices } from './lsp-services.js';
import type { WorkspaceManager } from '../workspace/workspace-manager.js';
import type { ServiceRegistry } from '../service-registry.js';

/**
* Shared service for handling text document changes and watching relevant files.
Expand All @@ -35,11 +36,13 @@ export class DefaultDocumentUpdateHandler implements DocumentUpdateHandler {
protected readonly workspaceManager: WorkspaceManager;
protected readonly documentBuilder: DocumentBuilder;
protected readonly workspaceLock: WorkspaceLock;
protected readonly serviceRegistry: ServiceRegistry;

constructor(services: LangiumSharedServices) {
this.workspaceManager = services.workspace.WorkspaceManager;
this.documentBuilder = services.workspace.DocumentBuilder;
this.workspaceLock = services.workspace.WorkspaceLock;
this.serviceRegistry = services.ServiceRegistry;

let canRegisterFileWatcher = false;
services.lsp.LanguageServer.onInitialize(params => {
Expand Down Expand Up @@ -73,6 +76,9 @@ export class DefaultDocumentUpdateHandler implements DocumentUpdateHandler {
}

protected fireDocumentUpdate(changed: URI[], deleted: URI[]): void {
// Filter out URIs that do not have a service in the registry
// Running the document builder update will fail for those URIs
changed = changed.filter(uri => this.serviceRegistry.hasServices(uri));
// Only fire the document update when the workspace manager is ready
// Otherwise, we might miss the initial indexing of the workspace
this.workspaceManager.ready.then(() => {
Expand Down
2 changes: 2 additions & 0 deletions packages/langium/src/lsp/index.ts
Expand Up @@ -15,7 +15,9 @@ export * from './default-lsp-module.js';
export * from './document-highlight-provider.js';
export * from './document-link-provider.js';
export * from './document-symbol-provider.js';
export * from './document-update-handler.js';
export * from './execute-command-handler.js';
export * from './file-operation-handler.js';
export * from './folding-range-provider.js';
export * from './formatter.js';
export * from './fuzzy-matcher.js';
Expand Down
31 changes: 14 additions & 17 deletions packages/langium/src/lsp/language-server.ts
Expand Up @@ -640,12 +640,12 @@ export function createHierarchyRequestHandler<P extends TypeHierarchySupertypesP
if (cancellationError) {
return cancellationError;
}
const language = serviceRegistry.getServices(uri);
if (!language) {
const message = `Could not find service instance for uri: '${uri.toString()}'`;
console.error(message);
throw new Error(message);
if (!serviceRegistry.hasServices(uri)) {
const errorText = `Could not find service instance for uri: '${uri}'`;
console.debug(errorText);
return responseError<E>(new Error(errorText));
}
const language = serviceRegistry.getServices(uri);
try {
return await serviceCall(language, params, cancelToken);
} catch (err) {
Expand All @@ -667,14 +667,14 @@ export function createServerRequestHandler<P extends { textDocument: TextDocumen
if (cancellationError) {
return cancellationError;
}
const language = serviceRegistry.getServices(uri);
if (!language) {
if (!serviceRegistry.hasServices(uri)) {
const errorText = `Could not find service instance for uri: '${uri}'`;
console.error(errorText);
throw new Error(errorText);
console.debug(errorText);
return responseError<E>(new Error(errorText));
}
const document = await documents.getOrCreateDocument(uri);
const language = serviceRegistry.getServices(uri);
try {
const document = await documents.getOrCreateDocument(uri);
return await serviceCall(language, document, params, cancelToken);
} catch (err) {
return responseError<E>(err);
Expand All @@ -695,16 +695,13 @@ export function createRequestHandler<P extends { textDocument: TextDocumentIdent
if (cancellationError) {
return cancellationError;
}
const language = serviceRegistry.getServices(uri);
if (!language) {
console.error(`Could not find service instance for uri: '${uri.toString()}'`);
return null;
}
const document = documents.getDocument(uri);
if (!document) {
if (!serviceRegistry.hasServices(uri)) {
console.debug(`Could not find service instance for uri: '${uri.toString()}'`);
return null;
}
const language = serviceRegistry.getServices(uri);
try {
const document = await documents.getOrCreateDocument(uri);
return await serviceCall(language, document, params, cancelToken);
} catch (err) {
return responseError<E>(err);
Expand Down
14 changes: 14 additions & 0 deletions packages/langium/src/service-registry.ts
Expand Up @@ -24,6 +24,11 @@ export interface ServiceRegistry {
*/
getServices(uri: URI): LangiumCoreServices;

/**
* Check whether services are available for the given URI.
*/
hasServices(uri: URI): boolean;

/**
* The full set of registered language services.
*/
Expand Down Expand Up @@ -78,6 +83,15 @@ export class DefaultServiceRegistry implements ServiceRegistry {
return services;
}

hasServices(uri: URI): boolean {
try {
this.getServices(uri);
return true;
} catch {
return false;
}
}

get all(): readonly LangiumCoreServices[] {
if (this.singleton !== undefined) {
return [this.singleton];
Expand Down