Search code examples
xtextxtend

How to have the AFTER separator in Xtend just behind last item


I use Xtend to generate some textual output from my Xtext grammar. My question is really simple, but I cannot figure it out reading the documentation and examples, so please give me advice!

Let us assume, I have a list with some items. I generate for every item a line within a FOR loop using the SEPARATOR feature. At the end I want to have a final separator using AFTER. Here is an example code to demonstrate it:

val list = #["a", "b", "c"]
'''
«FOR item : list SEPARATOR "," AFTER ","»
   «item»
«ENDFOR»
'''

In this way, I receive the following output:

a,
b,
c
,

Now the question: How can I have the final , separator immediately behind c and not on the new line? It's very important to me for proper formatting of my output (it's more complex than a,b,c in reality and the position of the separator matters). I want to have this:

a,
b,
c,

Experts, please help!


Solution

  • In your simple example, as SEPARATOR and AFTER are the same, you should skip the separator/after stuff entirely and just use

    '''
       «FOR item : list»
          «item»,
       «ENDFOR»
    '''
    

    The newlines after FOR and ENDFOR are skipped by Xtend's whitespace detection. The problem is that AFTER is applied after the loop is executed, and your loop-body contains a trailing newline that goes into the output (grayspace). You can overcome this by writing the entire loop in one line, e.g.

    '''
       «FOR item: list SEPARATOR ',\n' AFTER ',\n'»«item»«ENDFOR»
    '''
    

    and extract a method for when the loop's body becomes to long. For better readability, you can add any number of whitespaces within the guillemets, e.g.

    '''
       «FOR item: list SEPARATOR ',\n' AFTER ',\n'»«
          item
       »«ENDFOR»
    '''
    

    For smaller bodies, you might also consider prefer join()

    '''
       «list.join(',\n')»,
    '''
    

    or more general map(), reduce() whatsoever.