Custom Language Indent Follow
Hey. I'm developing a custom language plugin for a language with syntax similar to Lisp. A typical piece of code looks a lot like this:
(main_operation
(sub_op_1 param_1 param_2)
(several (chained (ops
param_3
param_4
)))
)
For this example, let's set the Tab size to 4 and check the "Use tab character" box. When I tell IntelliJ to format my code, I want the result to look like this:
(main_operation
(sub_op_1 param_1 param_2)
(several (chained (ops
param_3
param_4
)))
)
However, I have only been able to make the formatter spit out code that looks like this:
(main_operation
(sub_op_1 param_1 param_2)
(several (chained (ops
param_3
param_4
)))
)
Here's the same example again, with -> representing tab and . representing leading spaces. This is what I want:
(main_operation
->(sub_op_1 param_1 param_2)
->(several (chained (ops
->->param_3
->->param_4
->)))
)
This is as close as I've gotten the formatter to give me:
(main_operation
->.(sub_op_1 param_1 param_2)
->.(several (chained (ops
->->->->->->..param_3
->->->->->->..param_4
->->->->->..)))
)
Here are the two main areas that are giving me trouble. The first is a minor annoyance, but the second has me dead in the water.
- The start of line two is indenting from the first non-open-paren character of line one. This gives me an actual indent size of 5 instead of the 4 I wanted. I can work around this by using Indent.Type.SPACES and setting the value to one less than the indent size I actually want (3 in this case), but that feels hacky and I hope there's a better way.
- The real problem I can't get past is line 4. That line should be indented one level deeper than the previous line. However, when IndentAdjuster calculates the block offset in the adjustSpacingByIndentOffset method, tons of extra indentation is added as a result of the multiple blocks on the previous line.
I'd prefer not to reimplement any of the whitespace adjustment classes like IndentAdjuster and AdjustWhiteSpacesState. Please let me know if there's some quick and easy solution I'm missing, or if you can recommend a good example that accomplishes something similar. If some potentially helpful information is missing from my question, let me know and I'll add it.
Please sign in to leave a comment.
You can try to use Indent.getSmartIndent, basically it's a type of indent which tries to collapse multiple indents into single one if proper conditions are met.
It's used in java to format anonymous classes nicely:
while when there is no second parameter indent is collapsed
Thanks for the suggestion. In this case, SmartIndent results in the same spacing as normal indent, so it unfortunately did not magically solve my problem.
I ended up with a fairly hacky "solution" that manually parses the file and calculates the amount the indent should be offset to work around the issues I mentioned earlier. So, in this example, the Indent returned by my Block implementation for the param_3 line ends up being -11 spaces.
It's ugly, but it outputs the desired formating. I'm willing to throw it all in the garbage if something better comes along, but for now it's the best I've got.
As expected, the hacky solution didn't really work.
It turns out the problem was with Alignment, not Indent, and the fix had to be made in two places. The first was at the grammar level. I had to move the expression body to a separate element so it could be indented and aligned independently from the enclosing parentheses. The second fix was to properly set the parent alignment of child blocks during child block generation.
I have exactly the same problem, formatter works well with Ctrl+Alt+L but not properly during editing.
Reading your last post is not clear for me how you solve the problem. Can you give more details? Maybe an extract of the code? Did you work on the Block class? Or in the FormattingModelBuilder?
Thanks in advance for the help!
The main thing that helped was the one I already mentioned. I modified the definition of my language's grammar in the xxx.bnf file so that parens occupied their own nodes in the AST. I also ensured the blocks appropriately inherited parent alignment during block generation.
This is some of the code that helped adjust block indentation. I have no idea if doing it this way is a good idea.