diff --git a/src/parser/fixed_width_area.rs b/src/parser/fixed_width_area.rs index eae3833..9631ac8 100644 --- a/src/parser/fixed_width_area.rs +++ b/src/parser/fixed_width_area.rs @@ -2,16 +2,19 @@ use nom::branch::alt; use nom::bytes::complete::tag; use nom::character::complete::anychar; use nom::character::complete::space0; +use nom::combinator::map; use nom::combinator::not; +use nom::combinator::peek; use nom::combinator::recognize; use nom::multi::many0; use nom::multi::many_till; use nom::sequence::preceded; use nom::sequence::tuple; +use nom::InputTake; use super::affiliated_keyword::parse_affiliated_keywords; use super::org_source::OrgSource; -use super::util::maybe_consume_trailing_whitespace_if_not_exiting; +use super::util::maybe_consume_trailing_whitespace_if_not_exiting_mid_line; use super::util::org_line_ending; use crate::context::parser_with_context; use crate::context::RefContext; @@ -35,28 +38,22 @@ pub(crate) fn fixed_width_area<'b, 'g, 'r, 's, AK>( where AK: IntoIterator>, { - let fixed_width_area_line_matcher = parser_with_context!(fixed_width_area_line)(context); let exit_matcher = parser_with_context!(exit_matcher_parser)(context); - let (remaining, first_line) = fixed_width_area_line_matcher(remaining)?; - let (remaining, mut remaining_lines) = - many0(preceded(not(exit_matcher), fixed_width_area_line_matcher))(remaining)?; + let (remaining, first_line) = fixed_width_area_line(remaining)?; + let (remaining, remaining_lines) = many0(preceded( + not(tuple((org_line_ending, exit_matcher))), + map( + tuple((org_line_ending, fixed_width_area_line)), + |(_line_ending, line_contents)| line_contents, + ), + ))(remaining)?; let (remaining, post_blank) = - maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?; + maybe_consume_trailing_whitespace_if_not_exiting_mid_line(context, remaining)?; let source = get_consumed(input, remaining); let mut value = Vec::with_capacity(remaining_lines.len() + 1); - let last_line = remaining_lines.pop(); - if let Some(last_line) = last_line { - value.push(Into::<&str>::into(first_line)); - value.extend(remaining_lines.into_iter().map(Into::<&str>::into)); - let last_line = Into::<&str>::into(last_line); - // Trim the line ending from the final line. - value.push(&last_line[..(last_line.len() - 1)]) - } else { - // Trim the line ending from the only line. - let only_line = Into::<&str>::into(first_line); - value.push(&only_line[..(only_line.len() - 1)]) - } + value.push(Into::<&str>::into(first_line)); + value.extend(remaining_lines.into_iter().map(Into::<&str>::into)); Ok(( remaining, FixedWidthArea { @@ -71,21 +68,15 @@ where )) } -#[cfg_attr( - feature = "tracing", - tracing::instrument(ret, level = "debug", skip(_context)) -)] -fn fixed_width_area_line<'b, 'g, 'r, 's>( - _context: RefContext<'b, 'g, 'r, 's>, - input: OrgSource<'s>, -) -> Res, OrgSource<'s>> { +#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] +fn fixed_width_area_line<'s>(input: OrgSource<'s>) -> Res, OrgSource<'s>> { start_of_line(input)?; let (remaining, _) = tuple((space0, tag(":")))(input)?; - if let Ok((remaining, line_break)) = org_line_ending(remaining) { - return Ok((remaining, line_break)); + if let Ok((remain, _line_break)) = org_line_ending(remaining) { + return Ok((remain, remaining.take(0))); } let (remaining, _) = tag(" ")(remaining)?; - let (remaining, value) = recognize(many_till(anychar, org_line_ending))(remaining)?; + let (remaining, value) = recognize(many_till(anychar, peek(org_line_ending)))(remaining)?; Ok((remaining, value)) } diff --git a/src/parser/util.rs b/src/parser/util.rs index 29523f2..3ed86d2 100644 --- a/src/parser/util.rs +++ b/src/parser/util.rs @@ -72,6 +72,13 @@ fn element_trailing_whitespace<'s>(input: OrgSource<'s>) -> Res, O alt((eof, recognize(many0(blank_line))))(input) } +#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] +fn element_trailing_whitespace_mid_line<'s>( + input: OrgSource<'s>, +) -> Res, OrgSource<'s>> { + alt((eof, recognize(many0(blank_line))))(input) +} + #[cfg_attr( feature = "tracing", tracing::instrument(ret, level = "debug", skip(context)) @@ -114,6 +121,22 @@ pub(crate) fn maybe_consume_trailing_whitespace_if_not_exiting<'b, 'g, 'r, 's>( } } +#[cfg_attr( + feature = "tracing", + tracing::instrument(ret, level = "debug", skip(context)) +)] +pub(crate) fn maybe_consume_trailing_whitespace_if_not_exiting_mid_line<'b, 'g, 'r, 's>( + context: RefContext<'b, 'g, 'r, 's>, + input: OrgSource<'s>, +) -> Res, Option>> { + if context.should_consume_trailing_whitespace() && exit_matcher_parser(context, input).is_err() + { + Ok(opt(element_trailing_whitespace_mid_line)(input)?) + } else { + Ok((input, None)) + } +} + #[cfg_attr( feature = "tracing", tracing::instrument(ret, level = "debug", skip(context)) diff --git a/src/types/lesser_element.rs b/src/types/lesser_element.rs index 8ddaa12..17933df 100644 --- a/src/types/lesser_element.rs +++ b/src/types/lesser_element.rs @@ -498,13 +498,7 @@ impl<'s> Comment<'s> { impl<'s> FixedWidthArea<'s> { pub fn get_value(&self) -> String { - let final_size = self.value.iter().map(|line| line.len()).sum(); - let mut ret = String::with_capacity(final_size); - for line in &self.value { - ret.push_str(line); - } - - ret + self.value.join("\n") } }