Skip to content

Commit

Permalink
bring remark-math into nteract's monorepo
Browse files Browse the repository at this point in the history
Co-authored-by: Junyoung Choi <fluke8259@gmail.com>
Co-authored-by: Victor Felder <victor@draft.li>
  • Loading branch information
3 people committed Jan 31, 2018
1 parent 0799391 commit 61fa1a4
Show file tree
Hide file tree
Showing 4 changed files with 334 additions and 1 deletion.
2 changes: 1 addition & 1 deletion packages/markdown/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import React from "react";
import ReactMarkdown from "react-markdown";
import MathJax from "./mathjax";
import RemarkMathPlugin from "remark-math";
import RemarkMathPlugin from "./remark-math";

const math = (props: { value: string }) => (
<MathJax.Node>{props.value}</MathJax.Node>
Expand Down
228 changes: 228 additions & 0 deletions packages/markdown/src/remark-math/block.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
// @flow
var trim = require("trim-trailing-lines");

var C_NEWLINE = "\n";
var C_TAB = "\t";
var C_SPACE = " ";
var C_DOLLAR = "$";

var MIN_FENCE_COUNT = 2;
var CODE_INDENT_COUNT = 4;

module.exports = function blockPlugin(opts: Object) {
function blockTokenizer(eat, value, silent) {
var length = value.length + 1;
var index = 0;
var subvalue = "";
var fenceCount;
var marker;
var character;
var queue;
var content;
var exdentedContent;
var closing;
var exdentedClosing;
var indent;
var now;

/* Eat initial spacing. */
while (index < length) {
character = value.charAt(index);

if (character !== C_SPACE && character !== C_TAB) {
break;
}

subvalue += character;
index++;
}

indent = index;

/* Eat the fence. */
character = value.charAt(index);

if (character !== C_DOLLAR) {
return;
}

index++;
marker = character;
fenceCount = 1;
subvalue += character;

while (index < length) {
character = value.charAt(index);

if (character !== marker) {
break;
}

subvalue += character;
fenceCount++;
index++;
}

if (fenceCount < MIN_FENCE_COUNT) {
return;
}

/* Eat everything after the fence. */
while (index < length) {
character = value.charAt(index);

if (character === C_NEWLINE) {
break;
}
if (character === C_DOLLAR) {
return;
}

subvalue += character;
index++;
}

character = value.charAt(index);

if (silent) {
return true;
}

now = eat.now();
now.column += subvalue.length;
now.offset += subvalue.length;

queue = closing = exdentedClosing = content = exdentedContent = "";

/* Eat content. */
while (index < length) {
character = value.charAt(index);
content += closing;
exdentedContent += exdentedClosing;
closing = exdentedClosing = "";

if (character !== C_NEWLINE) {
content += character;
exdentedClosing += character;
index++;
continue;
}

/* Add the newline to `subvalue` if its the first
* character. Otherwise, add it to the `closing`
* queue. */
if (content) {
closing += character;
exdentedClosing += character;
} else {
subvalue += character;
}

queue = "";
index++;

while (index < length) {
character = value.charAt(index);

if (character !== C_SPACE) {
break;
}

queue += character;
index++;
}

closing += queue;
exdentedClosing += queue.slice(indent);

if (queue.length >= CODE_INDENT_COUNT) {
continue;
}

queue = "";

while (index < length) {
character = value.charAt(index);

if (character !== marker) {
break;
}

queue += character;
index++;
}

closing += queue;
exdentedClosing += queue;

if (queue.length < fenceCount) {
continue;
}

queue = "";

while (index < length) {
character = value.charAt(index);

if (character === C_NEWLINE) {
break;
}

closing += character;
exdentedClosing += character;
index++;
}

break;
}

subvalue += content + closing;
const trimmedContent = trim(exdentedContent);
return eat(subvalue)({
type: "math",
value: trimmedContent,
data: {
hName: "div",
hProperties: {
className: "math"
},
hChildren: [
{
type: "text",
value: trimmedContent
}
]
}
});
}

const Parser = this.Parser;

// Inject blockTokenizer
const blockTokenizers = Parser.prototype.blockTokenizers;
const blockMethods = Parser.prototype.blockMethods;
blockTokenizers.math = blockTokenizer;
blockMethods.splice(blockMethods.indexOf("fencedCode") + 1, 0, "math");

// Inject math to interrupt rules
const interruptParagraph = Parser.prototype.interruptParagraph;
const interruptList = Parser.prototype.interruptList;
const interruptBlockquote = Parser.prototype.interruptBlockquote;
interruptParagraph.splice(interruptParagraph.indexOf("fencedCode") + 1, 0, [
"math"
]);
interruptList.splice(interruptList.indexOf("fencedCode") + 1, 0, ["math"]);
interruptBlockquote.splice(interruptBlockquote.indexOf("fencedCode") + 1, 0, [
"math"
]);

const Compiler = this.Compiler;

// Stringify for math block
if (Compiler != null) {
const visitors = Compiler.prototype.visitors;
visitors.math = function(node) {
return "$$\n" + node.value + "\n$$";
};
}
};
9 changes: 9 additions & 0 deletions packages/markdown/src/remark-math/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// @flow

const inlinePlugin = require("./inline");
const blockPlugin = require("./block");

module.exports = function mathPlugin(opts: Object = {}) {
blockPlugin.call(this, opts);
inlinePlugin.call(this, opts);
};
96 changes: 96 additions & 0 deletions packages/markdown/src/remark-math/inline.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// @flow

function locator(value, fromIndex) {
return value.indexOf("$", fromIndex);
}

const ESCAPED_INLINE_MATH = /^\\\$/;
const INLINE_MATH = /^\$((?:\\\$|[^$])+)\$/;
const INLINE_MATH_DOUBLE = /^\$\$((?:\\\$|[^$])+)\$\$/;

module.exports = function inlinePlugin(opts: Object) {
function inlineTokenizer(eat, value, silent) {
let isDouble = true;
let match = INLINE_MATH_DOUBLE.exec(value);
if (!match) {
match = INLINE_MATH.exec(value);
isDouble = false;
}
const escaped = ESCAPED_INLINE_MATH.exec(value);

if (escaped) {
/* istanbul ignore if - never used (yet) */
if (silent) {
return true;
}
return eat(escaped[0])({
type: "text",
value: "$"
});
}

if (value.slice(-2) === "\\$") {
return eat(value)({
type: "text",
value: value.slice(0, -2) + "$"
});
}

if (match) {
/* istanbul ignore if - never used (yet) */
if (silent) {
return true;
}

const endingDollarInBackticks =
match[0].includes("`") && value.slice(match[0].length).includes("`");
if (endingDollarInBackticks) {
const toEat = value.slice(0, value.indexOf("`"));
return eat(toEat)({
type: "text",
value: toEat
});
}

const trimmedContent = match[1].trim();

return eat(match[0])({
type: "inlineMath",
value: trimmedContent,
data: {
hName: "span",
hProperties: {
className:
"inlineMath" +
(isDouble && opts.inlineMathDouble ? " inlineMathDouble" : "")
},
hChildren: [
{
type: "text",
value: trimmedContent
}
]
}
});
}
}
inlineTokenizer.locator = locator;

const Parser = this.Parser;

// Inject inlineTokenizer
const inlineTokenizers = Parser.prototype.inlineTokenizers;
const inlineMethods = Parser.prototype.inlineMethods;
inlineTokenizers.math = inlineTokenizer;
inlineMethods.splice(inlineMethods.indexOf("text"), 0, "math");

const Compiler = this.Compiler;

// Stringify for math inline
if (Compiler != null) {
const visitors = Compiler.prototype.visitors;
visitors.inlineMath = function(node) {
return "$" + node.value + "$";
};
}
};

0 comments on commit 61fa1a4

Please sign in to comment.