Introduce the tab_width setting and give tabs a greater value when counting indentation level.
This commit is contained in:
		
							parent
							
								
									c9ce32c881
								
							
						
					
					
						commit
						d443dbd468
					
				| @ -2,6 +2,7 @@ use std::collections::BTreeSet; | ||||
| 
 | ||||
| use super::FileAccessInterface; | ||||
| use super::LocalFileAccessInterface; | ||||
| use crate::types::IndentationLevel; | ||||
| use crate::types::Object; | ||||
| 
 | ||||
| // TODO: Ultimately, I think we'll need most of this: https://orgmode.org/manual/In_002dbuffer-Settings.html
 | ||||
| @ -16,6 +17,11 @@ pub struct GlobalSettings<'g, 's> { | ||||
|     ///
 | ||||
|     /// Corresponds to the org-list-allow-alphabetical elisp variable.
 | ||||
|     pub org_list_allow_alphabetical: bool, | ||||
| 
 | ||||
|     /// How many spaces a tab should be equal to.
 | ||||
|     ///
 | ||||
|     /// Corresponds to the tab-width elisp variable.
 | ||||
|     pub tab_width: IndentationLevel, | ||||
| } | ||||
| 
 | ||||
| impl<'g, 's> GlobalSettings<'g, 's> { | ||||
| @ -28,6 +34,7 @@ impl<'g, 's> GlobalSettings<'g, 's> { | ||||
|             in_progress_todo_keywords: BTreeSet::new(), | ||||
|             complete_todo_keywords: BTreeSet::new(), | ||||
|             org_list_allow_alphabetical: false, | ||||
|             tab_width: 8, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -22,6 +22,7 @@ use super::element_parser::element; | ||||
| use super::object_parser::standard_set_object; | ||||
| use super::org_source::OrgSource; | ||||
| use super::util::include_input; | ||||
| use super::util::indentation_level; | ||||
| use super::util::non_whitespace_character; | ||||
| use crate::context::parser_with_context; | ||||
| use crate::context::ContextElement; | ||||
| @ -39,6 +40,7 @@ use crate::parser::util::maybe_consume_trailing_whitespace_if_not_exiting; | ||||
| use crate::parser::util::org_space; | ||||
| use crate::parser::util::start_of_line; | ||||
| use crate::types::CheckboxType; | ||||
| use crate::types::IndentationLevel; | ||||
| use crate::types::Object; | ||||
| use crate::types::PlainList; | ||||
| use crate::types::PlainListItem; | ||||
| @ -87,7 +89,7 @@ pub(crate) fn plain_list<'b, 'g, 'r, 's>( | ||||
|     let parser_context = parser_context.with_additional_node(&contexts[2]); | ||||
|     // 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<usize> = None; | ||||
|     let mut first_item_indentation: Option<IndentationLevel> = 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:
 | ||||
| @ -148,9 +150,7 @@ fn plain_list_item<'b, 'g, 'r, 's>( | ||||
|     input: OrgSource<'s>, | ||||
| ) -> Res<OrgSource<'s>, PlainListItem<'s>> { | ||||
|     start_of_line(input)?; | ||||
|     let (remaining, leading_whitespace) = space0(input)?; | ||||
|     // It is fine that we get the indent level using the number of bytes rather than the number of characters because nom's space0 only matches space and tab (0x20 and 0x09)
 | ||||
|     let indent_level = leading_whitespace.len(); | ||||
|     let (remaining, (indent_level, _leading_whitespace)) = indentation_level(context, input)?; | ||||
|     let (remaining, bull) = verify( | ||||
|         parser_with_context!(bullet)(context), | ||||
|         |bull: &OrgSource<'_>| Into::<&str>::into(bull) != "*" || indent_level > 0, | ||||
| @ -287,7 +287,7 @@ fn plain_list_end<'b, 'g, 'r, 's>( | ||||
|     )))(input) | ||||
| } | ||||
| 
 | ||||
| const fn plain_list_item_end(indent_level: usize) -> impl ContextMatcher { | ||||
| const fn plain_list_item_end(indent_level: IndentationLevel) -> impl ContextMatcher { | ||||
|     let line_indented_lte_matcher = line_indented_lte(indent_level); | ||||
|     move |context, input: OrgSource<'_>| { | ||||
|         _plain_list_item_end(context, input, &line_indented_lte_matcher) | ||||
| @ -310,20 +310,23 @@ fn _plain_list_item_end<'b, 'g, 'r, 's>( | ||||
|     )))(input) | ||||
| } | ||||
| 
 | ||||
| const fn line_indented_lte(indent_level: usize) -> impl ContextMatcher { | ||||
| const fn line_indented_lte(indent_level: IndentationLevel) -> impl ContextMatcher { | ||||
|     move |context, input: OrgSource<'_>| _line_indented_lte(context, input, indent_level) | ||||
| } | ||||
| 
 | ||||
| #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] | ||||
| fn _line_indented_lte<'b, 'g, 'r, 's>( | ||||
|     _context: RefContext<'b, 'g, 'r, 's>, | ||||
|     context: RefContext<'b, 'g, 'r, 's>, | ||||
|     input: OrgSource<'s>, | ||||
|     indent_level: usize, | ||||
|     indent_level: IndentationLevel, | ||||
| ) -> Res<OrgSource<'s>, OrgSource<'s>> { | ||||
|     let matched = recognize(verify( | ||||
|         tuple((space0::<OrgSource<'_>, _>, non_whitespace_character)), | ||||
|         tuple(( | ||||
|             parser_with_context!(indentation_level)(context), | ||||
|             non_whitespace_character, | ||||
|         )), | ||||
|         // It is fine that we get the indent level using the number of bytes rather than the number of characters because nom's space0 only matches space and tab (0x20 and 0x09)
 | ||||
|         |(_space0, _anychar)| _space0.len() <= indent_level, | ||||
|         |((indentation_level, _leading_whitespace), _anychar)| *indentation_level <= indent_level, | ||||
|     ))(input)?; | ||||
| 
 | ||||
|     Ok(matched) | ||||
|  | ||||
| @ -20,6 +20,7 @@ use crate::context::RefContext; | ||||
| use crate::error::CustomError; | ||||
| use crate::error::MyError; | ||||
| use crate::error::Res; | ||||
| use crate::types::IndentationLevel; | ||||
| 
 | ||||
| pub(crate) const WORD_CONSTITUENT_CHARACTERS: &str = | ||||
|     "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; | ||||
| @ -240,7 +241,7 @@ pub(crate) fn org_space<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, char> { | ||||
| pub(crate) fn org_space_or_line_ending<'s>( | ||||
|     input: OrgSource<'s>, | ||||
| ) -> Res<OrgSource<'s>, OrgSource<'s>> { | ||||
|     alt((recognize(one_of(" \t")), org_line_ending))(input) | ||||
|     alt((recognize(org_space), org_line_ending))(input) | ||||
| } | ||||
| 
 | ||||
| /// Match a line break or the end of the file.
 | ||||
| @ -249,3 +250,20 @@ pub(crate) fn org_space_or_line_ending<'s>( | ||||
| pub(crate) fn org_line_ending<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> { | ||||
|     alt((line_ending, eof))(input) | ||||
| } | ||||
| 
 | ||||
| /// Match the whitespace at the beginning of a line and give it an indentation level.
 | ||||
| pub(crate) fn indentation_level<'b, 'g, 'r, 's>( | ||||
|     context: RefContext<'b, 'g, 'r, 's>, | ||||
|     input: OrgSource<'s>, | ||||
| ) -> Res<OrgSource<'s>, (IndentationLevel, OrgSource<'s>)> { | ||||
|     let (remaining, leading_whitespace) = space0(input)?; | ||||
|     let indentation_level = Into::<&str>::into(leading_whitespace) | ||||
|         .chars() | ||||
|         .map(|c| match c { | ||||
|             ' ' => 1, | ||||
|             '\t' => context.get_global_settings().tab_width, | ||||
|             _ => unreachable!(), | ||||
|         }) | ||||
|         .sum(); | ||||
|     Ok((remaining, (indentation_level, leading_whitespace))) | ||||
| } | ||||
|  | ||||
| @ -10,10 +10,13 @@ pub struct PlainList<'s> { | ||||
|     pub children: Vec<PlainListItem<'s>>, | ||||
| } | ||||
| 
 | ||||
| /// The width that something is indented. For example, a single tab character could be a value of 4 or 8.
 | ||||
| pub type IndentationLevel = u16; | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub struct PlainListItem<'s> { | ||||
|     pub source: &'s str, | ||||
|     pub indentation: usize, | ||||
|     pub indentation: IndentationLevel, | ||||
|     pub bullet: &'s str, | ||||
|     pub checkbox: Option<(CheckboxType, &'s str)>, | ||||
|     pub tag: Vec<Object<'s>>, | ||||
|  | ||||
| @ -16,6 +16,7 @@ pub use greater_element::Drawer; | ||||
| pub use greater_element::DynamicBlock; | ||||
| pub use greater_element::FootnoteDefinition; | ||||
| pub use greater_element::GreaterBlock; | ||||
| pub use greater_element::IndentationLevel; | ||||
| pub use greater_element::NodeProperty; | ||||
| pub use greater_element::PlainList; | ||||
| pub use greater_element::PlainListItem; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Tom Alexander
						Tom Alexander