- // ==UserScript==
- // @name texmath
- // @namespace https://www.cc98.org/
- // @version 0.1
- // @description TeXmath support for cc98 markdown posts
- // @author Secant
- // @match https://www.cc98.org/topic/*
- // @grant none
- // jshint esversion: 6
- (function () {
- "use strict";
- function texmath(md, options) {
- const delimiters = "dollars";
- const imgtexOptions = (options && options.imgtexOptions) || {
- apiBase: "https://math.now.sh",
- color: "black",
- };
-
- if (!texmath.imgtex) {
- // else ... depricated `use` method was used ...
- if (options && typeof options.engine === "object") {
- texmath.imgtex = options.engine;
- }
- // artifical error object.
- else
- texmath.imgtex = {
- renderToString() {
- return "No math renderer found.";
- },
- };
- }
-
- if (delimiters in texmath.rules) {
- for (const rule of texmath.rules[delimiters].inline) {
- md.inline.ruler.before("escape", rule.name, texmath.inline(rule)); // ! important
- md.renderer.rules[rule.name] = (tokens, idx) =>
- rule.tmpl.replace(
- /\$1/,
- texmath.render(
- tokens[idx].content,
- !!rule.displayMode,
- imgtexOptions
- )
- );
- }
-
- for (const rule of texmath.rules[delimiters].block) {
- md.block.ruler.before("fence", rule.name, texmath.block(rule)); // ! important for ```math delimiters
- md.renderer.rules[rule.name] = (tokens, idx) =>
- rule.tmpl.replace(
- /\$1/,
- texmath.render(tokens[idx].content, true, imgtexOptions)
- );
- }
- }
- }
-
- texmath.inline = (rule) =>
- function (state, silent) {
- const pos = state.pos;
- const str = state.src;
- const pre =
- str.startsWith(rule.tag, (rule.rex.lastIndex = pos)) &&
- (!rule.pre || rule.pre(str, pos)); // valid pre-condition ...
- const match = pre && rule.rex.exec(str);
- const res =
- !!match &&
- pos < rule.rex.lastIndex &&
- (!rule.post || rule.post(str, rule.rex.lastIndex - 1));
-
- if (res) {
- if (!silent) {
- const token = state.push(rule.name, "math", 0);
- token.content = match[1];
- token.markup = rule.tag;
- }
- state.pos = rule.rex.lastIndex;
- }
- return res;
- };
-
- texmath.block = (rule) =>
- function block(state, begLine, endLine, silent) {
- const pos = state.bMarks[begLine] + state.tShift[begLine];
- const str = state.src;
- const pre =
- str.startsWith(rule.tag, (rule.rex.lastIndex = pos)) &&
- (!rule.pre || rule.pre(str, pos)); // valid pre-condition ....
- const match = pre && rule.rex.exec(str);
- const res =
- !!match &&
- pos < rule.rex.lastIndex &&
- (!rule.post || rule.post(str, rule.rex.lastIndex - 1));
-
- if (res && !silent) {
- // match and valid post-condition ...
- const endpos = rule.rex.lastIndex - 1;
- let curline;
-
- for (curline = begLine; curline < endLine; curline++)
- if (
- endpos >= state.bMarks[curline] + state.tShift[curline] &&
- endpos <= state.eMarks[curline]
- )
- // line for end of block math found ...
- break;
-
- // "this will prevent lazy continuations from ever going past our end marker"
- // s. https://github.com/markdown-it/markdown-it-container/blob/master/index.js
- const lineMax = state.lineMax;
- state.lineMax = curline;
-
- // begin token
- let token = state.push(rule.name, "math", 1); // 'math_block'
- token.block = true;
- token.markup = rule.tag;
- token.content = match[1];
- token.map = [begLine, curline];
- // end token
- token = state.push(rule.name + "_end", "math", -1);
- token.block = true;
- token.markup = rule.tag;
-
- state.lineMax = lineMax;
- state.line = curline + 1;
- }
- return res;
- };
-
- texmath.render = function (tex, displayMode, options) {
- options.displayMode = displayMode;
- let res;
- try {
- res = texmath.imgtex.renderToString(tex, options);
- } catch (err) {
- res = tex + ": " + err.message;
- }
- return res;
- };
-
- // used for enable/disable math rendering by `markdown-it`
- texmath.inlineRuleNames = ["math_inline"];
- texmath.blockRuleNames = ["math_block"];
-
- texmath.$_pre = (str, beg) => {
- const prv = beg > 0 ? str[beg - 1].charCodeAt(0) : false;
- return (
- !prv ||
- (prv !== 0x5c && // no backslash,
- (prv < 0x30 || prv > 0x39))
- ); // no decimal digit .. before opening '$'
- };
- texmath.$_post = (str, end) => {
- const nxt = str[end + 1] && str[end + 1].charCodeAt(0);
- return !nxt || nxt < 0x30 || nxt > 0x39; // no decimal digit .. after closing '$'
- };
-
- texmath.rules = {
- dollars: {
- inline: [
- {
- name: "math_inline",
- rex: /\$((?:\S)|(?:\S.*?\S))\$/gy,
- tmpl: "$1",
- tag: "$",
- pre: texmath.$_pre,
- post: texmath.$_post,
- },
- ],
- block: [
- {
- name: "math_block",
- rex: /\${2}([^$]+?)\${2}/gmy,
- tmpl: "<center>$1</center>",
- tag: "$$",
- },
- ],
- },
- };
-
- window.texmath = texmath;
- })();