Merge branch 'planning_properties'
This commit is contained in:
		
						commit
						0654b676f7
					
				| @ -719,9 +719,58 @@ fn compare_heading<'b, 's>( | ||||
|         )); | ||||
|     } | ||||
| 
 | ||||
|     // TODO: Compare :pre-blank :scheduled :closed
 | ||||
|     //
 | ||||
|     // :scheduled and :closed seem to only appear when the headline has a planning
 | ||||
|     // Compare scheduled
 | ||||
|     let scheduled = get_property(emacs, ":scheduled")?; | ||||
|     match (scheduled, &rust.scheduled) { | ||||
|         (None, None) => {} | ||||
|         (None, Some(_)) | (Some(_), None) => { | ||||
|             this_status = DiffStatus::Bad; | ||||
|             message = Some(format!( | ||||
|                 "Scheduled mismatch (emacs != rust) {:?} != {:?}", | ||||
|                 scheduled, rust.scheduled | ||||
|             )); | ||||
|         } | ||||
|         (Some(emacs_child), Some(rust_child)) => { | ||||
|             let result = compare_ast_node(source, emacs_child, rust_child.into())?; | ||||
|             child_status.push(artificial_diff_scope("scheduled", vec![result])?); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Compare deadline
 | ||||
|     let deadline = get_property(emacs, ":deadline")?; | ||||
|     match (deadline, &rust.deadline) { | ||||
|         (None, None) => {} | ||||
|         (None, Some(_)) | (Some(_), None) => { | ||||
|             this_status = DiffStatus::Bad; | ||||
|             message = Some(format!( | ||||
|                 "Deadline mismatch (emacs != rust) {:?} != {:?}", | ||||
|                 deadline, rust.deadline | ||||
|             )); | ||||
|         } | ||||
|         (Some(emacs_child), Some(rust_child)) => { | ||||
|             let result = compare_ast_node(source, emacs_child, rust_child.into())?; | ||||
|             child_status.push(artificial_diff_scope("deadline", vec![result])?); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Compare closed
 | ||||
|     let closed = get_property(emacs, ":closed")?; | ||||
|     match (closed, &rust.closed) { | ||||
|         (None, None) => {} | ||||
|         (None, Some(_)) | (Some(_), None) => { | ||||
|             this_status = DiffStatus::Bad; | ||||
|             message = Some(format!( | ||||
|                 "Closed mismatch (emacs != rust) {:?} != {:?}", | ||||
|                 closed, rust.closed | ||||
|             )); | ||||
|         } | ||||
|         (Some(emacs_child), Some(rust_child)) => { | ||||
|             let result = compare_ast_node(source, emacs_child, rust_child.into())?; | ||||
|             child_status.push(artificial_diff_scope("closed", vec![result])?); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // TODO: Compare :pre-blank
 | ||||
| 
 | ||||
|     // Compare section
 | ||||
|     let section_status = children | ||||
| @ -1402,20 +1451,70 @@ fn compare_diary_sexp<'b, 's>( | ||||
| } | ||||
| 
 | ||||
| fn compare_planning<'b, 's>( | ||||
|     _source: &'s str, | ||||
|     source: &'s str, | ||||
|     emacs: &'b Token<'s>, | ||||
|     rust: &'b Planning<'s>, | ||||
| ) -> Result<DiffEntry<'b, 's>, Box<dyn std::error::Error>> { | ||||
|     let this_status = DiffStatus::Good; | ||||
|     let message = None; | ||||
|     let mut child_status = Vec::new(); | ||||
|     let mut this_status = DiffStatus::Good; | ||||
|     let mut message = None; | ||||
| 
 | ||||
|     // TODO: Compare :closed :deadline :scheduled
 | ||||
|     // Compare scheduled
 | ||||
|     let scheduled = get_property(emacs, ":scheduled")?; | ||||
|     match (scheduled, &rust.scheduled) { | ||||
|         (None, None) => {} | ||||
|         (None, Some(_)) | (Some(_), None) => { | ||||
|             this_status = DiffStatus::Bad; | ||||
|             message = Some(format!( | ||||
|                 "Scheduled mismatch (emacs != rust) {:?} != {:?}", | ||||
|                 scheduled, rust.scheduled | ||||
|             )); | ||||
|         } | ||||
|         (Some(emacs_child), Some(rust_child)) => { | ||||
|             let result = compare_ast_node(source, emacs_child, rust_child.into())?; | ||||
|             child_status.push(artificial_diff_scope("scheduled", vec![result])?); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Compare deadline
 | ||||
|     let deadline = get_property(emacs, ":deadline")?; | ||||
|     match (deadline, &rust.deadline) { | ||||
|         (None, None) => {} | ||||
|         (None, Some(_)) | (Some(_), None) => { | ||||
|             this_status = DiffStatus::Bad; | ||||
|             message = Some(format!( | ||||
|                 "Deadline mismatch (emacs != rust) {:?} != {:?}", | ||||
|                 deadline, rust.deadline | ||||
|             )); | ||||
|         } | ||||
|         (Some(emacs_child), Some(rust_child)) => { | ||||
|             let result = compare_ast_node(source, emacs_child, rust_child.into())?; | ||||
|             child_status.push(artificial_diff_scope("deadline", vec![result])?); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Compare closed
 | ||||
|     let closed = get_property(emacs, ":closed")?; | ||||
|     match (closed, &rust.closed) { | ||||
|         (None, None) => {} | ||||
|         (None, Some(_)) | (Some(_), None) => { | ||||
|             this_status = DiffStatus::Bad; | ||||
|             message = Some(format!( | ||||
|                 "Closed mismatch (emacs != rust) {:?} != {:?}", | ||||
|                 closed, rust.closed | ||||
|             )); | ||||
|         } | ||||
|         (Some(emacs_child), Some(rust_child)) => { | ||||
|             let result = compare_ast_node(source, emacs_child, rust_child.into())?; | ||||
|             child_status.push(artificial_diff_scope("closed", vec![result])?); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     Ok(DiffResult { | ||||
|         status: this_status, | ||||
|         name: rust.get_elisp_name(), | ||||
|         message, | ||||
|         children: Vec::new(), | ||||
|         children: child_status, | ||||
|         rust_source: rust.get_source(), | ||||
|         emacs_token: emacs, | ||||
|     } | ||||
|  | ||||
| @ -34,6 +34,7 @@ use crate::error::Res; | ||||
| use crate::parser::object_parser::standard_set_object; | ||||
| use crate::parser::util::blank_line; | ||||
| use crate::types::DocumentElement; | ||||
| use crate::types::Element; | ||||
| use crate::types::Heading; | ||||
| use crate::types::HeadlineLevel; | ||||
| use crate::types::Object; | ||||
| @ -55,6 +56,9 @@ fn _heading<'b, 'g, 'r, 's>( | ||||
|     input: OrgSource<'s>, | ||||
|     parent_star_count: HeadlineLevel, | ||||
| ) -> Res<OrgSource<'s>, Heading<'s>> { | ||||
|     let mut scheduled = None; | ||||
|     let mut deadline = None; | ||||
|     let mut closed = None; | ||||
|     not(|i| context.check_exit_matcher(i))(input)?; | ||||
|     let (remaining, pre_headline) = headline(context, input, parent_star_count)?; | ||||
|     let section_matcher = parser_with_context!(section)(context); | ||||
| @ -65,6 +69,14 @@ fn _heading<'b, 'g, 'r, 's>( | ||||
|     let (remaining, mut children) = | ||||
|         many0(map(heading_matcher, DocumentElement::Heading))(remaining)?; | ||||
|     if let Some(section) = maybe_section { | ||||
|         // If the section has a planning then the timestamp values are copied to the heading.
 | ||||
|         if let DocumentElement::Section(inner_section) = §ion { | ||||
|             if let Some(Element::Planning(planning)) = inner_section.children.first() { | ||||
|                 scheduled = planning.scheduled.clone(); | ||||
|                 deadline = planning.deadline.clone(); | ||||
|                 closed = planning.closed.clone(); | ||||
|             } | ||||
|         } | ||||
|         children.insert(0, section); | ||||
|     } | ||||
|     let remaining = if children.is_empty() { | ||||
| @ -94,6 +106,9 @@ fn _heading<'b, 'g, 'r, 's>( | ||||
|             is_comment: pre_headline.comment.is_some(), | ||||
|             is_archived, | ||||
|             is_footnote_section: pre_headline.is_footnote_section, | ||||
|             scheduled, | ||||
|             deadline, | ||||
|             closed, | ||||
|         }, | ||||
|     )) | ||||
| } | ||||
|  | ||||
| @ -3,6 +3,7 @@ use nom::bytes::complete::tag; | ||||
| use nom::bytes::complete::tag_no_case; | ||||
| use nom::character::complete::space0; | ||||
| use nom::character::complete::space1; | ||||
| use nom::combinator::map; | ||||
| use nom::multi::many1; | ||||
| use nom::sequence::tuple; | ||||
| 
 | ||||
| @ -16,6 +17,7 @@ use crate::error::Res; | ||||
| use crate::parser::util::get_consumed; | ||||
| use crate::parser::util::start_of_line; | ||||
| use crate::types::Planning; | ||||
| use crate::types::Timestamp; | ||||
| 
 | ||||
| #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] | ||||
| pub(crate) fn planning<'b, 'g, 'r, 's>( | ||||
| @ -24,7 +26,7 @@ pub(crate) fn planning<'b, 'g, 'r, 's>( | ||||
| ) -> Res<OrgSource<'s>, Planning<'s>> { | ||||
|     start_of_line(input)?; | ||||
|     let (remaining, _leading_whitespace) = space0(input)?; | ||||
|     let (remaining, _planning_parameters) = | ||||
|     let (remaining, planning_parameters) = | ||||
|         many1(parser_with_context!(planning_parameter)(context))(remaining)?; | ||||
|     let (remaining, _trailing_ws) = tuple((space0, org_line_ending))(remaining)?; | ||||
| 
 | ||||
| @ -32,26 +34,54 @@ pub(crate) fn planning<'b, 'g, 'r, 's>( | ||||
|         maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?; | ||||
|     let source = get_consumed(input, remaining); | ||||
| 
 | ||||
|     let mut scheduled = None; | ||||
|     let mut deadline = None; | ||||
|     let mut closed = None; | ||||
| 
 | ||||
|     for (timestamp_type, timestamp) in planning_parameters.into_iter() { | ||||
|         match timestamp_type { | ||||
|             PlanningTimestampType::Scheduled => { | ||||
|                 scheduled = Some(timestamp); | ||||
|             } | ||||
|             PlanningTimestampType::Deadline => { | ||||
|                 deadline = Some(timestamp); | ||||
|             } | ||||
|             PlanningTimestampType::Closed => { | ||||
|                 closed = Some(timestamp); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     Ok(( | ||||
|         remaining, | ||||
|         Planning { | ||||
|             source: source.into(), | ||||
|             scheduled, | ||||
|             deadline, | ||||
|             closed, | ||||
|         }, | ||||
|     )) | ||||
| } | ||||
| 
 | ||||
| enum PlanningTimestampType { | ||||
|     Scheduled, | ||||
|     Deadline, | ||||
|     Closed, | ||||
| } | ||||
| 
 | ||||
| #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] | ||||
| fn planning_parameter<'b, 'g, 'r, 's>( | ||||
|     context: RefContext<'b, 'g, 'r, 's>, | ||||
|     input: OrgSource<'s>, | ||||
| ) -> Res<OrgSource<'s>, OrgSource<'s>> { | ||||
|     let (remaining, _planning_type) = alt(( | ||||
|         tag_no_case("DEADLINE"), | ||||
|         tag_no_case("SCHEDULED"), | ||||
|         tag_no_case("CLOSED"), | ||||
| ) -> Res<OrgSource<'s>, (PlanningTimestampType, Timestamp<'s>)> { | ||||
|     let (remaining, planning_type) = alt(( | ||||
|         map(tag_no_case("DEADLINE"), |_| PlanningTimestampType::Deadline), | ||||
|         map(tag_no_case("SCHEDULED"), |_| { | ||||
|             PlanningTimestampType::Scheduled | ||||
|         }), | ||||
|         map(tag_no_case("CLOSED"), |_| PlanningTimestampType::Closed), | ||||
|     ))(input)?; | ||||
|     let (remaining, _gap) = tuple((tag(":"), space1))(remaining)?; | ||||
|     let (remaining, _timestamp) = timestamp(context, remaining)?; | ||||
|     let source = get_consumed(input, remaining); | ||||
|     Ok((remaining, source)) | ||||
|     let (remaining, timestamp) = timestamp(context, remaining)?; | ||||
|     Ok((remaining, (planning_type, timestamp))) | ||||
| } | ||||
|  | ||||
| @ -4,6 +4,7 @@ use super::Element; | ||||
| use super::GetStandardProperties; | ||||
| use super::Object; | ||||
| use super::StandardProperties; | ||||
| use super::Timestamp; | ||||
| 
 | ||||
| pub type PriorityCookie = u8; | ||||
| pub type HeadlineLevel = u16; | ||||
| @ -29,6 +30,9 @@ pub struct Heading<'s> { | ||||
|     pub is_comment: bool, | ||||
|     pub is_archived: bool, | ||||
|     pub is_footnote_section: bool, | ||||
|     pub scheduled: Option<Timestamp<'s>>, | ||||
|     pub deadline: Option<Timestamp<'s>>, | ||||
|     pub closed: Option<Timestamp<'s>>, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| use super::object::Object; | ||||
| use super::PlainText; | ||||
| use super::StandardProperties; | ||||
| use super::Timestamp; | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub struct Paragraph<'s> { | ||||
| @ -72,6 +73,9 @@ pub struct DiarySexp<'s> { | ||||
| #[derive(Debug)] | ||||
| pub struct Planning<'s> { | ||||
|     pub source: &'s str, | ||||
|     pub scheduled: Option<Timestamp<'s>>, | ||||
|     pub deadline: Option<Timestamp<'s>>, | ||||
|     pub closed: Option<Timestamp<'s>>, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
|  | ||||
| @ -182,7 +182,7 @@ pub struct Superscript<'s> { | ||||
|     pub source: &'s str, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, PartialEq)] | ||||
| #[derive(Debug, PartialEq, Clone)] | ||||
| pub struct Timestamp<'s> { | ||||
|     pub source: &'s str, | ||||
|     pub timestamp_type: TimestampType, | ||||
| @ -195,7 +195,7 @@ pub struct Timestamp<'s> { | ||||
|     pub warning_delay: Option<WarningDelay>, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, PartialEq)] | ||||
| #[derive(Debug, PartialEq, Clone)] | ||||
| pub enum TimestampType { | ||||
|     Diary, | ||||
|     Active, | ||||
| @ -204,7 +204,7 @@ pub enum TimestampType { | ||||
|     InactiveRange, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, PartialEq)] | ||||
| #[derive(Debug, PartialEq, Clone)] | ||||
| pub enum TimestampRangeType { | ||||
|     None, | ||||
|     DateRange, | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Tom Alexander
						Tom Alexander