Search code examples
eclipseformattingxtextxtend

Xtext 2.8+ formatter, formatting HiddenRegion with comment


I am using Xtext 2.9 formatter and I am trying to format hiddenRegion which contains comment. Here is part of my document region i am trying to format:

Columns: 1:offset 2:length 3:kind 4: text 5:grammarElement
Kind: H=IHiddenRegion S=ISemanticRegion B/E=IEObjectRegion

35  0 H
35 15 S ""xxx::a::b""        Refblock:namespace=Namespace
50  0 H
50  1 S "}"                  Refblock:RCBRACKET
      E Refblock             PackageHead:Block=Refblock path:PackageHead/Block=Package'xxx_constants'/head=Model/packages[0]
51  0 H
51  1 S ":"                  PackageHead:COLON
      E PackageHead          Package:head=PackageHead path:Package'xxx_constants'/head=Model/packages[0]
52    >>>H "\n    "             Whitespace:TerminalRule'WS'
        "# asd"              Comment:TerminalRule'SL_COMMENT'
   15   "\n    "             Whitespace:TerminalRule'WS'<<<
      B Error'ASSD'          Package:expressions+=Expression path:Package'xxx_constants'/expressions[0]=Model/packages[0]
67  5 S "error"              Error:'error'
72  1 H " "                  Whitespace:TerminalRule'WS'

and corresponding part of the grammar

Model:
    {Model}
    (packages+=Package)*;

Expression:
    Error | Warning | Enum | Text;

Package:
    {Package}
    'package' name=Name head=PackageHead
    (BEGIN
    (imports+=Import)*
    (expressions+=Expression)*
    END)?;

Error:
    {Error}
    ('error') name=ENAME parameter=Parameter COLON
    (BEGIN
    (expressions+=Estatement)+
    END)?;

PackageHead:
    Block=Refblock COLON;

Problem is that when i try prepend some characters before error keyword for example

error.regionFor.keyword('error').prepend[setSpace("\n    ")]

This indentation is prepended before the comment and not behind it. This results into improper formatting in case of single line comment before the 'error' keyword.

To provide more clarity, here is example code from my grammar and description of desired behavior:

package xxx_constants {namespace="xxx::a::b"}:
     # asd
     error ASSD {0}:
         Hello {0,world}

This is expected result: (one space to the left)

package xxx_constants {namespace="xxx::a::b"}:
    # asd
    error ASSD {0}:
         Hello {0,world}

and this is the actual result with prepend method

package xxx_constants {namespace="xxx::a::b"}:
    # asd
error ASSD {0}:
         Hello {0,world}

As the document structure says, the HiddenRegion is in this case is the statement:

# asd
    error

How can i prepend my characters directly before the keyword 'error' and not before the comment? Thanks.


Solution

  • I assume you're creating an indentation-sensitive language, because you're explicitly calling BEGIN and END.

    For indentation-sensitive language my answer is: You'll want to overwrite

    org.eclipse.xtext.formatting2.internal.HiddenRegionReplacer.applyHiddenRegionFormatting(List<ITextReplacer>)
    

    The methods append[] and prepend[] you're using are agnostic to comments and at a later time applyHiddenRegionFormatting() is called to decide how that formatting is weaved between comments.

    To make Xtext use your own subclass of HiddenRegionReplacer, overwrite

    org.eclipse.xtext.formatting2.AbstractFormatter2.createHiddenRegionReplacer(IHiddenRegion, IHiddenRegionFormatting)
    

    For languages that do not do whitespace-sensitive lexing/parsing (that's the default) the answer is to not call setSpace() to create indentation or line-wraps.

    Instead, do

    pkg.interior[indent]
    pkg.regionFor.keyword(":").append[newLine]
    pkg.append[newLine]