oak_markdown/lexer/
inline.rs1use crate::lexer::{MarkdownLexer, State, token_type::MarkdownTokenType};
2use oak_core::Source;
3
4impl<'config> MarkdownLexer<'config> {
5 pub fn lex_emphasis<S: Source + ?Sized>(&self, state: &mut State<S>) -> bool {
7 let start_pos = state.get_position();
8
9 let marker_char = if let Some('*') = state.peek() {
10 '*'
11 }
12 else if let Some('_') = state.peek() {
13 '_'
14 }
15 else {
16 return false;
17 };
18
19 let mut marker_count = 0;
20 let mut pos = start_pos;
21
22 while let Some(ch) = state.source().get_char_at(pos) {
23 if ch == marker_char {
24 marker_count += 1;
25 pos += 1;
26 }
27 else {
28 break;
29 }
30 }
31
32 if marker_count == 0 {
33 return false;
34 }
35
36 state.advance(marker_count);
37
38 let token_kind = if marker_count >= 2 { MarkdownTokenType::Strong } else { MarkdownTokenType::Emphasis };
39
40 state.add_token(token_kind, start_pos, state.get_position());
41 true
42 }
43
44 pub fn lex_inline_code<S: Source + ?Sized>(&self, state: &mut State<S>) -> bool {
46 let start_pos = state.get_position();
47
48 if let Some('`') = state.peek() {
49 state.advance(1);
50 let mut found_end = false;
51
52 while let Some(ch) = state.peek() {
53 if ch == '`' {
54 state.advance(1);
55 found_end = true;
56 break;
57 }
58 else if ch == '\n' || ch == '\r' {
59 break;
60 }
61 else {
62 state.advance(ch.len_utf8());
63 }
64 }
65
66 if found_end {
67 state.add_token(MarkdownTokenType::InlineCode, start_pos, state.get_position());
68 true
69 }
70 else {
71 state.set_position(start_pos);
72 false
73 }
74 }
75 else {
76 false
77 }
78 }
79
80 pub fn lex_strikethrough<S: Source + ?Sized>(&self, state: &mut State<S>) -> bool {
82 let start_pos = state.get_position();
83
84 if let Some('~') = state.peek() {
85 if let Some('~') = state.source().get_char_at(start_pos + 1) {
86 state.advance(2);
87 state.add_token(MarkdownTokenType::Strikethrough, start_pos, state.get_position());
88 true
89 }
90 else {
91 false
92 }
93 }
94 else {
95 false
96 }
97 }
98
99 pub fn lex_link_or_image<S: Source + ?Sized>(&self, state: &mut State<S>) -> bool {
101 let start_pos = state.get_position();
102
103 let is_image = if let Some('!') = state.peek() {
104 state.advance(1);
105 true
106 }
107 else {
108 false
109 };
110
111 if let Some('[') = state.peek() {
112 state.advance(1);
113
114 let token_kind = if is_image { MarkdownTokenType::Image } else { MarkdownTokenType::Link };
115
116 state.add_token(token_kind, start_pos, state.get_position());
117 true
118 }
119 else {
120 if is_image {
121 state.set_position(start_pos);
122 }
123 false
124 }
125 }
126
127 pub fn lex_math<S: Source + ?Sized>(&self, state: &mut State<S>) -> bool {
129 let start_pos = state.get_position();
130
131 if let Some('$') = state.peek() {
132 state.advance(1);
133 let mut is_block = false;
134
135 if let Some('$') = state.peek() {
136 state.advance(1);
137 is_block = true;
138 }
139
140 let mut found_end = false;
141 while let Some(ch) = state.peek() {
142 if ch == '$' {
143 if is_block {
144 if let Some('$') = state.source().get_char_at(state.get_position() + 1) {
145 state.advance(2);
146 found_end = true;
147 break;
148 }
149 }
150 else {
151 state.advance(1);
152 found_end = true;
153 break;
154 }
155 }
156 state.advance(ch.len_utf8())
157 }
158
159 if found_end {
160 let kind = if is_block { MarkdownTokenType::MathBlock } else { MarkdownTokenType::MathInline };
161 state.add_token(kind, start_pos, state.get_position());
162 true
163 }
164 else {
165 state.set_position(start_pos);
166 false
167 }
168 }
169 else {
170 false
171 }
172 }
173
174 pub fn lex_footnote<S: Source + ?Sized>(&self, state: &mut State<S>) -> bool {
176 let start_pos = state.get_position();
177
178 if let Some('^') = state.peek() {
179 let check_pos = start_pos;
180 if check_pos > 0 && state.source().get_char_at(check_pos - 1) == Some('[') {
181 state.advance(1);
182 while let Some(ch) = state.peek() {
183 if ch == ']' {
184 state.advance(1);
185 if state.peek() == Some(':') {
186 state.advance(1);
187 state.add_token(MarkdownTokenType::FootnoteDefinition, start_pos - 1, state.get_position())
188 }
189 else {
190 state.add_token(MarkdownTokenType::FootnoteReference, start_pos - 1, state.get_position())
191 }
192 return true;
193 }
194 else if ch == '\n' || ch == '\r' {
195 break;
196 }
197 state.advance(ch.len_utf8())
198 }
199 }
200 state.set_position(start_pos);
201 }
202 false
203 }
204
205 pub fn lex_sub_superscript<S: Source + ?Sized>(&self, state: &mut State<S>) -> bool {
207 let start_pos = state.get_position();
208
209 if let Some(ch) = state.peek() {
210 let marker = ch;
211 if marker == '^' || marker == '~' {
212 state.advance(1);
213 let mut found_end = false;
214 while let Some(next_ch) = state.peek() {
215 if next_ch == marker {
216 state.advance(1);
217 found_end = true;
218 break;
219 }
220 else if next_ch == ' ' || next_ch == '\t' || next_ch == '\n' || next_ch == '\r' {
221 break;
222 }
223 state.advance(next_ch.len_utf8())
224 }
225
226 if found_end {
227 let kind = if marker == '^' { MarkdownTokenType::Superscript } else { MarkdownTokenType::Subscript };
228 state.add_token(kind, start_pos, state.get_position());
229 true
230 }
231 else {
232 state.set_position(start_pos);
233 false
234 }
235 }
236 else {
237 false
238 }
239 }
240 else {
241 false
242 }
243 }
244}