Johan
Johan

Reputation: 615

xtext: How to format code where block needs to be indented

My grammar is given by:

Model:
    'module' (mn=ID)?
        (func+=Function)+
    'end_module'
;

Function:
    'function' name=ID '('')'
        (vars+=ID)*
    'end_function'
;

I can find the token like 'function', '(' etc.

The formatting I am looking for:

module test
  function fdf ()
    str1
    str2
  end_function

  function ff ()
  end_function
end_module

So far I do generate the formatting stubs by using: formatter = { generateStub = true }

Upvotes: 0

Views: 1961

Answers (2)

Christian Dietrich
Christian Dietrich

Reputation: 11868

that should be rather straight forward e.g.

@Inject extension MyDslGrammarAccess

def dispatch void format(Model model, extension IFormattableDocument document) {
    model.regionFor.keyword(modelAccess.end_moduleKeyword_3).prepend[newLine] 
    if (model.mn != null) {
        model.regionFor.feature(MyDslPackage.Literals.MODEL__MN).append[newLine]
        interior(
            model.regionFor.feature(MyDslPackage.Literals.MODEL__MN), 
            model.regionFor.keyword(modelAccess.end_moduleKeyword_3)
        ) [indent]
    } else {
        model.regionFor.keyword(modelAccess.moduleKeyword_0).append[newLine]
        interior(
            model.regionFor.keyword(modelAccess.moduleKeyword_0),
            model.regionFor.keyword(modelAccess.end_moduleKeyword_3)
        ) [indent]
    }
    for (Function func : model.getFunc()) {
        func.format;
    }
}

def dispatch void format(Function function, extension IFormattableDocument document) {
    function.regionFor.keyword(functionAccess.functionKeyword_0).append[newLine].prepend[newLine]
    function.regionFor.keyword(functionAccess.end_functionKeyword_5).prepend[newLine]
    interior(
        function.regionFor.keyword(functionAccess.functionKeyword_0),
        function.regionFor.keyword(functionAccess.end_functionKeyword_5)
    ) [indent]
}

Upvotes: 3

Lorenzo Addazi
Lorenzo Addazi

Reputation: 325

As proposed in Max's Answer, it is possible to cope with whitespace-aware languages starting from Xtext v2.8. Check it out!.

In your case, I guess you should define your grammar as follows:

Model:
    'module' (mn=ID)?
    BEGIN
        (func+=Function)+
    END
    'end_module'
;

Function:
    'function' name=ID '('')'
    BEGIN
        (vars+=ID)*
    END
    'end_function'
;

terminal BEGIN: 'synthetic:BEGIN';
terminal END: 'synthetic:END';

In case you would also want to allow 'empty-bodied' functions, I guess you should change the rule above as follows:

Function:
    'function' name=ID '('')'
    (BEGIN
         (vars+=ID)*
    END)?
    'end_function'
;

Hope it helps!

Upvotes: 2

Related Questions