From dab06e0debcb67b9ce166469360fbba5074caf9c Mon Sep 17 00:00:00 2001 From: Leonardo Uieda Date: Sun, 25 Sep 2022 12:17:15 +0100 Subject: [PATCH] Add a custom environment for LaTeX templates (#38) The default syntax doesn't work with latex because of all the curly braces in the language. Use an environment with custom syntax (`[# #]` for blocks and `[- -]` for variables) to get around that if the template is a latex file. Based on jtex by Curvenote (MIT license). --- nene/_api.py | 8 +++--- nene/rendering.py | 65 ++++++++++++++++++++++++++++++++++------------- 2 files changed, 51 insertions(+), 22 deletions(-) diff --git a/nene/_api.py b/nene/_api.py index 548122a..92dacf9 100644 --- a/nene/_api.py +++ b/nene/_api.py @@ -12,7 +12,7 @@ from .crawling import crawl from .parsing import load_config, load_data, load_jupyter_notebook, load_markdown from .printing import make_console, print_dict, print_file_stats -from .rendering import make_jinja_env, markdown_to_html, render_markdown, render_output +from .rendering import make_jinja_envs, markdown_to_html, render_markdown, render_output from .utils import capture_build_info @@ -173,12 +173,12 @@ def render(site, config, build, console=None, style=""): if console is None: console, style = make_console(verbose=False) - jinja_env = make_jinja_env(config["templates_dir"]) + jinja_envs = make_jinja_envs(config["templates_dir"]) console.print(":art: Rendering templates in Markdown content:", style=style) for page in site.values(): console.print(f" {page['source']}") - page["markdown"] = render_markdown(page, config, site, build, jinja_env) + page["markdown"] = render_markdown(page, config, site, build, jinja_envs) console.print(":art: Converting Markdown content to HTML:", style=style) for page in site.values(): @@ -189,7 +189,7 @@ def render(site, config, build, console=None, style=""): console.print(":art: Rendering templates for final outputs:", style=style) for page in site.values(): console.print(f" {page['path']} ← {page['template']}") - page["output"] = render_output(page, config, site, build, jinja_env) + page["output"] = render_output(page, config, site, build, jinja_envs) def export(site, files_to_copy, output_dir, console=None, style=""): diff --git a/nene/rendering.py b/nene/rendering.py index 48a011d..6339d75 100644 --- a/nene/rendering.py +++ b/nene/rendering.py @@ -2,15 +2,17 @@ # Distributed under the terms of the MIT License. # SPDX-License-Identifier: MIT """Render outputs with Jinja templates.""" +from pathlib import Path + import jinja2 import mdit_py_plugins.anchors import mdit_py_plugins.footnote from markdown_it import MarkdownIt -def make_jinja_env(templates_dir): +def make_jinja_envs(templates_dir): """ - Create the default Jinja environment given the template folder. + Create the default Jinja environments given the template folder. Parameters ---------- @@ -19,15 +21,40 @@ def make_jinja_env(templates_dir): Returns ------- - env : jinja2.Environment - The environment used to render the templates. + envs : dict + The keys are the file types supported as templates and values are the + corresponding environments used to render the templates for those file + types. """ - # Need to add the current dir so we can use the Markdown files as templates - env = jinja2.Environment( - loader=jinja2.FileSystemLoader([str(templates_dir), "."], followlinks=True), - extensions=["jinja2.ext.do", "jinja2.ext.loopcontrols"], - ) - return env + envs = { + "markdown": jinja2.Environment( + loader=jinja2.FileSystemLoader([str(templates_dir)], followlinks=True), + extensions=["jinja2.ext.do", "jinja2.ext.loopcontrols"], + ), + "html": jinja2.Environment( + loader=jinja2.FileSystemLoader([str(templates_dir)], followlinks=True), + extensions=["jinja2.ext.do", "jinja2.ext.loopcontrols"], + ), + "latex": jinja2.Environment( + loader=jinja2.FileSystemLoader([str(templates_dir)], followlinks=True), + extensions=["jinja2.ext.do", "jinja2.ext.loopcontrols"], + # Define custom syntax that is compatible with LaTeX + # Based on jtex by curvenote (MIT license): + # https://github.com/curvenote/jtex/blob/2778c9fc51cd2cbbe8d4b7deedd637e9dd59f662/jtex/TemplateRenderer.py#L36 + block_start_string=r"[#", + block_end_string="#]", + variable_start_string=r"[-", + variable_end_string="-]", + line_comment_prefix=r"%%", + comment_start_string=r"%#", + comment_end_string="#%", + trim_blocks=True, + autoescape=False, + auto_reload=True, + keep_trailing_newline=True, + ), + } + return envs def markdown_to_html(page): @@ -68,7 +95,7 @@ def _render_footnote_block_open(self, tokens, idx, options, env): return "\n".join(lines) -def render_markdown(page, config, site, build, jinja_env): +def render_markdown(page, config, site, build, jinja_envs): """ Render the templates in Markdown content of the page. @@ -83,20 +110,20 @@ def render_markdown(page, config, site, build, jinja_env): Dictionary with the entire site content so far. build : dict Dictionary with information about the build environment. - jinja_env - A Jinja2 environment for loading templates. + jinja_envs + A dictionary of Jinja2 environments for loading templates. Returns ------- markdown : str The rendered Markdown content for the page. """ - template = jinja_env.from_string(page["markdown"]) + template = jinja_envs["markdown"].from_string(page["markdown"]) markdown = template.render(page=page, config=config, site=site, build=build) return markdown -def render_output(page, config, site, build, jinja_env): +def render_output(page, config, site, build, jinja_envs): """ Render the full template output for a page. @@ -112,8 +139,8 @@ def render_output(page, config, site, build, jinja_env): Dictionary with the entire site content so far. build : dict Dictionary with information about the build environment. - jinja_env - A Jinja2 environment for loading templates. + jinja_envs + A dictionary of Jinja2 environments for loading templates. Returns ------- @@ -121,6 +148,8 @@ def render_output(page, config, site, build, jinja_env): The converted HTML. """ - template = jinja_env.get_template(page["template"]) + types = {".html": "html", ".tex": "latex"} + template_type = types[Path(page["template"]).suffix] + template = jinja_envs[template_type].get_template(page["template"]) html = template.render(page=page, config=config, site=site, build=build) return html