From a9177abe5a98dd31d9b5190e5c5e92244b861b21 Mon Sep 17 00:00:00 2001 From: Alf Eaton Date: Tue, 18 Jul 2023 11:53:38 +0100 Subject: [PATCH] [visual] Provide command definitions to MathJax (#13761) GitOrigin-RevId: 845921df363f61d2333c1305b0b3edb86501c296 --- .../extensions/visual/atomic-decorations.ts | 24 ++++++++++++++++++- .../extensions/visual/visual-widgets/math.ts | 19 +++++++++++++-- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/services/web/frontend/js/features/source-editor/extensions/visual/atomic-decorations.ts b/services/web/frontend/js/features/source-editor/extensions/visual/atomic-decorations.ts index 9b324ac701..4404a4caf9 100644 --- a/services/web/frontend/js/features/source-editor/extensions/visual/atomic-decorations.ts +++ b/services/web/frontend/js/features/source-editor/extensions/visual/atomic-decorations.ts @@ -150,6 +150,8 @@ export const atomicDecorations = (options: Options) => { ['proof', 'Proof'], ]) + let commandDefinitions = '' + const preamble: { from: number to: number @@ -570,6 +572,22 @@ export const atomicDecorations = (options: Options) => { } return false // no markup in verbatim content + } else if ( + nodeRef.type.is('NewCommand') || + nodeRef.type.is('RenewCommand') + ) { + const argumentNode = nodeRef.node.getChild('LiteralArgContent') + if (argumentNode) { + const argument = state + .sliceDoc(argumentNode.from, argumentNode.to) + .trim() + if (/^\\\w+/.test(argument)) { + const content = state.sliceDoc(nodeRef.from, nodeRef.to) + if (content) { + commandDefinitions += `${content}\n` + } + } + } } else if (nodeRef.type.is('Cite')) { // \cite command with a bibkey argument if (shouldDecorate(state, nodeRef)) { @@ -715,7 +733,11 @@ export const atomicDecorations = (options: Options) => { decorations.push( Decoration.replace({ - widget: new MathWidget(content, displayMode), + widget: new MathWidget( + content, + displayMode, + commandDefinitions + ), block: displayMode, }).range(ancestorNode.from, ancestorNode.to) ) diff --git a/services/web/frontend/js/features/source-editor/extensions/visual/visual-widgets/math.ts b/services/web/frontend/js/features/source-editor/extensions/visual/visual-widgets/math.ts index 3a5cc96d69..4c889f0ba3 100644 --- a/services/web/frontend/js/features/source-editor/extensions/visual/visual-widgets/math.ts +++ b/services/web/frontend/js/features/source-editor/extensions/visual/visual-widgets/math.ts @@ -5,7 +5,11 @@ import { placeSelectionInsideBlock } from '../selection' export class MathWidget extends WidgetType { destroyed = false - constructor(public math: string, public displayMode: boolean) { + constructor( + public math: string, + public displayMode: boolean, + public preamble?: string + ) { super() } @@ -26,7 +30,11 @@ export class MathWidget extends WidgetType { } eq(widget: MathWidget) { - return widget.math === this.math && widget.displayMode === this.displayMode + return ( + widget.math === this.math && + widget.displayMode === this.displayMode && + widget.preamble === this.preamble + ) } updateDOM(element: HTMLElement, view: EditorView) { @@ -62,6 +70,13 @@ export class MathWidget extends WidgetType { if (!this.destroyed) { MathJax.texReset([0]) // equation numbering is disabled, but this is still needed + if (this.preamble) { + try { + await MathJax.tex2svgPromise(this.preamble) + } catch { + // ignore errors thrown during parsing command definitions + } + } const math = await MathJax.tex2svgPromise(this.math, { ...MathJax.getMetricsFor(element), display: this.displayMode,