Skip to content

Instantly share code, notes, and snippets.

@tylerneylon
Last active September 12, 2021 00:30
Show Gist options
  • Save tylerneylon/6ebf0bbbce622975745c to your computer and use it in GitHub Desktop.
Save tylerneylon/6ebf0bbbce622975745c to your computer and use it in GitHub Desktop.
Convert markdown to LaTeX
#!/usr/local/bin/python3
#
# Usage:
# md_to_tex.py <md_filename> > myfile.tex
#
# Converts simple markdown to a LaTeX file.
# Use, for example, "pdflatex myfile.tex" to
# generate a pdf file using your output file.
#
# The current script does *not* parse all
# markdown syntax; only a subset so far.
#
import os
import re
import sys
tex_start = r"""
\documentclass[11pt,oneside]{amsart}
\usepackage{geometry}
\geometry{letterpaper}
%\usepackage[parfill]{parskip} % Activate to begin paragraphs with an empty line rather than an indent
\usepackage{graphicx}
\usepackage{amssymb}
\usepackage{epstopdf}
\DeclareGraphicsRule{.tif}{png}{.png}{`convert #1 `dirname #1`/`basename #1 .tif`.png}
\begin{document}
"""
tex_end = r"\end{document}"
indents = []
is_in_quote = False
def repl_quote(quote_match):
global is_in_quote
repl = r"''" if is_in_quote else r'``'
is_in_quote = not is_in_quote
return repl
# Accepts indent=-1 to indicate that
# the current list has ended completely.
def move_to_indent(indent):
global indents
if indent >= 0 and (len(indents) == 0 or indents[-1] < indent):
indents.append(indent)
print(r'\begin{itemize}')
return
while len(indents) > 0 and indents[-1] > indent:
indents.pop()
print(r'\end{itemize}')
def handle_line(line):
global indents
line = line.rstrip()
always_subs = [[r'\*\*(\S.*?)\*\*', r'{\\bf \1}'],
[r'\*(\S.*?)\*', r'{\\it \1}'],
[r'^---\s*$', r'\\hrule' ],
[r'"', repl_quote ]]
for s in always_subs: line = re.sub(s[0], s[1], line)
m = re.search(r'^( *)\* (.*)', line)
if m:
move_to_indent(len(m.group(1)))
line = r'\item ' + m.group(2)
else:
indent = -1
if re.search(r'^( +)\S', line) and len(indents): indent = indents[-1]
move_to_indent(indent)
normal_subs = [[r'^# (.*)', r'\\rightline{\\Large \1}'],
[r'^## (.*)', r'\\section{\1}' ],
[r'^### (.*)', r'\\subsection{\1}' ],
[r'^#### (.*)', r'\\subsubsection{\1}' ],
[r'^#####+ (.*)', r'{\\bf \1}' ]]
for s in normal_subs: line = re.sub(s[0], s[1], line)
print(line)
if __name__ == '__main__':
if len(sys.argv) < 2:
print('Usage: %s <md_filename>' % os.path.basename(sys.argv[0]))
print('Output is sent to stdout.')
exit(2)
print(tex_start)
with open(sys.argv[1]) as f:
for line in f:
handle_line(line)
print(tex_end)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment