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")
Notice the call to require
. HTT templates are transparently
compiled to Lua as they are first imported. Read more about importing HTT templates here
helloworld.htt
:
% <helloWorld>
Hello, John!
% </helloWorld>
htt test-htt.lua
, then the result.txt
file will look like this:
Hello, John!
helloworld.htt
, and defined a component, helloWorld
, inside ittest-htt.lua
, which uses the render
call to render a component, helloWorld
, to a file: result.txt
.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.
Are all lines starting with '%' really a Lua line?
There are 2 exceptions:
%%%
-lines mark the start- and end of a block of Lua code% <foo>
and % </foo>
mark the start- and end of a component, named foo
in this example. See more information below.Other than that, any line starting with %
really is just a line of plain Lua code!
We can use Lua for loops to repeat a block of output like so:
% for i = 1, 3 do
hello!
% end
hello!
hello!
hello!
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
Phew! Math works
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
Arguments & components
See the the "Context" section under "Components" for information on how to pass arguments to a component and how to access them.
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
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.
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
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 the component without no name:
{{@ helloName {} }}
Produces the following:
Hello, John Doe!
Calling the component without no name:
{{@ helloName {name = "Peter"} }}
Produces the following:
Hello, Peter!
% <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
How indentation works
The final indentation of any given line is the sum of:
This sounds complex, but feels natural. Play around and you will see how indentation generally behaves as you would expect and want.
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.
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.
hello
~>world!
hello
~> world...
This renders out to:
helloworld!
hello world...
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
.