chiark / gitweb /
m.math: ability of fallback to rendering math as code blocks.
authorVladimír Vondruš <mosra@centrum.cz>
Mon, 22 Jan 2018 13:13:28 +0000 (14:13 +0100)
committerVladimír Vondruš <mosra@centrum.cz>
Mon, 22 Jan 2018 13:17:29 +0000 (14:17 +0100)
doc/plugins/math-and-code.rst
pelican-plugins/m/math.py
pelican-plugins/m/test/math/page-code-fallback.html [new file with mode: 0644]
pelican-plugins/m/test/test_math.py

index 1a4f47394384b026e60a01f3b62270273359956e..36f7da029c3c66589e437172e52845e25f087eb7 100644 (file)
@@ -146,6 +146,23 @@ want to add additional CSS classes, derive a custom role from it.
     Quaternion-conjugated dual quaternion is :math-info:`\hat q^* = q_0^* + q_\epsilon^*`,
     while dual-conjugation gives :math:`\overline{\hat q} = q_0 - \epsilon q_\epsilon`.
 
+.. note-info::
+
+    LaTeX can be sometimes a real pain to set up. In order to make it possible
+    to work on sites that use the :py:`m.math` plugin on machines without LaTeX
+    installed, you can enable a fallback option to render all math as code
+    blocks using the :py:`M_MATH_RENDER_AS_CODE` setting. That can be, for
+    example, combined with a check for presence of the LaTeX binary:
+
+    .. code:: py
+
+        import shutil
+        import logging
+
+        if not shutil.which('latex'):
+            logging.warning("LaTeX not found, fallback to rendering math as code")
+            M_MATH_RENDER_AS_CODE = True
+
 `Code`_
 =======
 
index 41e0a8c9c9fd8aaafeb04c67ad21f9a8c4615545..5129206ec9ea6ebb0ac648270d949d82ba96b046 100644 (file)
@@ -24,7 +24,7 @@
 
 import re
 
-from docutils import nodes
+from docutils import nodes, utils
 from docutils.parsers import rst
 from docutils.parsers.rst import directives
 from docutils.parsers.rst.roles import set_classes
@@ -64,6 +64,8 @@ unique_dst = r"""\g<name>='\g<ref>eq{counter}-\g<id>'"""
 
 counter = 0
 
+render_as_code = False
+
 def _patch(formula, out, attribs):
     global counter
     counter += 1
@@ -77,6 +79,14 @@ class Math(rst.Directive):
     def run(self):
         set_classes(self.options)
         self.assert_has_content()
+
+        # Fallback rendering as code requested
+        if render_as_code:
+            content = nodes.raw('', '\n'.join(self.content), format='html')
+            pre = nodes.literal_block('')
+            pre.append(content)
+            return [pre]
+
         # join lines, separate blocks
         content = '\n'.join(self.content).split('\n\n')
         _nodes = []
@@ -104,6 +114,19 @@ def math(role, rawtext, text, lineno, inliner, options={}, content=[]):
     i = rawtext.find('`')
     text = rawtext.split('`')[1]
 
+    # Fallback rendering as code requested
+    if render_as_code:
+        set_classes(options)
+        classes = []
+        if 'classes' in options:
+            classes += options['classes']
+            del options['classes']
+
+        content = nodes.raw('', utils.unescape(text), format='html')
+        node = nodes.literal(rawtext, '', **options)
+        node.append(content)
+        return [node], []
+
     # Apply classes to the <svg> element instead of some outer <span>
     set_classes(options)
     classes = 'm-math'
@@ -121,7 +144,12 @@ def math(role, rawtext, text, lineno, inliner, options={}, content=[]):
     node = nodes.raw(rawtext, _patch(text, out, attribs), format='html', **options)
     return [node], []
 
+def configure_pelican(pelicanobj):
+    global render_as_code
+    render_as_code = pelicanobj.settings.get('M_MATH_RENDER_AS_CODE', False)
+
 def register():
+    pelican.signals.initialized.connect(configure_pelican)
     pelican.signals.content_object_init.connect(new_page)
     rst.directives.register_directive('math', Math)
     rst.roles.register_canonical_role('math', math)
diff --git a/pelican-plugins/m/test/math/page-code-fallback.html b/pelican-plugins/m/test/math/page-code-fallback.html
new file mode 100644 (file)
index 0000000..ba3df22
--- /dev/null
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8" />
+  <title>m.math | A Pelican Blog</title>
+  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i" />
+  <link rel="stylesheet" href="static/m-dark.css" />
+  <link rel="canonical" href="page.html" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+  <div class="m-container">
+    <div class="m-row">
+      <a href="./" id="m-navbar-brand" class="m-col-t-9 m-col-m-none m-left-m">A Pelican Blog</a>
+    </div>
+  </div>
+</nav></header>
+<main>
+<article>
+  <div class="m-container m-container-inflatable">
+    <div class="m-row">
+      <div class="m-col-l-10 m-push-l-1">
+        <h1>m.math</h1>
+<!-- content -->
+<p>Inline colored math <code>a^2</code> and colored math block:</p>
+<pre>a^2 + b^2 = c^2</pre>
+<p>Properly align <em>huge</em> formulas vertically on a line:
+<code>\hat q^{-1} = \frac{\hat q^*}{|\hat q|^2}</code>
+and make sure there's enough space for all the complex <code>W</code> things between
+the lines <code>W = \sum_{i=0}^{n} \frac{w_i}{h_i}</code> because
+<code>Y = \sum_{i=0}^{n} B</code></p>
+<p>The <code>\cfrac</code> thing doesn't align well: <code>W = \sum_{i=0}^{n} \cfrac{w_i}{h_i}</code></p>
+<!-- /content -->
+      </div>
+    </div>
+  </div>
+</article>
+</main>
+</body>
+</html>
+
index 735e15d012938932d9faf062d844a5b8c5e71066..8a9336856694ab1010cf3f1fd8de207eb138972e 100644 (file)
@@ -42,3 +42,11 @@ class Math(PluginTestCase):
         })
 
         self.assertEqual(*self.actual_expected_contents('page.html'))
+
+    def test_code_fallback(self):
+        self.run_pelican({
+            'PLUGINS': ['m.htmlsanity', 'm.math'],
+            'M_MATH_RENDER_AS_CODE': True
+        })
+
+        self.assertEqual(*self.actual_expected_contents('page.html', 'page-code-fallback.html'))