Simple tex jinja2 Precompiler
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
PreTex/bin/pretex

150 lines
5.3 KiB

#!/usr/bin/env python3
"""Simple tex jinja2 Precompiler.
With slightly different syntax:
{{ ... }} => \VAR{ ... } for Expressions to print to the template output
{% ... %} => \BLOCK{ ... } for Statements
{# ... #} => \#{ ... } for Comments not included in the template output
# ... ## => %$ ... %# for Line Statements
Usage:
pretex [<templates>] [options]
Arguments:
<templates> Compiles every given file ending with ".j2.tex" into
respective ".tex" file. [default: "**/*.j2.tex"]
Options:
-h --help Show this screen.
-p --pdf Also compiles rendered ".tex" file to pdf.
-o --out=<file> Save output to file.
-d --data=<yamlfile> YAML files with data for the template.
-t --tex=<compiler> LaTeX compiler to use [default: pdflatex]
-a --arg=<args> LaTeX compiler arguments
[default: -synctex=1 -interaction=nonstopmode -file-line-error]
-b --bib=<bib> bibTeX compiler to use. [default: bibtex]
-c --copy=<dir> Gather copies of all resulting pdf files in a folder.
--chain=<chain> Define the render command.
[default: {TEX} {ARG} {document}.tex, {BIB} {document}, {TEX} {ARG} {document}.tex, {TEX} {ARG} {document}.tex]
--clean Clean aux files.
-f --files=<end> Files to clean.
[default: *.aux, *.bbl, *.blg, *.idx, *.ind, *.lof, *.lot, *.out, *.toc, *.acn, *.acr, *.alg, *.glg, *.glo, *.gls, *.ist, *.fls, *.log, *.fdb_latexmk]
"""
import yaml
import glob
import jinja2
import os
from docopt import docopt
import dateparser
import datetime
import subprocess
import functools
import shlex
from shutil import copyfile
class RelEnvironment(jinja2.Environment):
"""Override join_path() to enable relative template paths."""
def join_path(self, template, parent):
return os.path.normpath(os.path.join(os.path.dirname(parent), template))
def datetime_filter(dt, format=None):
"""Jinja template filter to format a datetime object."""
if dt is None:
# By default, render an empty string.
return ''
if not isinstance(dt, datetime.datetime):
dt = dateparser.parse(dt, settings={'DATE_ORDER': 'DMY'})
if format is None:
# No format is given in the template call.
# Use a default format.
formatted_date = dt.strftime('%Y-%m-%d - %A')
formatted_time =\
dt.strftime('%I:%M%p').lstrip('0').lower()
formatted = '%s at %s' %\
(formatted_date, formatted_time)
else:
formatted = dt.strftime(format)
return formatted
def get_latex_toolchain(arguments, document):
return arguments["--chain"].format(
TEX=arguments["--tex"],
ARG=arguments["--arg"],
BIB=arguments["--bib"],
document=document).split(",")
def compile_all(data, templates, pdf, cmd, copy, clean):
if templates is None:
templates = "**/*.j2.tex"
for tex_file in glob.glob(templates, recursive=True):
if tex_file[-7:] == ".j2.tex":
compiled_file = f"{tex_file[:-7]}.tex"
print(compile_file(tex_file, data, compiled_file))
if not pdf:
continue
path, filename = os.path.split(compiled_file)
for command in cmd(filename[:-4]):
cwd = path
if cwd == '':
cwd = None
subprocess.call(shlex.split(command), cwd=cwd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
if copy:
if not os.path.exists(copy):
os.makedirs(copy)
copyfile(f"{tex_file[:-7]}.pdf", os.path.join(copy, f"{filename[:-4]}.pdf"))
if clean:
for ending in clean.split(","):
for file in glob.glob(os.path.join(path, ending.strip()), recursive=True):
os.remove(file)
def compile_file(tex_file, data, file=None):
template = latex_jinja_env.get_template(os.path.abspath(tex_file))
path, filename = os.path.split(tex_file)
rendered = template.render(**data, load_yaml=functools.partial(load_yaml, path=path))
if file is None:
return rendered
f = open(file, 'w')
f.write(rendered)
f.close()
return f'"{tex_file}" successful rendered into "{file}"'
def load_yaml(filename, path=""):
with open(os.path.join(path,filename)) as file:
data = yaml.load(file, Loader=yaml.FullLoader)
return data
if __name__ == '__main__':
arguments = docopt(__doc__)
latex_jinja_env = RelEnvironment(
block_start_string = '\\BLOCK{',
block_end_string = '}',
variable_start_string = '\\VAR{',
variable_end_string = '}',
comment_start_string = '\\#{',
comment_end_string = '}',
line_statement_prefix = '%§',
line_comment_prefix = '%#',
trim_blocks = True,
autoescape = False,
loader = jinja2.FileSystemLoader(os.path.abspath('/')),
)
latex_jinja_env.filters['datetime'] = datetime_filter
if arguments['--data']:
data = load_yaml(arguments["--data"])
else:
data = {}
cmd = functools.partial(get_latex_toolchain, arguments)
compile_all(data, arguments['<templates>'], arguments['--pdf'], cmd, arguments['--copy'], arguments['--clean'] and arguments['--files'])