blob: 57a6cf043da2ab31414415c9e0a69180b850f510 [file] [log] [blame] [edit]
from sphinx.directives.patches import MathDirective
from sphinx.util.texescape import tex_replace_map
from sphinx.writers.html5 import HTML5Translator
from sphinx.writers.latex import LaTeXTranslator
from docutils import nodes
from docutils.nodes import math
from docutils.parsers.rst.directives.misc import Replace
from six import text_type
import re
# Transform \xref in math nodes
xref_re = re.compile('\\\\xref\{([^}]*)\}\{([^}]*)\}', re.M)
def html_hyperlink(file, id):
if "/" in file:
return '\\href{../../core/%s.html#%s}' % (file, id.replace('_', '-'))
else:
return '\\href{%s.html#%s}' % (file, id.replace('_', '-'))
def html_transform_math_xref(node):
new_text = xref_re.sub(lambda m: html_hyperlink(m.group(1), m.group(2)), node.astext())
node.children[0] = nodes.Text(new_text)
# Mirrors sphinx/writers/latex
def latex_hyperlink(file, id):
id = text_type(id).translate(tex_replace_map).\
encode('ascii', 'backslashreplace').decode('ascii').\
replace('_', '-').replace('\\', '_')
if "/" in file:
return '\\hyperref[Core-%s:%s]' % (file, id)
else:
return '\\hyperref[%s:%s]' % (file, id)
def latex_transform_math_xref(node):
new_text = xref_re.sub(lambda m: latex_hyperlink(m.group(1), m.group(2)), node.astext())
node.children[0] = nodes.Text(new_text)
# Expand mathdef names in math roles and directives
def_re = re.compile('\\\\[A-Za-z][0-9A-Za-z]*', re.M)
auxcounter = 0
def lookup_mathdef(defs, name):
if name in defs:
[arity, s] = defs[name]
if arity > 0:
global auxcounter
auxcounter = auxcounter + 1
name = "\\mathdef%d" % auxcounter
s = "\\def%s#%d{%s}%s" % (name, arity, s, name)
return s
return name
def replace_mathdefs(doc, s):
if not hasattr(doc, 'mathdefs'):
return s
return def_re.sub(lambda m: lookup_mathdef(doc.mathdefs, m.group(0)), s)
def ext_math_role(role, raw, text, line, inliner, options = {}, content = []):
text = replace_mathdefs(inliner.document, raw.split('`')[1])
return [math(raw, text)], []
class ExtMathDirective(MathDirective):
def run(self):
doc = self.state.document
for i, s in enumerate(self.content):
self.content[i] = replace_mathdefs(doc, s)
for i, s in enumerate(self.arguments):
self.arguments[i] = replace_mathdefs(doc, s)
return super().run()
class MathdefDirective(Replace):
def run(self):
name = '\\' + self.state.parent.rawsource.split('|')[1]
name = name.split('#')
if len(name) > 1:
arity = int(name[1])
else:
arity = 0
name = name[0]
doc = self.state.document
if not hasattr(doc, 'mathdefs'):
doc.mathdefs = {}
# TODO: we don't ever hit the case where len(self.content) > 1
for i, s in enumerate(self.content):
self.content[i] = replace_mathdefs(doc, s)
doc.mathdefs[name] = [arity, ''.join(self.content)]
self.content[0] = ':math:`' + self.content[0]
self.content[-1] = self.content[-1] + '`'
return super().run()
class WebAssemblyHTML5Translator(HTML5Translator):
"""
Customize HTML5Translator.
Convert xref in math and math block nodes to hrefs.
"""
def visit_math(self, node, math_env = ''):
html_transform_math_xref(node)
super().visit_math(node, math_env)
def visit_math_block(self, node, math_env = ''):
html_transform_math_xref(node)
super().visit_math_block(node, math_env)
class WebAssemblyLaTeXTranslator(LaTeXTranslator):
"""
Customize LaTeXTranslator.
Convert xref in math and math block nodes to hyperrefs.
"""
def visit_math(self, node):
latex_transform_math_xref(node)
super().visit_math(node)
def visit_math_block(self, node):
latex_transform_math_xref(node)
super().visit_math_block(node)
# Setup
def setup(app):
app.set_translator('html', WebAssemblyHTML5Translator)
app.set_translator('latex', WebAssemblyLaTeXTranslator)
app.add_role('math', ext_math_role)
app.add_directive('math', ExtMathDirective, override = True)
app.add_directive('mathdef', MathdefDirective)