Как по-разному выделить перекрестную ссылку Xtext для целей разных типов?
У меня есть грамматика Xtext, которая читает (частично):
grammar mm.ecxt.MMLanguage hidden(WS, COMMENT)
import "http://www.eclipse.org/emf/2002/Ecore" as ecore
...
Statement:
ConstantStatement |
VariableStatement |
LabeledStatement |
...
LabeledStatement:
EssentialHypothesisStatement |
...
ConstantStatement:
DOLLAR_C (constants+=ConstDecl)+ DOLLAR_DOT;
VariableStatement:
DOLLAR_V (variables+=VarDecl)+ DOLLAR_DOT;
EssentialHypothesisStatement:
name=LABEL DOLLAR_E (symbols+=[Decl|MATHSYMBOL])+ DOLLAR_DOT;
Decl: ConstDecl | VarDecl;
ConstDecl returns ConstDecl: name=MATHSYMBOL;
VarDecl returns VarDecl: name=MATHSYMBOL;
MATHSYMBOL: PARENOPEN | PARENCLOSE | QUESTIONMARK | COMPRESSED | TLABEL | WORD;
...
(Полная грамматика - MMLanguage.xtext из текущего коммита 328a5e7 по https://github.com/marnix/metamath-eclipse-xtext/.)
Мой вопрос: как мне выделить symbols
в EssentialHypothesisStatement
, используя другой цвет для констант и переменных? Так что если MATHSYMBOL
относится к ConstDecl
, то это должно быть выделено в одну сторону, а другой - для VarDecl
,
Я пытался создать ISemanticHighlightingCalculator
разными способами, но я не могу определить, что такое реальный эталонный тип, ни через модель узла, ни через модель Ecore. С одной стороны, связанные с грамматикой методы только говорят мне, что ссылка идет на Decl
, С другой стороны, модель Ecore EReference
Скажите мне, является ли цель ConstDecl
или VarDecl
, но там я не могу найти местоположение источника MATHSYMBOL
,
Обратите внимание, что я предпочитаю использовать модель узла (в отличие от модели Ecore), так как я также хочу выделить комментарии, и по соображениям производительности я не могу позволить несколько проходов по документу.
Каков хороший / канонический / эффективный / простой способ добиться этого?
1 ответ
С точки зрения EObject взгляните на org.eclipse.xtext.nodemodel.util.NodeModelUtils.findNodesForFeature(EObject, EStructuralFeature) с точки зрения модели узла, которую вы можете использовать EObjectAtOffsetHelper
образец грамматики
Model:
defs+=Def*
uses+=Use*
;
Def:
ADef | BDef;
ADef:
"adef" name=ID
;
BDef:
"bdef" name=ID
;
Use:
"use" def=[Def]
;
И здесь Импл
public class MyDslSemanticHighlightingCalculator implements ISemanticHighlightingCalculator {
@Inject
private MyDslGrammarAccess ga;
@Inject
private EObjectAtOffsetHelper helper;
@Override
public void provideHighlightingFor(XtextResource resource, IHighlightedPositionAcceptor accoptor, CancelIndicator cancelIndicator) {
if (resource == null)
return;
IParseResult parseResult = resource.getParseResult();
if (parseResult == null || parseResult.getRootNode() == null)
return;
BidiTreeIterable<INode> tree = parseResult.getRootNode().getAsTreeIterable();
for (INode node : tree) {
if (cancelIndicator.isCanceled()) {
return;
}
if (node.getGrammarElement() instanceof CrossReference) {
if (ga.getUseAccess().getDefDefCrossReference_1_0() == node.getGrammarElement()) {
EObject target = helper.resolveElementAt(resource, node.getOffset());
if (target instanceof ADef) {
accoptor.addPosition(node.getOffset(), node.getLength(), HighlightingStyles.COMMENT_ID);
} else if (target instanceof BDef) {
accoptor.addPosition(node.getOffset(), node.getLength(), HighlightingStyles.STRING_ID);
}
}
}
}
}
}