Skip to content

Commit 174c6ff

Browse files
authoredAug 1, 2017
Merge pull request #244 from getnikola/localkatex
Add localkatex plugin for local rendering of KaTeX math
2 parents 67dffe0 + 9f21fea commit 174c6ff

8 files changed

+202
-0
lines changed
 

‎v7/localkatex/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules

‎v7/localkatex/README.md

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
A plugin that renders math using a local KaTeX install.
2+
3+
## Requirements
4+
5+
* node.js installed, in $PATH, accessible as the `node` command
6+
* KaTeX accessible by Node (run `npm install` in this plugin’s folder)
7+
* `USE_KATEX = True` in config
8+
9+
You may also edit `math_helper.tmpl` to remove the KaTeX JavaScript includes
10+
(which are now unused).
11+
12+
## Examples:
13+
14+
Inline:
15+
16+
Euler’s formula: {{% lmath %}}e^{ix} = \cos x + i\sin x{{% /lmath %}}
17+
18+
Display:
19+
20+
{{% lmath display=true %}}\int \frac{dx}{1+ax}=\frac{1}{a}\ln(1+ax)+C{{% /lmath %}}
21+
{{% lmathd %}}\int \frac{dx}{1+ax}=\frac{1}{a}\ln(1+ax)+C{{% /lmathd %}}
22+
23+
Alternate name:
24+
25+
{{% localkatex %}}e^{ix} = \cos x + i\sin x{{% /localkatex %}}
26+
27+
The following options are supported: `displayMode`, `display` (alias), `throwOnError`, `errorColor`, `colorIsTextColor` — see [KaTeX docs](https://github.com/Khan/KaTeX#rendering-options) for details.

‎v7/localkatex/conf.py.sample

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Enable KaTeX styles
2+
USE_KATEX = True
3+
4+
# Make sure you run `npm install` in this plugin’s directory.

‎v7/localkatex/localkatex.js

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright © 2017, Chris Warrick.
3+
*
4+
* Permission is hereby granted, free of charge, to any
5+
* person obtaining a copy of this software and associated
6+
* documentation files (the "Software"), to deal in the
7+
* Software without restriction, including without limitation
8+
* the rights to use, copy, modify, merge, publish,
9+
* distribute, sublicense, and/or sell copies of the
10+
* Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice
14+
* shall be included in all copies or substantial portions of
15+
* the Software.
16+
*
17+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
18+
* KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
19+
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
20+
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
21+
* OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
22+
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23+
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24+
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25+
*/
26+
27+
'use strict';
28+
29+
let readline;
30+
let katex;
31+
32+
try {
33+
readline = require('readline');
34+
katex = require('katex');
35+
} catch (e) {
36+
console.log(JSON.stringify({"input": null, "output": null, "success": false}));
37+
process.exit(1);
38+
}
39+
40+
const rl = readline.createInterface({
41+
input: process.stdin,
42+
});
43+
44+
rl.on('line', (line) => {
45+
let j = JSON.parse(line);
46+
try {
47+
let html = katex.renderToString(j["math"], j["options"]);
48+
console.log(JSON.stringify({"input": j["math"], "output": html, "success": true}));
49+
} catch (e) {
50+
console.log(JSON.stringify({"input": j["math"], "output": e.toString(), "success": false}));
51+
}
52+
});

‎v7/localkatex/localkatex.plugin

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[Core]
2+
Name = localkatex
3+
Module = localkatex
4+
5+
[Nikola]
6+
PluginCategory = ShortcodePlugin
7+
8+
[Documentation]
9+
Author = Chris Warrick
10+
Version = 0.1.0
11+
Website = https://chriswarrick.com/
12+
Description = Render math using KaTeX while building the site

‎v7/localkatex/localkatex.py

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# -*- coding: utf-8 -*-
2+
3+
# Copyright © 2017, Chris Warrick.
4+
5+
# Permission is hereby granted, free of charge, to any
6+
# person obtaining a copy of this software and associated
7+
# documentation files (the "Software"), to deal in the
8+
# Software without restriction, including without limitation
9+
# the rights to use, copy, modify, merge, publish,
10+
# distribute, sublicense, and/or sell copies of the
11+
# Software, and to permit persons to whom the Software is
12+
# furnished to do so, subject to the following conditions:
13+
#
14+
# The above copyright notice and this permission notice
15+
# shall be included in all copies or substantial portions of
16+
# the Software.
17+
#
18+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
19+
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
20+
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
21+
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
22+
# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23+
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24+
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25+
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26+
27+
from __future__ import unicode_literals
28+
import subprocess
29+
import json
30+
import os.path
31+
32+
from nikola.plugin_categories import ShortcodePlugin
33+
from nikola import utils
34+
35+
jspath = os.path.join(os.path.split(__file__)[0], 'localkatex.js')
36+
37+
38+
class LocalKatex(ShortcodePlugin):
39+
"""Render math using KaTeX while building the site."""
40+
41+
name = 'localkatex'
42+
_options_available = {'displayMode': bool, 'throwOnError': bool, 'errorColor': str, 'colorIsTextColor': bool}
43+
logger = None
44+
45+
def set_site(self, site):
46+
"""Set Nikola site."""
47+
site.register_shortcode('lmath', self.handler)
48+
site.register_shortcode('lmathd', self.handler_display)
49+
self.logger = utils.get_logger('localkatex')
50+
return super(LocalKatex, self).set_site(site)
51+
52+
@staticmethod
53+
def _str_to_bool(v):
54+
return v.lower() not in ('false', 'no', 'f', 'n')
55+
56+
def handler(self, site, lang, post, data, **options):
57+
"""Render math."""
58+
p = subprocess.Popen(['node', jspath], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
59+
60+
if 'display' in options:
61+
options['displayMode'] = options['display']
62+
del options['display']
63+
64+
for k, v in options.items():
65+
if k in self._options_available and self._options_available[k] == bool:
66+
options[k] = self._str_to_bool(v)
67+
elif k not in self._options_available:
68+
raise ValueError("Unknown KaTeX option {0}={1}".format(k, v))
69+
70+
json_input = json.dumps({'math': data, 'options': options}).encode('utf-8')
71+
stdout, stderr = p.communicate(json_input)
72+
output = json.loads(stdout.decode('utf-8').strip())
73+
if output['success']:
74+
return output['output']
75+
else:
76+
if output['input'] is None and output['output'] is None:
77+
raise Exception("Cannot import KaTeX. Did you run npm install?")
78+
else:
79+
self.logger.error("In expression {0}: {1}".format(data, output['output']))
80+
return '<span class="problematic"><strong>In expression <code>{0}</code>:</strong> {1}</span>'.format(data, output['output'])
81+
82+
def handler_display(self, site, lang, post, data, **options):
83+
"""Render math in display mode."""
84+
return self.handler(site, lang, post, data, displayMode='true', **options)

‎v7/localkatex/package-lock.json

+19
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎v7/localkatex/package.json

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"dependencies": "katex"
3+
}

0 commit comments

Comments
 (0)
Please sign in to comment.