org_rust_parser/element/
latex_env.rs1use crate::constants::{NEWLINE, RBRACE, STAR};
2use crate::node_pool::NodeID;
3use crate::types::{Cursor, MatchError, ParseOpts, Parseable, Parser, Result};
4use regex::bytes::Regex;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub struct LatexEnv<'a> {
8 pub name: &'a str,
9 pub contents: &'a str,
10}
11
12impl<'a> Parseable<'a> for LatexEnv<'a> {
13 fn parse(
14 parser: &mut Parser<'a>,
15 mut cursor: Cursor<'a>,
16 parent: Option<NodeID>,
17 parse_opts: ParseOpts,
18 ) -> Result<NodeID> {
19 let start = cursor.index;
20 cursor.word(r"\begin{")?;
21 let name_match = cursor.fn_until(|chr| {
22 !chr.is_ascii_alphanumeric() && chr != STAR || (chr == NEWLINE || chr == RBRACE)
23 })?;
24
25 cursor.index = name_match.end;
26 cursor.word("}\n")?;
27 let name = name_match.obj;
28
29 let a = format!(r"(?m)^[ \t]*\\end{{{name}}}[\t ]*$");
30 let a = a.replace("{", r"\{");
34 let a = a.replace("}", r"\}");
35
36 let ending_re: Regex = Regex::new(&a).unwrap();
37 let matched_reg = ending_re
38 .find_at(cursor.byte_arr, cursor.index)
39 .ok_or(MatchError::InvalidLogic)?;
40
41 Ok(parser.alloc(
42 Self {
43 name,
44 contents: cursor.clamp_forwards(matched_reg.start()),
45 },
46 start,
47 matched_reg.end(),
48 parent,
49 ))
50 }
51}
52
53#[cfg(test)]
54mod tests {
55 use crate::{element::LatexEnv, expr_in_pool, parse_org, types::Expr};
56
57 #[test]
58 fn basic_latex_env() {
59 let inp = r"
60\begin{align*}
61\end{align*}
62";
63
64 dbg!(parse_org(inp));
65 }
66
67 #[test]
68 fn latex_env_with_content() {
69 let inp = r"
70\begin{align*}
71
72\text{latex constructs}\\
73\alpha\\
74\beta\\
75
7610x + 4 &= 3\\
77
78\end{align*}
79";
80
81 dbg!(parse_org(inp));
82 }
83
84 #[test]
85 fn latex_env_failed_header() {
86 let inp = r"
88\begin{star!}
89\end{star!}
90";
91
92 dbg!(parse_org(inp));
93
94 let inp = r"
95\begin{a13214-}
96\end{a13214-}
97";
98 dbg!(parse_org(inp));
99 let inp = r"
101\begin{one}more stuff
102\end{one}
103";
104 dbg!(parse_org(inp));
105 }
106
107 #[test]
108 fn latex_empty_start() {
109 let inp = r"
110\begin{}
111\end{}
112";
113 dbg!(parse_org(inp));
114 }
115
116 #[test]
117 fn latex_failed_end() {
118 let inp = r"
119\begin{start}
120\end{notstart}
121";
122 dbg!(parse_org(inp));
123 }
124
125 #[test]
126 fn latex_env_indented() {
127 let input = r"
128 \begin{align}
129 we are eating so good?
130 \end{align}
131";
132
133 let parsed = parse_org(input);
134
135 let l = expr_in_pool!(parsed, LatexEnv).unwrap();
136
137 assert_eq!(
138 l,
139 &LatexEnv {
140 name: "align",
141 contents: " we are eating so good?\n"
142 }
143 )
144 }
145}