First commit.

Signed-off-by: Chen Xiao <abigwc@gmail.com>
This commit is contained in:
Chen Xiao
2026-05-08 14:43:16 +08:00
commit 0b64e2de94
10989 changed files with 2253791 additions and 0 deletions
+45
View File
@@ -0,0 +1,45 @@
/******************************************************************************
* Copyright 2022 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 { 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 './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';
import type { LangiumDocument, LangiumDocuments } from '../workspace/documents.js';
import type { MaybePromise } from '../utils/promise-utils.js';
/**
* Language-specific service for handling call hierarchy requests.
*/
export interface CallHierarchyProvider {
prepareCallHierarchy(document: LangiumDocument, params: CallHierarchyPrepareParams, cancelToken?: CancellationToken): MaybePromise<CallHierarchyItem[] | undefined>;
incomingCalls(params: CallHierarchyIncomingCallsParams, cancelToken?: CancellationToken): MaybePromise<CallHierarchyIncomingCall[] | undefined>;
outgoingCalls(params: CallHierarchyOutgoingCallsParams, cancelToken?: CancellationToken): MaybePromise<CallHierarchyOutgoingCall[] | undefined>;
}
export declare abstract class AbstractCallHierarchyProvider implements CallHierarchyProvider {
protected readonly grammarConfig: GrammarConfig;
protected readonly nameProvider: NameProvider;
protected readonly documents: LangiumDocuments;
protected readonly references: References;
constructor(services: LangiumServices);
prepareCallHierarchy(document: LangiumDocument<AstNode>, params: CallHierarchyPrepareParams): MaybePromise<CallHierarchyItem[] | undefined>;
protected getCallHierarchyItems(targetNode: AstNode, document: LangiumDocument<AstNode>): CallHierarchyItem[] | undefined;
protected getCallHierarchyItem(_targetNode: AstNode): Partial<CallHierarchyItem> | undefined;
incomingCalls(params: CallHierarchyIncomingCallsParams): Promise<CallHierarchyIncomingCall[] | undefined>;
/**
* Override this method to collect the incoming calls for your language
*/
protected abstract getIncomingCalls(node: AstNode, references: Stream<ReferenceDescription>): MaybePromise<CallHierarchyIncomingCall[] | undefined>;
outgoingCalls(params: CallHierarchyOutgoingCallsParams): Promise<CallHierarchyOutgoingCall[] | undefined>;
/**
* Override this method to collect the outgoing calls for your language
*/
protected abstract getOutgoingCalls(node: AstNode): MaybePromise<CallHierarchyOutgoingCall[] | undefined>;
}
//# sourceMappingURL=call-hierarchy-provider.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"call-hierarchy-provider.d.ts","sourceRoot":"","sources":["../../src/lsp/call-hierarchy-provider.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EAAE,yBAAyB,EAAE,gCAAgC,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,gCAAgC,EAAE,0BAA0B,EAAI,MAAM,uBAAuB,CAAC;AACvN,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AAC7E,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACnF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAK9D;;GAEG;AACH,MAAM,WAAW,qBAAqB;IAClC,oBAAoB,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,0BAA0B,EAAE,WAAW,CAAC,EAAE,iBAAiB,GAAG,YAAY,CAAC,iBAAiB,EAAE,GAAG,SAAS,CAAC,CAAC;IAEpK,aAAa,CAAC,MAAM,EAAE,gCAAgC,EAAE,WAAW,CAAC,EAAE,iBAAiB,GAAG,YAAY,CAAC,yBAAyB,EAAE,GAAG,SAAS,CAAC,CAAC;IAEhJ,aAAa,CAAC,MAAM,EAAE,gCAAgC,EAAE,WAAW,CAAC,EAAE,iBAAiB,GAAG,YAAY,CAAC,yBAAyB,EAAE,GAAG,SAAS,CAAC,CAAC;CACnJ;AAED,8BAAsB,6BAA8B,YAAW,qBAAqB;IAChF,SAAS,CAAC,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IAChD,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IAC9C,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAC;IAC/C,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;gBAE9B,QAAQ,EAAE,eAAe;IAOrC,oBAAoB,CAAC,QAAQ,EAAE,eAAe,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,0BAA0B,GAAG,YAAY,CAAC,iBAAiB,EAAE,GAAG,SAAS,CAAC;IAuB3I,SAAS,CAAC,qBAAqB,CAAC,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,eAAe,CAAC,OAAO,CAAC,GAAG,iBAAiB,EAAE,GAAG,SAAS;IAiBzH,SAAS,CAAC,oBAAoB,CAAC,WAAW,EAAE,OAAO,GAAG,OAAO,CAAC,iBAAiB,CAAC,GAAG,SAAS;IAItF,aAAa,CAAC,MAAM,EAAE,gCAAgC,GAAG,OAAO,CAAC,yBAAyB,EAAE,GAAG,SAAS,CAAC;IAqB/G;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,CAAC,oBAAoB,CAAC,GAAG,YAAY,CAAC,yBAAyB,EAAE,GAAG,SAAS,CAAC;IAE7I,aAAa,CAAC,MAAM,EAAE,gCAAgC,GAAG,OAAO,CAAC,yBAAyB,EAAE,GAAG,SAAS,CAAC;IAc/G;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,YAAY,CAAC,yBAAyB,EAAE,GAAG,SAAS,CAAC;CAC5G"}
+72
View File
@@ -0,0 +1,72 @@
/******************************************************************************
* Copyright 2022 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 { SymbolKind } from 'vscode-languageserver';
import { findDeclarationNodeAtOffset } from '../utils/cst-utils.js';
import { URI } from '../utils/uri-utils.js';
export class AbstractCallHierarchyProvider {
constructor(services) {
this.grammarConfig = services.parser.GrammarConfig;
this.nameProvider = services.references.NameProvider;
this.documents = services.shared.workspace.LangiumDocuments;
this.references = services.references.References;
}
prepareCallHierarchy(document, params) {
const rootNode = document.parseResult.value;
const targetNode = findDeclarationNodeAtOffset(rootNode.$cstNode, document.textDocument.offsetAt(params.position), this.grammarConfig.nameRegexp);
if (!targetNode) {
return undefined;
}
const declarationNodes = this.references.findDeclarationNodes(targetNode);
if (!declarationNodes) {
return undefined;
}
const items = [];
for (const declarationNode of declarationNodes) {
items.push(...(this.getCallHierarchyItems(declarationNode.astNode, document) ?? []));
}
return items;
}
getCallHierarchyItems(targetNode, document) {
const nameNode = this.nameProvider.getNameNode(targetNode);
const name = this.nameProvider.getName(targetNode);
if (!nameNode || !targetNode.$cstNode || name === undefined) {
return undefined;
}
return [{
kind: SymbolKind.Method,
name,
range: targetNode.$cstNode.range,
selectionRange: nameNode.range,
uri: document.uri.toString(),
...this.getCallHierarchyItem(targetNode)
}];
}
getCallHierarchyItem(_targetNode) {
return undefined;
}
async incomingCalls(params) {
const document = await this.documents.getOrCreateDocument(URI.parse(params.item.uri));
const rootNode = document.parseResult.value;
const targetNode = findDeclarationNodeAtOffset(rootNode.$cstNode, document.textDocument.offsetAt(params.item.range.start), this.grammarConfig.nameRegexp);
if (!targetNode) {
return undefined;
}
const references = this.references.findReferences(targetNode.astNode, {
includeDeclaration: false
});
return this.getIncomingCalls(targetNode.astNode, references);
}
async outgoingCalls(params) {
const document = await this.documents.getOrCreateDocument(URI.parse(params.item.uri));
const rootNode = document.parseResult.value;
const targetNode = findDeclarationNodeAtOffset(rootNode.$cstNode, document.textDocument.offsetAt(params.item.range.start), this.grammarConfig.nameRegexp);
if (!targetNode) {
return undefined;
}
return this.getOutgoingCalls(targetNode.astNode);
}
}
//# sourceMappingURL=call-hierarchy-provider.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"call-hierarchy-provider.js","sourceRoot":"","sources":["../../src/lsp/call-hierarchy-provider.ts"],"names":[],"mappings":"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"}
+19
View File
@@ -0,0 +1,19 @@
/******************************************************************************
* Copyright 2021 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 { 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';
export interface CodeActionProvider {
/**
* Handle a code action 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
*/
getCodeActions(document: LangiumDocument, params: CodeActionParams, cancelToken?: CancellationToken): MaybePromise<Array<Command | CodeAction> | undefined>;
}
//# sourceMappingURL=code-action.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"code-action.d.ts","sourceRoot":"","sources":["../../src/lsp/code-action.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACnF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAEjE,MAAM,WAAW,kBAAkB;IAC/B;;;;;OAKG;IACH,cAAc,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,gBAAgB,EAAE,WAAW,CAAC,EAAE,iBAAiB,GAAG,YAAY,CAAC,KAAK,CAAC,OAAO,GAAG,UAAU,CAAC,GAAG,SAAS,CAAC,CAAC;CAC/J"}
+7
View File
@@ -0,0 +1,7 @@
/******************************************************************************
* Copyright 2021 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.
******************************************************************************/
export {};
//# sourceMappingURL=code-action.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"code-action.js","sourceRoot":"","sources":["../../src/lsp/code-action.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF"}
+13
View File
@@ -0,0 +1,13 @@
/******************************************************************************
* Copyright 2022 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 { 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';
export interface CodeLensProvider {
provideCodeLens(document: LangiumDocument, params: CodeLensParams, cancelToken?: CancellationToken): MaybePromise<CodeLens[] | undefined>;
}
//# sourceMappingURL=code-lens-provider.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"code-lens-provider.d.ts","sourceRoot":"","sources":["../../src/lsp/code-lens-provider.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAEjE,MAAM,WAAW,gBAAgB;IAC7B,eAAe,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,cAAc,EAAE,WAAW,CAAC,EAAE,iBAAiB,GAAG,YAAY,CAAC,QAAQ,EAAE,GAAG,SAAS,CAAC,CAAA;CAC5I"}
+7
View File
@@ -0,0 +1,7 @@
/******************************************************************************
* Copyright 2022 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.
******************************************************************************/
export {};
//# sourceMappingURL=code-lens-provider.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"code-lens-provider.js","sourceRoot":"","sources":["../../src/lsp/code-lens-provider.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF"}
+178
View File
@@ -0,0 +1,178 @@
/******************************************************************************
* Copyright 2021 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 { 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 '../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, 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';
import type { GrammarConfig } from '../../languages/grammar-config.js';
import type { Lexer } from '../../parser/lexer.js';
import type { DocumentationProvider } from '../../documentation/documentation-provider.js';
import type { MarkupContent } from 'vscode-languageserver';
import { CompletionItemKind, CompletionList, Position } from 'vscode-languageserver';
import * as ast from '../../languages/generated/ast.js';
import { type Stream } from '../../utils/stream.js';
export type CompletionAcceptor = (context: CompletionContext, value: CompletionValueItem) => void;
export type CompletionValueItem = ({
label?: string;
} | {
node: AstNode;
} | {
nodeDescription: AstNodeDescription;
}) & Partial<CompletionItem>;
export interface CompletionContext {
node?: AstNode;
document: LangiumDocument;
textDocument: TextDocument;
features: NextFeature[];
/**
* Index at the start of the token related to this context.
* If the context performs completion for a token that doesn't exist yet, it is equal to the `offset`.
*/
tokenOffset: number;
/**
* Index at the end of the token related to this context, even if it is behind the cursor position.
* Points at the first character after the last token.
* If the context performs completion for a token that doesn't exist yet, it is equal to the `offset`.
*/
tokenEndOffset: number;
/**
* Index of the requested completed position.
*/
offset: number;
position: Position;
}
export interface CompletionProviderOptions {
/**
* Most tools trigger completion request automatically without explicitly requesting
* it using a keyboard shortcut (e.g. Ctrl+Space). Typically they do so when the user
* starts to type an identifier. For example if the user types `c` in a JavaScript file
* code complete will automatically pop up present `console` besides others as a
* completion item. Characters that make up identifiers don't need to be listed here.
*
* If code complete should automatically be trigger on characters not being valid inside
* an identifier (for example `.` in JavaScript) list them in `triggerCharacters`.
*/
triggerCharacters?: string[];
/**
* The list of all possible characters that commit a completion. This field can be used
* if clients don't support individual commit characters per completion item.
*
* If a server provides both `allCommitCharacters` and commit characters on an individual
* completion item the ones on the completion item win.
*/
allCommitCharacters?: string[];
}
export interface CompletionBacktrackingInformation {
previousTokenStart?: number;
previousTokenEnd?: number;
nextTokenStart: number;
nextTokenEnd: number;
}
export declare function mergeCompletionProviderOptions(options: Array<CompletionProviderOptions | undefined>): CompletionProviderOptions;
/**
* Language-specific service for handling completion requests.
*/
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
*/
getCompletion(document: LangiumDocument, params: CompletionParams, cancelToken?: CancellationToken): MaybePromise<CompletionList | undefined>;
/**
* Contains the completion options for this completion provider.
*
* If multiple languages return different options, they are merged before being sent to the language client.
*/
readonly completionOptions?: CompletionProviderOptions;
}
export declare class DefaultCompletionProvider implements CompletionProvider {
protected readonly completionParser: LangiumCompletionParser;
protected readonly documentationProvider: DocumentationProvider;
protected readonly scopeProvider: ScopeProvider;
protected readonly grammar: ast.Grammar;
protected readonly nameProvider: NameProvider;
protected readonly lexer: Lexer;
protected readonly nodeKindProvider: NodeKindProvider;
protected readonly fuzzyMatcher: FuzzyMatcher;
protected readonly grammarConfig: GrammarConfig;
protected readonly astReflection: AstReflection;
readonly completionOptions?: CompletionProviderOptions;
constructor(services: LangiumServices);
getCompletion(document: LangiumDocument, params: CompletionParams, _cancelToken?: CancellationToken): Promise<CompletionList | undefined>;
/**
* The completion algorithm could yield the same reference/keyword multiple times.
*
* This methods deduplicates these items afterwards before returning to the client.
* Unique items are identified as a combination of `kind`, `label` and `detail`.
*/
protected deduplicateItems(items: CompletionItem[]): CompletionItem[];
protected findFeaturesAt(document: TextDocument, offset: number): NextFeature[];
protected buildSyntheticEntryRuleCall(rule: ast.ParserRule): NextFeature;
protected buildContexts(document: LangiumDocument, position: Position): IterableIterator<CompletionContext>;
protected performNextTokenCompletion(document: LangiumDocument, text: string, _offset: number, _end: number): boolean;
protected findDataTypeRuleStart(cst: CstNode, offset: number): [number, number] | undefined;
/**
* Indicates whether the completion should continue to process the next completion context.
*
* The default implementation continues the completion only if there are currently no proposed completion items.
*/
protected continueCompletion(items: CompletionItem[]): boolean;
/**
* This method returns two sets of token offset information.
*
* The `nextToken*` offsets are related to the token at the cursor position.
* If there is none, both offsets are simply set to `offset`.
*
* The `previousToken*` offsets are related to the last token before the current token at the cursor position.
* They are `undefined`, if there is no token before the cursor position.
*/
protected backtrackToAnyToken(text: string, offset: number): CompletionBacktrackingInformation;
protected completionFor(context: CompletionContext, next: NextFeature, acceptor: CompletionAcceptor): MaybePromise<void>;
protected completionForCrossReference(context: CompletionContext, next: NextFeature<ast.CrossReference>, acceptor: CompletionAcceptor): MaybePromise<void>;
/**
* Override this method to change how the stream of candidates is determined for a reference.
* This way completion-specific modifications and refinements can be added to the proposals computation
* beyond the rules being implemented in the scope provider, e.g. filtering.
*
* @param refInfo Information about the reference for which the candidates are requested.
* @param _context Information about the completion request including document, cursor position, token under cursor, etc.
* @returns A stream of all elements being valid for the given reference.
*/
protected getReferenceCandidates(refInfo: ReferenceInfo, _context: CompletionContext): Stream<AstNodeDescription>;
/**
* Override this method to change how reference completion items are created.
*
* To change the `kind` of a completion item, override the `NodeKindProvider` service instead.
* To change the `documentation`, override the `DocumentationProvider` service instead.
*
* @param nodeDescription The description of a reference candidate
* @param _refInfo Information about the reference for which the candidate is proposed
* @param _context The completion context
* @returns A partial completion item
*/
protected createReferenceCompletionItem(nodeDescription: AstNodeDescription, _refInfo: ReferenceInfo, _context: CompletionContext): CompletionValueItem;
protected getReferenceDocumentation(nodeDescription: AstNodeDescription): MarkupContent | string | undefined;
protected completionForKeyword(context: CompletionContext, keyword: ast.Keyword, acceptor: CompletionAcceptor): MaybePromise<void>;
protected getKeywordCompletionItemKind(_keyword: ast.Keyword): CompletionItemKind;
protected filterKeyword(context: CompletionContext, keyword: ast.Keyword): boolean;
protected fillCompletionItem(context: CompletionContext, item: CompletionValueItem): CompletionItem | undefined;
protected buildCompletionTextEdit(context: CompletionContext, label: string, newText: string): TextEdit | undefined;
}
//# sourceMappingURL=completion-provider.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"completion-provider.d.ts","sourceRoot":"","sources":["../../../src/lsp/completion/completion-provider.ts"],"names":[],"mappings":"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"}
+478
View File
@@ -0,0 +1,478 @@
/******************************************************************************
* Copyright 2021 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 { CompletionItemKind, CompletionList, Position } from 'vscode-languageserver';
import * as ast from '../../languages/generated/ast.js';
import { assignMandatoryProperties, getContainerOfType } from '../../utils/ast-utils.js';
import { findDeclarationNodeAtOffset, findLeafNodeBeforeOffset, getDatatypeNode } from '../../utils/cst-utils.js';
import { getEntryRule } from '../../utils/grammar-utils.js';
import { stream } from '../../utils/stream.js';
import { findFirstFeatures, findNextFeatures } from './follow-element-computation.js';
export function mergeCompletionProviderOptions(options) {
const triggerCharacters = Array.from(new Set(options.flatMap(option => option?.triggerCharacters ?? [])));
const allCommitCharacters = Array.from(new Set(options.flatMap(option => option?.allCommitCharacters ?? [])));
return {
triggerCharacters: triggerCharacters.length > 0 ? triggerCharacters : undefined,
allCommitCharacters: allCommitCharacters.length > 0 ? allCommitCharacters : undefined
};
}
export class DefaultCompletionProvider {
constructor(services) {
this.scopeProvider = services.references.ScopeProvider;
this.grammar = services.Grammar;
this.completionParser = services.parser.CompletionParser;
this.nameProvider = services.references.NameProvider;
this.lexer = services.parser.Lexer;
this.nodeKindProvider = services.shared.lsp.NodeKindProvider;
this.fuzzyMatcher = services.shared.lsp.FuzzyMatcher;
this.grammarConfig = services.parser.GrammarConfig;
this.astReflection = services.shared.AstReflection;
this.documentationProvider = services.documentation.DocumentationProvider;
}
async getCompletion(document, params, _cancelToken) {
const items = [];
const contexts = this.buildContexts(document, params.position);
const acceptor = (context, value) => {
const completionItem = this.fillCompletionItem(context, value);
if (completionItem) {
items.push(completionItem);
}
};
const distinctionFunction = (element) => {
if (ast.isKeyword(element.feature)) {
return element.feature.value;
}
else {
return element.feature;
}
};
const completedFeatures = [];
for (const context of contexts) {
await Promise.all(stream(context.features)
.distinct(distinctionFunction)
.exclude(completedFeatures)
.map(e => this.completionFor(context, e, acceptor)));
// Do not try to complete the same feature multiple times
completedFeatures.push(...context.features);
// We might want to stop computing completion results
if (!this.continueCompletion(items)) {
break;
}
}
return CompletionList.create(this.deduplicateItems(items), true);
}
/**
* The completion algorithm could yield the same reference/keyword multiple times.
*
* This methods deduplicates these items afterwards before returning to the client.
* Unique items are identified as a combination of `kind`, `label` and `detail`.
*/
deduplicateItems(items) {
return stream(items).distinct(item => `${item.kind}_${item.label}_${item.detail}`).toArray();
}
findFeaturesAt(document, offset) {
const text = document.getText({
start: Position.create(0, 0),
end: document.positionAt(offset)
});
const parserResult = this.completionParser.parse(text);
const tokens = parserResult.tokens;
// If the parser didn't parse any tokens, return the next features of the entry rule
if (parserResult.tokenIndex === 0) {
const parserRule = getEntryRule(this.grammar);
// Generate a synthetic RuleCall to the entry rule
const syntheticEntryRuleCall = this.buildSyntheticEntryRuleCall(parserRule);
return findNextFeatures([[syntheticEntryRuleCall]], tokens);
}
const leftoverTokens = [...tokens].splice(parserResult.tokenIndex);
const features = findNextFeatures([parserResult.elementStack.map(feature => ({ feature }))], leftoverTokens);
return features;
}
buildSyntheticEntryRuleCall(rule) {
// The "start" node is simply an empty group that is followed by the rule call
const start = {
$type: 'Group',
$container: undefined,
elements: []
};
const startNext = {
feature: start
};
// This is the element that we want to complete
const ruleCall = {
$type: 'RuleCall',
$container: undefined,
rule: {
ref: rule,
$refText: rule.name
},
arguments: []
};
const group = {
$type: 'Group',
$container: undefined,
elements: [
start,
ruleCall
]
};
start.$container = group;
ruleCall.$container = group;
return startNext;
}
*buildContexts(document, position) {
const cst = document.parseResult.value.$cstNode;
if (!cst) {
return;
}
const textDocument = document.textDocument;
const text = textDocument.getText();
const offset = textDocument.offsetAt(position);
const partialContext = {
document,
textDocument,
offset,
position
};
// Data type rules need special handling, as their tokens are irrelevant for completion purposes.
// If we encounter a data type rule at the current offset, we jump to the start of the data type rule.
const dataTypeRuleOffsets = this.findDataTypeRuleStart(cst, offset);
if (dataTypeRuleOffsets) {
const [ruleStart, ruleEnd] = dataTypeRuleOffsets;
const parentNode = findLeafNodeBeforeOffset(cst, ruleStart)?.astNode;
yield {
...partialContext,
node: parentNode,
tokenOffset: ruleStart,
tokenEndOffset: ruleEnd,
features: this.findFeaturesAt(textDocument, ruleStart),
};
}
// For all other purposes, it's enough to jump to the start of the current/previous token
const { nextTokenStart, nextTokenEnd, previousTokenStart, previousTokenEnd } = this.backtrackToAnyToken(text, offset);
let astNodeOffset = nextTokenStart;
if (offset <= nextTokenStart && previousTokenStart !== undefined) {
// This check indicates that the cursor is still before the next token, so we should use the previous AST node (if it exists)
astNodeOffset = previousTokenStart;
}
const astNode = findLeafNodeBeforeOffset(cst, astNodeOffset)?.astNode;
let performNextCompletion = true;
if (previousTokenStart !== undefined && previousTokenEnd !== undefined && previousTokenEnd === offset) {
// This context aims to complete the current feature
yield {
...partialContext,
node: astNode,
tokenOffset: previousTokenStart,
tokenEndOffset: previousTokenEnd,
features: this.findFeaturesAt(textDocument, previousTokenStart),
};
// The completion after the current token should be prevented in case we find out that the current token definitely isn't completed yet
// This is usually the case when the current token ends on a letter.
performNextCompletion = this.performNextTokenCompletion(document, text.substring(previousTokenStart, previousTokenEnd), previousTokenStart, previousTokenEnd);
if (performNextCompletion) {
// This context aims to complete the immediate next feature (if one exists at the current cursor position)
// It uses the previous cst start/offset for that.
yield {
...partialContext,
node: astNode,
tokenOffset: previousTokenEnd,
tokenEndOffset: previousTokenEnd,
features: this.findFeaturesAt(textDocument, previousTokenEnd),
};
}
}
if (!astNode) {
const parserRule = getEntryRule(this.grammar);
if (!parserRule) {
throw new Error('Missing entry parser rule');
}
// This context aims to perform completion for the grammar start (usually when the document is empty)
yield {
...partialContext,
tokenOffset: nextTokenStart,
tokenEndOffset: nextTokenEnd,
features: findFirstFeatures(parserRule.definition).map(f => f[f.length - 1]),
};
}
else if (performNextCompletion) {
// This context aims to complete the next feature, using the next cst start/end
yield {
...partialContext,
node: astNode,
tokenOffset: nextTokenStart,
tokenEndOffset: nextTokenEnd,
features: this.findFeaturesAt(textDocument, nextTokenStart),
};
}
}
performNextTokenCompletion(document, text, _offset, _end) {
// This regex returns false if the text ends with a letter.
// We don't want to complete new text immediately after a keyword, ID etc.
// We only care about the last character in the text, so we use $ here.
// The \P{L} used here is a Unicode category that matches any character that is not a letter
return /\P{L}$/u.test(text);
}
findDataTypeRuleStart(cst, offset) {
const containerNode = findDeclarationNodeAtOffset(cst, offset, this.grammarConfig.nameRegexp);
if (!containerNode) {
return undefined;
}
// Identify whether the element was parsed as part of a data type rule
const fullNode = getDatatypeNode(containerNode);
if (fullNode) {
return [fullNode.offset, fullNode.end];
}
return undefined;
}
/**
* Indicates whether the completion should continue to process the next completion context.
*
* The default implementation continues the completion only if there are currently no proposed completion items.
*/
continueCompletion(items) {
return items.length === 0;
}
/**
* This method returns two sets of token offset information.
*
* The `nextToken*` offsets are related to the token at the cursor position.
* If there is none, both offsets are simply set to `offset`.
*
* The `previousToken*` offsets are related to the last token before the current token at the cursor position.
* They are `undefined`, if there is no token before the cursor position.
*/
backtrackToAnyToken(text, offset) {
const tokens = this.lexer.tokenize(text).tokens;
if (tokens.length === 0) {
// If we don't have any tokens in our document, just return the offset position
return {
nextTokenStart: offset,
nextTokenEnd: offset
};
}
let previousToken;
for (const token of tokens) {
if (token.startOffset >= offset) {
// We are between two tokens
// Return the current offset as the next token index
return {
nextTokenStart: offset,
nextTokenEnd: offset,
previousTokenStart: previousToken ? previousToken.startOffset : undefined,
previousTokenEnd: previousToken ? previousToken.endOffset + 1 : undefined
};
}
if (token.endOffset >= offset) {
// We are within a token
// Return the current and previous token offsets as normal
return {
nextTokenStart: token.startOffset,
nextTokenEnd: token.endOffset + 1,
previousTokenStart: previousToken ? previousToken.startOffset : undefined,
previousTokenEnd: previousToken ? previousToken.endOffset + 1 : undefined
};
}
previousToken = token;
}
// We have run into the end of the file
// Return the current offset as the next token index
return {
nextTokenStart: offset,
nextTokenEnd: offset,
previousTokenStart: previousToken ? previousToken.startOffset : undefined,
previousTokenEnd: previousToken ? previousToken.endOffset + 1 : undefined
};
}
completionFor(context, next, acceptor) {
if (ast.isKeyword(next.feature)) {
return this.completionForKeyword(context, next.feature, acceptor);
}
else if (ast.isCrossReference(next.feature) && context.node) {
return this.completionForCrossReference(context, next, acceptor);
}
// Don't offer any completion for other elements (i.e. terminals, datatype rules)
// We - from a framework level - cannot reasonably assume their contents.
// Adopters can just override `completionFor` if they want to do that anyway.
}
completionForCrossReference(context, next, acceptor) {
const assignment = getContainerOfType(next.feature, ast.isAssignment);
let node = context.node;
if (assignment && node) {
if (next.type) {
// When `type` is set, it indicates that we have just entered a new parser rule.
// The cross reference that we're trying to complete is on a new element that doesn't exist yet.
// So we create a new synthetic element with the correct type information.
node = {
$type: next.type,
$container: node,
$containerProperty: next.property
};
assignMandatoryProperties(this.astReflection, node);
}
let reference;
if (next.feature.isMulti) {
reference = {
$refText: '',
items: []
};
}
else {
reference = {
$refText: '',
ref: undefined
};
}
const refInfo = {
reference,
container: node,
property: assignment.feature
};
try {
for (const candidate of this.getReferenceCandidates(refInfo, context)) {
acceptor(context, this.createReferenceCompletionItem(candidate, refInfo, context));
}
}
catch (err) {
console.error(err);
}
}
}
/**
* Override this method to change how the stream of candidates is determined for a reference.
* This way completion-specific modifications and refinements can be added to the proposals computation
* beyond the rules being implemented in the scope provider, e.g. filtering.
*
* @param refInfo Information about the reference for which the candidates are requested.
* @param _context Information about the completion request including document, cursor position, token under cursor, etc.
* @returns A stream of all elements being valid for the given reference.
*/
getReferenceCandidates(refInfo, _context) {
return this.scopeProvider.getScope(refInfo).getAllElements();
}
/**
* Override this method to change how reference completion items are created.
*
* To change the `kind` of a completion item, override the `NodeKindProvider` service instead.
* To change the `documentation`, override the `DocumentationProvider` service instead.
*
* @param nodeDescription The description of a reference candidate
* @param _refInfo Information about the reference for which the candidate is proposed
* @param _context The completion context
* @returns A partial completion item
*/
createReferenceCompletionItem(nodeDescription, _refInfo, _context) {
const kind = this.nodeKindProvider.getCompletionItemKind(nodeDescription);
const documentation = this.getReferenceDocumentation(nodeDescription);
return {
nodeDescription,
kind,
documentation,
detail: nodeDescription.type,
sortText: '0'
};
}
getReferenceDocumentation(nodeDescription) {
if (!nodeDescription.node) {
return undefined;
}
const documentationText = this.documentationProvider.getDocumentation(nodeDescription.node);
if (!documentationText) {
return undefined;
}
return { kind: 'markdown', value: documentationText };
}
completionForKeyword(context, keyword, acceptor) {
if (!this.filterKeyword(context, keyword)) {
return;
}
acceptor(context, {
label: keyword.value,
kind: this.getKeywordCompletionItemKind(keyword),
detail: 'Keyword',
sortText: '1'
});
}
getKeywordCompletionItemKind(_keyword) {
return CompletionItemKind.Keyword;
}
filterKeyword(context, keyword) {
// Filter out keywords that do not contain any word character
return /\p{L}/u.test(keyword.value);
}
fillCompletionItem(context, item) {
let label;
if (typeof item.label === 'string') {
label = item.label;
}
else if ('node' in item) {
const name = this.nameProvider.getName(item.node);
if (!name) {
return undefined;
}
label = name;
}
else if ('nodeDescription' in item) {
label = item.nodeDescription.name;
}
else {
return undefined;
}
let insertText;
if (typeof item.textEdit?.newText === 'string') {
insertText = item.textEdit.newText;
}
else if (typeof item.insertText === 'string') {
insertText = item.insertText;
}
else {
insertText = label;
}
const textEdit = item.textEdit ?? this.buildCompletionTextEdit(context, label, insertText);
if (!textEdit) {
return undefined;
}
// Copy all valid properties of `CompletionItem`
const completionItem = {
additionalTextEdits: item.additionalTextEdits,
command: item.command,
commitCharacters: item.commitCharacters,
data: item.data,
detail: item.detail,
documentation: item.documentation,
filterText: item.filterText,
insertText: item.insertText,
insertTextFormat: item.insertTextFormat,
insertTextMode: item.insertTextMode,
kind: item.kind,
labelDetails: item.labelDetails,
preselect: item.preselect,
sortText: item.sortText,
tags: item.tags,
textEditText: item.textEditText,
textEdit,
label
};
return completionItem;
}
buildCompletionTextEdit(context, label, newText) {
const content = context.textDocument.getText();
const identifier = content.substring(context.tokenOffset, context.offset);
if (this.fuzzyMatcher.match(identifier, label)) {
const start = context.textDocument.positionAt(context.tokenOffset);
const end = context.position;
return {
newText,
range: {
start,
end
}
};
}
else {
return undefined;
}
}
}
//# sourceMappingURL=completion-provider.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,39 @@
/******************************************************************************
* Copyright 2021 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 { IToken } from 'chevrotain';
import * as ast from '../../languages/generated/ast.js';
export interface NextFeature<T extends ast.AbstractElement = ast.AbstractElement> {
/**
* A feature that could appear during completion.
*/
feature: T;
/**
* The type that carries this `feature`. Only set if we encounter a new type.
*/
type?: string;
/**
* The container property for the new `type`
*/
property?: string;
}
/**
* Calculates any features that can follow the given feature stack.
* This also includes features following optional features and features from previously called rules that could follow the last feature.
* @param featureStack A stack of features starting at the entry rule and ending at the feature of the current cursor position.
* @param unparsedTokens All tokens which haven't been parsed successfully yet. This is the case when we call this function inside an alternative or before parsing any tokens.
* @returns Any `AbstractElement` that could be following the given feature stack.
*/
export declare function findNextFeatures(featureStack: NextFeature[][], unparsedTokens: IToken[]): NextFeature[];
/**
* Calculates the first child feature of any `AbstractElement`.
* @param next The `AbstractElement` whose first child features should be calculated.
*/
export declare function findFirstFeatures(next: ast.AbstractElement): NextFeature[][];
export declare function findGroupAndChild(feature: ast.AbstractElement): {
group: ast.Group | undefined;
child: ast.AbstractElement;
};
//# sourceMappingURL=follow-element-computation.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"follow-element-computation.d.ts","sourceRoot":"","sources":["../../../src/lsp/completion/follow-element-computation.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,KAAK,GAAG,MAAM,kCAAkC,CAAC;AAIxD,MAAM,WAAW,WAAW,CAAC,CAAC,SAAS,GAAG,CAAC,eAAe,GAAG,GAAG,CAAC,eAAe;IAC5E;;OAEG;IACH,OAAO,EAAE,CAAC,CAAA;IACV;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CACpB;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,WAAW,EAAE,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,WAAW,EAAE,CAWvG;AAyED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,GAAG,CAAC,eAAe,GAAG,WAAW,EAAE,EAAE,CAE5E;AA4JD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,GAAG,CAAC,eAAe,GAAG;IAAE,KAAK,EAAE,GAAG,CAAC,KAAK,GAAG,SAAS,CAAC;IAAC,KAAK,EAAE,GAAG,CAAC,eAAe,CAAA;CAAE,CAsB5H"}
@@ -0,0 +1,312 @@
/******************************************************************************
* Copyright 2021 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 * as ast from '../../languages/generated/ast.js';
import { getCrossReferenceTerminal, getExplicitRuleType, getTypeName, isArrayCardinality, isOptionalCardinality, terminalRegex } from '../../utils/grammar-utils.js';
import { getContainerOfType } from '../../utils/ast-utils.js';
/**
* Calculates any features that can follow the given feature stack.
* This also includes features following optional features and features from previously called rules that could follow the last feature.
* @param featureStack A stack of features starting at the entry rule and ending at the feature of the current cursor position.
* @param unparsedTokens All tokens which haven't been parsed successfully yet. This is the case when we call this function inside an alternative or before parsing any tokens.
* @returns Any `AbstractElement` that could be following the given feature stack.
*/
export function findNextFeatures(featureStack, unparsedTokens) {
const context = {
stacks: featureStack,
tokens: unparsedTokens
};
interpretTokens(context);
// Reset the container property
context.stacks.flat().forEach(feature => { feature.property = undefined; });
const nextStacks = findNextFeatureStacks(context.stacks);
// We only need the last element of each stack
return nextStacks.map(e => e[e.length - 1]);
}
function findNextFeaturesInternal(stack) {
const features = [];
if (stack.length === 0) {
return features;
}
const top = stack[stack.length - 1];
const { group, child } = findGroupAndChild(top.feature);
if (isArrayCardinality(child.cardinality)) {
// The feature can appear again, so we try to find its first features again
const repeatingFeatures = findFirstFeaturesInternal({
feature: child,
type: top.type,
property: top.property
});
features.push(...repeatingFeatures);
}
let groupIndex = -1;
if (group) {
groupIndex = group.elements.indexOf(child);
}
const parentStack = stack.slice(0, -1);
if (!group) {
const parent = getAbstractElementParent(child);
if (parent) {
// The feature is not part of a group
// But the parent might be
features.push(...findNextFeaturesInternal([
...parentStack,
{
feature: parent,
}
]));
}
else {
// The feature is "standalone", meaning it is the top-level feature of a rule
// The next elements are defined by the previous stack elements
features.push(...findNextFeaturesInternal(parentStack));
}
}
else {
// The feature is somewhere within the group
const nextIndex = groupIndex + 1;
const { stacks, end } = findNextFeaturesInGroup({
feature: group,
type: top.type
}, nextIndex);
for (const newStack of stacks) {
features.push([...parentStack, ...newStack]);
}
// If we reached the end of the group, continue searching for following features
if (end) {
// Set groupIndex to the last element index to indicate that we are at the end of the group
// This will trigger the parent search below
groupIndex = group.elements.length - 1;
}
}
if (group && groupIndex === group.elements.length - 1) {
// The feature is the last element of a group
// The next elements are defined by the parent group
features.push(...findNextFeaturesInternal([
...parentStack,
{
feature: group,
}
]));
}
return features;
}
/**
* Calculates the first child feature of any `AbstractElement`.
* @param next The `AbstractElement` whose first child features should be calculated.
*/
export function findFirstFeatures(next) {
return findFirstFeaturesInternal({ feature: next });
}
function findFirstFeaturesInternal(next) {
const { feature, type } = next;
if (ast.isGroup(feature)) {
return findNextFeaturesInGroup(next, 0).stacks;
}
else if (ast.isAlternatives(feature) || ast.isUnorderedGroup(feature)) {
return feature.elements.flatMap(e => findFirstFeaturesInternal({
feature: e,
type,
property: next.property
}));
}
else if (ast.isAssignment(feature)) {
return findFirstFeaturesInternal({
feature: feature.terminal,
type,
property: next.property ?? feature.feature
});
}
else if (ast.isAction(feature)) {
return findNextFeaturesInternal([{
feature,
type: getTypeName(feature),
property: next.property ?? feature.feature
}]);
}
else if (ast.isRuleCall(feature) && ast.isParserRule(feature.rule.ref)) {
const rule = feature.rule.ref;
const stacks = findFirstFeaturesInternal({
feature: rule.definition,
type: rule.fragment || rule.dataType ? undefined : (getExplicitRuleType(rule) ?? rule.name),
property: next.property
});
for (const stack of stacks) {
stack.unshift(next);
}
return stacks;
}
else if (ast.isRuleCall(feature) && ast.isInfixRule(feature.rule.ref)) {
const rule = feature.rule.ref;
const call = rule.call.rule.ref;
if (!ast.isParserRule(call)) {
console.error('Failed to resolve reference to ' + rule.call.rule.$refText);
return [];
}
const stacks = findFirstFeaturesInternal({
feature: call.definition,
type: getExplicitRuleType(call) ?? call.name,
property: 'parts'
});
for (const stack of stacks) {
stack.unshift(next);
}
return stacks;
}
else {
return [[next]];
}
}
function findNextFeaturesInGroup(next, index) {
const features = [];
let firstFeature;
while (index < next.feature.elements.length) {
const feature = next.feature.elements[index];
firstFeature = {
feature,
type: next.type
};
const stacks = findFirstFeaturesInternal(firstFeature);
features.push(...stacks);
if (isElementOptional(feature, new Map())) {
// Continue with the next element
index++;
}
else {
break;
}
}
return {
stacks: features,
end: index >= next.feature.elements.length
};
}
/**
* Determines recursively whether an element is optional. It is not sufficient to check only the cardinality of the element itself,
* because it could a group or alternative that contains only optional elements.
*/
function isElementOptional(feature, visited) {
const visitedResult = visited.get(feature);
if (visitedResult !== undefined) {
return visitedResult;
}
visited.set(feature, false);
if (isOptionalCardinality(feature.cardinality, feature)) {
visited.set(feature, true);
return true;
}
if (ast.isGroup(feature)) {
for (const element of feature.elements) {
if (!isElementOptional(element, visited)) {
visited.set(feature, false);
return false;
}
}
visited.set(feature, true);
return true;
}
else if (ast.isAlternatives(feature) || ast.isUnorderedGroup(feature)) {
for (const element of feature.elements) {
if (isElementOptional(element, visited)) {
visited.set(feature, true);
return true;
}
}
visited.set(feature, false);
return false;
}
else if (ast.isRuleCall(feature) && ast.isParserRule(feature.rule.ref)) {
const rule = feature.rule.ref;
const result = isElementOptional(rule.definition, visited);
visited.set(feature, result);
return result;
}
return false;
}
function interpretTokens(context) {
for (const token of context.tokens) {
const nextFeatureStacks = findNextFeatureStacks(context.stacks, token);
context.stacks = nextFeatureStacks;
}
}
function findNextFeatureStacks(stacks, token) {
const newStacks = [];
for (const stack of stacks) {
newStacks.push(...interpretStackToken(stack, token));
}
return newStacks;
}
function interpretStackToken(stack, token) {
const allNextFeatures = findNextFeaturesInternal(stack);
const matchingNextFeatures = allNextFeatures.filter(next => token ? featureMatches(next[next.length - 1].feature, token) : true);
return matchingNextFeatures;
}
export function findGroupAndChild(feature) {
let parent;
let item = feature;
while (item.$container) {
if (ast.isGroup(item.$container)) {
parent = item.$container;
break;
}
else if (ast.isAbstractElement(item.$container)) {
item = item.$container;
}
else {
break;
}
}
if (parent) {
return { group: parent, child: item };
}
return {
group: undefined,
// Even if there is no group, return the feature parent if it is an assignment
// We need this later to handle the cardinality of the feature correctly
child: getContainerOfType(feature, ast.isAssignment) ?? feature
};
}
function getAbstractElementParent(element) {
const parent = element.$container;
const assignment = getContainerOfType(parent, ast.isAssignment);
if (assignment) {
return getAbstractElementParent(assignment);
}
else {
if (parent && ast.isAbstractElement(parent)) {
return parent;
}
}
return undefined;
}
function featureMatches(feature, token) {
if (ast.isKeyword(feature)) {
const content = feature.value;
return content === token.tokenType.name;
}
else if (ast.isRuleCall(feature)) {
return ruleMatches(feature.rule.ref, token);
}
else if (ast.isCrossReference(feature)) {
const crossRefTerminal = getCrossReferenceTerminal(feature);
if (crossRefTerminal) {
return featureMatches(crossRefTerminal, token);
}
}
return false;
}
function ruleMatches(rule, token) {
if (ast.isParserRule(rule)) {
const ruleFeatures = findFirstFeatures(rule.definition);
return ruleFeatures.some(e => featureMatches(e[e.length - 1].feature, token));
}
else if (ast.isTerminalRule(rule)) {
return terminalRegex(rule).test(token.image);
}
else {
return false;
}
}
//# sourceMappingURL=follow-element-computation.js.map
File diff suppressed because one or more lines are too long
+21
View File
@@ -0,0 +1,21 @@
/******************************************************************************
* Copyright 2022 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 { 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';
/**
* Language-specific service for handling go to declaration requests
*/
export interface DeclarationProvider {
/**
* Handle a go to declaration 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
*/
getDeclaration(document: LangiumDocument, params: DeclarationParams, cancelToken?: CancellationToken): MaybePromise<LocationLink[] | undefined>;
}
//# sourceMappingURL=declaration-provider.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"declaration-provider.d.ts","sourceRoot":"","sources":["../../src/lsp/declaration-provider.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC7E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAEjE;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAChC;;;;OAIG;IACH,cAAc,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,iBAAiB,EAAE,WAAW,CAAC,EAAE,iBAAiB,GAAG,YAAY,CAAC,YAAY,EAAE,GAAG,SAAS,CAAC,CAAA;CAClJ"}
+7
View File
@@ -0,0 +1,7 @@
/******************************************************************************
* Copyright 2022 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.
******************************************************************************/
export {};
//# sourceMappingURL=declaration-provider.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"declaration-provider.js","sourceRoot":"","sources":["../../src/lsp/declaration-provider.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF"}
+43
View File
@@ -0,0 +1,43 @@
/******************************************************************************
* 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 } from 'vscode-languageserver';
import { type DefaultCoreModuleContext, type DefaultSharedCoreModuleContext } from '../default-module.js';
import { Module } from '../dependency-injection.js';
import type { LangiumDefaultCoreServices, LangiumDefaultSharedCoreServices } from '../services.js';
import type { LangiumLSPServices, LangiumServices, LangiumSharedLSPServices, LangiumSharedServices } from './lsp-services.js';
/**
* Context required for creating the default language-specific dependency injection module.
*/
export interface DefaultModuleContext extends DefaultCoreModuleContext {
readonly 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 declare function createDefaultModule(context: DefaultModuleContext): Module<LangiumServices, LangiumDefaultCoreServices & LangiumLSPServices>;
/**
* Creates a dependency injection module configuring the default LSP services.
* This is a set of services that are dedicated to a specific language.
*/
export declare function createDefaultLSPModule(context: DefaultModuleContext): Module<LangiumServices, LangiumLSPServices>;
export interface DefaultSharedModuleContext extends DefaultSharedCoreModuleContext {
/**
* Represents an abstract language server connection
*/
readonly 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 declare function createDefaultSharedModule(context: DefaultSharedModuleContext): Module<LangiumSharedServices, LangiumDefaultSharedCoreServices & LangiumSharedLSPServices>;
/**
* Creates a dependency injection module configuring the default shared LSP services.
* This is the set of services that are shared between multiple languages.
*/
export declare function createDefaultSharedLSPModule(context: DefaultSharedModuleContext): Module<LangiumSharedServices, LangiumSharedLSPServices>;
//# sourceMappingURL=default-lsp-module.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"default-lsp-module.d.ts","sourceRoot":"","sources":["../../src/lsp/default-lsp-module.ts"],"names":[],"mappings":"AAAA;;;;+EAI+E;AAE/E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAA0D,KAAK,wBAAwB,EAAE,KAAK,8BAA8B,EAAE,MAAM,sBAAsB,CAAC;AAClK,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACpD,OAAO,KAAK,EAAE,0BAA0B,EAAE,gCAAgC,EAAE,MAAM,gBAAgB,CAAC;AAWnG,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAO9H;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,wBAAwB;IAClE,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;CAC1C;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,MAAM,CAAC,eAAe,EAAE,0BAA0B,GAAG,kBAAkB,CAAC,CAK3I;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,oBAAoB,GAAG,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,CAcjH;AAED,MAAM,WAAW,0BAA2B,SAAQ,8BAA8B;IAC9E;;OAEG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;CACpC;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,0BAA0B,GAAG,MAAM,CAAC,qBAAqB,EAAE,gCAAgC,GAAG,wBAAwB,CAAC,CAKzK;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,0BAA0B,GAAG,MAAM,CAAC,qBAAqB,EAAE,wBAAwB,CAAC,CAezI"}
+76
View File
@@ -0,0 +1,76 @@
/******************************************************************************
* 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 { createDefaultCoreModule, createDefaultSharedCoreModule } from '../default-module.js';
import { Module } from '../dependency-injection.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 { 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';
import { NormalizedNotebookDocuments, NormalizedTextDocuments } from './normalized-text-documents.js';
/**
* 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) {
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) {
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
};
}
/**
* 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) {
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) {
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 NormalizedTextDocuments(TextDocument),
NotebookDocuments: (services) => new NormalizedNotebookDocuments(services.workspace.TextDocuments)
}
};
}
//# sourceMappingURL=default-lsp-module.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"default-lsp-module.js","sourceRoot":"","sources":["../../src/lsp/default-lsp-module.ts"],"names":[],"mappings":"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"}
+47
View File
@@ -0,0 +1,47 @@
/******************************************************************************
* Copyright 2021 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 { 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 './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 { LocationLink } from 'vscode-languageserver';
/**
* Language-specific service for handling go to definition requests.
*/
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
*/
getDefinition(document: LangiumDocument, params: DefinitionParams, cancelToken?: CancellationToken): MaybePromise<LocationLink[] | undefined>;
}
export interface GoToLink {
source: CstNode;
target: CstNode;
targetDocument: LangiumDocument;
}
export declare class DefaultDefinitionProvider implements DefinitionProvider {
protected readonly nameProvider: NameProvider;
protected readonly references: References;
protected readonly grammarConfig: GrammarConfig;
constructor(services: LangiumServices);
getDefinition(document: LangiumDocument, params: DefinitionParams, _cancelToken?: CancellationToken): MaybePromise<LocationLink[] | undefined>;
protected collectLocationLinks(sourceCstNode: CstNode, _params: DefinitionParams): MaybePromise<LocationLink[] | undefined>;
protected findLinks(source: CstNode): GoToLink[];
}
//# sourceMappingURL=definition-provider.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"definition-provider.d.ts","sourceRoot":"","sources":["../../src/lsp/definition-provider.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAIrD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAC/B;;;;;;;;;;OAUG;IACH,aAAa,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,gBAAgB,EAAE,WAAW,CAAC,EAAE,iBAAiB,GAAG,YAAY,CAAC,YAAY,EAAE,GAAG,SAAS,CAAC,CAAC;CACjJ;AAED,MAAM,WAAW,QAAQ;IACrB,MAAM,EAAE,OAAO,CAAA;IACf,MAAM,EAAE,OAAO,CAAA;IACf,cAAc,EAAE,eAAe,CAAA;CAClC;AAED,qBAAa,yBAA0B,YAAW,kBAAkB;IAEhE,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IAC9C,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAC1C,SAAS,CAAC,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;gBAEpC,QAAQ,EAAE,eAAe;IAMrC,aAAa,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,gBAAgB,EAAE,YAAY,CAAC,EAAE,iBAAiB,GAAG,YAAY,CAAC,YAAY,EAAE,GAAG,SAAS,CAAC;IAY9I,SAAS,CAAC,oBAAoB,CAAC,aAAa,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,GAAG,YAAY,CAAC,YAAY,EAAE,GAAG,SAAS,CAAC;IAa3H,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,QAAQ,EAAE;CAgBnD"}
+50
View File
@@ -0,0 +1,50 @@
/******************************************************************************
* Copyright 2021 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 { LocationLink } from 'vscode-languageserver';
import { getDocument } from '../utils/ast-utils.js';
import { findDeclarationNodeAtOffset, getDatatypeNode } from '../utils/cst-utils.js';
export class DefaultDefinitionProvider {
constructor(services) {
this.nameProvider = services.references.NameProvider;
this.references = services.references.References;
this.grammarConfig = services.parser.GrammarConfig;
}
getDefinition(document, params, _cancelToken) {
const rootNode = document.parseResult.value;
if (rootNode.$cstNode) {
const cst = rootNode.$cstNode;
const sourceCstNode = findDeclarationNodeAtOffset(cst, document.textDocument.offsetAt(params.position), this.grammarConfig.nameRegexp);
if (sourceCstNode) {
return this.collectLocationLinks(sourceCstNode, params);
}
}
return undefined;
}
collectLocationLinks(sourceCstNode, _params) {
const goToLinks = this.findLinks(sourceCstNode);
if (goToLinks.length > 0) {
return goToLinks.map(link => LocationLink.create(link.targetDocument.textDocument.uri, (link.target.astNode.$cstNode ?? link.target).range, link.target.range, link.source.range));
}
return undefined;
}
findLinks(source) {
const datatypeSourceNode = getDatatypeNode(source) ?? source;
const targets = this.references.findDeclarationNodes(source);
const links = [];
for (const target of targets) {
const targetDocument = getDocument(target.astNode);
if (targets && targetDocument) {
links.push({
source: datatypeSourceNode,
target,
targetDocument
});
}
}
return links;
}
}
//# sourceMappingURL=definition-provider.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"definition-provider.js","sourceRoot":"","sources":["../../src/lsp/definition-provider.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAWhF,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,2BAA2B,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AA0BrF,MAAM,OAAO,yBAAyB;IAMlC,YAAY,QAAyB;QACjC,IAAI,CAAC,YAAY,GAAG,QAAQ,CAAC,UAAU,CAAC,YAAY,CAAC;QACrD,IAAI,CAAC,UAAU,GAAG,QAAQ,CAAC,UAAU,CAAC,UAAU,CAAC;QACjD,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,aAAa,CAAC;IACvD,CAAC;IAED,aAAa,CAAC,QAAyB,EAAE,MAAwB,EAAE,YAAgC;QAC/F,MAAM,QAAQ,GAAG,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC;QAC5C,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;YACpB,MAAM,GAAG,GAAG,QAAQ,CAAC,QAAQ,CAAC;YAC9B,MAAM,aAAa,GAAG,2BAA2B,CAAC,GAAG,EAAE,QAAQ,CAAC,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;YACvI,IAAI,aAAa,EAAE,CAAC;gBAChB,OAAO,IAAI,CAAC,oBAAoB,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;YAC5D,CAAC;QACL,CAAC;QACD,OAAO,SAAS,CAAC;IACrB,CAAC;IAES,oBAAoB,CAAC,aAAsB,EAAE,OAAyB;QAC5E,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;QAChD,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,OAAO,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,YAAY,CAAC,MAAM,CAC5C,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC,GAAG,EACpC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EACnD,IAAI,CAAC,MAAM,CAAC,KAAK,EACjB,IAAI,CAAC,MAAM,CAAC,KAAK,CACpB,CAAC,CAAC;QACP,CAAC;QACD,OAAO,SAAS,CAAC;IACrB,CAAC;IAES,SAAS,CAAC,MAAe;QAC/B,MAAM,kBAAkB,GAAG,eAAe,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC;QAC7D,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC;QAC7D,MAAM,KAAK,GAAe,EAAE,CAAC;QAC7B,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC3B,MAAM,cAAc,GAAG,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YACnD,IAAI,OAAO,IAAI,cAAc,EAAE,CAAC;gBAC5B,KAAK,CAAC,IAAI,CAAC;oBACP,MAAM,EAAE,kBAAkB;oBAC1B,MAAM;oBACN,cAAc;iBACjB,CAAC,CAAC;YACP,CAAC;QACL,CAAC;QACD,OAAO,KAAK,CAAC;IACjB,CAAC;CACJ"}
+43
View File
@@ -0,0 +1,43 @@
/******************************************************************************
* Copyright 2021 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 { 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 { References } from '../references/references.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';
import { DocumentHighlight } from 'vscode-languageserver';
/**
* Language-specific service for handling document highlight requests.
*/
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
*/
getDocumentHighlight(document: LangiumDocument, params: DocumentHighlightParams, cancelToken?: CancellationToken): MaybePromise<DocumentHighlight[] | undefined>;
}
export declare class DefaultDocumentHighlightProvider implements DocumentHighlightProvider {
protected readonly references: References;
protected readonly nameProvider: NameProvider;
protected readonly grammarConfig: GrammarConfig;
constructor(services: LangiumServices);
getDocumentHighlight(document: LangiumDocument, params: DocumentHighlightParams, _cancelToken?: CancellationToken): MaybePromise<DocumentHighlight[] | undefined>;
/**
* Override this method to determine the highlight kind of the given reference.
*/
protected createDocumentHighlight(reference: ReferenceDescription): DocumentHighlight;
}
//# sourceMappingURL=document-highlight-provider.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"document-highlight-provider.d.ts","sourceRoot":"","sources":["../../src/lsp/document-highlight-provider.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,KAAK,EAAyB,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACrF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AAC7E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAK1D;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACtC;;;;;;;;;OASG;IACH,oBAAoB,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,uBAAuB,EAAE,WAAW,CAAC,EAAE,iBAAiB,GAAG,YAAY,CAAC,iBAAiB,EAAE,GAAG,SAAS,CAAC,CAAC;CACpK;AAED,qBAAa,gCAAiC,YAAW,yBAAyB;IAC9E,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAC1C,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IAC9C,SAAS,CAAC,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;gBAEpC,QAAQ,EAAE,eAAe;IAMrC,oBAAoB,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,uBAAuB,EAAE,YAAY,CAAC,EAAE,iBAAiB,GAAG,YAAY,CAAC,iBAAiB,EAAE,GAAG,SAAS,CAAC;IAoBjK;;MAEE;IACF,SAAS,CAAC,uBAAuB,CAAC,SAAS,EAAE,oBAAoB,GAAG,iBAAiB;CAGxF"}
+42
View File
@@ -0,0 +1,42 @@
/******************************************************************************
* Copyright 2021 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 { DocumentHighlight } from 'vscode-languageserver';
import { getDocument } from '../utils/ast-utils.js';
import { findDeclarationNodeAtOffset } from '../utils/cst-utils.js';
import { UriUtils } from '../utils/uri-utils.js';
export class DefaultDocumentHighlightProvider {
constructor(services) {
this.references = services.references.References;
this.nameProvider = services.references.NameProvider;
this.grammarConfig = services.parser.GrammarConfig;
}
getDocumentHighlight(document, params, _cancelToken) {
const rootNode = document.parseResult.value.$cstNode;
if (!rootNode) {
return undefined;
}
const selectedNode = findDeclarationNodeAtOffset(rootNode, document.textDocument.offsetAt(params.position), this.grammarConfig.nameRegexp);
if (!selectedNode) {
return undefined;
}
const targetAstNode = this.references.findDeclarations(selectedNode);
const highlights = [];
for (const target of targetAstNode) {
const includeDeclaration = UriUtils.equals(getDocument(target).uri, document.uri);
const options = { documentUri: document.uri, includeDeclaration: includeDeclaration };
const references = this.references.findReferences(target, options);
highlights.push(...references.map(ref => this.createDocumentHighlight(ref)).toArray());
}
return highlights;
}
/**
* Override this method to determine the highlight kind of the given reference.
*/
createDocumentHighlight(reference) {
return DocumentHighlight.create(reference.segment.range);
}
}
//# sourceMappingURL=document-highlight-provider.js.map
@@ -0,0 +1 @@
{"version":3,"file":"document-highlight-provider.js","sourceRoot":"","sources":["../../src/lsp/document-highlight-provider.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAWhF,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,2BAA2B,EAAE,MAAM,uBAAuB,CAAC;AACpE,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAmBjD,MAAM,OAAO,gCAAgC;IAKzC,YAAY,QAAyB;QACjC,IAAI,CAAC,UAAU,GAAG,QAAQ,CAAC,UAAU,CAAC,UAAU,CAAC;QACjD,IAAI,CAAC,YAAY,GAAG,QAAQ,CAAC,UAAU,CAAC,YAAY,CAAC;QACrD,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,aAAa,CAAC;IACvD,CAAC;IAED,oBAAoB,CAAC,QAAyB,EAAE,MAA+B,EAAE,YAAgC;QAC7G,MAAM,QAAQ,GAAG,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC;QACrD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACZ,OAAO,SAAS,CAAC;QACrB,CAAC;QACD,MAAM,YAAY,GAAG,2BAA2B,CAAC,QAAQ,EAAE,QAAQ,CAAC,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;QAC3I,IAAI,CAAC,YAAY,EAAE,CAAC;YAChB,OAAO,SAAS,CAAC;QACrB,CAAC;QACD,MAAM,aAAa,GAAG,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC;QACrE,MAAM,UAAU,GAAwB,EAAE,CAAC;QAC3C,KAAK,MAAM,MAAM,IAAI,aAAa,EAAE,CAAC;YACjC,MAAM,kBAAkB,GAAG,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC;YAClF,MAAM,OAAO,GAA0B,EAAE,WAAW,EAAE,QAAQ,CAAC,GAAG,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,CAAC;YAC7G,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YACnE,UAAU,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,uBAAuB,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;QAC3F,CAAC;QACD,OAAO,UAAU,CAAC;IACtB,CAAC;IAED;;MAEE;IACQ,uBAAuB,CAAC,SAA+B;QAC7D,OAAO,iBAAiB,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC7D,CAAC;CACJ"}
+22
View File
@@ -0,0 +1,22 @@
/******************************************************************************
* Copyright 2022 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 { 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';
/**
* Language-specific service for handling document link requests.
*/
export interface DocumentLinkProvider {
/**
* Handle a document links 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
*/
getDocumentLinks(document: LangiumDocument, params: DocumentLinkParams, cancelToken?: CancellationToken): MaybePromise<DocumentLink[]>;
}
//# sourceMappingURL=document-link-provider.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"document-link-provider.d.ts","sourceRoot":"","sources":["../../src/lsp/document-link-provider.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC9E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAEjE;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACjC;;;;;OAKG;IACH,gBAAgB,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,kBAAkB,EAAE,WAAW,CAAC,EAAE,iBAAiB,GAAG,YAAY,CAAC,YAAY,EAAE,CAAC,CAAC;CAC1I"}
+7
View File
@@ -0,0 +1,7 @@
/******************************************************************************
* Copyright 2022 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.
******************************************************************************/
export {};
//# sourceMappingURL=document-link-provider.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"document-link-provider.js","sourceRoot":"","sources":["../../src/lsp/document-link-provider.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF"}
+40
View File
@@ -0,0 +1,40 @@
/******************************************************************************
* Copyright 2021 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 { DocumentSymbol, DocumentSymbolParams } from 'vscode-languageserver-protocol';
import type { CancellationToken } from '../utils/cancellation.js';
import type { NameProvider } from '../references/name-provider.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';
import type { NodeKindProvider } from './node-kind-provider.js';
/**
* Language-specific service for handling document symbols requests.
*/
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
*/
getSymbols(document: LangiumDocument, params: DocumentSymbolParams, cancelToken?: CancellationToken): MaybePromise<DocumentSymbol[]>;
}
export declare class DefaultDocumentSymbolProvider implements DocumentSymbolProvider {
protected readonly nameProvider: NameProvider;
protected readonly nodeKindProvider: NodeKindProvider;
constructor(services: LangiumServices);
getSymbols(document: LangiumDocument, _params: DocumentSymbolParams, _cancelToken?: CancellationToken): MaybePromise<DocumentSymbol[]>;
protected getSymbol(document: LangiumDocument, astNode: AstNode): DocumentSymbol[];
protected createSymbol(document: LangiumDocument, astNode: AstNode, cstNode: CstNode, nameNode: CstNode, computedName?: string): DocumentSymbol;
protected getChildSymbols(document: LangiumDocument, astNode: AstNode): DocumentSymbol[] | undefined;
}
//# sourceMappingURL=document-symbol-provider.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"document-symbol-provider.d.ts","sourceRoot":"","sources":["../../src/lsp/document-symbol-provider.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAC3F,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAE1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACnC;;;;;;;;;;OAUG;IACH,UAAU,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,oBAAoB,EAAE,WAAW,CAAC,EAAE,iBAAiB,GAAG,YAAY,CAAC,cAAc,EAAE,CAAC,CAAC;CACxI;AAED,qBAAa,6BAA8B,YAAW,sBAAsB;IAExE,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IAC9C,SAAS,CAAC,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;gBAE1C,QAAQ,EAAE,eAAe;IAKrC,UAAU,CAAC,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,oBAAoB,EAAE,YAAY,CAAC,EAAE,iBAAiB,GAAG,YAAY,CAAC,cAAc,EAAE,CAAC;IAItI,SAAS,CAAC,SAAS,CAAC,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,OAAO,GAAG,cAAc,EAAE;IAUlF,SAAS,CAAC,YAAY,CAAC,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,cAAc;IAU/I,SAAS,CAAC,eAAe,CAAC,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,OAAO,GAAG,cAAc,EAAE,GAAG,SAAS;CAYvG"}
+46
View File
@@ -0,0 +1,46 @@
/******************************************************************************
* Copyright 2021 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 { streamContents } from '../utils/ast-utils.js';
export class DefaultDocumentSymbolProvider {
constructor(services) {
this.nameProvider = services.references.NameProvider;
this.nodeKindProvider = services.shared.lsp.NodeKindProvider;
}
getSymbols(document, _params, _cancelToken) {
return this.getSymbol(document, document.parseResult.value);
}
getSymbol(document, astNode) {
const nameNode = this.nameProvider.getNameNode(astNode);
if (nameNode && astNode.$cstNode) {
const computedName = this.nameProvider.getName(astNode);
return [this.createSymbol(document, astNode, astNode.$cstNode, nameNode, computedName)];
}
else {
return this.getChildSymbols(document, astNode) || [];
}
}
createSymbol(document, astNode, cstNode, nameNode, computedName) {
return {
kind: this.nodeKindProvider.getSymbolKind(astNode),
name: computedName || nameNode.text,
range: cstNode.range,
selectionRange: nameNode.range,
children: this.getChildSymbols(document, astNode)
};
}
getChildSymbols(document, astNode) {
const children = [];
for (const child of streamContents(astNode)) {
const result = this.getSymbol(document, child);
children.push(...result);
}
if (children.length > 0) {
return children;
}
return undefined;
}
}
//# sourceMappingURL=document-symbol-provider.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"document-symbol-provider.js","sourceRoot":"","sources":["../../src/lsp/document-symbol-provider.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAOhF,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAuBvD,MAAM,OAAO,6BAA6B;IAKtC,YAAY,QAAyB;QACjC,IAAI,CAAC,YAAY,GAAG,QAAQ,CAAC,UAAU,CAAC,YAAY,CAAC;QACrD,IAAI,CAAC,gBAAgB,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC;IACjE,CAAC;IAED,UAAU,CAAC,QAAyB,EAAE,OAA6B,EAAE,YAAgC;QACjG,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IAChE,CAAC;IAES,SAAS,CAAC,QAAyB,EAAE,OAAgB;QAC3D,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QACxD,IAAI,QAAQ,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YAC/B,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YACxD,OAAO,CAAE,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,QAAQ,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAE,CAAC;QAC9F,CAAC;aAAM,CAAC;YACJ,OAAO,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC;QACzD,CAAC;IACL,CAAC;IAES,YAAY,CAAC,QAAyB,EAAE,OAAgB,EAAE,OAAgB,EAAE,QAAiB,EAAE,YAAqB;QAC1H,OAAO;YACH,IAAI,EAAE,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,OAAO,CAAC;YAClD,IAAI,EAAE,YAAY,IAAI,QAAQ,CAAC,IAAI;YACnC,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,cAAc,EAAE,QAAQ,CAAC,KAAK;YAC9B,QAAQ,EAAE,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,OAAO,CAAC;SACpD,CAAC;IACN,CAAC;IAES,eAAe,CAAC,QAAyB,EAAE,OAAgB;QACjE,MAAM,QAAQ,GAAqB,EAAE,CAAC;QAEtC,KAAK,MAAM,KAAK,IAAI,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC;YAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;YAC/C,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC;QAC7B,CAAC;QACD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,OAAO,QAAQ,CAAC;QACpB,CAAC;QACD,OAAO,SAAS,CAAC;IACrB,CAAC;CACJ"}
+76
View File
@@ -0,0 +1,76 @@
/******************************************************************************
* 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 { DidChangeWatchedFilesParams, Disposable, Event, TextDocumentChangeEvent, TextDocumentWillSaveEvent, TextEdit, FileSystemWatcher } from 'vscode-languageserver';
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';
import type { WorkspaceManager } from '../workspace/workspace-manager.js';
import type { ServiceRegistry } from '../service-registry.js';
import type { MaybePromise } from '../utils/promise-utils.js';
import { Emitter } from '../utils/event.js';
/**
* Shared service for handling text document changes and watching relevant files.
*/
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 document save event (initiated) was triggered by the `TextDocuments` service.
* @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 document save event (completed) was triggered by the `TextDocuments` service.
* @param event The document change event.
*/
didSaveDocument?(event: TextDocumentChangeEvent<TextDocument>): void;
/**
* A document close event was triggered by the `TextDocuments` service.
* @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;
/**
* Register a listener for raw file system changes. Which changes are actually reported
* depends on the file system watcher configuration.
*/
onWatchedFilesChange(callback: (params: DidChangeWatchedFilesParams) => void): Disposable;
}
export declare class DefaultDocumentUpdateHandler implements DocumentUpdateHandler {
protected readonly workspaceManager: WorkspaceManager;
protected readonly documentBuilder: DocumentBuilder;
protected readonly workspaceLock: WorkspaceLock;
protected readonly serviceRegistry: ServiceRegistry;
protected readonly onWatchedFilesChangeEmitter: Emitter<DidChangeWatchedFilesParams>;
constructor(services: LangiumSharedServices);
protected registerFileWatcher(services: LangiumSharedServices): void;
protected getWatchers(): FileSystemWatcher[];
protected fireDocumentUpdate(changed: URI[], deleted: URI[]): void;
didChangeContent(change: TextDocumentChangeEvent<TextDocument>): void;
didChangeWatchedFiles(params: DidChangeWatchedFilesParams): void;
get onWatchedFilesChange(): Event<DidChangeWatchedFilesParams>;
}
//# sourceMappingURL=document-update-handler.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"document-update-handler.d.ts","sourceRoot":"","sources":["../../src/lsp/document-update-handler.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EACR,2BAA2B,EAA4C,UAAU,EAAE,KAAK,EAAE,uBAAuB,EAAE,yBAAyB,EAAE,QAAQ,EAAE,iBAAiB,EAC5K,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAC;AAC5C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAE5C;;GAEG;AACH,MAAM,WAAW,qBAAqB;IAElC;;;OAGG;IACH,eAAe,CAAC,CAAC,KAAK,EAAE,uBAAuB,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC;IAErE;;;OAGG;IACH,gBAAgB,CAAC,CAAC,KAAK,EAAE,uBAAuB,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC;IAEtE;;;OAGG;IACH,gBAAgB,CAAC,CAAC,KAAK,EAAE,yBAAyB,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC;IAExE;;;;OAIG;IACH,yBAAyB,CAAC,CAAC,KAAK,EAAE,yBAAyB,CAAC,YAAY,CAAC,GAAG,YAAY,CAAC,QAAQ,EAAE,CAAC,CAAC;IAErG;;;OAGG;IACH,eAAe,CAAC,CAAC,KAAK,EAAE,uBAAuB,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC;IAErE;;;OAGG;IACH,gBAAgB,CAAC,CAAC,KAAK,EAAE,uBAAuB,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC;IAEtE;;;OAGG;IACH,qBAAqB,CAAC,CAAC,MAAM,EAAE,2BAA2B,GAAG,IAAI,CAAC;IAElE;;;OAGG;IACH,oBAAoB,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,2BAA2B,KAAK,IAAI,GAAG,UAAU,CAAC;CAE7F;AAED,qBAAa,4BAA6B,YAAW,qBAAqB;IAEtE,SAAS,CAAC,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;IACtD,SAAS,CAAC,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;IACpD,SAAS,CAAC,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IAChD,SAAS,CAAC,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;IACpD,SAAS,CAAC,QAAQ,CAAC,2BAA2B,uCAA8C;gBAEhF,QAAQ,EAAE,qBAAqB;IAkB3C,SAAS,CAAC,mBAAmB,CAAC,QAAQ,EAAE,qBAAqB,GAAG,IAAI;IASpE,SAAS,CAAC,WAAW,IAAI,iBAAiB,EAAE;IAS5C,SAAS,CAAC,kBAAkB,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,IAAI;IAWlE,gBAAgB,CAAC,MAAM,EAAE,uBAAuB,CAAC,YAAY,CAAC,GAAG,IAAI;IAIrE,qBAAqB,CAAC,MAAM,EAAE,2BAA2B,GAAG,IAAI;IAehE,IAAI,oBAAoB,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAE7D;CACJ"}
+74
View File
@@ -0,0 +1,74 @@
/******************************************************************************
* 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 { DidChangeWatchedFilesNotification, FileChangeType } from 'vscode-languageserver';
import { stream } from '../utils/stream.js';
import { URI } from '../utils/uri-utils.js';
import { Emitter } from '../utils/event.js';
export class DefaultDocumentUpdateHandler {
constructor(services) {
this.onWatchedFilesChangeEmitter = new Emitter();
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 => {
canRegisterFileWatcher = Boolean(params.capabilities.workspace?.didChangeWatchedFiles?.dynamicRegistration);
});
services.lsp.LanguageServer.onInitialized(_params => {
if (canRegisterFileWatcher) {
this.registerFileWatcher(services);
}
});
}
registerFileWatcher(services) {
const watchers = this.getWatchers();
if (watchers.length > 0) {
const connection = services.lsp.Connection;
const options = { watchers };
connection?.client.register(DidChangeWatchedFilesNotification.type, options);
}
}
getWatchers() {
return [{
// We need to watch all file changes in the workspace
// Otherwise we miss changes to directories
// This is a limitation of specific language client implementations
globPattern: '**/*'
}];
}
fireDocumentUpdate(changed, deleted) {
// 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(() => {
this.workspaceLock.write(token => this.documentBuilder.update(changed, deleted, token));
}).catch(err => {
// This should never happen, but if it does, we want to know about it
console.error('Workspace initialization failed. Could not perform document update.', err);
});
}
didChangeContent(change) {
this.fireDocumentUpdate([URI.parse(change.document.uri)], []);
}
didChangeWatchedFiles(params) {
this.onWatchedFilesChangeEmitter.fire(params);
const changedUris = stream(params.changes)
.filter(c => c.type !== FileChangeType.Deleted)
.distinct(c => c.uri)
.map(c => URI.parse(c.uri))
.toArray();
const deletedUris = stream(params.changes)
.filter(c => c.type === FileChangeType.Deleted)
.distinct(c => c.uri)
.map(c => URI.parse(c.uri))
.toArray();
this.fireDocumentUpdate(changedUris, deletedUris);
}
get onWatchedFilesChange() {
return this.onWatchedFilesChangeEmitter.event;
}
}
//# sourceMappingURL=document-update-handler.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"document-update-handler.js","sourceRoot":"","sources":["../../src/lsp/document-update-handler.ts"],"names":[],"mappings":"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"}
+22
View File
@@ -0,0 +1,22 @@
/******************************************************************************
* Copyright 2022 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 { MaybePromise } from '../utils/promise-utils.js';
import { CancellationToken } from '../utils/cancellation.js';
export interface ExecuteCommandHandler {
get commands(): string[];
executeCommand(name: string, args: any[], cancelToken?: CancellationToken): Promise<unknown>;
}
export type ExecuteCommandFunction = (args: any[], cancelToken: CancellationToken) => MaybePromise<unknown>;
export type ExecuteCommandAcceptor = (name: string, execute: ExecuteCommandFunction) => void;
export declare abstract class AbstractExecuteCommandHandler implements ExecuteCommandHandler {
protected registeredCommands: Map<string, ExecuteCommandFunction>;
get commands(): string[];
constructor();
executeCommand(name: string, args: any[], cancelToken?: CancellationToken): Promise<unknown>;
protected createCommandAcceptor(): ExecuteCommandAcceptor;
abstract registerCommands(acceptor: ExecuteCommandAcceptor): void;
}
//# sourceMappingURL=execute-command-handler.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"execute-command-handler.d.ts","sourceRoot":"","sources":["../../src/lsp/execute-command-handler.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAIhF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,MAAM,WAAW,qBAAqB;IAClC,IAAI,QAAQ,IAAI,MAAM,EAAE,CAAA;IACxB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,WAAW,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CAC/F;AAED,MAAM,MAAM,sBAAsB,GAAG,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,WAAW,EAAE,iBAAiB,KAAK,YAAY,CAAC,OAAO,CAAC,CAAA;AAE3G,MAAM,MAAM,sBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,sBAAsB,KAAK,IAAI,CAAC;AAE7F,8BAAsB,6BAA8B,YAAW,qBAAqB;IAEhF,SAAS,CAAC,kBAAkB,sCAA6C;IAEzE,IAAI,QAAQ,IAAI,MAAM,EAAE,CAEvB;;IAMK,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,WAAW,oBAAyB,GAAG,OAAO,CAAC,OAAO,CAAC;IASvG,SAAS,CAAC,qBAAqB,IAAI,sBAAsB;IAIzD,QAAQ,CAAC,gBAAgB,CAAC,QAAQ,EAAE,sBAAsB,GAAG,IAAI;CACpE"}
+28
View File
@@ -0,0 +1,28 @@
/******************************************************************************
* Copyright 2022 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 { CancellationToken } from '../utils/cancellation.js';
export class AbstractExecuteCommandHandler {
get commands() {
return Array.from(this.registeredCommands.keys());
}
constructor() {
this.registeredCommands = new Map();
this.registerCommands(this.createCommandAcceptor());
}
async executeCommand(name, args, cancelToken = CancellationToken.None) {
const command = this.registeredCommands.get(name);
if (command) {
return command(args, cancelToken);
}
else {
return undefined;
}
}
createCommandAcceptor() {
return (name, execute) => this.registeredCommands.set(name, execute);
}
}
//# sourceMappingURL=execute-command-handler.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"execute-command-handler.js","sourceRoot":"","sources":["../../src/lsp/execute-command-handler.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAKhF,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAW7D,MAAM,OAAgB,6BAA6B;IAI/C,IAAI,QAAQ;QACR,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,IAAI,EAAE,CAAC,CAAC;IACtD,CAAC;IAED;QANU,uBAAkB,GAAG,IAAI,GAAG,EAAkC,CAAC;QAOrE,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,qBAAqB,EAAE,CAAC,CAAC;IACxD,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,IAAY,EAAE,IAAW,EAAE,WAAW,GAAG,iBAAiB,CAAC,IAAI;QAChF,MAAM,OAAO,GAAG,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClD,IAAI,OAAO,EAAE,CAAC;YACV,OAAO,OAAO,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QACtC,CAAC;aAAM,CAAC;YACJ,OAAO,SAAS,CAAC;QACrB,CAAC;IACL,CAAC;IAES,qBAAqB;QAC3B,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACzE,CAAC;CAGJ"}
+54
View File
@@ -0,0 +1,54 @@
/******************************************************************************
* 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 { CreateFilesParams, DeleteFilesParams, FileOperationOptions, RenameFilesParams, WorkspaceEdit } from 'vscode-languageserver';
import type { MaybePromise } from '../utils/promise-utils.js';
/**
* Shared service for handling file changes such as file creation, deletion and renaming.
* The interface methods are optional, so they are only registered if they are implemented.
*/
export interface FileOperationHandler {
/**
* These options are reported to the client as part of the ServerCapabilities.
*/
readonly fileOperationOptions: FileOperationOptions;
/**
* Files were created from within the client.
* This notification must be registered with the {@link fileOperationOptions}.
*/
didCreateFiles?(params: CreateFilesParams): void;
/**
* Files were renamed from within the client.
* This notification must be registered with the {@link fileOperationOptions}.
*/
didRenameFiles?(params: RenameFilesParams): void;
/**
* Files were deleted from within the client.
* This notification must be registered with the {@link fileOperationOptions}.
*/
didDeleteFiles?(params: DeleteFilesParams): void;
/**
* Called before files are actually created as long as the creation is triggered from within
* the client either by a user action or by applying a workspace edit.
* This request must be registered with the {@link fileOperationOptions}.
* @returns a WorkspaceEdit which will be applied to workspace before the files are created.
*/
willCreateFiles?(params: CreateFilesParams): MaybePromise<WorkspaceEdit | null>;
/**
* Called before files are actually renamed as long as the rename is triggered from within
* the client either by a user action or by applying a workspace edit.
* This request must be registered with the {@link fileOperationOptions}.
* @returns a WorkspaceEdit which will be applied to workspace before the files are renamed.
*/
willRenameFiles?(params: RenameFilesParams): MaybePromise<WorkspaceEdit | null>;
/**
* Called before files are actually deleted as long as the deletion is triggered from within
* the client either by a user action or by applying a workspace edit.
* This request must be registered with the {@link fileOperationOptions}.
* @returns a WorkspaceEdit which will be applied to workspace before the files are deleted.
*/
willDeleteFiles?(params: DeleteFilesParams): MaybePromise<WorkspaceEdit | null>;
}
//# sourceMappingURL=file-operation-handler.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"file-operation-handler.d.ts","sourceRoot":"","sources":["../../src/lsp/file-operation-handler.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC1I,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAE9D;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IAEjC;;OAEG;IACH,QAAQ,CAAC,oBAAoB,EAAE,oBAAoB,CAAC;IAEpD;;;OAGG;IACH,cAAc,CAAC,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAEjD;;;OAGG;IACH,cAAc,CAAC,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAEjD;;;OAGG;IACH,cAAc,CAAC,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAEjD;;;;;OAKG;IACH,eAAe,CAAC,CAAC,MAAM,EAAE,iBAAiB,GAAG,YAAY,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;IAEhF;;;;;OAKG;IACH,eAAe,CAAC,CAAC,MAAM,EAAE,iBAAiB,GAAG,YAAY,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;IAEhF;;;;;OAKG;IACH,eAAe,CAAC,CAAC,MAAM,EAAE,iBAAiB,GAAG,YAAY,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;CAEnF"}
+7
View File
@@ -0,0 +1,7 @@
/******************************************************************************
* 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.
******************************************************************************/
export {};
//# sourceMappingURL=file-operation-handler.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"file-operation-handler.js","sourceRoot":"","sources":["../../src/lsp/file-operation-handler.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF"}
+57
View File
@@ -0,0 +1,57 @@
/******************************************************************************
* Copyright 2021 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 { 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';
import { FoldingRange } from 'vscode-languageserver';
/**
* Language-specific service for handling folding range requests.
*/
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
*/
getFoldingRanges(document: LangiumDocument, params: FoldingRangeParams, cancelToken?: CancellationToken): MaybePromise<FoldingRange[]>;
}
export type FoldingRangeAcceptor = (foldingRange: FoldingRange) => void;
export declare class DefaultFoldingRangeProvider implements FoldingRangeProvider {
protected readonly commentNames: string[];
constructor(services: LangiumServices);
getFoldingRanges(document: LangiumDocument, _params: FoldingRangeParams, _cancelToken?: CancellationToken): MaybePromise<FoldingRange[]>;
protected collectFolding(document: LangiumDocument, acceptor: FoldingRangeAcceptor): void;
/**
* Template method to determine whether the specified `AstNode` should be handled by the folding range provider.
* 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`.
*/
protected shouldProcess(_node: AstNode): boolean;
/**
* Template method to determine whether the content/children of the specified `AstNode` should be handled by the folding range provider.
* 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.
*/
protected shouldProcessContent(_node: AstNode): boolean;
protected collectObjectFolding(document: LangiumDocument, node: AstNode, acceptor: FoldingRangeAcceptor): void;
protected collectCommentFolding(document: LangiumDocument, node: AstNode, acceptor: FoldingRangeAcceptor): void;
protected toFoldingRange(document: LangiumDocument, node: CstNode, kind?: string): FoldingRange | undefined;
/**
* Template method to determine whether the folding range for this cst node should include its last line.
* Returns false by default for ast nodes which end in braces and for comments.
*/
protected includeLastFoldingLine(node: CstNode, kind?: string): boolean;
}
//# sourceMappingURL=folding-range-provider.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"folding-range-provider.d.ts","sourceRoot":"","sources":["../../src/lsp/folding-range-provider.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EAAE,YAAY,EAAoB,MAAM,uBAAuB,CAAC;AAIvE;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACjC;;;;;;;;;;OAUG;IACH,gBAAgB,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,kBAAkB,EAAE,WAAW,CAAC,EAAE,iBAAiB,GAAG,YAAY,CAAC,YAAY,EAAE,CAAC,CAAC;CAC1I;AAED,MAAM,MAAM,oBAAoB,GAAG,CAAC,YAAY,EAAE,YAAY,KAAK,IAAI,CAAC;AAExE,qBAAa,2BAA4B,YAAW,oBAAoB;IAEpE,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,EAAE,CAAC;gBAE9B,QAAQ,EAAE,eAAe;IAIrC,gBAAgB,CAAC,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,kBAAkB,EAAE,YAAY,CAAC,EAAE,iBAAiB,GAAG,YAAY,CAAC,YAAY,EAAE,CAAC;IAOxI,SAAS,CAAC,cAAc,CAAC,QAAQ,EAAE,eAAe,EAAE,QAAQ,EAAE,oBAAoB,GAAG,IAAI;IAwBzF;;;;OAIG;IACH,SAAS,CAAC,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO;IAIhD;;;;OAIG;IACH,SAAS,CAAC,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO;IAIvD,SAAS,CAAC,oBAAoB,CAAC,QAAQ,EAAE,eAAe,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,oBAAoB,GAAG,IAAI;IAU9G,SAAS,CAAC,qBAAqB,CAAC,QAAQ,EAAE,eAAe,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,oBAAoB,GAAG,IAAI;IAc/G,SAAS,CAAC,cAAc,CAAC,QAAQ,EAAE,eAAe,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAgB3G;;;OAGG;IACH,SAAS,CAAC,sBAAsB,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO;CAc1E"}
+110
View File
@@ -0,0 +1,110 @@
/******************************************************************************
* Copyright 2021 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 { FoldingRange, FoldingRangeKind } from 'vscode-languageserver';
import { streamAllContents } from '../utils/ast-utils.js';
import { flattenCst } from '../utils/cst-utils.js';
export class DefaultFoldingRangeProvider {
constructor(services) {
this.commentNames = services.parser.GrammarConfig.multilineCommentRules;
}
getFoldingRanges(document, _params, _cancelToken) {
const foldings = [];
const acceptor = (foldingRange) => foldings.push(foldingRange);
this.collectFolding(document, acceptor);
return foldings;
}
collectFolding(document, acceptor) {
const root = document.parseResult?.value;
if (root) {
if (this.shouldProcessContent(root)) {
const treeIterator = streamAllContents(root).iterator();
let result;
do {
result = treeIterator.next();
if (!result.done) {
const node = result.value;
if (this.shouldProcess(node)) {
this.collectObjectFolding(document, node, acceptor);
}
if (!this.shouldProcessContent(node)) {
treeIterator.prune();
}
}
} while (!result.done);
}
this.collectCommentFolding(document, root, acceptor);
}
}
/**
* Template method to determine whether the specified `AstNode` should be handled by the folding range provider.
* 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`.
*/
shouldProcess(_node) {
return true;
}
/**
* Template method to determine whether the content/children of the specified `AstNode` should be handled by the folding range provider.
* 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.
*/
shouldProcessContent(_node) {
return true;
}
collectObjectFolding(document, node, acceptor) {
const cstNode = node.$cstNode;
if (cstNode) {
const foldingRange = this.toFoldingRange(document, cstNode);
if (foldingRange) {
acceptor(foldingRange);
}
}
}
collectCommentFolding(document, node, acceptor) {
const cstNode = node.$cstNode;
if (cstNode) {
for (const node of flattenCst(cstNode)) {
if (this.commentNames.includes(node.tokenType.name)) {
const foldingRange = this.toFoldingRange(document, node, FoldingRangeKind.Comment);
if (foldingRange) {
acceptor(foldingRange);
}
}
}
}
}
toFoldingRange(document, node, kind) {
const range = node.range;
const start = range.start;
let end = range.end;
// Don't generate foldings for nodes that are less than 3 lines
if (end.line - start.line < 2) {
return undefined;
}
// As we don't want to hide the end token like 'if { ... --> } <--',
// we simply select the end of the previous line as the end position
if (!this.includeLastFoldingLine(node, kind)) {
end = document.textDocument.positionAt(document.textDocument.offsetAt({ line: end.line, character: 0 }) - 1);
}
return FoldingRange.create(start.line, end.line, start.character, end.character, kind);
}
/**
* Template method to determine whether the folding range for this cst node should include its last line.
* Returns false by default for ast nodes which end in braces and for comments.
*/
includeLastFoldingLine(node, kind) {
if (kind === FoldingRangeKind.Comment) {
return false;
}
const nodeText = node.text;
const endChar = nodeText.charAt(nodeText.length - 1);
if (endChar === '}' || endChar === ')' || endChar === ']') {
return false;
}
return true;
}
}
//# sourceMappingURL=folding-range-provider.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"folding-range-provider.js","sourceRoot":"","sources":["../../src/lsp/folding-range-provider.ts"],"names":[],"mappings":"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"}
+257
View File
@@ -0,0 +1,257 @@
/******************************************************************************
* Copyright 2021 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 { 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, TextDocument } from '../workspace/documents.js';
/**
* Language specific service for handling formatting related LSP requests.
*/
export interface Formatter {
/**
* Handles full document formatting.
*/
formatDocument(document: LangiumDocument, params: DocumentFormattingParams, cancelToken?: CancellationToken): MaybePromise<TextEdit[]>;
/**
* Handles partial document formatting. Only parts of the document within the `params.range` property are formatted.
*/
formatDocumentRange(document: LangiumDocument, params: DocumentRangeFormattingParams, cancelToken?: CancellationToken): MaybePromise<TextEdit[]>;
/**
* Handles document formatting while typing. Only formats the current line.
*/
formatDocumentOnType(document: LangiumDocument, params: DocumentOnTypeFormattingParams, cancelToken?: CancellationToken): MaybePromise<TextEdit[]>;
/**
* Options that determine when the `formatDocumentOnType` method should be invoked by the language client.
* When `undefined` is returned, document format on type will be disabled.
*/
get formatOnTypeOptions(): DocumentOnTypeFormattingOptions | undefined;
}
export declare abstract class AbstractFormatter implements Formatter {
protected collector: FormattingCollector;
/**
* Creates a formatter scoped to the supplied AST node.
* Allows to define fine-grained formatting rules for elements.
*
* Example usage:
*
* ```ts
* export class CustomFormatter extends AbstractFormatter {
* protected override format(node: AstNode): void {
* if (isPerson(node)) {
* const formatter = this.getNodeFormatter(node);
* formatter.property('name').prepend(Formatting.oneSpace());
* }
* }
* }
* ```
* @param node The specific node the formatter should be scoped to. Every call to properties or keywords will only select those which belong to the supplied AST node.
*/
protected getNodeFormatter<T extends AstNode>(node: T): NodeFormatter<T>;
formatDocument(document: LangiumDocument, params: DocumentFormattingParams): MaybePromise<TextEdit[]>;
/**
* Returns whether a range for a given document is error free, i.e. safe to format
*
* @param document Document to inspect for lexer & parser errors that may produce an unsafe range
* @param range Formatting range to check for safety
* @returns Whether the given formatting range does not overlap with or follow any regions with an error
*/
protected isFormatRangeErrorFree(document: LangiumDocument, range: Range): boolean;
formatDocumentRange(document: LangiumDocument, params: DocumentRangeFormattingParams): MaybePromise<TextEdit[]>;
formatDocumentOnType(document: LangiumDocument, params: DocumentOnTypeFormattingParams): MaybePromise<TextEdit[]>;
get formatOnTypeOptions(): DocumentOnTypeFormattingOptions | undefined;
protected doDocumentFormat(document: LangiumDocument, options: FormattingOptions, range?: Range): TextEdit[];
protected avoidOverlappingEdits(textDocument: TextDocument, textEdits: TextEdit[]): TextEdit[];
protected iterateAstFormatting(document: LangiumDocument, range?: Range): void;
protected abstract format(node: AstNode): void;
protected nodeModeToKey(node: CstNode, mode: 'prepend' | 'append'): string;
protected insideRange(inside: Range, total?: Range): boolean;
protected isNecessary(edit: TextEdit, document: TextDocument): boolean;
protected iterateCstFormatting(document: LangiumDocument, formattings: Map<string, FormattingAction>, options: FormattingOptions, range?: Range): TextEdit[];
protected createHiddenTextEdits(previous: CstNode | undefined, hidden: CstNode, formatting: FormattingAction | undefined, context: FormattingContext): TextEdit[];
protected getExistingIndentationCharacterCount(text: string, context: FormattingContext): number;
protected getIndentationCharacterCount(context: FormattingContext, formattingMove?: FormattingMove): number;
protected createTextEdit(a: CstNode | undefined, b: CstNode, formatting: FormattingAction, context: FormattingContext): TextEdit[];
protected createSpaceTextEdit(range: Range, spaces: number, options: FormattingActionOptions): TextEdit;
protected createLineTextEdit(range: Range, lines: number, context: FormattingContext, options: FormattingActionOptions): TextEdit;
protected createTabTextEdit(range: Range, hasPrevious: boolean, context: FormattingContext): TextEdit;
protected fitIntoOptions(value: number, existing: number, options: FormattingActionOptions): number;
protected findFittingMove(range: Range, moves: FormattingMove[], _context: FormattingContext): FormattingMove | undefined;
protected iterateCstTree(document: LangiumDocument, context: FormattingContext): Stream<CstNode>;
protected iterateCst(node: CstNode, context: FormattingContext): Stream<CstNode>;
}
/**
* Represents an object that allows to format certain parts of a specific node, like its keywords or properties.
*/
export interface NodeFormatter<T extends AstNode> {
/**
* Creates a new formatting region that contains the specified node.
*/
node(node: AstNode): FormattingRegion;
/**
* Creates a new formatting region that contains all of the specified nodes.
*/
nodes(...nodes: AstNode[]): FormattingRegion;
/**
* Creates a new formatting region that contains the specified property of the supplied node.
*
* @param property The name of the property to format. Scoped to the supplied node.
* @param index The index of the property, if the property is an array. `0` by default. To retrieve all elements of this array, use the {@link properties} method instead.
*/
property(property: Properties<T>, index?: number): FormattingRegion;
/**
* Creates a new formatting region that contains the all of the specified properties of the supplied node.
*
* @param properties The names of the properties to format. Scoped to the supplied node.
*/
properties(...properties: Array<Properties<T>>): FormattingRegion;
/**
* Creates a new formatting region that contains the specified keyword of the supplied node.
*
* @param keyword The keyword to format. Scoped to the supplied node.
* @param index The index of the keyword, necessary if the keyword appears multiple times. `0` by default. To retrieve all keywords, use the {@link keywords} method instead.
*/
keyword(keyword: string, index?: number): FormattingRegion;
/**
* Creates a new formatting region that contains the all of the specified keywords of the supplied node.
*
* @param keywords The keywords to format. Scoped to the supplied node.
*/
keywords(...keywords: string[]): FormattingRegion;
/**
* Creates a new formatting region that contains the all of the specified CST nodes.
*
* @param nodes A list of CST nodes to format
*/
cst(nodes: CstNode[]): FormattingRegion;
/**
* Creates a new formatting region that contains all nodes between the given formatting regions.
*
* For example, can be used to retrieve a formatting region that contains all nodes between two curly braces:
*
* ```ts
* const formatter = this.getNodeFormatter(node);
* const bracesOpen = formatter.keyword('{');
* const bracesClose = formatter.keyword('}');
* formatter.interior(bracesOpen, bracesClose).prepend(Formatting.indent());
* ```
*
* @param start Determines where the search for interior nodes should start
* @param end Determines where the search for interior nodes should end
*/
interior(start: FormattingRegion, end: FormattingRegion): FormattingRegion;
}
export declare class DefaultNodeFormatter<T extends AstNode> implements NodeFormatter<T> {
protected readonly astNode: T;
protected readonly collector: FormattingCollector;
constructor(astNode: T, collector: FormattingCollector);
node(node: AstNode): FormattingRegion;
nodes(...nodes: AstNode[]): FormattingRegion;
property(feature: Properties<T>, index?: number): FormattingRegion;
properties(...features: Array<Properties<T>>): FormattingRegion;
keyword(keyword: string, index?: number): FormattingRegion;
keywords(...keywords: string[]): FormattingRegion;
cst(nodes: CstNode[]): FormattingRegion;
interior(start: FormattingRegion, end: FormattingRegion): FormattingRegion;
}
export interface FormattingContext {
document: TextDocument;
options: FormattingOptions;
indentation: number;
}
export declare class FormattingRegion {
readonly nodes: CstNode[];
protected readonly collector: FormattingCollector;
constructor(nodes: CstNode[], collector: FormattingCollector);
/**
* Prepends the specified formatting to all nodes of this region.
*/
prepend(formatting: FormattingAction): FormattingRegion;
/**
* Appends the specified formatting to all nodes of this region.
*/
append(formatting: FormattingAction): FormattingRegion;
/**
* Sorrounds all nodes of this region with the specified formatting.
* Functionally the same as invoking `prepend` and `append` with the same formatting.
*/
surround(formatting: FormattingAction): FormattingRegion;
/**
* Creates a copy of this region with a slice of the selected nodes.
* For both start and end, a negative index can be used to indicate an offset from the end of the array.
* For example, -2 refers to the second to last element of the array.
* @param start The beginning index of the specified portion of the region. If start is undefined, then the slice begins at index 0.
* @param end The end index of the specified portion of the region. This is exclusive of the element at the index 'end'. If end is undefined, then the slice extends to the end of the region.
*/
slice(start?: number, end?: number): FormattingRegion;
}
export interface FormattingAction {
options: FormattingActionOptions;
moves: FormattingMove[];
}
export interface FormattingActionOptions {
/**
* The priority of this formatting. Formattings with a higher priority override those with lower priority.
* `0` by default.
*/
priority?: number;
/**
* Determines whether this formatting allows more spaces/lines than expected. For example, if {@link Formatting.newLine} is used, but 2 empty lines already exist between the elements, no formatting is applied.
*/
allowMore?: boolean;
/**
* Determines whether this formatting allows less spaces/lines than expected. For example, if {@link Formatting.oneSpace} is used, but no spaces exist between the elements, no formatting is applied.
*/
allowLess?: boolean;
}
export interface FormattingMove {
characters?: number;
tabs?: number;
lines?: number;
}
/**
* Contains utilities to easily create formatting actions that can be applied to a {@link FormattingRegion}.
*/
export declare namespace Formatting {
/**
* Creates a new formatting that tries to fit the existing text into one of the specified formattings.
* @param formattings All possible formattings.
*/
function fit(...formattings: FormattingAction[]): FormattingAction;
/**
* Creates a new formatting that removes all spaces
*/
function noSpace(options?: FormattingActionOptions): FormattingAction;
/**
* Creates a new formatting that creates a single space
*/
function oneSpace(options?: FormattingActionOptions): FormattingAction;
/**
* Creates a new formatting that creates the specified amount of spaces
*
* @param count The amount of spaces to be inserted
*/
function spaces(count: number, options?: FormattingActionOptions): FormattingAction;
/**
* Creates a new formatting that moves an element to the next line
*/
function newLine(options?: FormattingActionOptions): FormattingAction;
/**
* Creates a new formatting that creates the specified amount of new lines.
*/
function newLines(count: number, options?: FormattingActionOptions): FormattingAction;
/**
* Creates a new formatting that moves the element to a new line and indents that line.
*/
function indent(options?: FormattingActionOptions): FormattingAction;
/**
* Creates a new formatting that removes all indentation.
*/
function noIndent(options?: FormattingActionOptions): FormattingAction;
}
export type FormattingCollector = (node: CstNode, mode: 'prepend' | 'append', formatting: FormattingAction) => void;
//# sourceMappingURL=formatter.d.ts.map
File diff suppressed because one or more lines are too long
+664
View File
@@ -0,0 +1,664 @@
/******************************************************************************
* Copyright 2021 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 { findNodeForKeyword, findNodesForKeyword, findNodeForProperty, findNodesForProperty } from '../utils/grammar-utils.js';
import { isCompositeCstNode, isLeafCstNode } from '../syntax-tree.js';
import { streamAllContents } from '../utils/ast-utils.js';
import { getInteriorNodes, getNextNode } from '../utils/cst-utils.js';
import { DONE_RESULT, EMPTY_STREAM, StreamImpl, TreeStreamImpl } from '../utils/stream.js';
export class AbstractFormatter {
constructor() {
this.collector = () => { };
}
/**
* Creates a formatter scoped to the supplied AST node.
* Allows to define fine-grained formatting rules for elements.
*
* Example usage:
*
* ```ts
* export class CustomFormatter extends AbstractFormatter {
* protected override format(node: AstNode): void {
* if (isPerson(node)) {
* const formatter = this.getNodeFormatter(node);
* formatter.property('name').prepend(Formatting.oneSpace());
* }
* }
* }
* ```
* @param node The specific node the formatter should be scoped to. Every call to properties or keywords will only select those which belong to the supplied AST node.
*/
getNodeFormatter(node) {
return new DefaultNodeFormatter(node, this.collector);
}
formatDocument(document, params) {
const pr = document.parseResult;
if (pr.lexerErrors.length === 0 && pr.parserErrors.length === 0) {
// safe to format
return this.doDocumentFormat(document, params.options);
}
else {
// don't format a potentially broken document, return no edits
return [];
}
}
/**
* Returns whether a range for a given document is error free, i.e. safe to format
*
* @param document Document to inspect for lexer & parser errors that may produce an unsafe range
* @param range Formatting range to check for safety
* @returns Whether the given formatting range does not overlap with or follow any regions with an error
*/
isFormatRangeErrorFree(document, range) {
const pr = document.parseResult;
if (pr.lexerErrors.length || pr.parserErrors.length) {
// collect the earliest error line from either
const earliestErrLine = Math.min(...pr.lexerErrors.map(e => e.line ?? Number.MAX_VALUE), ...pr.parserErrors.map(e => e.token.startLine ?? Number.MAX_VALUE));
// if the earliest error line occurs before or at the end line of the range, then don't format
return earliestErrLine > range.end.line;
}
else {
// no errors, ok to format
return true;
}
}
formatDocumentRange(document, params) {
if (this.isFormatRangeErrorFree(document, params.range)) {
return this.doDocumentFormat(document, params.options, params.range);
}
else {
return [];
}
}
formatDocumentOnType(document, params) {
// Format the current line after typing something
const range = {
start: {
character: 0,
line: params.position.line
},
end: params.position
};
if (this.isFormatRangeErrorFree(document, range)) {
return this.doDocumentFormat(document, params.options, range);
}
else {
return [];
}
}
get formatOnTypeOptions() {
return undefined;
}
doDocumentFormat(document, options, range) {
const map = new Map();
const collector = (node, mode, formatting) => {
const key = this.nodeModeToKey(node, mode);
const existing = map.get(key);
const priority = formatting.options.priority ?? 0;
const existingPriority = existing?.options.priority ?? 0;
if (!existing || existingPriority <= priority) {
map.set(key, formatting);
}
};
this.collector = collector;
this.iterateAstFormatting(document, range);
const edits = this.iterateCstFormatting(document, map, options, range);
return this.avoidOverlappingEdits(document.textDocument, edits);
}
avoidOverlappingEdits(textDocument, textEdits) {
const edits = [];
for (const edit of textEdits) {
let last = edits[edits.length - 1];
while (last) {
const currentStart = textDocument.offsetAt(edit.range.start);
const lastEnd = textDocument.offsetAt(last.range.end);
if (currentStart < lastEnd) {
edits.pop();
last = edits[edits.length - 1];
}
else {
break;
}
}
edits.push(edit);
}
return edits.filter(edit => this.isNecessary(edit, textDocument));
}
iterateAstFormatting(document, range) {
const root = document.parseResult.value;
this.format(root);
const treeIterator = streamAllContents(root).iterator();
let result;
do {
result = treeIterator.next();
if (!result.done) {
const node = result.value;
const inside = this.insideRange(node.$cstNode.range, range);
if (inside) {
this.format(node);
}
else {
treeIterator.prune();
}
}
} while (!result.done);
}
nodeModeToKey(node, mode) {
return `${node.offset}:${node.end}:${mode}`;
}
insideRange(inside, total) {
if (!total) {
return true;
}
if ((inside.start.line <= total.start.line && inside.end.line >= total.end.line) ||
(inside.start.line >= total.start.line && inside.end.line <= total.end.line) ||
(inside.start.line <= total.end.line && inside.end.line >= total.end.line)) {
return true;
}
return false;
}
isNecessary(edit, document) {
return edit.newText !== document.getText(edit.range).replace(/\r/g, '');
}
iterateCstFormatting(document, formattings, options, range) {
const context = {
indentation: 0,
options,
document: document.textDocument
};
const edits = [];
const cstTreeStream = this.iterateCstTree(document, context);
const iterator = cstTreeStream.iterator();
let lastNode;
let result;
do {
result = iterator.next();
if (!result.done) {
const node = result.value;
const isLeaf = isLeafCstNode(node);
const prependKey = this.nodeModeToKey(node, 'prepend');
const prependFormatting = formattings.get(prependKey);
formattings.delete(prependKey);
if (prependFormatting) {
const nodeEdits = this.createTextEdit(lastNode, node, prependFormatting, context);
for (const edit of nodeEdits) {
if (edit && this.insideRange(edit.range, range)) {
edits.push(edit);
}
}
}
const appendKey = this.nodeModeToKey(node, 'append');
const appendFormatting = formattings.get(appendKey);
formattings.delete(appendKey);
if (appendFormatting) {
const nextNode = getNextNode(node);
if (nextNode) {
const nodeEdits = this.createTextEdit(node, nextNode, appendFormatting, context);
for (const edit of nodeEdits) {
if (edit && this.insideRange(edit.range, range)) {
edits.push(edit);
}
}
}
}
if (!prependFormatting && node.hidden) {
const hiddenEdits = this.createHiddenTextEdits(lastNode, node, undefined, context);
for (const edit of hiddenEdits) {
if (edit && this.insideRange(edit.range, range)) {
edits.push(edit);
}
}
}
if (isLeaf) {
lastNode = node;
}
}
} while (!result.done);
return edits;
}
createHiddenTextEdits(previous, hidden, formatting, context) {
// Don't format the hidden node if it is on the same line as its previous node
const startLine = hidden.range.start.line;
if (previous && previous.range.end.line === startLine) {
return [];
}
const edits = [];
const startRange = {
start: {
character: 0,
line: startLine
},
end: hidden.range.start
};
const hiddenStartText = context.document.getText(startRange);
const move = this.findFittingMove(startRange, formatting?.moves ?? [], context);
const hiddenStartChar = this.getExistingIndentationCharacterCount(hiddenStartText, context);
const expectedStartChar = this.getIndentationCharacterCount(context, move);
const characterIncrease = expectedStartChar - hiddenStartChar;
if (characterIncrease === 0) {
return [];
}
let newText = '';
if (characterIncrease > 0) {
newText = (context.options.insertSpaces ? ' ' : '\t').repeat(characterIncrease);
}
const lines = hidden.text.split('\n');
lines[0] = hiddenStartText + lines[0];
for (let i = 0; i < lines.length; i++) {
const currentLine = startLine + i;
const pos = {
character: 0,
line: currentLine
};
if (characterIncrease > 0) {
edits.push({
newText,
range: {
start: pos,
end: pos
}
});
}
else {
const currentText = lines[i];
let j = 0;
for (; j < currentText.length; j++) {
const char = currentText.charAt(j);
if (char !== ' ' && char !== '\t') {
break;
}
}
edits.push({
newText: '',
range: {
start: pos,
end: {
line: currentLine,
// Remove as much whitespace characters as necessary
// In some cases `characterIncrease` is actually larger than the amount of whitespace available
// So we simply remove all whitespace characters `j`
character: Math.min(j, Math.abs(characterIncrease))
}
}
});
}
}
return edits;
}
getExistingIndentationCharacterCount(text, context) {
const tabWhitespace = ' '.repeat(context.options.tabSize);
let replacement = '';
let regex;
if (context.options.insertSpaces) {
regex = new RegExp('\\t', 'g');
replacement = tabWhitespace;
}
else {
regex = new RegExp(tabWhitespace, 'g');
replacement = '\t';
}
const normalized = text.replace(regex, replacement);
return normalized.length;
}
getIndentationCharacterCount(context, formattingMove) {
let indentation = context.indentation;
if (formattingMove && formattingMove.tabs) {
indentation += formattingMove.tabs;
}
return (context.options.insertSpaces ? context.options.tabSize : 1) * indentation;
}
createTextEdit(a, b, formatting, context) {
if (b.hidden) {
return this.createHiddenTextEdits(a, b, formatting, context);
}
// Ignore the edit if the previous node ends after the current node starts
if (a && (a.range.end.line > b.range.start.line ||
(a.range.end.line === b.range.start.line && a.range.end.character > b.range.start.character))) {
return [];
}
const betweenRange = {
start: a?.range.end ?? {
character: 0,
line: 0
},
end: b.range.start
};
const move = this.findFittingMove(betweenRange, formatting.moves, context);
if (!move) {
return [];
}
const chars = move.characters;
const lines = move.lines;
const tabs = move.tabs;
const existingIndentation = context.indentation;
context.indentation += (tabs ?? 0);
const edits = [];
if (chars !== undefined) {
// Do not apply formatting on the same line if preceding node is hidden
if (!a?.hidden) {
edits.push(this.createSpaceTextEdit(betweenRange, chars, formatting.options));
}
}
else if (lines !== undefined) {
edits.push(this.createLineTextEdit(betweenRange, lines, context, formatting.options));
}
else if (tabs !== undefined) {
edits.push(this.createTabTextEdit(betweenRange, Boolean(a), context));
}
if (isLeafCstNode(b)) {
context.indentation = existingIndentation;
}
return edits;
}
createSpaceTextEdit(range, spaces, options) {
if (range.start.line === range.end.line) {
const existingSpaces = range.end.character - range.start.character;
spaces = this.fitIntoOptions(spaces, existingSpaces, options);
}
const newText = ' '.repeat(spaces);
return {
newText,
range
};
}
createLineTextEdit(range, lines, context, options) {
const existingLines = range.end.line - range.start.line;
lines = this.fitIntoOptions(lines, existingLines, options);
const indent = context.options.insertSpaces ? ' '.repeat(context.options.tabSize) : '\t';
const nodeIndent = indent.repeat(context.indentation);
const newText = `${'\n'.repeat(lines)}${nodeIndent}`;
return {
newText,
range
};
}
createTabTextEdit(range, hasPrevious, context) {
const indent = context.options.insertSpaces ? ' '.repeat(context.options.tabSize) : '\t';
const nodeIndent = indent.repeat(context.indentation);
const minimumLines = hasPrevious ? 1 : 0;
const lines = Math.max(range.end.line - range.start.line, minimumLines);
const newText = `${'\n'.repeat(lines)}${nodeIndent}`;
return {
newText,
range
};
}
fitIntoOptions(value, existing, options) {
if (options.allowMore) {
value = Math.max(existing, value);
}
else if (options.allowLess) {
value = Math.min(existing, value);
}
return value;
}
findFittingMove(range, moves, _context) {
if (moves.length === 0) {
return undefined;
}
else if (moves.length === 1) {
return moves[0];
}
const existingLines = range.end.line - range.start.line;
for (const move of moves) {
if (move.lines !== undefined && existingLines <= move.lines) {
return move;
}
else if (move.lines === undefined && existingLines === 0) {
return move;
}
}
// Return the last move
return moves[moves.length - 1];
}
iterateCstTree(document, context) {
const root = document.parseResult.value;
const rootCst = root.$cstNode;
if (!rootCst) {
return EMPTY_STREAM;
}
return new TreeStreamImpl(rootCst, node => this.iterateCst(node, context));
}
iterateCst(node, context) {
if (!isCompositeCstNode(node)) {
return EMPTY_STREAM;
}
const initial = context.indentation;
return new StreamImpl(() => ({ index: 0 }), (state) => {
if (state.index < node.content.length) {
return { done: false, value: node.content[state.index++] };
}
else {
// Reset the indentation to the level when we entered the node
context.indentation = initial;
return DONE_RESULT;
}
});
}
}
export class DefaultNodeFormatter {
constructor(astNode, collector) {
this.astNode = astNode;
this.collector = collector;
}
node(node) {
return new FormattingRegion(node.$cstNode ? [node.$cstNode] : [], this.collector);
}
nodes(...nodes) {
const cstNodes = [];
for (const node of nodes) {
if (node.$cstNode) {
cstNodes.push(node.$cstNode);
}
}
return new FormattingRegion(cstNodes, this.collector);
}
property(feature, index) {
const cstNode = findNodeForProperty(this.astNode.$cstNode, feature, index);
return new FormattingRegion(cstNode ? [cstNode] : [], this.collector);
}
properties(...features) {
const nodes = [];
for (const feature of features) {
const cstNodes = findNodesForProperty(this.astNode.$cstNode, feature);
nodes.push(...cstNodes);
}
return new FormattingRegion(nodes, this.collector);
}
keyword(keyword, index) {
const cstNode = findNodeForKeyword(this.astNode.$cstNode, keyword, index);
return new FormattingRegion(cstNode ? [cstNode] : [], this.collector);
}
keywords(...keywords) {
const nodes = [];
for (const feature of keywords) {
const cstNodes = findNodesForKeyword(this.astNode.$cstNode, feature);
nodes.push(...cstNodes);
}
return new FormattingRegion(nodes, this.collector);
}
cst(nodes) {
return new FormattingRegion([...nodes], this.collector);
}
interior(start, end) {
const startNodes = start.nodes;
const endNodes = end.nodes;
if (startNodes.length !== 1 || endNodes.length !== 1) {
return new FormattingRegion([], this.collector);
}
let startNode = startNodes[0];
let endNode = endNodes[0];
if (startNode.offset > endNode.offset) {
const intermediate = startNode;
startNode = endNode;
endNode = intermediate;
}
return new FormattingRegion(getInteriorNodes(startNode, endNode), this.collector);
}
}
export class FormattingRegion {
constructor(nodes, collector) {
this.nodes = nodes;
this.collector = collector;
}
/**
* Prepends the specified formatting to all nodes of this region.
*/
prepend(formatting) {
for (const node of this.nodes) {
this.collector(node, 'prepend', formatting);
}
return this;
}
/**
* Appends the specified formatting to all nodes of this region.
*/
append(formatting) {
for (const node of this.nodes) {
this.collector(node, 'append', formatting);
}
return this;
}
/**
* Sorrounds all nodes of this region with the specified formatting.
* Functionally the same as invoking `prepend` and `append` with the same formatting.
*/
surround(formatting) {
for (const node of this.nodes) {
this.collector(node, 'prepend', formatting);
this.collector(node, 'append', formatting);
}
return this;
}
/**
* Creates a copy of this region with a slice of the selected nodes.
* For both start and end, a negative index can be used to indicate an offset from the end of the array.
* For example, -2 refers to the second to last element of the array.
* @param start The beginning index of the specified portion of the region. If start is undefined, then the slice begins at index 0.
* @param end The end index of the specified portion of the region. This is exclusive of the element at the index 'end'. If end is undefined, then the slice extends to the end of the region.
*/
slice(start, end) {
return new FormattingRegion(this.nodes.slice(start, end), this.collector);
}
}
/**
* Contains utilities to easily create formatting actions that can be applied to a {@link FormattingRegion}.
*/
export var Formatting;
(function (Formatting) {
/**
* Creates a new formatting that tries to fit the existing text into one of the specified formattings.
* @param formattings All possible formattings.
*/
function fit(...formattings) {
return {
options: {},
moves: formattings.flatMap(e => e.moves).sort(compareMoves)
};
}
Formatting.fit = fit;
/**
* Creates a new formatting that removes all spaces
*/
function noSpace(options) {
return spaces(0, options);
}
Formatting.noSpace = noSpace;
/**
* Creates a new formatting that creates a single space
*/
function oneSpace(options) {
return spaces(1, options);
}
Formatting.oneSpace = oneSpace;
/**
* Creates a new formatting that creates the specified amount of spaces
*
* @param count The amount of spaces to be inserted
*/
function spaces(count, options) {
return {
options: options ?? {},
moves: [{
characters: count
}]
};
}
Formatting.spaces = spaces;
/**
* Creates a new formatting that moves an element to the next line
*/
function newLine(options) {
return newLines(1, options);
}
Formatting.newLine = newLine;
/**
* Creates a new formatting that creates the specified amount of new lines.
*/
function newLines(count, options) {
return {
options: options ?? {},
moves: [{
lines: count
}]
};
}
Formatting.newLines = newLines;
/**
* Creates a new formatting that moves the element to a new line and indents that line.
*/
function indent(options) {
return {
options: options ?? {},
moves: [{
tabs: 1,
lines: 1
}]
};
}
Formatting.indent = indent;
/**
* Creates a new formatting that removes all indentation.
*/
function noIndent(options) {
return {
options: options ?? {},
moves: [{
tabs: 0
}]
};
}
Formatting.noIndent = noIndent;
function compareMoves(a, b) {
const aLines = a.lines ?? 0;
const bLines = b.lines ?? 0;
const aTabs = a.tabs ?? 0;
const bTabs = b.tabs ?? 0;
const aSpaces = a.characters ?? 0;
const bSpaces = b.characters ?? 0;
if (aLines < bLines) {
return -1;
}
else if (aLines > bLines) {
return 1;
}
else if (aTabs < bTabs) {
return -1;
}
else if (aTabs > bTabs) {
return 1;
}
else if (aSpaces < bSpaces) {
return -1;
}
else if (aSpaces > bSpaces) {
return 1;
}
else {
return 0;
}
}
})(Formatting || (Formatting = {}));
//# sourceMappingURL=formatter.js.map
File diff suppressed because one or more lines are too long
+27
View File
@@ -0,0 +1,27 @@
/******************************************************************************
* 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.
******************************************************************************/
/**
* This service implements a [fuzzy matching](https://en.wikipedia.org/wiki/Approximate_string_matching) method.
*/
export interface FuzzyMatcher {
/**
* Performs [fuzzy matching](https://en.wikipedia.org/wiki/Approximate_string_matching).
*
* Fuzzy matching improves search/completion user experience by allowing to omit characters.
* For example, a query such as `FuMa` matches the text `FuzzyMatcher`.
*
* @param query The user input search query.
* @param text The text that should be matched against the query.
* @returns Whether the query matches the text.
*/
match(query: string, text: string): boolean;
}
export declare class DefaultFuzzyMatcher implements FuzzyMatcher {
match(query: string, text: string): boolean;
protected isWordTransition(previous: number, current: number): boolean;
protected toUpperCharCode(charCode: number): number;
}
//# sourceMappingURL=fuzzy-matcher.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"fuzzy-matcher.d.ts","sourceRoot":"","sources":["../../src/lsp/fuzzy-matcher.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF;;GAEG;AACH,MAAM,WAAW,YAAY;IACzB;;;;;;;;;OASG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;CAC/C;AAED,qBAAa,mBAAoB,YAAW,YAAY;IAEpD,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO;IA4B3C,SAAS,CAAC,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO;IAKtE,SAAS,CAAC,eAAe,CAAC,QAAQ,EAAE,MAAM;CAM7C"}
+48
View File
@@ -0,0 +1,48 @@
/******************************************************************************
* 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.
******************************************************************************/
export class DefaultFuzzyMatcher {
match(query, text) {
if (query.length === 0) {
return true;
}
let matchedFirstCharacter = false;
let previous;
let character = 0;
const len = text.length;
for (let i = 0; i < len; i++) {
const strChar = text.charCodeAt(i);
const testChar = query.charCodeAt(character);
if (strChar === testChar || this.toUpperCharCode(strChar) === this.toUpperCharCode(testChar)) {
matchedFirstCharacter || (matchedFirstCharacter = previous === undefined || // Beginning of word
this.isWordTransition(previous, strChar));
if (matchedFirstCharacter) {
character++;
}
if (character === query.length) {
return true;
}
}
previous = strChar;
}
return false;
}
isWordTransition(previous, current) {
return a <= previous && previous <= z && A <= current && current <= Z || // camelCase transition
previous === _ && current !== _; // snake_case transition
}
toUpperCharCode(charCode) {
if (a <= charCode && charCode <= z) {
return charCode - 32;
}
return charCode;
}
}
const a = 'a'.charCodeAt(0);
const z = 'z'.charCodeAt(0);
const A = 'A'.charCodeAt(0);
const Z = 'Z'.charCodeAt(0);
const _ = '_'.charCodeAt(0);
//# sourceMappingURL=fuzzy-matcher.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"fuzzy-matcher.js","sourceRoot":"","sources":["../../src/lsp/fuzzy-matcher.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAmBhF,MAAM,OAAO,mBAAmB;IAE5B,KAAK,CAAC,KAAa,EAAE,IAAY;QAC7B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACrB,OAAO,IAAI,CAAC;QAChB,CAAC;QAED,IAAI,qBAAqB,GAAG,KAAK,CAAC;QAClC,IAAI,QAA4B,CAAC;QACjC,IAAI,SAAS,GAAG,CAAC,CAAC;QAClB,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC;QACxB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3B,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YACnC,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;YAC7C,IAAI,OAAO,KAAK,QAAQ,IAAI,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC3F,qBAAqB,KAArB,qBAAqB,GACjB,QAAQ,KAAK,SAAS,IAAI,oBAAoB;oBAC9C,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAC;gBAC7C,IAAI,qBAAqB,EAAE,CAAC;oBACxB,SAAS,EAAE,CAAC;gBAChB,CAAC;gBACD,IAAI,SAAS,KAAK,KAAK,CAAC,MAAM,EAAE,CAAC;oBAC7B,OAAO,IAAI,CAAC;gBAChB,CAAC;YACL,CAAC;YACD,QAAQ,GAAG,OAAO,CAAC;QACvB,CAAC;QACD,OAAO,KAAK,CAAC;IACjB,CAAC;IAES,gBAAgB,CAAC,QAAgB,EAAE,OAAe;QACxD,OAAO,CAAC,IAAI,QAAQ,IAAI,QAAQ,IAAI,CAAC,IAAI,CAAC,IAAI,OAAO,IAAI,OAAO,IAAI,CAAC,IAAI,uBAAuB;YAC5F,QAAQ,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,CAAC,CAAC,wBAAwB;IACjE,CAAC;IAES,eAAe,CAAC,QAAgB;QACtC,IAAI,CAAC,IAAI,QAAQ,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;YACjC,OAAO,QAAQ,GAAG,EAAE,CAAC;QACzB,CAAC;QACD,OAAO,QAAQ,CAAC;IACpB,CAAC;CACJ;AAED,MAAM,CAAC,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AAC5B,MAAM,CAAC,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AAC5B,MAAM,CAAC,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AAC5B,MAAM,CAAC,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AAC5B,MAAM,CAAC,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC"}
+40
View File
@@ -0,0 +1,40 @@
/******************************************************************************
* Copyright 2021 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 { 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 './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 type { DocumentationProvider } from '../documentation/documentation-provider.js';
/**
* Language-specific service for handling hover requests.
*/
export interface HoverProvider {
/**
* Handle a hover 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
*/
getHoverContent(document: LangiumDocument, params: HoverParams, cancelToken?: CancellationToken): MaybePromise<Hover | undefined>;
}
export declare abstract class AstNodeHoverProvider implements HoverProvider {
protected readonly references: References;
protected readonly grammarConfig: GrammarConfig;
constructor(services: LangiumServices);
getHoverContent(document: LangiumDocument, params: HoverParams): Promise<Hover | undefined>;
protected abstract getAstNodeHoverContent(node: AstNode): MaybePromise<string | undefined>;
protected getKeywordHoverContent(node: AstNode): MaybePromise<Hover | undefined>;
}
export declare class MultilineCommentHoverProvider extends AstNodeHoverProvider {
protected readonly documentationProvider: DocumentationProvider;
constructor(services: LangiumServices);
protected getAstNodeHoverContent(node: AstNode): MaybePromise<string | undefined>;
}
//# sourceMappingURL=hover-provider.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"hover-provider.d.ts","sourceRoot":"","sources":["../../src/lsp/hover-provider.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4CAA4C,CAAC;AAMxF;;GAEG;AACH,MAAM,WAAW,aAAa;IAC1B;;;;;OAKG;IACH,eAAe,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,CAAC,EAAE,iBAAiB,GAAG,YAAY,CAAC,KAAK,GAAG,SAAS,CAAC,CAAC;CACrI;AAED,8BAAsB,oBAAqB,YAAW,aAAa;IAE/D,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAC1C,SAAS,CAAC,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;gBAEpC,QAAQ,EAAE,eAAe;IAK/B,eAAe,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC;IAgCjG,SAAS,CAAC,QAAQ,CAAC,sBAAsB,CAAC,IAAI,EAAE,OAAO,GAAG,YAAY,CAAC,MAAM,GAAG,SAAS,CAAC;IAE1F,SAAS,CAAC,sBAAsB,CAAC,IAAI,EAAE,OAAO,GAAG,YAAY,CAAC,KAAK,GAAG,SAAS,CAAC;CAkBnF;AAED,qBAAa,6BAA8B,SAAQ,oBAAoB;IAEnE,SAAS,CAAC,QAAQ,CAAC,qBAAqB,EAAE,qBAAqB,CAAC;gBAEpD,QAAQ,EAAE,eAAe;IAKrC,SAAS,CAAC,sBAAsB,CAAC,IAAI,EAAE,OAAO,GAAG,YAAY,CAAC,MAAM,GAAG,SAAS,CAAC;CAQpF"}
+77
View File
@@ -0,0 +1,77 @@
/******************************************************************************
* Copyright 2021 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 { findCommentNode, findDeclarationNodeAtOffset } from '../utils/cst-utils.js';
import { isKeyword } from '../languages/generated/ast.js';
import { isJSDoc, parseJSDoc } from '../documentation/jsdoc.js';
import { isAstNodeWithComment } from '../serializer/json-serializer.js';
export class AstNodeHoverProvider {
constructor(services) {
this.references = services.references.References;
this.grammarConfig = services.parser.GrammarConfig;
}
async getHoverContent(document, params) {
const rootNode = document.parseResult?.value?.$cstNode;
if (rootNode) {
const offset = document.textDocument.offsetAt(params.position);
const cstNode = findDeclarationNodeAtOffset(rootNode, offset, this.grammarConfig.nameRegexp);
if (cstNode && cstNode.offset + cstNode.length > offset) {
const contents = [];
const targetNodes = this.references.findDeclarations(cstNode);
for (const targetNode of targetNodes) {
const content = await this.getAstNodeHoverContent(targetNode);
if (typeof content === 'string') {
contents.push(content);
}
}
if (contents.length > 0) {
return {
contents: {
kind: 'markdown',
value: contents.join(' ')
}
};
}
// Add support for documentation on keywords
if (isKeyword(cstNode.grammarSource)) {
return this.getKeywordHoverContent(cstNode.grammarSource);
}
}
}
return undefined;
}
getKeywordHoverContent(node) {
let comment = isAstNodeWithComment(node) ? node.$comment : undefined;
if (!comment) {
comment = findCommentNode(node.$cstNode, ['ML_COMMENT'])?.text;
}
if (comment && isJSDoc(comment)) {
const content = parseJSDoc(comment).toMarkdown();
if (content) {
return {
contents: {
kind: 'markdown',
value: content
}
};
}
}
return undefined;
}
}
export class MultilineCommentHoverProvider extends AstNodeHoverProvider {
constructor(services) {
super(services);
this.documentationProvider = services.documentation.DocumentationProvider;
}
getAstNodeHoverContent(node) {
const content = this.documentationProvider.getDocumentation(node);
if (content) {
return content;
}
return undefined;
}
}
//# sourceMappingURL=hover-provider.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"hover-provider.js","sourceRoot":"","sources":["../../src/lsp/hover-provider.ts"],"names":[],"mappings":"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"}
+30
View File
@@ -0,0 +1,30 @@
/******************************************************************************
* Copyright 2022 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 { ImplementationParams, LocationLink } from 'vscode-languageserver';
import type { GrammarConfig } from '../languages/grammar-config.js';
import type { References } from '../references/references.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 '../utils/cancellation.js';
/**
* Language-specific service for handling go to implementation requests.
*/
export interface ImplementationProvider {
/**
* Handles a go to implementation request.
*/
getImplementation(document: LangiumDocument, params: ImplementationParams, cancelToken?: CancellationToken): MaybePromise<LocationLink[] | undefined>;
}
export declare abstract class AbstractGoToImplementationProvider implements ImplementationProvider {
protected readonly references: References;
protected readonly grammarConfig: GrammarConfig;
constructor(services: LangiumServices);
getImplementation(document: LangiumDocument<AstNode>, params: ImplementationParams, cancelToken?: CancellationToken): Promise<LocationLink[] | undefined>;
abstract collectGoToImplementationLocationLinks(element: AstNode, cancelToken: CancellationToken): MaybePromise<LocationLink[] | undefined>;
}
//# sourceMappingURL=implementation-provider.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"implementation-provider.d.ts","sourceRoot":"","sources":["../../src/lsp/implementation-provider.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAG7D;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACnC;;OAEG;IACH,iBAAiB,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,oBAAoB,EAAE,WAAW,CAAC,EAAE,iBAAiB,GAAG,YAAY,CAAC,YAAY,EAAE,GAAG,SAAS,CAAC,CAAC;CACzJ;AAED,8BAAsB,kCAAmC,YAAW,sBAAsB;IACtF,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAC1C,SAAS,CAAC,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;gBAEpC,QAAQ,EAAE,eAAe;IAK/B,iBAAiB,CAAC,QAAQ,EAAE,eAAe,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,oBAAoB,EAAE,WAAW,oBAAyB,GAAG,OAAO,CAAC,YAAY,EAAE,GAAG,SAAS,CAAC;IAkBpK,QAAQ,CAAC,sCAAsC,CAAC,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,iBAAiB,GAAG,YAAY,CAAC,YAAY,EAAE,GAAG,SAAS,CAAC;CAC9I"}
+31
View File
@@ -0,0 +1,31 @@
/******************************************************************************
* Copyright 2022 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 { CancellationToken } from '../utils/cancellation.js';
import { findDeclarationNodeAtOffset } from '../utils/cst-utils.js';
export class AbstractGoToImplementationProvider {
constructor(services) {
this.references = services.references.References;
this.grammarConfig = services.parser.GrammarConfig;
}
async getImplementation(document, params, cancelToken = CancellationToken.None) {
const rootNode = document.parseResult.value;
if (rootNode.$cstNode) {
const sourceCstNode = findDeclarationNodeAtOffset(rootNode.$cstNode, document.textDocument.offsetAt(params.position), this.grammarConfig.nameRegexp);
if (sourceCstNode) {
const nodeDeclarations = this.references.findDeclarations(sourceCstNode);
const links = [];
for (const node of nodeDeclarations) {
const location = await this.collectGoToImplementationLocationLinks(node, cancelToken);
if (location) {
links.push(...location);
}
}
}
}
return undefined;
}
}
//# sourceMappingURL=implementation-provider.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"implementation-provider.js","sourceRoot":"","sources":["../../src/lsp/implementation-provider.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAShF,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,2BAA2B,EAAE,MAAM,uBAAuB,CAAC;AAYpE,MAAM,OAAgB,kCAAkC;IAIpD,YAAY,QAAyB;QACjC,IAAI,CAAC,UAAU,GAAG,QAAQ,CAAC,UAAU,CAAC,UAAU,CAAC;QACjD,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,aAAa,CAAC;IACvD,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,QAAkC,EAAE,MAA4B,EAAE,WAAW,GAAG,iBAAiB,CAAC,IAAI;QAC1H,MAAM,QAAQ,GAAG,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC;QAC5C,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;YACpB,MAAM,aAAa,GAAG,2BAA2B,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;YACrJ,IAAI,aAAa,EAAE,CAAC;gBAChB,MAAM,gBAAgB,GAAG,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,aAAa,CAAC,CAAC;gBACzE,MAAM,KAAK,GAAmB,EAAE,CAAC;gBACjC,KAAK,MAAM,IAAI,IAAI,gBAAgB,EAAE,CAAC;oBAClC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,sCAAsC,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;oBACtF,IAAI,QAAQ,EAAE,CAAC;wBACX,KAAK,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC;oBAC5B,CAAC;gBACL,CAAC;YACL,CAAC;QACL,CAAC;QACD,OAAO,SAAS,CAAC;IACrB,CAAC;CAGJ"}
+39
View File
@@ -0,0 +1,39 @@
/******************************************************************************
* Copyright 2021 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.
*
* @module langium/lsp
*/
export * from './completion/completion-provider.js';
export * from './completion/follow-element-computation.js';
export * from './call-hierarchy-provider.js';
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';
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';
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 './normalized-text-documents.js';
export * from './references-provider.js';
export * from './rename-provider.js';
export * from './semantic-token-provider.js';
export * from './signature-help-provider.js';
export * from './type-hierarchy-provider.js';
export * from './type-provider.js';
export * from './workspace-symbol-provider.js';
//# sourceMappingURL=index.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lsp/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,cAAc,qCAAqC,CAAC;AACpD,cAAc,4CAA4C,CAAC;AAC3D,cAAc,8BAA8B,CAAC;AAC7C,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,kCAAkC,CAAC;AACjD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,0BAA0B,CAAC;AACzC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,yBAAyB,CAAC;AACxC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,0BAA0B,CAAC;AACzC,cAAc,sBAAsB,CAAC;AACrC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,oBAAoB,CAAC;AACnC,cAAc,gCAAgC,CAAC"}
+39
View File
@@ -0,0 +1,39 @@
/******************************************************************************
* Copyright 2021 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.
*
* @module langium/lsp
*/
export * from './completion/completion-provider.js';
export * from './completion/follow-element-computation.js';
export * from './call-hierarchy-provider.js';
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';
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';
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 './normalized-text-documents.js';
export * from './references-provider.js';
export * from './rename-provider.js';
export * from './semantic-token-provider.js';
export * from './signature-help-provider.js';
export * from './type-hierarchy-provider.js';
export * from './type-provider.js';
export * from './workspace-symbol-provider.js';
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/lsp/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,cAAc,qCAAqC,CAAC;AACpD,cAAc,4CAA4C,CAAC;AAC3D,cAAc,8BAA8B,CAAC;AAC7C,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,kCAAkC,CAAC;AACjD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,0BAA0B,CAAC;AACzC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,yBAAyB,CAAC;AACxC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,0BAA0B,CAAC;AACzC,cAAc,sBAAsB,CAAC;AACrC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,oBAAoB,CAAC;AACnC,cAAc,gCAAgC,CAAC"}
+28
View File
@@ -0,0 +1,28 @@
/******************************************************************************
* 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 { InlayHint, InlayHintParams } from 'vscode-languageserver';
import type { AstNode } from '../syntax-tree.js';
import { CancellationToken } from '../utils/cancellation.js';
import type { MaybePromise } from '../utils/promise-utils.js';
import type { LangiumDocument } from '../workspace/documents.js';
export type InlayHintAcceptor = (inlayHint: InlayHint) => void;
/**
* Provider for the inlay hint LSP type.
*/
export interface InlayHintProvider {
/**
* Handle the `textDocument.inlayHint` language server 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
*/
getInlayHints(document: LangiumDocument, params: InlayHintParams, cancelToken?: CancellationToken): MaybePromise<InlayHint[] | undefined>;
}
export declare abstract class AbstractInlayHintProvider implements InlayHintProvider {
getInlayHints(document: LangiumDocument, params: InlayHintParams, cancelToken?: CancellationToken): Promise<InlayHint[] | undefined>;
abstract computeInlayHint(astNode: AstNode, acceptor: InlayHintAcceptor): void;
}
//# sourceMappingURL=inlay-hint-provider.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"inlay-hint-provider.d.ts","sourceRoot":"","sources":["../../src/lsp/inlay-hint-provider.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAIjE,MAAM,MAAM,iBAAiB,GAAG,CAAC,SAAS,EAAE,SAAS,KAAK,IAAI,CAAC;AAE/D;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAC9B;;;;;OAKG;IACH,aAAa,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,eAAe,EAAE,WAAW,CAAC,EAAE,iBAAiB,GAAG,YAAY,CAAC,SAAS,EAAE,GAAG,SAAS,CAAC,CAAC;CAC7I;AAED,8BAAsB,yBAA0B,YAAW,iBAAiB;IAClE,aAAa,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,eAAe,EAAE,WAAW,oBAAyB,GAAG,OAAO,CAAC,SAAS,EAAE,GAAG,SAAS,CAAC;IAW/I,QAAQ,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,iBAAiB,GAAG,IAAI;CACjF"}
+21
View File
@@ -0,0 +1,21 @@
/******************************************************************************
* 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 { CancellationToken } from '../utils/cancellation.js';
import { streamAst } from '../utils/ast-utils.js';
import { interruptAndCheck } from '../utils/promise-utils.js';
export class AbstractInlayHintProvider {
async getInlayHints(document, params, cancelToken = CancellationToken.None) {
const root = document.parseResult.value;
const inlayHints = [];
const acceptor = hint => inlayHints.push(hint);
for (const node of streamAst(root, { range: params.range })) {
await interruptAndCheck(cancelToken);
this.computeInlayHint(node, acceptor);
}
return inlayHints;
}
}
//# sourceMappingURL=inlay-hint-provider.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"inlay-hint-provider.js","sourceRoot":"","sources":["../../src/lsp/inlay-hint-provider.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAIhF,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAG7D,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAiB9D,MAAM,OAAgB,yBAAyB;IAC3C,KAAK,CAAC,aAAa,CAAC,QAAyB,EAAE,MAAuB,EAAE,WAAW,GAAG,iBAAiB,CAAC,IAAI;QACxG,MAAM,IAAI,GAAG,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC;QACxC,MAAM,UAAU,GAAgB,EAAE,CAAC;QACnC,MAAM,QAAQ,GAAsB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClE,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC;YAC1D,MAAM,iBAAiB,CAAC,WAAW,CAAC,CAAC;YACrC,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAC1C,CAAC;QACD,OAAO,UAAU,CAAC;IACtB,CAAC;CAGJ"}
+115
View File
@@ -0,0 +1,115 @@
/******************************************************************************
* Copyright 2021 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 { CallHierarchyIncomingCallsParams, CallHierarchyOutgoingCallsParams, CancellationToken, Connection, Disposable, Event, HandlerResult, InitializedParams, InitializeParams, InitializeResult, RequestHandler, ServerRequestHandler, TextDocumentIdentifier, TypeHierarchySubtypesParams, TypeHierarchySupertypesParams } from 'vscode-languageserver';
import { Emitter } from 'vscode-languageserver-protocol';
import type { LangiumCoreServices } from '../services.js';
import { DocumentState, type LangiumDocument } from '../workspace/documents.js';
import type { LangiumSharedServices, PartialLangiumLSPServices } from './lsp-services.js';
export interface LanguageServer {
initialize(params: InitializeParams): Promise<InitializeResult>;
initialized(params: InitializedParams): void;
onInitialize(callback: (params: InitializeParams) => void): Disposable;
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<LangiumCoreServices & PartialLangiumLSPServices, 'shared'>;
export declare class DefaultLanguageServer implements LanguageServer {
protected onInitializeEmitter: Emitter<InitializeParams>;
protected onInitializedEmitter: Emitter<InitializedParams>;
protected readonly services: LangiumSharedServices;
constructor(services: LangiumSharedServices);
get onInitialize(): Event<InitializeParams>;
get onInitialized(): Event<InitializedParams>;
initialize(params: InitializeParams): Promise<InitializeResult>;
/**
* Eagerly loads all services before emitting the `onInitialize` event.
* Ensures that all services are able to catch the event.
*/
protected eagerLoadServices(): void;
protected hasService(callback: (language: LangiumCoreAndPartialLSPServices) => object | undefined): boolean;
protected buildInitializeResult(_params: InitializeParams): InitializeResult;
initialized(params: InitializedParams): void;
protected fireInitializeOnDefaultServices(params: InitializeParams): void;
protected fireInitializedOnDefaultServices(params: InitializedParams): void;
}
export interface ServiceRequirements {
readonly CallHierarchyProvider: ServiceRequirement;
readonly CodeActionProvider: ServiceRequirement;
readonly CodeLensProvider: ServiceRequirement;
readonly CompletionProvider: ServiceRequirement;
readonly DeclarationProvider: ServiceRequirement;
readonly DefinitionProvider: ServiceRequirement;
readonly DocumentHighlightProvider: ServiceRequirement;
readonly DocumentLinkProvider: ServiceRequirement;
readonly DocumentSymbolProvider: ServiceRequirement;
readonly FoldingRangeProvider: ServiceRequirement;
readonly Formatter: ServiceRequirement;
readonly HoverProvider: ServiceRequirement;
readonly ImplementationProvider: ServiceRequirement;
readonly InlayHintProvider: ServiceRequirement;
readonly ReferencesProvider: ServiceRequirement;
readonly RenameProvider: ServiceRequirement;
readonly SemanticTokenProvider: ServiceRequirement;
readonly SignatureHelp: ServiceRequirement;
readonly TypeHierarchyProvider: ServiceRequirement;
readonly TypeProvider: ServiceRequirement;
readonly WorkspaceSymbolProvider: ServiceRequirement;
}
export type ServiceRequirement = DocumentState | {
readonly type: 'document' | 'workspace';
readonly state: DocumentState;
};
export declare namespace WorkspaceState {
const Parsed: ServiceRequirement;
const IndexedContent: ServiceRequirement;
const ComputedScopes: ServiceRequirement;
const Linked: ServiceRequirement;
const IndexedReferences: ServiceRequirement;
const Validated: ServiceRequirement;
}
export declare function startLanguageServer(services: LangiumSharedServices, serviceRequirements?: Partial<ServiceRequirements>): void;
/**
* 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 declare function addDocumentUpdateHandler(connection: Connection, services: LangiumSharedServices): void;
export declare function addFileOperationHandler(connection: Connection, services: LangiumSharedServices): void;
export declare function addDiagnosticsHandler(connection: Connection, services: LangiumSharedServices): void;
export declare function addCompletionHandler(connection: Connection, services: LangiumSharedServices, requiredState?: ServiceRequirement): void;
export declare function addFindReferencesHandler(connection: Connection, services: LangiumSharedServices, requiredState?: ServiceRequirement): void;
export declare function addCodeActionHandler(connection: Connection, services: LangiumSharedServices, requiredState?: ServiceRequirement): void;
export declare function addDocumentSymbolHandler(connection: Connection, services: LangiumSharedServices, requiredState?: ServiceRequirement): void;
export declare function addGotoDefinitionHandler(connection: Connection, services: LangiumSharedServices, requiredState?: ServiceRequirement): void;
export declare function addGoToTypeDefinitionHandler(connection: Connection, services: LangiumSharedServices, requiredState?: ServiceRequirement): void;
export declare function addGoToImplementationHandler(connection: Connection, services: LangiumSharedServices, requiredState?: ServiceRequirement): void;
export declare function addGoToDeclarationHandler(connection: Connection, services: LangiumSharedServices, requiredState?: ServiceRequirement): void;
export declare function addDocumentHighlightHandler(connection: Connection, services: LangiumSharedServices, requiredState?: ServiceRequirement): void;
export declare function addHoverHandler(connection: Connection, services: LangiumSharedServices, requiredState?: ServiceRequirement): void;
export declare function addFoldingRangeHandler(connection: Connection, services: LangiumSharedServices, requiredState?: ServiceRequirement): void;
export declare function addFormattingHandler(connection: Connection, services: LangiumSharedServices, requiredState?: ServiceRequirement): void;
export declare function addRenameHandler(connection: Connection, services: LangiumSharedServices, requiredState?: ServiceRequirement): void;
export declare function addInlayHintHandler(connection: Connection, services: LangiumSharedServices, requiredState?: ServiceRequirement): void;
export declare function addSemanticTokenHandler(connection: Connection, services: LangiumSharedServices, requiredState?: ServiceRequirement): void;
export declare function addConfigurationChangeHandler(connection: Connection, services: LangiumSharedServices): void;
export declare function addExecuteCommandHandler(connection: Connection, services: LangiumSharedServices): void;
export declare function addDocumentLinkHandler(connection: Connection, services: LangiumSharedServices, requiredState?: ServiceRequirement): void;
export declare function addSignatureHelpHandler(connection: Connection, services: LangiumSharedServices, requiredState?: ServiceRequirement): void;
export declare function addCodeLensHandler(connection: Connection, services: LangiumSharedServices, requiredState?: ServiceRequirement): void;
export declare function addWorkspaceSymbolHandler(connection: Connection, services: LangiumSharedServices, requiredState?: ServiceRequirement): void;
export declare function addCallHierarchyHandler(connection: Connection, services: LangiumSharedServices, requiredState?: ServiceRequirement): void;
export declare function addTypeHierarchyHandler(connection: Connection, sharedServices: LangiumSharedServices, requiredState?: ServiceRequirement): void;
export declare function createHierarchyRequestHandler<P extends TypeHierarchySupertypesParams | TypeHierarchySubtypesParams | CallHierarchyIncomingCallsParams | CallHierarchyOutgoingCallsParams, R, PR, E = void>(serviceCall: (services: LangiumCoreAndPartialLSPServices, params: P, cancelToken: CancellationToken) => HandlerResult<R, E>, sharedServices: LangiumSharedServices, requiredState?: ServiceRequirement): ServerRequestHandler<P, R, PR, E>;
export declare function createServerRequestHandler<P extends {
textDocument: TextDocumentIdentifier;
}, R, PR, E = void>(serviceCall: (services: LangiumCoreAndPartialLSPServices, document: LangiumDocument, params: P, cancelToken: CancellationToken) => HandlerResult<R, E>, sharedServices: LangiumSharedServices, requiredState?: ServiceRequirement): ServerRequestHandler<P, R, PR, E>;
export declare function createRequestHandler<P extends {
textDocument: TextDocumentIdentifier;
}, R, E = void>(serviceCall: (services: LangiumCoreAndPartialLSPServices, document: LangiumDocument, params: P, cancelToken: CancellationToken) => HandlerResult<R, E>, sharedServices: LangiumSharedServices, requiredState?: ServiceRequirement): RequestHandler<P, R | null, E>;
//# sourceMappingURL=language-server.d.ts.map
File diff suppressed because one or more lines are too long
+554
View File
@@ -0,0 +1,554 @@
/******************************************************************************
* Copyright 2021 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 { DidChangeConfigurationNotification, Emitter, LSPErrorCodes, ResponseError, TextDocumentSyncKind } from 'vscode-languageserver-protocol';
import { eagerLoad } from '../dependency-injection.js';
import { isOperationCancelled } from '../utils/promise-utils.js';
import { URI } from '../utils/uri-utils.js';
import { DocumentState } from '../workspace/documents.js';
import { mergeCompletionProviderOptions } from './completion/completion-provider.js';
import { mergeSemanticTokenProviderOptions } from './semantic-token-provider.js';
import { mergeSignatureHelpOptions } from './signature-help-provider.js';
export class DefaultLanguageServer {
constructor(services) {
this.onInitializeEmitter = new Emitter();
this.onInitializedEmitter = new Emitter();
this.services = services;
}
get onInitialize() {
return this.onInitializeEmitter.event;
}
get onInitialized() {
return this.onInitializedEmitter.event;
}
async initialize(params) {
this.eagerLoadServices();
this.fireInitializeOnDefaultServices(params);
this.onInitializeEmitter.fire(params);
this.onInitializeEmitter.dispose();
return this.buildInitializeResult(params);
}
/**
* Eagerly loads all services before emitting the `onInitialize` event.
* Ensures that all services are able to catch the event.
*/
eagerLoadServices() {
eagerLoad(this.services);
this.services.ServiceRegistry.all.forEach(language => eagerLoad(language));
}
hasService(callback) {
const allServices = this.services.ServiceRegistry.all;
return allServices.some(services => callback(services) !== undefined);
}
buildInitializeResult(_params) {
const documentUpdateHandler = this.services.lsp.DocumentUpdateHandler;
const fileOperationOptions = this.services.lsp.FileOperationHandler?.fileOperationOptions;
const allServices = 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 semanticTokensOptions = mergeSemanticTokenProviderOptions(allServices.map(e => e.lsp?.SemanticTokenProvider?.semanticTokensOptions));
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 = {
capabilities: {
workspace: {
workspaceFolders: {
supported: true
},
fileOperations: fileOperationOptions
},
executeCommandProvider: commandNames && {
commands: commandNames
},
textDocumentSync: {
change: TextDocumentSyncKind.Incremental,
openClose: true,
save: Boolean(documentUpdateHandler.didSaveDocument),
willSave: Boolean(documentUpdateHandler.willSaveDocument),
willSaveWaitUntil: Boolean(documentUpdateHandler.willSaveDocumentWaitUntil)
},
completionProvider: hasCompletionProvider ? completionOptions : undefined,
referencesProvider: hasReferencesProvider,
documentSymbolProvider: hasDocumentSymbolProvider,
definitionProvider: hasDefinitionProvider,
typeDefinitionProvider: hasGoToTypeProvider,
documentHighlightProvider: hasDocumentHighlightProvider,
codeActionProvider: hasCodeActionProvider,
documentFormattingProvider: hasFormattingService,
documentRangeFormattingProvider: hasFormattingService,
documentOnTypeFormattingProvider: formattingOnTypeOptions,
foldingRangeProvider: hasFoldingRangeProvider,
hoverProvider: hasHoverProvider,
renameProvider: hasRenameProvider ? {
prepareProvider: true
} : undefined,
semanticTokensProvider: hasSemanticTokensProvider
? semanticTokensOptions
: undefined,
signatureHelpProvider: signatureHelpOptions,
implementationProvider: hasGoToImplementationProvider,
callHierarchyProvider: hasCallHierarchyProvider
? {}
: undefined,
typeHierarchyProvider: hasTypeHierarchyProvider
? {}
: undefined,
documentLinkProvider: hasDocumentLinkProvider
? { resolveProvider: false }
: undefined,
codeLensProvider: hasCodeLensProvider
? { resolveProvider: false }
: undefined,
declarationProvider: hasDeclarationProvider,
inlayHintProvider: hasInlayHintProvider
? { resolveProvider: false }
: undefined,
workspaceSymbolProvider: workspaceSymbolProvider
? { resolveProvider: Boolean(workspaceSymbolProvider.resolveSymbol) }
: undefined
}
};
return result;
}
initialized(params) {
this.fireInitializedOnDefaultServices(params);
this.onInitializedEmitter.fire(params);
this.onInitializedEmitter.dispose();
}
fireInitializeOnDefaultServices(params) {
this.services.workspace.ConfigurationProvider.initialize(params);
this.services.workspace.WorkspaceManager.initialize(params);
}
fireInitializedOnDefaultServices(params) {
const connection = this.services.lsp.Connection;
const configurationParams = connection ? {
...params,
register: params => connection.client.register(DidChangeConfigurationNotification.type, params),
fetchConfiguration: params => connection.workspace.getConfiguration(params)
} : params;
// do not await the promises of the following calls, as they must not block the initialization process!
// otherwise, there is the danger of out-of-order processing of subsequent incoming messages from the language client
// however, awaiting should be possible in general, e.g. in unit test scenarios
this.services.workspace.ConfigurationProvider.initialized(configurationParams)
.catch(err => console.error('Error in ConfigurationProvider initialization:', err));
this.services.workspace.WorkspaceManager.initialized(params)
.catch(err => console.error('Error in WorkspaceManager initialization:', err));
}
}
function isDocumentState(obj) {
return typeof obj === 'number';
}
export var WorkspaceState;
(function (WorkspaceState) {
WorkspaceState.Parsed = Object.freeze({ type: 'workspace', state: DocumentState.Parsed });
WorkspaceState.IndexedContent = Object.freeze({ type: 'workspace', state: DocumentState.IndexedContent });
WorkspaceState.ComputedScopes = Object.freeze({ type: 'workspace', state: DocumentState.ComputedScopes });
WorkspaceState.Linked = Object.freeze({ type: 'workspace', state: DocumentState.Linked });
WorkspaceState.IndexedReferences = Object.freeze({ type: 'workspace', state: DocumentState.IndexedReferences });
WorkspaceState.Validated = Object.freeze({ type: 'workspace', state: DocumentState.Validated });
})(WorkspaceState || (WorkspaceState = {}));
export function startLanguageServer(services, serviceRequirements = {}) {
const connection = services.lsp.Connection;
if (!connection) {
throw new Error('Starting a language server requires the languageServer.Connection service to be set.');
}
addDocumentUpdateHandler(connection, services);
addFileOperationHandler(connection, services);
addDiagnosticsHandler(connection, services);
addCompletionHandler(connection, services, serviceRequirements.CompletionProvider);
addFindReferencesHandler(connection, services, serviceRequirements.ReferencesProvider);
addDocumentSymbolHandler(connection, services, serviceRequirements.DocumentSymbolProvider);
addGotoDefinitionHandler(connection, services, serviceRequirements.DefinitionProvider);
addGoToTypeDefinitionHandler(connection, services, serviceRequirements.TypeProvider);
addGoToImplementationHandler(connection, services, serviceRequirements.ImplementationProvider);
addDocumentHighlightHandler(connection, services, serviceRequirements.DocumentHighlightProvider);
addFoldingRangeHandler(connection, services, serviceRequirements.FoldingRangeProvider);
addFormattingHandler(connection, services, serviceRequirements.Formatter);
addCodeActionHandler(connection, services, serviceRequirements.CodeActionProvider);
addRenameHandler(connection, services, serviceRequirements.RenameProvider);
addHoverHandler(connection, services, serviceRequirements.HoverProvider);
addInlayHintHandler(connection, services, serviceRequirements.InlayHintProvider);
addSemanticTokenHandler(connection, services, serviceRequirements.SemanticTokenProvider);
addExecuteCommandHandler(connection, services);
addSignatureHelpHandler(connection, services, serviceRequirements.SignatureHelp);
addCallHierarchyHandler(connection, services, serviceRequirements.CallHierarchyProvider);
addTypeHierarchyHandler(connection, services, serviceRequirements.TypeHierarchyProvider);
addCodeLensHandler(connection, services, serviceRequirements.CodeLensProvider);
addDocumentLinkHandler(connection, services, serviceRequirements.DocumentLinkProvider);
addConfigurationChangeHandler(connection, services);
addGoToDeclarationHandler(connection, services, serviceRequirements.DeclarationProvider);
addWorkspaceSymbolHandler(connection, services, serviceRequirements.WorkspaceSymbolProvider);
connection.onInitialize(params => {
return services.lsp.LanguageServer.initialize(params);
});
connection.onInitialized(params => {
services.lsp.LanguageServer.initialized(params);
});
// Make the text document manager listen on the connection for open, change and close text document events.
const documents = services.workspace.TextDocuments;
documents.listen(connection);
// Start listening for incoming messages from the client.
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, services) {
const handler = services.lsp.DocumentUpdateHandler;
const documents = services.workspace.TextDocuments;
if (handler.didOpenDocument) {
documents.onDidOpen(change => handler.didOpenDocument(change));
}
if (handler.didChangeContent) {
documents.onDidChangeContent(change => handler.didChangeContent(change));
}
if (handler.didCloseDocument) {
documents.onDidClose(change => handler.didCloseDocument(change));
}
if (handler.didSaveDocument) {
documents.onDidSave(change => handler.didSaveDocument(change));
}
if (handler.willSaveDocument) {
documents.onWillSave(event => handler.willSaveDocument(event));
}
if (handler.willSaveDocumentWaitUntil) {
documents.onWillSaveWaitUntil(event => handler.willSaveDocumentWaitUntil(event));
}
if (handler.didChangeWatchedFiles) {
connection.onDidChangeWatchedFiles(params => handler.didChangeWatchedFiles(params));
}
}
export function addFileOperationHandler(connection, services) {
const handler = services.lsp.FileOperationHandler;
if (!handler) {
return;
}
if (handler.didCreateFiles) {
connection.workspace.onDidCreateFiles(params => handler.didCreateFiles(params));
}
if (handler.didRenameFiles) {
connection.workspace.onDidRenameFiles(params => handler.didRenameFiles(params));
}
if (handler.didDeleteFiles) {
connection.workspace.onDidDeleteFiles(params => handler.didDeleteFiles(params));
}
if (handler.willCreateFiles) {
connection.workspace.onWillCreateFiles(params => handler.willCreateFiles(params));
}
if (handler.willRenameFiles) {
connection.workspace.onWillRenameFiles(params => handler.willRenameFiles(params));
}
if (handler.willDeleteFiles) {
connection.workspace.onWillDeleteFiles(params => handler.willDeleteFiles(params));
}
}
export function addDiagnosticsHandler(connection, services) {
const documentBuilder = services.workspace.DocumentBuilder;
documentBuilder.onUpdate(async (_, deleted) => {
for (const uri of deleted) {
connection.sendDiagnostics({
uri: uri.toString(),
diagnostics: []
});
}
});
documentBuilder.onDocumentPhase(DocumentState.Validated, async (document) => {
if (document.diagnostics) {
connection.sendDiagnostics({
uri: document.uri.toString(),
diagnostics: document.diagnostics
});
}
});
}
export function addCompletionHandler(connection, services, requiredState = DocumentState.Linked) {
connection.onCompletion(createRequestHandler((services, document, params, cancelToken) => {
return services.lsp?.CompletionProvider?.getCompletion(document, params, cancelToken);
}, services, requiredState));
}
export function addFindReferencesHandler(connection, services, requiredState = WorkspaceState.IndexedReferences) {
connection.onReferences(createRequestHandler((services, document, params, cancelToken) => services.lsp?.ReferencesProvider?.findReferences(document, params, cancelToken), services, requiredState));
}
export function addCodeActionHandler(connection, services, requiredState = DocumentState.Validated) {
connection.onCodeAction(createRequestHandler((services, document, params, cancelToken) => services.lsp?.CodeActionProvider?.getCodeActions(document, params, cancelToken), services, requiredState));
}
export function addDocumentSymbolHandler(connection, services, requiredState = DocumentState.Parsed) {
connection.onDocumentSymbol(createRequestHandler((services, document, params, cancelToken) => services.lsp?.DocumentSymbolProvider?.getSymbols(document, params, cancelToken), services, requiredState));
}
export function addGotoDefinitionHandler(connection, services, requiredState = DocumentState.Linked) {
connection.onDefinition(createRequestHandler((services, document, params, cancelToken) => services.lsp?.DefinitionProvider?.getDefinition(document, params, cancelToken), services, requiredState));
}
export function addGoToTypeDefinitionHandler(connection, services, requiredState = DocumentState.Linked) {
connection.onTypeDefinition(createRequestHandler((services, document, params, cancelToken) => services.lsp?.TypeProvider?.getTypeDefinition(document, params, cancelToken), services, requiredState));
}
export function addGoToImplementationHandler(connection, services, requiredState = WorkspaceState.IndexedReferences) {
connection.onImplementation(createRequestHandler((services, document, params, cancelToken) => services.lsp?.ImplementationProvider?.getImplementation(document, params, cancelToken), services, requiredState));
}
export function addGoToDeclarationHandler(connection, services, requiredState = DocumentState.Linked) {
connection.onDeclaration(createRequestHandler((services, document, params, cancelToken) => services.lsp?.DeclarationProvider?.getDeclaration(document, params, cancelToken), services, requiredState));
}
export function addDocumentHighlightHandler(connection, services, requiredState = WorkspaceState.IndexedReferences) {
connection.onDocumentHighlight(createRequestHandler((services, document, params, cancelToken) => services.lsp?.DocumentHighlightProvider?.getDocumentHighlight(document, params, cancelToken), services, requiredState));
}
export function addHoverHandler(connection, services, requiredState = DocumentState.Linked) {
connection.onHover(createRequestHandler((services, document, params, cancelToken) => services.lsp?.HoverProvider?.getHoverContent(document, params, cancelToken), services, requiredState));
}
export function addFoldingRangeHandler(connection, services, requiredState = DocumentState.Parsed) {
connection.onFoldingRanges(createRequestHandler((services, document, params, cancelToken) => services.lsp?.FoldingRangeProvider?.getFoldingRanges(document, params, cancelToken), services, requiredState));
}
export function addFormattingHandler(connection, services, requiredState = DocumentState.Parsed) {
connection.onDocumentFormatting(createRequestHandler((services, document, params, cancelToken) => services.lsp?.Formatter?.formatDocument(document, params, cancelToken), services, requiredState));
connection.onDocumentRangeFormatting(createRequestHandler((services, document, params, cancelToken) => services.lsp?.Formatter?.formatDocumentRange(document, params, cancelToken), services, requiredState));
connection.onDocumentOnTypeFormatting(createRequestHandler((services, document, params, cancelToken) => services.lsp?.Formatter?.formatDocumentOnType(document, params, cancelToken), services, requiredState));
}
export function addRenameHandler(connection, services, requiredState = WorkspaceState.IndexedReferences) {
connection.onRenameRequest(createRequestHandler((services, document, params, cancelToken) => services.lsp?.RenameProvider?.rename(document, params, cancelToken), services, requiredState));
connection.onPrepareRename(createRequestHandler((services, document, params, cancelToken) => services.lsp?.RenameProvider?.prepareRename(document, params, cancelToken), services, requiredState));
}
export function addInlayHintHandler(connection, services, requiredState = DocumentState.IndexedReferences) {
connection.languages.inlayHint.on(createServerRequestHandler((services, document, params, cancelToken) => services.lsp?.InlayHintProvider?.getInlayHints(document, params, cancelToken), services, requiredState));
}
export function addSemanticTokenHandler(connection, services, requiredState = DocumentState.Linked) {
// If no semantic token provider is registered that's fine. Just return an empty result
const emptyResult = { data: [] };
connection.languages.semanticTokens.on(createServerRequestHandler((services, document, params, cancelToken) => {
if (services.lsp?.SemanticTokenProvider) {
return services.lsp.SemanticTokenProvider.semanticHighlight(document, params, cancelToken);
}
return emptyResult;
}, services, requiredState));
connection.languages.semanticTokens.onDelta(createServerRequestHandler((services, document, params, cancelToken) => {
if (services.lsp?.SemanticTokenProvider) {
return services.lsp.SemanticTokenProvider.semanticHighlightDelta(document, params, cancelToken);
}
return emptyResult;
}, services, requiredState));
connection.languages.semanticTokens.onRange(createServerRequestHandler((services, document, params, cancelToken) => {
if (services.lsp?.SemanticTokenProvider) {
return services.lsp.SemanticTokenProvider.semanticHighlightRange(document, params, cancelToken);
}
return emptyResult;
}, services, requiredState));
}
export function addConfigurationChangeHandler(connection, services) {
connection.onDidChangeConfiguration(change => {
services.workspace.ConfigurationProvider.updateConfiguration(change);
});
}
export function addExecuteCommandHandler(connection, services) {
const commandHandler = services.lsp.ExecuteCommandHandler;
if (commandHandler) {
connection.onExecuteCommand(async (params, token) => {
try {
return await commandHandler.executeCommand(params.command, params.arguments ?? [], token);
}
catch (err) {
return responseError(err);
}
});
}
}
export function addDocumentLinkHandler(connection, services, requiredState = DocumentState.Parsed) {
connection.onDocumentLinks(createServerRequestHandler((services, document, params, cancelToken) => services.lsp?.DocumentLinkProvider?.getDocumentLinks(document, params, cancelToken), services, requiredState));
}
export function addSignatureHelpHandler(connection, services, requiredState = DocumentState.IndexedReferences) {
connection.onSignatureHelp(createServerRequestHandler((services, document, params, cancelToken) => services.lsp?.SignatureHelp?.provideSignatureHelp(document, params, cancelToken), services, requiredState));
}
export function addCodeLensHandler(connection, services, requiredState = DocumentState.IndexedReferences) {
connection.onCodeLens(createServerRequestHandler((services, document, params, cancelToken) => services.lsp?.CodeLensProvider?.provideCodeLens(document, params, cancelToken), services, requiredState));
}
export function addWorkspaceSymbolHandler(connection, services, requiredState = WorkspaceState.IndexedContent) {
const workspaceSymbolProvider = services.lsp.WorkspaceSymbolProvider;
if (workspaceSymbolProvider) {
if (isDocumentState(requiredState) || requiredState.type === 'document') {
throw new Error('Workspace symbol requests are independent of a certain document, so the given document-specific required state is invalid. Provide a service requirement of type "workspace".');
}
const documentBuilder = services.workspace.DocumentBuilder;
connection.onWorkspaceSymbol(async (params, token) => {
try {
await documentBuilder.waitUntil(requiredState.state, token);
return await workspaceSymbolProvider.getSymbols(params, token);
}
catch (err) {
return responseError(err);
}
});
const resolveWorkspaceSymbol = workspaceSymbolProvider.resolveSymbol?.bind(workspaceSymbolProvider);
if (resolveWorkspaceSymbol) {
connection.onWorkspaceSymbolResolve(async (workspaceSymbol, token) => {
try {
await documentBuilder.waitUntil(requiredState.state, token);
return await resolveWorkspaceSymbol(workspaceSymbol, token);
}
catch (err) {
return responseError(err);
}
});
}
}
}
export function addCallHierarchyHandler(connection, services, requiredState = WorkspaceState.IndexedReferences) {
connection.languages.callHierarchy.onPrepare(createServerRequestHandler(async (services, document, params, cancelToken) => {
if (services.lsp?.CallHierarchyProvider) {
const result = await services.lsp.CallHierarchyProvider.prepareCallHierarchy(document, params, cancelToken);
return result ?? null;
}
return null;
}, services, requiredState));
connection.languages.callHierarchy.onIncomingCalls(createHierarchyRequestHandler(async (services, params, cancelToken) => {
if (services.lsp?.CallHierarchyProvider) {
const result = await services.lsp.CallHierarchyProvider.incomingCalls(params, cancelToken);
return result ?? null;
}
return null;
}, services, requiredState));
connection.languages.callHierarchy.onOutgoingCalls(createHierarchyRequestHandler(async (services, params, cancelToken) => {
if (services.lsp?.CallHierarchyProvider) {
const result = await services.lsp.CallHierarchyProvider.outgoingCalls(params, cancelToken);
return result ?? null;
}
return null;
}, services, requiredState));
}
export function addTypeHierarchyHandler(connection, sharedServices, requiredState = WorkspaceState.IndexedReferences) {
// Don't register type hierarchy handlers if no type hierarchy provider is registered
if (!sharedServices.ServiceRegistry.all.some((services) => services.lsp?.TypeHierarchyProvider)) {
return;
}
connection.languages.typeHierarchy.onPrepare(createServerRequestHandler(async (services, document, params, cancelToken) => {
const result = await services.lsp?.TypeHierarchyProvider?.prepareTypeHierarchy(document, params, cancelToken);
return result ?? null;
}, sharedServices, requiredState));
connection.languages.typeHierarchy.onSupertypes(createHierarchyRequestHandler(async (services, params, cancelToken) => {
const result = await services.lsp?.TypeHierarchyProvider?.supertypes(params, cancelToken);
return result ?? null;
}, sharedServices, requiredState));
connection.languages.typeHierarchy.onSubtypes(createHierarchyRequestHandler(async (services, params, cancelToken) => {
const result = await services.lsp?.TypeHierarchyProvider?.subtypes(params, cancelToken);
return result ?? null;
}, sharedServices, requiredState));
}
export function createHierarchyRequestHandler(serviceCall, sharedServices, requiredState) {
const serviceRegistry = sharedServices.ServiceRegistry;
return async (params, cancelToken) => {
const uri = URI.parse(params.item.uri);
const cancellationError = await waitUntilPhase(sharedServices, cancelToken, uri, requiredState);
if (cancellationError) {
return cancellationError;
}
if (!serviceRegistry.hasServices(uri)) {
const errorText = `Could not find service instance for uri: '${uri}'`;
console.debug(errorText);
return responseError(new Error(errorText));
}
const language = serviceRegistry.getServices(uri);
try {
return await serviceCall(language, params, cancelToken);
}
catch (err) {
return responseError(err);
}
};
}
export function createServerRequestHandler(serviceCall, sharedServices, requiredState) {
const documents = sharedServices.workspace.LangiumDocuments;
const serviceRegistry = sharedServices.ServiceRegistry;
return async (params, cancelToken) => {
const uri = URI.parse(params.textDocument.uri);
const cancellationError = await waitUntilPhase(sharedServices, cancelToken, uri, requiredState);
if (cancellationError) {
return cancellationError;
}
if (!serviceRegistry.hasServices(uri)) {
const errorText = `Could not find service instance for uri: '${uri}'`;
console.debug(errorText);
return responseError(new Error(errorText));
}
const language = serviceRegistry.getServices(uri);
try {
const document = await documents.getOrCreateDocument(uri);
return await serviceCall(language, document, params, cancelToken);
}
catch (err) {
return responseError(err);
}
};
}
export function createRequestHandler(serviceCall, sharedServices, requiredState) {
const documents = sharedServices.workspace.LangiumDocuments;
const serviceRegistry = sharedServices.ServiceRegistry;
return async (params, cancelToken) => {
const uri = URI.parse(params.textDocument.uri);
const cancellationError = await waitUntilPhase(sharedServices, cancelToken, uri, requiredState);
if (cancellationError) {
return cancellationError;
}
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(err);
}
};
}
async function waitUntilPhase(services, cancelToken, uri, requiredState) {
if (requiredState !== undefined) {
const documentBuilder = services.workspace.DocumentBuilder;
const workspaceManager = services.workspace.WorkspaceManager;
try {
await workspaceManager.ready; // mandatory if awaiting the state of a document (uri !== undefined) while the LS is starting
if (isDocumentState(requiredState)) {
await documentBuilder.waitUntil(requiredState, uri, cancelToken);
}
else if (requiredState.type === 'document') {
await documentBuilder.waitUntil(requiredState.state, uri, cancelToken);
}
else {
await documentBuilder.waitUntil(requiredState.state, cancelToken);
}
}
catch (err) {
return responseError(err);
}
}
return undefined;
}
function responseError(err) {
if (isOperationCancelled(err)) {
return new ResponseError(LSPErrorCodes.RequestCancelled, 'The request has been cancelled.');
}
if (err instanceof ResponseError) {
return err;
}
throw err;
}
//# sourceMappingURL=language-server.js.map
File diff suppressed because one or more lines are too long
+108
View File
@@ -0,0 +1,108 @@
/******************************************************************************
* 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 } 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';
import type { NotebookDocuments, TextDocuments } from './normalized-text-documents.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 = {
readonly lsp: {
readonly CompletionProvider?: CompletionProvider;
readonly DocumentHighlightProvider?: DocumentHighlightProvider;
readonly DocumentSymbolProvider?: DocumentSymbolProvider;
readonly HoverProvider?: HoverProvider;
readonly FoldingRangeProvider?: FoldingRangeProvider;
readonly DefinitionProvider?: DefinitionProvider;
readonly TypeProvider?: TypeDefinitionProvider;
readonly ImplementationProvider?: ImplementationProvider;
readonly ReferencesProvider?: ReferencesProvider;
readonly CodeActionProvider?: CodeActionProvider;
readonly SemanticTokenProvider?: SemanticTokenProvider;
readonly RenameProvider?: RenameProvider;
readonly Formatter?: Formatter;
readonly SignatureHelp?: SignatureHelpProvider;
readonly CallHierarchyProvider?: CallHierarchyProvider;
readonly TypeHierarchyProvider?: TypeHierarchyProvider;
readonly DeclarationProvider?: DeclarationProvider;
readonly InlayHintProvider?: InlayHintProvider;
readonly CodeLensProvider?: CodeLensProvider;
readonly DocumentLinkProvider?: DocumentLinkProvider;
};
readonly shared: LangiumSharedServices;
};
/**
* LSP services shared between multiple languages of which Langium provides default implementations.
*/
export type LangiumSharedLSPServices = {
readonly lsp: {
readonly Connection?: Connection;
readonly DocumentUpdateHandler: DocumentUpdateHandler;
readonly ExecuteCommandHandler?: ExecuteCommandHandler;
readonly FileOperationHandler?: FileOperationHandler;
readonly FuzzyMatcher: FuzzyMatcher;
readonly LanguageServer: LanguageServer;
readonly NodeKindProvider: NodeKindProvider;
readonly WorkspaceSymbolProvider?: WorkspaceSymbolProvider;
};
readonly workspace: {
readonly TextDocuments: TextDocuments<TextDocument>;
readonly NotebookDocuments: NotebookDocuments<TextDocument>;
};
};
/**
* Language-specific LSP services to be partially overridden via dependency injection.
*/
export type PartialLangiumLSPServices = DeepPartial<LangiumLSPServices>;
/**
* Language-specific services to be partially overridden via dependency injection.
*/
export type PartialLangiumServices = DeepPartial<LangiumServices>;
/**
* Shared LSP services to be partially overridden via dependency injection.
*/
export type PartialLangiumSharedLSPServices = DeepPartial<LangiumSharedLSPServices>;
/**
* Shared services to be partially overridden via dependency injection.
*/
export type PartialLangiumSharedServices = DeepPartial<LangiumSharedServices>;
//# sourceMappingURL=lsp-services.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"lsp-services.d.ts","sourceRoot":"","sources":["../../src/lsp/lsp-services.ts"],"names":[],"mappings":"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"}
+7
View File
@@ -0,0 +1,7 @@
/******************************************************************************
* 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.
******************************************************************************/
export {};
//# sourceMappingURL=lsp-services.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"lsp-services.js","sourceRoot":"","sources":["../../src/lsp/lsp-services.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF"}
+39
View File
@@ -0,0 +1,39 @@
/******************************************************************************
* 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 { AstNode, AstNodeDescription } from '../syntax-tree.js';
import { CompletionItemKind, SymbolKind } from 'vscode-languageserver';
/**
* This service consolidates the logic for gathering LSP kind information based on AST nodes or their descriptions.
*/
export interface NodeKindProvider {
/**
* Returns a `SymbolKind` as used by `WorkspaceSymbolProvider` or `DocumentSymbolProvider`.
* @param node AST node or node description.
* @returns The corresponding symbol kind.
*/
getSymbolKind(node: AstNode | AstNodeDescription): SymbolKind;
/**
* Returns a `CompletionItemKind` as used by the `CompletionProvider`.
* @param node AST node or node description.
* @returns The corresponding completion item kind.
*/
getCompletionItemKind(node: AstNode | AstNodeDescription): CompletionItemKind;
}
/**
* Default implementation of the `NodeKindProvider` interface.
* @remarks This implementation returns `SymbolKind.Field` for all nodes and `CompletionItemKind.Reference` for all nodes. Extend this class to customize symbol and completion types your langauge.
*/
export declare class DefaultNodeKindProvider implements NodeKindProvider {
/**
* @remarks The default implementation returns `SymbolKind.Field` for all nodes.
*/
getSymbolKind(_node: AstNode | AstNodeDescription): SymbolKind;
/**
* @remarks The default implementation returns `CompletionItemKind.Reference` for all nodes.
*/
getCompletionItemKind(_node: AstNode | AstNodeDescription): CompletionItemKind;
}
//# sourceMappingURL=node-kind-provider.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"node-kind-provider.d.ts","sourceRoot":"","sources":["../../src/lsp/node-kind-provider.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEvE;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC7B;;;;OAIG;IACH,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,kBAAkB,GAAG,UAAU,CAAC;IAC9D;;;;OAIG;IACH,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,kBAAkB,GAAG,kBAAkB,CAAC;CACjF;AAED;;;GAGG;AACH,qBAAa,uBAAwB,YAAW,gBAAgB;IAC5D;;OAEG;IACH,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,kBAAkB,GAAG,UAAU;IAG9D;;OAEG;IACH,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,kBAAkB,GAAG,kBAAkB;CAGjF"}
+25
View File
@@ -0,0 +1,25 @@
/******************************************************************************
* 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 { CompletionItemKind, SymbolKind } from 'vscode-languageserver';
/**
* Default implementation of the `NodeKindProvider` interface.
* @remarks This implementation returns `SymbolKind.Field` for all nodes and `CompletionItemKind.Reference` for all nodes. Extend this class to customize symbol and completion types your langauge.
*/
export class DefaultNodeKindProvider {
/**
* @remarks The default implementation returns `SymbolKind.Field` for all nodes.
*/
getSymbolKind(_node) {
return SymbolKind.Field;
}
/**
* @remarks The default implementation returns `CompletionItemKind.Reference` for all nodes.
*/
getCompletionItemKind(_node) {
return CompletionItemKind.Reference;
}
}
//# sourceMappingURL=node-kind-provider.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"node-kind-provider.js","sourceRoot":"","sources":["../../src/lsp/node-kind-provider.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAGhF,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAoBvE;;;GAGG;AACH,MAAM,OAAO,uBAAuB;IAChC;;OAEG;IACH,aAAa,CAAC,KAAmC;QAC7C,OAAO,UAAU,CAAC,KAAK,CAAC;IAC5B,CAAC;IACD;;OAEG;IACH,qBAAqB,CAAC,KAAmC;QACrD,OAAO,kBAAkB,CAAC,SAAS,CAAC;IACxC,CAAC;CACJ"}
+181
View File
@@ -0,0 +1,181 @@
/******************************************************************************
* 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.
******************************************************************************/
import type { Connection, TextDocumentsConfiguration, TextDocumentChangeEvent, TextDocumentWillSaveEvent, RequestHandler, TextEdit, Event, NotebookCell, NotebookDocument, DocumentUri } from 'vscode-languageserver';
import { Disposable } from 'vscode-languageserver';
import type { URI } from '../utils/uri-utils.js';
import type { NotebookDocumentChangeEvent } from 'vscode-languageserver/lib/common/notebook.js';
export type TextDocumentConnection = Pick<Connection, 'onDidOpenTextDocument' | 'onDidChangeTextDocument' | 'onDidCloseTextDocument' | 'onWillSaveTextDocument' | 'onWillSaveTextDocumentWaitUntil' | 'onDidSaveTextDocument'>;
/**
* A manager service that keeps track of all currently opened text documents.
*
* Designed to be compatible with the `TextDocuments` class in the `vscode-languageserver` package.
*/
export interface TextDocuments<T extends {
uri: string;
}> {
/**
* An event that fires when a text document managed by this manager
* has been opened.
*/
readonly onDidOpen: Event<TextDocumentChangeEvent<T>>;
/**
* An event that fires when a text document managed by this manager
* has been opened or the content changes.
*/
readonly onDidChangeContent: Event<TextDocumentChangeEvent<T>>;
/**
* An event that fires when a text document managed by this manager
* will be saved.
*/
readonly onWillSave: Event<TextDocumentWillSaveEvent<T>>;
/**
* Sets a handler that will be called if a participant wants to provide
* edits during a text document save.
*/
onWillSaveWaitUntil(handler: RequestHandler<TextDocumentWillSaveEvent<T>, TextEdit[], void>): void;
/**
* An event that fires when a text document managed by this manager
* has been saved.
*/
readonly onDidSave: Event<TextDocumentChangeEvent<T>>;
/**
* An event that fires when a text document managed by this manager
* has been closed.
*/
readonly onDidClose: Event<TextDocumentChangeEvent<T>>;
/**
* Returns the document for the given URI. Returns undefined if
* the document is not managed by this instance.
*
* @param uri The text document's URI to retrieve.
* @return the text document or `undefined`.
*/
get(uri: string | URI): T | undefined;
/**
* Sets the text document managed by this instance.
* @param document The text document to add.
* @returns `true` if the document didn't exist yet, `false` if it was already present.
*/
set(document: T): boolean;
/**
* Deletes a text document managed by this instance.
*/
delete(uri: string | URI | T): void;
/**
* Returns all text documents managed by this instance.
*
* @return all text documents.
*/
all(): T[];
/**
* Returns the URIs of all text documents managed by this instance.
*
* @return the URI's of all text documents.
*/
keys(): string[];
/**
* Listens for `low level` notification on the given connection to
* update the text documents managed by this instance.
*
* Please note that the connection only provides handlers not an event model. Therefore
* listening on a connection will overwrite the following handlers on a connection:
* `onDidOpenTextDocument`, `onDidChangeTextDocument`, `onDidCloseTextDocument`,
* `onWillSaveTextDocument`, `onWillSaveTextDocumentWaitUntil` and `onDidSaveTextDocument`.
*
* Use the corresponding events on the TextDocuments instance instead.
*
* @param connection The connection to listen on.
*/
listen(connection: TextDocumentConnection): Disposable;
}
/**
* Normalizing text document manager. Normalizes all incoming URIs to the same format used by VS Code.
*/
export declare class NormalizedTextDocuments<T extends {
uri: string;
}> implements TextDocuments<T> {
private readonly _configuration;
private readonly _syncedDocuments;
private readonly _onDidChangeContent;
private readonly _onDidOpen;
private readonly _onDidClose;
private readonly _onDidSave;
private readonly _onWillSave;
private _willSaveWaitUntil;
constructor(configuration: TextDocumentsConfiguration<T>);
get onDidOpen(): Event<TextDocumentChangeEvent<T>>;
get onDidChangeContent(): Event<TextDocumentChangeEvent<T>>;
get onWillSave(): Event<TextDocumentWillSaveEvent<T>>;
onWillSaveWaitUntil(handler: RequestHandler<TextDocumentWillSaveEvent<T>, TextEdit[], void>): void;
get onDidSave(): Event<TextDocumentChangeEvent<T>>;
get onDidClose(): Event<TextDocumentChangeEvent<T>>;
get(uri: string | URI): T | undefined;
set(document: T): boolean;
delete(uri: string | T | URI): void;
all(): T[];
keys(): string[];
listen(connection: Connection): Disposable;
}
export interface NotebookDocuments<T extends {
uri: string;
}> {
get cellTextDocuments(): TextDocuments<T>;
getCellTextDocument(cell: NotebookCell): T | undefined;
getNotebookDocument(uri: string | URI): NotebookDocument | undefined;
getNotebookCell(uri: string | URI): NotebookCell | undefined;
findNotebookDocumentForCell(cell: string | URI | NotebookCell): NotebookDocument | undefined;
get onDidOpen(): Event<NotebookDocument>;
get onDidSave(): Event<NotebookDocument>;
get onDidChange(): Event<NotebookDocumentChangeEvent>;
get onDidClose(): Event<NotebookDocument>;
/**
* Listens for `low level` notification on the given connection to
* update the notebook documents managed by this instance.
*
* Please note that the connection only provides handlers not an event model. Therefore
* listening on a connection will overwrite the following handlers on a connection:
* `onDidOpenNotebookDocument`, `onDidChangeNotebookDocument`, `onDidSaveNotebookDocument`,
* and `onDidCloseNotebookDocument`.
*
* @param connection The connection to listen on.
*/
listen(connection: Connection): Disposable;
}
export declare class NormalizedNotebookDocuments<T extends {
uri: DocumentUri;
}> implements NotebookDocuments<T> {
private readonly notebookDocuments;
private readonly notebookCellMap;
private readonly _onDidOpen;
private readonly _onDidSave;
private readonly _onDidChange;
private readonly _onDidClose;
private readonly _cellTextDocuments;
constructor(configurationOrTextDocuments: TextDocumentsConfiguration<T> | TextDocuments<T>);
get cellTextDocuments(): TextDocuments<T>;
getCellTextDocument(cell: NotebookCell): T | undefined;
getNotebookDocument(uri: string | URI): NotebookDocument | undefined;
getNotebookCell(uri: string | URI): NotebookCell | undefined;
findNotebookDocumentForCell(cell: string | URI | NotebookCell): NotebookDocument | undefined;
get onDidOpen(): Event<NotebookDocument>;
get onDidSave(): Event<NotebookDocument>;
get onDidChange(): Event<NotebookDocumentChangeEvent>;
get onDidClose(): Event<NotebookDocument>;
/**
* Listens for `low level` notification on the given connection to
* update the notebook documents managed by this instance.
*
* Please note that the connection only provides handlers not an event model. Therefore
* listening on a connection will overwrite the following handlers on a connection:
* `onDidOpenNotebookDocument`, `onDidChangeNotebookDocument`, `onDidSaveNotebookDocument`,
* and `onDidCloseNotebookDocument`.
*
* @param connection The connection to listen on.
*/
listen(connection: Connection): Disposable;
private updateCellMap;
}
//# sourceMappingURL=normalized-text-documents.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"normalized-text-documents.d.ts","sourceRoot":"","sources":["../../src/lsp/normalized-text-documents.ts"],"names":[],"mappings":"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"}
+354
View File
@@ -0,0 +1,354 @@
/******************************************************************************
* 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.
******************************************************************************/
import { TextDocumentSyncKind, Disposable, Emitter } from 'vscode-languageserver';
import { UriUtils } from '../utils/uri-utils.js';
// Adapted from:
// https://github.com/microsoft/vscode-languageserver-node/blob/8f5fa710d3a9f60ff5e7583a9e61b19f86e39da3/server/src/common/textDocuments.ts
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
/**
* Normalizing text document manager. Normalizes all incoming URIs to the same format used by VS Code.
*/
export class NormalizedTextDocuments {
constructor(configuration) {
this._configuration = configuration;
this._syncedDocuments = new Map();
this._onDidChangeContent = new Emitter();
this._onDidOpen = new Emitter();
this._onDidClose = new Emitter();
this._onDidSave = new Emitter();
this._onWillSave = new Emitter();
}
get onDidOpen() {
return this._onDidOpen.event;
}
get onDidChangeContent() {
return this._onDidChangeContent.event;
}
get onWillSave() {
return this._onWillSave.event;
}
onWillSaveWaitUntil(handler) {
this._willSaveWaitUntil = handler;
}
get onDidSave() {
return this._onDidSave.event;
}
get onDidClose() {
return this._onDidClose.event;
}
get(uri) {
return this._syncedDocuments.get(UriUtils.normalize(uri));
}
set(document) {
const uri = UriUtils.normalize(document.uri);
let result = true;
if (this._syncedDocuments.has(uri)) {
result = false;
}
this._syncedDocuments.set(uri, document);
const toFire = Object.freeze({ document });
this._onDidOpen.fire(toFire);
this._onDidChangeContent.fire(toFire);
return result;
}
delete(uri) {
const uriString = UriUtils.normalize(typeof uri === 'object' && 'uri' in uri ? uri.uri : uri);
const syncedDocument = this._syncedDocuments.get(uriString);
if (syncedDocument !== undefined) {
this._syncedDocuments.delete(uriString);
this._onDidClose.fire(Object.freeze({ document: syncedDocument }));
}
}
all() {
return Array.from(this._syncedDocuments.values());
}
keys() {
return Array.from(this._syncedDocuments.keys());
}
listen(connection) {
// Required for interoperability with the the vscode-languageserver package
// eslint-disable-next-line @typescript-eslint/no-explicit-any
connection.__textDocumentSync = TextDocumentSyncKind.Incremental;
const disposables = [];
disposables.push(connection.onDidOpenTextDocument((event) => {
const td = event.textDocument;
const uri = UriUtils.normalize(td.uri);
const document = this._configuration.create(uri, td.languageId, td.version, td.text);
this._syncedDocuments.set(uri, document);
const toFire = Object.freeze({ document });
this._onDidOpen.fire(toFire);
this._onDidChangeContent.fire(toFire);
}));
disposables.push(connection.onDidChangeTextDocument((event) => {
const td = event.textDocument;
const changes = event.contentChanges;
if (changes.length === 0) {
return;
}
const { version } = td;
if (version === null || version === undefined) {
throw new Error(`Received document change event for ${td.uri} without valid version identifier`);
}
const uri = UriUtils.normalize(td.uri);
let syncedDocument = this._syncedDocuments.get(uri);
if (syncedDocument !== undefined) {
syncedDocument = this._configuration.update(syncedDocument, changes, version);
this._syncedDocuments.set(uri, syncedDocument);
this._onDidChangeContent.fire(Object.freeze({ document: syncedDocument }));
}
}));
disposables.push(connection.onDidCloseTextDocument((event) => {
const uri = UriUtils.normalize(event.textDocument.uri);
const syncedDocument = this._syncedDocuments.get(uri);
if (syncedDocument !== undefined) {
this._syncedDocuments.delete(uri);
this._onDidClose.fire(Object.freeze({ document: syncedDocument }));
}
}));
disposables.push(connection.onWillSaveTextDocument((event) => {
const syncedDocument = this._syncedDocuments.get(UriUtils.normalize(event.textDocument.uri));
if (syncedDocument !== undefined) {
this._onWillSave.fire(Object.freeze({ document: syncedDocument, reason: event.reason }));
}
}));
disposables.push(connection.onWillSaveTextDocumentWaitUntil((event, token) => {
const syncedDocument = this._syncedDocuments.get(UriUtils.normalize(event.textDocument.uri));
if (syncedDocument !== undefined && this._willSaveWaitUntil) {
return this._willSaveWaitUntil(Object.freeze({ document: syncedDocument, reason: event.reason }), token);
}
else {
return [];
}
}));
disposables.push(connection.onDidSaveTextDocument((event) => {
const syncedDocument = this._syncedDocuments.get(UriUtils.normalize(event.textDocument.uri));
if (syncedDocument !== undefined) {
this._onDidSave.fire(Object.freeze({ document: syncedDocument }));
}
}));
return Disposable.create(() => { disposables.forEach(disposable => disposable.dispose()); });
}
}
export class NormalizedNotebookDocuments {
constructor(configurationOrTextDocuments) {
this.notebookDocuments = new Map();
this.notebookCellMap = new Map();
this._onDidOpen = new Emitter();
this._onDidSave = new Emitter();
this._onDidChange = new Emitter();
this._onDidClose = new Emitter();
if ('listen' in configurationOrTextDocuments) {
this._cellTextDocuments = configurationOrTextDocuments;
}
else {
this._cellTextDocuments = new NormalizedTextDocuments(configurationOrTextDocuments);
}
}
get cellTextDocuments() {
return this._cellTextDocuments;
}
getCellTextDocument(cell) {
return this._cellTextDocuments.get(cell.document);
}
getNotebookDocument(uri) {
return this.notebookDocuments.get(UriUtils.normalize(uri));
}
getNotebookCell(uri) {
const value = this.notebookCellMap.get(UriUtils.normalize(uri));
return value && value[0];
}
findNotebookDocumentForCell(cell) {
const key = typeof cell === 'string' || 'scheme' in cell ? cell : cell.document;
const value = this.notebookCellMap.get(UriUtils.normalize(key));
return value && value[1];
}
get onDidOpen() {
return this._onDidOpen.event;
}
get onDidSave() {
return this._onDidSave.event;
}
get onDidChange() {
return this._onDidChange.event;
}
get onDidClose() {
return this._onDidClose.event;
}
/**
* Listens for `low level` notification on the given connection to
* update the notebook documents managed by this instance.
*
* Please note that the connection only provides handlers not an event model. Therefore
* listening on a connection will overwrite the following handlers on a connection:
* `onDidOpenNotebookDocument`, `onDidChangeNotebookDocument`, `onDidSaveNotebookDocument`,
* and `onDidCloseNotebookDocument`.
*
* @param connection The connection to listen on.
*/
listen(connection) {
const cellTextDocumentConnection = new CellTextDocumentConnection();
const disposables = [];
disposables.push(this.cellTextDocuments.listen(cellTextDocumentConnection));
disposables.push(connection.notebooks.synchronization.onDidOpenNotebookDocument((params) => {
const uri = UriUtils.normalize(params.notebookDocument.uri);
this.notebookDocuments.set(uri, params.notebookDocument);
for (const cellTextDocument of params.cellTextDocuments) {
cellTextDocumentConnection.openTextDocument({ textDocument: cellTextDocument });
}
this.updateCellMap(params.notebookDocument);
this._onDidOpen.fire(params.notebookDocument);
}));
disposables.push(connection.notebooks.synchronization.onDidChangeNotebookDocument((params) => {
const uri = UriUtils.normalize(params.notebookDocument.uri);
const notebookDocument = this.notebookDocuments.get(uri);
if (notebookDocument === undefined) {
return;
}
notebookDocument.version = params.notebookDocument.version;
const oldMetadata = notebookDocument.metadata;
let metadataChanged = false;
const change = params.change;
if (change.metadata !== undefined) {
metadataChanged = true;
notebookDocument.metadata = change.metadata;
}
const opened = [];
const closed = [];
const data = [];
const text = [];
if (change.cells !== undefined) {
const changedCells = change.cells;
if (changedCells.structure !== undefined) {
const array = changedCells.structure.array;
notebookDocument.cells.splice(array.start, array.deleteCount, ...(array.cells !== undefined ? array.cells : []));
// Additional open cell text documents.
if (changedCells.structure.didOpen !== undefined) {
for (const open of changedCells.structure.didOpen) {
cellTextDocumentConnection.openTextDocument({ textDocument: open });
opened.push(open.uri);
}
}
// Additional closed cell test documents.
if (changedCells.structure.didClose) {
for (const close of changedCells.structure.didClose) {
cellTextDocumentConnection.closeTextDocument({ textDocument: close });
closed.push(close.uri);
}
}
}
if (changedCells.data !== undefined) {
const cellUpdates = new Map(changedCells.data.map(cell => [cell.document, cell]));
for (let i = 0; i <= notebookDocument.cells.length; i++) {
const change = cellUpdates.get(notebookDocument.cells[i].document);
if (change !== undefined) {
const old = notebookDocument.cells.splice(i, 1, change);
data.push({ old: old[0], new: change });
cellUpdates.delete(change.document);
if (cellUpdates.size === 0) {
break;
}
}
}
}
if (changedCells.textContent !== undefined) {
for (const cellTextDocument of changedCells.textContent) {
cellTextDocumentConnection.changeTextDocument({ textDocument: cellTextDocument.document, contentChanges: cellTextDocument.changes });
text.push(cellTextDocument.document.uri);
}
}
}
// Update internal data structure.
this.updateCellMap(notebookDocument);
const changeEvent = { notebookDocument };
if (metadataChanged) {
changeEvent.metadata = { old: oldMetadata, new: notebookDocument.metadata };
}
const added = [];
for (const open of opened) {
added.push(this.getNotebookCell(open));
}
const removed = [];
for (const close of closed) {
removed.push(this.getNotebookCell(close));
}
const textContent = [];
for (const change of text) {
textContent.push(this.getNotebookCell(change));
}
if (added.length > 0 || removed.length > 0 || data.length > 0 || textContent.length > 0) {
changeEvent.cells = { added, removed, changed: { data, textContent } };
}
if (changeEvent.metadata !== undefined || changeEvent.cells !== undefined) {
this._onDidChange.fire(changeEvent);
}
}));
disposables.push(connection.notebooks.synchronization.onDidSaveNotebookDocument((params) => {
const notebookDocument = this.getNotebookDocument(params.notebookDocument.uri);
if (notebookDocument === undefined) {
return;
}
this._onDidSave.fire(notebookDocument);
}));
disposables.push(connection.notebooks.synchronization.onDidCloseNotebookDocument((params) => {
const uri = UriUtils.normalize(params.notebookDocument.uri);
const notebookDocument = this.notebookDocuments.get(uri);
if (notebookDocument === undefined) {
return;
}
this._onDidClose.fire(notebookDocument);
for (const cellTextDocument of params.cellTextDocuments) {
cellTextDocumentConnection.closeTextDocument({ textDocument: cellTextDocument });
}
this.notebookDocuments.delete(uri);
for (const cell of notebookDocument.cells) {
this.notebookCellMap.delete(cell.document);
}
}));
return Disposable.create(() => { disposables.forEach(disposable => disposable.dispose()); });
}
updateCellMap(notebookDocument) {
for (const cell of notebookDocument.cells) {
this.notebookCellMap.set(cell.document, [cell, notebookDocument]);
}
}
}
class CellTextDocumentConnection {
onDidOpenTextDocument(handler) {
this.openHandler = handler;
return Disposable.create(() => { this.openHandler = undefined; });
}
openTextDocument(params) {
this.openHandler && this.openHandler(params);
}
onDidChangeTextDocument(handler) {
this.changeHandler = handler;
return Disposable.create(() => { this.changeHandler = handler; });
}
changeTextDocument(params) {
this.changeHandler && this.changeHandler(params);
}
onDidCloseTextDocument(handler) {
this.closeHandler = handler;
return Disposable.create(() => { this.closeHandler = undefined; });
}
closeTextDocument(params) {
this.closeHandler && this.closeHandler(params);
}
onWillSaveTextDocument() {
return CellTextDocumentConnection.NULL_DISPOSE;
}
onWillSaveTextDocumentWaitUntil() {
return CellTextDocumentConnection.NULL_DISPOSE;
}
onDidSaveTextDocument() {
return CellTextDocumentConnection.NULL_DISPOSE;
}
}
CellTextDocumentConnection.NULL_DISPOSE = Object.freeze({ dispose: () => { } });
//# sourceMappingURL=normalized-text-documents.js.map
File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More