From c991767c9372d75916bcde3c029ba222f14dec92 Mon Sep 17 00:00:00 2001 From: Cristian Le Date: Wed, 13 Mar 2024 14:46:56 +0100 Subject: [PATCH 1/4] Try to handle some AMSMath environments Signed-off-by: Cristian Le --- packages/myst-to-tex/src/math.ts | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/packages/myst-to-tex/src/math.ts b/packages/myst-to-tex/src/math.ts index d17890661..8b61d9a91 100644 --- a/packages/myst-to-tex/src/math.ts +++ b/packages/myst-to-tex/src/math.ts @@ -1,4 +1,5 @@ import type { Handler, ITexSerializer } from './types.js'; +import assert from 'node:assert'; function addMacrosToState(value: string, state: ITexSerializer) { if (!state.options.math) return; @@ -47,15 +48,29 @@ 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}}`); + // TODO: properly handle AMS math environments + // For now only checking if a multi-line AMSMath environment is used, than avoid using + // equation and label + const AMSMath = /\\(begin|end)\{(gather)\*?\}/g; + if (node.value.match(AMSMath)) { + // If multi-line AMSMath is used, use the contents as-is + if (label) { + throw new Error('Multi-line AMSMath environment is incompatible with math.label'); + } + state.ensureNewLine(); + state.write(node.value); + state.ensureNewLine(true); + } else { + // Otherwise enclose the math envrioment 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); }; From e0ba8f98b1162967b54cc704db8ad59421c029ae Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Wed, 13 Mar 2024 15:51:11 -0600 Subject: [PATCH 2/4] Add tests and expand to other AMS environments --- packages/myst-to-tex/src/math.ts | 46 ++++++++++++++++++++------ packages/myst-to-tex/tests/amsmath.yml | 34 +++++++++++++++++++ 2 files changed, 69 insertions(+), 11 deletions(-) create mode 100644 packages/myst-to-tex/tests/amsmath.yml diff --git a/packages/myst-to-tex/src/math.ts b/packages/myst-to-tex/src/math.ts index 8b61d9a91..f0817e8c9 100644 --- a/packages/myst-to-tex/src/math.ts +++ b/packages/myst-to-tex/src/math.ts @@ -1,5 +1,34 @@ import type { Handler, ITexSerializer } from './types.js'; -import assert from 'node:assert'; + +// 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) { + const matchOpen = value.trim().match(RE_OPEN); + if (!matchOpen) return false; + const [, environment, numbered] = matchOpen; + const end = `\\end{${environment}${numbered}}`; + const matchClose = value.trim().endsWith(end); + if (!matchClose) return false; + return { environment, numbered }; +} function addMacrosToState(value: string, state: ITexSerializer) { if (!state.options.math) return; @@ -48,20 +77,15 @@ const math: Handler = (node, state) => { state.write(node.value); state.write(' \\)'); } else { - // TODO: properly handle AMS math environments - // For now only checking if a multi-line AMSMath environment is used, than avoid using - // equation and label - const AMSMath = /\\(begin|end)\{(gather)\*?\}/g; - if (node.value.match(AMSMath)) { - // If multi-line AMSMath is used, use the contents as-is - if (label) { - throw new Error('Multi-line AMSMath environment is incompatible with math.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 envrioment by equation+label + // Otherwise enclose the math environment by equation + label state.write(`\\begin{equation${enumerated === false ? '*' : ''}}\n`); if (label) { state.write(`\\label{${label}}`); diff --git a/packages/myst-to-tex/tests/amsmath.yml b/packages/myst-to-tex/tests/amsmath.yml new file mode 100644 index 000000000..86950a074 --- /dev/null +++ b/packages/myst-to-tex/tests/amsmath.yml @@ -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 && 00\\ + & a \quad && \text{multiplicador} \quad && 0 Date: Wed, 13 Mar 2024 15:52:24 -0600 Subject: [PATCH 3/4] Add changeset --- .changeset/giant-books-greet.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/giant-books-greet.md diff --git a/.changeset/giant-books-greet.md b/.changeset/giant-books-greet.md new file mode 100644 index 000000000..553f93bea --- /dev/null +++ b/.changeset/giant-books-greet.md @@ -0,0 +1,5 @@ +--- +"myst-to-tex": patch +--- + +Properly handle AMS environments, and no longer wrap with equation environment. From fda5f3d5809615f10ffccaedd5640981994a5478 Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Fri, 15 Mar 2024 10:39:16 -0600 Subject: [PATCH 4/4] PR review --- packages/myst-to-tex/src/math.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/myst-to-tex/src/math.ts b/packages/myst-to-tex/src/math.ts index f0817e8c9..04e02ddac 100644 --- a/packages/myst-to-tex/src/math.ts +++ b/packages/myst-to-tex/src/math.ts @@ -20,14 +20,14 @@ const ENVIRONMENTS = [ const RE_OPEN = new RegExp(`^\\\\begin{(${ENVIRONMENTS.join('|')})([*]?)}`); -function isAmsmathEnvironment(value: string) { +function isAmsmathEnvironment(value: string): boolean { const matchOpen = value.trim().match(RE_OPEN); if (!matchOpen) return false; - const [, environment, numbered] = matchOpen; - const end = `\\end{${environment}${numbered}}`; + const [, environment, star] = matchOpen; + const end = `\\end{${environment}${star}}`; const matchClose = value.trim().endsWith(end); if (!matchClose) return false; - return { environment, numbered }; + return true; } function addMacrosToState(value: string, state: ITexSerializer) {