-
Notifications
You must be signed in to change notification settings - Fork 1
Standard Way of Code Formatting in Xtext Framework
The following text describes what are current resources for code formatting in the Xtext framework. All of the code formatters, which are available for use, work over the token stream. Each formatter reads tokens from an input stream, recognizes them and accordingly inserts formatting characters such as a white space, a tab, a new line, etc. between consecutive tokens which serves as a whole to fulfill an output token stream. The Xtext framework standardly serves two following code formatters.
The formatter writes one white space between all tokens. Since the code formatted into one line is poorly legible, this formatter is practically useless for a coder of a particular language. On the other hand, the formatter can find its application in code storing because the token separator is minimalistic and the code formatted in this way is free from additional formatting characters.
The formatter is more sophisticated than the previous. It is supposed that the behavior of the formatter will be configured by the language developer. The language developer can do this by creating a new class which inherits from the AbstractDeclarativeFormatter
class and contains overridden the configureFormatting
method. The method has one parameter whose type is the FormatterConfig
class.
The body of the configureFormatting
method should contain commands which set the parameter. When the body is empty, the formatter behaves exactly like the OneWhitespaceFormatter
. The mentioned commands are essentially method callings on the parameter. The following list contains description of these methods.
-
setAutoLineWrap(int lineSize)
- The method sets the maximum line size in the entire file. The size can be exceeded only when the line is represented by one token whose length is greater than the defined size. -
setIndentationIncrement()
- The method increases by one unit the indentation. The unit is one tab by default. In other words, the indentation is the number of units before the first token on the line. -
setIndentationDecrement()
- The method decreases by one unit the indentation. All details are similar to the details of the previous method. -
setLinewrap(int count)
- The method sets a defined count of line-wraps at a given position. -
setNoLinewrap()
- The method suppresses automatic line wrap, which may occur when the line size exceeds the defined limit. -
setSpace(String space)
- The method inserts the defined string space into the given position. -
setNoSpace()
- The method suppresses white spaces between tokens at the given position.
Although, the methods, which allow for setting the parameter of the configureFormatting
method, were described, some of them perform an action at the position which is not yet known how to specify. Each method which is related to some position returns an object fulfilling the function of
a locator. So as the parameter of the configureFormatting
method can be adjusted by method calling on itself as well as the position can be set by calling the given method, on the locator. The parameters of these methods are parser rules (see Grammar Rules) as well as grammar elements used to define some parser rule (see Defining Elements of the Parser Rule). The following list contains description of methods that specifies a position.
-
after(element)
- The method sets the locator to specify a position located immediately after a token which is related to the defined element. -
before(element)
- The method sets the locator to specify a position located immediately before a token which is related to the defined element. -
around(element)
- The method sets the locator to specify positions located immediately before and after a token which is related to the defined element. -
between(left, right)
- The method sets the locator to specify a position located between two tokens where the related right element immediately follows after the left one. -
bounds(left, right)
- The method sets the locator to specify positions located immediately after the token which is related to the left element and immediately before the token which is related to the defined right element. -
range(start, end)
- The method sets the locator to specify positions located between tokens bounded by tokens whose related elements are the defined start and the defined end. The position immediately after the token related to the start element and the position immediately before the token related to the end element are parts of the locator configuration.
Since the elements are needed as parameters for the described methods, the formatter serves the getGrammarAccess
method returning a data structure which allows for accessing the elements of the grammar. The elements are accessible through the generated methods whose names are derived from
names of grammar elements (see the Listing 1).
Although, this approach makes it possible to define all grammar elements contained in the data structure, each of the mentioned methods represents only one grammar element. However, this means that the formatting configuration for the keyword which is contained in more parser rule specifications (see Grammar Rules) has to be defined separately for every occurrence of the keyword in the grammar and even when the formatting configurations of particular occurrences do not differ. For this issue, the parameter of the
configureFormatting
method allows for calling the following methods on itself.
-
findKeywords(String... keywords)
- The method returns all occurrences of the keyword just when the keyword is a parameter of the method. -
findKeywordPairs(String left, String right)
- The method returns couples formed from occurrences of left and right keyword from the same specification of the parser rule (see Grammar Rules) . Pairs are matched nested and sequentially, therefore it is impossible that the particular occurrence of the keyword was contained in more couples.
The following two listings demonstrate what the formatter based on the AbstractDeclarativeFormatter
may look like in practice.
A code formatter based on the AbstractDeclarativeFormatter
which can format the code written in the language whose grammar is specified in the listing on this page.
public class ExampleFormatter extends AbstractDeclarativeFormatter
{
@Override
protected void configureFormatting(FormattingConfig c) {
ExampleGrammarAccess f = (ExampleGrammarAccess)getGrammarAccess();
// set a maximum size of lines
c.setAutoLinewrap(160);
// set a line wrap after each import of a name space
c.setLinewrap().after(f.getImportRule());
// set an empty line between a package declaration a set of name space imports
c.setLinewrap(2).between(f.getModelAccess().getPackageAssignment_0(), f.getModelAccess().getImportsAssignment_1_0());
// set an empty line between a package declaration and a class
c.setLinewrap(2).between(f.getModelAccess().getPackageAssignment_0(), f.getModelAccess().getClassAssignment_1_1());
// set an empty line between a set of name space imports and a class
c.setLinewrap(2).between(f.getModelAccess().getImportsAssignment_1_0(), f.getModelAccess().getClassAssignment_1_1());
// set an empty line between a class and a set of name space imports
c.setLinewrap(2).between(f.getClassRule(), f.getImportRule());
// set no space around all parentheses
for(Pair<Keyword, Keyword> p : f.findKeywordPairs("(", ")")) {
c.setNoSpace().around(p.getFirst());
c.setNoSpace().around(p.getSecond());
}
// set no space before all commas
for(Keyword comma : f.findKeywords(",")) {
c.setNoSpace().before(comma);
}
// set indentation inside all curly brackets
// set line wrap after each left curly bracket
// set line wrap around each right curly bracket
for(Pair<Keyword, Keyword> p : f.findKeywordPairs("{", "}")) {
c.setIndentationIncrement().after(p.getFirst());
c.setIndentationDecrement().before(p.getSecond());
c.setLinewrap().after(p.getFirst());
c.setLinewrap().around(p.getSecond());
}
// set line wrap before left curly bracket which is contained in Class rule
c.setLinewrap().before(f.getClassAccess().getLeftCurlyBracketKeyword_4());
// set empty line between two inner elements of class (inner class or method)
c.setLinewrap(2).between(f.getClassAccess().getAlternatives_5(), f.getClassAccess().getAlternatives_5());
}
}
A code written in the language whose grammar is specified in the listing on this page. The code is formated by the formatter defined in the Listing 1.
package CZ.GPP.TESTS.EXAMPLES
import NAMESPACE1
import NAMESPACE2
class CLASS1 extends SUPER_CLASS
{
abstract class INTERNAL_CLASS
{
private SUPER_CLASS FOO(string PAR1, int PAR2){
1 2 3
}
protected SUPER_CLASS BAR(CLASS1 PAR){
4 5
}
}
public CLASS1 CREATE_OBJECT(string NAME){
6 7
}
}