From 9a3bde0d80968582a3b7f98183f358b59efde542 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sat, 22 Apr 2023 19:34:13 -0400 Subject: [PATCH] First attempt at text markup. --- src/parser/lesser_element.rs | 4 +- src/parser/object.rs | 1 + src/parser/text_markup.rs | 76 ++++++++++++++++++++++++++++++++++-- toy_language.txt | 36 +---------------- 4 files changed, 76 insertions(+), 41 deletions(-) diff --git a/src/parser/lesser_element.rs b/src/parser/lesser_element.rs index 9c9a67f8..cac3adf9 100644 --- a/src/parser/lesser_element.rs +++ b/src/parser/lesser_element.rs @@ -1,6 +1,6 @@ use super::object::Object; -use super::object::TextMarkup; use super::source::Source; +use super::PlainText; #[derive(Debug)] pub struct Paragraph<'s> { @@ -97,7 +97,7 @@ pub struct LatexEnvironment<'s> { impl<'s> Paragraph<'s> { pub fn of_text(input: &'s str) -> Self { let mut objects = Vec::with_capacity(1); - objects.push(Object::TextMarkup(TextMarkup { source: input })); + objects.push(Object::PlainText(PlainText { source: input })); Paragraph { source: input, children: objects, diff --git a/src/parser/object.rs b/src/parser/object.rs index db0534e8..9347e6c2 100644 --- a/src/parser/object.rs +++ b/src/parser/object.rs @@ -14,6 +14,7 @@ pub enum Object<'s> { #[derive(Debug)] pub struct TextMarkup<'s> { pub source: &'s str, + pub children: Vec>, } #[derive(Debug)] diff --git a/src/parser/text_markup.rs b/src/parser/text_markup.rs index 80f134d5..40671f02 100644 --- a/src/parser/text_markup.rs +++ b/src/parser/text_markup.rs @@ -1,10 +1,21 @@ use nom::branch::alt; use nom::bytes::complete::tag; +use nom::combinator::peek; +use nom::combinator::verify; +use nom::multi::many_till; +use nom::sequence::terminated; use super::Context; use crate::error::CustomError; use crate::error::MyError; use crate::error::Res; +use crate::parser::exiting::ExitClass; +use crate::parser::object_parser::standard_set_object; +use crate::parser::parser_context::ContextElement; +use crate::parser::parser_context::ExitMatcherNode; +use crate::parser::parser_with_context::parser_with_context; +use crate::parser::util::exit_matcher_parser; +use crate::parser::util::get_consumed; use crate::parser::util::get_one_before; use crate::parser::TextMarkup; @@ -15,11 +26,27 @@ pub fn text_markup<'r, 's>( ) -> Res<&'s str, TextMarkup<'s>> { let (remaining, _) = pre(context, input)?; let (remaining, open) = marker(remaining)?; - return Err(nom::Err::Error(CustomError::MyError(MyError( - "text markup not implemented yet.", - )))); + let text_markup_end_specialized = text_markup_end(open); + let parser_context = + context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode { + class: ExitClass::Beta, + exit_matcher: &text_markup_end_specialized, + })); - todo!() + let (remaining, (children, _exit_contents)) = verify( + many_till( + parser_with_context!(standard_set_object)(&parser_context), + parser_with_context!(exit_matcher_parser)(&parser_context), + ), + |(children, _exit_contents)| !children.is_empty(), + )(remaining)?; + + // TODO: Sometimes its plain text, not objects + let (remaining, close) = text_markup_end_specialized(context, remaining)?; + + let source = get_consumed(input, remaining); + + Ok((remaining, TextMarkup { source, children })) } #[tracing::instrument(ret, level = "debug")] @@ -42,7 +69,48 @@ pub fn pre<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, ()> Ok((input, ())) } +#[tracing::instrument(ret, level = "debug")] +pub fn post<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, ()> { + let document_root = context.get_document_root().unwrap(); + let preceding_character = get_one_before(document_root, input) + .map(|slice| slice.chars().next()) + .flatten(); + match preceding_character { + // If None, we are at the start of the file which is technically the beginning of a line. + None | Some('\r') | Some('\n') | Some(' ') | Some('\t') | Some('-') | Some('(') + | Some('{') | Some('\'') | Some('"') => {} + Some(_) => { + // Not at start of line, cannot be a heading + return Err(nom::Err::Error(CustomError::MyError(MyError( + "Not a valid pre character for text markup.", + )))); + } + }; + Ok((input, ())) +} + #[tracing::instrument(ret, level = "debug")] pub fn marker(input: &str) -> Res<&str, &str> { alt((tag("*"), tag("/"), tag("_"), tag("="), tag("~"), tag("+")))(input) } + +fn text_markup_end( + marker_symbol: &str, +) -> impl for<'r, 's> Fn(Context<'r, 's>, &'s str) -> Res<&'s str, &'s str> { + let marker_symbol = marker_symbol.to_owned(); + move |context: Context, input: &str| _text_markup_end(context, input, marker_symbol.as_str()) +} + +#[tracing::instrument(ret, level = "debug")] +fn _text_markup_end<'r, 's, 'x>( + context: Context<'r, 's>, + input: &'s str, + marker_symbol: &'x str, +) -> Res<&'s str, &'s str> { + let (remaining, _marker) = terminated( + tag(marker_symbol), + peek(parser_with_context!(post)(context)), + )(input)?; + let source = get_consumed(input, remaining); + Ok((remaining, source)) +} diff --git a/toy_language.txt b/toy_language.txt index 5d183337..6c2c9844 100644 --- a/toy_language.txt +++ b/toy_language.txt @@ -1,35 +1 @@ -prologue *goes here* I guess *bold -text* - -bold*wont* start *or stop*when there is text outside it - -I guess *regular - -text* - -[foo *bar] baz* car - - -*nesting *bold entrances* and* exits - -* Heading - -body of heading - -** Child heading -** Immediate second child heading - -* Second top-level heading -foo bar -1. This is a list immediately after a paragraph -2. This is a second item in the list - 1. This is a child of the second item -#+begin_center -1. foo -2. bar -#+end_center -[fn:1] A footnote. - -[fn:2] A multi- - -line footnote. +foo *bar* baz