StringTemplate has auto-indentation on by default. To turn it off, use NoIndentWriter rather than (the default) AutoIndentWriter.

At the simplest level, the indentation looks like a simple column count:

My dogs' names 
  $names; separator="\n"$
The last, unindented line

will yield output like:

My dog's names
The last, unindented line

where the last line gets "unindented" after displaying the list. StringTemplate tracks the characters to the left of the $ or < rather than the column number so that if you indent with tabs versus spaces, you'll get the same indentation in the output.

When there are nested templates, StringTemplate tracks the combined indentation:

// <user> is indented two spaces
main(user) ::= <<
\t$user:quote(); separator="\n"$

quote ::= " '$it$'"

In this case, you would get output like:

\t 'Bob'
\t 'Ephram'
\t 'Mary'

where the combined indentation is tab plus space for the attribute references in template quote. Expression $user$ is indented by 1 tab and hence any attribute generated from it (in this case the $attr$ of quote()) must have
at least the tab.

Consider generating nested statement lists as in C. Any statements inside must be nested 4 spaces. Here are two templates that could take care of this:

function(name,body) ::= <<
void $name$() $body$

slist(statements) ::= <<
    $statements; separator="\n"$

Your code would create a function template instance and an slist instance, which gets passed to the function template as attribute body. The following code:


StringTemplate f = group.getInstanceOf("function");
f.setAttribute("name", "foo");
StringTemplate body = group.getInstanceOf("slist");
body.setAttribute("statements", "i=1;");
StringTemplate nestedSList = group.getInstanceOf("slist");
nestedSList.setAttribute("statements", "i=2;");
body.setAttribute("statements", nestedSList);
body.setAttribute("statements", "i=3;");
f.setAttribute("body", body);


StringTemplate f = group.GetInstanceOf("function");
f.SetAttribute("name", "foo");
StringTemplate body = group.GetInstanceOf("slist");
body.SetAttribute("statements", "i=1;");
StringTemplate nestedSList = group.GetInstanceOf("slist");
nestedSList.SetAttribute("statements", "i=2;");
body.SetAttribute("statements", nestedSList);
body.SetAttribute("statements", "i=3;");
f.SetAttribute("body", body);


f = group.getInstanceOf("function")
f["name"] = "foo"
body = group.getInstanceOf("slist")
body["statements"] = "i=1;"
nestedSList = group.getInstanceOf("slist")
nestedSList["statements"] = "i=2;"
body["statements"] = nestedSList
body["statements"] = "i=3;"
f["body"] = body

should generate something like:

void foo() {

Indentation can only occur at the start of a line so indentation is only tracked in front of attribute expressions following a newline.

The one exception to indentation is that naturally, $if$ actions do not cause indentation as they do not result in any output. However, the subtemplates (THEN and ELSE clauses) will see indentations. For example, in the following template, the two subtemplates are indented by exactly 1 space each: