fix(equations): preserve LaTeX row-break dimensions in sub-equation tagging

- Update the sub-equation row split logic in live-preview-equations to use a capturing regex `/(\\\\(?:\s*\[[^\]]*\])?)/`.
- Reconstruct the equation parts by only tagging the math content and preserving the separators (e.g. `\\[0.6em]`) exactly as-is.
- Add unit tests verifying both standard and dimensioned row breaks.
This commit is contained in:
JK 2026-07-17 13:06:44 +02:00
parent 27caaa6ef4
commit 16ca794de8
5 changed files with 4063 additions and 1350 deletions

View file

@ -5,7 +5,6 @@ import fs from 'fs';
import path from 'path';
import inlineWorkerPlugin from 'esbuild-plugin-inline-worker';
const builtins = [
...new Set([...builtinModules, ...builtinModules.map(moduleName => `node:${moduleName}`)])
];

File diff suppressed because it is too large Load diff

View file

@ -264,27 +264,33 @@ function createTagManagerPlugin(
// --- Mode 1: Sub-equation ---
if (info.subIndices && info.subIndices.size > 0 && info.printName) {
const baseName = info.printName.slice(1, -1);
const rows = mathPart.trim().split(/\\\\/);
const parts = mathPart.trim().split(/(\\\\(?:\s*\[[^\]]*\])?)/);
let hasContent = false;
const newParts = [...parts];
const taggedRows = rows.map((row, index) => {
for (let i = 0; i < parts.length; i += 2) {
const row = parts[i];
const cleanedRow = row.replace(/^[ \t]+/, '');
if (cleanedRow.trim() === '') return cleanedRow;
if (cleanedRow.trim() === '') {
newParts[i] = cleanedRow;
continue;
}
hasContent = true;
const subIndex = index + 1;
const subIndex = i / 2 + 1;
const newTag = ` \\tag{${baseName}.${subIndex}}`;
const endEnvMatch = cleanedRow.match(/(\\end\{[a-zA-Z*]+\})/);
if (endEnvMatch && endEnvMatch.index !== undefined) {
const before = cleanedRow.substring(0, endEnvMatch.index).trimEnd();
const environment = endEnvMatch[0];
const after = cleanedRow.substring(endEnvMatch.index + environment.length);
return `${before + newTag} ${environment}${after}`;
newParts[i] = `${before + newTag} ${environment}${after}`;
} else {
newParts[i] = cleanedRow.trimEnd() + newTag;
}
return cleanedRow.trimEnd() + newTag;
});
}
if (hasContent) {
newInnerContent = taggedRows.join(' \\\\ ');
newInnerContent = newParts.join('');
}
}
// --- Mode 2: Normal Equation ---

View file

@ -113,3 +113,22 @@ describe('general.ts tests', () => {
expect(arr).toEqual([1, 99, 2, 3]);
});
});
describe('Sub-equation splitting regex tests', () => {
it('should split rows while keeping \\[dimen] intact', () => {
const regex = /(\\\\(?:\s*\[[^\]]*\])?)/;
const input = `\\beta \\frac{\\partial P}{\\partial \\rho} & = \\frac{\\partial}{\\partial \\eta} \\left[ \\eta \\frac{1 + \\eta + \\eta^2}{(1 - \\eta)^3} \\right] \\\\[0.6em]\n\\implies q(\\eta) & = \\frac{(1 + 2\\eta)^2}{(1 - \\eta)^4} \\end{align}`;
const parts = input.split(regex);
expect(parts.length).toBe(3);
expect(parts[0]).toContain('\\beta');
expect(parts[1]).toBe('\\\\[0.6em]');
expect(parts[2]).toContain('\\implies');
});
it('should split rows when there is no dimension parameter', () => {
const regex = /(\\\\(?:\s*\[[^\]]*\])?)/;
const input = `row1 \\\\ row2`;
const parts = input.split(regex);
expect(parts).toEqual(['row1 ', '\\\\', ' row2']);
});
});

File diff suppressed because one or more lines are too long