Channels ▼
RSS

Design

Customizing Xtext


Another Example: Syntax Highlighting

The preceding discussion gives you a basic idea of how to customize components in our language's infrastructure. The next example is syntax highlighting: Currently, only keywords are highlighted in the editor. We want to display DataTypes and references to them in italics to better distinguish them from Entities.

Syntax highlighting is defined in two components. The IHighlightingConfiguration defines text styles and maps them to IDs. These IDs are used in the ISemanticHighlightingCalculator to apply the text styles to regions in the text.

As we want to extend the default behavior, our DomainmodelHighlightingConfiguration should extend the DefaultHighlightingConfiguration. The following code should be clear, especially if you have a look at the superclass: We define a new text style and register it with the ID datatype.

public class DomainmodelHighlightingConfiguration extends
             DefaultHighlightingConfiguration 
{

	public static final String DATA_TYPE_ID = "datatype";

	public void configure(IHighlightingConfigurationAcceptor
                            acceptor) 
	{
		super.configure(acceptor);
		acceptor.acceptDefaultHighlighting(
               DATA_TYPE_ID, "DataType", dataTypeTextStyle());
	}

	public TextStyle dataTypeTextStyle() 
	{
		TextStyle textStyle = defaultTextStyle().copy();
		textStyle.setStyle(SWT.ITALIC);
		return textStyle;
	}
}

Next, we have to tell Xtext to use our implementation. We only have to add a binding in the DomainmodelUiModule:

public Class<? extends IHighlightingConfiguration> 
		bindIHighlightingConfiguration() {
	     return DomainmodelHighlightingConfiguration.class;
}

If you restart your runtime workbench, you should already have a configuration item in the properties page for your language (Figure 3).

Figure 3: The existing dialog box in Xtext for specifying syntax coloring.

To apply the new DataType text style to the corresponding regions in the text, implement the ISemanticHighlightingCalculator. This time there is no default implementation. We need to implement a single method provideHighlightingFor(XtextResource, IHighlightedPositionAcceptor). The first parameter is the resource holding the model. We have to iterate its contents — the model elements — and spot all DataTypes and Features pointing to a DataType.

public class DomainmodelSemanticHighlightingCalculator 
             implements ISemanticHighlightingCalculator 
{
	public void provideHighlightingFor(XtextResource resource,
			IHighlightedPositionAcceptor acceptor) 
{
		for(Iterator<EObject> contents = resource.getAllContents(); 
			contents.hasNext(); ) 
		{
			EObject element = contents.next();
			if (element instanceof Feature && 
				((Feature) element).getType() instanceof 
                          DataType)
				highlightAsDataType(element, 
					DomainmodelPackage.Literals.FEATURE__TYPE, 
					acceptor);
			else if(element instanceof DataType) 
				highlightAsDataType(element,
 					DomainmodelPackage.Literals.TYPE__NAME, 
					acceptor);
		}
	}
	
	protected void highlightAsDataType(EObject element, 
			EStructuralFeature feature, 
			IHighlightedPositionAcceptor acceptor) 
{
		for(INode node: 
			NodeModelUtils.findNodesForFeature(element, feature)) 
			acceptor.addPosition(node.getOffset(), 
			   node.getLength(),						  
                   DomainmodelHighlightingConfiguration.DATA_TYPE_ID);
	}
}

The NodeModelUtils provide access to the node model, which stores trace information of the parser. We use it to determine the text region (offset and length) from which a model element was parsed.

DomainmodelPackage.Literals.FEATURE__TYPE and DomainmodelPackage.Literals.TYPE__NAME is the EMF way to say "the property type of the class Feature" ("...name of the class Type"). The text style is applied to a region IHighlightedPositionAcceptor.addPosition().

What is missing now? You guessed it: We have to add the binding for the ISemanticHighlightingCalculator to our DomainmodelSemanticHighlightingCalculator/ in the UI module:

public class DomainmodelUiModule 
	extends org.example.domainmodel.ui.AbstractDomainmodelUiModule 
{
     ...
	public Class<? extends ISemanticHighlightingCalculator> 
		bindISemanticHighlightingCalculator() 
	{
		return DomainmodelSemanticHighlightingCalculator.class;
	}
}

If you restart the runtime Eclipse the editor shows the desired highlighting (Figure 4).

Figure 4: The syntax highlighting results, showing the use of italics.

Where to Go from Here...

In this tutorial, we focused on UI aspects of Xtext. Infrastructural parts, such as scoping, linking, and formatting can be changed with the same mechanism. As always, you will find many more examples in the Xtext documentation.

In this article, we've discussed the basic mechanisms to customize an Xtext-based DSL. In Xtext, everything is wired up using dependency injection. You can easily customize individual components by changing the bindings if the defaults do not fit your needs. Whenever you need another component, you just let the framework inject it. For the aspects you customize, Xtext likely offers generator fragments that create skeleton classes and their bindings. By using the Generation Gap Pattern, you can evolve your language and regenerate the infrastructure without losing your customizations. Enjoy!


Jan Koehnlein and Sebastian Zarnekow are principals on the Xtext project.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video