๐Ÿงฑ Tera Templates

Tera is a template engine for Rust, inspired by Jinja2 and Django templates. Dr. Jekyll includes a custom Rouge lexer that highlights Teraโ€™s expression blocks ({{ }}), statement tags ({% %}), and comment blocks ({# #}), while treating surrounding content as plain text.

Tera syntax is also highlighted automatically inside triple-quoted (""") values in Cliff TOML files.

Table of Contents
  1. How to Use
  2. Expression Blocks
  3. Statement Tags
    1. Conditionals
    2. Loops
    3. Variable Assignment
    4. Template Inheritance
  4. Comment Blocks
  5. Filters
  6. Macros
  7. Built-in Functions and Tests
  8. Full Example
  9. References

How to Use

Use the tera language tag on a fenced code block:

```tera
{{ page.title }}
```

Expression Blocks

Expression blocks evaluate a variable or expression and output the result. Use as delimiters; the whitespace-stripping variants trim surrounding whitespace:

```tera
{{ user.name }}
{{ version | trim_start_matches(pat="v") }}
{{- timestamp | date(format="%Y-%m-%d") -}}
{{ "<REMOTE_URL>/" ~ remote.github.owner ~ "/" ~ remote.github.repo -}}
```

{{ user.name }}
{{ version | trim_start_matches(pat="v") }}
{{- timestamp | date(format="%Y-%m-%d") -}}
{{ "<REMOTE_URL>/" ~ remote.github.owner ~ "/" ~ remote.github.repo -}}

The ~ operator concatenates strings.


Statement Tags

Statement tags control template logic. Use {% and %} as delimiters:

Conditionals

```tera
{% if user.is_admin %}
  <p>Welcome, admin.</p>
{% elif user.is_logged_in %}
  <p>Welcome, {{ user.name }}.</p>
{% else %}
  <p>Please log in.</p>
{% endif %}
```

{% if user.is_admin %}
  <p>Welcome, admin.</p>
{% elif user.is_logged_in %}
  <p>Welcome, {{ user.name }}.</p>
{% else %}
  <p>Please log in.</p>
{% endif %}

Loops

```tera
{% for commit in commits %}
- {{ commit.message | upper_first }}
{% endfor %}
```

{% for commit in commits %}
- {{ commit.message | upper_first }}
{% endfor %}

Variable Assignment

```tera
{% set greeting = "Hello, " ~ user.name ~ "!" %}
{{ greeting }}

{% set_global counter = 0 %}
```

{% set greeting = "Hello, " ~ user.name ~ "!" %}
{{ greeting }}

{% set_global counter = 0 %}

Template Inheritance

```tera
{% extends "base.html" %}

{% block content %}
  <h1>{{ page.title }}</h1>
  {{ super() }}
{% endblock content %}
```

{% extends "base.html" %}

{% block content %}
  <h1>{{ page.title }}</h1>
  {{ super() }}
{% endblock content %}


Comment Blocks

Comment blocks are not rendered in the output. Use {# and #} as delimiters:

```tera
{# This is a comment and will not appear in the rendered output #}
{#- Whitespace-stripping comment -#}
```

{# This is a comment and will not appear in the rendered output #}
{#- Whitespace-stripping comment -#}


Filters

Filters transform a value using the pipe | operator. Chaining is supported:

```tera
{{ commits | group_by(attribute="group") }}
{{ message | striptags | trim | upper_first }}
{{ body | truncate(length=200) }}
{{ items | sort | first }}
{{ count | round(method="ceil", precision=2) }}
{{ r.contributors | filter(attribute="is_first_time", value=true) }}
{{ input | trim_start_matches(pat='"') | trim_end_matches(pat='"') }}
```

{{ commits | group_by(attribute="group") }}
{{ message | striptags | trim | upper_first }}
{{ body | truncate(length=200) }}
{{ items | sort | first }}
{{ count | round(method="ceil", precision=2) }}
{{ r.contributors | filter(attribute="is_first_time", value=true) }}
{{ input | trim_start_matches(pat='"') | trim_end_matches(pat='"') }}

filter is also a block-level statement tag ({% filter lower %}...{% endfilter %}). When used after a pipe | it acts as a collection filter; the lexer highlights it as a control keyword in both cases.


Macros

Macros are reusable template fragments. self::macro_name() calls a macro defined in the same template:

```tera
{%- macro user_url(name) -%}
  [@{{ name | lower }}](https://github.com/{{ name | lower }})
{%- endmacro -%}

{%- macro plural(count, singular, plural) -%}
  {%- if count == 1 -%}{{ singular }}{%- else -%}{{ plural }}{%- endif -%}
{%- endmacro -%}

{{ self::user_url(name=commit.remote.username) }}
{{ self::plural(count=s_commit_count, singular="commit", plural="commits") }}
```

{%- macro user_url(name) -%}
  [@{{ name | lower }}](https://github.com/{{ name | lower }})
{%- endmacro -%}

{%- macro plural(count, singular, plural) -%}
  {%- if count == 1 -%}{{ singular }}{%- else -%}{{ plural }}{%- endif -%}
{%- endmacro -%}

{{ self::user_url(name=commit.remote.username) }}
{{ self::plural(count=s_commit_count, singular="commit", plural="commits") }}


Built-in Functions and Tests

```tera
{% set nums = range(end=5) %}
{% set ts = now(timestamp=true) %}

{% if value is defined %}{{ value }}{% endif %}
{% if count is odd %}odd{% endif %}
{% if name is starting_with("v") %}versioned{% endif %}
```

{% set nums = range(end=5) %}
{% set ts = now(timestamp=true) %}

{% if value is defined %}{{ value }}{% endif %}
{% if count is odd %}odd{% endif %}
{% if name is starting_with("v") %}versioned{% endif %}


Full Example

```tera
{# Changelog body template for git-cliff #}
{% if version %}
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
{% else %}
## [unreleased]
{% endif %}

{% for group, commits in commits | group_by(attribute="group") %}
### {{ group | striptags | trim | upper_first }}

{% for commit in commits %}
- {% if commit.scope %}*({{ commit.scope }})* {% endif %}\
  {% if commit.breaking %}[**breaking**] {% endif %}\
  {{ commit.message | upper_first }} โ€” \
  [{{ commit.id | truncate(length=7, end="") }}]({{ commit.remote.link }})
{% endfor %}
{% endfor %}
```

{# Changelog body template for git-cliff #}
{% if version %}
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
{% else %}
## [unreleased]
{% endif %}

{% for group, commits in commits | group_by(attribute="group") %}
### {{ group | striptags | trim | upper_first }}

{% for commit in commits %}
- {% if commit.scope %}*({{ commit.scope }})* {% endif %}\
  {% if commit.breaking %}[**breaking**] {% endif %}\
  {{ commit.message | upper_first }} โ€” \
  [{{ commit.id | truncate(length=7, end="") }}]({{ commit.remote.link }})
{% endfor %}
{% endfor %}


References