minijinja/syntax.rs
1#![cfg_attr(
2 feature = "custom_syntax",
3 doc = "Documents the syntax for templates and provides ways to reconfigure it."
4)]
5#![cfg_attr(
6 not(feature = "custom_syntax"),
7 doc = "Documents the syntax for templates."
8)]
9//!
10//! <details><summary><strong style="cursor: pointer">Table of Contents</strong></summary>
11//!
12//! - [Synopsis](#synopsis)
13//! - [Trailing Newlines](#trailing-newlines)
14//! - [Expressions](#expressions)
15//! - [Literals](#literals)
16//! - [Math](#math)
17//! - [Comparisons](#comparisons)
18//! - [Logic](#logic)
19//! - [Other Operators](#other-operators)
20//! - [If Expressions](#if-expressions)
21//! - [Tags](#tags)
22//! - [`{% for %}`](#-for-)
23//! - [`{% if %}`](#-if-)
24//! - [`{% extends %}`](#-extends-)
25//! - [`{% block %}`](#-block-)
26//! - [`{% include %}`](#-include-)
27//! - [`{% import %}`](#-import-)
28//! - [`{% with %}`](#-with-)
29//! - [`{% set %}`](#-set-)
30//! - [`{% filter %}`](#-filter-)
31//! - [`{% macro %}`](#-macro-)
32//! - [`{% call %}`](#-call-)
33//! - [`{% do %}`](#-do-)
34//! - [`{% autoescape %}`](#-autoescape-)
35//! - [`{% raw %}`](#-raw-)
36//! - [`{% break %} / {% continue %}`](#-break----continue-)
37#"
40)]
41//! - [Whitespace Control](#whitespace-control)
42//!
43//! </details>
44//!
45//! # Synopsis
46//!
47//! A MiniJinja template is simply a text file. MiniJinja can generate any text-based
48//! format (HTML, XML, CSV, LaTeX, etc.). A template doesn’t need to have a specific extension
49//! and in fact MiniJinja does not understand much about the file system. However the default
50//! configuration for [auto escaping](crate::Environment::set_auto_escape_callback) uses file
51//! extensions to configure the initial behavior.
52//!
53//! A template contains [**expressions**](#expressions), which get replaced with values when a
54//! template is rendered; and [**tags**](#tags), which control the logic of the template. The
55//! template syntax is heavily inspired by Jinja2, Django and Python.
56//!
57//! This is a minimal template that illustrates a few basics:
58//!
59//! ```jinja
60//! <!doctype html>
61//! <title>{% block title %}My Website{% endblock %}</title>
62//! <ul id="navigation">
63//! {% for item in navigation %}
64//! <li><a href="{{ item.href }}">{{ item.caption }}</a></li>
65//! {% endfor %}
66//! </ul>
67//!
68//! <h1>My Webpage</h1>
69//! {% block body %}{% endblock %}
70//!
71//! {# a comment #}
72//! ```
73//!
74//! # Trailing Newlines
75//!
76//! MiniJinja, like Jinja2, will remove one trailing newline from the end of the file automatically
77//! on parsing. This lets templates produce a consistent output no matter if the editor adds a
78//! trailing newline or not. If one wants a trailing newline an extra newline can be added or the
79//! code rendering it adds it manually.
80//!
81//! # Expressions
82//!
83//! MiniJinja allows basic expressions everywhere. These work largely as you expect from Jinja2.
84//! Even if you have not used Jinja2 you should feel comfortable with it. To output the result
85//! of an expression wrap it in `{{ .. }}`.
86//!
87//! ## Literals
88//!
89//! The simplest form of expressions are literals. Literals are representations for
90//! objects such as strings and numbers. The following literals exist:
91//!
92//! - `"Hello World"`: Everything between two double or single quotes is a string. They are
93//! useful whenever you need a string in the template (e.g. as arguments to function calls
94//! and filters, or just to extend or include a template).
95//! - `42`: Integers are whole numbers without a decimal part. They can be prefixed with
96//! `0b` to indicate binary, `0o` to indicate octal and `0x` to indicate hexadecimal.
97//! Underscores are tolerated (and ignored) everywhere a digit is except in the last place.
98//! - `42.0`: Floating point numbers can be written using a `.` as a decimal mark.
99//! Underscores are tolerated (and ignored) everywhere a digit is except in the last place.
100//! - `['list', 'of', 'objects']`: Everything between two brackets is a list. Lists are useful
101//! for storing sequential data to be iterated over.
102//! for compatibility with Jinja2 `('list', 'of', 'objects')` is also allowed.
103//! - `{'map': 'of', 'key': 'and', 'value': 'pairs'}`: A map is a structure that combines keys
104//! and values. Keys must be unique and always have exactly one value. Maps are rarely
105//! created in templates.
106//! - `true` / `false` / `none`: boolean values and the special `none` value which maps to the
107//! unit type in Rust.
108//!
109//! ## Math
110//!
111//! MiniJinja allows you to calculate with values. The following operators are supported:
112//!
113//! - ``+``: Adds two numbers up. ``{{ 1 + 1 }}`` is ``2``.
114//! - ``-``: Subtract the second number from the first one. ``{{ 3 - 2 }}`` is ``1``.
115//! - ``/``: Divide two numbers. ``{{ 1 / 2 }}`` is ``0.5``. See note on divisions below.
116//! - ``//``: Integer divide two numbers. ``{{ 5 // 3 }}`` is ``1``. See note on divisions below.
117//! - ``%``: Calculate the remainder of an integer division. ``{{ 11 % 7 }}`` is ``4``.
118//! - ``*``: Multiply the left operand with the right one. ``{{ 2 * 2 }}`` would return ``4``.
119//! - ``**``: Raise the left operand to the power of the right operand. ``{{ 2**3 }}``
120//! would return ``8``.
121//!
122//! Note on divisions: divisions in Jinja2 are flooring, divisions in MiniJinja
123//! are at present using euclidean division. They are almost the same but not quite.
124//!
125//! ## Comparisons
126//!
127//! - ``==``: Compares two objects for equality.
128//! - ``!=``: Compares two objects for inequality.
129//! - ``>``: ``true`` if the left hand side is greater than the right hand side.
130//! - ``>=``: ``true`` if the left hand side is greater or equal to the right hand side.
131//! - ``<``:``true`` if the left hand side is less than the right hand side.
132//! - ``<=``: ``true`` if the left hand side is less or equal to the right hand side.
133//!
134//! ## Logic
135//!
136//! For ``if`` statements it can be useful to combine multiple expressions:
137//!
138//! - ``and``: Return true if the left and the right operand are true.
139//! - ``or``: Return true if the left or the right operand are true.
140//! - ``not``: negate a statement (see below).
141//! - ``(expr)``: Parentheses group an expression.
142//!
143//! ## Other Operators
144//!
145//! The following operators are very useful but don't fit into any of the other
146//! two categories:
147//!
148//! - ``is``/``is not``: Performs a [test](crate::tests).
149//! - ``in``/``not in``: Performs a containment check.
150//! - ``|`` (pipe, vertical bar): Applies a [filter](crate::filters).
151//! - ``~`` (tilde): Converts all operands into strings and concatenates them.
152//! ``{{ "Hello " ~ name ~ "!" }}`` would return (assuming `name` is set
153//! to ``'John'``) ``Hello John!``.
154//! - ``()``: Call a callable: ``{{ super() }}``. Inside of the parentheses you
155//! can use positional arguments. Additionally keyword arguments are supported
156//! which are treated like a dict syntax. Eg: `foo(a=1, b=2)` is the same as
157//! `foo({"a": 1, "b": 2})`.
158//! - ``.`` / ``[]``: Get an attribute of an object. If an object does not have a specific
159//! attribute or item then `undefined` is returned. Accessing a property of an already
160//! undefined value will result in an error.
161//! - ``[start:stop]`` / ``[start:stop:step]``: slices a list or string. All three expressions
162//! are optional (`start`, `stop`, `step`). For instance ``"Hello World"[:5]`` will return
163//! just `"Hello"`. Likewise ``"Hello"[1:-1]`` will return `"ell"`. The step component can
164//! be used to change the step size. `"12345"[::2]` will return `"135"`.
165//!
166//! ### If Expressions
167//!
168//! It is also possible to use inline _if_ expressions. These are useful in some situations.
169//! For example, you can use this to extend from one template if a variable is defined,
170//! otherwise from the default layout template:
171//!
172//! ```jinja
173//! {% extends layout_template if layout_template is defined else 'default.html' %}
174//! ```
175//!
176//! The `else` part is optional. If not provided, the else block implicitly evaluates
177//! into an undefined value:
178//!
179//! ```jinja
180//! {{ title|upper if title }}
181//! ```
182//!
183//! Note that for compatibility with Jinja2, when the `else` block is missing the undefined
184//! value will be marked as "silent". This means even if strict undefined behavior is
185//! requested, this undefined value will print to an empty string. This means
186//! that this is always valid:
187//!
188//! ```jinja
189//! {{ value if false }} -> prints an empty string (silent undefined returned from else)
190//! ```
191//!
192//! # Tags
193//!
194//! Tags control logic in templates. The following tags exist:
195//!
196//! ## `{% for %}`
197//!
198//! The for tag loops over each item in a sequence. For example, to display a list
199//! of users provided in a variable called `users`:
200//!
201//! ```jinja
202//! <h1>Members</h1>
203//! <ul>
204//! {% for user in users %}
205//! <li>{{ user.username }}</li>
206//! {% endfor %}
207//! </ul>
208//! ```
209//!
210//! It's also possible to unpack tuples while iterating:
211//!
212//! ```jinja
213//! <h1>Members</h1>
214//! <ul>
215//! {% for (key, value) in list_of_pairs %}
216//! <li>{{ key }}: {{ value }}</li>
217//! {% endfor %}
218//! </ul>
219//! ```
220//!
221//! Inside of the for block you can access some special variables:
222//!
223//! - `loop.index`: The current iteration of the loop. (1 indexed)
224//! - `loop.index0`: The current iteration of the loop. (0 indexed)
225//! - `loop.revindex`: The number of iterations from the end of the loop (1 indexed)
226//! - `loop.revindex0`: The number of iterations from the end of the loop (0 indexed)
227//! - `loop.first`: True if this is the first iteration.
228//! - `loop.last`: True if this is the last iteration.
229//! - `loop.length`: The number of items in the sequence.
230//! - `loop.cycle`: A helper function to cycle between a list of sequences. See the explanation below.
231//! - `loop.depth`: Indicates how deep in a recursive loop the rendering currently is. Starts at level 1
232//! - `loop.depth0`: Indicates how deep in a recursive loop the rendering currently is. Starts at level 0
233//! - `loop.previtem`: The item from the previous iteration of the loop. `Undefined` during the first iteration.
234//! - `loop.nextitem`: The item from the previous iteration of the loop. `Undefined` during the last iteration.
235//! - `loop.changed(...args)`: Returns true if the passed values have changed since the last time it was called with the same arguments.
236//! - `loop.cycle(...args)`: Returns a value from the passed sequence in a cycle.
237//!
238//! A special note on iterators: in the current version of MiniJinja, some sequences are actually
239//! lazy iterators. They behave a bit like sequences not not entirely. They can be iterated over,
240//! will happily serialize once into a a list etc. However when iterating over an actual iterator,
241//! `last`, `revindex` and `revindex0` will always be undefined.
242//!
243//! Within a for-loop, it’s possible to cycle among a list of strings/variables each time through
244//! the loop by using the special `loop.cycle` helper:
245//!
246//! ```jinja
247//! {% for row in rows %}
248//! <li class="{{ loop.cycle('odd', 'even') }}">{{ row }}</li>
249//! {% endfor %}
250//! ```
251//!
252//! A `loop.changed()` helper is also available which can be used to detect when
253//! a value changes between the last iteration and the current one. The method
254//! takes one or more arguments that are all compared.
255//!
256//! ```jinja
257//! {% for entry in entries %}
258//! {% if loop.changed(entry.category) %}
259//! <h2>{{ entry.category }}</h2>
260//! {% endif %}
261//! <p>{{ entry.message }}</p>
262//! {% endfor %}
263//! ```
264//!
265//! Unlike in Rust or Python, it’s not possible to break or continue in a loop. You can,
266//! however, filter the sequence during iteration, which allows you to skip items. The
267//! following example skips all the users which are hidden:
268//!
269//! ```jinja
270//! {% for user in users if not user.hidden %}
271//! <li>{{ user.username }}</li>
272//! {% endfor %}
273//! ```
274//!
275//! If no iteration took place because the sequence was empty or the filtering
276//! removed all the items from the sequence, you can render a default block by
277//! using else:
278//!
279//! ```jinja
280//! <ul>
281//! {% for user in users %}
282//! <li>{{ user.username }}</li>
283//! {% else %}
284//! <li><em>no users found</em></li>
285//! {% endfor %}
286//! </ul>
287//! ```
288//!
289//! It is also possible to use loops recursively. This is useful if you are
290//! dealing with recursive data such as sitemaps. To use loops recursively, you
291//! basically have to add the ``recursive`` modifier to the loop definition and
292//! call the loop variable with the new iterable where you want to recurse.
293//!
294//! ```jinja
295//! <ul class="menu">
296//! {% for item in menu recursive %}
297//! <li><a href="{{ item.href }}">{{ item.title }}</a>
298//! {% if item.children %}
299//! <ul class="submenu">{{ loop(item.children) }}</ul>
300//! {% endif %}</li>
301//! {% endfor %}
302//! </ul>
303//! ```
304//!
305//! **Special note:** the `previtem` and `nextitem` attributes are available by default
306//! but can be disabled by removing the `adjacent_loop_items` crate feature. Removing
307//! these attributes can provide meaningful speedups for templates with a lot of loops.
308//!
309//! ## `{% if %}`
310//!
311//! The `if` statement is comparable with the Python if statement. In the simplest form,
312//! you can use it to test if a variable is defined, not empty and not false:
313//!
314//! ```jinja
315//! {% if users %}
316//! <ul>
317//! {% for user in users %}
318//! <li>{{ user.username }}</li>
319//! {% endfor %}
320//! </ul>
321//! {% endif %}
322//! ```
323//!
324//! For multiple branches, `elif` and `else` can be used like in Python. You can use more
325//! complex expressions there too:
326//!
327//! ```jinja
328//! {% if kenny.sick %}
329//! Kenny is sick.
330//! {% elif kenny.dead %}
331//! You killed Kenny! You bastard!!!
332//! {% else %}
333//! Kenny looks okay --- so far
334//! {% endif %}
335//! ```
336//!
337//! ## `{% extends %}`
338//!
339//! **Feature:** `multi_template` (included by default)
340//!
341//! The `extends` tag can be used to extend one template from another. You can have multiple
342//! `extends` tags in a file, but only one of them may be executed at a time. For more
343//! information see [block](#-block-).
344//!
345//! ## `{% block %}`
346//!
347//! Blocks are used for inheritance and act as both placeholders and replacements at the
348//! same time:
349//!
350//! The most powerful part of MiniJinja is template inheritance. Template inheritance allows
351//! you to build a base "skeleton" template that contains all the common elements of your
352//! site and defines **blocks** that child templates can override.
353//!
354//! **Base Template:**
355//!
356//! This template, which we'll call ``base.html``, defines a simple HTML skeleton
357//! document that you might use for a simple two-column page. It's the job of
358//! "child" templates to fill the empty blocks with content:
359//!
360//! ```jinja
361//! <!doctype html>
362//! {% block head %}
363//! <title>{% block title %}{% endblock %}</title>
364//! {% endblock %}
365//! {% block body %}{% endblock %}
366//! ```
367//!
368//! **Child Template:**
369//!
370//! ```jinja
371//! {% extends "base.html" %}
372//! {% block title %}Index{% endblock %}
373//! {% block head %}
374//! {{ super() }}
375//! <style type="text/css">
376//! .important { color: #336699; }
377//! </style>
378//! {% endblock %}
379//! {% block body %}
380//! <h1>Index</h1>
381//! <p class="important">
382//! Welcome to my awesome homepage.
383//! </p>
384//! {% endblock %}
385//! ```
386//!
387//! The ``{% extends %}`` tag is the key here. It tells the template engine that
388//! this template "extends" another template. When the template system evaluates
389//! this template, it first locates the parent. The extends tag should be the
390//! first tag in the template.
391//!
392//! As you can see it's also possible to render the contents of the parent block by calling
393//! ``super()``. You can’t define multiple ``{% block %}`` tags with the same name in
394//! the same template. This limitation exists because a block tag works in “both”
395//! directions. That is, a block tag doesn’t just provide a placeholder to fill -
396//! it also defines the content that fills the placeholder in the parent. If
397//! there were two similarly-named ``{% block %}`` tags in a template, that
398//! template’s parent wouldn’t know which one of the blocks’ content to use.
399//!
400//! If you want to print a block multiple times, you can, however, use the
401//! special self variable and call the block with that name:
402//!
403//! ```jinja
404//! <title>{% block title %}{% endblock %}</title>
405//! <h1>{{ self.title() }}</h1>
406//! {% block body %}{% endblock %}
407//! ```
408//!
409//! MiniJinja allows you to put the name of the block after the end tag for better
410//! readability:
411//!
412//! ```jinja
413//! {% block sidebar %}
414//! {% block inner_sidebar %}
415//! ...
416//! {% endblock inner_sidebar %}
417//! {% endblock sidebar %}
418//! ```
419//!
420//! However, the name after the `endblock` word must match the block name.
421//!
422//! ## `{% include %}`
423//!
424//! **Feature:** `multi_template` (included by default)
425//!
426//! The `include` tag is useful to include a template and return the rendered contents of that file
427//! into the current namespace:
428//!
429//! ```jinja
430//! {% include 'header.html' %}
431//! Body
432//! {% include 'footer.html' %}
433//! ```
434//!
435//! Optionally `ignore missing` can be added in which case non existing templates
436//! are silently ignored.
437//!
438//! ```jinja
439//! {% include 'customization.html' ignore missing %}
440//! ```
441//!
442//! You can also provide a list of templates that are checked for existence
443//! before inclusion. The first template that exists will be included. If `ignore
444//! missing` is set, it will fall back to rendering nothing if none of the
445//! templates exist, otherwise it will fail with an error.
446//!
447//! ```jinja
448//! {% include ['page_detailed.html', 'page.html'] %}
449//! {% include ['special_sidebar.html', 'sidebar.html'] ignore missing %}
450//! ```
451//!
452//! Included templates have access to the variables of the active context.
453//!
454//! ## `{% import %}`
455//!
456//! **Feature:** `multi_template` (included by default)
457//!
458//! MiniJinja supports the `{% import %}` and `{% from ... import ... %}`
459//! syntax. With it variables or macros can be included from other templates:
460//!
461//! ```jinja
462//! {% from "my_template.html" import my_macro, my_variable %}
463//! ```
464//!
465//! Imports can also be aliased:
466//!
467//! ```jinja
468//! {% from "my_template.html" import my_macro as other_name %}
469//! {{ other_name() }}
470//! ```
471//!
472//! Full modules can be imported with `{% import ... as ... %}`:
473//!
474//! ```jinja
475//! {% import "my_template.html" as helpers %}
476//! {{ helpers.my_macro() }}
477//! ```
478//!
479//! Note that unlike Jinja2, exported modules do not contain any template code. Only
480//! variables and macros that are defined can be imported. Also imports unlike in Jinja2
481//! are not cached and they get access to the full template context.
482//!
483//! ## `{% with %}`
484//!
485//! The with statement makes it possible to create a new inner scope. Variables set within
486//! this scope are not visible outside of the scope:
487//!
488//! ```jinja
489//! {% with foo = 42 %}
490//! {{ foo }} foo is 42 here
491//! {% endwith %}
492//! foo is not visible here any longer
493//! ```
494//!
495//! Multiple variables can be set at once and unpacking is supported:
496//!
497//! ```jinja
498//! {% with a = 1, (b, c) = [2, 3] %}
499//! {{ a }}, {{ b }}, {{ c }} (outputs 1, 2, 3)
500//! {% endwith %}
501//! ```
502//!
503//! ## `{% set %}`
504//!
505//! The `set` statement can be used to assign to variables on the same scope. This is
506//! similar to how `with` works but it won't introduce a new scope.
507//!
508//! ```jinja
509//! {% set navigation = [('index.html', 'Index'), ('about.html', 'About')] %}
510//! ```
511//!
512//! Please keep in mind that it is not possible to set variables inside a block
513//! and have them show up outside of it. This also applies to loops. The only
514//! exception to that rule are if statements which do not introduce a scope.
515//!
516//! It's also possible to capture blocks of template code into a variable by using
517//! the `set` statement as a block. In that case, instead of using an equals sign
518//! and a value, you just write the variable name and then everything until
519//! `{% endset %}` is captured.
520//!
521//! ```jinja
522//! {% set navigation %}
523//! <li><a href="/">Index</a>
524//! <li><a href="/downloads">Downloads</a>
525//! {% endset %}
526//! ```
527//!
528//! The `navigation` variable then contains the navigation HTML source.
529//!
530//! This can also be combined with applying a filter:
531//!
532//! ```jinja
533//! {% set title | upper %}Title of the page{% endset %}
534//! ```
535//!
536//! More complex use cases can be handled using namespace objects which allow
537//! propagating of changes across scopes:
538//!
539//! ```jinja
540//! {% set ns = namespace(found=false) %}
541//! {% for item in items %}
542//! {% if item.check_something() %}
543//! {% set ns.found = true %}
544//! {% endif %}
545//! * {{ item.title }}
546//! {% endfor %}
547//! Found item having something: {{ ns.found }}
548//! ```
549//!
550//! Note that the `obj.attr` notation in the set tag is only allowed for namespace
551//! objects; attempting to assign an attribute on any other object will cause
552//! an error.
553//!
554//! ## `{% filter %}`
555//!
556//! Filter sections allow you to apply regular [filters](crate::filters) on a
557//! block of template data. Just wrap the code in the special filter block:
558//!
559//! ```jinja
560//! {% filter upper %}
561//! This text becomes uppercase
562//! {% endfilter %}
563//! ```
564//!
565//! ## `{% macro %}`
566//!
567//! **Feature:** `macros` (included by default)
568//!
569//! MiniJinja has limited support for macros. They allow you to write reusable
570//! template functions. They are useful to put often used idioms into reusable
571//! functions so you don't repeat yourself (“DRY”).
572//!
573//! Here’s a small example of a macro that renders a form element:
574//!
575//! ```jinja
576//! {% macro input(name, value="", type="text") -%}
577//! <input type="{{ type }}" name="{{ name }}" value="{{ value }}">
578//! {%- endmacro %}
579//! ```
580//!
581//! The macro can then be called like a function in the namespace:
582//!
583//! ```jinja
584//! <p>{{ input('username') }}</p>
585//! <p>{{ input('password', type='password') }}</p>
586//! ```
587//!
588//! The behavior of macros with regards to undefined variables is that they capture
589//! them at macro declaration time (eg: they use a closure).
590//!
591//! Macros can be imported via `{% import %}` or `{% from ... import %}`.
592//!
593//! Macros also accept a hidden `caller` keyword argument for the use with
594//! `{% call %}`.
595//!
596//! ## `{% call %}`
597//!
598//! **Feature:** `macros` (included by default)
599//!
600//! This tag functions similar to a macro that is passed to another macro. You can
601//! think of it as a way to declare an anonymous macro and pass it to another macro
602//! with the `caller` keyword argument. The following example shows a macro that
603//! takes advantage of the call functionality and how it can be used:
604//!
605//! ```jinja
606//! {% macro dialog(title) %}
607//! <div class="dialog">
608//! <h3>{{ title }}</h3>
609//! <div class="contents">{{ caller() }}</div>
610//! </div>
611//! {% endmacro %}
612//!
613//! {% call dialog(title="Hello World") %}
614//! This is the dialog body.
615//! {% endcall %}
616//! ```
617//!
618//! <details><summary><strong style="cursor: pointer">Macro Alternative:</strong></summary>
619//!
620//! The above example is more or less equivalent with the following:
621//!
622//! ```jinja
623//! {% macro dialog(title) %}
624//! <div class="dialog">
625//! <h3>{{ title }}</h3>
626//! <div class="contents">{{ caller() }}</div>
627//! </div>
628//! {% endmacro %}
629//!
630//! {% macro caller() %}
631//! This is the dialog body.
632//! {% endmacro %}
633//! {{ dialog(title="Hello World", caller=caller) }}
634//! ```
635//!
636//! </details>
637//!
638//! It’s also possible to pass arguments back to the call block. This makes it
639//! useful to build macros that behave like if statements or loops. Arguments
640//! are placed surrounded in parentheses right after the `call` keyword and
641//! is followed by the macro to be called.
642//!
643//! ```jinja
644//! {% macro render_user_list(users) %}
645//! <ul>
646//! {% for user in users %}
647//! <li><p>{{ user.username }}</p>{{ caller(user) }}</li>
648//! {% endfor %}
649//! </ul>
650//! {% endmacro %}
651//!
652//! {% call(user) render_user_list(list_of_user) %}
653//! <dl>
654//! <dt>Name</dt>
655//! <dd>{{ user.name }}</dd>
656//! <dt>E-Mail</dt>
657//! <dd>{{ user.email }}</dd>
658//! </dl>
659//! {% endcall %}
660//! ```
661//!
662//! ## `{% do %}`
663//!
664//! The do tag has the same functionality as regular template tags (`{{ ... }}`);
665//! except it doesn't output anything when called.
666//!
667//! This is useful if you have a function or macro that has a side-effect, and
668//! you don’t want to display output in the template. The following example
669//! shows a macro that uses the do functionality, and how it can be used:
670//!
671//! ```jinja
672//! {% macro dialog(title) %}
673//! Dialog is {{ title }}
674//! {% endmacro %}
675//!
676//! {% do dialog(title="Hello World") %} <- does not output anything
677//! ```
678//!
679//! The above example will not output anything when using the `do` tag.
680//!
681//! This tag exists for consistency with Jinja2 and can be useful if you have
682//! custom functionality in templates that uses side-effects. For instance if
683//! you expose a function to templates that can be used to log warnings:
684//!
685//! ```jinja
686//! {% for user in users %}
687//! {% if user.deleted %}
688//! {% log warn("Found unexpected deleted user in template") %}
689//! {% endif %}
690//! ...
691//! {% endfor %}
692//! ```
693//!
694//! ## `{% autoescape %}`
695//!
696//! If you want you can activate and deactivate the autoescaping from within
697//! the templates.
698//!
699//! Example:
700//!
701//! ```jinja
702//! {% autoescape true %}
703//! Autoescaping is active within this block
704//! {% endautoescape %}
705//!
706//! {% autoescape false %}
707//! Autoescaping is inactive within this block
708//! {% endautoescape %}
709//! ```
710//!
711//! After an `endautoescape` the behavior is reverted to what it was before.
712//!
713//! The exact auto escaping behavior is determined by the value of
714//! [`AutoEscape`](crate::AutoEscape) set to the template.
715//!
716//! ## `{% raw %}`
717//!
718//! A raw block is a special construct that lets you ignore the embedded template
719//! syntax. This is particularly useful if a segment of template code would
720//! otherwise require constant escaping with things like `{{ "{{" }}`:
721//!
722//! Example:
723//!
724//! ```jinja
725//! {% raw %}
726//! <ul>
727//! {% for item in seq %}
728//! <li>{{ item }}</li>
729//! {% endfor %}
730//! </ul>
731//! {% endraw %}
732//! ```
733//!
734//! ## `{% break %}` / `{% continue %}`
735//!
736//! If MiniJinja was compiled with the `loop_controls` feature, it’s possible to
737//! use `break`` and `continue`` in loops. When break is reached, the loop is
738//! terminated; if continue is reached, the processing is stopped and continues
739//! with the next iteration.
740//!
741//! Here’s a loop that skips every second item:
742//!
743//! ```jinja
744//! {% for user in users %}
745//! {%- if loop.index is even %}{% continue %}{% endif %}
746//! ...
747//! {% endfor %}
748//! ```
749//!
750//! Likewise, a loop that stops processing after the 10th iteration:
751//!
752//! ```jinja
753//! {% for user in users %}
754//! {%- if loop.index >= 10 %}{% break %}{% endif %}
755//! {%- endfor %}
756//! ```
757//!
758//! **Note on one-shot iterators:** if you break from a loop but you have
759//! accessed the `loop.nextitem` special variable, then you will lose one item.
760//! This is because accessing that attribute will peak into the iterator and
761//! there is no support for "putting values back".
762//!
763#![cfg_attr(
764 feature = "custom_syntax",
765 doc = r###"
766# Custom Delimiters
767
768When MiniJinja has been compiled with the `custom_syntax` feature (see
769[`SyntaxConfig`]), it's possible to reconfigure the delimiters of the
770templates. This is generally not recommended but it's useful for situations
771where Jinja templates are used to generate files with a syntax that would be
772conflicting for Jinja. With custom delimiters it can for instance be more
773convenient to generate LaTeX files:
774
775```
776# use minijinja::{Environment, syntax::SyntaxConfig};
777let mut environment = Environment::new();
778environment.set_syntax(SyntaxConfig::builder()
779 .block_delimiters("\\BLOCK{", "}")
780 .variable_delimiters("\\VAR{", "}")
781 .comment_delimiters("\\#{", "}")
782 .build()
783 .unwrap()
784);
785```
786
787And then a template might look like this instead:
788
789```latex
790\begin{itemize}
791\BLOCK{for item in sequence}
792 \item \VAR{item}
793\BLOCK{endfor}
794\end{itemize}
795```
796
797# Line Statements and Comments
798
799MiniJinja supports line statements and comments like Jinja2 does. Line statements
800and comments are an alternative syntax feature where blocks can be placed on their
801own line if they are opened with a configured prefix. They must appear on their own
802line but can be prefixed with whitespace. Line comments are similar but they can
803also be trailing. These syntax features need to be configured explicitly.
804There are however small differences with regards to whitespace compared to
805Jinja2.
806
807To use line statements and comments the `custom_syntax` feature needs to be
808enabled and they need to be configured (see [`SyntaxConfig`]).
809
810```
811# use minijinja::{Environment, syntax::SyntaxConfig};
812let mut environment = Environment::new();
813environment.set_syntax(SyntaxConfig::builder()
814 .line_statement_prefix("#")
815 .line_comment_prefix("##")
816 .build()
817 .unwrap()
818);
819```
820
821With the above config you can render a template like this:
822
823```jinja
824## This block is
825## completely removed
826<ul>
827 # for item in [1, 2]
828 ## this is a comment that is also removed including leading whitespace
829 <li>{{ item }}
830 # endfor
831</ul>
832```
833
834Renders into the following HTML:
835
836```html
837<ul>
838 <li>1
839 <li>2
840</ul>
841```
842
843Note that this is slightly different than in Jinja2. Specifically the following
844rules apply with regards to whitespace:
845
846* line statements remove all whitespace before and after including the newline
847* line comments remove the trailing newline and leading whitespace.
848
849This is different than in Jinja2 where empty lines can remain from line comments.
850Additionally whitespace control is not available for line statements.
851"###
852)]
853//! # Whitespace Control
854//!
855//! MiniJinja shares the same behavior with Jinja2 when it comes to
856//! whitespace handling. By default a single trailing newline is stripped if present
857//! and all other whitespace is returned unchanged.
858//!
859//! If an application configures Jinja to [`trim_blocks`](crate::Environment::set_trim_blocks),
860//! the first newline after a template tag is removed automatically (like in PHP). The
861//! [`lstrip_blocks`](crate::Environment::set_lstrip_blocks) option can also be set to strip
862//! tabs and spaces from the beginning of a line to the start of a block. (Nothing will be
863//! stripped if there are other characters before the start of the block.)
864//!
865//! With both `trim_blocks` and `lstrip_blocks` enabled, you can put block tags on their
866//! own lines, and the entire block line will be removed when rendered, preserving the
867//! whitespace of the contents.
868//!
869//! For example, without the `trim_blocks` and `lstrip_blocks` options, this template:
870//!
871//! ```jinja
872//! <div>
873//! {% if True %}
874//! yay
875//! {% endif %}
876//! </div>
877//! ```
878//!
879//! gets rendered with blank lines inside the div:
880//!
881//! ```jinja
882//! <div>
883//!
884//! yay
885//!
886//! </div>
887//! ```
888//!
889//! But with both `trim_blocks` and `lstrip_blocks` enabled, the template block lines
890//! are removed and other whitespace is preserved:
891//!
892//! ```jinja
893//! <div>
894//! yay
895//! </div>
896//! ````
897//!
898//! You can manually disable the `lstrip_blocks` behavior by putting a plus sign (`+`)
899//! at the start of a block:
900//!
901//! ```jinja
902//! <div>
903//! {%+ if something %}yay{% endif %}
904//! </div>
905//! ```
906//!
907//! Similarly, you can manually disable the `trim_blocks` behavior by putting a plus
908//! sign (`+`) at the end of a block:
909//!
910//! ```jinja
911//! <div>
912//! {% if something +%}
913//! yay
914//! {% endif %}
915//! </div>
916//! ```
917//!
918//! You can also strip whitespace in templates by hand. If you add a minus sign (`-`) to the
919//! start or end of a block (e.g. a for tag), a comment, or a variable expression, the
920//! whitespaces before or after that block will be removed:
921//!
922//! ```jinja
923//! {% for item in range(1, 10) -%}
924//! {{ item }}
925//! {%- endfor %}
926//! ```
927//!
928//! This will yield all elements without whitespace between them, in this case
929//! the output would be `123456789`.
930//!
931//! By default, MiniJinja also removes trailing newlines. To keep single trailing newlines,
932//! configure MiniJinja to [`keep_trailing_newline`](crate::Environment::set_keep_trailing_newline).
933
934#[cfg(feature = "custom_syntax")]
935mod imp {
936 use crate::compiler::lexer::StartMarker;
937 use crate::error::{Error, ErrorKind};
938 use aho_corasick::{AhoCorasick, PatternID};
939 use std::borrow::Cow;
940 use std::sync::Arc;
941
942 #[derive(Debug, PartialEq, Clone)]
943 pub(crate) struct Delims {
944 block_start: Cow<'static, str>,
945 block_end: Cow<'static, str>,
946 variable_start: Cow<'static, str>,
947 variable_end: Cow<'static, str>,
948 comment_start: Cow<'static, str>,
949 comment_end: Cow<'static, str>,
950 line_statement_prefix: Cow<'static, str>,
951 line_comment_prefix: Cow<'static, str>,
952 }
953
954 const DEFAULT_DELIMS: Delims = Delims {
955 block_start: Cow::Borrowed("{%"),
956 block_end: Cow::Borrowed("%}"),
957 variable_start: Cow::Borrowed("{{"),
958 variable_end: Cow::Borrowed("}}"),
959 comment_start: Cow::Borrowed("{#"),
960 comment_end: Cow::Borrowed("#}"),
961 line_statement_prefix: Cow::Borrowed(""),
962 line_comment_prefix: Cow::Borrowed(""),
963 };
964
965 impl Delims {
966 fn validated_start_delims(&self) -> Result<Vec<&str>, Error> {
967 let mut delims = Vec::with_capacity(5);
968 for (delim, required) in [
969 (&self.variable_start, true),
970 (&self.block_start, true),
971 (&self.comment_start, true),
972 (&self.line_statement_prefix, false),
973 (&self.line_comment_prefix, false),
974 ] {
975 let delim = delim as &str;
976 if delim.is_empty() {
977 if required {
978 return Err(ErrorKind::InvalidDelimiter.into());
979 }
980 } else if delims.contains(&delim) {
981 return Err(ErrorKind::InvalidDelimiter.into());
982 } else {
983 delims.push(delim);
984 }
985 }
986
987 Ok(delims)
988 }
989 }
990
991 /// Builder helper to reconfigure the syntax.
992 ///
993 /// A new builder is returned by [`SyntaxConfig::builder`].
994 #[derive(Debug)]
995 #[cfg_attr(docsrs, doc(cfg(feature = "custom_syntax")))]
996 pub struct SyntaxConfigBuilder {
997 delims: Arc<Delims>,
998 }
999
1000 impl SyntaxConfigBuilder {
1001 /// Sets the block start and end delimiters.
1002 pub fn block_delimiters<S, E>(&mut self, s: S, e: E) -> &mut Self
1003 where
1004 S: Into<Cow<'static, str>>,
1005 E: Into<Cow<'static, str>>,
1006 {
1007 let delims = Arc::make_mut(&mut self.delims);
1008 delims.block_start = s.into();
1009 delims.block_end = e.into();
1010 self
1011 }
1012
1013 /// Sets the variable start and end delimiters.
1014 pub fn variable_delimiters<S, E>(&mut self, s: S, e: E) -> &mut Self
1015 where
1016 S: Into<Cow<'static, str>>,
1017 E: Into<Cow<'static, str>>,
1018 {
1019 let delims = Arc::make_mut(&mut self.delims);
1020 delims.variable_start = s.into();
1021 delims.variable_end = e.into();
1022 self
1023 }
1024
1025 /// Sets the comment start and end delimiters.
1026 pub fn comment_delimiters<S, E>(&mut self, s: S, e: E) -> &mut Self
1027 where
1028 S: Into<Cow<'static, str>>,
1029 E: Into<Cow<'static, str>>,
1030 {
1031 let delims = Arc::make_mut(&mut self.delims);
1032 delims.comment_start = s.into();
1033 delims.comment_end = e.into();
1034 self
1035 }
1036
1037 /// Sets the line statement prefix.
1038 ///
1039 /// By default this is the empty string which disables the line
1040 /// statement prefix feature.
1041 pub fn line_statement_prefix<S>(&mut self, s: S) -> &mut Self
1042 where
1043 S: Into<Cow<'static, str>>,
1044 {
1045 let delims = Arc::make_mut(&mut self.delims);
1046 delims.line_statement_prefix = s.into();
1047 self
1048 }
1049
1050 /// Sets the line comment prefix.
1051 ///
1052 /// By default this is the empty string which disables the line
1053 /// comment prefix feature.
1054 pub fn line_comment_prefix<S>(&mut self, s: S) -> &mut Self
1055 where
1056 S: Into<Cow<'static, str>>,
1057 {
1058 let delims = Arc::make_mut(&mut self.delims);
1059 delims.line_comment_prefix = s.into();
1060 self
1061 }
1062
1063 /// Builds the final syntax config.
1064 pub fn build(&self) -> Result<SyntaxConfig, Error> {
1065 let delims = self.delims.clone();
1066 if *delims == DEFAULT_DELIMS {
1067 return Ok(SyntaxConfig::default());
1068 }
1069 let aho_corasick = ok!(AhoCorasick::builder()
1070 .build(ok!(delims.validated_start_delims()))
1071 .map_err(|_| ErrorKind::InvalidDelimiter.into()));
1072 Ok(SyntaxConfig {
1073 delims,
1074 aho_corasick: Some(aho_corasick),
1075 })
1076 }
1077 }
1078
1079 /// The delimiter configuration for the environment and the parser.
1080 ///
1081 /// Custom syntax configurations require the `custom_syntax` feature.
1082 /// Otherwise just the default syntax is available.
1083 ///
1084 /// You can override the syntax configuration for templates by setting different
1085 /// delimiters. The end markers can be shared, but the start markers need to be
1086 /// distinct. It would thus not be valid to configure `{{` to be the marker for
1087 /// both variables and blocks.
1088 ///
1089 /// ```
1090 /// # use minijinja::{Environment, syntax::SyntaxConfig};
1091 /// let mut environment = Environment::new();
1092 /// environment.set_syntax(
1093 /// SyntaxConfig::builder()
1094 /// .block_delimiters("\\BLOCK{", "}")
1095 /// .variable_delimiters("\\VAR{", "}")
1096 /// .comment_delimiters("\\#{", "}")
1097 /// .build()
1098 /// .unwrap()
1099 /// );
1100 #[derive(Clone, Debug)]
1101 pub struct SyntaxConfig {
1102 delims: Arc<Delims>,
1103 pub(crate) aho_corasick: Option<aho_corasick::AhoCorasick>,
1104 }
1105
1106 impl Default for SyntaxConfig {
1107 fn default() -> Self {
1108 Self {
1109 delims: Arc::new(DEFAULT_DELIMS),
1110 aho_corasick: None,
1111 }
1112 }
1113 }
1114
1115 impl SyntaxConfig {
1116 /// Creates a syntax builder.
1117 #[cfg_attr(docsrs, doc(cfg(feature = "custom_syntax")))]
1118 pub fn builder() -> SyntaxConfigBuilder {
1119 SyntaxConfigBuilder {
1120 delims: Arc::new(DEFAULT_DELIMS),
1121 }
1122 }
1123
1124 /// Returns the block delimiters.
1125 #[inline(always)]
1126 pub fn block_delimiters(&self) -> (&str, &str) {
1127 (&self.delims.block_start, &self.delims.block_end)
1128 }
1129
1130 /// Returns the variable delimiters.
1131 #[inline(always)]
1132 pub fn variable_delimiters(&self) -> (&str, &str) {
1133 (&self.delims.variable_start, &self.delims.variable_end)
1134 }
1135
1136 /// Returns the comment delimiters.
1137 #[inline(always)]
1138 pub fn comment_delimiters(&self) -> (&str, &str) {
1139 (&self.delims.comment_start, &self.delims.comment_end)
1140 }
1141
1142 /// Returns the line statement prefix.
1143 #[inline(always)]
1144 pub fn line_statement_prefix(&self) -> Option<&str> {
1145 if self.delims.line_statement_prefix.is_empty() {
1146 None
1147 } else {
1148 Some(&self.delims.line_statement_prefix)
1149 }
1150 }
1151
1152 /// Returns the line comment prefix.
1153 #[inline(always)]
1154 pub fn line_comment_prefix(&self) -> Option<&str> {
1155 if self.delims.line_comment_prefix.is_empty() {
1156 None
1157 } else {
1158 Some(&self.delims.line_comment_prefix)
1159 }
1160 }
1161
1162 /// Reverse resolves the pattern to a start marker.
1163 pub(crate) fn pattern_to_marker(&self, pattern: PatternID) -> StartMarker {
1164 match pattern.as_usize() {
1165 0 => StartMarker::Variable,
1166 1 => StartMarker::Block,
1167 2 => StartMarker::Comment,
1168 3 => {
1169 if self.line_statement_prefix().is_some() {
1170 StartMarker::LineStatement
1171 } else {
1172 StartMarker::LineComment
1173 }
1174 }
1175 4 => StartMarker::LineComment,
1176 _ => unreachable!(),
1177 }
1178 }
1179 }
1180}
1181
1182#[cfg(not(feature = "custom_syntax"))]
1183mod imp {
1184 /// The default delimiter configuration for the environment and the parser.
1185 #[derive(Clone, Default, Debug)]
1186 pub struct SyntaxConfig;
1187
1188 impl SyntaxConfig {
1189 /// Returns the block delimiters.
1190 #[inline(always)]
1191 pub fn block_delimiters(&self) -> (&str, &str) {
1192 ("{%", "%}")
1193 }
1194
1195 /// Returns the variable delimiters.
1196 #[inline(always)]
1197 pub fn variable_delimiters(&self) -> (&str, &str) {
1198 ("{{", "}}")
1199 }
1200
1201 /// Returns the comment delimiters.
1202 #[inline(always)]
1203 pub fn comment_delimiters(&self) -> (&str, &str) {
1204 ("{#", "#}")
1205 }
1206
1207 /// Returns the line statement prefix.
1208 #[inline(always)]
1209 pub fn line_statement_prefix(&self) -> Option<&str> {
1210 None
1211 }
1212
1213 /// Returns the line comment prefix.
1214 #[inline(always)]
1215 pub fn line_comment_prefix(&self) -> Option<&str> {
1216 None
1217 }
1218 }
1219}
1220
1221pub use self::imp::*;