katex-parser 0.1.0

A port of the KaTeX parser: lexing and parsing LaTeX math expressions with macro expansion into a typed AST, plus a Unicode rendering backend
Documentation
use crate::ast::{Mode, ParseNode};
use crate::source_location::SourceLocation;

fn merged_text_location(first: &ParseNode, last: &ParseNode) -> Option<SourceLocation> {
    if let (ParseNode::TextOrd { loc: Some(start), .. }, ParseNode::TextOrd { loc: Some(end), .. }) =
        (first, last)
        && start.input == end.input {
            return Some(SourceLocation::range(start, end));
        }
    None
}

fn merged_text_ord(first: &ParseNode, last: &ParseNode, text: String) -> ParseNode {
    ParseNode::TextOrd {
        mode: Mode::Text,
        loc: merged_text_location(first, last),
        text,
    }
}

pub(crate) fn form_text_ligatures(body: Vec<ParseNode>) -> Vec<ParseNode> {
    let mut output: Vec<ParseNode> = Vec::new();
    let mut index = 0;
    while index < body.len() {
        let current = &body[index];
        if let ParseNode::TextOrd { text, .. } = current {
            if text == "-"
                && let Some(next) = body.get(index + 1)
                    && let ParseNode::TextOrd { text: next_text, .. } = next
                        && next_text == "-" {
                            if let Some(last) = body.get(index + 2)
                                && let ParseNode::TextOrd {
                                    text: last_text, ..
                                } = last
                                    && last_text == "-" {
                                        output.push(merged_text_ord(
                                            current,
                                            last,
                                            "---".to_string(),
                                        ));
                                        index += 3;
                                        continue;
                                    }
                            output.push(merged_text_ord(current, next, "--".to_string()));
                            index += 2;
                            continue;
                        }
            if (text == "'" || text == "`")
                && let Some(next) = body.get(index + 1)
                    && let ParseNode::TextOrd {
                        text: next_text, ..
                    } = next
                        && next_text == text {
                            output.push(merged_text_ord(
                                current,
                                next,
                                format!("{}{}", text, text),
                            ));
                            index += 2;
                            continue;
                        }
        }
        output.push(current.clone());
        index += 1;
    }
    output
}