Parse out the plain list type.
This commit is contained in:
		
							parent
							
								
									1b7326eafe
								
							
						
					
					
						commit
						a4b1d462c3
					
				| @ -44,6 +44,7 @@ use crate::types::IndentationLevel; | ||||
| use crate::types::Object; | ||||
| use crate::types::PlainList; | ||||
| use crate::types::PlainListItem; | ||||
| use crate::types::PlainListType; | ||||
| 
 | ||||
| #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] | ||||
| pub(crate) fn detect_plain_list<'b, 'g, 'r, 's>( | ||||
| @ -90,6 +91,7 @@ pub(crate) fn plain_list<'b, 'g, 'r, 's>( | ||||
|     // children stores tuple of (input string, parsed object) so we can re-parse the final item
 | ||||
|     let mut children = Vec::new(); | ||||
|     let mut first_item_indentation: Option<IndentationLevel> = None; | ||||
|     let mut first_item_list_type: Option<PlainListType> = None; | ||||
|     let mut remaining = input; | ||||
| 
 | ||||
|     // The final list item does not consume trailing blank lines (which instead get consumed by the list). We have three options here:
 | ||||
| @ -102,8 +104,15 @@ pub(crate) fn plain_list<'b, 'g, 'r, 's>( | ||||
| 
 | ||||
|     loop { | ||||
|         let list_item = parser_with_context!(plain_list_item)(&parser_context)(remaining); | ||||
|         match (&first_item_list_type, &list_item) { | ||||
|             (None, Ok((_remain, (list_type, _item)))) => { | ||||
|                 let _ = first_item_list_type.insert(*list_type); | ||||
|             } | ||||
|             (None, Err(_)) => {} | ||||
|             (Some(_), _) => {} | ||||
|         }; | ||||
|         match list_item { | ||||
|             Ok((remain, item)) | ||||
|             Ok((remain, (_list_type, item))) | ||||
|                 if item.indentation == *first_item_indentation.get_or_insert(item.indentation) => | ||||
|             { | ||||
|                 children.push((remaining, item)); | ||||
| @ -130,7 +139,7 @@ pub(crate) fn plain_list<'b, 'g, 'r, 's>( | ||||
|     }; | ||||
|     let final_item_context = ContextElement::ConsumeTrailingWhitespace(false); | ||||
|     let final_item_context = parser_context.with_additional_node(&final_item_context); | ||||
|     let (remaining, reparsed_final_item) = | ||||
|     let (remaining, (_, reparsed_final_item)) = | ||||
|         parser_with_context!(plain_list_item)(&final_item_context)(final_child_start)?; | ||||
|     children.push((final_child_start, reparsed_final_item)); | ||||
| 
 | ||||
| @ -139,6 +148,7 @@ pub(crate) fn plain_list<'b, 'g, 'r, 's>( | ||||
|         remaining, | ||||
|         PlainList { | ||||
|             source: source.into(), | ||||
|             list_type: PlainListType::Ordered, | ||||
|             children: children.into_iter().map(|(_start, item)| item).collect(), | ||||
|         }, | ||||
|     )) | ||||
| @ -148,7 +158,7 @@ pub(crate) fn plain_list<'b, 'g, 'r, 's>( | ||||
| fn plain_list_item<'b, 'g, 'r, 's>( | ||||
|     context: RefContext<'b, 'g, 'r, 's>, | ||||
|     input: OrgSource<'s>, | ||||
| ) -> Res<OrgSource<'s>, PlainListItem<'s>> { | ||||
| ) -> Res<OrgSource<'s>, (PlainListType, PlainListItem<'s>)> { | ||||
|     start_of_line(input)?; | ||||
|     let (remaining, (indent_level, _leading_whitespace)) = indentation_level(context, input)?; | ||||
|     let (remaining, (bullet_type, bull)) = verify( | ||||
| @ -170,6 +180,12 @@ fn plain_list_item<'b, 'g, 'r, 's>( | ||||
|     } else { | ||||
|         (remaining, None) | ||||
|     }; | ||||
|     let list_type = match (&maybe_tag, bullet_type) { | ||||
|         (None, BulletType::Ordered) => PlainListType::Ordered, | ||||
|         (None, BulletType::Unordered) => PlainListType::Unordered, | ||||
|         (Some(_), BulletType::Ordered) => unreachable!(), | ||||
|         (Some(_), BulletType::Unordered) => PlainListType::Descriptive, | ||||
|     }; | ||||
| 
 | ||||
|     let exit_matcher = plain_list_item_end(indent_level); | ||||
|     let contexts = [ | ||||
| @ -195,16 +211,19 @@ fn plain_list_item<'b, 'g, 'r, 's>( | ||||
|             let source = get_consumed(input, remaining); | ||||
|             return Ok(( | ||||
|                 remaining, | ||||
|                 PlainListItem { | ||||
|                     source: source.into(), | ||||
|                     indentation: indent_level, | ||||
|                     bullet: bull.into(), | ||||
|                     checkbox: None, | ||||
|                     tag: maybe_tag | ||||
|                         .map(|(_ws, item_tag)| item_tag) | ||||
|                         .unwrap_or(Vec::new()), | ||||
|                     children: Vec::new(), | ||||
|                 }, | ||||
|                 ( | ||||
|                     list_type, | ||||
|                     PlainListItem { | ||||
|                         source: source.into(), | ||||
|                         indentation: indent_level, | ||||
|                         bullet: bull.into(), | ||||
|                         checkbox: None, | ||||
|                         tag: maybe_tag | ||||
|                             .map(|(_ws, item_tag)| item_tag) | ||||
|                             .unwrap_or(Vec::new()), | ||||
|                         children: Vec::new(), | ||||
|                     }, | ||||
|                 ), | ||||
|             )); | ||||
|         } | ||||
|         Err(_) => {} | ||||
| @ -235,17 +254,21 @@ fn plain_list_item<'b, 'g, 'r, 's>( | ||||
|     let source = get_consumed(input, remaining); | ||||
|     return Ok(( | ||||
|         remaining, | ||||
|         PlainListItem { | ||||
|             source: source.into(), | ||||
|             indentation: indent_level, | ||||
|             bullet: bull.into(), | ||||
|             checkbox: maybe_checkbox | ||||
|                 .map(|(_, (checkbox_type, source))| (checkbox_type, Into::<&str>::into(source))), | ||||
|             tag: maybe_tag | ||||
|                 .map(|(_ws, item_tag)| item_tag) | ||||
|                 .unwrap_or(Vec::new()), | ||||
|             children: children.into_iter().map(|(_start, item)| item).collect(), | ||||
|         }, | ||||
|         ( | ||||
|             list_type, | ||||
|             PlainListItem { | ||||
|                 source: source.into(), | ||||
|                 indentation: indent_level, | ||||
|                 bullet: bull.into(), | ||||
|                 checkbox: maybe_checkbox.map(|(_, (checkbox_type, source))| { | ||||
|                     (checkbox_type, Into::<&str>::into(source)) | ||||
|                 }), | ||||
|                 tag: maybe_tag | ||||
|                     .map(|(_ws, item_tag)| item_tag) | ||||
|                     .unwrap_or(Vec::new()), | ||||
|                 children: children.into_iter().map(|(_start, item)| item).collect(), | ||||
|             }, | ||||
|         ), | ||||
|     )); | ||||
| } | ||||
| 
 | ||||
| @ -454,7 +477,7 @@ mod tests { | ||||
|         let initial_context = ContextElement::document_context(); | ||||
|         let initial_context = Context::new(&global_settings, List::new(&initial_context)); | ||||
|         let plain_list_item_matcher = parser_with_context!(plain_list_item)(&initial_context); | ||||
|         let (remaining, result) = plain_list_item_matcher(input).unwrap(); | ||||
|         let (remaining, (_, result)) = plain_list_item_matcher(input).unwrap(); | ||||
|         assert_eq!(Into::<&str>::into(remaining), ""); | ||||
|         assert_eq!(result.get_standard_properties().get_source(), "1."); | ||||
|     } | ||||
| @ -466,7 +489,7 @@ mod tests { | ||||
|         let initial_context = ContextElement::document_context(); | ||||
|         let initial_context = Context::new(&global_settings, List::new(&initial_context)); | ||||
|         let plain_list_item_matcher = parser_with_context!(plain_list_item)(&initial_context); | ||||
|         let (remaining, result) = plain_list_item_matcher(input).unwrap(); | ||||
|         let (remaining, (_, result)) = plain_list_item_matcher(input).unwrap(); | ||||
|         assert_eq!(Into::<&str>::into(remaining), ""); | ||||
|         assert_eq!(result.get_standard_properties().get_source(), "1. foo"); | ||||
|     } | ||||
|  | ||||
| @ -7,9 +7,17 @@ use super::StandardProperties; | ||||
| #[derive(Debug)] | ||||
| pub struct PlainList<'s> { | ||||
|     pub source: &'s str, | ||||
|     pub list_type: PlainListType, | ||||
|     pub children: Vec<PlainListItem<'s>>, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Copy, Clone)] | ||||
| pub enum PlainListType { | ||||
|     Unordered, | ||||
|     Ordered, | ||||
|     Descriptive, | ||||
| } | ||||
| 
 | ||||
| /// The width that something is indented. For example, a single tab character could be a value of 4 or 8.
 | ||||
| pub type IndentationLevel = u16; | ||||
| 
 | ||||
|  | ||||
| @ -24,6 +24,7 @@ pub use greater_element::IndentationLevel; | ||||
| pub use greater_element::NodeProperty; | ||||
| pub use greater_element::PlainList; | ||||
| pub use greater_element::PlainListItem; | ||||
| pub use greater_element::PlainListType; | ||||
| pub use greater_element::PropertyDrawer; | ||||
| pub use greater_element::Table; | ||||
| pub use greater_element::TableRow; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Tom Alexander
						Tom Alexander