Markdown parser fork with extended syntax for personal use.
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}