diff --git a/src/compare/diff.rs b/src/compare/diff.rs index 0bfd6ba..da30bef 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -9,6 +9,7 @@ use super::sexp::unquote; use super::sexp::Token; use super::util::compare_standard_properties; use super::util::get_property; +use super::util::get_property_quoted_string; use super::util::get_property_unquoted_atom; use crate::types::AngleLink; use crate::types::BabelCall; @@ -830,7 +831,16 @@ fn compare_plain_list_item<'s>( .collect::, _>>()?; child_status.push(artificial_diff_scope("contents", contents_status)?); - // TODO: Compare :bullet :counter :pre-blank + // TODO: Compare :counter :pre-blank + let bullet = get_property_quoted_string(emacs, ":bullet")? + .ok_or("Plain list items must have a :bullet.")?; + if bullet != rust.bullet { + this_status = DiffStatus::Bad; + message = Some(format!( + "Plain list item bullet mismatch (emacs != rust) {:?} != {:?}", + bullet, rust.bullet + )); + } // Compare checkbox let checkbox = get_property(emacs, ":checkbox")? diff --git a/src/compare/util.rs b/src/compare/util.rs index f52ef47..a706804 100644 --- a/src/compare/util.rs +++ b/src/compare/util.rs @@ -1,5 +1,6 @@ use super::elisp_fact::GetElispFact; use super::sexp::Token; +use crate::compare::sexp::unquote; use crate::types::GetStandardProperties; use crate::types::StandardProperties; @@ -202,3 +203,17 @@ pub(crate) fn get_property_unquoted_atom<'s, 'x>( .map(Token::as_atom) .map_or(Ok(None), |r| r.map(Some))?) } + +/// Get a named property containing an quoted string from the emacs token. +/// +/// Returns None if key is not found. +pub(crate) fn get_property_quoted_string<'s, 'x>( + emacs: &'s Token<'s>, + key: &'x str, +) -> Result, Box> { + Ok(get_property(emacs, key)? + .map(Token::as_atom) + .map_or(Ok(None), |r| r.map(Some))? + .map(unquote) + .map_or(Ok(None), |r| r.map(Some))?) +} diff --git a/src/parser/org_source.rs b/src/parser/org_source.rs index 252a5fc..8e3a9a6 100644 --- a/src/parser/org_source.rs +++ b/src/parser/org_source.rs @@ -78,6 +78,12 @@ impl<'s> OrgSource<'s> { self.slice(..(other.start - self.start)) } + pub(crate) fn get_until_end_of(&self, other: OrgSource<'s>) -> OrgSource<'s> { + debug_assert!(other.start >= self.start); + debug_assert!(other.end <= self.end); + self.slice(..(other.end - self.start)) + } + pub(crate) fn get_start_of_line(&self) -> OrgSource<'s> { let skipped_text = self.text_since_line_break(); let mut bracket_depth = self.bracket_depth; diff --git a/src/parser/plain_list.rs b/src/parser/plain_list.rs index 3b10d55..564db26 100644 --- a/src/parser/plain_list.rs +++ b/src/parser/plain_list.rs @@ -54,12 +54,12 @@ pub(crate) fn detect_plain_list<'b, 'g, 'r, 's>( if verify( tuple(( start_of_line, - space0, + parser_with_context!(indentation_level)(context), parser_with_context!(bullet)(context), alt((space1, line_ending, eof)), )), - |(_start, indent, (_bullet_type, bull), _after_whitespace)| { - Into::<&str>::into(bull) != "*" || indent.len() > 0 + |(_start, (indent_level, _), (_bullet_type, bull), _after_whitespace)| { + !Into::<&str>::into(bull).starts_with("*") || *indent_level > 0 }, )(input) .is_ok() @@ -163,7 +163,7 @@ fn plain_list_item<'b, 'g, 'r, 's>( let (remaining, (indent_level, _leading_whitespace)) = indentation_level(context, input)?; let (remaining, (bullet_type, bull)) = verify( parser_with_context!(bullet)(context), - |(_bullet_type, bull)| Into::<&str>::into(bull) != "*" || indent_level > 0, + |(_bullet_type, bull)| !Into::<&str>::into(bull).starts_with("*") || indent_level > 0, )(remaining)?; let (remaining, _maybe_counter_set) = @@ -279,18 +279,23 @@ fn bullet<'b, 'g, 'r, 's>( context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, ) -> Res, (BulletType, OrgSource<'s>)> { - alt(( - map(tag("*"), |bull| (BulletType::Unordered, bull)), - map(tag("-"), |bull| (BulletType::Unordered, bull)), - map(tag("+"), |bull| (BulletType::Unordered, bull)), - map( - recognize(tuple(( - parser_with_context!(counter)(context), - alt((tag("."), tag(")"))), - ))), - |bull| (BulletType::Ordered, bull), - ), - ))(input) + let (remaining, ((bullet_type, _without_space), peek_trailing_space)) = tuple(( + alt(( + map(tag("*"), |bull| (BulletType::Unordered, bull)), + map(tag("-"), |bull| (BulletType::Unordered, bull)), + map(tag("+"), |bull| (BulletType::Unordered, bull)), + map( + recognize(tuple(( + parser_with_context!(counter)(context), + alt((tag("."), tag(")"))), + ))), + |bull| (BulletType::Ordered, bull), + ), + )), + peek(space0), + ))(input)?; + let with_space = input.get_until_end_of(peek_trailing_space); + Ok((remaining, (bullet_type, with_space))) } #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]