Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Hover provider for crossrefs #473

Merged
merged 8 commits into from
Apr 25, 2022
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 @@ -6,6 +6,7 @@

import { createDefaultModule, createDefaultSharedModule, DefaultSharedModuleContext } from '../default-module';
import { inject, Module } from '../dependency-injection';
import { LangiumGrammarHoverProvider } from '../lsp/langium-grammar-hover-provider';
import { LangiumServices, LangiumSharedServices, PartialLangiumServices } from '../services';
import { LangiumGrammarGeneratedModule, LangiumGrammarGeneratedSharedModule } from './generated/module';
import { LangiumGrammarCodeActionProvider } from './langium-grammar-code-actions';
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/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.
******************************************************************************/
msujew marked this conversation as resolved.
Show resolved Hide resolved
import { Hover, HoverParams } from 'vscode-languageserver';
import {CrossReference, findLeafNodeAtOffset, findNameAssignment, findRelevantNode, Grammar, isCrossReference, isKeyword, isParserRule, isRuleCall, isType, LangiumDocument, LangiumDocuments, LangiumServices } from '..';
import { AstNode } from '../syntax-tree';
import { MaybePromise } from '../utils/promise-util';
import { MultilineCommentHoverProvider } from './hover-provider';

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: ref.$cstNode!.text
gfontorbe marked this conversation as resolved.
Show resolved Hide resolved
}
};
} else if (isParserRule(ref)) {
const typeName = ref.name;
const terminal = node.terminal;
let terminalName = '';
if (terminal === undefined){
gfontorbe marked this conversation as resolved.
Show resolved Hide resolved
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: `[${typeName}:${terminalName}]`
gfontorbe marked this conversation as resolved.
Show resolved Hide resolved
}
};
}
}
return undefined;
}

}