Skip to content

Commit

Permalink
🧮 Fix AMSMath environment for LaTeX (#977)
Browse files Browse the repository at this point in the history
Signed-off-by: Cristian Le <cristian.le@mpsd.mpg.de>
Co-authored-by: Rowan Cockett <rowanc1@gmail.com>
  • Loading branch information
LecrisUT and rowanc1 authored Mar 15, 2024
1 parent 4f6699c commit 1b3c9e2
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 8 deletions.
5 changes: 5 additions & 0 deletions .changeset/giant-books-greet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"myst-to-tex": patch
---

Properly handle AMS environments, and no longer wrap with equation environment.
55 changes: 47 additions & 8 deletions packages/myst-to-tex/src/math.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,35 @@
import type { Handler, ITexSerializer } from './types.js';

// Top level environments in amsmath version 2.1 (and eqnarray), see:
// http://anorien.csc.warwick.ac.uk/mirrors/CTAN/macros/latex/required/amsmath/amsldoc.pdf
const ENVIRONMENTS = [
'equation',
'multline',
'gather',
'align',
'alignat',
'flalign',
'matrix',
'pmatrix',
'bmatrix',
'Bmatrix',
'vmatrix',
'Vmatrix',
'eqnarray',
];

const RE_OPEN = new RegExp(`^\\\\begin{(${ENVIRONMENTS.join('|')})([*]?)}`);

function isAmsmathEnvironment(value: string): boolean {
const matchOpen = value.trim().match(RE_OPEN);
if (!matchOpen) return false;
const [, environment, star] = matchOpen;
const end = `\\end{${environment}${star}}`;
const matchClose = value.trim().endsWith(end);
if (!matchClose) return false;
return true;
}

function addMacrosToState(value: string, state: ITexSerializer) {
if (!state.options.math) return;
Object.entries(state.options.math).forEach(([k, v]) => {
Expand Down Expand Up @@ -47,15 +77,24 @@ const math: Handler = (node, state) => {
state.write(node.value);
state.write(' \\)');
} else {
// TODO: AMS math
state.write(`\\begin{equation${enumerated === false ? '*' : ''}}\n`);
if (label) {
state.write(`\\label{${label}}`);
// Check if the node is an AMSMath environment, if so, render it directly
const isAmsMath = isAmsmathEnvironment(node.value);
if (isAmsMath) {
// TODO: labels may be stripped previously in the transform, we may need to back that out
state.ensureNewLine();
state.write(node.value);
state.ensureNewLine(true);
} else {
// Otherwise enclose the math environment by equation + label
state.write(`\\begin{equation${enumerated === false ? '*' : ''}}\n`);
if (label) {
state.write(`\\label{${label}}`);
}
state.ensureNewLine();
state.write(node.value);
state.ensureNewLine(true);
state.write(`\\end{equation${enumerated === false ? '*' : ''}}`);
}
state.ensureNewLine();
state.write(node.value);
state.ensureNewLine(true);
state.write(`\\end{equation${enumerated === false ? '*' : ''}}`);
}
if (!state.data.isInTable) state.closeBlock(node);
};
Expand Down
34 changes: 34 additions & 0 deletions packages/myst-to-tex/tests/amsmath.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
title: myst-to-tex amsmath tests
cases:
- title: gather
mdast:
type: root
children:
- type: math
value: |-
\begin{gather}
E=mc^2
\end{gather}
latex: |-
\begin{gather}
E=mc^2
\end{gather}
- title: alignat*
mdast:
type: root
children:
- type: math
value: |-
\begin{alignat*}{3}
& m \quad && \text{módulo} \quad && m>0\\
& a \quad && \text{multiplicador} \quad && 0<a<m\\
& c \quad && \text{constante aditiva} \quad && 0\leq c<m\\
& x_0 \quad && \text{valor inicial} \quad && 0\leq x_0 <m
\end{alignat*}
latex: |-
\begin{alignat*}{3}
& m \quad && \text{módulo} \quad && m>0\\
& a \quad && \text{multiplicador} \quad && 0<a<m\\
& c \quad && \text{constante aditiva} \quad && 0\leq c<m\\
& x_0 \quad && \text{valor inicial} \quad && 0\leq x_0 <m
\end{alignat*}

0 comments on commit 1b3c9e2

Please sign in to comment.