Switch to putting radio targets in the global settings instead of the context tree.
All checks were successful
rustfmt Build rustfmt has succeeded
rust-test Build rust-test has succeeded
rust-build Build rust-build has succeeded

This commit is contained in:
Tom Alexander 2023-09-04 12:28:33 -04:00
parent 71180d19fb
commit 0ef141d65e
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE
4 changed files with 44 additions and 35 deletions

View File

@ -1,16 +1,19 @@
#[derive(Debug)] use crate::types::Object;
pub struct GlobalSettings<'s> {
#[allow(dead_code)] #[derive(Debug, Clone)]
placeholder: Option<&'s str>, pub struct GlobalSettings<'g, 's> {
pub radio_targets: Vec<&'g Vec<Object<'s>>>,
} }
impl<'s> GlobalSettings<'s> { impl<'g, 's> GlobalSettings<'g, 's> {
pub fn new() -> Self { 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 { fn default() -> Self {
GlobalSettings::new() GlobalSettings::new()
} }

View File

@ -1,3 +1,5 @@
use std::marker::PhantomData;
use nom::combinator::eof; use nom::combinator::eof;
use nom::IResult; use nom::IResult;
@ -10,7 +12,6 @@ use crate::error::CustomError;
use crate::error::MyError; use crate::error::MyError;
use crate::error::Res; use crate::error::Res;
use crate::parser::OrgSource; use crate::parser::OrgSource;
use crate::types::Object;
#[derive(Debug)] #[derive(Debug)]
pub enum ContextElement<'r, 's> { pub enum ContextElement<'r, 's> {
@ -23,12 +24,8 @@ pub enum ContextElement<'r, 's> {
/// Indicates if elements should consume the whitespace after them. /// Indicates if elements should consume the whitespace after them.
ConsumeTrailingWhitespace(bool), ConsumeTrailingWhitespace(bool),
/// The contents of a radio target. /// This is just here to use the 's lifetime until I'm sure we can eliminate it from ContextElement.
/// Placeholder(PhantomData<&'s str>),
/// 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<Object<'s>>>),
} }
pub struct ExitMatcherNode<'r> { pub struct ExitMatcherNode<'r> {
@ -47,13 +44,13 @@ impl<'r> std::fmt::Debug for ExitMatcherNode<'r> {
#[derive(Debug)] #[derive(Debug)]
pub struct Context<'g, 'r, 's> { pub struct Context<'g, 'r, 's> {
global_settings: &'g GlobalSettings<'g>, global_settings: &'g GlobalSettings<'g, 's>,
tree: List<'r, &'r ContextElement<'r, 's>>, tree: List<'r, &'r ContextElement<'r, 's>>,
} }
impl<'g, 'r, 's> Context<'g, 'r, 's> { impl<'g, 'r, 's> Context<'g, 'r, 's> {
pub fn new( pub fn new(
global_settings: &'g GlobalSettings<'g>, global_settings: &'g GlobalSettings<'g, 's>,
tree: List<'r, &'r ContextElement<'r, 's>>, tree: List<'r, &'r ContextElement<'r, 's>>,
) -> Self { ) -> Self {
Self { Self {
@ -89,6 +86,17 @@ impl<'g, 'r, 's> Context<'g, 'r, 's> {
self.tree.get_data() 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"))] #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
pub fn check_exit_matcher( pub fn check_exit_matcher(
&'r self, &'r self,
@ -145,7 +153,7 @@ fn document_end<'b, 'g, 'r, 's>(
} }
pub struct Iter<'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>>, next: super::list::IterList<'r, &'r ContextElement<'r, 's>>,
} }

View File

@ -95,8 +95,9 @@ fn document_org_source<'b, 'g, 'r, 's>(
.map(|rt| &rt.children) .map(|rt| &rt.children)
.collect(); .collect();
if !all_radio_targets.is_empty() { if !all_radio_targets.is_empty() {
let parser_context = ContextElement::RadioTarget(all_radio_targets); let mut new_global_settings = context.get_global_settings().clone();
let parser_context = context.with_additional_node(&parser_context); 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) let (remaining, document) = _document(&parser_context, input)
.map(|(rem, out)| (Into::<&str>::into(rem), out))?; .map(|(rem, out)| (Into::<&str>::into(rem), out))?;
return Ok((remaining.into(), document)); return Ok((remaining.into(), document));

View File

@ -27,14 +27,7 @@ pub fn radio_link<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>, context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>, input: OrgSource<'s>,
) -> Res<OrgSource<'s>, RadioLink<'s>> { ) -> Res<OrgSource<'s>, RadioLink<'s>> {
let radio_targets = context for radio_target in &context.get_global_settings().radio_targets {
.iter()
.filter_map(|context_element| match context_element {
ContextElement::RadioTarget(targets) => Some(targets),
_ => None,
})
.flatten();
for radio_target in radio_targets {
let rematched_target = rematch_target(context, radio_target, input); let rematched_target = rematch_target(context, radio_target, input);
if let Ok((remaining, rematched_target)) = rematched_target { if let Ok((remaining, rematched_target)) = rematched_target {
let (remaining, _) = space0(remaining)?; let (remaining, _) = space0(remaining)?;
@ -149,12 +142,14 @@ mod tests {
fn plain_text_radio_target() { fn plain_text_radio_target() {
let input = OrgSource::new("foo bar baz"); let input = OrgSource::new("foo bar baz");
let radio_target_match = vec![Object::PlainText(PlainText { source: "bar" })]; 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 = ContextElement::document_context();
let initial_context = Context::new(&global_settings, List::new(&initial_context)); let initial_context = Context::new(&global_settings, List::new(&initial_context));
let document_context = ContextElement::RadioTarget(vec![&radio_target_match]); let paragraph_matcher = parser_with_context!(element(true))(&initial_context);
let document_context = initial_context.with_additional_node(&document_context);
let paragraph_matcher = parser_with_context!(element(true))(&document_context);
let (remaining, first_paragraph) = paragraph_matcher(input).expect("Parse first paragraph"); let (remaining, first_paragraph) = paragraph_matcher(input).expect("Parse first paragraph");
let first_paragraph = match first_paragraph { let first_paragraph = match first_paragraph {
Element::Paragraph(paragraph) => paragraph, Element::Paragraph(paragraph) => paragraph,
@ -182,12 +177,14 @@ mod tests {
source: "*bar*", source: "*bar*",
children: vec![Object::PlainText(PlainText { 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 = ContextElement::document_context();
let initial_context = Context::new(&global_settings, List::new(&initial_context)); let initial_context = Context::new(&global_settings, List::new(&initial_context));
let document_context = ContextElement::RadioTarget(vec![&radio_target_match]); let paragraph_matcher = parser_with_context!(element(true))(&initial_context);
let document_context = initial_context.with_additional_node(&document_context);
let paragraph_matcher = parser_with_context!(element(true))(&document_context);
let (remaining, first_paragraph) = let (remaining, first_paragraph) =
paragraph_matcher(input.into()).expect("Parse first paragraph"); paragraph_matcher(input.into()).expect("Parse first paragraph");
let first_paragraph = match first_paragraph { let first_paragraph = match first_paragraph {