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

Alignment of Default Class Implementations to Interface definitions #1604

Merged
merged 6 commits into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion packages/langium/src/lsp/completion/completion-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ export interface CompletionProvider {
/**
* Handle a completion request.
*
* @param document - the document for which the completion request was triggered
* @param params - the completion parameters
* @param cancelToken - a token that can be used to cancel the request
*
* @throws `OperationCancelled` if cancellation is detected during execution
* @throws `ResponseError` if an error is detected that should be sent as response to the client
*/
Expand All @@ -131,6 +135,7 @@ export class DefaultCompletionProvider implements CompletionProvider {
protected readonly fuzzyMatcher: FuzzyMatcher;
protected readonly grammarConfig: GrammarConfig;
protected readonly astReflection: AstReflection;
readonly completionOptions?: CompletionProviderOptions;

constructor(services: LangiumServices) {
this.scopeProvider = services.references.ScopeProvider;
Expand All @@ -145,7 +150,7 @@ export class DefaultCompletionProvider implements CompletionProvider {
this.documentationProvider = services.documentation.DocumentationProvider;
}

async getCompletion(document: LangiumDocument, params: CompletionParams): Promise<CompletionList | undefined> {
async getCompletion(document: LangiumDocument, params: CompletionParams, _cancelToken?: CancellationToken): Promise<CompletionList | undefined> {
const items: CompletionItem[] = [];
const contexts = this.buildContexts(document, params.position);

Expand Down
7 changes: 6 additions & 1 deletion packages/langium/src/lsp/definition-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ export interface DefinitionProvider {
/**
* Handle a go to definition request.
*
* @param document The document in which the request was triggered.
* @param params The parameters of the request.
* @param cancelToken A cancellation token that can be used to cancel the request.
* @returns A list of location links to the definition(s) of the symbol at the given position.
*
* @throws `OperationCancelled` if cancellation is detected during execution
* @throws `ResponseError` if an error is detected that should be sent as response to the client
*/
Expand All @@ -48,7 +53,7 @@ export class DefaultDefinitionProvider implements DefinitionProvider {
this.grammarConfig = services.parser.GrammarConfig;
}

getDefinition(document: LangiumDocument, params: DefinitionParams): MaybePromise<LocationLink[] | undefined> {
getDefinition(document: LangiumDocument, params: DefinitionParams, _cancelToken?: CancellationToken): MaybePromise<LocationLink[] | undefined> {
const rootNode = document.parseResult.value;
if (rootNode.$cstNode) {
const cst = rootNode.$cstNode;
Expand Down
6 changes: 5 additions & 1 deletion packages/langium/src/lsp/document-highlight-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ export interface DocumentHighlightProvider {
/**
* Handle a document highlight request.
*
* @param document The document in which the request was received.
* @param params The parameters of the document highlight request.
* @param cancelToken A cancellation token that can be used to cancel the request.
* @returns The document highlights or `undefined` if no highlights are available.
* @throws `OperationCancelled` if cancellation is detected during execution
* @throws `ResponseError` if an error is detected that should be sent as response to the client
*/
Expand All @@ -42,7 +46,7 @@ export class DefaultDocumentHighlightProvider implements DocumentHighlightProvid
this.grammarConfig = services.parser.GrammarConfig;
}

getDocumentHighlight(document: LangiumDocument, params: DocumentHighlightParams): MaybePromise<DocumentHighlight[] | undefined> {
getDocumentHighlight(document: LangiumDocument, params: DocumentHighlightParams, _cancelToken?: CancellationToken): MaybePromise<DocumentHighlight[] | undefined> {
const rootNode = document.parseResult.value.$cstNode;
if (!rootNode) {
return undefined;
Expand Down
7 changes: 6 additions & 1 deletion packages/langium/src/lsp/document-symbol-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ export interface DocumentSymbolProvider {
/**
* Handle a document symbols request.
*
* @param document The document in the workspace.
* @param params The parameters of the request.
* @param cancelToken A cancellation token that migh be used to cancel the request.
* @returns The symbols for the given document.
*
* @throws `OperationCancelled` if cancellation is detected during execution
* @throws `ResponseError` if an error is detected that should be sent as response to the client
*/
Expand All @@ -37,7 +42,7 @@ export class DefaultDocumentSymbolProvider implements DocumentSymbolProvider {
this.nodeKindProvider = services.shared.lsp.NodeKindProvider;
}

getSymbols(document: LangiumDocument): MaybePromise<DocumentSymbol[]> {
getSymbols(document: LangiumDocument, _params: DocumentSymbolParams, _cancelToken?: CancellationToken): MaybePromise<DocumentSymbol[]> {
return this.getSymbol(document, document.parseResult.value);
}

Expand Down
44 changes: 44 additions & 0 deletions packages/langium/src/lsp/document-update-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,46 @@ import type { MaybePromise } from '../utils/promise-utils.js';
*/
export interface DocumentUpdateHandler {

/**
* A document open event was triggered by the `TextDocuments` service.
* @param event The document change event.
*/
didOpenDocument?(event: TextDocumentChangeEvent<TextDocument>): void;

/**
* A content change event was triggered by the `TextDocuments` service.
* @param event The document change event.
*/
didChangeContent?(event: TextDocumentChangeEvent<TextDocument>): void;

/**
* A document save event (initiated) was triggered by the `TextDocuments` service.
* @param event The document change event.
*/
willSaveDocument?(event: TextDocumentWillSaveEvent<TextDocument>): void;

/**
* A docuemnt save event (initiated) was triggered by the `TextDocuments` service.
snarkipus marked this conversation as resolved.
Show resolved Hide resolved
* @param event The document change event.
* @returns An array of text edits which will be applied to the document before it is saved.
*/
willSaveDocumentWaitUntil?(event: TextDocumentWillSaveEvent<TextDocument>): MaybePromise<TextEdit[]>;

/**
* A docuemnt save event (completed) was triggered by the `TextDocuments` service.
snarkipus marked this conversation as resolved.
Show resolved Hide resolved
* @param event The document change event.
*/
didSaveDocument?(event: TextDocumentChangeEvent<TextDocument>): void;

/**
* A docuemnt close event was triggered by the `TextDocuments` service.
snarkipus marked this conversation as resolved.
Show resolved Hide resolved
* @param event The document change event.
*/
didCloseDocument?(event: TextDocumentChangeEvent<TextDocument>): void;

/**
* The client detected changes to files and folders watched by the language client.
* @param params The files/folders change event.
*/
didChangeWatchedFiles?(params: DidChangeWatchedFilesParams): void;

Expand Down Expand Up @@ -119,4 +142,25 @@ export class DefaultDocumentUpdateHandler implements DocumentUpdateHandler {
this.fireDocumentUpdate(changedUris, deletedUris);
}

didOpenDocument(_event: TextDocumentChangeEvent<TextDocument>): void {
snarkipus marked this conversation as resolved.
Show resolved Hide resolved
// To be implemented by subclasses if needed
}

willSaveDocument(_event: TextDocumentWillSaveEvent<TextDocument>): void {
// To be implemented by subclasses if needed
}

willSaveWaitUntilDocument(_event: TextDocumentWillSaveEvent<TextDocument>): MaybePromise<TextEdit[]> {
// To be implemented by subclasses if needed
return [];
}

didSaveDocument(_event: TextDocumentChangeEvent<TextDocument>): void {
// To be implemented by subclasses if needed
}

didCloseDocument(_event: TextDocumentChangeEvent<TextDocument>): void {
// To be implemented by subclasses if needed
}

}
13 changes: 8 additions & 5 deletions packages/langium/src/lsp/folding-range-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ export interface FoldingRangeProvider {
/**
* Handle a folding range request.
*
* @param document The document to compute folding ranges for
* @param params The folding range parameters
* @param cancelToken A cancellation token that can be used to cancel the request
* @returns The computed folding ranges
*
* @throws `OperationCancelled` if cancellation is detected during execution
* @throws `ResponseError` if an error is detected that should be sent as response to the client
*/
Expand All @@ -37,7 +42,7 @@ export class DefaultFoldingRangeProvider implements FoldingRangeProvider {
this.commentNames = services.parser.GrammarConfig.multilineCommentRules;
}

getFoldingRanges(document: LangiumDocument): MaybePromise<FoldingRange[]> {
getFoldingRanges(document: LangiumDocument, _params: FoldingRangeParams, _cancelToken?: CancellationToken): MaybePromise<FoldingRange[]> {
const foldings: FoldingRange[] = [];
const acceptor: FoldingRangeAcceptor = (foldingRange) => foldings.push(foldingRange);
this.collectFolding(document, acceptor);
Expand Down Expand Up @@ -73,8 +78,7 @@ export class DefaultFoldingRangeProvider implements FoldingRangeProvider {
* Returns true by default for all nodes. Returning false only ignores the specified node and not its content.
* To ignore the content of a node use `shouldProcessContent`.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
protected shouldProcess(node: AstNode): boolean {
protected shouldProcess(_node: AstNode): boolean {
return true;
}

Expand All @@ -83,8 +87,7 @@ export class DefaultFoldingRangeProvider implements FoldingRangeProvider {
* Returns true by default for all nodes. Returning false ignores _all_ content of this node, even transitive ones.
* For more precise control over foldings use the `shouldProcess` method.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
protected shouldProcessContent(node: AstNode): boolean {
protected shouldProcessContent(_node: AstNode): boolean {
return true;
}

Expand Down
7 changes: 6 additions & 1 deletion packages/langium/src/lsp/references-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ export interface ReferencesProvider {
/**
* Handle a find references request.
*
* @param document The document in which to search for references.
* @param params The parameters of the find references request.
* @param cancelToken A cancellation token that can be used to cancel the request.
* @returns The locations of the references.
*
* @throws `OperationCancelled` if cancellation is detected during execution
* @throws `ResponseError` if an error is detected that should be sent as response to the client
*/
Expand All @@ -40,7 +45,7 @@ export class DefaultReferencesProvider implements ReferencesProvider {
this.grammarConfig = services.parser.GrammarConfig;
}

findReferences(document: LangiumDocument, params: ReferenceParams): MaybePromise<Location[]> {
findReferences(document: LangiumDocument, params: ReferenceParams, _cancelToken?: CancellationToken): MaybePromise<Location[]> {
const rootNode = document.parseResult.value.$cstNode;
if (!rootNode) {
return [];
Expand Down
14 changes: 12 additions & 2 deletions packages/langium/src/lsp/rename-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ export interface RenameProvider {
/**
* Handle a rename request.
*
* @param document The document in which the rename request was triggered.
* @param params The rename parameters.
* @param cancelToken A cancellation token that can be used to cancel the request.
* @returns A workspace edit that describes the changes to be applied to the workspace.
*
* @throws `OperationCancelled` if cancellation is detected during execution
* @throws `ResponseError` if an error is detected that should be sent as response to the client
*/
Expand All @@ -32,6 +37,11 @@ export interface RenameProvider {
/**
* Handle a prepare rename request.
*
* @param document The document in which the prepare rename request was triggered.
* @param params The prepare rename parameters.
* @param cancelToken A cancellation token that can be used to cancel the request.
* @returns A range that describes the range of the symbol to be renamed.
*
* @throws `OperationCancelled` if cancellation is detected during execution
* @throws `ResponseError` if an error is detected that should be sent as response to the client
*/
Expand All @@ -50,7 +60,7 @@ export class DefaultRenameProvider implements RenameProvider {
this.grammarConfig = services.parser.GrammarConfig;
}

async rename(document: LangiumDocument, params: RenameParams): Promise<WorkspaceEdit | undefined> {
async rename(document: LangiumDocument, params: RenameParams, _cancelToken?: CancellationToken): Promise<WorkspaceEdit | undefined> {
const changes: Record<string, TextEdit[]> = {};
const rootNode = document.parseResult.value.$cstNode;
if (!rootNode) return undefined;
Expand All @@ -73,7 +83,7 @@ export class DefaultRenameProvider implements RenameProvider {
return { changes };
}

prepareRename(document: LangiumDocument, params: TextDocumentPositionParams): MaybePromise<Range | undefined> {
prepareRename(document: LangiumDocument, params: TextDocumentPositionParams, _cancelToken?: CancellationToken): MaybePromise<Range | undefined> {
return this.renameNodeRange(document, params.position);
}

Expand Down
18 changes: 16 additions & 2 deletions packages/langium/src/lsp/workspace-symbol-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,21 @@ export interface WorkspaceSymbolProvider {
/**
* Handle a workspace symbols request.
*
* @param params workspaces symbols request parameters
* @param cancelToken a cancellation token tha can be used to cancel the request
* @returns a list of workspace symbols
*
* @throws `OperationCancelled` if cancellation is detected during execution
* @throws `ResponseError` if an error is detected that should be sent as response to the client
*/
getSymbols(params: WorkspaceSymbolParams, cancelToken?: CancellationToken): MaybePromise<WorkspaceSymbol[]>;
/**
* Handle a resolve request for a workspace symbol.
*
* @param symbol the workspace symbol to resolve
* @param cancelToken a cancellation token tha can be used to cancel the request
* @returns the resolved workspace symbol
*
* @throws `OperationCancelled` if cancellation is detected during execution
* @throws `ResponseError` if an error is detected that should be sent as response to the client
*/
Expand All @@ -46,11 +54,12 @@ export class DefaultWorkspaceSymbolProvider implements WorkspaceSymbolProvider {
this.fuzzyMatcher = services.lsp.FuzzyMatcher;
}

async getSymbols(params: WorkspaceSymbolParams, cancelToken = CancellationToken.None): Promise<WorkspaceSymbol[]> {
async getSymbols(params: WorkspaceSymbolParams, cancelToken?: CancellationToken): Promise<WorkspaceSymbol[]> {
const token = cancelToken ?? CancellationToken.None;
snarkipus marked this conversation as resolved.
Show resolved Hide resolved
const workspaceSymbols: WorkspaceSymbol[] = [];
const query = params.query.toLowerCase();
for (const description of this.indexManager.allElements()) {
await interruptAndCheck(cancelToken);
await interruptAndCheck(token);
if (this.fuzzyMatcher.match(query, description.name)) {
const symbol = this.getWorkspaceSymbol(description);
if (symbol) {
Expand All @@ -76,4 +85,9 @@ export class DefaultWorkspaceSymbolProvider implements WorkspaceSymbolProvider {
return undefined;
}
}

async resolveSymbol(symbol: WorkspaceSymbol, _cancelToken?: CancellationToken): Promise<WorkspaceSymbol> {
snarkipus marked this conversation as resolved.
Show resolved Hide resolved
// no-op by default, override to implement custom symbol resolution
return symbol;
}
}
22 changes: 15 additions & 7 deletions packages/langium/src/parser/async-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,28 @@ import { Deferred, OperationCancelled } from '../utils/promise-utils.js';
import { Emitter } from '../utils/event.js';

/**
* Async parser that allows to cancel the current parsing process.
* The sync parser implementation is blocking the event loop, which can become quite problematic for large files.
* Async parser that allows cancellation of the current parsing process.
*
* Note that the default implementation is not actually async. It just wraps the sync parser in a promise.
* A real implementation would create worker threads or web workers to offload the parsing work.
* @remark The sync parser implementation is blocking the event loop, which can become quite problematic for large files.
* @remark The default implementation is not actually async. It just wraps the sync parser in a promise. A real implementation would create worker threads or web workers to offload the parsing work.
*/
export interface AsyncParser {
/**
* Parses the given text and returns the parse result.
*
* @param text The text to parse.
* @param cancelToken A cancellation token that can be used to cancel the parsing process.
* @returns A promise that resolves to the parse result.
*
* @throw `OperationCancelled` if the parsing process is cancelled.
*/
parse<T extends AstNode>(text: string, cancelToken: CancellationToken): Promise<ParseResult<T>>;
}

/**
* Default implementation of the async parser. This implementation only wraps the sync parser in a promise.
* Default implementation of the async parser which simply wraps the sync parser in a promise.
*
* A real implementation would create worker threads or web workers to offload the parsing work.
* @remark A real implementation would create worker threads or web workers to offload the parsing work.
*/
export class DefaultAsyncParser implements AsyncParser {

Expand All @@ -37,7 +45,7 @@ export class DefaultAsyncParser implements AsyncParser {
this.syncParser = services.parser.LangiumParser;
}

parse<T extends AstNode>(text: string): Promise<ParseResult<T>> {
parse<T extends AstNode>(text: string, _cancelToken: CancellationToken): Promise<ParseResult<T>> {
return Promise.resolve(this.syncParser.parse<T>(text));
}
}
Expand Down
7 changes: 5 additions & 2 deletions packages/langium/src/references/linker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ export interface Linker {
*
* @param document A LangiumDocument that shall be linked.
* @param cancelToken A token for cancelling the operation.
*
* @throws `OperationCancelled` if a cancellation event is detected
*/
link(document: LangiumDocument, cancelToken?: CancellationToken): Promise<void>;

Expand Down Expand Up @@ -87,9 +89,10 @@ export class DefaultLinker implements Linker {
this.astNodeLocator = services.workspace.AstNodeLocator;
}

async link(document: LangiumDocument, cancelToken = CancellationToken.None): Promise<void> {
async link(document: LangiumDocument, cancelToken?: CancellationToken): Promise<void> {
const token = cancelToken ?? CancellationToken.None;
for (const node of streamAst(document.parseResult.value)) {
await interruptAndCheck(cancelToken);
await interruptAndCheck(token);
streamReferences(node).forEach(ref => this.doLink(ref, document));
}
}
Expand Down
5 changes: 3 additions & 2 deletions packages/langium/src/references/scope-computation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,12 +111,13 @@ export class DefaultScopeComputation implements ScopeComputation {
}
}

async computeLocalScopes(document: LangiumDocument, cancelToken = CancellationToken.None): Promise<PrecomputedScopes> {
async computeLocalScopes(document: LangiumDocument, cancelToken?: CancellationToken): Promise<PrecomputedScopes> {
const token = cancelToken ?? CancellationToken.None;
const rootNode = document.parseResult.value;
const scopes = new MultiMap<AstNode, AstNodeDescription>();
// Here we navigate the full AST - local scopes shall be available in the whole document
for (const node of streamAllContents(rootNode)) {
await interruptAndCheck(cancelToken);
await interruptAndCheck(token);
this.processNode(node, document, scopes);
}
return scopes;
Expand Down
Loading
Loading