Markdown parser fork with extended syntax for personal use.
at hack 153 lines 4.5 kB view raw
1//! Space or tab occurs in tons of places. 2//! 3//! ## Grammar 4//! 5//! Space or tab forms with the following BNF 6//! (<small>see [construct][crate::construct] for character groups</small>): 7//! 8//! ```bnf 9//! space_or_tab ::= 1*('\t' | ' ') 10//! ``` 11//! 12//! ## References 13//! 14//! * [`micromark-factory-space/index.js` in `micromark`](https://github.com/micromark/micromark/blob/main/packages/micromark-factory-space/dev/index.js) 15 16use crate::event::{Content, Link, Name}; 17use crate::state::{Name as StateName, State}; 18use crate::subtokenize::link; 19use crate::tokenizer::Tokenizer; 20 21/// Configuration. 22#[derive(Debug)] 23pub struct Options { 24 /// Minimum allowed bytes (inclusive). 25 pub min: usize, 26 /// Maximum allowed bytes (inclusive). 27 pub max: usize, 28 /// Name to use for events. 29 pub kind: Name, 30 /// Connect this event to the previous. 31 pub connect: bool, 32 /// Embedded content type to use. 33 pub content: Option<Content>, 34} 35 36/// One or more `space_or_tab`. 37/// 38/// ```bnf 39/// space_or_tab ::= 1*( ' ' '\t' ) 40/// ``` 41pub fn space_or_tab(tokenizer: &mut Tokenizer) -> StateName { 42 space_or_tab_min_max(tokenizer, 1, usize::MAX) 43} 44 45/// Between `x` and `y` `space_or_tab`. 46/// 47/// ```bnf 48/// space_or_tab_min_max ::= x*y( ' ' '\t' ) 49/// ``` 50pub fn space_or_tab_min_max(tokenizer: &mut Tokenizer, min: usize, max: usize) -> StateName { 51 space_or_tab_with_options( 52 tokenizer, 53 Options { 54 kind: Name::SpaceOrTab, 55 min, 56 max, 57 content: None, 58 connect: false, 59 }, 60 ) 61} 62 63/// `space_or_tab`, with the given options. 64pub fn space_or_tab_with_options(tokenizer: &mut Tokenizer, options: Options) -> StateName { 65 tokenizer.tokenize_state.space_or_tab_connect = options.connect; 66 tokenizer.tokenize_state.space_or_tab_content = options.content; 67 tokenizer.tokenize_state.space_or_tab_min = options.min; 68 tokenizer.tokenize_state.space_or_tab_max = options.max; 69 tokenizer.tokenize_state.space_or_tab_token = options.kind; 70 StateName::SpaceOrTabStart 71} 72 73/// Start of `space_or_tab`. 74/// 75/// ```markdown 76/// > | a␠␠b 77/// ^ 78/// ``` 79pub fn start(tokenizer: &mut Tokenizer) -> State { 80 if tokenizer.tokenize_state.space_or_tab_max > 0 81 && matches!(tokenizer.current, Some(b'\t' | b' ')) 82 { 83 if let Some(ref content) = tokenizer.tokenize_state.space_or_tab_content { 84 tokenizer.enter_link( 85 tokenizer.tokenize_state.space_or_tab_token.clone(), 86 Link { 87 previous: None, 88 next: None, 89 content: content.clone(), 90 }, 91 ); 92 } else { 93 tokenizer.enter(tokenizer.tokenize_state.space_or_tab_token.clone()); 94 } 95 96 if tokenizer.tokenize_state.space_or_tab_connect { 97 let index = tokenizer.events.len() - 1; 98 link(&mut tokenizer.events, index); 99 } else { 100 tokenizer.tokenize_state.space_or_tab_connect = true; 101 } 102 103 State::Retry(StateName::SpaceOrTabInside) 104 } else { 105 State::Retry(StateName::SpaceOrTabAfter) 106 } 107} 108 109/// In `space_or_tab`. 110/// 111/// ```markdown 112/// > | a␠␠b 113/// ^ 114/// ``` 115pub fn inside(tokenizer: &mut Tokenizer) -> State { 116 match tokenizer.current { 117 Some(b'\t' | b' ') 118 if tokenizer.tokenize_state.space_or_tab_size 119 < tokenizer.tokenize_state.space_or_tab_max => 120 { 121 tokenizer.consume(); 122 tokenizer.tokenize_state.space_or_tab_size += 1; 123 State::Next(StateName::SpaceOrTabInside) 124 } 125 _ => { 126 tokenizer.exit(tokenizer.tokenize_state.space_or_tab_token.clone()); 127 State::Retry(StateName::SpaceOrTabAfter) 128 } 129 } 130} 131 132/// After `space_or_tab`. 133/// 134/// ```markdown 135/// > | a␠␠b 136/// ^ 137/// ``` 138pub fn after(tokenizer: &mut Tokenizer) -> State { 139 let state = if tokenizer.tokenize_state.space_or_tab_size 140 >= tokenizer.tokenize_state.space_or_tab_min 141 { 142 State::Ok 143 } else { 144 State::Nok 145 }; 146 tokenizer.tokenize_state.space_or_tab_connect = false; 147 tokenizer.tokenize_state.space_or_tab_content = None; 148 tokenizer.tokenize_state.space_or_tab_size = 0; 149 tokenizer.tokenize_state.space_or_tab_max = 0; 150 tokenizer.tokenize_state.space_or_tab_min = 0; 151 tokenizer.tokenize_state.space_or_tab_token = Name::SpaceOrTab; 152 state 153}