diff --git a/tools/server/public/index.html.gz b/tools/server/public/index.html.gz
index 4cff76429e1..3fd631b77a8 100644
Binary files a/tools/server/public/index.html.gz and b/tools/server/public/index.html.gz differ
diff --git a/tools/server/webui/src/lib/utils/latex-protection.test.ts b/tools/server/webui/src/lib/utils/latex-protection.test.ts
index 2354f8fa0ec..40fe1b0db27 100644
--- a/tools/server/webui/src/lib/utils/latex-protection.test.ts
+++ b/tools/server/webui/src/lib/utils/latex-protection.test.ts
@@ -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);
diff --git a/tools/server/webui/src/lib/utils/latex-protection.ts b/tools/server/webui/src/lib/utils/latex-protection.ts
index 7f5cf2cddfa..cafa2d4761f 100644
--- a/tools/server/webui/src/lib/utils/latex-protection.ts
+++ b/tools/server/webui/src/lib/utils/latex-protection.ts
@@ -226,19 +226,16 @@ export function preprocessLaTeX(content: string): string {
return expr;
});
- // Step 5: Restore code blocks
- content = content.replace(/<>/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 `(? {
- 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(/<>/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) => {