Xtext: using the grammar classes in ISemanticHighlightingCalculator
Listen, I have a grammar. See just the specific part I need to handle:
Par:
id=ID | string=STRING | integer=INT;
What I want to obtain is:
if it's a Par element of type ID then color the background
if it's a Par element of type STRING then set text color
And here is my SemanticHighlightingCalculator
public class GrailSemanticHighlightingCalculator implements ISemanticHighlightingCalculator {
@Override
public void provideHighlightingFor(XtextResource resource, IHighlightedPositionAcceptor acceptor) {
if (resource == null) return;
Iterable<AbstractNode> allNodes = NodeUtil.getAllContents( resource.getParseResult().getRootNode() );
for (AbstractNode node : allNodes) {
System.out.println(node.getGrammarElement().toString());
if (node.getGrammarElement() instanceof Par) {
System.out.println("Il mio par: " + ((Par)node).getId());
acceptor.addPosition(node.getOffset(), node.getLength(), GrailHighlightingConfiguration.ELEMENT_ID);
}
}
}
}
I'm doing this as written here in the documentation. I'm not getting any error at compile time. Here's an example output of System.out.println(node.getGrammarElement().toString());
org.eclipse.xtext.impl.RuleCallImpl@165a43b (cardinality: null)
org.eclipse.xtext.impl.RuleCallImpl@159b3 (cardinality: null)
org.eclipse.xtext.impl.RuleCallImpl@a866a9 (cardinality: null)
org.eclipse.xtext.impl.KeywordImpl@f4c9c4 (cardinality: null) (value: ()
org.eclipse.xtext.impl.RuleCallImpl@a82a10 (cardinality: null)
org.eclipse.xtext.impl.RuleCallImpl@618b08 (cardinality: null)
org.eclipse.xtext.impl.TerminalRuleImpl@1eed0fb (name: WS)
org.eclipse.xtext.impl.RuleCallImpl@1da2b6d (cardinality: null)
org.eclipse.xtext.impl.KeywordImpl@591171 (cardinality: null) (value: ,)
org.eclipse.xtext.impl.RuleCallImpl@1882876 (cardinality: null)
org.eclipse.xtext.impl.RuleCallImpl@618b08 (cardinality: null)
org.eclipse.xtext.impl.TerminalRuleImpl@1eed0fb (name: WS)
org.eclipse.xtext.impl.RuleCallImpl@1da2b6d (cardinality: null)
org.eclipse.xtext.impl.KeywordImpl@591171 (cardinality: null) (value: ,)
org.eclipse.xtext.impl.RuleCallImpl@1882876 (cardinality: null)
org.eclipse.xtext.impl.RuleCallImpl@618b08 (cardinality: null)
org.eclipse.xtext.impl.TerminalRuleImpl@1eed0fb (name: WS)
org.eclipse.xtext.impl.RuleCallImpl@1860e4 (cardinality: null)
org.eclipse.xtext.impl.KeywordImpl@ea8847 (cardinality: null) (value: ))
org.eclipse.xtext.impl.RuleCallImpl@812517 (cardinality: null)
org.eclipse.xtext.impl.RuleCallImpl@aa3e9a (cardinality: null)
org.eclipse.xtext.impl.RuleCallImpl@f42d53 (cardinality: null)
org.eclipse.xtext.impl.RuleCallImpl@cbb612 (cardinality: null)
org.eclipse.xtext.impl.TerminalRuleImpl@1eed0fb (name: WS)
org.eclipse.xtext.impl.KeywordImpl@1990d96 (cardinality: null) (value: ()
org.eclipse.xtext.impl.RuleCallImpl@1e7f21 (cardinality: null)
org.eclipse.xtext.impl.ActionImpl@2c79a5 (cardinality: null) (feature: left, operator: =)
org.eclipse.xtext.impl.RuleCallImpl@aa3e9a (cardinality: null)
org.eclipse.xtext.impl.RuleCallImpl@f42d53 (cardinality: null)
org.eclipse.xtext.impl.RuleCallImpl@cbb612 (cardinality: null)
org.eclipse.xtext.impl.TerminalRuleImpl@1eed0fb (name: WS)
org.eclipse.xtext.impl.KeywordImpl@1990d96 (cardinality: null) (value: ()
org.eclipse.xtext.impl.RuleCallImpl@1e7f21 (cardinality: null)
org.eclipse.xtext.impl.RuleCallImpl@aa3e9a (cardinality: null)
org.eclipse.xtext.impl.RuleCallImpl@f42d53 (cardinality: null)
org.eclipse.xtext.impl.RuleCallImpl@cbb612 (cardinality: null)
org.eclipse.xtext.impl.RuleCallImpl@1e668c2 (cardinality: null)
org.eclipse.xtext.impl.KeywordImpl@1e7a4d0 (cardinality: null) (value: .)
org.eclipse.xtext.impl.RuleCallImpl@f55ff2 (cardinality: null)
org.eclipse.xtext.impl.TerminalRuleImpl@1eed0fb (name: WS)
org.eclipse.xtext.impl.RuleCallImpl@16e3eb3 (cardinality: null)
org.eclipse.xtext.impl.RuleCallImpl@d67d61 (cardinality: null)
org.eclipse.xtext.impl.TerminalRuleImpl@1eed0fb (name: WS)
org.eclipse.xtext.impl.RuleCallImpl@1860e4 (cardinality: null)
org.eclipse.xtext.impl.TerminalRuleImpl@1eed0fb (name: WS)
org.eclipse.xt开发者_Python百科ext.impl.KeywordImpl@14afef4 (cardinality: null) (value: ))
org.eclipse.xtext.impl.TerminalRuleImpl@1eed0fb (name: WS)
org.eclipse.xtext.impl.KeywordImpl@1c190a2 (cardinality: null) (value: AND)
org.eclipse.xtext.impl.RuleCallImpl@feba21 (cardinality: null)
org.eclipse.xtext.impl.TerminalRuleImpl@1eed0fb (name: WS)
org.eclipse.xtext.impl.KeywordImpl@16dd645 (cardinality: null) (value: NOT)
org.eclipse.xtext.impl.RuleCallImpl@e54f3 (cardinality: null)
org.eclipse.xtext.impl.TerminalRuleImpl@1eed0fb (name: WS)
org.eclipse.xtext.impl.RuleCallImpl@1e668c2 (cardinality: null)
org.eclipse.xtext.impl.KeywordImpl@1e7a4d0 (cardinality: null) (value: .)
org.eclipse.xtext.impl.RuleCallImpl@f55ff2 (cardinality: null)
org.eclipse.xtext.impl.TerminalRuleImpl@1eed0fb (name: WS)
org.eclipse.xtext.impl.RuleCallImpl@16e3eb3 (cardinality: null)
org.eclipse.xtext.impl.RuleCallImpl@d67d61 (cardinality: null)
org.eclipse.xtext.impl.TerminalRuleImpl@1eed0fb (name: WS)
org.eclipse.xtext.impl.RuleCallImpl@eb3f66 (cardinality: null)
org.eclipse.xtext.impl.TerminalRuleImpl@1eed0fb (name: WS)
org.eclipse.xtext.impl.KeywordImpl@14afef4 (cardinality: null) (value: ))
org.eclipse.xtext.impl.RuleCallImpl@165a43b (cardinality: null)
org.eclipse.xtext.impl.RuleCallImpl@159b3 (cardinality: null)
org.eclipse.xtext.impl.TerminalRuleImpl@1eed0fb (name: WS)
org.eclipse.xtext.impl.RuleCallImpl@a866a9 (cardinality: null)
org.eclipse.xtext.impl.KeywordImpl@f4c9c4 (cardinality: null) (value: ()
org.eclipse.xtext.impl.RuleCallImpl@a82a10 (cardinality: null)
org.eclipse.xtext.impl.RuleCallImpl@618b08 (cardinality: null)
org.eclipse.xtext.impl.RuleCallImpl@1da2b6d (cardinality: null)
org.eclipse.xtext.impl.KeywordImpl@ea8847 (cardinality: null) (value: ))
org.eclipse.xtext.impl.RuleCallImpl@812517 (cardinality: null)
org.eclipse.xtext.impl.RuleCallImpl@aa3e9a (cardinality: null)
org.eclipse.xtext.impl.RuleCallImpl@f42d53 (cardinality: null)
org.eclipse.xtext.impl.RuleCallImpl@cbb612 (cardinality: null)
org.eclipse.xtext.impl.TerminalRuleImpl@1eed0fb (name: WS)
org.eclipse.xtext.impl.KeywordImpl@1990d96 (cardinality: null) (value: ()
org.eclipse.xtext.impl.RuleCallImpl@1e7f21 (cardinality: null)
org.eclipse.xtext.impl.RuleCallImpl@aa3e9a (cardinality: null)
org.eclipse.xtext.impl.RuleCallImpl@f42d53 (cardinality: null)
org.eclipse.xtext.impl.RuleCallImpl@cbb612 (cardinality: null)
org.eclipse.xtext.impl.TerminalRuleImpl@1eed0fb (name: WS)
org.eclipse.xtext.impl.RuleCallImpl@1e668c2 (cardinality: null)
org.eclipse.xtext.impl.KeywordImpl@1e7a4d0 (cardinality: null) (value: .)
org.eclipse.xtext.impl.RuleCallImpl@f55ff2 (cardinality: null)
org.eclipse.xtext.impl.TerminalRuleImpl@1eed0fb (name: WS)
org.eclipse.xtext.impl.RuleCallImpl@16e3eb3 (cardinality: null)
org.eclipse.xtext.impl.RuleCallImpl@d67d61 (cardinality: null)
org.eclipse.xtext.impl.TerminalRuleImpl@1eed0fb (name: WS)
org.eclipse.xtext.impl.RuleCallImpl@1860e4 (cardinality: null)
org.eclipse.xtext.impl.KeywordImpl@14afef4 (cardinality: null) (value: ))
I'm only just starting out with XText as well but I might be able to help. I was able to get syntax highlighting working for a small project with similar code to yours, but with a few differences. I found the useful forum posting on the Eclipse forums here.
Based on the console output it looks like it's never recognising any of the AbstractNodes as being an instance of Par.
The differences between the Eclipse forum and your code seem to be:
- It uses
Iterator<EObject> iter = EcoreUtil.getAllContents(resource, true);
and awhile
loop to iterate through the results. - It checks the type (in your case for Par) against the EObject directly rather than using
getGrammarElement
.
It might be as simple as changing it as above, to something like:
public class GrailSemanticHighlightingCalculator implements ISemanticHighlightingCalculator {
@Override
public void provideHighlightingFor(XtextResource resource, IHighlightedPositionAcceptor acceptor) {
if (resource == null) return;
Iterator<EObject> iter = EcoreUtil.getAllContents(resource, true);
while (iter.hasNext()) {
EObject current = iter.next();
if (current instanceof Par) {
Par parNode = (Par) current;
if (parNode.getId() != null) {
acceptor.addPosition(node.getOffset(), node.getLength(), GrailHighlightingConfiguration.ELEMENT_ID);
} else if (parNode.getString() != null) {
acceptor.addPosition(node.getOffset(), node.getLength(), GrailHighlightingConfiguration.ELEMENT_STRING);
} else if (parNode.getInt() != null) {
acceptor.addPosition(node.getOffset(), node.getLength(), GrailHighlightingConfiguration.ELEMENT_INT);
}
}
}
}
I've included some code to handle the other highlighting options, so you'd need to add in the ELEMENT_STRING and ELEMENT_INT handlers to your configure()
method in whatever your IHighlightingConfiguration class is called, to return the TextStyle
applicable to them.
Also note that I have not tested any of the above, so it may actually be completely wrong and misleading! Hope it's not, though. :)
For Xtext 2.0, this code can be used as a template:
import java.util.Iterator;
import java.util.List;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.xtext.nodemodel.ILeafNode;
import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.ui.editor.syntaxcoloring.IHighlightedPositionAcceptor;
import org.eclipse.xtext.ui.editor.syntaxcoloring.ISemanticHighlightingCalculator;
public class YourDslSemanticHighlightingCalculator implements ISemanticHighlightingCalculator {
@Override
public void provideHighlightingFor( XtextResource resource, IHighlightedPositionAcceptor acceptor ) {
if( resource == null ) {
return;
}
HighlightingSwitch switcher = new HighlightingSwitch( acceptor );
Iterator<EObject> iter = EcoreUtil.getAllContents(resource, true);
while(iter.hasNext()) {
EObject current = iter.next();
switcher.doSwitch( current );
}
}
private class HighlightingSwitch extends YourDslSwitch<Void> {
private final IHighlightedPositionAcceptor acceptor;
public HighlightingSwitch( IHighlightedPositionAcceptor acceptor ) {
this.acceptor = acceptor;
}
@Override
public Void caseOption( Option object ) {
INode node = getFirstFeatureNode( object, YourDslPackage.eINSTANCE.getOption_Name() );
highlightNode( node, YourDslHighlightingConfiguration.OPTION );
return null;
}
private void highlightNode( INode node, String id ) {
if( node == null )
return;
if( node instanceof ILeafNode ) {
acceptor.addPosition( node.getOffset(), node.getLength(), id );
} else {
for( ILeafNode leaf : node.getLeafNodes() ) {
if( !leaf.isHidden() ) {
acceptor.addPosition( leaf.getOffset(), leaf.getLength(), id );
}
}
}
}
}
public INode getFirstFeatureNode( EObject semantic, EStructuralFeature feature ) {
if( feature == null )
return NodeModelUtils.findActualNodeFor( semantic );
List<INode> nodes = NodeModelUtils.findNodesForFeature( semantic, feature );
if( !nodes.isEmpty() )
return nodes.get( 0 );
return null;
}
}
This iterates over all nodes in your model and invokes a case in the HighlightingSwitch
.
In the case method, you need to locate the INode
related to the feature or EObject
instance that you care about and then, you can highlight it.
Note that getFirstFeatureNode()
doesn't search the whole AST for a node; the implementation is actually pretty fast.
The style configuration looks like this:
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.xtext.ui.editor.syntaxcoloring.DefaultHighlightingConfiguration;
import org.eclipse.xtext.ui.editor.syntaxcoloring.IHighlightingConfigurationAcceptor;
import org.eclipse.xtext.ui.editor.utils.TextStyle;
public class YourDslHighlightingConfiguration extends DefaultHighlightingConfiguration {
public static final String OPTION = "yourDsl.option";
public void configure(IHighlightingConfigurationAcceptor acceptor) {
acceptor.acceptDefaultHighlighting( OPTION, "Option", option() );
super.configure( acceptor );
}
public TextStyle option() {
TextStyle textStyle = defaultTextStyle().copy();
textStyle.setColor( new RGB( 0, 26, 171 ) );
textStyle.setStyle( SWT.ITALIC );
return textStyle;
}
}
Don't forget to bind the two new classes in your UI module!
精彩评论