├── LICENSE.txt
├── tests
├── simple.markdown
├── text.markdown
├── error.markdown
├── nested.markdown
├── markdown-latex.cfg
├── preamble.markdown
└── math.markdown
├── tests2
├── markdown-latex.cfg
└── simple.markdown
├── README.markdown
└── latex.py
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | http://creativecommons.org/publicdomain/mark/1.0/
2 |
--------------------------------------------------------------------------------
/tests/simple.markdown:
--------------------------------------------------------------------------------
1 | This is a simple test: $y = mx + b$. This should all be inlined.
2 |
--------------------------------------------------------------------------------
/tests/text.markdown:
--------------------------------------------------------------------------------
1 | To which he said, %``My name is Justin Bruce Van Horne"% and I replied "Nay.".
2 |
3 |
--------------------------------------------------------------------------------
/tests/error.markdown:
--------------------------------------------------------------------------------
1 | This page should generate an error. The output should be logged to a temporary file.
2 | $\undefinederror$
3 |
--------------------------------------------------------------------------------
/tests/nested.markdown:
--------------------------------------------------------------------------------
1 | %This should be an image% But this should not be %But this should be%
2 | \$9.99 is not an image, but $\$9.99$ is. Likewise, 6 \% 4 is not the same as %6 \% 4%.
3 |
--------------------------------------------------------------------------------
/tests/markdown-latex.cfg:
--------------------------------------------------------------------------------
1 | # This configuration file is parsed by python's ConfigParser and therefore
2 | # follows RFC 822.
3 |
4 | [dvipng]
5 | # The following arguments are passed to dvipng.
6 | args = -q -T tight -bg Transparent -z 9 -D 106
7 |
--------------------------------------------------------------------------------
/tests/preamble.markdown:
--------------------------------------------------------------------------------
1 |
2 |
3 | %%
4 | \definecolor{jvh}{rgb}{0.411, 0.407, 0.196}
5 | \pagecolor{jvh}
6 | \color{White}
7 | %%
8 |
9 | Oh, such strange color. Yet, %it does seem to look right!%
10 | $\displaystyle \sigma$!
11 |
--------------------------------------------------------------------------------
/tests/math.markdown:
--------------------------------------------------------------------------------
1 | %We could also consider situations such as:%
2 |
3 |
4 | $
5 | \begin{tabular}{|c|c|c|c|}
6 | Name & Age & Degree & Happy \\
7 | \hline \\
8 | Justin & 21 & Electrical Engineering & Yes \\
9 | Miuche & 39 & None & No \\
10 | \hline \\
11 | \end{tabular}
12 | $
13 |
14 |
15 | - Or even: $y = mx + b$
16 | - Or even: $e^{\imath x} = \cos{x} + \imath\sin{x}$
17 |
--------------------------------------------------------------------------------
/tests2/markdown-latex.cfg:
--------------------------------------------------------------------------------
1 | # This configuration file is parsed by python's ConfigParser and therefore
2 | # follows RFC 822.
3 |
4 | [general]
5 | preamble : \usepackage[sc]{mathpazo}
6 | \usepackage{tgpagella}
7 |
8 | [dvipng]
9 | # The following arguments are passed to dvipng.
10 | args = -q -T tight -bg Transparent -z 9 -D 106
11 |
12 | [delimiters]
13 | text = %%
14 | math = $$
15 | preamble = %%%
16 |
--------------------------------------------------------------------------------
/tests2/simple.markdown:
--------------------------------------------------------------------------------
1 | This examples illustrates using delimiters \$$, \%%, and %\%%
2 | --------
3 |
4 | This is math: $$\int_0^\infty e^{-x} \; d x = 1$$
5 | This is text: %%\LaTeX\ rocks, even in markdown with the latex plugin.%%
6 |
7 | %%%
8 | \usepackage[usenames]{xcolor}
9 | \color{red}
10 | %%%
11 |
12 | This is not latex text: \%% foo \%%
13 | This is not latex math: \$$ i^2 = -1 \$$
14 | This is a backslash with delimiters: \\\%%, \\%\%%, \\$$
15 | And again: \\\%%, \\%\%%, \\$$
16 |
17 |
--------------------------------------------------------------------------------
/README.markdown:
--------------------------------------------------------------------------------
1 | # Markdown-LaTeX
2 | This [Markdown](http://daringfireball.net/projects/markdown/) extension adds support for inline LaTeX expressions without the need for external images.
3 | The available modes are %TEXT%, $MATH$, and %%PREAMBLE%%.
4 |
5 | ## Modes
6 | Markdown-LaTeX can technically allow for any sort of LaTeX expression, but there are three main modes that make writing everything much easier.
7 |
8 | ### %TEXT% mode
9 | The most basic of the modes is %TEXT% mode. Any expression within %TEXT% will be parsed in a basic LaTeX text-mode, e.g. plain. For example, %``Justin Bruce Van Horne''%.
10 |
11 | ### $MATH$ mode
12 | Math mode is our second basic functionality of Markdown-LaTeX. It automatically puts LaTeX into math mode and allows for inline and multiline expressions. Let's say that we wanted to write [Euler's formula](http://en.wikipedia.org/wiki/Euler's_formula): We would then write $e^{\imath x} = \cos{x} + \imath\sin{x}$.
13 |
14 | ### %%PREAMBLE%% mode
15 | Preamble mode is the only "complex" mode. It allows you to add to the preamble of the LaTeX template. So, if there are specific packages or commands you want for the HTML page, then this is where to do it. This is a global modifier and will affect the entire document. I haven't come up with an intuitive design for a per-expression basis.
16 |
17 | ## Dependencies
18 | Markdown-LaTeX depends on:
19 |
20 | - [LaTeX](http://www.latex-project.org/)
21 | - [dvipng](http://sourceforge.net/projects/dvipng/)
22 | - [Python Markdown](http://www.freewisdom.org/projects/python-markdown/)
23 |
24 | ## Installation
25 | You can either copy it into the extensions sub-directory in your markdown folder (ex: /usr/lib/python2.7/site-packages/markdown/extensions/latex.py) or use it locally with the mdx_ prefix. See [Markdown Extensions](http://www.freewisdom.org/projects/python-markdown/Writing_Extensions) for more details.
26 |
27 | ## Usage
28 | markdown -x latex somefile.markdown > somefile.html
29 |
30 | ## Configuration
31 |
32 | This plugin uses dvipng in order to produce the output images. The arguments
33 | passed to dvipng are configurable, see tests/markdown-latex.cfg for an example.
34 | In particular, you may want to adapt the argument passed to the -D option in
35 | order to change output resolution resp. font size.
36 |
37 | You may also change the delimiters used for text, math and preamble mode within
38 | the configuration file, see tests2/markdown-latex.cfg. When running this plugin
39 | on existing text you need to escape all occurrences of % and $. Changing
40 | delimiters may reduce this effort.
41 |
42 |
43 | ----
44 |
45 | ## How does it work?
46 | The LaTeX extension will search for either $text$ or %text% expressions. For each expression, it generates a tex file that is parsed by latex and then run through dvipng. The data is encoded via base64 and then inlined. A cache file (latex.cache) is used to store all expressions and their base64 counterparts. This is to prevent latex from being run each time.
47 |
48 | ----
49 |
50 | ## Suggestions/Improvements:
51 | - [Geremy Condra](https://github.com/debatem1)
52 | - [Jabba Laci](https://github.com/jabbalaci)
53 | - [Stefan Huber](https://github.com/shuber2)
54 |
--------------------------------------------------------------------------------
/latex.py:
--------------------------------------------------------------------------------
1 | """
2 | Licensed under Public Domain Mark 1.0.
3 | See http://creativecommons.org/publicdomain/mark/1.0/
4 | Author: Justin Bruce Van Horne
5 | """
6 |
7 |
8 | """
9 | Python-Markdown LaTeX Extension
10 |
11 | Adds support for $math mode$ and %text mode%. This plugin supports
12 | multiline equations/text.
13 |
14 | The actual image generation is done via LaTeX/DVI output.
15 | It encodes data as base64 so there is no need for images directly.
16 | All the work is done in the preprocessor.
17 | """
18 |
19 | from sys import version
20 | import re
21 | import os
22 | import string
23 | import base64
24 | import tempfile
25 | import markdown
26 |
27 |
28 | from subprocess import call as rawcall, PIPE
29 |
30 |
31 |
32 | # Proxies to existing functions for conserving compatibility between
33 | # Python2 and Python3
34 | def isalnum(expr):
35 | '''Proxy to expr.isalnum() that can be used by filter()'''
36 | return expr.isalnum()
37 |
38 | def call(*args, **kwargs):
39 | '''
40 | Proxy to subprocess.call(), removes timeout argument in case of
41 | Python2 because that was only implemented in Python3.
42 | '''
43 | if 'timeout' in kwargs and version[0] == '2':
44 | del kwargs['timeout']
45 | rawcall(*args, **kwargs)
46 |
47 |
48 |
49 | # Defines our basic inline image
50 | IMG_EXPR = "
"
52 |
53 |
54 | # Base CSS template
55 | IMG_CSS = \
56 | "\n"
57 |
58 |
59 | # Cache and temp file paths
60 | _TEMPDIR = tempfile.gettempdir() + '/markdown-latex'
61 | _CACHEFILE = _TEMPDIR + '/latex.cache'
62 |
63 | class LaTeXPreprocessor(markdown.preprocessors.Preprocessor):
64 | # These are our cached expressions that are stored in latex.cache
65 | cached = {}
66 |
67 | # Basic LaTex Setup as well as our list of expressions to parse
68 | tex_preamble = r"""\documentclass{article}
69 | \usepackage{amsmath}
70 | \usepackage{amsthm}
71 | \usepackage{amssymb}
72 | \usepackage{bm}
73 | \usepackage[usenames,dvipsnames]{color}
74 | \pagestyle{empty}
75 | """
76 |
77 | def __init__(self, configs):
78 | if not os.path.isdir(_TEMPDIR):
79 | os.makedirs(_TEMPDIR)
80 | try:
81 | cache_file = open(_CACHEFILE, 'r+')
82 | for line in cache_file.readlines():
83 | key, val = line.strip("\n").split(" ")
84 | self.cached[key] = val
85 | except IOError:
86 | pass
87 |
88 | self.config = {
89 | ("general", "preamble"): "",
90 | ("dvipng", "args"): "-q -T tight -bg Transparent -z 9 -D 106",
91 | ("delimiters", "text"): "%",
92 | ("delimiters", "math"): "$",
93 | ("delimiters", "preamble"): "%%" }
94 |
95 | try:
96 | # ConfigParser was renamed to configparser in Python3.
97 | # Import it in a way that works across versions,
98 | # using the Python3 naming convention in the rest of the code.
99 | try:
100 | import configparser
101 | except ImportError:
102 | import ConfigParser as configparser
103 | cfgfile = configparser.RawConfigParser()
104 | cfgfile.read('markdown-latex.cfg')
105 |
106 | for sec in cfgfile.sections():
107 | for opt in cfgfile.options(sec):
108 | self.config[(sec, opt)] = cfgfile.get(sec, opt)
109 | except configparser.NoSectionError:
110 | pass
111 |
112 | def build_regexp(delim):
113 | delim = re.escape(delim)
114 | regexp = r'(?html_block")
262 | # Our cleanup postprocessing extension
263 | md.postprocessors.add('latex',
264 | LaTeXPostprocessor(self), ">amp_substitute")
265 |
266 |
267 | def makeExtension(*args, **kwargs):
268 | """Wrapper for a MarkDown extension"""
269 | return MarkdownLatex(*args, **kwargs)
270 |
--------------------------------------------------------------------------------