Skip to main content

oak_markdown/lexer/
list.rs

1use crate::lexer::{MarkdownLexer, State, token_type::MarkdownTokenType};
2use oak_core::Source;
3
4impl<'config> MarkdownLexer<'config> {
5    /// Handles list markers.
6    pub fn lex_list_marker<S: Source + ?Sized>(&self, state: &mut State<S>) -> bool {
7        let start_pos = state.get_position();
8
9        let mut check_pos = start_pos;
10        while check_pos > 0 {
11            check_pos -= 1;
12            if let Some(ch) = state.source().get_char_at(check_pos) {
13                if ch == '\n' || ch == '\r' {
14                    break;
15                }
16                else if ch != ' ' && ch != '\t' {
17                    return false;
18                }
19            }
20        }
21
22        if let Some(ch) = state.peek() {
23            match ch {
24                '-' | '*' | '+' => {
25                    state.advance(1);
26                    if let Some(next_ch) = state.peek() {
27                        if next_ch == ' ' || next_ch == '\t' {
28                            state.add_token(MarkdownTokenType::ListMarker, start_pos, state.get_position());
29                            return true;
30                        }
31                    }
32                    state.set_position(start_pos);
33                    false
34                }
35                '0'..='9' => {
36                    while let Some(digit) = state.peek() {
37                        if digit.is_ascii_digit() { state.advance(1) } else { break }
38                    }
39
40                    if let Some('.') = state.peek() {
41                        state.advance(1);
42                        if let Some(next_ch) = state.peek() {
43                            if next_ch == ' ' || next_ch == '\t' {
44                                state.add_token(MarkdownTokenType::ListMarker, start_pos, state.get_position());
45                                return true;
46                            }
47                        }
48                    }
49
50                    state.set_position(start_pos);
51                    false
52                }
53                _ => false,
54            }
55        }
56        else {
57            false
58        }
59    }
60
61    /// Handles task markers.
62    pub fn lex_task_marker<S: Source + ?Sized>(&self, state: &mut State<S>) -> bool {
63        let start_pos = state.get_position();
64
65        if let Some('[') = state.peek() {
66            state.advance(1);
67            if let Some(ch) = state.peek() {
68                if ch == ' ' || ch == 'x' || ch == 'X' {
69                    state.advance(1);
70                    if let Some(']') = state.peek() {
71                        state.advance(1);
72                        state.add_token(MarkdownTokenType::TaskMarker, start_pos, state.get_position());
73                        return true;
74                    }
75                }
76            }
77            state.set_position(start_pos);
78        }
79        false
80    }
81
82    /// Lexes definition list descriptions.
83    pub fn lex_definition_description<S: Source + ?Sized>(&self, state: &mut State<S>) -> bool {
84        let start_pos = state.get_position();
85
86        let mut check_pos = start_pos;
87        while check_pos > 0 {
88            check_pos -= 1;
89            if let Some(ch) = state.source().get_char_at(check_pos) {
90                if ch == '\n' || ch == '\r' {
91                    break;
92                }
93                else if ch != ' ' && ch != '\t' {
94                    return false;
95                }
96            }
97        }
98
99        if let Some(':') = state.peek() {
100            state.advance(1);
101            if let Some(next_ch) = state.peek() {
102                if next_ch == ' ' || next_ch == '\t' {
103                    state.add_token(MarkdownTokenType::DefinitionDescription, start_pos, state.get_position());
104                    return true;
105                }
106            }
107            state.set_position(start_pos);
108            false
109        }
110        else {
111            false
112        }
113    }
114
115    /// Lexes abbreviation definitions.
116    pub fn lex_abbreviation<S: Source + ?Sized>(&self, state: &mut State<S>) -> bool {
117        let start_pos = state.get_position();
118
119        let mut check_pos = start_pos;
120        while check_pos > 0 {
121            check_pos -= 1;
122            if let Some(ch) = state.source().get_char_at(check_pos) {
123                if ch == '\n' || ch == '\r' {
124                    break;
125                }
126                else if ch != ' ' && ch != '\t' {
127                    return false;
128                }
129            }
130        }
131
132        if let Some('*') = state.peek() {
133            state.advance(1);
134            if let Some('[') = state.peek() {
135                state.advance(1);
136
137                while let Some(ch) = state.peek() {
138                    if ch == ']' {
139                        state.advance(1);
140                        if let Some(':') = state.peek() {
141                            state.advance(1);
142                            state.add_token(MarkdownTokenType::Abbreviation, start_pos, state.get_position());
143                            return true;
144                        }
145                        break;
146                    }
147                    state.advance(ch.len_utf8());
148                }
149            }
150            state.set_position(start_pos);
151        }
152        false
153    }
154}