Markdown parser fork with extended syntax for personal use.
1use crate::construct::partial_space_or_tab_eol::{space_or_tab_eol_with_options, Options};
2use crate::event::{Content, Link, Name};
3use crate::state::{Name as StateName, State};
4use crate::subtokenize::link;
5use crate::tokenizer::Tokenizer;
6use crate::util::constant::LINK_REFERENCE_SIZE_MAX;
7
8/// Start of label.
9///
10/// ```markdown
11/// > | [a]
12/// ^
13/// ```
14pub fn start(tokenizer: &mut Tokenizer) -> State {
15 State::Retry(StateName::WikilinkLabelAtBreak)
16}
17
18/// In label, at something, before something else.
19///
20/// ```markdown
21/// > | [a]
22/// ^
23/// ```
24pub fn at_break(tokenizer: &mut Tokenizer) -> State {
25 if tokenizer.tokenize_state.size > LINK_REFERENCE_SIZE_MAX || matches!(tokenizer.current, None)
26 {
27 State::Retry(StateName::WikilinkLabelNok)
28 } else {
29 match tokenizer.current {
30 Some(b'\n') => {
31 tokenizer.attempt(
32 State::Next(StateName::WikilinkLabelEolAfter),
33 State::Next(StateName::WikilinkLabelNok),
34 );
35 State::Retry(space_or_tab_eol_with_options(
36 tokenizer,
37 Options {
38 content: Some(Content::String),
39 connect: tokenizer.tokenize_state.connect,
40 },
41 ))
42 }
43
44 Some(b']') if tokenizer.tokenize_state.size_b == 1 => {
45 tokenizer.tokenize_state.size_b = 0;
46 State::Retry(StateName::WikilinkEnd)
47 }
48 _ => {
49 tokenizer.enter_link(
50 Name::Data,
51 Link {
52 previous: None,
53 next: None,
54 content: Content::String,
55 },
56 );
57
58 if tokenizer.tokenize_state.connect {
59 let index = tokenizer.events.len() - 1;
60 link(&mut tokenizer.events, index);
61 } else {
62 tokenizer.tokenize_state.connect = true;
63 }
64
65 State::Retry(StateName::WikilinkLabelInside)
66 }
67 }
68 }
69}
70
71/// In label, after whitespace.
72///
73/// ```markdown
74/// | [a␊
75/// > | b]
76/// ^
77/// ```
78pub fn eol_after(tokenizer: &mut Tokenizer) -> State {
79 tokenizer.tokenize_state.connect = true;
80 State::Retry(StateName::WikilinkLabelAtBreak)
81}
82
83/// In label, on something disallowed.
84///
85/// ```markdown
86/// > | []
87/// ^
88/// ```
89pub fn nok(tokenizer: &mut Tokenizer) -> State {
90 tokenizer.tokenize_state.connect = false;
91 tokenizer.tokenize_state.seen = false;
92 tokenizer.tokenize_state.size = 0;
93 State::Nok
94}
95
96/// In label, in text.
97///
98/// ```markdown
99/// > | [a]
100/// ^
101/// ```
102pub fn inside(tokenizer: &mut Tokenizer) -> State {
103 match tokenizer.current {
104 None | Some(b'\n') => {
105 tokenizer.exit(Name::Data);
106 State::Retry(StateName::WikilinkLabelAtBreak)
107 }
108 Some(b']') => {
109 tokenizer.exit(Name::Data);
110 tokenizer.consume();
111 tokenizer.tokenize_state.size += 1;
112 tokenizer.tokenize_state.size_b = 1;
113 tokenizer.tokenize_state.seen = false; // ??
114
115 State::Next(StateName::WikilinkLabelAtBreak)
116 }
117 Some(byte) => {
118 if tokenizer.tokenize_state.size > LINK_REFERENCE_SIZE_MAX {
119 tokenizer.exit(Name::Data);
120 State::Retry(StateName::WikilinkLabelAtBreak)
121 } else {
122 tokenizer.consume();
123 tokenizer.tokenize_state.size += 1;
124 if !tokenizer.tokenize_state.seen && !matches!(byte, b'\t' | b' ') {
125 tokenizer.tokenize_state.seen = true;
126 }
127 State::Next(if matches!(byte, b'\\') {
128 StateName::WikilinkLabelEscape
129 } else {
130 StateName::WikilinkLabelInside
131 })
132 }
133 }
134 }
135}
136
137/// After `\`, at a special character.
138///
139/// ```markdown
140/// > | [a\*a]
141/// ^
142/// ```
143pub fn escape(tokenizer: &mut Tokenizer) -> State {
144 match tokenizer.current {
145 Some(b'[' | b'\\' | b']') => {
146 tokenizer.consume();
147 tokenizer.tokenize_state.size += 1;
148 State::Next(StateName::WikilinkLabelInside)
149 }
150 _ => State::Retry(StateName::WikilinkLabelInside),
151 }
152}