diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatCopyActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatCopyActions.ts index 15e4fd5e780..21d3388ad92 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatCopyActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatCopyActions.ts @@ -12,6 +12,7 @@ import { CHAT_CATEGORY, stringifyItem } from './chatActions.js'; import { ChatTreeItem, IChatWidgetService } from '../chat.js'; import { ChatContextKeys } from '../../common/chatContextKeys.js'; import { IChatRequestViewModel, IChatResponseViewModel, isChatTreeItem, isRequestVM, isResponseVM } from '../../common/chatViewModel.js'; +import { katexContainerClassName, katexContainerLatexAttributeName } from '../../../markdown/common/markedKatexExtension.js'; export function registerChatCopyActions() { registerAction2(class CopyAllAction extends Action2 { @@ -135,15 +136,13 @@ export function registerChatCopyActions() { // Otherwise, fallback to querying from the active element if (!selectedElement) { // eslint-disable-next-line no-restricted-syntax - selectedElement = activeElement?.querySelector('.katex') ?? null; + selectedElement = activeElement?.querySelector(`.${katexContainerClassName}`) ?? null; } // Extract the LaTeX source from the annotation element - const katexElement = dom.isHTMLElement(selectedElement) ? selectedElement.closest('.katex') : null; - // eslint-disable-next-line no-restricted-syntax - const annotation = katexElement?.querySelector('annotation[encoding="application/x-tex"]'); - if (annotation) { - const latexSource = annotation.textContent || ''; + const katexElement = dom.isHTMLElement(selectedElement) ? selectedElement.closest(`.${katexContainerClassName}`) : null; + const latexSource = katexElement?.getAttribute(katexContainerLatexAttributeName) || ''; + if (latexSource) { await clipboardService.writeText(latexSource); } } diff --git a/src/vs/workbench/contrib/chat/browser/chatWidget.ts b/src/vs/workbench/contrib/chat/browser/chatWidget.ts index a1daf80645d..b0b45d973dd 100644 --- a/src/vs/workbench/contrib/chat/browser/chatWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/chatWidget.ts @@ -95,6 +95,7 @@ import { ChatViewPane } from './chatViewPane.js'; import { ChatViewWelcomePart, IChatSuggestedPrompts, IChatViewWelcomeContent } from './viewsWelcome/chatViewWelcomeController.js'; import { IWorkspaceContextService, WorkbenchState } from '../../../../platform/workspace/common/workspace.js'; import { ILifecycleService } from '../../../services/lifecycle/common/lifecycle.js'; +import { katexContainerClassName } from '../../markdown/common/markedKatexExtension.js'; const $ = dom.$; @@ -2015,7 +2016,7 @@ export class ChatWidget extends Disposable implements IChatWidget { // Check if the context menu was opened on a KaTeX element const target = e.browserEvent.target as HTMLElement; - const isKatexElement = target.closest('.katex') !== null; + const isKatexElement = target.closest(`.${katexContainerClassName}`) !== null; const scopedContextKeyService = this.contextKeyService.createOverlay([ [ChatContextKeys.responseIsFiltered.key, isResponseVM(selected) && !!selected.errorDetails?.responseIsFiltered], diff --git a/src/vs/workbench/contrib/markdown/browser/markedKatexSupport.ts b/src/vs/workbench/contrib/markdown/browser/markedKatexSupport.ts index a43139a5591..3d83476e176 100644 --- a/src/vs/workbench/contrib/markdown/browser/markedKatexSupport.ts +++ b/src/vs/workbench/contrib/markdown/browser/markedKatexSupport.ts @@ -9,7 +9,7 @@ import { MarkdownSanitizerConfig } from '../../../../base/browser/markdownRender import { CodeWindow } from '../../../../base/browser/window.js'; import { Lazy } from '../../../../base/common/lazy.js'; import type * as marked from '../../../../base/common/marked/marked.js'; -import { MarkedKatexExtension } from '../common/markedKatexExtension.js'; +import { katexContainerLatexAttributeName, MarkedKatexExtension } from '../common/markedKatexExtension.js'; export class MarkedKatexSupport { @@ -32,6 +32,7 @@ export class MarkedKatexSupport { 'stretchy', 'encoding', 'accent', + katexContainerLatexAttributeName, // SVG 'd', diff --git a/src/vs/workbench/contrib/markdown/common/markedKatexExtension.ts b/src/vs/workbench/contrib/markdown/common/markedKatexExtension.ts index 25686fdcc6f..01b35c39d86 100644 --- a/src/vs/workbench/contrib/markdown/common/markedKatexExtension.ts +++ b/src/vs/workbench/contrib/markdown/common/markedKatexExtension.ts @@ -3,9 +3,11 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import type * as marked from '../../../../base/common/marked/marked.js'; +import { htmlAttributeEncodeValue } from '../../../../base/common/strings.js'; export const mathInlineRegExp = /(?\${1,2})(?!\$)((?:\\.|[^\\\n])*?(?:\\.|[^\\\n\$]))\k(?![a-zA-Z0-9])/; // Non-standard, but ensure opening $ is not preceded and closing $ is not followed by word/number characters - +export const katexContainerClassName = 'vscode-katex-container'; +export const katexContainerLatexAttributeName = 'data-latex'; const inlineRule = new RegExp('^' + mathInlineRegExp.source); @@ -32,11 +34,15 @@ export namespace MarkedKatexExtension { return (token: marked.Tokens.Generic) => { let out: string; try { - out = katex.renderToString(token.text, { + const html = katex.renderToString(token.text, { ...options, throwOnError: true, displayMode: token.displayMode, }); + + // Wrap in a container with attribute as a fallback for extracting the original LaTeX source + // This ensures we can always retrieve the source even if the annotation element is not present + out = `${html}`; } catch { // On failure, just use the original text including the wrapping $ or $$ out = token.raw; diff --git a/src/vs/workbench/contrib/markdown/test/browser/__snapshots__/Markdown_Katex_Support_Test_Basic_inline_equation.0.snap b/src/vs/workbench/contrib/markdown/test/browser/__snapshots__/Markdown_Katex_Support_Test_Basic_inline_equation.0.snap index 3af85838d9a..58789c49006 100644 --- a/src/vs/workbench/contrib/markdown/test/browser/__snapshots__/Markdown_Katex_Support_Test_Basic_inline_equation.0.snap +++ b/src/vs/workbench/contrib/markdown/test/browser/__snapshots__/Markdown_Katex_Support_Test_Basic_inline_equation.0.snap @@ -1 +1 @@ -

Hello 12\frac{1}{2}21 World!

\ No newline at end of file +

Hello 12\frac{1}{2}21 World!

\ No newline at end of file diff --git a/src/vs/workbench/contrib/markdown/test/browser/__snapshots__/Markdown_Katex_Support_Test_Should_still_render_math_at_start_and_end_of_line.0.snap b/src/vs/workbench/contrib/markdown/test/browser/__snapshots__/Markdown_Katex_Support_Test_Should_still_render_math_at_start_and_end_of_line.0.snap index d12c80ba96d..b74946442b0 100644 --- a/src/vs/workbench/contrib/markdown/test/browser/__snapshots__/Markdown_Katex_Support_Test_Should_still_render_math_at_start_and_end_of_line.0.snap +++ b/src/vs/workbench/contrib/markdown/test/browser/__snapshots__/Markdown_Katex_Support_Test_Should_still_render_math_at_start_and_end_of_line.0.snap @@ -1 +1 @@ -

12\frac{1}{2}21 at start, and at end x2x^2x2

\ No newline at end of file +

12\frac{1}{2}21 at start, and at end x2x^2x2

\ No newline at end of file diff --git a/src/vs/workbench/contrib/markdown/test/browser/__snapshots__/Markdown_Katex_Support_Test_Should_still_render_math_with_special_characters_around_dollars.0.snap b/src/vs/workbench/contrib/markdown/test/browser/__snapshots__/Markdown_Katex_Support_Test_Should_still_render_math_with_special_characters_around_dollars.0.snap index 42ca2f57169..a3c12437529 100644 --- a/src/vs/workbench/contrib/markdown/test/browser/__snapshots__/Markdown_Katex_Support_Test_Should_still_render_math_with_special_characters_around_dollars.0.snap +++ b/src/vs/workbench/contrib/markdown/test/browser/__snapshots__/Markdown_Katex_Support_Test_Should_still_render_math_with_special_characters_around_dollars.0.snap @@ -1 +1 @@ -

Hello (12\frac{1}{2}21) and [x2x^2x2] work fine

\ No newline at end of file +

Hello (12\frac{1}{2}21) and [x2x^2x2] work fine

\ No newline at end of file diff --git a/src/vs/workbench/contrib/markdown/test/browser/__snapshots__/Markdown_Katex_Support_Test_Should_support_blocks_immediately_after_paragraph.0.snap b/src/vs/workbench/contrib/markdown/test/browser/__snapshots__/Markdown_Katex_Support_Test_Should_support_blocks_immediately_after_paragraph.0.snap index 5d089f4c241..ab6482a2567 100644 --- a/src/vs/workbench/contrib/markdown/test/browser/__snapshots__/Markdown_Katex_Support_Test_Should_support_blocks_immediately_after_paragraph.0.snap +++ b/src/vs/workbench/contrib/markdown/test/browser/__snapshots__/Markdown_Katex_Support_Test_Should_support_blocks_immediately_after_paragraph.0.snap @@ -1,4 +1,4 @@ -

Block example:

ex2dx=π\int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi}ex2dx=πex2dx=π\int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi}ex2dx=π +M834 80h400000v40h-400000z"> diff --git a/src/vs/workbench/contrib/markdown/test/browser/__snapshots__/Markdown_Katex_Support_Test_Should_support_inline_equation_wrapped_in_parans.0.snap b/src/vs/workbench/contrib/markdown/test/browser/__snapshots__/Markdown_Katex_Support_Test_Should_support_inline_equation_wrapped_in_parans.0.snap index 5c29aad77f0..b0144ff9fc8 100644 --- a/src/vs/workbench/contrib/markdown/test/browser/__snapshots__/Markdown_Katex_Support_Test_Should_support_inline_equation_wrapped_in_parans.0.snap +++ b/src/vs/workbench/contrib/markdown/test/browser/__snapshots__/Markdown_Katex_Support_Test_Should_support_inline_equation_wrapped_in_parans.0.snap @@ -1 +1 @@ -

Hello (12\frac{1}{2}21) World!

\ No newline at end of file +

Hello (12\frac{1}{2}21) World!

\ No newline at end of file