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:

0
6 comments

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.

0

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)".

YJS file(0,159)
  ANTLRPsiNode(program)(0,158)
    ANTLRPsiNode(contractDeclar)(0,158)
      PsiElement('oracle')('oracle')(0,6)
      PsiElement(Identifier)('GlobalRouter')(8,20)
      PsiElement('{')('{')(21,22)
      ANTLRPsiNode(clzOrFunctionDeclaration)(27,156)
        ANTLRPsiNode(functionDeclaration)(27,156)
          PsiElement('function')('function')(27,35)
          PsiElement(Identifier)('initAsync')(36,45)
          PsiElement('(')('(')(45,46)
          ANTLRPsiNode(formalParameterList)(46,49)
            ANTLRPsiNode(formalParameterArg)(46,49)
              PsiElement(Identifier)('arg')(46,49)
          PsiElement(')')(')')(49,50)
          PsiElement('{')('{')(51,52)
          ANTLRPsiNode(functionBody)(61,150)
            ANTLRPsiNode(sourceElements)(61,150)
              ANTLRPsiNode(sourceElement)(61,150)
                ANTLRPsiNode(statement)(61,150)
                  ANTLRPsiNode(ifStatement)(61,150)
                    PsiElement('if')('if')(61,63)
                    PsiElement('(')('(')(64,65)
                    ANTLRPsiNode(expressionSequence)(65,76)
                      ANTLRPsiNode(singleExpression)(65,76)
                        ANTLRPsiNode(singleExpression)(65,68)
                          PsiElement(Identifier)('arg')(65,68)
                        PsiElement('==')('==')(69,71)
                        ANTLRPsiNode(singleExpression)(72,76)
                          ANTLRPsiNode(literal)(72,76)
                            PsiElement(BooleanLiteral)('true')(72,76)
                    PsiElement(')')(')')(76,77)
                    ANTLRPsiNode(statement)(78,150)
                      ANTLRPsiNode(block)(78,150)
                        PsiElement('{')('{')(78,79)
                        ANTLRPsiNode(statementList)(109,123)
                          ANTLRPsiNode(statement)(109,123)
                            ANTLRPsiNode(expressionStatement)(109,123)
                              ANTLRPsiNode(expressionSequence)(109,122)
                                ANTLRPsiNode(singleExpression)(109,122)
                                  ANTLRPsiNode(singleExpression)(109,120)
                                    PsiElement(Identifier)('startServer')(109,120)
                                  ANTLRPsiNode(arguments)(120,122)
                                    PsiElement('(')('(')(120,121)
                                    PsiElement(')')(')')(121,122)
                              ANTLRPsiNode(eos)(122,123)
                                PsiElement(';')(';')(122,123)
                        PsiElement('}')('}')(149,150)
          PsiElement('}')('}')(155,156)
      PsiElement('}')('}')(157,158)
0

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?

0

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?

0

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.

0

Awesome! It looks so normal now. Thank you a lot!

0

Please sign in to leave a comment.