From b293684fb79123b56b107c3091739ebffc1f7c37 Mon Sep 17 00:00:00 2001 From: Amy Gale Ruth Bowersox Date: Tue, 30 Jul 2024 21:32:06 -0600 Subject: [PATCH] added the basic template rendering loop at the end --- .gitignore | 2 ++ doc/configuration.yaml | 6 ++++++ src/dragonglass/config.py | 13 ++++++++++++- src/dragonglass/dragonglass.py | 18 ++++++++++++++++++ src/dragonglass/template.py | 28 ++++++++++++++++++++++++++++ src/dragonglass/tree.py | 12 ++++++++++++ 6 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 doc/configuration.yaml create mode 100644 src/dragonglass/template.py diff --git a/.gitignore b/.gitignore index 5d381cc..3f3c986 100644 --- a/.gitignore +++ b/.gitignore @@ -160,3 +160,5 @@ cython_debug/ # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ +# Test directory +blort/ diff --git a/doc/configuration.yaml b/doc/configuration.yaml new file mode 100644 index 0000000..6298e95 --- /dev/null +++ b/doc/configuration.yaml @@ -0,0 +1,6 @@ +# The prefix to apply to all internally-generated URLs. Default is "/". +url_prefix: / +# The template directory name under the Obsidian vault. Default is ".dragonglass.tmpl". +template_directory: .dragonglass.tmpl +# The default template name. Default is "default.html". +default_template: default.html diff --git a/src/dragonglass/config.py b/src/dragonglass/config.py index bab0e1a..49c46df 100644 --- a/src/dragonglass/config.py +++ b/src/dragonglass/config.py @@ -9,12 +9,18 @@ import yaml from .tree import SourceIndex, SourceNode +DEFAULT_TEMPLATE_DIRECTORY = ".dragonglass.tmpl" +DEFAULT_TEMPLATE_NAME = "default.html" + + class Context: def __init__(self) -> None: self.source_dir: Path | None = None + self.template_dir: Path | None = None self.config: dict[str, Any] = {} self.src_index: SourceIndex | None = None self.current_node: SourceNode | None = None + self._default_template_name: str | None = None def load_config(self, args: Namespace) -> None: config_filename: str = str(args.config) if args.config else ".dragonglass" @@ -23,10 +29,15 @@ class Context: if config_path.exists() and config_path.is_file(): with open(config_path, "r") as f: self.config = yaml.full_load(f) + self.template_dir = self.source_dir / self.config.get("template_directory", DEFAULT_TEMPLATE_DIRECTORY) + self._default_template_name = self.config.get("default_template", DEFAULT_TEMPLATE_NAME) @property def url_prefix(self) -> str: rc = self.config.get("url_prefix", "/") return rc if rc.endswith("/") else rc + '/' - + def get_template_name_for_node(self, node: SourceNode) -> str: + if not self.template_dir.is_dir(): + return DEFAULT_TEMPLATE_NAME + return self._default_template_name diff --git a/src/dragonglass/dragonglass.py b/src/dragonglass/dragonglass.py index 610a049..6c1b8dc 100644 --- a/src/dragonglass/dragonglass.py +++ b/src/dragonglass/dragonglass.py @@ -1,10 +1,12 @@ #!/usr/bin/env python3 import argparse +import shutil from pathlib import Path from .config import Context from .mparse import create_markdown_parser +from .template import create_template_environment from .tree import SourceIndex, generate_list # The command line parser @@ -29,6 +31,7 @@ def main() -> int: return 1 context.load_config(args) + tenv = create_template_environment(context) nodes = generate_list(context.source_dir) for node in nodes: @@ -52,4 +55,19 @@ def main() -> int: print(node.text) print("------ END TEXT ------") + if not dest_dir.exists(): + dest_dir.mkdir() + + for node in nodes: + p = node.target_file(dest_dir) + if node.is_dir: + p.mkdir(exist_ok=True) + elif node.is_md: + tmpl = tenv.get_template(context.get_template_name_for_node(node)) + data = tmpl.render(node.make_vars()) + with p.open("wt") as f: + f.write(data) + else: + shutil.copyfile(context.source_dir / node.path, p) + return 0 diff --git a/src/dragonglass/template.py b/src/dragonglass/template.py new file mode 100644 index 0000000..83a65b3 --- /dev/null +++ b/src/dragonglass/template.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 + +from jinja2 import Environment, BaseLoader, ChoiceLoader, FunctionLoader, FileSystemLoader + +from .config import Context, DEFAULT_TEMPLATE_NAME + +DEFAULT_TEMPLATE = """ + + + {{ title }} + + +

{{ title }}

+ {{ text }} + + +""" + + +def _create_loader(ctxt: Context) -> BaseLoader: + return ChoiceLoader([ + FileSystemLoader(ctxt.template_dir), + FunctionLoader(lambda n: DEFAULT_TEMPLATE if n == DEFAULT_TEMPLATE_NAME else None) + ]) + + +def create_template_environment(ctxt: Context) -> Environment: + return Environment(loader=_create_loader(ctxt)) diff --git a/src/dragonglass/tree.py b/src/dragonglass/tree.py index a01852e..28b6087 100644 --- a/src/dragonglass/tree.py +++ b/src/dragonglass/tree.py @@ -40,6 +40,12 @@ class SourceNode: def path(self) -> Path: return self._path + def target_file(self, dest_dir: Path) -> Path: + p = self._path + if self._is_md: + p = p.with_suffix('.html') + return dest_dir / p + def link_target(self, prefix: str = "/") -> str: xpath = self._path.with_suffix('.html') if self._is_md else self._path return urlquote(prefix + xpath.as_posix()) @@ -62,6 +68,12 @@ class SourceNode: with open(source_dir / self._path, "r", encoding="utf-8") as f: self.text = markdown_parser.convert(f.read()) + def make_vars(self) -> dict[str, Any]: + return { + "text": self.text, + "title": self._path.stem + } + def generate_list(source_root: Path) -> list[SourceNode]: nodes: list[SourceNode] = []