message: tell markdown parser to ignore properly-formatted math tags
diff: @@ -23,19 +23,47 @@ const ALLOWED_HTML_TAGS = ['sub', 'sup', 'del', 'u'];
  // These types of node are definitely text
  const TEXT_NODES = ['text', 'softbreak', 'linebreak', 'paragraph', 'document'];
  -function is_math_node(node) {
  - return node != null &&
  - node.literal != null &&
  - node.literal.match(/^<((div|span) data-mx-maths="[^"]*"|\/(div|span))>$/) != null;
  +// prevent renderer from interpreting contents of AST node
  +function freeze_node(walker, node) {
  + const newNode = new commonmark.Node('custom_inline', node.sourcepos);
  + newNode.onEnter = node.literal;
  + node.insertAfter(newNode);
  + node.unlink();
  + walker.resumeAt(newNode.next, true);
  +}
  +
  +// prevent renderer from interpreting contents of latex math tags
  +function freeze_math(parsed) {
  + const walker = parsed.walker();
  + let ev;
  + let inMath = false;
  + while ( (ev = walker.next()) ) {
  + const node = ev.node;
  + if (ev.entering) {
  + if (!inMath) {
  + // entering a math tag
  + if (node.literal != null && node.literal.match('^<(div|span) data-mx-maths="[^"]*">$') != null) {
  + inMath = true;
  + freeze_node(walker, node);
  + }
  + } else {
  + // math tags should only contain a single code block, with URL-escaped latex as fallback output
  + if (node.literal != null && node.literal.match('^(<code>|</code>|[^<>]*)$')) {
  + freeze_node(walker, node);
  + // leave when span or div is closed
  + } else if (node.literal == '</span>' || node.literal == '</div>') {
  + inMath = false;
  + freeze_node(walker, node);
  + // this case only happens if we have improperly formatted math tags, so bail
  + } else {
  + inMath = false;
  + }
  + }
  + }
  }
  -
  -function is_allowed_html_tag(node) {
  - if (SettingsStore.getValue("feature_latex_maths") &&
  - (is_math_node(node) ||
  - (node.literal.match(/^<\/?code>$/) && is_math_node(node.parent)))) {
  - return true;
  }
  +function is_allowed_html_tag(node) {
  // Regex won't work for tags with attrs, but we only
  // allow <del> anyway.
  const matches = /^<\/?(.*)>$/.exec(node.literal);
  @@ -173,6 +201,9 @@ export default class Markdown {
  */
  };
  + // prevent strange behaviour when mixing latex math and markdown
  + freeze_math(this.parsed);
  +
  return renderer.render(this.parsed);
  }
  