Formatter and Indentation

Answered

Hey, 

 

I know here are some answers already regarding this question, but unfortunately the answers are way too old or did not resolve the problem.

So here we go.

 

I have a simple Lua Grammar and all i want to get every Child Block indented by 1 tab. As you can see, as far as the parent is not the File itself, i want to get a normal Indent. The "return parent.getIndent();" was already a Indent.getNoneIndent() and null, always with the same result: nothing...

 

My FormattingBlock where the indentation is built, inherited from AbstractBlock:

spacing rules:

PsiTree (CoronaBlockImpl(BLOCK) starting from the second layer should be indented):

and now the result i get from the indentation:

 

so can someone please explain to me, why this stuff is not indented as expected? As far as I have read through forums, Documentations and internets this should be correct?

0
36 comments

The indent in a formatter block is always relative to it's parent. If you want a child block be unindented to it's parent, you simply return Indent.getNoneIndent(), not parent.getIndent(). In you case BLOCK element may be indented if it's located, for example, inside another BLOCK element, right? The code then would look something like that:

if (parent.getNode().getElementType() == BLOCK) {
    return Indent.getNormalIndent(); // Indent every child inside BLOCK element including another BLOCK.
}
return Indent.getNoneIndent(); // Do not indent otherwise.

Also be careful with "instanceof". Perhaps "FileElemeent" is of class PsiElement while getNode() will return ASTNode. So to get a corresponding PSI element you may need to call getNode().getPsi(), otherwise the condition may be always false.

0
Avatar
Felix Dörschner

I didn't test your example code yet, I have just a question:

wouldn't it make more sense to apply the indentation to the Block Element at creation-point? So, if i create my new AbstractBlock (in my case, CoronaFormatBlock), i want the whole Block to be indented, right?

so if i say:

new CoronaFormatBlock(astNode, wrap, alignment, CoronaIndent.getIndent(astNode));

where astNode.getElementType() == BLOCK!

So, in my intention, the whole block should be indented right?

 

From what i unterstood from your post, i would apply the indentation only to the childs of the Block-Element.

0

Correct. You can definitely assign the indentation type at block creation time. In reality child blocks are created lazily on demand but at this point they may get some fixed assigned indentation.

0
Avatar
Felix Dörschner

So, i applied the indentation to what your example code gave me.

code:

result (i am on a different pc now, so the code in the result looks different):

 

edit: tab (or indent) size is set to 4 spaces, this are 8!

0
Avatar
Felix Dörschner

Ok, but why is this not working then? :D

 

edit: as you can see, the question is not answered. Would you mind removing that flag please?

0

You have still missed one thing: the last statement is still wrong, it should be "return Indent.getNoneIndent()",  not "return parent.getIndent()". I have already explained it above.

0
Avatar
Felix Dörschner

Saw that already, fixed that already, still won't work...



0
Avatar
Felix Dörschner

Any more suggestions please, since it is still not working as expected? :/

0

it is possible to use spacing instead of Indent: 

add Extension Point: lang.formatter : implement FormattingModelBuilder

implement FormattingModel

implement Block:

@Override
public List<Block> getSubBlocks();

@Override
public Spacing getSpacing(@Nullable Block child1, @NotNull Block child2){
...
return Spacing.createSpacing(...);
}

 

the last getSpacing method would need to handle both indents and spacing between symbols, punctuation. Indent logic can get quite complex.

0
Avatar
Felix Dörschner

In my initial post I already posted the Spacing Blocks/Builder. The "horizontal" Spaces are not acknowledged as well, unfortunately. For example, if i change my "NO_SPACING_WITH_NEWLINE" from .createSpacing(0, 0, 1, false, 0) to .createSpacing(4, 4, 1, false, 0) nothing happens 

0

did you register FormattingModelBuilder and implement FormattingModel, Block?

 if you decide to try this solution (which will take time and may not work for you), 

  FormattingModel's initRootBlock should return your Block implementation.

  getSubBlocks should return your Block implementations (cast as Block as you add them to the List).

0
Avatar
Felix Dörschner

yes, it is registered.

 

I can only guess, but i think my blocks are in the solution, because new lines are working. For example the NO_SPACING_EXTRA_LINE thing works fine. Or at least fine enough since only lines and no spaces are added.

0

try this in Block impl:

@Override
public Indent getIndent() {return null;}

 

try putting a breakpoint in getSpacing to see when it is called.

 

another thing: Block implementation methods should not be static but instance methods. I am not sure from where in code your static methods are called.

0
Avatar
Felix Dörschner

did that, what is supposed to happen?

0

getSpacing is supposed to be called for every block in a file: for beginning of line, between symbols etc.

this is Block implementation's getSpacing - not static getSpacing

0
Avatar
Felix Dörschner

ah ok, yes, that is happening. And that is why I can't wrap my head around it, why it is not working and stuff

0

is this formatting code online somewhere?

0
Avatar
Felix Dörschner

more or less, yes. I posted nearly everything that is to it in this thread as screenshots. If I have missed something, I can screenshot that as well. If that is not enough, I can upload that to the upload.jetbrains-thing as well

0

FormattingModel uses Block instances.

in the screenshots many methods are static. I am not sure how this is supposed to work. It may be possible but this is a very different approach. This, or key code parts are missing from the picture.

0
Avatar
Felix Dörschner

ah ok, I am terribly sorry. Yes, Keyparts are missing. 

the getSpacing() and getIndet() functions are in helper classes (CoronaSpacing and CoronaIndent) and therefore static. In the second picture in the initial post you can see the call.

The FormatBlock is a derivation from AbstractBlock (taken from here: http://www.jetbrains.org/intellij/sdk/docs/tutorials/custom_language_support/formatter.html

0
Avatar
Felix Dörschner

here is the whole FormatBlock:



the rest should be here already

0

try to leave AbstractBlock out and implement original Block interface.

here is a hint where you are likely to pause:

 @NotNull
public ChildAttributes getChildAttributes(int i) {
return new ChildAttributes((Indent)null, (Alignment)null);
}

 

0
Avatar
Felix Dörschner

Hey,

thank you for your help so far.

I just changed to your suggestions (worked on my grammar, so i couldn't earlier) and set my breakpoint in that function but that is not even called. The "getSubBlocks()" instead is. 

So I guess my models are not saved somehow?

 

0
Avatar
Felix Dörschner

wait nevermind, it is called, but not when i hit the autoformat command (ctrl+alt+L)

0

could you post somewhere (here, git, pastebin, ...)   

your implementations of:

FormattingModelBuilder

FormattingModel

Block

(as text, please.Images are blurred for some reason)  

0
Avatar
Felix Dörschner

sure:

Block: http://pastebin.com/CUDBfKKn

FormatModelBuilder: http://pastebin.com/vDEbsKLz

IndentationHelper: http://pastebin.com/rhck4A3r

SpacingHelper: http://pastebin.com/kVMj6j8n

 

FormattingModel is created by the ModelProvider, so no Code there

0

if you were to implement everything without FormattingModelProvider, here are a couple more steps:

 

FormattingModelBuilder:

    createModel - returns implementation of FormattingModel.

 

Implementation of FormattingModel :

   getRootBlock -  returns implementation of Block

   getDocumentModel - returns implementation of FormattingDocumentModel

 

if you do all this and indenting still does not work as expected, try to 

@Override
public Indent getIndent() {
return null;
}

in Block.

Then set all spacing (including indent) with 

 @Override
public Spacing getSpacing(@Nullable Block child1, @NotNull Block child2) 

 

it is a bit of work but it works.

 

actually, try "getIndent returns null" first. It is less work.

0
Avatar
Felix Dörschner

well, yeah, no ;/ did not work

FormattingModel: http://pastebin.com/TfUHpHXi

and "new" SpacingHleper: http://pastebin.com/jyGFuemd

rest is unoticeable changed

0

does  FormattingModelBuilder createModel return CoronaFormatModel?

did you try to not use Indent altogether? return null, and let getSpacing handle indenting?

if I understand correctly, you are looking to fix indenting, yes?

0
Avatar
Felix Dörschner

@1: yes, one of the unnoticeable changes. I though a new pastebin wasn't necessary for that change

@2: yes, tried both, with Indent, without Indent:

@3: basically yes. But i would call it "create" first since it was not even running properly till now :D

0

Please sign in to leave a comment.