public abstract class AbstractFormatter2 extends java.lang.Object implements IFormatter2
This is an abstract base class for language-specific formatters.
It is the formatters responsibility to create a list of text replacements, which, when applied to a text document, increase the documents readability for humans. At the same time the text changes should not have an impact on the semantic model a parser would create from the document.
Formatters based on this class compute text replacements in two logical steps: First, they traverses the semantic
model and collect text replaces
. Each replacer is responsible for a (small) section of the
document. In a second step, the replacers are executed from the beginning to the end of the document and create the
actual text replacements
. This decoupling allows it to traverse the semantic model in
arbitrary order and yet compute information that requires sequential processing of the document, e.g. indentation.
To allow subclasses to implement this mechanism conveniently, there are several helper classes:
ITextRegionAccess
allows to obtain text regions for elements in the semantic model.ITextReplacer
creates replacements
for a specific region in the document.IFormattableDocument
collects replacers
and validates if they overlap.
A formatter based on this class typically uses the ITextRegionAccess
to obtain the IHiddenRegion
which precedes or trails semantic object
, features
, keywords
, or rule calls
. This IHiddenRegion
represents the whitespace, newlines and
comments between semantic tokens. No matter if there are zero or N hidden tokens between two semantic tokens, there
is always exactly one IHiddenRegion
. In other words, the IHiddenRegion
groups all hidden tokens
between two semantic tokens.
For the IHiddenRegion
, the formatter will create a ITextReplacer
and store the replacer in the
IFormattableDocument
. Typically this is a HiddenRegionReplacer
parameterized with an
IHiddenRegionFormatting
. The HiddenRegionReplacer
will then delegate to a WhitespaceReplacer
or CommentReplacer
, depending on which kind of tokens are inside the hidden region.
To format a document with syntax confirming to the parser rule:
Entity: 'entity' name=ValidID '{' features+=Feature* '}';
the following formatter implementation (Xtend code) can be used:
def dispatch void format(Entity entity, extension IFormattableDocument document) { entity.regionForFeature(ABSTRACT_ELEMENT__NAME).surround[oneSpace] entity.regionForKeyword("{").append[newLine; increaseIndentation] for (Feature feature : entity.features) { format(feature, document); feature.append[newLine] } entity.regionForKeyword("}").prepend[decreaseIndentation] }
For the full example, see the DomainModel Example. It can be accessed via Eclipse -> File -> New -> Example.
The class Entity
is part of the semantic model.
The methods regionForFeature()
and regionForKeyword
are extension methods: {link
ITextRegionAccess#regionForFeature(EObject, EStructuralFeature)} and {link
ITextRegionAccess#regionForKeyword(EObject, String)}. They return an ISemanticRegion
.
The methods prepend()
, append()
and surround()
are extension methods from
IFormattableDocument
. They create and register an HiddenRegionReplacer
for the IHiddenRegion
before and/or after the provided ISemanticRegion
.
Override create*()
methods to customize formatter-local services.
This implementation is stateful and cannot be used in parallel.
The package {@code org.eclipse.xtext.formatting2} for an introduction to the topic
,
{@code IFormatter2}: the interface to invoke the formatter
,
The method {@code format(Object, IFormattableDocument)} should be
overridden to implement a formatter
,
The method {@code initalize(FormatterRequest)} should be overridden to set values
of member fields
,
The method {@code reset()} should be overridden to cleanup after execution.
Modifier and Type | Field and Description |
---|---|
protected ITextRegionExtensions |
textRegionExtensions
Offer subclasses access to the methods from
ITextRegionAccess as extension methods. |
Constructor and Description |
---|
AbstractFormatter2() |
@Extension protected ITextRegionExtensions textRegionExtensions
ITextRegionAccess
as extension methods.protected void _format(java.lang.Object obj, IFormattableDocument document)
protected void _format(org.eclipse.emf.ecore.EObject obj, IFormattableDocument document)
protected void _format(java.lang.Void obj, IFormattableDocument document)
protected void _format(XtextResource resource, IFormattableDocument document)
resources
, assume we want to format the first EObject from the contents list only.
Because that's where the parser puts the semantic model.public ITextReplacer createCommentReplacer(IComment comment)
public IFormattableDocument createFormattableRootDocument()
public IFormattableSubDocument createFormattableSubDocument(ITextSegment region, IFormattableDocument parent)
public IHiddenRegionFormatter createHiddenRegionFormatter(IHiddenRegionFormatting formatting)
public IHiddenRegionFormatter createHiddenRegionFormatter(IHiddenRegionFormatting f1, IHiddenRegionFormatting f2)
public IHiddenRegionFormatting createHiddenRegionFormatting()
public IMerger<IHiddenRegionFormatting> createHiddenRegionFormattingMerger()
public ITextReplacer createHiddenRegionReplacer(IHiddenRegion region, IHiddenRegionFormatting formatting)
public ITextReplacerContext createTextReplacerContext(IFormattableDocument document)
public IMerger<ITextReplacer> createTextReplacerMerger()
public ITextReplacer createWhitespaceReplacer(ITextSegment hiddens, IHiddenRegionFormatting formatting)
public final java.util.List<ITextReplacement> format(FormatterRequest request)
IFormatter2
format
in interface IFormatter2
public abstract void format(java.lang.Object obj, IFormattableDocument document)
obj
- An XtextResource or an object for from your semantic model.document
- The document to collect and execute ITextReplacer
s.public <T> T getPreference(TypedPreferenceKey<T> key)
FormatterRequest.getPreferences()
public ITypedPreferenceValues getPreferences()
FormatterRequest
public FormatterRequest getRequest()
FormatterRequest
that was passed into IFormatter2.format(FormatterRequest)
when
invoking the formatter.public ITextRegionAccess getTextRegionAccess()
protected void initalize(FormatterRequest request)
format(Object, IFormattableDocument)
is called.protected boolean isInRequestedRange(org.eclipse.emf.ecore.EObject obj)
protected java.util.List<ITextReplacement> postProcess(IFormattableDocument document, java.util.List<ITextReplacement> replacements)
protected void reset()
format(Object, IFormattableDocument)
has been
called.public boolean shouldFormat(java.lang.Object obj, IFormattableDocument document)