djc / askama Goto Github PK
View Code? Open in Web Editor NEWType-safe, compiled Jinja-like templates for Rust
License: Apache License 2.0
Type-safe, compiled Jinja-like templates for Rust
License: Apache License 2.0
I haven't found a way to use tuples in a template. It would be great with support both for tuple indexing and destructuring assignments with let.
It seems that the only thing stopping tuple indexing is that identifiers are not allowed to start with numbers. I'm not sure changing the identifier rule is the best solution though because it would not be valid for all usages of identifiers.
Using the fix from #8, something is wrong with the loop index tracking.
{% for inner in nested %}
outer = {{ loop.index0 }}
{% for _ in inner %}
inner = {{ loop.index0 }}
{% endfor %}
{% endfor %}
thread 'main' panicked at 'index out of bounds: the len is 1 but the index is 1', /checkout/src/libcollections/vec.rs:1410
From a quick read, it looks like the _loop_cur variable is never decremented.
How feasible would it be to support generic template types?
{{ t }}
#[derive(Template)]
#[template(path = "test")]
struct Test<T> {
t: T,
}
error[E0243]: wrong number of type arguments: expected 1, found 0
--> src/main.rs:7:10
|
7 | #[derive(Template)]
| ^^^^^^^^ expected 1 type argument
error[E0243]: wrong number of type arguments: expected 1, found 0
--> src/main.rs:7:10
|
7 | #[derive(Template)]
| ^^^^^^^^ expected 1 type argument
error: aborting due to 2 previous errors
Custom derive macros can not be exported together with other items, so you have to depend on a separate crate for it.
They can actually. If you are okay requiring Rust >=1.15 to compile askama, you can include this in askama/src/lib.rs:
#[allow(unused_imports)]
#[macro_use]
extern crate askama_derive;
pub use askama_derive::*;
Then users can write:
#[macro_use]
extern crate askama;
and get access to the derives that way.
I'm having trouble chaining filters together.
In Rust:
mod filters {
pub fn mytrim(s: &::std::fmt::Display) -> ::askama::Result<String> {
let s = format!("{}", s);
Ok(s.trim().to_owned())
}
}
In the template:
<div>{{ todo.subject|mytrim|safe }}</div>
And the error:
error[E0597]: borrowed value does not live long enough
--> src\view.rs:52:10
|
52 | #[derive(Template)]
| ^^^^^^^-
| | |
| | temporary value dropped here while still borrowed
| temporary value does not live long enough
|
= note: values in a scope are dropped in the opposite order they are created
= note: consider using a `let` binding to increase its lifetime
Would it be possible to make this work?
#[derive(Template)]
#[template(path = "test")]
struct Test<'a> {
names: &'a [&'a str],
}
{% for n in names %}
name = {{ n }}
{% endfor %}
error[E0277]: the trait bound `&&[&str]: std::iter::Iterator` is not satisfied
--> src/main.rs:7:10
|
7 | #[derive(Template)]
| ^^^^^^^^ the trait `std::iter::Iterator` is not implemented for `&&[&str]`
|
= note: `&&[&str]` is not an iterator; maybe try calling `.iter()` or a similar method
= note: required by `std::iter::IntoIterator::into_iter`
Example:
base.html
{% block foo %}{% endblock %}
{% block bar %}Default{% endblock %}
foo.html
{% extends "base.html" %}
{% block foo %}Foo{% endblock %}
Should compile.
Right now it fails because base generate a traits that has a method for each block and the child one doesn't implement the bar
one.
I had a quick look at the code but can't find any easy way of fixing that :/
Porting some jinja templates, I was using include
to conditionally including partials (specifically for repeated snippets) that looked something like this:
<section name="{{foo_name}}">
{% include 'creds-'~provider~'-partial.j2' %}
</section>
<section name="{{bar_name}}">
{% include 'creds-'~provider~'partial.j2 %}
</section>
Porting this to use template inheritance doesn't work since the block would be repeated, and I didn't see a built-in partial mechanism. I've currently resorted to just rendering the creds template and storing the String
result on the main template struct and using it like this:
<section name="{{foo_name}}">
{{provider_creds}}
</section>
<section name="{{bar_name}}">
{{provider_creds}}
</section>
Overall that template file seems fine, but it's kinda disappointing that I have to pre-render the provider_creds
to and store it on the parent template struct as provider_creds: String
. I'd prefer to store provider_creds: AwsCreds
(where AwsCreds
also derives Template
) and have Askama handle the recursive rendering. I'm currently hacking together something like this with:
impl ::std::fmt::Display for AwsCreds {
fn fmt(&self, mut f: &mut fmt::Formatter) -> ::std::fmt::Result {
writeln!(&mut f, "{}", self.render())
}
}
I could even extend that to impl <T: Template> Display for T
, but I'm not sure how I feel about implementing Display
for a bunch of these types. Perhaps this would work more elegantly if Askama used a Renderable
trait instead of the Display
type, and provided a blanket impl <T: Display> Renderable for T
and impl <T: Template> Renderable for T
? I might be missing something here, but it seems simple and elegant to me.
Alternatively, Askama could try and add an include
statement. I don't see how include 'path/to/file'
would work given the the path is a part of the derived Template
, but I could imagine a scenario where you allow {% include provider_creds %}
or just {% render provider_creds %}
to trigger self.provider_creds.render()
, although, at that point maybe {{ provider_creds.render() }}
is even more intuitive.
Anyhow, this is just my first attempt to think through the space around partials/nested templates. There are still a few kinks in my head that I want to sleep on (e.g. how to maximize template reuse when supporting both AwsCreds
and OpenStackCreds
). But I'd love to know your thoughts. Does anything along these lines fit into the scope of Askama?
The Debug representation of errors is typically not designed to be shown to users.
#[derive(Template)]
#[template(path = "ello.html")]
struct HelloTemplate<'a> {
name: &'a str,
}
error: proc-macro derive panicked
--> src/main.rs:7:10
|
7 | #[derive(Template)]
| ^^^^^^^^
|
= help: message: called `Result::unwrap()` on an `Err` value: Error { repr: Os { code: 2, message: "No such file or directory" } }
I've been using Askama for while and I think it's great.
However I've found one case where some of my templates take a very long time to compile. Now when I finally took some time to investigate it seems to be related to a specific construct in the templates that leads to very long time spent in the parser.
Compilation of the following code takes about a minute for me to compile before it fails.
#[macro_use]
extern crate askama;
use askama::Template;
#[derive(Template)]
#[template(source = "{{ a.b(c.d()) }}")]
struct MyTemplate {
}
fn main() {
let template = MyTemplate {};
println!("{}", template.render())
}
Profiling of similar case using 0.3.4 shows that most of the time is spent in the parser.
Total number in stack (recursive counted multiple, when >=5):
87736 askama_derive::parser::expr_filtered (in libaskama_derive-3ae4a4b851656feb.dylib) + 189 [0x118c74f7d] parser.rs:189
47349 askama_derive::parser::expr_attr (in libaskama_derive-3ae4a4b851656feb.dylib) + 1711 [0x118c72a8f] parser.rs:166
47134 askama_derive::parser::attr (in libaskama_derive-3ae4a4b851656feb.dylib) + 2242 [0x118c71e12] parser.rs:159
46629 askama_derive::parser::arguments (in libaskama_derive-3ae4a4b851656feb.dylib) + 2276 [0x118c6add4] parser.rs:126
45844 askama_derive::parser::expr_addsub (in libaskama_derive-3ae4a4b851656feb.dylib) + 248 [0x118c7ac18] parser.rs:223```
I hit this when upgrading from ffc74a1 to 8bda0d6. I haven't had time to dig in yet, (will try and set aside some time tomorrow if you haven't magically fixed it by then), but I thought I'd give you a quick heads up (i.e. hold off on publishing the updates to crates.io).
error[E0244]: wrong number of type arguments: expected 1, found 2
--> src/templates/mod.rs:139:10
|
139 | #[derive(Template)]
| ^^^^^^^^ expected 1 type argument
Hey,
It would be great to be able to have macros in a file and be able to include that file in another.
Currently it's hitting panic!("no extends or macros allowed in content");
.
This looks like a really neat project!
Before I would use it in production though, it needs to have escaping be enabled by default for HTML. Otherwise it will inevitably lead to security problems.
See here for what some other template engines do:
This library doing things at compile-time, maybe there's a different approach you could use, e.g. escaping all String
s by default, but introducing a new type that wraps a string that will result in unescaped output.
What are your thoughts on this?
Hello,
is Rocket integration working with latest Rocket version? (0.3.6) It seems to be broken since they changed their Responder trait.
It seems to me that builds should be failing now, but Travis isn't running those tests.
Tracking down the built-in filters available in jinja2. So that people can pick these to contribute. Feel free to add / remove items.
ref: https://jinja.palletsprojects.com/en/2.11.x/templates/#builtin-filters
This compiles:
{% match phrase_data %} {% when Some with (pd) %}{% when None %}{% endmatch %}
this doesn't:
{% match phrase_data %}{% when Some with (pd) %}{% when None %}{% endmatch %}
message: unable to parse template
annoying, as I am trying set attribute value of optional is not none
(tested on master)
If I'm reading expr_attr correctly, then it doesn't support recursive productions, such as obj.x.y.z
.
I've tried to extend expr_attr
to support this using fold_many0!. Alas, I had a bunch of lifetime errors, probably due to some bizarre nom idiosyncrasy I'm not aware of.
I'm curious to see if you have any thoughts on idiomatic use of Option<String>
in a template? I'm currently doing something like:
{% if foo.is_some() %}
{{ foo.as_ref().unwrap() }}
{% endif %}
If I were trying to be more rust-like, I might try:
{% if let Some(ref foo) = foo %}
{{ foo }}
{% endif %}
But that doesn't look very nice, so i sorta wonder if Askama could be a bit magical here to feel more Jinja like:
{% if foo is defined %}
{{ foo }}
{% endif %}
where if foo is defined
(or if foo is some
) translates to if let Some(ref foo) = foo
. Of course, this pattern probably isn't generic enough to work for arbitrary enums; I'm not sure how deep you want to go into match
semantics in templates, but it seems like it could be useful to at least have an idiomatic solution for Option
and Result
The documentation is rather sparse in terms of how to integrate with Rocket and the file testing/tests/rocket.rs
is not quite sufficient for me to understand exactly what I should do either, so it could be that the following build failure arises because I am doing something wrong here.
When I try to build my project, I get the following error:
error[E0106]: missing lifetime specifier
--> /home/user/.cargo/registry/src/github.com-1ecc6299db9ec823/askama-0.5.0/src/lib.rs:310:55
|
310 | pub fn respond(t: &super::Template, ext: &str) -> Result {
| ^^^^^^ expected lifetime parameter
|
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `t` or `ext`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0106`.
error: Could not compile `askama`.
warning: build failed, waiting for other jobs to finish...
error: build failed
Here is my Cargo.toml
, my build.rs
and my src/main.rs
: https://gist.github.com/ctsrc/dc2645843c8ca4a00697275a6c94a256
I am using Rust 1.27.0 nightly.
Maybe I don't understand the full scope of what it is solving, but this generated code looks like it could be a lot simpler and faster.
{% for inner in nested %}{% for _ in inner %}{% endfor %}{% endfor %}
let mut _loop_indexes = Vec::new();
let mut _loop_cur = 0;
_loop_indexes.push(0);
_loop_cur = 0;
for inner in (&self.nested).into_iter() {
_loop_indexes[_loop_cur] += 1;
_loop_indexes.push(0);
_loop_cur = 1;
for _ in (&inner).into_iter() {
_loop_indexes[_loop_cur] += 1;
}
_loop_indexes.pop();
}
_loop_indexes.pop();
How about:
for (_index, inner) in (&self.nested).into_iter().enumerate() {
for (_index, _) in (&inner).into_iter().enumerate() {
}
}
Given that in templates there are situations where multiple if/else cases are stacked, the final generated file contains empty lines where the if statements reside.
{% if x %}
{% if z %}
hello
{% endif %}
virtual
{% else %}
world
{% endif %}
How can one prevent this?
#[derive(Template)]
#[template(path = "test")]
struct Test<T: Display = u8> {
t: T,
}
error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions.
--> tests/simple.rs:119:10
|
119 | #[derive(Template)]
| ^^^^^^^^
|
= note: #[deny(invalid_type_param_default)] on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
What is this useful for?
#[allow(dead_code, non_camel_case_types)]
type TemplateFromhello2ehtml<'a> = HelloTemplate<'a>;
I had a child template start with this (a typo of extends
as extend
)
{% extend "path/to/file.j2" %}
then the generated coded ended up with an empty render_to
block. More generally, I can insert almost any arbitrary, non-valid content inside the {% %}
(including nothing inside the tag) and any content after that tag is not rendered. So:
foo
{% garbage %}
baz
generates
impl< 'a > ::askama::Template for ApplicationConfAws< 'a > {
fn render_to(&self, writer: &mut ::std::fmt::Write) {
writer.write_str("foo").unwrap();
writer.write_str("\n").unwrap();
}
}
As previously mentioned, I was tripping over trying to move templates involving inheritance into subfolders. I would annotate the my template structs with the subfolder: #[template(path = "terraform/variables_tf.j2")]
, but I'd get this as an error:
error[E0405]: cannot find trait `TraitFromvariables5ftf2ej2` in this scope
--> src/templates/variables_tf.rs:15:10
|
15 | #[derive(Template)]
| ^^^^^^^^ not found in this scope
After battling with it a bit more, I came to understand that the child template file needed to also include the full path as {% extends "terraform/variables_tf.j2" %}
. It felt unintuitive because I was writing that in a child template file that was in the same directory, so {% extends "variables_tf.j2" %}
seemed more natural, though I do see the value in the extends path matching the path specified in the attribute.
So primarily this is a papercut that could use a better error message and documentation, though I do wonder if it's worth considering a breaking change where "variables_tf.j2" could mean relative to current file and /terraform/variables_tf.j2
could be relative to the template root (assuming the macro intrinsics are good enough to achieve that).
I originally misattributed this issue first as cross-rs/cross#193 and then as #72 but I have now found conclusively that simply using Askama at revision 36cbfd4 with Rust nightly-2018-04-07 causes the following problem: The produced binary gets dynamically linked to libstd and libproc_macro which cannot be found, resulting in it being possible to run the binary with cargo run
but not by direct execution of ./target/debug/hello_askama
(hello_askama is what I named the minimal example that is made based on the Askama README) as in rust-lang/cargo#4651.
$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
Running `target/debug/hello_askama`
Hello, world!
$ ./target/debug/hello_askama
./target/debug/hello_askama: error while loading shared libraries: libproc_macro-d3bd4d284648dcab.so: cannot open shared object file: No such file or directory
$ ldd target/debug/hello_askama
linux-vdso.so.1 => (0x00007fff265d1000)
libproc_macro-d3bd4d284648dcab.so => not found
libstd-b70fe684839d0aca.so => not found
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f3db94ba000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f3db92a3000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3db8ec3000)
/lib64/ld-linux-x86-64.so.2 (0x00007f3db9921000)
I used a Cargo.toml
that looks like this:
[package]
name = "hello_askama"
version = "0.0.1"
authors = [ "Your name <[email protected]>" ]
[dependencies]
askama = { git = "https://github.com/djc/askama", rev = "36cbfd4bad8c3f534c8cb13f9ddbc463e1c44ef5" }
[build-dependencies]
askama = { git = "https://github.com/djc/askama", rev = "36cbfd4bad8c3f534c8cb13f9ddbc463e1c44ef5" }
build.rs
like in Askama README:
extern crate askama;
fn main() {
askama::rerun_if_templates_changed();
}
templates/hello.htm
like in Askama README:
Hello, {{ name }}!
src/main.rs
like in Askama README:
#[macro_use]
extern crate askama;
use askama::Template;
#[derive(Template)]
#[template(path = "hello.htm")]
struct HelloTemplate<'a> {
name: &'a str,
}
fn main() {
let hello = HelloTemplate { name: "world" };
println!("{}", hello.render().unwrap());
}
And like I said, I was using Rust nightly-2018-04-07.
rustup default nightly-2018-04-07
let tmpl = DefaultTemplate { name: "world" };
let tmpl_body = tmpl.render().unwrap();
let layout = DefaultLayout { content: &tmpl_body };
let layout_body = layout.render().unwrap();
Ok(HttpResponse::Ok().content_type("text/html").body(layout_body))
tmpl_body
is rendered as an String to HTML body. Is there a away around this?
#[derive(Template)]
struct HelloTemplate<'a> {
name: &'a str,
}
error: proc-macro derive panicked
--> src/main.rs:7:10
|
7 | #[derive(Template)]
| ^^^^^^^^
|
= help: message: called `Option::unwrap()` on a `None` value
{% for x in ["a", "b"] %}
{{ x }}
{% endfor %}
nor
{% let xes = ["a", "b"] %}
{% for x in xes %}
{{ x }}
{% endfor %}
works, which would be intuitively what I'd want to do.
This is mostly for shortening a template where huge parts are redundant, but do not need to be adjustable from within the binary.
The file test.yml
smth
is included by main.yml
:
x:
{% include "test.yml"}
ends up in
x: smth
where it should be
x:
smth
unless I am mistaken.
The path is interpreted as relative to the templates dir in the directory where the originating crate's Cargo.toml resides.
Why? This forces me a 1 way structure, that works bad with my project tree. Please add an option to change the root dir, or better to add multiple ones.
The _loop_indexes
mechanism makes it seem like nested loops are intended to be supported, but I haven't figured it out. Here is what I tried:
{% for y in names %}
{% for x in y %}
x = {{ x }}
{% endfor %}
{% endfor %}
#[derive(Template)]
#[template(path = "test")]
struct Test<'a> {
names: Vec<Vec<&'a str>>,
}
error[E0277]: the trait bound `&&std::vec::Vec<&str>: std::iter::Iterator` is not satisfied
--> src/main.rs:7:10
|
7 | #[derive(Template)]
| ^^^^^^^^ the trait `std::iter::Iterator` is not implemented for `&&std::vec::Vec<&str>`
|
= note: `&&std::vec::Vec<&str>` is not an iterator; maybe try calling `.iter()` or a similar method
= note: required by `std::iter::IntoIterator::into_iter`
It would be helpful to have a copy of the "How to get started" readme section as a fully laid out examples directory where someone could just drop in and do cargo run
and see everything work.
I have a pair of parent/child templates like this:
#[derive(Template)]
#[template(path = "application.conf.j2")]
pub struct ApplicationConf<'a> {
app: &'a AppConfig,
provider: Provider,
}
#[derive(Template)]
#[template(path = "application.conf.openstack")]
struct ApplicationConfOpenStack<'a> {
_parent: ApplicationConf<'a>,
os: &'a OpenStackConfig,
}
And I'd like application.conf.openstack
to be able to use {{app.field}}
rather than {{_parent.app.field}}
. I am accomplishing this by adding this Deref
impl.
impl <'a> ::std::ops::Deref for ApplicationConfOpenStack<'a> {
type Target = ApplicationConf<'a>;
fn deref(&self) -> &Self::Target {
&self._parent
}
}
And it seems to me that the idea of template inheritance lines up pretty well with the intent of Deref
.
In askama/src/lib.rs
we find:
Lines 244 to 248 in 36cbfd4
I added features = ["with-rocket"]
both in the [dependencies]
and [build-dependencies]
section, and this caused the same issue that is seen in rust-lang/cargo#4651; libstd and libproc_macro are linked dynamically and cannot be found, resulting in a binary that runs with cargo run
but not when executed alone.
I eventually tracked down that me having put features = ["with-rocket"]
in the [build-dependencies]
section also was the cause for this.
I suggest that it be specified in the documentation I referenced above that features = ["with-rocket"]
is to be added in the [dependencies]
section only and not in the [build-dependencies]
section.
For some reason, kcov is not picking up correctly on my tests the way they're currently structured. Before 664398b, it worked better, but not great. Ideally, we'd be able to get coverage both from the compiler (as it uses the proc macro) while compiling tests as well as the tests when they're run. It seems like SimonKagstrom/kcov#149 might be relevant.
The compiler fails when not using clone() on a struct field inside of the template.
See https://github.com/greatest-ape/rs_news/tree/askama-template-borrowing-issue
The error occurs in this commit and is fixed with the change in the next commit.
Using rustc 1.22.0-nightly (14039a42a 2017-09-22) on macOS.
It's unclear to me from the documentation what the difference between
{% foo %}
and
{% foo -%}
are.
I've noticed a problem when calling a macro with a parameter name that is the same as the name of a member of the template struct.
Changing the name of the parameter in the macro unit test to param is enough to make it fail with message
error[E0425]: cannot find value
param
in this scope
--> testing\tests\macro.rs:6:10
|
6 | #[derive(Template)]
| ^^^^^^^^ help: try:self.param
error: aborting due to previous error
#[derive(Template)]
#[template(path = "macro.html")]
struct MacroTemplate<'a> {
param: &'a str,
}
#[test]
fn test_macro() {
let t = MacroTemplate { param: "foo" };
assert_eq!(t.render().unwrap(), "foo foo foo");
}
I'm new to using askama, so I apologize if this has been addressed or if I am missing something...
I had a child template set up with a parent template and everything was working as expected.
However, I moved that parent template into a new file (and use
d the parent template in the file containing the child), and I am getting the error:
cannot find trait `TraitFromlayout2ehtml` in this scope
--> src/web/handlers.rs:15:14
|
15 | #[derive(Template)]
| ^^^^^^^^ not found in this scope
help: possible candidate is found in another module, you can import it into scope
|
1 | use web::other::TraitFromlayout2ehtml;
The suggestion doesn't work since that trait is private.
It's not a big deal--I can move the parent template back into the same file. I just wanted to make sure I wasn't missing something, and if this is the case, it would be nice if it was documented somewhere (unless it already is and I missed it).
This is with askama 0.5.0 on nightly-2017-11-27 Rust. Thanks!
'''
error[E0308]: mismatched types
--> /home/mdziardziel/.cargo/registry/src/github.com-1ecc6299db9ec823/askama_shared-0.5.0/src/parser.rs:102:34
|
102 | End(0) => IResult::Error(nom::ErrorKind::Custom(0)),
| ^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| expected enum nom::Err
, found enum nom::ErrorKind
| help: try using a variant of the expected type: nom::Err::Code(nom::ErrorKind::Custom(0))
|
= note: expected type nom::Err<&[u8]>
found type nom::ErrorKind<{integer}>
error[E0308]: mismatched types
--> /home/mdziardziel/.cargo/registry/src/github.com-1ecc6299db9ec823/askama_shared-0.5.0/src/parser.rs:109:31
|
109 | return IResult::Error(nom::ErrorKind::Custom(0));
| ^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| expected enum nom::Err
, found enum nom::ErrorKind
| help: try using a variant of the expected type: nom::Err::Code(nom::ErrorKind::Custom(0))
|
= note: expected type nom::Err<&[u8]>
found type nom::ErrorKind<{integer}>
'''
Simply starting a template file with a single {
character (e.g a JSON file) causes the AST and code to be empty:
[]
impl< 'a > ::askama::Template for ServiceProxyConfig< 'a > {
fn render_to(&self, writer: &mut ::std::fmt::Write) {
}
}
Prepend an extra space or newline and the template renders fine.
# src/main.rs
extern crate askama;
#[macro_use]
use askama::Template;
#[derive(Template)]
#[template(path = "templates/index.html")]
struct IndexTemplate {
name: String,
}
===>
error: cannot find derive macro
Template in this scope
Currently askama throws errors when trying to compare an enum in an if clause (or it is non obvious how to write such an comparison).
The required version of Iron with "with-iron" feature is fixed to 0.5, so that if we try to use the latest version of Iron (0.6), the build fails.
I am not sure whether this is appropriate, but it would be sufficient to relax the version specification;
[dependencies]
...
iron = { version = ">= 0.5", optional = true }
...
(I have checked that this works: dbea895)
In terms of the compatibility, just like iron/staticfile,
iron = { version = ">= 0.5, < 0.7", optional = true }
might be better.
I was checking the jinja documentation regarding newline behaviour (related to #69, looking for a workaround)
http://jinja.pocoo.org/docs/2.10/templates/
and I tried to use {%+ include %}
which was not recognized.
Is this something that is planned/not planned to be implemented?
Whitespace before and after macro blocks are not suppressed even though the suppression is used. The parser supports the syntax but the macro nodes are excluded from the code generation. The solution to this is to include macro nodes in code generation but only for the purpose of whitespace supression.
Example:
#[derive(Template)]
#[template(source = "{% macro foo(bar) %}{% endmacro -%}\nafter", ext="txt")]
struct SuppressTemplate {
}
#[test]
fn test_suppress() {
let t = SuppressTemplate{};
assert_eq!(t.render().unwrap(), "after");
}
Fails with:
´´´
'assertion failed: (left == right)
left: "\nafter"
,
right: "after"
´´´
I don't found it from doc or tests.
I have a project using Tera where I want to use Askama instead. It consists of a library and two executables. After adding the recommended build.rs file, building fails with: error[E0601]: main function not found.
The code in question is available here: https://github.com/greatest-ape/rs_news/tree/askama , see commit bff1d68f12c786a3a37f8cc5739e90ed73daa834.
I run macOS 10.10.5, rustc 1.22.0-nightly (0701b37d9 2017-09-18), but I get the same error on Debian.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.