mirror of
https://github.com/askama-rs/askama.git
synced 2025-10-02 15:25:19 +00:00
Implement generator support for whitespace handling markers
This commit is contained in:
parent
38c31ee4bd
commit
06bd6ef634
@ -1,4 +1,4 @@
|
|||||||
use parser::{Cond, Expr, Node, Target};
|
use parser::{Cond, Expr, Node, Target, WS};
|
||||||
use std::str;
|
use std::str;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use syn;
|
use syn;
|
||||||
@ -28,21 +28,25 @@ fn path_as_identifier(s: &str) -> String {
|
|||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Generator {
|
struct Generator<'a> {
|
||||||
buf: String,
|
buf: String,
|
||||||
indent: u8,
|
indent: u8,
|
||||||
start: bool,
|
start: bool,
|
||||||
locals: HashSet<String>,
|
locals: HashSet<String>,
|
||||||
|
next_ws: Option<&'a str>,
|
||||||
|
skip_ws: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Generator {
|
impl<'a> Generator<'a> {
|
||||||
|
|
||||||
fn new() -> Generator {
|
fn new() -> Generator<'a> {
|
||||||
Generator {
|
Generator {
|
||||||
buf: String::new(),
|
buf: String::new(),
|
||||||
indent: 0,
|
indent: 0,
|
||||||
start: true,
|
start: true,
|
||||||
locals: HashSet::new(),
|
locals: HashSet::new(),
|
||||||
|
next_ws: None,
|
||||||
|
skip_ws: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,20 +121,42 @@ impl Generator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_lit(&mut self, lws: &str, val: &str, rws: &str) {
|
fn flush_ws(&mut self, ws: &WS) {
|
||||||
self.write(&format!("writer.write_str({:#?}).unwrap();", lws));
|
if self.next_ws.is_some() && !ws.0 {
|
||||||
|
let val = self.next_ws.unwrap();
|
||||||
self.write(&format!("writer.write_str({:#?}).unwrap();", val));
|
self.write(&format!("writer.write_str({:#?}).unwrap();", val));
|
||||||
self.write(&format!("writer.write_str({:#?}).unwrap();", rws));
|
self.next_ws = None;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_expr(&mut self, s: &Expr) {
|
fn prepare_ws(&mut self, ws: &WS) {
|
||||||
|
self.skip_ws = ws.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_ws(&mut self, ws: &WS) {
|
||||||
|
self.flush_ws(ws);
|
||||||
|
self.prepare_ws(ws);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_lit(&mut self, lws: &str, val: &str, rws: &'a str) {
|
||||||
|
assert!(self.next_ws.is_none());
|
||||||
|
if !self.skip_ws {
|
||||||
|
self.write(&format!("writer.write_str({:#?}).unwrap();", lws));
|
||||||
|
}
|
||||||
|
self.write(&format!("writer.write_str({:#?}).unwrap();", val));
|
||||||
|
self.next_ws = Some(rws);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_expr(&mut self, ws: &WS, s: &Expr) {
|
||||||
|
self.handle_ws(ws);
|
||||||
self.write("writer.write_fmt(format_args!(\"{}\", ");
|
self.write("writer.write_fmt(format_args!(\"{}\", ");
|
||||||
self.visit_expr(s);
|
self.visit_expr(s);
|
||||||
self.writeln(")).unwrap();");
|
self.writeln(")).unwrap();");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_cond(&mut self, conds: &[Cond]) {
|
fn write_cond(&mut self, conds: &'a [Cond], ws: &WS) {
|
||||||
for (i, &(_, ref cond, ref nodes)) in conds.iter().enumerate() {
|
for (i, &(ref cws, ref cond, ref nodes)) in conds.iter().enumerate() {
|
||||||
|
self.handle_ws(cws);
|
||||||
match *cond {
|
match *cond {
|
||||||
Some(ref expr) => {
|
Some(ref expr) => {
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
@ -147,11 +173,14 @@ impl Generator {
|
|||||||
self.handle(nodes);
|
self.handle(nodes);
|
||||||
self.dedent();
|
self.dedent();
|
||||||
}
|
}
|
||||||
|
self.handle_ws(ws);
|
||||||
self.writeln("}");
|
self.writeln("}");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_loop(&mut self, var: &Target, iter: &Expr, body: &[Node]) {
|
fn write_loop(&mut self, ws1: &WS, var: &Target, iter: &Expr,
|
||||||
|
body: &'a [Node], ws2: &WS) {
|
||||||
|
|
||||||
|
self.handle_ws(ws1);
|
||||||
self.write("for ");
|
self.write("for ");
|
||||||
let targets = self.visit_target(var);
|
let targets = self.visit_target(var);
|
||||||
for name in &targets {
|
for name in &targets {
|
||||||
@ -164,6 +193,7 @@ impl Generator {
|
|||||||
|
|
||||||
self.indent();
|
self.indent();
|
||||||
self.handle(body);
|
self.handle(body);
|
||||||
|
self.handle_ws(ws2);
|
||||||
self.dedent();
|
self.dedent();
|
||||||
self.writeln("}");
|
self.writeln("}");
|
||||||
for name in &targets {
|
for name in &targets {
|
||||||
@ -171,33 +201,42 @@ impl Generator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_block(&mut self, name: &str) {
|
fn write_block(&mut self, ws1: &WS, name: &str, ws2: &WS) {
|
||||||
|
self.flush_ws(ws1);
|
||||||
self.writeln(&format!("self.render_block_{}_into(writer);", name));
|
self.writeln(&format!("self.render_block_{}_into(writer);", name));
|
||||||
|
self.prepare_ws(ws2);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_block_def(&mut self, name: &str, nodes: &[Node]) {
|
fn write_block_def(&mut self, ws1: &WS, name: &str, nodes: &'a [Node],
|
||||||
|
ws2: &WS) {
|
||||||
self.writeln("#[allow(unused_variables)]");
|
self.writeln("#[allow(unused_variables)]");
|
||||||
self.writeln(&format!(
|
self.writeln(&format!(
|
||||||
"fn render_block_{}_into(&self, writer: &mut std::fmt::Write) {{",
|
"fn render_block_{}_into(&self, writer: &mut std::fmt::Write) {{",
|
||||||
name));
|
name));
|
||||||
self.indent();
|
self.indent();
|
||||||
|
self.prepare_ws(ws1);
|
||||||
self.handle(nodes);
|
self.handle(nodes);
|
||||||
|
self.flush_ws(ws2);
|
||||||
self.dedent();
|
self.dedent();
|
||||||
self.writeln("}");
|
self.writeln("}");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle(&mut self, nodes: &[Node]) {
|
fn handle(&mut self, nodes: &'a [Node]) {
|
||||||
for n in nodes {
|
for n in nodes {
|
||||||
match *n {
|
match *n {
|
||||||
Node::Lit(lws, val, rws) => { self.write_lit(lws, val, rws); }
|
Node::Lit(lws, val, rws) => { self.write_lit(lws, val, rws); }
|
||||||
Node::Expr(_, ref val) => { self.write_expr(val); },
|
Node::Expr(ref ws, ref val) => { self.write_expr(ws, val); },
|
||||||
Node::Cond(ref conds, _) => { self.write_cond(conds); },
|
Node::Cond(ref conds, ref ws) => {
|
||||||
Node::Loop(_, ref var, ref iter, ref body, _) => {
|
self.write_cond(conds, ws);
|
||||||
self.write_loop(var, iter, body);
|
|
||||||
},
|
},
|
||||||
Node::Block(_, name, _) => { self.write_block(name) },
|
Node::Loop(ref ws1, ref var, ref iter, ref body, ref ws2) => {
|
||||||
Node::BlockDef(_, name, ref block_nodes, _) => {
|
self.write_loop(ws1, var, iter, body, ws2);
|
||||||
self.write_block_def(name, block_nodes);
|
},
|
||||||
|
Node::Block(ref ws1, name, ref ws2) => {
|
||||||
|
self.write_block(ws1, name, ws2);
|
||||||
|
},
|
||||||
|
Node::BlockDef(ref ws1, name, ref block_nodes, ref ws2) => {
|
||||||
|
self.write_block_def(ws1, name, block_nodes, ws2);
|
||||||
}
|
}
|
||||||
Node::Extends(_) => {
|
Node::Extends(_) => {
|
||||||
panic!("no extends or block definition allowed in content");
|
panic!("no extends or block definition allowed in content");
|
||||||
@ -216,7 +255,7 @@ impl Generator {
|
|||||||
self.writeln(&s);
|
self.writeln(&s);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn template_impl(&mut self, ast: &syn::DeriveInput, nodes: &[Node]) {
|
fn template_impl(&mut self, ast: &syn::DeriveInput, nodes: &'a [Node]) {
|
||||||
let anno = annotations(&ast.generics);
|
let anno = annotations(&ast.generics);
|
||||||
self.writeln(&format!("impl{} askama::Template for {}{} {{",
|
self.writeln(&format!("impl{} askama::Template for {}{} {{",
|
||||||
anno, ast.ident.as_ref(), anno));
|
anno, ast.ident.as_ref(), anno));
|
||||||
@ -225,6 +264,7 @@ impl Generator {
|
|||||||
self.writeln("fn render_into(&self, writer: &mut std::fmt::Write) {");
|
self.writeln("fn render_into(&self, writer: &mut std::fmt::Write) {");
|
||||||
self.indent();
|
self.indent();
|
||||||
self.handle(nodes);
|
self.handle(nodes);
|
||||||
|
self.flush_ws(&WS(false, false));
|
||||||
self.dedent();
|
self.dedent();
|
||||||
self.writeln("}");
|
self.writeln("}");
|
||||||
|
|
||||||
@ -232,13 +272,14 @@ impl Generator {
|
|||||||
self.writeln("}");
|
self.writeln("}");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trait_impl(&mut self, ast: &syn::DeriveInput, base: &str, blocks: &[Node]) {
|
fn trait_impl(&mut self, ast: &syn::DeriveInput, base: &str, blocks: &'a [Node]) {
|
||||||
let anno = annotations(&ast.generics);
|
let anno = annotations(&ast.generics);
|
||||||
self.writeln(&format!("impl{} TraitFrom{} for {}{} {{",
|
self.writeln(&format!("impl{} TraitFrom{} for {}{} {{",
|
||||||
anno, path_as_identifier(base),
|
anno, path_as_identifier(base),
|
||||||
ast.ident.as_ref(), anno));
|
ast.ident.as_ref(), anno));
|
||||||
self.indent();
|
self.indent();
|
||||||
self.handle(blocks);
|
self.handle(blocks);
|
||||||
|
self.flush_ws(&WS(false, false));
|
||||||
self.dedent();
|
self.dedent();
|
||||||
self.writeln("}");
|
self.writeln("}");
|
||||||
}
|
}
|
||||||
@ -260,7 +301,7 @@ impl Generator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn template_trait(&mut self, ast: &syn::DeriveInput, path: &str,
|
fn template_trait(&mut self, ast: &syn::DeriveInput, path: &str,
|
||||||
blocks: &[Node], nodes: &[Node]) {
|
blocks: &'a [Node], nodes: &'a [Node]) {
|
||||||
let anno = annotations(&ast.generics);
|
let anno = annotations(&ast.generics);
|
||||||
self.writeln(&format!("trait{} TraitFrom{}{} {{", anno,
|
self.writeln(&format!("trait{} TraitFrom{}{} {{", anno,
|
||||||
path_as_identifier(path), anno));
|
path_as_identifier(path), anno));
|
||||||
@ -271,6 +312,7 @@ impl Generator {
|
|||||||
self.writeln("fn render_trait_into(&self, writer: &mut std::fmt::Write) {");
|
self.writeln("fn render_trait_into(&self, writer: &mut std::fmt::Write) {");
|
||||||
self.indent();
|
self.indent();
|
||||||
self.handle(nodes);
|
self.handle(nodes);
|
||||||
|
self.flush_ws(&WS(false, false));
|
||||||
self.dedent();
|
self.dedent();
|
||||||
self.writeln("}");
|
self.writeln("}");
|
||||||
|
|
||||||
@ -304,6 +346,7 @@ pub fn generate(ast: &syn::DeriveInput, path: &str, mut nodes: Vec<Node>) -> Str
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let empty = Vec::new();
|
||||||
let mut gen = Generator::new();
|
let mut gen = Generator::new();
|
||||||
gen.path_based_name(ast, path);
|
gen.path_based_name(ast, path);
|
||||||
if !blocks.is_empty() {
|
if !blocks.is_empty() {
|
||||||
@ -313,7 +356,7 @@ pub fn generate(ast: &syn::DeriveInput, path: &str, mut nodes: Vec<Node>) -> Str
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
gen.template_trait(ast, path, &blocks, &content);
|
gen.template_trait(ast, path, &blocks, &content);
|
||||||
gen.trait_impl(ast, path, &Vec::new());
|
gen.trait_impl(ast, path, &empty);
|
||||||
}
|
}
|
||||||
gen.trait_based_impl(ast);
|
gen.trait_based_impl(ast);
|
||||||
} else {
|
} else {
|
||||||
|
@ -13,7 +13,7 @@ pub enum Target<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct WS(bool, bool);
|
pub struct WS(pub bool, pub bool);
|
||||||
|
|
||||||
pub enum Node<'a> {
|
pub enum Node<'a> {
|
||||||
Lit(&'a str, &'a str, &'a str),
|
Lit(&'a str, &'a str, &'a str),
|
||||||
|
@ -1,6 +1,48 @@
|
|||||||
{% if a == b %}t{% endif %}{% if a == c %}t{% else %}f{% endif %}
|
{% if a == b -%}
|
||||||
{% if a != c %}t{% endif %}{% if a != b %}t{% else %}f{% endif %}
|
t
|
||||||
{% if c >= b %}t{% endif %}{% if b >= c %}t{% else %}f{% endif %}
|
{%- endif -%}
|
||||||
{% if c > b %}t{% endif %}{% if a > c %}t{% else %}f{% endif %}
|
{% if a == c -%}
|
||||||
{% if a <= b %}t{% endif %}{% if c <= b %}t{% else %}f{% endif %}
|
t
|
||||||
{% if a < c %}t{% endif %}{% if a < b %}t{% else %}f{% endif %}
|
{%- else -%}
|
||||||
|
f
|
||||||
|
{%- endif %}
|
||||||
|
{% if a != c -%}
|
||||||
|
t
|
||||||
|
{%- endif %}
|
||||||
|
{%- if a != b -%}
|
||||||
|
t
|
||||||
|
{%- else -%}
|
||||||
|
f
|
||||||
|
{%- endif %}
|
||||||
|
{% if c >= b -%}
|
||||||
|
t
|
||||||
|
{%- endif -%}
|
||||||
|
{% if b >= c -%}
|
||||||
|
t
|
||||||
|
{%- else -%}
|
||||||
|
f
|
||||||
|
{%- endif %}
|
||||||
|
{% if c > b -%}
|
||||||
|
t
|
||||||
|
{%- endif -%}
|
||||||
|
{% if a > c -%}
|
||||||
|
t
|
||||||
|
{%- else -%}
|
||||||
|
f
|
||||||
|
{%- endif %}
|
||||||
|
{% if a <= b %}
|
||||||
|
t
|
||||||
|
{% endif -%}
|
||||||
|
{% if c <= b -%}
|
||||||
|
t
|
||||||
|
{%- else -%}
|
||||||
|
f
|
||||||
|
{%- endif %}
|
||||||
|
{% if a < c -%}
|
||||||
|
t
|
||||||
|
{%- endif %}
|
||||||
|
{%- if a < b -%}
|
||||||
|
t
|
||||||
|
{%- else -%}
|
||||||
|
f
|
||||||
|
{%- endif %}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user