From adc5a383c3a3166cf501742ae489a0218716fe94 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Mon, 9 Oct 2023 13:44:14 -0400 Subject: [PATCH] Allow text markup at the start of a radio target. --- src/context/context.rs | 5 +++++ src/parser/radio_link.rs | 14 +++++++++----- src/parser/text_markup.rs | 12 +++++++++++- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/context/context.rs b/src/context/context.rs index def26bf..138338f 100644 --- a/src/context/context.rs +++ b/src/context/context.rs @@ -33,6 +33,11 @@ pub(crate) enum ContextElement<'r, 's> { /// The value stored is the start of the element after the affiliated keywords. In this way, we can ensure that we do not exit an element immediately after the affiliated keyword had been consumed. HasAffiliatedKeyword(HasAffiliatedKeywordInner<'r, 's>), + /// Indicate the position that we started parsing a radio target. + /// + /// This value is stored because "<<<" is not a valid prefix for text markup UNLESS it is starting a radio target. + StartRadioTarget(OrgSource<'s>), + /// This is just here to use the 's lifetime until I'm sure we can eliminate it from ContextElement. #[allow(dead_code)] Placeholder(PhantomData<&'s str>), diff --git a/src/parser/radio_link.rs b/src/parser/radio_link.rs index 5955344..15eb6cd 100644 --- a/src/parser/radio_link.rs +++ b/src/parser/radio_link.rs @@ -103,11 +103,15 @@ pub(crate) fn radio_target<'b, 'g, 'r, 's>( input: OrgSource<'s>, ) -> Res, RadioTarget<'s>> { let (remaining, _opening) = tag("<<<")(input)?; - let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode { - class: ExitClass::Gamma, - exit_matcher: &radio_target_end, - }); - let parser_context = context.with_additional_node(&parser_context); + let contexts = [ + ContextElement::ExitMatcherNode(ExitMatcherNode { + class: ExitClass::Gamma, + exit_matcher: &radio_target_end, + }), + ContextElement::StartRadioTarget(remaining), + ]; + let parser_context = context.with_additional_node(&contexts[0]); + let parser_context = parser_context.with_additional_node(&contexts[1]); let (remaining, (raw_value, children)) = consumed(verify( map( diff --git a/src/parser/text_markup.rs b/src/parser/text_markup.rs index a32c4c1..d666633 100644 --- a/src/parser/text_markup.rs +++ b/src/parser/text_markup.rs @@ -283,7 +283,7 @@ fn _text_markup_string<'b, 'g, 'r, 's, 'c>( #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] fn pre<'b, 'g, 'r, 's>( - _context: RefContext<'b, 'g, 'r, 's>, + context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, ) -> Res, ()> { if start_of_line(input).is_ok() { @@ -292,6 +292,16 @@ fn pre<'b, 'g, 'r, 's>( if preceded_by_whitespace(true)(input).is_ok() { return Ok((input, ())); } + let radio_target_start = context + .iter() + .find_map(|c| match c { + ContextElement::StartRadioTarget(text) => Some(text), + _ => None, + }) + .map(|text| text.get_byte_offset()); + if Some(input.get_byte_offset()) == radio_target_start { + return Ok((input, ())); + } let preceding_character = input.get_preceding_character(); match preceding_character { // If None, we are at the start of the file which is technically the beginning of a line.