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
ITextReplacer
s. Each TextReplacer is responsible for a (small) section of the document. In
a second step, the TextReplacers are 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:
A formatter based on this class typically uses
ITextRegionAccess
to obtain the
IHiddenRegion
which
precedes or trails EObjects, EStructuralFeatures, Keywords, RuleCalls. 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
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:
ITextRegionAccess.regionForFeature(EObject, EStructuralFeature)
and
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
.