Skip to main content

mdwright_lint/stdlib/
math_unbalanced_env.rs

1//! `math/unbalanced-env` — LaTeX `\begin{env}` with no matching
2//! `\end{env}` at the same nesting depth.
3//!
4//! Environments outside `\[ … \]` are common in mathematical prose
5//! (`KaTeX` renders them directly). An open `\begin` with no close
6//! turns the rest of the document into math in the author's mental
7//! model; pulldown-cmark parses it as prose and the document
8//! renders badly.
9//!
10//! Companion rule [`super::math_unbalanced_delim::MathUnbalancedDelim`]
11//! covers primitive delimiter imbalance.
12
13use crate::diagnostic::Diagnostic;
14use crate::rule::LintRule;
15use mdwright_document::Document;
16use mdwright_document::MathError;
17
18pub struct MathUnbalancedEnv;
19
20impl LintRule for MathUnbalancedEnv {
21    fn name(&self) -> &str {
22        "math/unbalanced-env"
23    }
24
25    fn description(&self) -> &str {
26        "LaTeX `\\begin{env}` with no matching `\\end{env}` at the same nesting depth."
27    }
28
29    fn explain(&self) -> &str {
30        include_str!("explain/math__unbalanced_env.md")
31    }
32
33    fn check(&self, doc: &Document, out: &mut Vec<Diagnostic>) {
34        for err in doc.math_errors() {
35            let MathError::UnbalancedEnv { name, range } = err else {
36                continue;
37            };
38            let message = format!(
39                "unbalanced `\\begin{{{name}}}` — no matching `\\end{{{name}}}` before end of document or next code/HTML block"
40            );
41            if let Some(d) = Diagnostic::at(doc, 0, range.clone(), message, None) {
42                out.push(d);
43            }
44        }
45    }
46}