General structure to the rendering code.

This commit is contained in:
Tom Alexander 2020-05-31 21:18:54 -04:00
parent 680fc167ea
commit da6655d4b6
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE

View File

@ -1,12 +1,20 @@
use crate::parser::template;
use crate::parser::Body;
use crate::parser::DustTag;
use crate::parser::PartialNameElement;
use crate::parser::Path;
use crate::parser::Template;
use crate::parser::TemplateElement;
use crate::renderer::breadcrumb_tree::BreadcrumbTree;
use crate::renderer::breadcrumb_tree::BreadcrumbTreeElement;
use crate::renderer::context_element::ContextElement;
use crate::renderer::context_element::IntoContextElement;
use crate::renderer::errors::CompileError;
use crate::renderer::errors::RenderError;
use crate::renderer::inline_partial_tree::extract_inline_partials;
use crate::renderer::inline_partial_tree::InlinePartialTreeElement;
use crate::renderer::tree_walking::walk_path;
use std::borrow::Borrow;
use std::collections::HashMap;
#[derive(Clone, Debug)]
@ -32,6 +40,103 @@ impl<'a> DustRenderer<'a> {
self.templates.insert(name, template);
}
pub fn render<C>(&'a self, name: &str, context: Option<&C>) -> Result<String, RenderError>
where
C: IntoContextElement,
{
let breadcrumbs =
context.map(|ctx| BreadcrumbTree::new(None, BreadcrumbTreeElement::Borrowed(ctx)));
self.render_template(name, breadcrumbs.as_ref(), None)
}
pub fn render_template(
&'a self,
name: &str,
breadcrumbs: Option<&'a BreadcrumbTree>,
blocks: Option<&'a InlinePartialTreeElement<'a>>,
) -> Result<String, RenderError> {
let main_template = match self.templates.get(name) {
Some(tmpl) => tmpl,
None => {
return Err(RenderError::TemplateNotFound(name.to_owned()));
}
};
let extracted_inline_partials = extract_inline_partials(main_template);
let new_blocks = InlinePartialTreeElement::new(blocks, extracted_inline_partials);
let new_block_context = BlockContext {
breadcrumbs: breadcrumbs,
blocks: &new_blocks,
};
self.render_body(&main_template.contents, breadcrumbs, &new_block_context)
}
fn render_maybe_body(
&'a self,
body: &'a Option<Body>,
breadcrumbs: Option<&'a BreadcrumbTree>,
blocks: &'a BlockContext<'a>,
) -> Result<String, RenderError> {
match body {
None => Ok("".to_owned()),
Some(body) => Ok(self.render_body(body, breadcrumbs, blocks)?),
}
}
fn render_body(
&'a self,
body: &'a Body,
breadcrumbs: Option<&'a BreadcrumbTree>,
blocks: &'a BlockContext<'a>,
) -> Result<String, RenderError> {
let mut output = String::new();
for elem in &body.elements {
match elem {
TemplateElement::TEIgnoredWhitespace(_) => {}
TemplateElement::TESpan(span) => output.push_str(span.contents),
TemplateElement::TETag(dt) => {
output.push_str(&self.render_tag(dt, breadcrumbs, blocks)?);
}
}
}
Ok(output)
}
/// For rendering a dynamic partial's name or an rvalue template
pub fn render_partial_name(
&'a self,
body: &'a Vec<PartialNameElement>,
breadcrumbs: Option<&'a BreadcrumbTree>,
) -> Result<String, RenderError> {
let converted_to_template_elements: Vec<TemplateElement<'a>> =
body.into_iter().map(|e| e.into()).collect();
// Simple templates like partial names and reference rvalues
// cannot contain blocks or inline partials, so we use a blank
// BlockContext.
let empty_block_context = BlockContext {
breadcrumbs: None,
blocks: &InlinePartialTreeElement::new(None, HashMap::new()),
};
self.render_body(
&Body {
elements: converted_to_template_elements,
},
breadcrumbs,
&empty_block_context,
)
}
fn render_tag(
&'a self,
tag: &'a DustTag,
breadcrumbs: Option<&'a BreadcrumbTree>,
blocks: &'a BlockContext<'a>,
) -> Result<String, RenderError> {
match tag {
_ => panic!("Unsupported tag"),
}
Ok("".to_owned())
}
/// Returns a option of a tuple of (parent, new_node_elements)
/// which can then be formed into new BreadcrumbTreeNodes
///
@ -42,8 +147,8 @@ impl<'a> DustRenderer<'a> {
/// explicit contexts) and the additional node elements (which may
/// be empty) should be combined into a final BreadcrumbTreeNode
fn new_breadcrumbs_section<'b>(
&self,
maybe_breadcrumbs: Option<&'a BreadcrumbTree>,
&'b self,
maybe_breadcrumbs: Option<&'b BreadcrumbTree>,
index_context: Option<&'b dyn IntoContextElement>,
injected_context: Option<&'b dyn IntoContextElement>,
explicit_context: &Option<Path<'b>>,
@ -87,6 +192,15 @@ impl<'a> DustRenderer<'a> {
Some((parent, new_nodes))
}
/// Returns a option of a tuple of (parent, new_node_elements)
/// which can then be formed into new BreadcrumbTreeNodes
///
/// If None is returned, then it is a signal to simply re-use the
/// existing breadcrumbs.
///
/// Otherwise, the parent (which may be None, especially for
/// explicit contexts) and the additional node elements (which may
/// be empty) should be combined into a final BreadcrumbTreeNode
fn new_breadcrumbs_partial<'b>(
&'b self,
maybe_breadcrumbs: Option<&'b BreadcrumbTree>,
@ -168,3 +282,9 @@ impl<'a> DustRenderer<'a> {
}
}
}
struct BlockContext<'a> {
/// The breadcrumbs at the time of entering the current partial
breadcrumbs: Option<&'a BreadcrumbTree<'a>>,
blocks: &'a InlinePartialTreeElement<'a>,
}