aboutsummaryrefslogtreecommitdiffstats
path: root/askama_shared
diff options
context:
space:
mode:
authorLibravatar larros <larserik.rosengren@gmail.com>2017-09-26 10:02:44 +0200
committerLibravatar Dirkjan Ochtman <dirkjan@ochtman.nl>2017-09-26 10:02:44 +0200
commitdf58dcb49db77b2c283db3c9a8a738bdff3a8e37 (patch)
tree0de4a117d1e97216381b8336a1cec826e894d075 /askama_shared
parent4e919e47539b5fa346f1cac323ab250558b834bc (diff)
downloadaskama-df58dcb49db77b2c283db3c9a8a738bdff3a8e37.tar.gz
askama-df58dcb49db77b2c283db3c9a8a738bdff3a8e37.tar.bz2
askama-df58dcb49db77b2c283db3c9a8a738bdff3a8e37.zip
Add support for importing template files with macros (#51)
* Fix review comments for macro imports
Diffstat (limited to '')
-rw-r--r--askama_shared/src/generator.rs10
-rw-r--r--askama_shared/src/lib.rs43
-rw-r--r--askama_shared/src/parser.rs13
3 files changed, 62 insertions, 4 deletions
diff --git a/askama_shared/src/generator.rs b/askama_shared/src/generator.rs
index e92a2c6..e135c13 100644
--- a/askama_shared/src/generator.rs
+++ b/askama_shared/src/generator.rs
@@ -12,8 +12,8 @@ use std::collections::{HashMap, HashSet};
use syn;
-pub fn generate(input: &TemplateInput, nodes: &[Node]) -> String {
- Generator::default().build(&State::new(input, nodes))
+pub fn generate(input: &TemplateInput, nodes: &[Node], imported: &HashMap<&str, Macro>) -> String {
+ Generator::default().build(&State::new(input, nodes, imported))
}
struct State<'a> {
@@ -26,7 +26,7 @@ struct State<'a> {
}
impl<'a> State<'a> {
- fn new<'n>(input: &'n TemplateInput, nodes: &'n [Node]) -> State<'n> {
+ fn new<'n>(input: &'n TemplateInput, nodes: &'n [Node], imported: &'n HashMap<&'n str, Macro<'n>>) -> State<'n> {
let mut base: Option<&Expr> = None;
let mut blocks = Vec::new();
let mut macros = HashMap::new();
@@ -47,6 +47,9 @@ impl<'a> State<'a> {
_ => {},
}
}
+ for (name, ref m) in imported {
+ macros.insert(name, m);
+ }
State {
input,
nodes,
@@ -351,6 +354,7 @@ impl<'a> Generator<'a> {
},
Node::Call(ref ws, name, ref args) => self.write_call(state, ws, name, args),
Node::Macro(_, _) |
+ Node::Import(_, _) |
Node::Extends(_) => {
if let AstLevel::Nested = level {
panic!("macro or extend blocks only allowed at the top level");
diff --git a/askama_shared/src/lib.rs b/askama_shared/src/lib.rs
index 066faca..a7deaff 100644
--- a/askama_shared/src/lib.rs
+++ b/askama_shared/src/lib.rs
@@ -21,7 +21,11 @@ mod input;
mod parser;
use input::Print;
+use parser::{Node, Macro};
+use std::borrow::Cow;
+use std::collections::HashMap;
+use std::path::Path;
/// Takes a `syn::DeriveInput` and generates source code for it
///
@@ -33,16 +37,53 @@ use input::Print;
pub fn build_template(ast: &syn::DeriveInput) -> String {
let data = input::TemplateInput::new(ast);
let nodes = parser::parse(data.source.as_ref());
+ let imports = Imports::new(&nodes, &data.path);
+ let imported = imports.parse();
if data.meta.print == Print::Ast || data.meta.print == Print::All {
println!("{:?}", nodes);
}
- let code = generator::generate(&data, &nodes);
+ let code = generator::generate(&data, &nodes, &imported);
if data.meta.print == Print::Code || data.meta.print == Print::All {
println!("{}", code);
}
code
}
+
+pub struct Imports<'a> {
+ pub sources: Vec<Cow<'a, str>>
+}
+
+impl <'a> Imports<'a> {
+ pub fn new(parent_nodes: &'a [Node], parent_path: &'a Path) -> Imports<'a> {
+ let sources = parent_nodes.iter().filter_map(|n| {
+ match *n {
+ Node::Import(_, ref import_path) => {
+ let path = path::find_template_from_path(import_path, Some(parent_path));
+ let src = path::get_template_source(&path);
+ Some(Cow::Owned(src))
+ },
+ _ => None,
+ }
+ }).collect();
+ Imports {
+ sources,
+ }
+ }
+
+ pub fn parse(&'a self) -> HashMap<&'a str, Macro<'a>> {
+ self.sources.iter()
+ .flat_map(|s| parser::parse(s.as_ref()))
+ .filter_map(|n| {
+ match n {
+ Node::Macro(name, m) => Some((name, m)),
+ _ => None,
+ }})
+ .collect()
+ }
+}
+
+
mod errors {
error_chain! {
foreign_links {
diff --git a/askama_shared/src/parser.rs b/askama_shared/src/parser.rs
index ab79a31..083e96b 100644
--- a/askama_shared/src/parser.rs
+++ b/askama_shared/src/parser.rs
@@ -42,6 +42,7 @@ pub enum Node<'a> {
Extends(Expr<'a>),
BlockDef(WS, &'a str, Vec<Node<'a>>, WS),
Include(WS, &'a str),
+ Import(WS, &'a str),
Macro(&'a str, Macro<'a>),
}
@@ -388,6 +389,17 @@ named!(block_include<Node>, do_parse!(
}))
));
+named!(block_import<Node>, do_parse!(
+ pws: opt!(tag_s!("-")) >>
+ ws!(tag_s!("import")) >>
+ name: ws!(expr_str_lit) >>
+ nws: opt!(tag_s!("-")) >>
+ (Node::Import(WS(pws.is_some(), nws.is_some()), match name {
+ Expr::StrLit(s) => s,
+ _ => panic!("import path must be a string literal"),
+ }))
+));
+
named!(block_macro<Node>, do_parse!(
pws1: opt!(tag_s!("-")) >>
ws!(tag_s!("macro")) >>
@@ -420,6 +432,7 @@ named!(block_node<Node>, do_parse!(
block_for |
block_extends |
block_include |
+ block_import |
block_block |
block_macro
) >>