Skip to content

Commit

Permalink
Hover provider for crossrefs (#473)
Browse files Browse the repository at this point in the history
* Added hover provider for crossrefs

* Moved HoverProvider to LangiumGrammarModule

* Refactored LangiumGrammarHoverProvider

* Formatting

* Update packages/langium/src/lsp/langium-grammar-hover-provider.ts

Co-authored-by: Mark Sujew <mark.sujew@typefox.io>

* Update packages/langium/src/lsp/langium-grammar-hover-provider.ts

Co-authored-by: Mark Sujew <mark.sujew@typefox.io>

* Update packages/langium/src/lsp/langium-grammar-hover-provider.ts

Co-authored-by: Mark Sujew <mark.sujew@typefox.io>

* Moved langium-grammar-hover-provider to src/grammar/lsp

Co-authored-by: Mark Sujew <mark.sujew@typefox.io>
  • Loading branch information
gfontorbe and msujew committed Apr 25, 2022
1 parent 6c1addb commit a06aa60
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 2 deletions.
2 changes: 1 addition & 1 deletion packages/langium/src/default-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ import { Connection, TextDocuments } from 'vscode-languageserver';
import { TextDocument } from 'vscode-languageserver-textdocument';
import { Module } from './dependency-injection';
import { createGrammarConfig } from './grammar/grammar-config';
import { MultilineCommentHoverProvider } from './lsp';
import { DefaultCompletionProvider } from './lsp/completion/completion-provider';
import { RuleInterpreter } from './lsp/completion/rule-interpreter';
import { DefaultDocumentHighlighter } from './lsp/document-highlighter';
import { DefaultDocumentSymbolProvider } from './lsp/document-symbol-provider';
import { DefaultFoldingRangeProvider } from './lsp/folding-range-provider';
import { DefaultGoToResolverProvider } from './lsp/goto';
import { MultilineCommentHoverProvider } from './lsp/hover-provider';
import { DefaultReferenceFinder } from './lsp/reference-finder';
import { DefaultRenameHandler } from './lsp/rename-refactoring';
import { createLangiumParser } from './parser/langium-parser-builder';
Expand Down
4 changes: 3 additions & 1 deletion packages/langium/src/grammar/langium-grammar-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { LangiumGrammarScopeComputation, LangiumScopeProvider } from './langium-
import { LangiumGrammarSemanticTokenProvider } from './langium-grammar-semantic-token-provider';
import { LangiumGrammarValidationRegistry, LangiumGrammarValidator } from './langium-grammar-validator';
import { LangiumGrammarFoldingRangeProvider } from './lsp/langium-grammar-folding-range-provider';
import { LangiumGrammarHoverProvider } from './lsp/langium-grammar-hover-provider';

export type LangiumGrammarAddedServices = {
validation: {
Expand All @@ -30,7 +31,8 @@ export const LangiumGrammarModule: Module<LangiumGrammarServices, PartialLangium
lsp: {
FoldingRangeProvider: (services) => new LangiumGrammarFoldingRangeProvider(services),
CodeActionProvider: () => new LangiumGrammarCodeActionProvider(),
SemanticTokenProvider: () => new LangiumGrammarSemanticTokenProvider()
SemanticTokenProvider: () => new LangiumGrammarSemanticTokenProvider(),
HoverProvider: (services) => new LangiumGrammarHoverProvider(services)
},
references: {
ScopeComputation: (services) => new LangiumGrammarScopeComputation(services),
Expand Down
83 changes: 83 additions & 0 deletions packages/langium/src/grammar/lsp/langium-grammar-hover-provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/******************************************************************************
* 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 { Hover, HoverParams } from 'vscode-languageserver';
import { AstNode } from '../../syntax-tree';
import { MaybePromise } from '../../utils/promise-util';
import { MultilineCommentHoverProvider } from '../../lsp/hover-provider';
import { CrossReference, findLeafNodeAtOffset, findNameAssignment, findRelevantNode, Grammar, isCrossReference, isKeyword, isParserRule, isRuleCall, isType, LangiumDocument, LangiumDocuments, LangiumServices } from '../..';

export class LangiumGrammarHoverProvider extends MultilineCommentHoverProvider {

readonly grammar: Grammar;
readonly documents: LangiumDocuments;
constructor(services: LangiumServices) {
super(services);
this.grammar = services.Grammar;
this.documents = services.shared.workspace.LangiumDocuments;
}

protected getAstNodeHoverContent(node: AstNode): MaybePromise<Hover | undefined> {
if(isCrossReference(node)) {
return this.getCrossReferenceHoverContent(node);
}
return super.getAstNodeHoverContent(node);
}

getHoverContent(document: LangiumDocument<AstNode>, params: HoverParams): MaybePromise<Hover | undefined> {
const rootNode = document.parseResult?.value?.$cstNode;
if (rootNode) {
const offset = document.textDocument.offsetAt(params.position);
const cstNode = findLeafNodeAtOffset(rootNode, offset);
if (cstNode && cstNode.offset + cstNode.length > offset) {
const relevantNode = findRelevantNode(cstNode);
const targetNode = this.references.findDeclaration(cstNode);
if (isCrossReference(relevantNode)) {
return this.getAstNodeHoverContent(relevantNode);
} else if (targetNode) {
return this.getAstNodeHoverContent(targetNode?.element);
}
}
}
return undefined;
}

getCrossReferenceHoverContent(node: CrossReference): MaybePromise<Hover | undefined> {
const ref = node.type.ref;
if (ref) {
if (isType(ref)) {
return {
contents: {
kind: 'markdown',
value: '```\n' + ref.$cstNode!.text + '\n```'
}
};
} else if (isParserRule(ref)) {
const typeName = ref.name;
const terminal = node.terminal;
let terminalName = '';
if (terminal === undefined) {
const terminalRule = findNameAssignment(ref);
if (terminalRule && isRuleCall(terminalRule.terminal)){
terminalName = terminalRule.terminal.rule.ref!.name;
}
} else if (isKeyword(terminal)) {
terminalName = terminal.value;
} else if (isRuleCall(terminal)) {
terminalName = terminal.rule.ref!.name;
}

return {
contents: {
kind: 'markdown',
value: '```\n' + `[${typeName}:${terminalName}]` + '\n```'
}
};
}
}
return undefined;
}

}

0 comments on commit a06aa60

Please sign in to comment.