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`_
=======
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
counter = 0
+render_as_code = False
+
def _patch(formula, out, attribs):
global counter
counter += 1
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 = []
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'
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)
--- /dev/null
+<!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>
+
})
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'))