emerald

an HTML templating engine for Nim

Documentation

This is the complete documentation of emerald. It explains all of emerald's features and also explains implementation details, so it is also the developer documentation. The reader is expected to be used to the Nim programming language and its concepts.

emerald tries to omit HTML that is valid polyglot markup, i.e. that is valid HTML 5 and also valid XHTML. This means that emerald writes properly closed HTML tags in all cases, uses quotes for attribute values, and writes a value for boolean attributes where HTML permits the value to be omitted. The goal is for emerald's output to be as robust as possible.

Like Nim itself, emerald treats all keywords, commands and procs it declares independently of style and casing, so you can use both mixin_content and mixinContent as you please. HTML tag and attribute names are also parsed case-independently; however, the styling matters here: http_equiv is not the same as httpEquiv.

input...
... the resulting AST, visualized as Nim code ...
... and how to use it in your code.

Interface

The two macros html_templ and html_mixin are the main API of emerald. The only other things that are publicly exposed are the filters that come with emerald. These are explained in Filters.

html_templ

This macro can only be applied to a proc. This proc may not have a return type and may be publicly exposed (via *) or private. The whole content of the proc will be parsed as HTML template. Parsing will convert the proc into an object type with the same name, a constructor proc for this type, and a method named render() that operates on this type. This is shown in the example code.

The render method takes an instance of the template object as first parameter and a Stream as second parameter. The object type, the constructor proc and the render method will have the same visibility as the original proc, so you can have private and public templates.

All parameters of the original proc will be transformed into fields of the resulting object type. This enables you to re-use an object instance multiple times without needing to specify all parameters each time.

html_mixin

define and use a mixin

This macro must also be applied to a proc that has no return value. Parsing it will not produce any nodes in the resulting AST; instead, it is parsed directly into the render proc at each place where it is called. There are two reasons for doing that: Firstly, it enables emerald to validate the HTML structure at each position where it is called. Secondly, the resulting HTML is properly indented everywhere.

Mixins can be called with the call_mixin command. The command takes the call to the mixin as first parameter; you have to give all parameters you defined for the mixin there. You can also give a block as second parameter, in which case this block can be called from within the mixin by calling mixin_content(). If you call mixin_content() in the mixin code, but do not supply a block as parameter in the template where you call the mixin, emerald will exit with an error message.

using the tag syntax

Tags

In an HTML template, every standalone call is interpreted as HTML tag. Standalone means that the call is not part of an expression, or in simpler terms: The call is written on its own line with nothing else there. You can of course condense multiple lines by using semicolons to make your code more compact. Standalone calls may, but do not need to, have a child block. The structure of the tags is validated according to the HTML 5 specification. Infix expressions are not considered to be calls; they will be parsed as text content generators (see below).

The content of a tag may also be given as direct content, meaning that it is written as parameter into the brackets of the tag, rather than into the child block. This may be convenient for tags that usually occur between character data, like e.g. <strong>.

If a tag name is also a keyword name in Nim, you have to put the tag name between accents, like this: `object`. As a special feature, you can write d for <div> tags, because they are pretty common and div is a keyword in Nim.

You can give tags classes by using the dot notation, as illustrated in the example. Tags can have any number of classes. The dot notation is somewhat limited, because you cannot use expressions for defining the class name, so you can also set the attribute class. You can use both dot notation and the class attribute on one tag.

The html tag is kind of a special feature. It automatically emits the HTML 5 doctype, gets a proper XML namespace definition, and its required attribute lang gets automatically copied into the attribute xml:lang, which is necessary for valid XHTML. That does not mean that you must start every template with an html tag - it is perfectly fine to write templates which only generate a part of an HTML DOM-tree. You would use such templates e.g. for AJAX-based websites.

set attribute values

Attributes

For each tag, attributes can be specified in the brackets of the tag call. The name of the attribute comes first, followed by an equals sign and the value of the attribute. The value may be any Nim expression. Attributes which are specified to be boolean, such as checked or readonly, must have an expression of Nim type bool as value. All other attribute values will be converted into strings.

Like tags, attributes are validated by emerald. A missing required attribute and an attribute that is not allowed for the tag that contains it both lead to an error message.

Attribute values are automatically filtered. Unlike the filtering of normal text, the filtering of attribute values cannot be customized, because there is no use-case for that (please file an issue if you can think of one). Filtering will convert the characters <, >, &, " and ' to their corresponding HTML entities.

Some HTML attributes contain a - in their name. This cannot be a part of a Nim identifier. Therefore, you must use a _ instead. So, for example, you have to write http_equiv instead of http-equiv. Also be aware that attribute names are case and style sensitive.

Data Attributes

HTML 5 allows any HTML tag to have an arbitrary number of data attributes, named like this: data-*emerald treats these values as a table, meaning that you can assign the data attribute a table constructor. This constructor must have string literals as keys, so that emerald can check the validity of the names at compile time - it doesn't make much sense to define the data attribute names with variables anyway. The value of each data attribute may be any expression. The example shows how to set data attributes.

creating text content

Text Content

Text content is generated by every expression that is used as a statement, excluding calls (which are used for creating HTML tags). The simplest way to generate text content is to use string literals. Infix expressions also generate text content, although they are technically calls. The operator $ is used to transform any value into a string for outputting it.

If you want to call a proc and output the result as text content, you have to use the command put, because normal calls are interpreted as HTML tags. If you just want to call a proc without using its return value - or a proc which does not have a return value at all - use discard.

All text content is processed by the current filter chain before being written to the output. By default, this converts the HTML characters <, > and & to their corresponding HTML entities. The filter chain can be customized to your needs, see the next section.

using control structures

Control structures

Most of Nim's control structures are directly usable in emerald: You can use if, case and while just like you would in Nim code. You can also declare and assign variables in your template. However, you cannot do everything in emerald you could do in Nim, and if you need to write logic that spans more than a few lines, it is probably a good idea to write it in a proper Nim proc and call that from within your template.

Pragmas

You can modify the way emerald compiles your template by using pragmas. Pragmas use the usual Nim syntax {. pragma here .}. emerald supports the following pragmas:

{. compact_mode = val .}
Toggles whether the generated HTML should be written in human-readable form with newlines and indentation, or as compact as possible without any unnecessary whitespace. val may be either true or false, default value is false.
{. indent_step = val .}
Sets the amount of spaces added to every new level of indentation. val may be any non-negative integer value. default is 4.
{. preserve_whitespace = val .}
Defines whether the lines of generated text content will be indented to the current output indentation, removing any existing indentation. val may be true or false, default is false. If true, the existing whitespace at the beginning of each line for text output will be preserved and no indentation will be applied ( regardless of the value of compact_mode. This is useful when inserting source code or anything similar in your HTML page.
{. debug = val .}
Enables or disables debugging output. If enabled, emerald will output the generated AST as Nim code to stdout. val may be true or false, default is false.
{. filters = filter_chain .}
This pragma manipulates the filter chain and is described in detail in the next section.

Apart from debug, all pragmas are applied to the current level of your template code, not globally. That means that the new pragma value you have set only affects the content of the current HTML tag and all tags within, but not the part of the template outside the current HTML tag.

modifying the filter chain

Filters

emerald maintains a filter chain while compiling your template. All text content is processed by the current filter chain. The filter chain may contain zero or more filters. A filter is a proc that takes a string as input and writes data to an output stream. By default, the filter chain contains one filter, escape_html, which converts HTML special characters to their corresponding entities.

You can modify the filter chain by using the pragma filters, which allows you to specify the filter chain as a list of filters separated by & operators. You may use the identifier filterswhen setting this chain to insert the previously active filters. You may use nil to specify that no filter at all should be used. The code example shows how to use the pragma.

Filters may take additional parameters. You can set them in brackets as seen in the example.

Builtin Filters

escape_html(escapeQuotes: bool = false)
Convert HTML special chars to their corresponding entities. if escapeQuotes is true, " and ' are escaped as well.
rst(options: TRstParseOptions = {}, config: StringTableRef = newStringTable())
Parses the input as RST, using Nim's internal RST implementation. Be aware that the resulting HTML is not validated by emerald.
pygmentize(language: string)
Uses pygments to add syntax highlighting to text output. Pygments must be available on your system in order to use this filter. You have to include a pygments css theme in order to actually see the syntax highlighting in the rendered output.
a simple filter

Writing Your Own Filters

Filters are simple procs. If you want to write your own filter, you just implement it as proc. It should look like this:

proc myFilter(target: Stream, value: string, ...)

At ..., you can add your own parameters. You need to give values for any non-optional parameters you add here when using the filter. The first two parameters are added by emerald when you use the filter in the filter chain.

When the filter gets called, you should process value and write the result to target. That's all.

inheriting from a template

Template Inheritance

You can inherit from templates by specifying the parent template when declaring the child template. This will make the generated object type of the child template inherit from the object type of the parent template.

In any template that inherits from another template, you cannot have HTML tags or text content nodes on the root level. However, you can assign values to the parent template's parameters. For adding content, you use the following commands:prepend, replace and append. Each of these takes one argument and must have a child block. The argument must be the name of a block in any parent template (does not need to be the immediate parent). prepend will add its content before the content of the block in the parent template, replace will completely replace the content of the block, and append will append its content to the block in the parent template.

Blocks must always have names in templates. You may still use them for scoping variables as you can do it in Nim, but be aware that each block will be compiled into a multimethod.

Fork me on GitHub