1. Dietmar Winkler
  2. TracMathJaxPlugin


TracMathJaxPlugin / tracmathjax / tracmathjax.py

from trac.core import Component, implements
from trac.web.api import IRequestFilter
from trac.web.chrome import ITemplateProvider, add_script
from trac.wiki.api import IWikiSyntaxProvider, IWikiMacroProvider
import os.path

"""Renders a LaTeX using MathJax.

\left( \sum_{k=1}^n a_k b_k \\right)^{\!\!2} \leq
\left( \sum_{k=1}^n a_k^2 \\right) \left( \sum_{k=1}^n b_k^2 \\right)

results in output like:
\left( \sum_{k=1}^n a_k b_k \\right)^{\!\!2} \leq
\left( \sum_{k=1}^n a_k^2 \\right) \left( \sum_{k=1}^n b_k^2 \\right)

MATHJAX_JS = "MathJax.js"

WIKI_RE = r"(?P<mathjax_inline>\\\(.*?\\\)|\$\$.*?\$\$)"

class TracMathJax(Component):

    def __init__(self):
        self.mathjax_path = os.path.abspath(self.config.get('tracmathjax', 'mathjax_path'))
        self.log.debug("MathJax path: %s" % self.mathjax_path)
        if not os.path.exists(os.path.join(self.mathjax_path, MATHJAX_JS)):
            self.log.error("Could not find a MathJax install at %s" % self.mathjax_path)

    # ITemplateProvider methods
    def get_htdocs_dirs(self):
        return [(MATHJAX_DIR, self.mathjax_path)]

    def get_templates_dirs(self):
        # we have no templates
        return []

    # IRequestFilter methods
    def pre_process_request(self, req, handler):
        return handler

    def post_process_request(self, req, template, data, content_type):
        add_script(req, "/chrome/%s/%s" % (MATHJAX_DIR, MATHJAX_JS))
        return template, data, content_type

    # IWikiSyntaxProvider methods
    def get_wiki_syntax(self):
        # Capture text in between MathJax delimiters to keep other wiki syntax
        # from being applied.
        yield (WIKI_RE, self._render_inline)

    def get_link_resolvers(self):
        # we have no link resolvers
        return []

    # IWikiMacroProvider methods
    def get_macros(self):
        return ('latex', 'Latex', 'LaTeX')

    def get_macro_description(self, name):
        return MACRO_DESCRIPTION

    def expand_macro(self, formatter, name, content):
        if name.lower() == "latex":
            return "<p>\\[\n%s\n\\]</p>" % content

    def _render_inline(self, formatter, ns, match):
        """Inline rendering function."""
        return match.group("mathjax_inline")