Merge branch 'pseudo_context' into explicit_context_priority

This commit is contained in:
Tom Alexander 2020-05-30 12:26:11 -04:00
commit 9bdc398a6d
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE
5 changed files with 56 additions and 12 deletions

View File

@ -21,6 +21,16 @@ pub trait Truthiness {
pub trait Walkable { pub trait Walkable {
fn walk(&self, segment: &str) -> Result<&dyn ContextElement, WalkError>; fn walk(&self, segment: &str) -> Result<&dyn ContextElement, WalkError>;
/// If an element contains meta information and should not be
/// returned as the final result of a walk, this function should
/// return true.
///
/// For example, the iteration context contains $idx and $len but
/// it should not be the result of a dot-reference like `{.}`.
fn is_pseudo_element(&self) -> bool {
false
}
} }
pub trait Renderable { pub trait Renderable {

View File

@ -68,6 +68,10 @@ impl Walkable for IterationContext {
_ => Err(WalkError::CantWalk), _ => Err(WalkError::CantWalk),
} }
} }
fn is_pseudo_element(&self) -> bool {
true
}
} }
impl CompareContextElement for IterationContext { impl CompareContextElement for IterationContext {

View File

@ -103,6 +103,10 @@ impl Walkable for ParametersContext {
OwnedRValue::RVLiteral(literal) => Ok(literal), OwnedRValue::RVLiteral(literal) => Ok(literal),
} }
} }
fn is_pseudo_element(&self) -> bool {
true
}
} }
impl Clone for ParametersContext { impl Clone for ParametersContext {

View File

@ -17,6 +17,7 @@ use crate::renderer::inline_partial_tree::InlinePartialTreeElement;
use crate::renderer::iteration_context::IterationContext; use crate::renderer::iteration_context::IterationContext;
use crate::renderer::parameters_context::ParametersContext; use crate::renderer::parameters_context::ParametersContext;
use crate::renderer::walking::walk_path; use crate::renderer::walking::walk_path;
use std::borrow::Borrow;
use std::collections::HashMap; use std::collections::HashMap;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -813,6 +814,15 @@ impl<'a> DustRenderer<'a> {
Some(new_stack) Some(new_stack)
} }
fn get_index_of_first_non_pseudo_element<'b, B>(breadcrumbs: &'b Vec<B>) -> Option<usize>
where
B: Borrow<dyn ContextElement + 'a>,
{
breadcrumbs
.iter()
.rposition(|b| !(*b).borrow().is_pseudo_element())
}
fn new_breadcrumbs_partial<'b>( fn new_breadcrumbs_partial<'b>(
breadcrumbs: &'b Vec<&'b dyn ContextElement>, breadcrumbs: &'b Vec<&'b dyn ContextElement>,
explicit_context_breadcrumbs: &'b Vec<&'b dyn ContextElement>, explicit_context_breadcrumbs: &'b Vec<&'b dyn ContextElement>,
@ -837,7 +847,10 @@ impl<'a> DustRenderer<'a> {
// added after the current context but before the explicit // added after the current context but before the explicit
// context. // context.
match explicit_context { match explicit_context {
None => new_stack.insert(std::cmp::max(new_stack.len() - 1, 0), ctx), None => new_stack.insert(
Self::get_index_of_first_non_pseudo_element(&new_stack).unwrap_or(0),
ctx,
),
_ => new_stack.push(ctx), _ => new_stack.push(ctx),
} }
}); });

View File

@ -1,4 +1,5 @@
use crate::renderer::context_element::ContextElement; use crate::renderer::context_element::ContextElement;
use crate::renderer::context_element::Walkable;
use crate::renderer::WalkError; use crate::renderer::WalkError;
use std::borrow::Borrow; use std::borrow::Borrow;
@ -34,6 +35,17 @@ where
WalkResult::FullyWalked(output) WalkResult::FullyWalked(output)
} }
pub fn get_first_non_pseudo_element<'a, B>(breadcrumbs: &'a Vec<B>) -> Option<&B>
where
B: Borrow<dyn ContextElement + 'a>,
{
breadcrumbs
.iter()
.rev()
.filter(|b| !(*b).borrow().is_pseudo_element())
.next()
}
pub fn walk_path<'a, B, P>( pub fn walk_path<'a, B, P>(
breadcrumbs: &'a Vec<B>, breadcrumbs: &'a Vec<B>,
path: &Vec<P>, path: &Vec<P>,
@ -60,17 +72,18 @@ where
.borrow() .borrow()
== "." == "."
{ {
return match walk_path_from_single_level( let first_non_pseudo_element = get_first_non_pseudo_element(breadcrumbs);
breadcrumbs return match first_non_pseudo_element {
.last() None => Err(WalkError::CantWalk),
.expect("Breadcrumbs should never be empty"), Some(current_context) => {
&path[1..], match walk_path_from_single_level(current_context, &path[1..]) {
) { // If no walking was done at all or we partially walked
// If no walking was done at all or we partially walked // then stop trying to find anything because '.' restricts
// then stop trying to find anything because '.' restricts // us to the current scope
// us to the current scope WalkResult::NoWalk | WalkResult::PartialWalk => Err(WalkError::CantWalk),
WalkResult::NoWalk | WalkResult::PartialWalk => Err(WalkError::CantWalk), WalkResult::FullyWalked(new_context) => Ok(new_context),
WalkResult::FullyWalked(new_context) => Ok(new_context), }
}
}; };
} }
for context in breadcrumbs.iter().rev() { for context in breadcrumbs.iter().rev() {