How to make the Indent relative to direct parent's parents?
Answered
I'm recently working on a language support plugin and I'm having a problem developing the formater.
I overload the getIndent function in my block class to format indent. But in some cases, because the indent of the block is relative to the direct parent node, I encountered the problem as shown in the picture:

the statements' indent in the if statement relative to the '{', but I want is relative to the "if", like every formater program else do.
How can I do it?
here is the grammer g4 code and my getIndent code:



Please sign in to leave a comment.
Hi,
It is hard to help without knowing the formatting blocks structure. I suggest taking a look at the structure in PSI Viewer (see the screenshot here: https://plugins.jetbrains.com/docs/intellij/code-formatting.html) and checking if there are any redundant indents in intermediate blocks.
here is the structure screenshot. I only defined one block class so that the structure may not be so clear.
and I copied the PSI tree as following. It's easier to locate the problem by searching "ANTLRPsiNode(ifStatement)(61,150)".
Hi,
I don't see any indent in your blocks structure, but alignment raises my attention.
Could you please paste the rest of your block code and other code around the formatting model?
You are right, I did not pay attention to the settings of alignment
here is the YJSBlock class:
public class YJSBlock extends AbstractBlock {
private final SpacingBuilder spacingBuilder;
protected YJSBlock(@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 YJSBlock(child, Wrap.createWrap(WrapType.NONE, false), Alignment.createAlignment(),
spacingBuilder);
blocks.add(block);
}
child = child.getTreeNext();
}
return blocks;
}
@Override
public Indent getIndent() {
if (isEmpty(myNode)) {
return null;
}
String parentType;
if(myNode.getTreeParent() != null) {
parentType = myNode.getTreeParent().getElementType().toString();
} else {
parentType = "";
}
String firstChildType;
if(myNode.getFirstChildNode() != null) {
firstChildType = myNode.getFirstChildNode().getElementType().toString();
} else {
firstChildType = "";
}
String type = myNode.getElementType().toString();
if(type.equals("clzOrFunctionDeclaration"))
return Indent.getNormalIndent();
if(type.equals("functionBody"))
return Indent.getNormalIndent();
if(type.equals("statementList") && parentType.equals("block"))
return Indent.getNormalIndent();
if (type.equals("statement") && parentType.equals("ifStatement") && !firstChildType.equals("block"))
return Indent .getNormalIndent();
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;
}
private static boolean isEmpty(ASTNode node) {
return node.getElementType() == TokenType.WHITE_SPACE || node.getTextLength() == 0;
}
}
and here is YJSFormattingModelBuilder class:
public class YJSFormattingModelBuilder implements FormattingModelBuilder {
private static SpacingBuilder createSpaceBuilder(CodeStyleSettings settings) {
SpacingBuilder builder = new SpacingBuilder(settings, YJSLanguage.INSTANCE);
builder.around(YJSTokenTypes.TOKEN_TYPES.get(JavaScriptLexer.Assign)).spacing(1, 1, 0, false, 0);
builder.before(YJSTokenTypes.TOKEN_TYPES.get(JavaScriptLexer.SemiColon)).spacing(0, 0, 0, false, 0);
builder.after(YJSTokenTypes.TOKEN_TYPES.get(JavaScriptLexer.SemiColon)).spacing(0, 0, 1, true, 0);
builder.before(YJSTokenTypes.TOKEN_TYPES.get(JavaScriptLexer.Comma)).spacing(0, 0, 0, false, 0);
builder.after(YJSTokenTypes.TOKEN_TYPES.get(JavaScriptLexer.Comma)).spacing(1, 1, 0, false, 0);
builder.after(YJSTokenTypes.TOKEN_TYPES.get(JavaScriptLexer.OpenBrace)).spacing(0, 0, 1, true, 0);
builder.before(YJSTokenTypes.TOKEN_TYPES.get(JavaScriptLexer.OpenBrace)).spacing(1, 1, 0, false, 0);
builder.around(YJSTokenTypes.TOKEN_TYPES.get(JavaScriptLexer.CloseBrace)).spacing(0, 0, 1, true, 0);
return builder;
}
@Override
public @NotNull FormattingModel createModel(@NotNull FormattingContext formattingContext) {
final CodeStyleSettings codeStyleSettings = formattingContext.getCodeStyleSettings();
return FormattingModelProvider
.createFormattingModelForPsiFile(formattingContext.getContainingFile(),
new YJSBlock(formattingContext.getNode(),
Wrap.createWrap(WrapType.NONE, false),
Alignment.createAlignment(),
createSpaceBuilder(codeStyleSettings)),
codeStyleSettings);
}
}
Do you have any advice on how to define the alignment?
Hi,
I don't think you need alignment at all, so as a first step please do not create it (pass null instead of Alignment.createAlignment()). The same applies to Wrap - if you don't need it at the moment, please pass null instead of creating objects.
Check if removing these parts changes your formatting behavior.
Awesome! It looks so normal now. Thank you a lot!