From da6655d4b68d4a57f3fbff7632d98f0db84ea054 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 31 May 2020 21:18:54 -0400 Subject: [PATCH] General structure to the rendering code. --- src/renderer/renderer.rs | 124 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 122 insertions(+), 2 deletions(-) diff --git a/src/renderer/renderer.rs b/src/renderer/renderer.rs index 94d3fcc..34f04fa 100644 --- a/src/renderer/renderer.rs +++ b/src/renderer/renderer.rs @@ -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(&'a self, name: &str, context: Option<&C>) -> Result + 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 { + 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, + breadcrumbs: Option<&'a BreadcrumbTree>, + blocks: &'a BlockContext<'a>, + ) -> Result { + 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 { + 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, + breadcrumbs: Option<&'a BreadcrumbTree>, + ) -> Result { + let converted_to_template_elements: Vec> = + 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 { + 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>, @@ -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>, +}