HTT Documentation

Quick Start

Hello World

HTT takes a single Lua script as its argument, from here you can generate as many files as you want by calling the render function.

Let's create a script, test-htt.lua:

local tpl = require("//helloworld.htt")

render(tpl.helloWorld, "result.txt")
Let's then fill out the template file, helloworld.htt:
% <helloWorld>
Hello, John!
% </helloWorld>
If you now run the command htt test-htt.lua, then the result.txt file will look like this:
Hello, John!

To Summarize

  1. We wrote a template file, helloworld.htt, and defined a component, helloWorld, inside it
  2. We wrote a Lua script, test-htt.lua, which uses the render call to render a component, helloWorld, to a file: result.txt.

Using Lua inside templates

HTT uses plain Lua for all logic inside of templates. Any line which starts with % is taken to be a line of Lua code injected verbatim into the compiled template.

Looping with Lua

We can use Lua for loops to repeat a block of output like so:

% for i = 1, 3 do
hello!
% end
hello!
            hello!
            hello!

Conditional rendering with Lua

We can use Lua if-statements to decide whether to render a block of output or not:

% if 1 == 2 then
Math is broken!
% else
Phew! Math works
% end
If we render this component, we get:
Phew! Math works

Using variables in output

You can use {{ ... }} to embed the values of variables or other expressions in the output:

% local name = "Peter"
Hello, {{name}}!
2 + 2 is {{2 + 2}}
Hello, Peter!
            2 + 2 is 4

In-lining blocks of Lua code

Generally, you should move larger pieces of logic (Lua code) out of your templates. However, it is possible to define blocks of code directly inside a component:

%%%
local names = {
  "john",
  "jane"
}
%%%
Hello {{names[1]}}, {{names[2]}}
Hello john, jane

Components

Template files can contain many components. A component is a small, reusable "mini-template", which can be called from other components and which, when called, can receive arguments, including other components.

Calling components from within components

To call a component, we use this syntax: {{@ component ctx }}. component is any component and ctx is the context we want to pass on to the component. The context should be a Lua table and it is the way to pass arguments to the component (including other components, if you want!).


Given this component:

% <child>
Sincerely hello
  - Child
% </child>

Let's call it from another component.

% <parent>
let's call the child:
{{@ child {} }}
% </parent>

The output becomes:

let's call the child:
            Sincerely hello
              - Child

Providing arguments to Components

When introducing the syntax to call a component, {{@ component ctx }}, we touched on the ctx being a Lua table.

We first define a component which uses the argument name, if provided. Note that all arguments passed to a component are exposed via the ctx variable. ctx.name is simply the Lua way of accessing the attribute name on the ctx table.

% <helloName>
Hello, {{ctx.name or "John Doe"}}!
% </helloName>

Calling component without name argument

Calling the component without no name:

{{@ helloName {} }}

Produces the following:

Hello, John Doe!

Calling component with name argument

Calling the component without no name:

{{@ helloName {name = "Peter"} }}

Produces the following:

Hello, Peter!

Indentation and Components

A focus of HTT has been to get indentation "right". Before we summarize how it works, here's an expanded example:
% <child>
Sincerely hello
  - Child
% </child>
% <middleChild>
--middle child
  {{@ child {} }}
% </middleChild>
% <callWithIndentation>
{{@ child {} }}
    {{@ middleChild {} }}
    {{@ child {} }}
% </callWithIndentation>

Rendering this out gives this output:

Sincerely hello
              - Child
                --middle child
                  Sincerely hello
                    - Child
                Sincerely hello
                  - Child

Nested Components

Components can be defined inside another component. This is useful whenever you write components which should not be used elsewhere. One example would be a site-generator, where we want to inject the page content into a full HTML5 page:

% <page>
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>{{ctx.title}}</title>
  </head>
  <body>
    {{@ ctx.body {} }}
  </body>
</html>
% </page>
% <page_hobbies>
% <content>
<p>Something I like to do</p>
% </content>
{{@ page {title = "my hobbies", body = content}}}
% </page_hobbies>

Notice how in page_hobbies, we define a nested component, content, which we pass along to the page component.

Line Continuations

There will be times, usually when mixing output and Lua lines, where you want to build up a single line of output across multiple lines in the template.

If a line starts with ~> (after whitespace), then the line is taken to be a continuation of the preceding line of output.

Simple Example

hello
~>world!
hello
~> world...

This renders out to:

helloworld!
            hello world...

Realistic Example

The following example builds up an array where elements are separated by , . Another example would be rendering function arguments or parameters.

% local sep = ctx.separator or ","
[
% for i, v in ipairs(ctx.lst) do
% local is_last = (i == #ctx.lst)
~> "{{v}}"{{not is_last and sep or ""}}
% end
~> ]

This renders out to:

[ "one", "two", "three" ]

The line printing the separator uses a trick in Lua to simulate a ternary-if:

$test and $if-truthy or $otherwise.
Alternatively, we could have used an if-block instead.