Skip to content

Terse Syntax

Jonathan Revusky edited this page Jun 16, 2024 · 8 revisions

New Terse Syntax in FreeMarker 3

Here is the new terse syntax in a nutshell:

As long as a built-in directive (such as #if, or #list etc.) starts on its own line, there is no need for the pointy (or square) bracket delimiters.

The newer syntax is entirely optional, but we strongly suspect that most people will prefer it.

Look, Ma! No brackets!

So, the following:

[#if foo = bar]
   Foo is bar.
[#else]
   Foo is not bar.
[/#if]

can now be written (if you want) as:

#if foo = bar
   Foo is bar.
#else
   Foo is not bar.
/#if

There is really quite little to understand about this... Well, when it comes to syntax, there are almost always a few little corners, so, for example:

Note that as of 2024-15-05, one can terminate an #if block with #endif or a #switch block with endswitch etc. Thus, the code above could be written as:

#if foo = bar
   Foo is bar.
#else
   Foo is not bar.
#endif

(Even though this is a bit longer to type, my feeling is that it is a bit more aesthetic and most people will prefer it.)

*Note that as of 2024-15-06, one can (optionally) write #elif instead of #elseif.

A bit of detail about when directives end

Again, note that this syntax only works when the directive is the first thing on a line (excluding whitespace). In that case, you enter a mode in which the next end-of-line is taken to be a closing delimiter. As a result,

[#var x = 1, y = 2]

can be written:

#var x = 1, y =2

(Note the use of the newer #var syntax in the above. That is described here.)

Note also that the above can be written on multiple lines, i.e.

#var x = 1,
     y = 2

This is because certain delimiter tokens (the comma among them) suppress the interpretation of the following newline as closing the directive. (Another way of looking at this is that, since the directive is obviously incomplete, we will continue parsing it into the next line.) Now, one aspect of this is that the above does not work without the comma. Specifically, if you write:

#var x = 1
     y = 2

that would be as if you wrote, in the older, more verbose syntax:

 [#var x = 1]
       y = 2

So, you see, without the comma, the y = 2 line is parsed as being just regular text to output, which is probably not one's intention in this spot, but the parser can hardly be expected to read your mind! Without the trailing comma, in the terse syntax, the newline character that follows is taken to terminate the assignment instruction. I would admit that does mean that certain terse constructs are (in certain cases) harder to read than their fully delimited traditional equivalents. However, on consideration, the older, more verbose syntax is still available, so you can write these things however you think they are more clear. In an earlier implementation of all this it was more strict and the terse directive had to be written on a single line, so you would have to write:

  #var x = 1
  #var x = 2

And you can still write that. Of course, in Java, you can write:

  int x = 1, y = 2;

or:

  int x = 1;
  int y = 2;

I learned a few months ago that the first, shorter form is considered bad style by some style checkers (that presumably enforce whatever style guidelines.)

Single Line Comments

Comments can now be written in single-line style. Basically, #-- is taken to start a comment, which terminates with a newline character. This is completely analogous to the way // starts a comment in Java/C#/C++. Such a comment does not have to begin a line, as with the terse directives described above. So you can write:

  Just some text blah blah #-- Just some comment

Or:

  #set foo = bar.baz #-- This line is very important!

Terse un-escaping

In FreeMarker 3, when you want to output some variable or expression as-is there is the terse syntax of:

 $\{x}

This means that if auto-escaping is in effect, such that, for example, ${x} really means ${x?html}, the escaping is suppressed. Well, the simplest example is that if we had #escape x as x?html in place, then:

 ${">"}

would output:

 >

but

 $\{">"}

would output:

 >

This terse unescaping simply removes all levels of escape, so that if there are two (or more) levels of escaping in place, they are all disregarded for this interpolation.

Clone this wiki locally