Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified tools/server/public/index.html.gz
Binary file not shown.
21 changes: 21 additions & 0 deletions tools/server/webui/src/lib/utils/latex-protection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,27 @@ $$\n\\pi_n(\\mathbb{S}^3) = \\begin{cases}
expect(output).toBe(input); // Code blocks prevent misinterpretation
});

test('preserves backslash parentheses in code blocks (GitHub issue)', () => {
const input = '```python\nfoo = "\\(bar\\)"\n```';
const output = preprocessLaTeX(input);

expect(output).toBe(input); // Code blocks should not have LaTeX conversion applied
});

test('preserves backslash brackets in code blocks', () => {
const input = '```python\nfoo = "\\[bar\\]"\n```';
const output = preprocessLaTeX(input);

expect(output).toBe(input); // Code blocks should not have LaTeX conversion applied
});

test('preserves backslash parentheses in inline code', () => {
const input = 'Use `foo = "\\(bar\\)"` in your code.';
const output = preprocessLaTeX(input);

expect(output).toBe(input);
});

test('escape backslash in mchem ce', () => {
const input = 'mchem ce:\n$\\ce{2H2(g) + O2(g) -> 2H2O(l)}$';
const output = preprocessLaTeX(input);
Expand Down
23 changes: 13 additions & 10 deletions tools/server/webui/src/lib/utils/latex-protection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,19 +226,16 @@ export function preprocessLaTeX(content: string): string {
return expr;
});

// Step 5: Restore code blocks
content = content.replace(/<<CODE_BLOCK_(\d+)>>/g, (_, index) => {
return codeBlocks[parseInt(index)];
});

// Step 6: Apply additional escaping functions (brackets and mhchem)
// Step 5: Apply additional escaping functions (brackets and mhchem)
// This must happen BEFORE restoring code blocks to avoid affecting code content
content = escapeBrackets(content);

if (doEscapeMhchem && (content.includes('\\ce{') || content.includes('\\pu{'))) {
content = escapeMhchem(content);
}

// Final pass: Convert \(...\) → $...$, \[...\] → $$...$$
// Step 6: Convert remaining \(...\) → $...$, \[...\] → $$...$$
// This must happen BEFORE restoring code blocks to avoid affecting code content
content = content
// Using the look‑behind pattern `(?<!\\)` we skip matches
// that are preceded by a backslash, e.g.
Expand All @@ -248,12 +245,18 @@ export function preprocessLaTeX(content: string): string {
// Using the look‑behind pattern `(?<!\\)` we skip matches
// that are preceded by a backslash, e.g. `\\[4pt]`.
/(?<!\\)\\\[([\s\S]*?)\\\]/g, // display, see also PR #16599
(_, prefix: string, content: string) => {
return `${prefix}$$${content}$$`;
(_, content: string) => {
return `$$${content}$$`;
}
);

// Step 7: Restore blockquote markers
// Step 7: Restore code blocks
// This happens AFTER all LaTeX conversions to preserve code content
content = content.replace(/<<CODE_BLOCK_(\d+)>>/g, (_, index) => {
return codeBlocks[parseInt(index)];
});

// Step 8: Restore blockquote markers
if (blockquoteMarkers.size > 0) {
const finalLines = content.split('\n');
const restoredLines = finalLines.map((line, index) => {
Expand Down
Loading