Skip to content

Commit 12280ae

Browse files
authored
webui: Fix parsing non-LaTeX occurrencies of \( or \) (#17810)
* fix: Improve latex protection logic to prevent turning non-latex `\(` into `$` * chore: update webui build output
1 parent 54a0fee commit 12280ae

File tree

3 files changed

+34
-10
lines changed

3 files changed

+34
-10
lines changed

tools/server/public/index.html.gz

-6 Bytes
Binary file not shown.

tools/server/webui/src/lib/utils/latex-protection.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,27 @@ $$\n\\pi_n(\\mathbb{S}^3) = \\begin{cases}
303303
expect(output).toBe(input); // Code blocks prevent misinterpretation
304304
});
305305

306+
test('preserves backslash parentheses in code blocks (GitHub issue)', () => {
307+
const input = '```python\nfoo = "\\(bar\\)"\n```';
308+
const output = preprocessLaTeX(input);
309+
310+
expect(output).toBe(input); // Code blocks should not have LaTeX conversion applied
311+
});
312+
313+
test('preserves backslash brackets in code blocks', () => {
314+
const input = '```python\nfoo = "\\[bar\\]"\n```';
315+
const output = preprocessLaTeX(input);
316+
317+
expect(output).toBe(input); // Code blocks should not have LaTeX conversion applied
318+
});
319+
320+
test('preserves backslash parentheses in inline code', () => {
321+
const input = 'Use `foo = "\\(bar\\)"` in your code.';
322+
const output = preprocessLaTeX(input);
323+
324+
expect(output).toBe(input);
325+
});
326+
306327
test('escape backslash in mchem ce', () => {
307328
const input = 'mchem ce:\n$\\ce{2H2(g) + O2(g) -> 2H2O(l)}$';
308329
const output = preprocessLaTeX(input);

tools/server/webui/src/lib/utils/latex-protection.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -226,19 +226,16 @@ export function preprocessLaTeX(content: string): string {
226226
return expr;
227227
});
228228

229-
// Step 5: Restore code blocks
230-
content = content.replace(/<<CODE_BLOCK_(\d+)>>/g, (_, index) => {
231-
return codeBlocks[parseInt(index)];
232-
});
233-
234-
// Step 6: Apply additional escaping functions (brackets and mhchem)
229+
// Step 5: Apply additional escaping functions (brackets and mhchem)
230+
// This must happen BEFORE restoring code blocks to avoid affecting code content
235231
content = escapeBrackets(content);
236232

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

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

256-
// Step 7: Restore blockquote markers
253+
// Step 7: Restore code blocks
254+
// This happens AFTER all LaTeX conversions to preserve code content
255+
content = content.replace(/<<CODE_BLOCK_(\d+)>>/g, (_, index) => {
256+
return codeBlocks[parseInt(index)];
257+
});
258+
259+
// Step 8: Restore blockquote markers
257260
if (blockquoteMarkers.size > 0) {
258261
const finalLines = content.split('\n');
259262
const restoredLines = finalLines.map((line, index) => {

0 commit comments

Comments
 (0)