16. Formatter
Edit pageLast modified: 14 November 2024tip
This page is part of multi-step Custom Language Support Tutorial. All previous steps must be executed in sequence for the code to work.
The IntelliJ Platform includes a powerful framework for implementing formatting for custom languages. A formatter enables reformatting code automatically based on code style settings. The formatter controls spaces, indents, wrap, and alignment.
Define a Block
The formatting model represents the formatting structure of a file as a tree of Block
objects, with associated indent, wrap, alignment, and spacing settings. The goal is to cover each PSI element with such a block. Since each block builds its children's blocks, it can generate extra blocks or skip any PSI elements. Define SimpleBlock
based on AbstractBlock
.
public class SimpleBlock extends AbstractBlock {
private final SpacingBuilder spacingBuilder;
protected SimpleBlock(@NotNull ASTNode node, @Nullable Wrap wrap, @Nullable Alignment alignment,
SpacingBuilder spacingBuilder) {
super(node, wrap, alignment);
this.spacingBuilder = spacingBuilder;
}
@Override
protected List<Block> buildChildren() {
List<Block> blocks = new ArrayList<>();
ASTNode child = myNode.getFirstChildNode();
while (child != null) {
if (child.getElementType() != TokenType.WHITE_SPACE) {
Block block = new SimpleBlock(child, Wrap.createWrap(WrapType.NONE, false), Alignment.createAlignment(),
spacingBuilder);
blocks.add(block);
}
child = child.getTreeNext();
}
return blocks;
}
@Override
public Indent getIndent() {
return Indent.getNoneIndent();
}
@Nullable
@Override
public Spacing getSpacing(@Nullable Block child1, @NotNull Block child2) {
return spacingBuilder.getSpacing(this, child1, child2);
}
@Override
public boolean isLeaf() {
return myNode.getFirstChildNode() == null;
}
}
Define a Formatting Model Builder
Define a formatter that removes extra spaces except for the single spaces around the property separator:
Before
foo = bar
After
foo = bar
Create SimpleFormattingModelBuilder
by implementing FormattingModelBuilder
.
final class SimpleFormattingModelBuilder implements FormattingModelBuilder {
private static SpacingBuilder createSpaceBuilder(CodeStyleSettings settings) {
return new SpacingBuilder(settings, SimpleLanguage.INSTANCE)
.around(SimpleTypes.SEPARATOR)
.spaceIf(settings.getCommonSettings(SimpleLanguage.INSTANCE.getID()).SPACE_AROUND_ASSIGNMENT_OPERATORS)
.before(SimpleTypes.PROPERTY)
.none();
}
@Override
public @NotNull FormattingModel createModel(@NotNull FormattingContext formattingContext) {
final CodeStyleSettings codeStyleSettings = formattingContext.getCodeStyleSettings();
return FormattingModelProvider
.createFormattingModelForPsiFile(formattingContext.getContainingFile(),
new SimpleBlock(formattingContext.getNode(),
Wrap.createWrap(WrapType.NONE, false),
Alignment.createAlignment(),
createSpaceBuilder(codeStyleSettings)),
codeStyleSettings);
}
}
Register the Formatter
The SimpleFormattingModelBuilder
implementation is registered with the IntelliJ Platform in the plugin configuration file using the com.intellij.lang.formatter
extension point.
<extensions defaultExtensionNs="com.intellij">
<lang.formatter
language="Simple"
implementationClass="org.intellij.sdk.language.SimpleFormattingModelBuilder"/>
</extensions>
Run the Project
Run the plugin by using the Gradle runIde
task.
Open the example Simple Language properties file in the IDE Development Instance. Add some extra spaces around the =
separator between language
and English
. Reformat the code by invoking Code | Reformat File... dialog and choose Run.

Thanks for your feedback!