Markdown parser fork with extended syntax for personal use.
1//! Label start (footnote) occurs in the [text][] content type.
2//!
3//! ## Grammar
4//!
5//! Label start (footnote) forms with the following BNF
6//! (<small>see [construct][crate::construct] for character groups</small>):
7//!
8//! ```bnf
9//! gfm_label_start_footnote ::= '[' '^'
10//! ```
11//!
12//! ## HTML
13//!
14//! Label start (footnote) does not, on its own, relate to anything in HTML.
15//! When matched with a [label end][label_end], they together relate to `<sup>`
16//! and `<a>` elements in HTML.
17//! See [*§ 4.5.19 The `sub` and `sup` elements*][html_sup] and
18//! [*§ 4.5.1 The `a` element*][html_a] in the HTML spec for more info.
19//! Without an end, the characters (`[^`) are output.
20//!
21//! ## Tokens
22//!
23//! * [`GfmFootnoteCallLabel`][Name::GfmFootnoteCallLabel]
24//! * [`GfmFootnoteCallMarker`][Name::GfmFootnoteCallMarker]
25//! * [`LabelMarker`][Name::LabelMarker]
26//!
27//! ## References
28//!
29//! * [`micromark-extension-gfm-footnote`](https://github.com/micromark/micromark-extension-gfm-footnote)
30//!
31//! > 👉 **Note**: Footnotes are not specified in GFM yet.
32//! > See [`github/cmark-gfm#270`](https://github.com/github/cmark-gfm/issues/270)
33//! > for the related issue.
34//!
35//! [text]: crate::construct::text
36//! [label_end]: crate::construct::label_end
37//! [html_a]: https://html.spec.whatwg.org/multipage/text-level-semantics.html#the-a-element
38//! [html_sup]: https://html.spec.whatwg.org/multipage/text-level-semantics.html#the-sub-and-sup-elements
39
40use crate::event::Name;
41use crate::resolve::Name as ResolveName;
42use crate::state::{Name as StateName, State};
43use crate::tokenizer::{LabelKind, LabelStart, Tokenizer};
44
45/// Start of label (footnote) start.
46///
47/// ```markdown
48/// > | a [^b] c
49/// ^
50/// ```
51pub fn start(tokenizer: &mut Tokenizer) -> State {
52 if tokenizer
53 .parse_state
54 .options
55 .constructs
56 .gfm_label_start_footnote
57 && tokenizer.current == Some(b'[')
58 {
59 tokenizer.enter(Name::GfmFootnoteCallLabel);
60 tokenizer.enter(Name::LabelMarker);
61 tokenizer.consume();
62 tokenizer.exit(Name::LabelMarker);
63 State::Next(StateName::GfmLabelStartFootnoteOpen)
64 } else {
65 State::Nok
66 }
67}
68
69/// After `[`, at `^`.
70///
71/// ```markdown
72/// > | a [^b] c
73/// ^
74/// ```
75pub fn open(tokenizer: &mut Tokenizer) -> State {
76 match tokenizer.current {
77 Some(b'^') => {
78 tokenizer.enter(Name::GfmFootnoteCallMarker);
79 tokenizer.consume();
80 tokenizer.exit(Name::GfmFootnoteCallMarker);
81 tokenizer.exit(Name::GfmFootnoteCallLabel);
82 tokenizer.tokenize_state.label_starts.push(LabelStart {
83 kind: LabelKind::GfmFootnote,
84 start: (tokenizer.events.len() - 6, tokenizer.events.len() - 1),
85 inactive: false,
86 });
87 tokenizer.register_resolver_before(ResolveName::Label);
88 State::Ok
89 }
90 _ => State::Nok,
91 }
92}