Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » TMF (Xtext) » Formatting: Best practices around ownership of surrounding hidden regions(Who should own the hidden regions specifically around conditional formatting)
Formatting: Best practices around ownership of surrounding hidden regions [message #1860562] Thu, 17 August 2023 09:05
Oscar Ablinger is currently offline Oscar AblingerFriend
Messages: 6
Registered: August 2023
Junior Member
I'm currently trying to come up with a consistent way to work with "formatConditionally" and specifically the whitespace at the edges of the element being formatted conditionally.

First, let me describe the problem. I'll purposefully use a more abstract description of the grammar, as I believe that this can be easily solved for small grammars, but not for large ones (like the one I'm working on).
So, also, please don't take the code too exactly.

Let's say we have a grammar for your standard assignment in a language without a terminating symbol (like ';'):

foobar = "foobar"


We can have expressions on the right side that we'd rather have spreading multiple lines:

foobar = "foo" +
    "bar"


Since we want to properly indent it, lets indent everything to the right of the assignment:

// _format(final Assignment assignment, final IFormattableDocument document) { ...
    document.surround(assignment.getRight(), IHiddenRegionFormatter::indent);


Nice, now let's introduce ternary operators:

    foobar2 = foobar != null ? foobar : "default"


...and of course a multi-line version if it becomes too long:

foobar2 = foobar != null ?
    foobar :
    "default"


Afaik the recommended method to implement this is "formatConditionally":

// _format(final TernaryOperation tOp, final IFormattableDocument document) { ...
    final ISubFormatter singleLine = doc -> {
        doc = doc.requireFitsInLine();
        var region = regionFor(tOp);
        doc.surround(region.keyword("?"), IHiddenRegionFormatter::oneSpace);
        doc.surround(region.keyword(":"), IHiddenRegionFormatter::oneSpace);
    };
    final ISubFormatter multiLine = doc -> {
        var region = regionFor(tOp);
        doc.prepend(region.keyword("?"), IHiddenRegionFormatter::oneSpace);
        doc.append(region.keyword("?"), f -> f.setNewLines(1));
        doc.prepend(region.keyword(":"), IHiddenRegionFormatter::oneSpace);
        doc.append(region.keyword(":"), f -> f.setNewLines(1));

        doc.surround(tOp.getThen(), IHiddenRegionFormatter::indent);
        doc.surround(tOp.getElse(), IHiddenRegionFormatter::indent);
    };
    document.formatConditionally(tOp, singleLine, muiltiLine);


For simple examples this works great.
But notice how the muiltiLine formatter wants to add a replacer to the whitespace after the ternary operation? That means that currently this should throw an exception as the SubDocument has no access to that region.

That's the problem I don't know how to fix properly.

We can of course directly edit the formatter such that we increase the indentation inside the ISubFormatters and decrease it again outside of it.
But that falls apart if we have nested ternary operators as the IFormattableDocument that the _format(TernaryOperation, IFormattableDocument) method gets is already a SubDocument that doesn't include the whitespace after the ternary operation.

We could also always include the next hidden region in the "formatConditionally".
But that would run into a similar problem since we cannot call "doc.surround(tOp.getElse(), IHiddenRegionFormatter::indent);" if the else branch contains another ternary operator (that now also wants to own the whitespace around it).

Now for such a simple grammar I can get around it by just not using "formatConditionally" in the nested ternary operators (if the outermost has to be muiltiLined, then all other should be too), but in a sufficiently complex grammar, this becomes almost impossible to control.
So I see the need for a general guide for the formatter as to what whitespace a method for a specific node is allowed to touch.

So in the end, I think, my question can be summarized as such: Where should I format the whitespaces on the edges of elements used in "formatConditionally"?


Anyways, thanks for all of your help and insights.


P.s.: I think in theory you could resolve this issue by executing the conditional formatter eagerly and resolving it into a bunch of "normal" text-replacers. I'm sure there is a good reason why this is not the case, I just wonder what the reason behind it is.
Previous Topic:How to implement nested conditional formatting?
Next Topic:Configure Standalone
Goto Forum:
  


Current Time: Sat Jul 27 04:48:34 GMT 2024

Powered by FUDForum. Page generated in 0.02756 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top