diff --git a/src/context/global_settings.rs b/src/context/global_settings.rs index b5f818b..ad3640d 100644 --- a/src/context/global_settings.rs +++ b/src/context/global_settings.rs @@ -1,16 +1,19 @@ -#[derive(Debug)] -pub struct GlobalSettings<'s> { - #[allow(dead_code)] - placeholder: Option<&'s str>, +use crate::types::Object; + +#[derive(Debug, Clone)] +pub struct GlobalSettings<'g, 's> { + pub radio_targets: Vec<&'g Vec>>, } -impl<'s> GlobalSettings<'s> { +impl<'g, 's> GlobalSettings<'g, 's> { pub fn new() -> Self { - GlobalSettings { placeholder: None } + GlobalSettings { + radio_targets: Vec::new(), + } } } -impl<'s> Default for GlobalSettings<'s> { +impl<'g, 's> Default for GlobalSettings<'g, 's> { fn default() -> Self { GlobalSettings::new() } diff --git a/src/context/parser_context.rs b/src/context/parser_context.rs index 8b21c50..d8f2de3 100644 --- a/src/context/parser_context.rs +++ b/src/context/parser_context.rs @@ -1,3 +1,5 @@ +use std::marker::PhantomData; + use nom::combinator::eof; use nom::IResult; @@ -10,7 +12,6 @@ use crate::error::CustomError; use crate::error::MyError; use crate::error::Res; use crate::parser::OrgSource; -use crate::types::Object; #[derive(Debug)] pub enum ContextElement<'r, 's> { @@ -23,12 +24,8 @@ pub enum ContextElement<'r, 's> { /// Indicates if elements should consume the whitespace after them. ConsumeTrailingWhitespace(bool), - /// The contents of a radio target. - /// - /// If any are found, this will force a 2nd parse through the - /// org-mode document since text needs to be re-parsed to look for - /// radio links matching the contents of radio targets. - RadioTarget(Vec<&'r Vec>>), + /// This is just here to use the 's lifetime until I'm sure we can eliminate it from ContextElement. + Placeholder(PhantomData<&'s str>), } pub struct ExitMatcherNode<'r> { @@ -47,13 +44,13 @@ impl<'r> std::fmt::Debug for ExitMatcherNode<'r> { #[derive(Debug)] pub struct Context<'g, 'r, 's> { - global_settings: &'g GlobalSettings<'g>, + global_settings: &'g GlobalSettings<'g, 's>, tree: List<'r, &'r ContextElement<'r, 's>>, } impl<'g, 'r, 's> Context<'g, 'r, 's> { pub fn new( - global_settings: &'g GlobalSettings<'g>, + global_settings: &'g GlobalSettings<'g, 's>, tree: List<'r, &'r ContextElement<'r, 's>>, ) -> Self { Self { @@ -89,6 +86,17 @@ impl<'g, 'r, 's> Context<'g, 'r, 's> { self.tree.get_data() } + pub fn get_global_settings(&self) -> &'g GlobalSettings<'g, 's> { + self.global_settings + } + + pub fn with_global_settings<'gg>(&self, new_settings: &'gg GlobalSettings<'gg, 's>) -> Context<'gg, 'r, 's> { + Context { + global_settings: new_settings, + tree: self.tree.clone(), + } + } + #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] pub fn check_exit_matcher( &'r self, @@ -145,7 +153,7 @@ fn document_end<'b, 'g, 'r, 's>( } pub struct Iter<'g, 'r, 's> { - global_settings: &'g GlobalSettings<'g>, + global_settings: &'g GlobalSettings<'g, 's>, next: super::list::IterList<'r, &'r ContextElement<'r, 's>>, } diff --git a/src/parser/document.rs b/src/parser/document.rs index 4f09a94..3e9cbe4 100644 --- a/src/parser/document.rs +++ b/src/parser/document.rs @@ -95,8 +95,9 @@ fn document_org_source<'b, 'g, 'r, 's>( .map(|rt| &rt.children) .collect(); if !all_radio_targets.is_empty() { - let parser_context = ContextElement::RadioTarget(all_radio_targets); - let parser_context = context.with_additional_node(&parser_context); + let mut new_global_settings = context.get_global_settings().clone(); + new_global_settings.radio_targets = all_radio_targets; + let parser_context = context.with_global_settings(&new_global_settings); let (remaining, document) = _document(&parser_context, input) .map(|(rem, out)| (Into::<&str>::into(rem), out))?; return Ok((remaining.into(), document)); diff --git a/src/parser/radio_link.rs b/src/parser/radio_link.rs index ec1e444..f47a4d2 100644 --- a/src/parser/radio_link.rs +++ b/src/parser/radio_link.rs @@ -27,14 +27,7 @@ pub fn radio_link<'b, 'g, 'r, 's>( context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, ) -> Res, RadioLink<'s>> { - let radio_targets = context - .iter() - .filter_map(|context_element| match context_element { - ContextElement::RadioTarget(targets) => Some(targets), - _ => None, - }) - .flatten(); - for radio_target in radio_targets { + for radio_target in &context.get_global_settings().radio_targets { let rematched_target = rematch_target(context, radio_target, input); if let Ok((remaining, rematched_target)) = rematched_target { let (remaining, _) = space0(remaining)?; @@ -149,12 +142,14 @@ mod tests { fn plain_text_radio_target() { let input = OrgSource::new("foo bar baz"); let radio_target_match = vec![Object::PlainText(PlainText { source: "bar" })]; - let global_settings = GlobalSettings::default(); + let global_settings = { + let mut global_settings = GlobalSettings::default(); + global_settings.radio_targets = vec![&radio_target_match]; + global_settings + }; let initial_context = ContextElement::document_context(); let initial_context = Context::new(&global_settings, List::new(&initial_context)); - let document_context = ContextElement::RadioTarget(vec![&radio_target_match]); - let document_context = initial_context.with_additional_node(&document_context); - let paragraph_matcher = parser_with_context!(element(true))(&document_context); + let paragraph_matcher = parser_with_context!(element(true))(&initial_context); let (remaining, first_paragraph) = paragraph_matcher(input).expect("Parse first paragraph"); let first_paragraph = match first_paragraph { Element::Paragraph(paragraph) => paragraph, @@ -182,12 +177,14 @@ mod tests { source: "*bar*", children: vec![Object::PlainText(PlainText { source: "bar" })], })]; - let global_settings = GlobalSettings::default(); + let global_settings = { + let mut global_settings = GlobalSettings::default(); + global_settings.radio_targets = vec![&radio_target_match]; + global_settings + }; let initial_context = ContextElement::document_context(); let initial_context = Context::new(&global_settings, List::new(&initial_context)); - let document_context = ContextElement::RadioTarget(vec![&radio_target_match]); - let document_context = initial_context.with_additional_node(&document_context); - let paragraph_matcher = parser_with_context!(element(true))(&document_context); + let paragraph_matcher = parser_with_context!(element(true))(&initial_context); let (remaining, first_paragraph) = paragraph_matcher(input.into()).expect("Parse first paragraph"); let first_paragraph = match first_paragraph {