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