Replacing text between dollar signs for Mathml expression.

Hi, I’m new to Codemirror and find it really useful, it’s an awesome tool. However, I’m struggling with one problem. I’d like to know how can I replace text between dollar signs for Mathml expressions using the KaTeX module. So far I’ve tried to follow a simillar strcuture of the widget decoration’s example on the docs.

equations.ts:

import {EditorView, Decoration, MatchDecorator, WidgetType} from "@codemirror/view"
import {EquationWidget} from "./equationWidget"
import {RegExpCursor} from '@codemirror/search'

export default function equations(view: EditorView) {
  let widgets: any[] = []
  let doc = view.state.doc
  let latexInDoc = doc.toString().match(/\$([^$]+)\$/g)
  for (let i in latexInDoc){
    let regexcursor = new RegExpCursor(doc, '\\$([^$]+)\\$').next()
    let deco = Decoration.replace({
      widget: new EquationWidget('\\int')
    })
    widgets.push(deco.range(regexcursor.next().value.from, regexcursor.next().value.to))
  }
  return Decoration.set(widgets)
}

equationPlugin.ts:

import {ViewUpdate, ViewPlugin, DecorationSet, EditorView} from "@codemirror/view"
import equations from "./equations"
const equationPlugin = ViewPlugin.fromClass(class {
  decorations: DecorationSet
  constructor(view: EditorView) {
    this.decorations = equations(view)
  }
  update(update: ViewUpdate) {
    if (update.docChanged || update.viewportChanged)
      this.decorations = equations(update.view)
  }
}, {
  decorations: v => v.decorations,
  // eventHandlers: {
  //   mousedown: (e, view) => {
  //     let target = e.target as HTMLElement
  //     if (target.nodeName == "INPUT" &&
  //         target.parentElement!.classList.contains("cm-boolean-toggle"))
  //       return toggleBoolean(view, view.posAtDOM(target))
  //   }
  // }
})
export default equationPlugin

equationWidget.ts

import {WidgetType} from "@codemirror/view"
import katex from 'katex'
export class EquationWidget extends WidgetType {
  constructor(readonly latex: string) {
    super()
    this.latex = latex
  }
  eq(other: EquationWidget) { return false }
  toDOM() {
    const wrap = document.createElement('span')
    wrap.className = 'cm-math'
    wrap.innerHTML = katex.renderToString(this.latex)
    return wrap
  }
  ignoreEvent() { return false }
}

I’ve added the equationPlugin.ts to the extensions field on the editor’s state. When I run the code, it kind of works, but, everytime I add a new expression between dollar signs, anterior expressions get back to normal. Would the above be the correct approach? Am I using the correct type of Decoration?

You’re importing MatchDecorator but not using it? And why match the regexp yourself with .match and then also run a RegExpCursor?

You’re importing MatchDecorator but not using it?

It’s just an unused import, was trying to make the code work and did not remember to take it out.

And why match the regexp yourself with .match and then also run a RegExpCursor ?

This was a bad attempt to iterate through all the matches on the document and replace each one for the desired expression. However, I figured out how to make everything work, I’m using MatchDecorator.

Mantained the whole code but the following part at equations.ts

import {EditorView, Decoration, MatchDecorator, WidgetType} from "@codemirror/view"
import {EquationWidget} from "./equationWidget"
export default function equations(view: EditorView) {
  let decorator = new MatchDecorator(
    {
      regexp: new RegExp('\\$([^$]+)\\$', 'g'),
      decoration: (match) => {  
        return Decoration.replace({
          widget: new EquationWidget(match[1])
        })
      },
    }
  )
  return decorator.createDeco(view)
}

It seems to work, is this a good way to approach the problem?

I think so!