aboutsummaryrefslogtreecommitdiffstats
path: root/book/src
diff options
context:
space:
mode:
authorLibravatar cetra3 <cetra3@hotmail.com>2020-06-29 09:40:01 +0000
committerLibravatar GitHub <noreply@github.com>2020-06-29 11:40:01 +0200
commit3248ad939a4b331472dc0fe985546da5a6641204 (patch)
tree8e1c3f517f68ffa2c43fe85d9a1c43e6d1e33216 /book/src
parent6d5d404bb81ef7f75c11c9665df3613e2801b496 (diff)
downloadaskama-3248ad939a4b331472dc0fe985546da5a6641204.tar.gz
askama-3248ad939a4b331472dc0fe985546da5a6641204.tar.bz2
askama-3248ad939a4b331472dc0fe985546da5a6641204.zip
Initial Askama Book (#332)
Diffstat (limited to 'book/src')
-rw-r--r--book/src/SUMMARY.md10
-rw-r--r--book/src/askama.md56
-rw-r--r--book/src/configuration.md67
-rw-r--r--book/src/creating_templates.md93
-rw-r--r--book/src/debugging.md49
-rw-r--r--book/src/filters.md254
-rw-r--r--book/src/getting_started.md37
-rw-r--r--book/src/integrations.md75
-rw-r--r--book/src/template_syntax.md370
9 files changed, 1011 insertions, 0 deletions
diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md
new file mode 100644
index 0000000..2994524
--- /dev/null
+++ b/book/src/SUMMARY.md
@@ -0,0 +1,10 @@
+# Summary
+
+- [Askama](./askama.md)
+- [Getting Started](./getting_started.md)
+- [Creating Templates](./creating_templates.md)
+- [Debugging](./debugging.md)
+- [Configuration](./configuration.md)
+- [Template Syntax](./template_syntax.md)
+- [Filters](./filters.md)
+- [Integrations](./integrations.md)
diff --git a/book/src/askama.md b/book/src/askama.md
new file mode 100644
index 0000000..739f6d2
--- /dev/null
+++ b/book/src/askama.md
@@ -0,0 +1,56 @@
+# Askama
+
+[![Documentation](https://docs.rs/askama/badge.svg)](https://docs.rs/askama/)
+[![Latest version](https://img.shields.io/crates/v/askama.svg)](https://crates.io/crates/askama)
+[![Build Status](https://github.com/djc/askama/workflows/CI/badge.svg)](https://github.com/djc/askama/actions?query=workflow%3ACI)
+[![Chat](https://badges.gitter.im/gitterHQ/gitter.svg)](https://gitter.im/djc/askama)
+
+Askama implements a template rendering engine based on Jinja.
+It generates Rust code from your templates at compile time
+based on a user-defined `struct` to hold the template's context.
+See below for an example, or read [the documentation][docs].
+
+**"I use Askama for actix's TechEmpower benchmarks."** --
+[Nikolay Kim][fafhrd91], creator of actix-web
+
+**"Pretty exciting. I would love to use this already."** --
+[Armin Ronacher][mitsuhiko], creator of Jinja
+
+All feedback welcome. Feel free to file bugs, requests for documentation and
+any other feedback to the [issue tracker][issues] or [tweet me][twitter].
+Many thanks to [David Tolnay][dtolnay] for his support in improving Askama.
+
+Askama was created by and is maintained by Dirkjan Ochtman. If you are in a
+position to support ongoing maintenance and further development or use it
+in a for-profit context, please consider supporting my open source work on
+[Patreon][patreon].
+
+### Feature highlights
+
+* Construct templates using a familiar, easy-to-use syntax
+* Template code is compiled into your crate for [optimal performance][benchmarks]
+* Benefit from the safety provided by Rust's type system
+* Optional built-in support for Actix, Gotham, Iron, Rocket and warp web frameworks
+* Debugging features to assist you in template development
+* Templates must be valid UTF-8 and produce UTF-8 when rendered
+* Works on stable Rust
+
+### Supported in templates
+
+* Template inheritance
+* Loops, if/else statements and include support
+* Macro support
+* Variables (no mutability allowed)
+* Some built-in filters, and the ability to use your own
+* Whitespace suppressing with '-' markers
+* Opt-out HTML escaping
+* Syntax customization
+
+[docs]: https://docs.rs/askama
+[fafhrd91]: https://github.com/fafhrd91
+[mitsuhiko]: http://lucumr.pocoo.org/
+[issues]: https://github.com/djc/askama/issues
+[twitter]: https://twitter.com/djco/
+[dtolnay]: https://github.com/dtolnay
+[patreon]: https://www.patreon.com/dochtman
+[benchmarks]: https://github.com/djc/template-benchmarks-rs
diff --git a/book/src/configuration.md b/book/src/configuration.md
new file mode 100644
index 0000000..7c68724
--- /dev/null
+++ b/book/src/configuration.md
@@ -0,0 +1,67 @@
+# Configuration
+
+At compile time, Askama will read optional configuration values from
+`askama.toml` in the crate root (the directory where `Cargo.toml` can
+be found). Currently, this covers the directories to search for templates,
+custom syntax configuration and escaper configuration.
+
+This example file demonstrates the default configuration:
+
+```toml
+[general]
+# Directories to search for templates, relative to the crate root.
+dirs = ["templates"]
+```
+
+Here is an example that defines two custom syntaxes:
+
+```toml
+[general]
+default_syntax = "foo"
+
+[[syntax]]
+name = "foo"
+block_start = "%{"
+comment_start = "#{"
+expr_end = "^^"
+
+[[syntax]]
+name = "bar"
+block_start = "%%"
+block_end = "%%"
+comment_start = "%#"
+expr_start = "%{"
+```
+
+A syntax block consists of at least the attribute `name` which uniquely
+names this syntax in the project.
+
+The following keys can currently be used to customize template syntax:
+
+* `block_start`, defaults to `{%`
+* `block_end`, defaults to `%}`
+* `comment_start`, defaults to `{#`
+* `comment_end`, defaults to `#}`
+* `expr_start`, defaults to `{{`
+* `expr_end`, defaults to `}}`
+
+Values must be 2 characters long and start delimiters must all start with the same
+character. If a key is omitted, the value from the default syntax is used.
+
+Here is an example of a custom escaper:
+
+```toml
+[[escaper]]
+path = "::tex_escape::Tex"
+extensions = ["tex"]
+```
+
+An escaper block consists of the attributes `path` and `name`. `path`
+contains a Rust identifier that must be in scope for templates using this
+escaper. `extensions` defines a list of file extensions that will trigger
+the use of that escaper. Extensions are matched in order, starting with the
+first escaper configured and ending with the default escapers for HTML
+(extensions `html`, `htm`, `xml`, `j2`, `jinja`, `jinja2`) and plain text
+(no escaping; `md`, `yml`, `none`, `txt`, and the empty string). Note that
+this means you can also define other escapers that match different extensions
+to the same escaper. \ No newline at end of file
diff --git a/book/src/creating_templates.md b/book/src/creating_templates.md
new file mode 100644
index 0000000..406a825
--- /dev/null
+++ b/book/src/creating_templates.md
@@ -0,0 +1,93 @@
+# Creating Templates
+
+An Askama template is a `struct` definition which provides the template
+context combined with a UTF-8 encoded text file (or inline source, see
+below). Askama can be used to generate any kind of text-based format.
+The template file's extension may be used to provide content type hints.
+
+A template consists of **text contents**, which are passed through as-is,
+**expressions**, which get replaced with content while being rendered, and
+**tags**, which control the template's logic.
+The [template syntax](template_syntax.md) is very similar to [Jinja](http://jinja.pocoo.org/),
+as well as Jinja-derivatives like [Twig](http://twig.sensiolabs.org/) or
+[Tera](https://github.com/Keats/tera).
+
+```rust
+#[derive(Template)] // this will generate the code...
+#[template(path = "hello.html")] // using the template in this path, relative
+ // to the `templates` dir in the crate root
+struct HelloTemplate<'a> { // the name of the struct can be anything
+ name: &'a str, // the field name should match the variable name
+ // in your template
+}
+```
+
+## The `template()` attribute
+
+Askama works by generating one or more trait implementations for any
+`struct` type decorated with the `#[derive(Template)]` attribute. The
+code generation process takes some options that can be specified through
+the `template()` attribute. The following sub-attributes are currently
+recognized:
+
+* `path` (as `path = "foo.html"`): sets the path to the template file. The
+ path is interpreted as relative to the configured template directories
+ (by default, this is a `templates` directory next to your `Cargo.toml`).
+ The file name extension is used to infer an escape mode (see below). In
+ web framework integrations, the path's extension may also be used to
+ infer the content type of the resulting response.
+ Cannot be used together with `source`.
+ ```rust
+ #[derive(Template)]
+ #[template(path = "hello.html")]
+ struct HelloTemplate<'a> { ... }
+ ```
+
+* `source` (as `source = "{{ foo }}"`): directly sets the template source.
+ This can be useful for test cases or short templates. The generated path
+ is undefined, which generally makes it impossible to refer to this
+ template from other templates. If `source` is specified, `ext` must also
+ be specified (see below). Cannot be used together with `path`.
+ ```rust
+ #[derive(Template)]
+ #[template(source = "Hello {{ name }}")]
+ struct HelloTemplate<'a> {
+ name: &'a str,
+ }
+ ```
+* `ext` (as `ext = "txt"`): lets you specify the content type as a file
+ extension. This is used to infer an escape mode (see below), and some
+ web framework integrations use it to determine the content type.
+ Cannot be used together with `path`.
+ ```rust
+ #[derive(Template)]
+ #[template(source = "Hello {{ name }}", ext = "txt")]
+ struct HelloTemplate<'a> {
+ name: &'a str,
+ }
+ ```
+* `print` (as `print = "code"`): enable debugging by printing nothing
+ (`none`), the parsed syntax tree (`ast`), the generated code (`code`)
+ or `all` for both. The requested data will be printed to stdout at
+ compile time.
+ ```rust
+ #[derive(Template)]
+ #[template(path = "hello.html", print = "all")]
+ struct HelloTemplate<'a> { ... }
+ ```
+* `escape` (as `escape = "none"`): override the template's extension used for
+ the purpose of determining the escaper for this template. See the section
+ on configuring custom escapers for more information.
+ ```rust
+ #[derive(Template)]
+ #[template(path = "hello.html", escape = "none")]
+ struct HelloTemplate<'a> { ... }
+ ```
+* `syntax` (as `syntax = "foo"`): set the syntax name for a parser defined
+ in the configuration file. The default syntax , "default", is the one
+ provided by Askama.
+ ```rust
+ #[derive(Template)]
+ #[template(path = "hello.html", syntax = "foo")]
+ struct HelloTemplate<'a> { ... }
+ ``` \ No newline at end of file
diff --git a/book/src/debugging.md b/book/src/debugging.md
new file mode 100644
index 0000000..8995438
--- /dev/null
+++ b/book/src/debugging.md
@@ -0,0 +1,49 @@
+# Debugging and Troubleshooting
+
+You can view the parse tree for a template as well as the generated code by
+changing the `template` attribute item list for the template struct:
+
+```rust
+#[derive(Template)]
+#[template(path = "hello.html", print = "all")]
+struct HelloTemplate<'a> { ... }
+```
+
+The `print` key can take one of four values:
+
+* `none` (the default value)
+* `ast` (print the parse tree)
+* `code` (print the generated code)
+* `all` (print both parse tree and code)
+
+The resulting output will be printed to `stderr` during the compilation process.
+
+The parse tree looks like this for the example template:
+
+```
+[Lit("", "Hello,", " "), Expr(WS(false, false), Var("name")),
+Lit("", "!", "\n")]
+```
+
+The generated code looks like this:
+
+```rust
+impl < 'a > ::askama::Template for HelloTemplate< 'a > {
+ fn render_into(&self, writer: &mut ::std::fmt::Write) -> ::askama::Result<()> {
+ write!(
+ writer,
+ "Hello, {expr0}!",
+ expr0 = &::askama::MarkupDisplay::from(&self.name),
+ )?;
+ Ok(())
+ }
+ fn extension() -> Option<&'static str> {
+ Some("html")
+ }
+}
+impl < 'a > ::std::fmt::Display for HelloTemplate< 'a > {
+ fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+ ::askama::Template::render_into(self, f).map_err(|_| ::std::fmt::Error {})
+ }
+}
+```
diff --git a/book/src/filters.md b/book/src/filters.md
new file mode 100644
index 0000000..35cb557
--- /dev/null
+++ b/book/src/filters.md
@@ -0,0 +1,254 @@
+# Filters
+
+Values such as those obtained from variables can be post-processed
+using **filters**.
+Filters are applied to values using the pipe symbol (`|`) and may
+have optional extra arguments in parentheses.
+Filters can be chained, in which case the output from one filter
+is passed to the next.
+
+```
+{{"HELLO" | lower}}
+```
+
+Askama has a collection of built-in filters, documented below, but can also include custom filters.
+
+## Built-In Filters
+
+### capitalize
+
+Capitalize a value. The first character will be uppercase, all others lowercase:
+
+```
+{{ "hello" | capitalize}}
+```
+
+Output:
+
+```
+Hello
+```
+
+### center
+
+Centers the value in a field of a given width:
+
+```
+-{{ "a" | center(5)}}-
+```
+
+Output:
+```
+- a -
+```
+
+### escape | e
+
+Escapes html characters in strings:
+
+```
+{{ "Escape <>&" | e}}
+```
+
+Output:
+
+```
+Escape &lt;&gt;&amp;
+```
+
+### filesizeformat
+
+Returns adequate string representation (in KB, ..) of number of bytes:
+
+```
+{{ 1000 | filesizeformat }}
+```
+
+Output:
+```
+1 KB
+```
+
+### format
+
+Formats arguments according to the specified format
+
+The first argument to this filter must be a string literal (as in normal Rust).
+
+All arguments are passed through to the format!() macro by the Askama code generator.
+
+```
+{{ "{:?}"|format(var) }}
+```
+
+### indent
+
+Indent newlines with width spaces
+
+```
+{{ "hello\nfoo\nbar" | indent(4) }}
+```
+
+Output:
+
+```
+hello
+ foo
+ bar
+```
+
+### join
+
+Joins iterable into a string separated by provided argument
+
+```
+array = &["foo", "bar", "bazz"]
+```
+
+```
+{{ array | join(", ")}}
+```
+
+Output:
+
+```
+foo, bar, bazz
+```
+
+### linebreaks
+
+Replaces line breaks in plain text with appropriate HTML
+
+A single newline becomes an HTML line break <br> and a new line followed by a blank line becomes a paragraph break <p>.
+
+```
+{{ "hello\nworld\n\nfrom\naskama" | linebreaks }}
+```
+
+Output:
+
+```
+<p>hello<br />world</p><p>from<br />askama</p>
+```
+
+### linebreaksbr
+
+Converts all newlines in a piece of plain text to HTML line breaks
+
+```
+{{ "hello\nworld\n\nfrom\naskama" | linebreaks }}
+```
+
+Output:
+
+```
+hello<br />world<br /><br />from<br />askama
+```
+
+### lower | lowercase
+
+Converts to lowercase
+
+```
+{{ "HELLO" | lower }}
+```
+
+Output:
+
+```
+hello
+```
+
+### safe
+
+Marks a string (or other Display type) as safe. By default all strings are escaped according to the format
+
+```
+{{ "<p>I'm Safe</p>" | safe}}
+```
+
+Output:
+
+```
+<p>I'm Safe</p>
+```
+
+### trim
+
+Strip leading and trailing whitespace
+
+```
+{{ " hello " | trim}}
+```
+
+Output:
+
+```
+hello
+```
+
+### truncate
+
+Limit string length, appends '...' if truncated
+
+
+```
+{{ "hello" | truncate(2) }}
+```
+
+Output:
+
+```
+he...
+```
+
+### upper | uppercase
+
+Converts to uppercase
+
+```
+{{ "hello" | upper}}
+```
+
+Output:
+
+```
+HELLO
+```
+
+### wordcount
+
+Count the words in that string
+
+```
+{{ "askama is sort of cool" | wordcount}}
+```
+
+```
+5
+```
+
+## Custom Filters
+
+To define your own filters, simply have a module named filters in scope of the context deriving a Template impl.
+
+Note that in case of name collision, the built in filters take precedence.
+
+```rust
+#[derive(Template)]
+#[template(source = "{{ s|myfilter }}", ext = "txt")]
+struct MyFilterTemplate<'a> {
+ s: &'a str,
+}
+
+mod filters {
+ pub fn myfilter(s: &str) -> ::askama::Result<String> {
+ Ok(s.replace("oo", "aa"))
+ }
+}
+
+fn main() {
+ let t = MyFilterTemplate { s: "foo" };
+ assert_eq!(t.render().unwrap(), "faa");
+}
+``` \ No newline at end of file
diff --git a/book/src/getting_started.md b/book/src/getting_started.md
new file mode 100644
index 0000000..4b7fb5f
--- /dev/null
+++ b/book/src/getting_started.md
@@ -0,0 +1,37 @@
+# Getting Started
+
+First, add the following to your crate's `Cargo.toml`:
+
+```toml
+# in section [dependencies]
+askama = "0.8"
+
+```
+
+Now create a directory called `templates` in your crate root.
+In it, create a file called `hello.html`, containing the following:
+
+```
+Hello, {{ name }}!
+```
+
+In any Rust file inside your crate, add the following:
+
+```rust
+use askama::Template; // bring trait in scope
+
+#[derive(Template)] // this will generate the code...
+#[template(path = "hello.html")] // using the template in this path, relative
+ // to the `templates` dir in the crate root
+struct HelloTemplate<'a> { // the name of the struct can be anything
+ name: &'a str, // the field name should match the variable name
+ // in your template
+}
+
+fn main() {
+ let hello = HelloTemplate { name: "world" }; // instantiate your struct
+ println!("{}", hello.render().unwrap()); // then render it.
+}
+```
+
+You should now be able to compile and run this code.
diff --git a/book/src/integrations.md b/book/src/integrations.md
new file mode 100644
index 0000000..ed0fec0
--- /dev/null
+++ b/book/src/integrations.md
@@ -0,0 +1,75 @@
+# Integrations
+
+## Rocket integration
+
+Enabling the `with-rocket` feature appends an implementation of Rocket's
+`Responder` trait for each template type. This makes it easy to trivially
+return a value of that type in a Rocket handler. See
+[the example](https://github.com/djc/askama/blob/master/askama_rocket/tests/basic.rs)
+from the Askama test suite for more on how to integrate.
+
+In case a run-time error occurs during templating, a `500 Internal Server
+Error` `Status` value will be returned, so that this can be further
+handled by your error catcher.
+
+## Iron integration
+
+Enabling the `with-iron` feature appends an implementation of Iron's
+`Modifier<Response>` trait for each template type. This makes it easy to
+trivially return a value of that type in an Iron handler. See
+[the example](https://github.com/djc/askama/blob/master/askama_iron/tests/basic.rs)
+from the Askama test suite for more on how to integrate.
+
+Note that Askama's generated `Modifier<Response>` implementation currently
+unwraps any run-time errors from the template. If you have a better
+suggestion, please [file an issue](https://github.com/djc/askama/issues/new).
+
+## Actix-web integration
+
+Enabling the `with-actix-web` feature appends an implementation of Actix-web's
+`Responder` trait for each template type. This makes it easy to trivially return
+a value of that type in an Actix-web handler. See
+[the example](https://github.com/djc/askama/blob/master/askama_actix/tests/basic.rs)
+from the Askama test suite for more on how to integrate.
+
+## Gotham integration
+
+Enabling the `with-gotham` feature appends an implementation of Gotham's
+`IntoResponse` trait for each template type. This makes it easy to trivially
+return a value of that type in a Gotham handler. See
+[the example](https://github.com/djc/askama/blob/master/askama_gotham/tests/basic.rs)
+from the Askama test suite for more on how to integrate.
+
+In case of a run-time error occurring during templating, the response will be of the same
+signature, with a status code of `500 Internal Server Error`, mime `*/*`, and an empty `Body`.
+This preserves the response chain if any custom error handling needs to occur.
+
+## Warp integration
+
+Enabling the `with-warp` feature appends an implementation of Warp's `Reply`
+trait for each template type. This makes it simple to return a template from
+a Warp filter. See [the example](https://github.com/djc/askama/blob/master/askama_warp/tests/warp.rs)
+from the Askama test suite for more on how to integrate.
+
+## The `json` filter
+
+Enabling the `serde-json` filter will enable the use of the `json` filter.
+This will output formatted JSON for any value that implements the required
+`Serialize` trait.
+
+```
+{
+ "foo": "{{ foo }}",
+ "bar": {{ bar|json }}
+}
+```
+
+## The `yaml` filter
+
+Enabling the `serde-yaml` filter will enable the use of the `yaml` filter.
+This will output formatted JSON for any value that implements the required
+`Serialize` trait.
+
+```
+{{ foo|yaml }}
+``` \ No newline at end of file
diff --git a/book/src/template_syntax.md b/book/src/template_syntax.md
new file mode 100644
index 0000000..6b98d99
--- /dev/null
+++ b/book/src/template_syntax.md
@@ -0,0 +1,370 @@
+# Template Syntax
+
+## Variables
+
+Top-level template variables are defined by the template's context type.
+You can use a dot (`.`) to access variable's attributes or methods.
+Reading from variables is subject to the usual borrowing policies.
+For example, `{{ name }}` will get the ``name`` field from the template
+context,
+while `{{ user.name }}` will get the ``name`` field of the ``user``
+field from the template context.
+
+## Assignments
+
+Inside code blocks, you can also declare variables or assign values
+to variables.
+Assignments can't be imported by other templates.
+
+Assignments use the let tag:
+
+```text
+{% let name = user.name %}
+{% let len = name.len() %}
+
+{% let val -%}
+{% if len == 0 -%}
+ {% let val = "foo" -%}
+{% else -%}
+ {% let val = name -%}
+{% endif -%}
+{{ val }}
+```
+
+## Filters
+
+Values such as those obtained from variables can be post-processed
+using **filters**.
+Filters are applied to values using the pipe symbol (`|`) and may
+have optional extra arguments in parentheses.
+Filters can be chained, in which case the output from one filter
+is passed to the next.
+
+For example, `{{ "{:?}"|format(name|escape) }}` will escape HTML
+characters from the value obtained by accessing the `name` field,
+and print the resulting string as a Rust literal.
+
+The built-in filters are documented as part of the
+[filters documentation](filters.md).
+
+To define your own filters, simply have a module named `filters` in
+scope of the context deriving a `Template` `impl`. Note that in case of
+name collision, the built in filters take precedence.
+
+## Whitespace control
+
+Askama considers all tabs, spaces, newlines and carriage returns to be
+whitespace. By default, it preserves all whitespace in template code,
+except that a single trailing newline character is suppressed.
+However, whitespace before and after expression and block delimiters
+can be suppressed by writing a minus sign directly following a
+start delimiter or leading into an end delimiter.
+
+Here is an example:
+
+```text
+{% if foo %}
+ {{- bar -}}
+{% else if -%}
+ nothing
+{%- endif %}
+```
+
+This discards all whitespace inside the if/else block. If a literal
+(any part of the template not surrounded by `{% %}` or `{{ }}`)
+includes only whitespace, whitespace suppression on either side will
+completely suppress that literal content.
+
+## Template inheritance
+
+Template inheritance allows you to build a base template with common
+elements that can be shared by all inheriting templates.
+A base template defines **blocks** that child templates can override.
+
+### Base template
+
+```html
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <title>{% block title %}{{ title }} - My Site{% endblock %}</title>
+ {% block head %}{% endblock %}
+ </head>
+ <body>
+ <div id="content">
+ {% block content %}{% endblock %}
+ </div>
+ </body>
+</html>
+```
+
+The `block` tags define three blocks that can be filled in by child
+templates. The base template defines a default version of the block.
+A base template must define one or more blocks in order to enable
+inheritance. Blocks can only be specified at the top level of a template
+or inside other blocks, not inside `if`/`else` branches or in `for`-loop
+bodies.
+
+### Child template
+
+Here's an example child template:
+
+```html
+{% extends "base.html" %}
+
+{% block title %}Index{% endblock %}
+
+{% block head %}
+ <style>
+ </style>
+{% endblock %}
+
+{% block content %}
+ <h1>Index</h1>
+ <p>Hello, world!</p>
+{% endblock %}
+```
+
+The `extends` tag tells the code generator that this template inherits
+from another template. It will search for the base template relative to
+itself before looking relative to the template base directory. It will
+render the top-level content from the base template, and substitute
+blocks from the base template with those from the child template. Inside
+a block in a child template, the `super()` macro can be called to render
+the parent block's contents.
+
+## HTML escaping
+
+Askama by default escapes variables if it thinks it is rendering HTML
+content. It infers the escaping context from the extension of template
+filenames, escaping by default if the extension is one of `html`, `htm`,
+or `xml`. When specifying a template as `source` in an attribute, the
+`ext` attribute parameter must be used to specify a type. Additionally,
+you can specify an escape mode explicitly for your template by setting
+the `escape` attribute parameter value (to `none` or `html`).
+
+Askama escapes `<`, `>`, `&`, `"`, `'`, `\` and `/`, according to the
+[OWASP escaping recommendations][owasp]. Use the `safe` filter to
+prevent escaping for a single expression, or the `escape` (or `e`)
+filter to escape a single expression in an unescaped context.
+
+[owasp]: https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet#RULE_.231_-_HTML_Escape_Before_Inserting_Untrusted_Data_into_HTML_Element_Content
+
+```rust
+#[derive(Template)]
+#[template(source = "{{strvar}}")]
+struct TestTemplate {
+ strvar: String,
+}
+
+fn main() {
+ let s = TestTemplate {
+ strvar: "// my <html> is \"unsafe\" & should be 'escaped'".to_string(),
+ };
+ assert_eq!(
+ s.render().unwrap(),
+ "&#x2f;&#x2f; my &lt;html&gt; is &quot;unsafe&quot; &amp; \
+ should be &#x27;escaped&#x27;"
+ );
+}
+```
+
+## Control structures
+
+### For
+
+Loop over each item in an iterator. For example:
+
+```html
+<h1>Users</h1>
+<ul>
+{% for user in users %}
+ <li>{{ user.name|e }}</li>
+{% endfor %}
+</ul>
+```
+
+Inside for-loop blocks, some useful variables are accessible:
+
+* *loop.index*: current loop iteration (starting from 1)
+* *loop.index0*: current loop iteration (starting from 0)
+* *loop.first*: whether this is the first iteration of the loop
+* *loop.last*: whether this is the last iteration of the loop
+
+
+```html
+<h1>Users</h1>
+<ul>
+{% for user in users %}
+ {% if loop.first %}
+ <li>First: {{user.name}}</li>
+ {% else %}
+ <li>User#{{loop.index}}: {{user.name}}</li>
+ {% endif %}
+{% endfor %}
+</ul>
+```
+
+### If
+
+The *if* statement is used as you might expect:
+
+```text
+{% if users.len() == 0 %}
+ No users
+{% else if users.len() == 1 %}
+ 1 user
+{% else %}
+ {{ users.len() }} users
+{% endif %}
+```
+
+### Match
+
+In order to deal with Rust `enum`s in a type-safe way, templates support
+match blocks from version 0.6. Here is a simple example showing how to
+expand an `Option`:
+
+```text
+{% match item %}
+ {% when Some with ("foo") %}
+ Found literal foo
+ {% when Some with (val) %}
+ Found {{ val }}
+ {% when None %}
+{% endmatch %}
+```
+
+That is, a `match` block can optionally contain some whitespace (but
+no other literal content), followed by a number of `when` blocks
+and an optional `else` block. Each `when` block must name a list of
+matches (`(val)`), optionally introduced with a variant name. The
+`else` block is equivalent to matching on `_` (matching anything).
+
+Struct-like enum variants are supported from version 0.8, with the list
+of matches surrounded by curly braces instead (`{ field }`). New names
+for the fields can be specified after a colon in the list of matches
+(`{ field: val }`).
+
+### Include
+
+The *include* statement lets you split large or repetitive blocks into
+separate template files. Included templates get full access to the context
+in which they're used, including local variables like those from loops:
+
+```text
+{% for i in iter %}
+ {% include "item.html" %}
+{% endfor %}
+```
+
+```text
+* Item: {{ i }}
+```
+
+The path to include must be a string literal, so that it is known at
+compile time. Askama will try to find the specified template relative
+to the including template's path before falling back to the absolute
+template path. Use `include` within the branches of an `if`/`else`
+block to use includes more dynamically.
+
+## Expressions
+
+Askama supports string literals (`"foo"`) and integer literals (`1`).
+It supports almost all binary operators that Rust supports,
+including arithmetic, comparison and logic operators.
+The parser applies the same precedence order as the Rust compiler.
+Expressions can be grouped using parentheses.
+The HTML special characters `&`, `<` and `>` will be replaced with their
+character entities unless the `escape` mode is disabled for a template.
+Methods can be called on variables that are in scope, including `self`.
+
+```
+{{ 3 * 4 / 2 }}
+{{ 26 / 2 % 7 }}
+{{ 3 % 2 * 6 }}
+{{ 1 * 2 + 4 }}
+{{ 11 - 15 / 3 }}
+{{ 4 + 5 % 3 }}
+{{ 4 | 2 + 5 & 2 }}
+```
+
+**Warning**: if the result of an expression (a `{{ }}` block) is
+equivalent to `self`, this can result in a stack overflow from infinite
+recursion. This is because the `Display` implementation for that expression
+will in turn evaluate the expression and yield `self` again.
+
+
+## Templates in templates
+
+Using expressions, it is possible to delegate rendering part of a template to another template.
+This makes it possible to inject modular template sections into other templates and facilitates
+testing and reuse.
+
+```rust
+use askama::Template;
+#[derive(Template)]
+#[template(source = "Section 1: {{ s1.render().unwrap() }}", ext = "txt")]
+struct RenderInPlace<'a> {
+ s1: SectionOne<'a>
+}
+
+#[derive(Template)]
+#[template(source = "A={{ a }}\nB={{ b }}", ext = "txt")]
+struct SectionOne<'a> {
+ a: &'a str,
+ b: &'a str,
+}
+let t = RenderInPlace { s1: SectionOne { a: "a", b: "b" } };
+assert_eq!(t.render().unwrap(), "Section 1: A=a\nB=b")
+```
+
+See the example
+[render in place](https://github.com/djc/askama/blob/master/testing/tests/render_in_place.rs)
+using a vector of templates in a for block.
+
+## Comments
+
+Askama supports block comments delimited by `{#` and `#}`.
+
+```
+{# A Comment #}
+```
+
+## Recursive Structures
+
+Recursive implementations should preferably use a custom iterator and
+use a plain loop. If that is not doable, call `.render()`
+directly by using an expression as shown below.
+Including self does not work, see #105 and #220 .
+
+```rust
+use askama::Template;
+
+#[derive(Template)]
+#[template(source = r#"
+//! {% for item in children %}
+ {{ item.render().unwrap() }}
+{% endfor %}
+"#, ext = "html", escape = "none")]
+struct Item<'a> {
+ name: &'a str,
+ children: &'a [Item<'a>],
+}
+```
+
+## Macros
+
+You can define macros within your template by using `{% macro name(args) %}`, ending with `{% endmacro %}`
+
+You can then call it later with `{% call name(args) %}`
+
+```
+{% macro heading(arg) %}
+
+<h1>{{arg}}</h1>
+
+{% endmacro %}
+
+{% call heading(s) %}
+```