From 1b403a4ffab0833cdce527360f445a0003c7ea41 Mon Sep 17 00:00:00 2001 From: oobabooga <112222186+oobabooga@users.noreply.github.com> Date: Sat, 4 Apr 2026 19:33:05 -0700 Subject: [PATCH] UI: Fix inline LaTeX rendering by protecting $...$ from markdown (closes #7423) --- modules/html_generator.py | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/modules/html_generator.py b/modules/html_generator.py index 8f3f261f..8dd46850 100644 --- a/modules/html_generator.py +++ b/modules/html_generator.py @@ -185,28 +185,29 @@ def process_markdown_content(string): if not string: return "" - # Define unique placeholders for LaTeX asterisks and underscores + # Define unique placeholders for LaTeX characters that conflict with markdown LATEX_ASTERISK_PLACEHOLDER = "LATEXASTERISKPLACEHOLDER" LATEX_UNDERSCORE_PLACEHOLDER = "LATEXUNDERSCOREPLACEHOLDER" + LATEX_PIPE_PLACEHOLDER = "LATEXPIPEPLACEHOLDER" + + def protect_latex_content(content): + """Protect markdown-sensitive characters inside LaTeX.""" + content = content.replace('*', LATEX_ASTERISK_PLACEHOLDER) + content = content.replace('_', LATEX_UNDERSCORE_PLACEHOLDER) + content = content.replace('|', LATEX_PIPE_PLACEHOLDER) + return content def protect_asterisks_underscores_in_latex(match): - """A replacer function for re.sub to protect asterisks and underscores in multiple LaTeX formats.""" + """A replacer function for re.sub to protect markdown-sensitive characters in multiple LaTeX formats.""" # Check which delimiter group was captured if match.group(1) is not None: # Content from $$...$$ - content = match.group(1) - modified_content = content.replace('*', LATEX_ASTERISK_PLACEHOLDER) - modified_content = modified_content.replace('_', LATEX_UNDERSCORE_PLACEHOLDER) - return f'{modified_content}' + return protect_latex_content(match.group(1)) elif match.group(2) is not None: # Content from \[...\] - content = match.group(2) - modified_content = content.replace('*', LATEX_ASTERISK_PLACEHOLDER) - modified_content = modified_content.replace('_', LATEX_UNDERSCORE_PLACEHOLDER) - return f'\\[{modified_content}\\]' + return f'\\[{protect_latex_content(match.group(2))}\\]' elif match.group(3) is not None: # Content from \(...\) - content = match.group(3) - modified_content = content.replace('*', LATEX_ASTERISK_PLACEHOLDER) - modified_content = modified_content.replace('_', LATEX_UNDERSCORE_PLACEHOLDER) - return f'\\({modified_content}\\)' + return f'\\({protect_latex_content(match.group(3))}\\)' + elif match.group(4) is not None: # Content from $...$ + return f'${protect_latex_content(match.group(4).strip())}$' return match.group(0) # Fallback @@ -240,7 +241,7 @@ def process_markdown_content(string): string = re.sub(r"(.)```", r"\1\n```", string) # Protect asterisks and underscores within all LaTeX blocks before markdown conversion - latex_pattern = re.compile(r'((?:^|[\r\n\s])\$\$[^`]*?\$\$)|\\\[(.*?)\\\]|\\\((.*?)\\\)', + latex_pattern = re.compile(r'((?:^|[\r\n\s])\$\$[^`]*?\$\$)|\\\[(.*?)\\\]|\\\((.*?)\\\)|(? html_output = re.sub(r'\s*', '', html_output)