diff --git a/src/compare/compare_field.rs b/src/compare/compare_field.rs index 9ea46c3..f6af4dc 100644 --- a/src/compare/compare_field.rs +++ b/src/compare/compare_field.rs @@ -230,6 +230,45 @@ pub(crate) fn compare_property_boolean<'b, 's, 'x, R, RG: Fn(R) -> bool>( } } +pub(crate) fn compare_property_single_ast_node< + 'b, + 's, + 'x: 'b + 's, + R, + RV: std::fmt::Debug, + RG: Fn(R) -> Option, +>( + source: &'s str, + emacs: &'b Token<'s>, + rust_node: R, + emacs_field: &'x str, + rust_value_getter: RG, +) -> Result, Box> +where + AstNode<'b, 's>: From, +{ + let value = get_property(emacs, emacs_field)?; + let rust_value = rust_value_getter(rust_node); + match (value, rust_value) { + (None, None) => {} + (None, rv @ Some(_)) | (Some(_), rv @ None) => { + let this_status = DiffStatus::Bad; + let message = Some(format!( + "{} mismatch (emacs != rust) {:?} != {:?}", + emacs_field, value, rv + )); + return Ok(ComparePropertiesResult::SelfChange(this_status, message)); + } + (Some(ev), Some(rv)) => { + let child_status: Vec> = + vec![compare_ast_node(source, ev, rv.into())?]; + let diff_scope = artificial_diff_scope(emacs_field, child_status)?; + return Ok(ComparePropertiesResult::DiffEntry(diff_scope)); + } + } + Ok(ComparePropertiesResult::NoChange) +} + pub(crate) fn compare_property_list_of_ast_nodes< 'b, 's, diff --git a/src/compare/diff.rs b/src/compare/diff.rs index e782676..16c62e0 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -12,6 +12,7 @@ use super::compare_field::compare_property_list_of_ast_nodes; use super::compare_field::compare_property_list_of_quoted_string; use super::compare_field::compare_property_numeric; use super::compare_field::compare_property_quoted_string; +use super::compare_field::compare_property_single_ast_node; use super::compare_field::compare_property_unquoted_atom; use super::elisp_fact::ElispFact; use super::elisp_fact::GetElispFact; @@ -621,6 +622,86 @@ fn new_compare_heading<'b, 's>( EmacsField::Required(":level"), |r| Some(r.level), compare_property_numeric + ), + ( + EmacsField::Required(":tags"), + |r| if r.tags.is_empty() { + None + } else { + Some(r.tags.iter()) + }, + compare_property_list_of_quoted_string + ), + ( + EmacsField::Required(":todo-keyword"), + |r| r.todo_keyword.as_ref().map(|(_, text)| text), + compare_property_quoted_string + ), + ( + EmacsField::Required(":todo-type"), + |r| r + .todo_keyword + .as_ref() + .map(|(todo_type, _)| todo_type) + .map(|todo_type| match todo_type { + TodoKeywordType::Todo => "todo", + TodoKeywordType::Done => "done", + }), + compare_property_unquoted_atom + ), + ( + EmacsField::Required(":title"), + |r| if r.title.is_empty() { + None + } else { + Some(r.title.iter()) + }, + compare_property_list_of_ast_nodes + ), + ( + EmacsField::Required(":priority"), + |r| r.priority_cookie, + compare_property_numeric + ), + ( + EmacsField::Required(":archivedp"), + |r| r.is_archived, + compare_property_boolean + ), + ( + EmacsField::Required(":commentedp"), + |r| r.is_comment, + compare_property_boolean + ), + ( + EmacsField::Required(":raw-value"), + |r| Some(r.get_raw_value()), + compare_property_quoted_string + ), + ( + EmacsField::Required(":footnote-section-p"), + |r| r.is_footnote_section, + compare_property_boolean + ), + ( + EmacsField::Required(":scheduled"), + |r| r.scheduled.as_ref(), + compare_property_single_ast_node + ), + ( + EmacsField::Required(":deadline"), + |r| r.deadline.as_ref(), + compare_property_single_ast_node + ), + ( + EmacsField::Required(":closed"), + |r| r.closed.as_ref(), + compare_property_single_ast_node + ), + ( + EmacsField::Required(":pre-blank"), + compare_identity, + compare_noop ) ) { match diff {