mirror of
https://github.com/askama-rs/askama.git
synced 2025-10-01 15:00:57 +00:00
Add scope when importing macros
This commit is contained in:
parent
5333a52ca2
commit
a32532d5ae
@ -12,7 +12,7 @@ use std::collections::{HashMap, HashSet};
|
|||||||
use syn;
|
use syn;
|
||||||
|
|
||||||
|
|
||||||
pub fn generate(input: &TemplateInput, nodes: &[Node], imported: &HashMap<&str, Macro>) -> String {
|
pub fn generate(input: &TemplateInput, nodes: &[Node], imported: &HashMap<(&str, &str), Macro>) -> String {
|
||||||
Generator::default().build(&State::new(input, nodes, imported))
|
Generator::default().build(&State::new(input, nodes, imported))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ struct State<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> State<'a> {
|
impl<'a> State<'a> {
|
||||||
fn new<'n>(input: &'n TemplateInput, nodes: &'n [Node], imported: &'n HashMap<&'n str, Macro<'n>>) -> State<'n> {
|
fn new<'n>(input: &'n TemplateInput, nodes: &'n [Node], imported: &'n HashMap<(&'n str, &'n str), Macro<'n>>) -> State<'n> {
|
||||||
let mut base: Option<&Expr> = None;
|
let mut base: Option<&Expr> = None;
|
||||||
let mut blocks = Vec::new();
|
let mut blocks = Vec::new();
|
||||||
let mut macros = HashMap::new();
|
let mut macros = HashMap::new();
|
||||||
@ -42,13 +42,13 @@ impl<'a> State<'a> {
|
|||||||
blocks.push(def);
|
blocks.push(def);
|
||||||
},
|
},
|
||||||
Node::Macro(name, ref m) => {
|
Node::Macro(name, ref m) => {
|
||||||
macros.insert(name, m);
|
macros.insert((None, name), m);
|
||||||
},
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (name, ref m) in imported {
|
for (&(scope, name), ref m) in imported {
|
||||||
macros.insert(name, m);
|
macros.insert((Some(scope), name), m);
|
||||||
}
|
}
|
||||||
State {
|
State {
|
||||||
input,
|
input,
|
||||||
@ -351,7 +351,7 @@ impl<'a> Generator<'a> {
|
|||||||
Node::Include(ref ws, path) => {
|
Node::Include(ref ws, path) => {
|
||||||
self.handle_include(state, ws, path);
|
self.handle_include(state, ws, path);
|
||||||
},
|
},
|
||||||
Node::Call(ref ws, name, ref args) => self.write_call(state, ws, name, args),
|
Node::Call(ref ws, scope, name, ref args) => self.write_call(state, ws, scope, name, args),
|
||||||
Node::Macro(_, ref m) => {
|
Node::Macro(_, ref m) => {
|
||||||
if let AstLevel::Nested = level {
|
if let AstLevel::Nested = level {
|
||||||
panic!("macro blocks only allowed at the top level");
|
panic!("macro blocks only allowed at the top level");
|
||||||
@ -359,7 +359,7 @@ impl<'a> Generator<'a> {
|
|||||||
self.flush_ws(&m.ws1);
|
self.flush_ws(&m.ws1);
|
||||||
self.prepare_ws(&m.ws2);
|
self.prepare_ws(&m.ws2);
|
||||||
},
|
},
|
||||||
Node::Import(ref ws, _) => {
|
Node::Import(ref ws, _, _) => {
|
||||||
if let AstLevel::Nested = level {
|
if let AstLevel::Nested = level {
|
||||||
panic!("import blocks only allowed at the top level");
|
panic!("import blocks only allowed at the top level");
|
||||||
}
|
}
|
||||||
@ -446,8 +446,14 @@ impl<'a> Generator<'a> {
|
|||||||
self.locals.pop();
|
self.locals.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_call(&mut self, state: &'a State, ws: &WS, name: &str, args: &[Expr]) {
|
fn write_call(&mut self, state: &'a State, ws: &WS, scope: Option<&str>, name: &str, args: &[Expr]) {
|
||||||
let def = state.macros.get(name).expect(&format!("macro '{}' not found", name));
|
let def = state.macros.get(&(scope, name)).unwrap_or_else(|| {
|
||||||
|
if let Some(ref s) = scope {
|
||||||
|
panic!(format!("macro '{}::{}' not found", s, name));
|
||||||
|
} else {
|
||||||
|
panic!(format!("macro '{}' not found", name));
|
||||||
|
}
|
||||||
|
});
|
||||||
self.flush_ws(ws); // Cannot handle_ws() here: whitespace from macro definition comes first
|
self.flush_ws(ws); // Cannot handle_ws() here: whitespace from macro definition comes first
|
||||||
self.locals.push();
|
self.locals.push();
|
||||||
self.writeln("{");
|
self.writeln("{");
|
||||||
@ -812,4 +818,4 @@ enum DisplayWrap {
|
|||||||
Unwrapped,
|
Unwrapped,
|
||||||
}
|
}
|
||||||
|
|
||||||
type MacroMap<'a> = HashMap<&'a str, &'a Macro<'a>>;
|
type MacroMap<'a> = HashMap<(Option<&'a str>, &'a str), &'a Macro<'a>>;
|
||||||
|
@ -50,17 +50,17 @@ pub fn build_template(ast: &syn::DeriveInput) -> String {
|
|||||||
|
|
||||||
|
|
||||||
pub struct Imports<'a> {
|
pub struct Imports<'a> {
|
||||||
pub sources: Vec<Cow<'a, str>>
|
pub sources: HashMap<&'a str, Cow<'a, str>>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'a> Imports<'a> {
|
impl <'a> Imports<'a> {
|
||||||
pub fn new(parent_nodes: &'a [Node], parent_path: &'a Path) -> Imports<'a> {
|
pub fn new(parent_nodes: &'a [Node], parent_path: &'a Path) -> Imports<'a> {
|
||||||
let sources = parent_nodes.iter().filter_map(|n| {
|
let sources = parent_nodes.iter().filter_map(|n| {
|
||||||
match *n {
|
match *n {
|
||||||
Node::Import(_, ref import_path) => {
|
Node::Import(_, ref import_path, scope) => {
|
||||||
let path = path::find_template_from_path(import_path, Some(parent_path));
|
let path = path::find_template_from_path(import_path, Some(parent_path));
|
||||||
let src = path::get_template_source(&path);
|
let src = path::get_template_source(&path);
|
||||||
Some(Cow::Owned(src))
|
Some((scope, Cow::Owned(src)))
|
||||||
},
|
},
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
@ -68,15 +68,17 @@ impl <'a> Imports<'a> {
|
|||||||
Imports { sources }
|
Imports { sources }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn macro_map(&'a self) -> HashMap<&'a str, Macro<'a>> {
|
pub fn macro_map(&'a self) -> HashMap<(&'a str, &'a str), Macro<'a>> {
|
||||||
self.sources.iter()
|
let mut macro_map = HashMap::new();
|
||||||
.flat_map(|s| parser::parse(s.as_ref()))
|
for (scope, s) in self.sources.iter() {
|
||||||
.filter_map(|n| {
|
for n in parser::parse(&s.as_ref()) {
|
||||||
match n {
|
match n {
|
||||||
Node::Macro(name, m) => Some((name, m)),
|
Node::Macro(name, m) => macro_map.insert((*scope, name), m),
|
||||||
_ => None,
|
_ => None,
|
||||||
}})
|
};
|
||||||
.collect()
|
}
|
||||||
|
}
|
||||||
|
macro_map
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ pub enum Node<'a> {
|
|||||||
Lit(&'a str, &'a str, &'a str),
|
Lit(&'a str, &'a str, &'a str),
|
||||||
Comment(),
|
Comment(),
|
||||||
Expr(WS, Expr<'a>),
|
Expr(WS, Expr<'a>),
|
||||||
Call(WS, &'a str, Vec<Expr<'a>>),
|
Call(WS, Option<& 'a str>, &'a str, Vec<Expr<'a>>),
|
||||||
LetDecl(WS, Target<'a>),
|
LetDecl(WS, Target<'a>),
|
||||||
Let(WS, Target<'a>, Expr<'a>),
|
Let(WS, Target<'a>, Expr<'a>),
|
||||||
Cond(Vec<(WS, Option<Expr<'a>>, Vec<Node<'a>>)>, WS),
|
Cond(Vec<(WS, Option<Expr<'a>>, Vec<Node<'a>>)>, WS),
|
||||||
@ -43,7 +43,7 @@ pub enum Node<'a> {
|
|||||||
Extends(Expr<'a>),
|
Extends(Expr<'a>),
|
||||||
BlockDef(WS, &'a str, Vec<Node<'a>>, WS),
|
BlockDef(WS, &'a str, Vec<Node<'a>>, WS),
|
||||||
Include(WS, &'a str),
|
Include(WS, &'a str),
|
||||||
Import(WS, &'a str),
|
Import(WS, &'a str, &'a str),
|
||||||
Macro(&'a str, Macro<'a>),
|
Macro(&'a str, Macro<'a>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,10 +296,15 @@ named!(expr_node<Node>, do_parse!(
|
|||||||
named!(block_call<Node>, do_parse!(
|
named!(block_call<Node>, do_parse!(
|
||||||
pws: opt!(tag_s!("-")) >>
|
pws: opt!(tag_s!("-")) >>
|
||||||
ws!(tag_s!("call")) >>
|
ws!(tag_s!("call")) >>
|
||||||
|
scope: opt!(do_parse!(
|
||||||
|
scope: ws!(identifier) >>
|
||||||
|
ws!(tag_s!("::")) >>
|
||||||
|
(scope)
|
||||||
|
)) >>
|
||||||
name: ws!(identifier) >>
|
name: ws!(identifier) >>
|
||||||
args: ws!(arguments) >>
|
args: ws!(arguments) >>
|
||||||
nws: opt!(tag_s!("-")) >>
|
nws: opt!(tag_s!("-")) >>
|
||||||
(Node::Call(WS(pws.is_some(), nws.is_some()), name, args))
|
(Node::Call(WS(pws.is_some(), nws.is_some()), scope, name, args))
|
||||||
));
|
));
|
||||||
|
|
||||||
named!(cond_if<Expr>, do_parse!(
|
named!(cond_if<Expr>, do_parse!(
|
||||||
@ -411,11 +416,13 @@ named!(block_import<Node>, do_parse!(
|
|||||||
pws: opt!(tag_s!("-")) >>
|
pws: opt!(tag_s!("-")) >>
|
||||||
ws!(tag_s!("import")) >>
|
ws!(tag_s!("import")) >>
|
||||||
name: ws!(expr_str_lit) >>
|
name: ws!(expr_str_lit) >>
|
||||||
|
ws!(tag_s!("as")) >>
|
||||||
|
scope: ws!(identifier) >>
|
||||||
nws: opt!(tag_s!("-")) >>
|
nws: opt!(tag_s!("-")) >>
|
||||||
(Node::Import(WS(pws.is_some(), nws.is_some()), match name {
|
(Node::Import(WS(pws.is_some(), nws.is_some()), match name {
|
||||||
Expr::StrLit(s) => s,
|
Expr::StrLit(s) => s,
|
||||||
_ => panic!("import path must be a string literal"),
|
_ => panic!("import path must be a string literal"),
|
||||||
}))
|
}, scope))
|
||||||
));
|
));
|
||||||
|
|
||||||
named!(block_macro<Node>, do_parse!(
|
named!(block_macro<Node>, do_parse!(
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
|
|
||||||
{%- import "macro.html" -%}
|
{%- import "macro.html" as scope -%}
|
||||||
|
|
||||||
{% call thrice(s) %}
|
{% call scope::thrice(s) %}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user