tex2typst_rs/
tex_parser_utils.rs

1use crate::definitions::{TexNode, TexNodeType, TexToken, TexTokenType};
2use std::sync::LazyLock;
3
4pub static EMPTY_NODE: LazyLock<TexNode> =
5    LazyLock::new(|| TexNode::new(TexNodeType::Empty, String::new(), None, None));
6
7pub static LEFT_CURLY_BRACKET: LazyLock<TexToken> =
8    LazyLock::new(|| TexToken::new(TexTokenType::Control, "{".to_string()));
9pub static RIGHT_CURLY_BRACKET: LazyLock<TexToken> =
10    LazyLock::new(|| TexToken::new(TexTokenType::Control, "}".to_string()));
11
12pub static LEFT_SQUARE_BRACKET: LazyLock<TexToken> =
13    LazyLock::new(|| TexToken::new(TexTokenType::Element, "[".to_string()));
14pub static RIGHT_SQUARE_BRACKET: LazyLock<TexToken> =
15    LazyLock::new(|| TexToken::new(TexTokenType::Element, "]".to_string()));
16
17pub fn eat_whitespaces(tokens: &[TexToken], start: usize) -> usize {
18    let mut pos = start;
19    while pos < tokens.len() && matches!(tokens[pos].token_type, TexTokenType::Space | TexTokenType::Newline) {
20        pos += 1;
21    }
22    tokens[start..pos].len()
23}
24
25pub fn eat_parenthesis(tokens: &[TexToken], start: usize) -> Option<&TexToken> {
26    let first_token = &tokens[start];
27    if first_token.token_type == TexTokenType::Element
28        && ["(", ")", "[", "]", "|", "\\{", "\\}", "."].contains(&first_token.value.as_str())
29    {
30        Some(first_token)
31    } else if first_token.token_type == TexTokenType::Command
32        && ["lfloor", "rfloor", "lceil", "rceil", "langle", "rangle"].contains(&&first_token.value[1..])
33    {
34        Some(first_token)
35    } else {
36        None
37    }
38}
39
40pub fn eat_primes(tokens: &[TexToken], start: usize) -> usize {
41    let mut pos = start;
42    while pos < tokens.len() && tokens[pos] == TexToken::new(TexTokenType::Element, "'".to_string()) {
43        pos += 1;
44    }
45    pos - start
46}
47
48pub fn find_closing_match(tokens: &[TexToken], start: usize, left_token: &TexToken, right_token: &TexToken) -> isize {
49    assert!(tokens[start].eq(left_token));
50    let mut count = 1;
51    let mut pos = start + 1;
52
53    while count > 0 {
54        if pos >= tokens.len() {
55            return -1;
56        }
57        if tokens[pos].eq(left_token) {
58            count += 1;
59        } else if tokens[pos].eq(right_token) {
60            count -= 1;
61        }
62        pos += 1;
63    }
64
65    (pos - 1) as isize
66}
67
68pub static LEFT_COMMAND: LazyLock<TexToken> =
69    LazyLock::new(|| TexToken::new(TexTokenType::Command, "\\left".to_string()));
70pub static RIGHT_COMMAND: LazyLock<TexToken> =
71    LazyLock::new(|| TexToken::new(TexTokenType::Command, "\\right".to_string()));
72
73pub fn find_closing_right_command(tokens: &[TexToken], start: usize) -> isize {
74    find_closing_match(tokens, start, &LEFT_COMMAND, &RIGHT_COMMAND)
75}
76
77pub static BEGIN_COMMAND: LazyLock<TexToken> =
78    LazyLock::new(|| TexToken::new(TexTokenType::Command, "\\begin".to_string()));
79pub static END_COMMAND: LazyLock<TexToken> =
80    LazyLock::new(|| TexToken::new(TexTokenType::Command, "\\end".to_string()));
81
82pub fn find_closing_end_command(tokens: &[TexToken], start: usize) -> isize {
83    find_closing_match(tokens, start, &BEGIN_COMMAND, &END_COMMAND)
84}
85
86pub static SUB_SYMBOL: LazyLock<TexToken> = LazyLock::new(|| TexToken::new(TexTokenType::Control, "_".to_string()));
87pub static SUP_SYMBOL: LazyLock<TexToken> = LazyLock::new(|| TexToken::new(TexTokenType::Control, "^".to_string()));