diff --git a/README.md b/README.md index fc9579f..563be0e 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ -# PreTex +# PreTeX -Simple tex jinja2 Precompiler \ No newline at end of file +Use `pretex -h` for help. + +## Installation + +`pip install git+` diff --git a/bin/pretex b/bin/pretex new file mode 100755 index 0000000..07924d6 --- /dev/null +++ b/bin/pretex @@ -0,0 +1,139 @@ +#!/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 [] --data= [options] + +Arguments: + 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= Save output to file. + -d --data= YAML files with data for the template. + -t --tex= LaTeX compiler to use [default: pdflatex] + -a --arg= LaTeX compiler arguments + [default: -synctex=1 -interaction=nonstopmode -file-line-error] + -b --bib= bibTeX compiler to use. [default: bibtex] + -c --copy= Gather copies of all resulting pdf files in a folder. + --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= Files to clean. + [default: *.aux, *.bbl, *.blg, *.idx, *.ind, *.lof, *.lot, *.out, *.toc, *.acn, *.acr, *.alg, *.glg, *.glo, *.gls, *.ist, *.fls, *.log, *.fdb_latexmk, *.synctex.gz] +""" + +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]): + subprocess.call(shlex.split(command), cwd=path, 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(tex_file) + rendered = template.render(**data) + if file is None: + return rendered + f = open(file, 'w') + f.write(rendered) + f.close() + return f'"{tex_file}" successful rendered into "{file}"' + + +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 + + with open(arguments['--data']) as file: + data = yaml.load(file, Loader=yaml.FullLoader)["data"] + + cmd = functools.partial(get_latex_toolchain, arguments) + compile_all(data, arguments[''], arguments['--pdf'], cmd, arguments['--copy'], arguments['--clean'] and arguments['--files']) diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..f91d24f --- /dev/null +++ b/setup.py @@ -0,0 +1,18 @@ +import setuptools + +with open("README.md", "r") as fh: + long_description = fh.read() + +setuptools.setup( + name="PreTeX", # Replace with your own username + version="0.1", + scripts=["bin/pretex"], + author="Ugo Finnendahl", + author_email="ugo.finnendahl@tu-berlin.de", + description="A jinja2 based TeX precompiler", + long_description=long_description, + long_description_content_type="text/markdown", + url="", + packages=setuptools.find_packages(), + install_requires=['PyYAML','Jinja2', 'docopt', 'dateparser'], +)