Skip to content

Instantly share code, notes, and snippets.

@waylan
Created February 22, 2012 16:59
Show Gist options
  • Save waylan/1886026 to your computer and use it in GitHub Desktop.
Save waylan/1886026 to your computer and use it in GitHub Desktop.
Math extension for Python-Markdown
#!/usr/bin/env python
"""
Math extension for Python-Markdown
Copied from http://freewisdom.org/projects/python-markdown/mdx_math for preservation.
The following description was attached by the author:
> This is a quick and dirty implementation of allowing <math> LaTeX </math> to do
> formulae in Markdown. We'll call this page right here the "official site" for this
> extension I think.
>
> It requires "latex" and "dvipng". I use MiKTeX on Win32 in particular, but I'm sure
> other types of them would work fine.
>
> Finally, I've never written any Python before so please feel free to tidy/fix.
>
> -- Scott http://h4ck3r.net
"""
import markdown
import os
import re
import md5
BEFORE_TEX = """\\documentclass[12pt]{article}
\\usepackage[latin1]{inputenc}
\\usepackage{amsmath}
\\usepackage{amsfonts}
\\usepackage{amssymb}
\\pagestyle{empty}
\\begin{document}
$"""
AFTER_TEX = """$
\\end{document}
"""
BLACKLIST = [
"include",
"def",
"command",
"loop",
"repeat",
"open",
"toks",
"output",
"input",
"catcode",
"name",
"^^",
"\\every",
"\\errhelp",
"\\errorstopmode",
"\\scrollmode",
"\\nonstopmode",
"\\batchmode",
"\\read",
"\\write",
"csname",
"\\newhelp",
"\\uppercase",
"\\lowercase",
"\\relax",
"\\aftergroup",
"\\afterassignment",
"\\expandafter",
"\\noexpand",
"\\special"
]
class MathPattern(markdown.Pattern):
def __init__ (self, md):
markdown.Pattern.__init__(self, r'(<|<)math>(.*)(<|<)/math>')
self.md = md
def getFnFromCode(self, code):
hash = md5.new(code).hexdigest()
matches = re.match("(.)(.)(.)(.*)", hash)
dirs = "static\\images\\" + matches.group(1) + "\\" + matches.group(2) + "\\" + matches.group(3) + "\\"
file = dirs + hash
png = file + ".png"
tex = file + ".tex"
dvi = file + ".dvi"
aux = file + ".aux"
log = file + ".log"
return (dirs, png, tex, dvi, aux, log)
def handleMatch(self, m, doc):
code = m.group(3).strip()
code = code.replace("<", "<")
code = code.replace(">", ">")
(dirsb, pngb, texb, dvib, auxb, logb) = self.getFnFromCode(code)
pngf = pngb.replace("\\", "/")
def done(fn):
img = doc.createElement('img')
img.setAttribute("src", "/" + fn)
img.setAttribute("alt", code)
return img
def error():
err = doc.createElement("font")
err.setAttribute("color", "red")
err.appendChild(doc.createTextNode("error rendering: " + code))
return err
if os.path.exists(pngb): return done(pngf)
def checker(x,y):
if not x: return False
return code.find(y) == -1
if not reduce(checker, BLACKLIST, True):
return error()
if not os.path.exists(dirsb): os.makedirs(dirsb)
f = open(texb, "w")
f.writelines([BEFORE_TEX, code, AFTER_TEX])
f.close()
if os.system("latex -quiet -interaction=batchmode -output-directory=" + dirsb + " -aux-directory=" + dirsb + " " + texb) != 0: return error()
if os.system("dvipng -D 150 -o " + pngb + " -T tight " + dvib) != 0: return error()
os.remove(texb)
os.remove(auxb)
os.remove(dvib)
os.remove(logb)
return done(pngf)
class MathExtension(markdown.Extension):
def extendMarkdown(self, md, md_globals):
md.inlinePatterns.insert(0, MathPattern(md))
def makeExtension(configs):
return MathExtension(configs)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment