1use std::ops::Range;
11
12#[derive(Clone, Debug, PartialEq, Eq)]
19pub enum EnvKind {
20 Known(KnownEnv),
21 Custom(Range<usize>),
25}
26
27#[derive(Copy, Clone, Debug, PartialEq, Eq)]
31pub enum KnownEnv {
32 Align,
33 AlignStar,
34 Aligned,
35 Equation,
36 EquationStar,
37 Gather,
38 GatherStar,
39 Matrix,
40 Pmatrix,
41 Bmatrix,
42 Vmatrix,
43 Smallmatrix,
44 Cases,
45 Array,
46 Split,
47 Multline,
48 MultlineStar,
49}
50
51impl KnownEnv {
52 pub fn from_name(name: &str) -> Option<Self> {
56 Some(match name {
57 "align" => Self::Align,
58 "align*" => Self::AlignStar,
59 "aligned" => Self::Aligned,
60 "equation" => Self::Equation,
61 "equation*" => Self::EquationStar,
62 "gather" => Self::Gather,
63 "gather*" => Self::GatherStar,
64 "matrix" => Self::Matrix,
65 "pmatrix" => Self::Pmatrix,
66 "bmatrix" => Self::Bmatrix,
67 "vmatrix" => Self::Vmatrix,
68 "smallmatrix" => Self::Smallmatrix,
69 "cases" => Self::Cases,
70 "array" => Self::Array,
71 "split" => Self::Split,
72 "multline" => Self::Multline,
73 "multline*" => Self::MultlineStar,
74 _ => return None,
75 })
76 }
77
78 pub const fn name(self) -> &'static str {
80 match self {
81 Self::Align => "align",
82 Self::AlignStar => "align*",
83 Self::Aligned => "aligned",
84 Self::Equation => "equation",
85 Self::EquationStar => "equation*",
86 Self::Gather => "gather",
87 Self::GatherStar => "gather*",
88 Self::Matrix => "matrix",
89 Self::Pmatrix => "pmatrix",
90 Self::Bmatrix => "bmatrix",
91 Self::Vmatrix => "vmatrix",
92 Self::Smallmatrix => "smallmatrix",
93 Self::Cases => "cases",
94 Self::Array => "array",
95 Self::Split => "split",
96 Self::Multline => "multline",
97 Self::MultlineStar => "multline*",
98 }
99 }
100
101 pub const fn is_aligning(self) -> bool {
106 matches!(
107 self,
108 Self::Align
109 | Self::AlignStar
110 | Self::Aligned
111 | Self::Matrix
112 | Self::Pmatrix
113 | Self::Bmatrix
114 | Self::Vmatrix
115 | Self::Smallmatrix
116 | Self::Cases
117 | Self::Array
118 | Self::Split
119 )
120 }
121}
122
123impl EnvKind {
124 pub fn is_aligning(&self) -> bool {
128 matches!(self, Self::Known(k) if k.is_aligning())
129 }
130
131 pub fn name<'a>(&self, source: &'a str) -> &'a str {
134 match self {
135 Self::Known(k) => k.name(),
136 Self::Custom(range) => source.get(range.clone()).unwrap_or(""),
137 }
138 }
139}
140
141#[cfg(test)]
142mod tests {
143 use super::*;
144
145 #[test]
146 fn known_from_name_round_trips() {
147 for k in [
148 KnownEnv::Align,
149 KnownEnv::AlignStar,
150 KnownEnv::Pmatrix,
151 KnownEnv::Cases,
152 KnownEnv::MultlineStar,
153 ] {
154 assert_eq!(KnownEnv::from_name(k.name()), Some(k));
155 }
156 }
157
158 #[test]
159 fn unknown_name_returns_none() {
160 assert_eq!(KnownEnv::from_name("tikzcd"), None);
161 assert_eq!(KnownEnv::from_name("widget"), None);
162 }
163
164 #[test]
165 fn aligning_split() {
166 assert!(KnownEnv::Align.is_aligning());
167 assert!(KnownEnv::Pmatrix.is_aligning());
168 assert!(KnownEnv::Cases.is_aligning());
169 assert!(!KnownEnv::Equation.is_aligning());
170 assert!(!KnownEnv::Gather.is_aligning());
171 assert!(!KnownEnv::Multline.is_aligning());
172 }
173
174 #[test]
175 fn custom_is_never_aligning() {
176 let env = EnvKind::Custom(0..6);
177 assert!(!env.is_aligning());
178 }
179
180 #[test]
181 fn custom_name_resolves_from_source() {
182 let s = "tikzcd";
183 let env = EnvKind::Custom(0..6);
184 assert_eq!(env.name(s), "tikzcd");
185 }
186}