Markdown parser fork with extended syntax for personal use.
at hack 98 lines 3.0 kB view raw
1//! wikilink occurs in the [[text]][] content type. 2//! 3//! ## Grammar 4//! 5//! ```bnf 6//! wikilink ::= '[[' label opt_alias opt_heading opt_block ']]' 7//! 8//! opt_alias ::= '|' label | '' 9//! opt_heading ::= '#' label | '' 10//! opt_block ::= '^' label | '' 11//! 12//! ; See the `label` constructs for the BNF of 13//! ; those parts. 14//! ``` 15//! 16 17use crate::event::Name; 18use crate::state::Name as MoveName; 19use crate::state::State; 20use crate::tokenizer::{Label, LabelKind, LabelStart, Tokenizer}; 21 22/// Start of label (link) start. 23/// 24/// ```markdown 25/// > | a [b] c 26/// ^ 27/// ``` 28pub fn start(tokenizer: &mut Tokenizer) -> State { 29 if !tokenizer.parse_state.options.constructs.wikilink { 30 return State::Retry(MoveName::TextBeforeLabelStartLink); 31 } 32 33 let start_conditions = tokenizer.current == Some(b'['); 34 35 if start_conditions && tokenizer.tokenize_state.size == 0 { 36 tokenizer.tokenize_state.size += 1; 37 tokenizer.attempt( 38 State::Next(MoveName::WikilinkLabelStart), 39 State::Next(MoveName::TextBeforeLabelStartLink), 40 ); 41 42 tokenizer.consume(); 43 State::Next(MoveName::WikilinkStart) 44 } else if start_conditions && tokenizer.tokenize_state.size == 1 { 45 tokenizer.tokenize_state.size = 0; 46 let start = tokenizer.events.len(); 47 48 tokenizer.enter(Name::WikilinkStart); 49 // // tokenizer.enter(Name::LabelMarker); 50 tokenizer.consume(); 51 // // tokenizer.exit(Name::LabelMarker); 52 tokenizer.exit(Name::WikilinkStart); 53 54 tokenizer.tokenize_state.wikilink_starts.push(LabelStart { 55 kind: LabelKind::Link, 56 start: (start, tokenizer.events.len()), 57 inactive: false, 58 }); 59 State::Ok 60 } else { 61 tokenizer.tokenize_state.size = 0; 62 63 // Resume the "regular" sequence of state transitions 64 State::Nok 65 // State::Retry(MoveName::TextBeforeLabelStartLink) 66 } 67} 68 69pub fn end(tokenizer: &mut Tokenizer) -> State { 70 if Some(b']') == tokenizer.current 71 && Some(b']') == tokenizer.previous 72 && tokenizer.parse_state.options.constructs.wikilink 73 && !tokenizer.tokenize_state.wikilink_starts.is_empty() 74 { 75 let wikilink_start = tokenizer.tokenize_state.wikilink_starts.last().unwrap(); 76 tokenizer.tokenize_state.end = tokenizer.events.len(); 77 78 // If the corresponding label (link) start is marked as inactive, 79 // it means we’d be wrapping a link, like this: 80 // 81 // ```markdown 82 // > | a [b [c](d) e](f) g. 83 // ^ 84 // ``` 85 // 86 // We can’t have that, so it’s just balanced brackets. 87 if wikilink_start.inactive { 88 return State::Retry(MoveName::WikilinkEndNok); 89 } 90 91 tokenizer.enter(Name::WikilinkEnd); 92 tokenizer.consume(); 93 tokenizer.exit(Name::WikilinkEnd); 94 return State::Ok; 95 } 96 97 State::Nok 98}