-
Notifications
You must be signed in to change notification settings - Fork 5.3k
fix(web): render LaTeX math in chat #7166
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
9df702f
cb5e50f
b995dc9
b17463c
dd8efab
dc581a7
118927f
4784861
d29aef9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -45,10 +45,12 @@ import React, { | |
| import type { Components, Options as ReactMarkdownOptions } from "react-markdown"; | ||
| import ReactMarkdown from "react-markdown"; | ||
| import { defaultUrlTransform } from "react-markdown"; | ||
| import rehypeKatex from "rehype-katex"; | ||
| import rehypeRaw from "rehype-raw"; | ||
| import rehypeSanitize, { defaultSchema } from "rehype-sanitize"; | ||
| import remarkBreaks from "remark-breaks"; | ||
| import remarkGfm from "remark-gfm"; | ||
| import remarkMath from "remark-math"; | ||
| import { remarkGithubAlerts } from "../markdown-github-alerts"; | ||
| import { renderSkillInlineMarkdownChildren } from "./chat/SkillInlineText"; | ||
| import { CHAT_FILE_TAG_CHIP_CLASS_NAME, FileTagChipContent } from "./chat/FileTagChip"; | ||
|
|
@@ -88,6 +90,12 @@ import { | |
| serializeTableElementToMarkdown, | ||
| } from "../markdown-clipboard"; | ||
| import { remarkNormalizeListItemIndentation } from "../markdown-list-indentation"; | ||
| import { | ||
| MARKDOWN_MATH_CODE_CLASS_NAMES, | ||
| normalizeLatexMathDelimiters, | ||
| rehypeStripKatexErrorTitle, | ||
| remarkPromoteBracketDisplayMath, | ||
| } from "../markdown-math"; | ||
| import { | ||
| extractMarkdownLinkHrefs, | ||
| normalizeMarkdownLinkDestination, | ||
|
|
@@ -272,7 +280,14 @@ const CHAT_MARKDOWN_SANITIZE_SCHEMA = { | |
| attributes: { | ||
| ...defaultSchema.attributes, | ||
| "*": (defaultSchema.attributes?.["*"] ?? []).filter((attribute) => attribute !== "title"), | ||
| code: [...(defaultSchema.attributes?.code ?? []), "dataCodeMeta", "dataInlineCode"], | ||
| code: [ | ||
| ...(defaultSchema.attributes?.code ?? []).filter( | ||
| (attribute) => !Array.isArray(attribute) || attribute[0] !== "className", | ||
| ), | ||
| ["className", /^language-./, ...MARKDOWN_MATH_CODE_CLASS_NAMES], | ||
| "dataCodeMeta", | ||
| "dataInlineCode", | ||
| ], | ||
| blockquote: [...(defaultSchema.attributes?.blockquote ?? []), "dataAlert"], | ||
| }, | ||
| protocols: { | ||
|
|
@@ -282,27 +297,22 @@ const CHAT_MARKDOWN_SANITIZE_SCHEMA = { | |
| }, | ||
| } satisfies Parameters<typeof rehypeSanitize>[0]; | ||
|
|
||
| const CHAT_MARKDOWN_REMARK_PLUGINS = [ | ||
| remarkGfm, | ||
| remarkGithubAlerts, | ||
| remarkNormalizeListItemIndentation, | ||
| remarkPreserveCodeMeta, | ||
| remarkNormalizeLinksAndTagInlineCode, | ||
| ] satisfies NonNullable<ReactMarkdownOptions["remarkPlugins"]>; | ||
|
|
||
| const CHAT_MARKDOWN_REMARK_PLUGINS_WITH_BREAKS = [ | ||
| remarkGfm, | ||
| remarkGithubAlerts, | ||
| remarkNormalizeListItemIndentation, | ||
| remarkBreaks, | ||
| remarkPreserveCodeMeta, | ||
| remarkNormalizeLinksAndTagInlineCode, | ||
| ] satisfies NonNullable<ReactMarkdownOptions["remarkPlugins"]>; | ||
| const CHAT_MARKDOWN_KATEX_OPTIONS = { | ||
| output: "htmlAndMathml", | ||
| errorColor: "var(--destructive)", | ||
| } as const; | ||
|
|
||
| const CHAT_MARKDOWN_REHYPE_PLUGINS = [ | ||
| rehypeRaw, | ||
| rehypeNormalizeWindowsImageSrc, | ||
| [rehypeSanitize, CHAT_MARKDOWN_SANITIZE_SCHEMA], | ||
| [rehypeKatex, CHAT_MARKDOWN_KATEX_OPTIONS], | ||
| rehypeStripKatexErrorTitle, | ||
| ] satisfies NonNullable<ReactMarkdownOptions["rehypePlugins"]>; | ||
|
|
||
| const CHAT_MARKDOWN_REHYPE_PLUGINS_WITHOUT_RAW_HTML = [ | ||
| [rehypeKatex, CHAT_MARKDOWN_KATEX_OPTIONS], | ||
| rehypeStripKatexErrorTitle, | ||
| ] satisfies NonNullable<ReactMarkdownOptions["rehypePlugins"]>; | ||
|
|
||
| /** GitHub's own five alert kinds, in its colors: the glyph names the urgency, the title says it. */ | ||
|
|
@@ -1695,6 +1705,21 @@ function ChatMarkdown({ | |
| [environmentId, openInEditor], | ||
| ); | ||
| const diffThemeName = resolveDiffThemeName(resolvedTheme); | ||
| const markdownSource = useMemo(() => normalizeLatexMathDelimiters(text), [text]); | ||
| const remarkPlugins = useMemo( | ||
| () => | ||
| [ | ||
| remarkGfm, | ||
| [remarkMath, { singleDollarTextMath: false }], | ||
| [remarkPromoteBracketDisplayMath, { source: text }], | ||
| remarkGithubAlerts, | ||
| remarkNormalizeListItemIndentation, | ||
| ...(lineBreaks ? [remarkBreaks] : []), | ||
| remarkPreserveCodeMeta, | ||
| remarkNormalizeLinksAndTagInlineCode, | ||
| ] satisfies NonNullable<ReactMarkdownOptions["remarkPlugins"]>, | ||
| [lineBreaks, text], | ||
| ); | ||
| const markdownFileLinkMetaByHref = useMemo(() => { | ||
| const metaByHref = new Map< | ||
| string, | ||
|
|
@@ -2245,15 +2270,17 @@ function ChatMarkdown({ | |
| onCopy={handleCopy} | ||
| > | ||
| <ReactMarkdown | ||
| remarkPlugins={ | ||
| lineBreaks ? CHAT_MARKDOWN_REMARK_PLUGINS_WITH_BREAKS : CHAT_MARKDOWN_REMARK_PLUGINS | ||
| remarkPlugins={remarkPlugins} | ||
| rehypePlugins={ | ||
| parseRawHtml | ||
| ? CHAT_MARKDOWN_REHYPE_PLUGINS | ||
| : CHAT_MARKDOWN_REHYPE_PLUGINS_WITHOUT_RAW_HTML | ||
| } | ||
| rehypePlugins={parseRawHtml ? CHAT_MARKDOWN_REHYPE_PLUGINS : undefined} | ||
| skipHtml={false} | ||
| components={markdownComponents} | ||
| urlTransform={markdownUrlTransform} | ||
| > | ||
| {text} | ||
| {markdownSource} | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With Suggest teaching the serializer about math: on an element with the Posted via Macroscope — UI Consistency
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in a0f1693e. The clipboard serializer now recognizes inline and display KaTeX, reads the application/x-tex annotation, and emits explicit LaTeX delimiters. I used \(…\) and \[...\] rather than single-dollar syntax because single-dollar math is now intentionally disabled. Added round-trip tests for both forms.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, I'm unable to act on this request because you do not have permissions within this repository. |
||
| </ReactMarkdown> | ||
| </div> | ||
| ); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.