Markdown parser fork with extended syntax for personal use.
at hack 119 lines 3.3 kB view raw
1//! Label start (image) occurs in the [text][] content type. 2//! 3//! ## Grammar 4//! 5//! Label start (image) forms with the following BNF 6//! (<small>see [construct][crate::construct] for character groups</small>): 7//! 8//! ```bnf 9//! label_start_image ::= '!' '[' 10//! ``` 11//! 12//! ## HTML 13//! 14//! Label start (image) does not, on its own, relate to anything in HTML. 15//! When matched with a [label end][label_end], they together relate to the 16//! `<img>` element in HTML. 17//! See [*§ 4.8.3 The `img` element*][html_img] in the HTML spec for more info. 18//! Without an end, the characters (`![`) are output. 19//! 20//! ## Tokens 21//! 22//! * [`LabelImage`][Name::LabelImage] 23//! * [`LabelImageMarker`][Name::LabelImageMarker] 24//! * [`LabelMarker`][Name::LabelMarker] 25//! 26//! ## References 27//! 28//! * [`label-start-image.js` in `micromark`](https://github.com/micromark/micromark/blob/main/packages/micromark-core-commonmark/dev/lib/label-start-image.js) 29//! * [*§ 6.4 Images* in `CommonMark`](https://spec.commonmark.org/0.31/#images) 30//! 31//! [text]: crate::construct::text 32//! [label_end]: crate::construct::label_end 33//! [html_img]: https://html.spec.whatwg.org/multipage/embedded-content.html#the-img-element 34 35use crate::event::Name; 36use crate::resolve::Name as ResolveName; 37use crate::state::{Name as StateName, State}; 38use crate::tokenizer::{LabelKind, LabelStart, Tokenizer}; 39 40/// Start of label (image) start. 41/// 42/// ```markdown 43/// > | a ![b] c 44/// ^ 45/// ``` 46pub fn start(tokenizer: &mut Tokenizer) -> State { 47 if tokenizer.parse_state.options.constructs.label_start_image && tokenizer.current == Some(b'!') 48 { 49 tokenizer.enter(Name::LabelImage); 50 tokenizer.enter(Name::LabelImageMarker); 51 tokenizer.consume(); 52 tokenizer.exit(Name::LabelImageMarker); 53 State::Next(StateName::LabelStartImageOpen) 54 } else { 55 State::Nok 56 } 57} 58 59/// After `!`, at `[`. 60/// 61/// ```markdown 62/// > | a ![b] c 63/// ^ 64/// ``` 65pub fn open(tokenizer: &mut Tokenizer) -> State { 66 match tokenizer.current { 67 Some(b'[') => { 68 tokenizer.enter(Name::LabelMarker); 69 tokenizer.consume(); 70 tokenizer.exit(Name::LabelMarker); 71 tokenizer.exit(Name::LabelImage); 72 State::Next(StateName::LabelStartImageAfter) 73 } 74 _ => State::Nok, 75 } 76} 77 78/// After `![`. 79/// 80/// ```markdown 81/// > | a ![b] c 82/// ^ 83/// ``` 84/// 85/// This is needed in because, when GFM footnotes are enabled, images never 86/// form when started with a `^`. 87/// Instead, links form: 88/// 89/// ```markdown 90/// ![^a](b) 91/// 92/// ![^a][b] 93/// 94/// [b]: c 95/// ``` 96/// 97/// ```html 98/// <p>!<a href=\"b\">^a</a></p> 99/// <p>!<a href=\"c\">^a</a></p> 100/// ``` 101pub fn after(tokenizer: &mut Tokenizer) -> State { 102 if tokenizer 103 .parse_state 104 .options 105 .constructs 106 .gfm_label_start_footnote 107 && tokenizer.current == Some(b'^') 108 { 109 State::Nok 110 } else { 111 tokenizer.tokenize_state.label_starts.push(LabelStart { 112 kind: LabelKind::Image, 113 start: (tokenizer.events.len() - 6, tokenizer.events.len() - 1), 114 inactive: false, 115 }); 116 tokenizer.register_resolver_before(ResolveName::Label); 117 State::Ok 118 } 119}