diff --git a/src/compare/diff.rs b/src/compare/diff.rs index a2f41178..4b24dc48 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -60,6 +60,7 @@ use crate::types::TableCell; use crate::types::TableRow; use crate::types::Target; use crate::types::Timestamp; +use crate::types::TodoKeywordType; use crate::types::Underline; use crate::types::Verbatim; use crate::types::VerseBlock; @@ -510,9 +511,9 @@ fn compare_heading<'s>( .map(Token::as_atom) .map_or(Ok(None), |r| r.map(Some))? .unwrap_or("nil"); - match (todo_keyword, rust.todo_keyword, unquote(todo_keyword)) { + match (todo_keyword, &rust.todo_keyword, unquote(todo_keyword)) { ("nil", None, _) => {} - (_, Some(rust_todo), Ok(emacs_todo)) if emacs_todo == rust_todo => {} + (_, Some((_rust_todo_type, rust_todo)), Ok(emacs_todo)) if emacs_todo == *rust_todo => {} (emacs_todo, rust_todo, _) => { this_status = DiffStatus::Bad; message = Some(format!( @@ -521,6 +522,24 @@ fn compare_heading<'s>( )); } }; + // Compare todo-type + let todo_type = get_property(emacs, ":todo-type")? + .map(Token::as_atom) + .map_or(Ok(None), |r| r.map(Some))? + .unwrap_or("nil"); + // todo-type is an unquoted string either todo, done, or nil + match (todo_type, &rust.todo_keyword) { + ("nil", None) => {} + ("todo", Some((TodoKeywordType::Todo, _))) => {} + ("done", Some((TodoKeywordType::Done, _))) => {} + (emacs_todo, rust_todo) => { + this_status = DiffStatus::Bad; + message = Some(format!( + "(emacs != rust) {:?} != {:?}", + emacs_todo, rust_todo + )); + } + }; // Compare title let title = get_property(emacs, ":title")?.ok_or("Missing :title attribute.")?; @@ -532,7 +551,7 @@ fn compare_heading<'s>( .collect::, _>>()?; child_status.push(artificial_diff_scope("title".to_owned(), title_status)?); - // TODO: Compare todo-type, priority, :footnote-section-p, :archivedp, :commentedp + // TODO: Compare priority, :footnote-section-p, :archivedp, :commentedp // Compare section let section_status = children diff --git a/src/parser/document.rs b/src/parser/document.rs index e9556f3f..8c50dbd2 100644 --- a/src/parser/document.rs +++ b/src/parser/document.rs @@ -51,6 +51,7 @@ use crate::types::Element; use crate::types::Heading; use crate::types::Object; use crate::types::Section; +use crate::types::TodoKeywordType; /// Parse a full org-mode document. /// @@ -346,8 +347,9 @@ fn _heading<'b, 'g, 'r, 's>( Heading { source: source.into(), stars: star_count, - todo_keyword: maybe_todo_keyword - .map(|(todo_keyword, _ws)| Into::<&str>::into(todo_keyword)), + todo_keyword: maybe_todo_keyword.map(|((todo_keyword_type, todo_keyword), _ws)| { + (todo_keyword_type, Into::<&str>::into(todo_keyword)) + }), title, tags: heading_tags, children, @@ -371,7 +373,7 @@ fn headline<'b, 'g, 'r, 's>( ( usize, OrgSource<'s>, - Option<(OrgSource<'s>, OrgSource<'s>)>, + Option<((TodoKeywordType, OrgSource<'s>), OrgSource<'s>)>, Vec>, Vec<&'s str>, ), @@ -447,23 +449,38 @@ fn single_tag<'r, 's>(input: OrgSource<'s>) -> Res, OrgSource<'s>> fn heading_keyword<'b, 'g, 'r, 's>( context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, -) -> Res, OrgSource<'s>> { +) -> Res, (TodoKeywordType, OrgSource<'s>)> { let global_settings = context.get_global_settings(); if global_settings.in_progress_todo_keywords.is_empty() && global_settings.complete_todo_keywords.is_empty() { - alt((tag("TODO"), tag("DONE")))(input) + alt(( + map(tag("TODO"), |capture| (TodoKeywordType::Todo, capture)), + map(tag("DONE"), |capture| (TodoKeywordType::Done, capture)), + ))(input) } else { for todo_keyword in global_settings .in_progress_todo_keywords .iter() - .chain(global_settings.complete_todo_keywords.iter()) .map(String::as_str) { let result = tag::<_, _, CustomError<_>>(todo_keyword)(input); match result { Ok((remaining, ent)) => { - return Ok((remaining, ent)); + return Ok((remaining, (TodoKeywordType::Todo, ent))); + } + Err(_) => {} + } + } + for todo_keyword in global_settings + .complete_todo_keywords + .iter() + .map(String::as_str) + { + let result = tag::<_, _, CustomError<_>>(todo_keyword)(input); + match result { + Ok((remaining, ent)) => { + return Ok((remaining, (TodoKeywordType::Done, ent))); } Err(_) => {} } diff --git a/src/types/document.rs b/src/types/document.rs index 957d7b9c..654377a9 100644 --- a/src/types/document.rs +++ b/src/types/document.rs @@ -13,7 +13,7 @@ pub struct Document<'s> { pub struct Heading<'s> { pub source: &'s str, pub stars: usize, - pub todo_keyword: Option<&'s str>, + pub todo_keyword: Option<(TodoKeywordType, &'s str)>, // TODO: add todo-type enum pub title: Vec>, pub tags: Vec<&'s str>, @@ -32,6 +32,12 @@ pub enum DocumentElement<'s> { Section(Section<'s>), } +#[derive(Debug)] +pub enum TodoKeywordType { + Todo, + Done, +} + impl<'s> Source<'s> for Document<'s> { fn get_source(&'s self) -> &'s str { self.source diff --git a/src/types/mod.rs b/src/types/mod.rs index 4ab8c174..efd1b047 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -8,6 +8,7 @@ pub use document::Document; pub use document::DocumentElement; pub use document::Heading; pub use document::Section; +pub use document::TodoKeywordType; pub use element::Element; pub use greater_element::Drawer; pub use greater_element::DynamicBlock;