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
        
MACRO_DESCRIPTION = \
"""Renders a LaTeX using MathJax.

Usage:
{{{
{{{
#!latex
\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:
{{{
#!latex
\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_DIR = "MathJax"
MATHJAX_JS = "MathJax.js"

class TracMathJax(Component):
    implements(ITemplateProvider, 
               IRequestFilter, 
               IWikiSyntaxProvider,
               IWikiMacroProvider)

    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 (r"(?P<mathjax_inline>\\(.*?\\)|\$\$.*?\$\$)", 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")
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.