diff --git a/IPython/html/static/base/js/utils.js b/IPython/html/static/base/js/utils.js
index b3f7b3a..90eca6e 100644
--- a/IPython/html/static/base/js/utils.js
+++ b/IPython/html/static/base/js/utils.js
@@ -448,6 +448,10 @@ IPython.utils = (function (IPython) {
// http://stackoverflow.com/questions/2400935/browser-detection-in-javascript
var browser = (function() {
+ if (typeof navigator === 'undefined') {
+ // navigator undefined in node
+ return 'None';
+ }
var N= navigator.appName, ua= navigator.userAgent, tem;
var M= ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
if (M && (tem= ua.match(/version\/([\.\d]+)/i))!= null) M[2]= tem[1];
diff --git a/IPython/html/static/notebook/js/mathjaxutils.js b/IPython/html/static/notebook/js/mathjaxutils.js
index e076901..62044dc 100644
--- a/IPython/html/static/notebook/js/mathjaxutils.js
+++ b/IPython/html/static/notebook/js/mathjaxutils.js
@@ -106,12 +106,11 @@ IPython.mathjaxutils = (function (IPython) {
// math, then push the math string onto the storage array.
// The preProcess function is called on all blocks if it has been passed in
var process_math = function (i, j, pre_process, math, blocks) {
- var hub = MathJax.Hub;
var block = blocks.slice(i, j + 1).join("").replace(/&/g, "&") // use HTML entity for &
.replace(//g, ">") // use HTML entity for >
;
- if (hub.Browser.isMSIE) {
+ if (IPython.utils.browser === 'msie') {
block = block.replace(/(%[^\n]*)\n/g, "$1
\n");
}
while (j > i) {
@@ -133,10 +132,6 @@ IPython.mathjaxutils = (function (IPython) {
// (which will be a paragraph).
//
var remove_math = function (text) {
- if (!window.MathJax) {
- return [text, null];
- }
-
var math = []; // stores math strings for later
var start;
var end;
@@ -241,9 +236,6 @@ IPython.mathjaxutils = (function (IPython) {
// and clear the math array (no need to keep it around).
//
var replace_math = function (text, math) {
- if (!window.MathJax) {
- return text;
- }
text = text.replace(/@@(\d+)@@/g, function (match, n) {
return math[n];
});
diff --git a/IPython/nbconvert/filters/markdown.py b/IPython/nbconvert/filters/markdown.py
index cd4b5a2..5bfd4e6 100755
--- a/IPython/nbconvert/filters/markdown.py
+++ b/IPython/nbconvert/filters/markdown.py
@@ -16,21 +16,33 @@ markdown within Jinja templates.
from __future__ import print_function
# Stdlib imports
-import sys
+import os
import subprocess
+from io import TextIOWrapper, BytesIO
+# IPython imports
from IPython.nbconvert.utils.pandoc import pandoc
+from IPython.nbconvert.utils.exceptions import ConversionException
+from IPython.utils.process import find_cmd, FindCmdError
+from IPython.utils.py3compat import cast_bytes
#-----------------------------------------------------------------------------
# Functions
#-----------------------------------------------------------------------------
+marked = os.path.join(os.path.dirname(__file__), "marked.js")
__all__ = [
'markdown2html',
+ 'markdown2html_pandoc',
+ 'markdown2html_marked',
'markdown2latex',
- 'markdown2rst'
+ 'markdown2rst',
]
+class NodeJSMissing(ConversionException):
+ """Exception raised when node.js is missing."""
+ pass
+
def markdown2latex(source):
"""Convert a markdown string to LaTeX via pandoc.
@@ -49,11 +61,26 @@ def markdown2latex(source):
"""
return pandoc(source, 'markdown', 'latex')
-
-def markdown2html(source):
+def markdown2html_pandoc(source):
"""Convert a markdown string to HTML via pandoc"""
return pandoc(source, 'markdown', 'html', extra_args=['--mathjax'])
+def markdown2html_marked(source, encoding='utf-8'):
+ """Convert a markdown string to HTML via marked"""
+ command = ['node', marked]
+ try:
+ p = subprocess.Popen(command,
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE
+ )
+ except OSError as e:
+ raise NodeJSMissing(
+ "The command '%s' returned an error: %s.\n" % (" ".join(command), e) +
+ "Please check that Node.js is installed."
+ )
+ out, _ = p.communicate(cast_bytes(source, encoding))
+ out = TextIOWrapper(BytesIO(out), encoding, 'replace').read()
+ return out.rstrip('\n')
+
def markdown2rst(source):
"""Convert a markdown string to LaTeX via pandoc.
@@ -72,3 +99,9 @@ def markdown2rst(source):
"""
return pandoc(source, 'markdown', 'rst')
+try:
+ find_cmd('node')
+except FindCmdError:
+ markdown2html = markdown2html_pandoc
+else:
+ markdown2html = markdown2html_marked
diff --git a/IPython/nbconvert/filters/marked.js b/IPython/nbconvert/filters/marked.js
new file mode 100644
index 0000000..2816630
--- /dev/null
+++ b/IPython/nbconvert/filters/marked.js
@@ -0,0 +1,54 @@
+// Node.js script for markdown to html conversion
+// This applies the same math extraction and marked settings
+// that we use in the live notebook.
+
+// IPython static_path dir relative to here:
+var static_path = __dirname + "/../../html/static/";
+
+var fs = require('fs');
+var IPython;
+// marked can be loaded with require,
+// the others must be execfiled
+var marked = require(static_path + 'components/marked/lib/marked.js');
+
+eval(fs.readFileSync(static_path + "components/highlight.js/build/highlight.pack.js", 'utf8'));
+eval(fs.readFileSync(static_path + "base/js/namespace.js", 'utf8'));
+
+eval(fs.readFileSync(static_path + "base/js/utils.js", 'utf8'));
+eval(fs.readFileSync(static_path + "notebook/js/mathjaxutils.js", 'utf8'));
+
+// this is copied from notebook.main. Should it be moved somewhere we can reuse it?
+marked.setOptions({
+ gfm : true,
+ tables: true,
+ langPrefix: "language-",
+ highlight: function(code, lang) {
+ if (!lang) {
+ // no language, no highlight
+ return code;
+ }
+ var highlighted;
+ try {
+ highlighted = hljs.highlight(lang, code, false);
+ } catch(err) {
+ highlighted = hljs.highlightAuto(code);
+ }
+ return highlighted.value;
+ }
+});
+
+// read the markdown from stdin
+var md='';
+process.stdin.on("data", function (data) {
+ md += data;
+});
+
+// perform the md2html transform once stdin is complete
+process.stdin.on("end", function () {
+ var text_and_math = IPython.mathjaxutils.remove_math(md);
+ var text = text_and_math[0];
+ var math = text_and_math[1];
+ var html = marked.parser(marked.lexer(text));
+ html = IPython.mathjaxutils.replace_math(html, math);
+ process.stdout.write(html);
+});
diff --git a/setupbase.py b/setupbase.py
index 5afbdfe..b5c9b20 100644
--- a/setupbase.py
+++ b/setupbase.py
@@ -164,6 +164,7 @@ def find_package_data():
'IPython.qt.console' : ['resources/icon/*.svg'],
'IPython.nbconvert' : nbconvert_templates +
['tests/files/*.*', 'exporters/tests/files/*.*'],
+ 'IPython.nbconvert.filters' : ['marked.js'],
'IPython.nbformat' : ['tests/*.ipynb']
}
return package_data