from pathlib import Path
from md import MDRenderer
-from template import Template
from utils import get_content, write_content
if output_path.exists():
shutil.rmtree(output_path)
output_path.mkdir(0o755)
- template = Template(source_path / "template.html")
+ template = get_content(source_path / "template.html")
context = {
- "nav-items": [
- {
- "link": "/",
- "text": "Home",
- },
- {
- "link": "/blog/",
- "text": "Blog",
- },
- {
- "link": "https://git.mar77i.info/",
- "text": "Git",
- },
- ]
+ "nav": MDRenderer(get_content(content_path / "nav.md")).render_html()[1],
}
context["title"], context["page"] = MDRenderer(
get_content(content_path / "index.md")
).render_html()
- write_content(output_path / "index.html", template.render(context))
+ write_content(output_path / "index.html", template.format(**context))
#context["blogs"] = []
#context["hashtags"] = []
blog_path = output_path / "blog"
blog_path.mkdir(0o755)
context["title"], context["page"] = "Blog stub", "<h2>Blog stub</h2>"
- write_content(blog_path / "index.html", template.render(context))
+ write_content(blog_path / "index.html", template.format(**context))
if __name__ == "__main__":
+++ /dev/null
-from collections.abc import Sequence
-
-from html import escape
-from io import StringIO
-
-from utils import find_or_end, get_content
-
-
-class Template:
- def __init__(self, path):
- self.path = path
- self.tokens = self.get_tokens(get_content(path))
-
- def get_tokens(self, content):
- """
- {{ -> literal {
- }} -> literal }
- {tag} -> html-escaped tag
- {tag|safe} -> unescaped tag
- """
- tokens = []
- tokens_stack = [(None, tokens)]
- current = tokens
- len_content = len(content)
- pos = 0
- while True:
- new_pos = min(find_or_end(content, c, pos) for c in ("{", "}"))
- if new_pos - pos > 0:
- current.append({"text": content[pos:new_pos]})
- if new_pos == len_content:
- break
- pos = new_pos
- if content[pos] == "}" and (
- pos == len_content - 1 or content[pos + 1] != "}"
- ):
- line = content[:pos].count("\n") + 1
- raise ValueError(
- f"Found '}}' without previous '{{': {pos} (line {line})"
- )
- if content[pos + 1] in ("{", "}"):
- if len(current) > 0 and set(current[-1]) == {"text"}:
- current[-1]["text"] = f"{current[-1]['text']}{content[pos]}"
- else:
- current.append({"text": content[pos]})
- continue
- closing_tag = content.find("}", pos)
- if closing_tag == -1:
- line = content[:pos].count("\n") + 1
- raise ValueError(
- f"Found '{{' without subsequent '}}': {pos} (line {line})"
- )
- tag, *pipes = content[pos + 1:closing_tag].split("|")
- pos = closing_tag + 1
- if tag.startswith("start-"):
- tag_dict = {
- "tag": tag[6:],
- "pipes": pipes,
- "children": [],
- }
- current.append(tag_dict)
- current = tag_dict["children"]
- tokens_stack.append((tag[6:], current))
- continue
- elif not tag.startswith("end-"):
- current.append({"tag": tag, "pipes": pipes})
- continue
- elif pipes:
- raise ValueError(f"Unexpected pipes: '{tag}' | {', '.join(pipes)}")
- elif tag[4:] != tokens_stack.pop()[0]:
- raise ValueError(f"Mismatched closing tag: '{tag}'")
- current = tokens_stack[-1][1]
- if len(tokens_stack) > 1:
- raise ValueError(f"Found unclosed tag: 'start-{tokens_stack[-1][0]}'")
- return tokens
-
- @staticmethod
- def run_pipes(value, pipes):
- if pipes == []:
- value = escape(value, False)
- else:
- for pipe in pipes:
- if pipe == "attrquote":
- value = escape(value)
- elif pipe == "safe":
- pass
- else:
- raise ValueError(f"Invalid pipe: '{pipe}'")
- return value
-
- def render(self, context, tokens=None):
- sio = StringIO()
- for token in self.tokens if tokens is None else tokens:
- if set(token) == {"text"}:
- sio.write(token["text"])
- elif "children" not in token:
- sio.write(self.run_pipes(context[token["tag"]], token["pipes"]))
- elif isinstance(token["tag"], Sequence):
- for ctx in context[token["tag"]]:
- sio.write(self.render(ctx, token["children"]))
- return sio.getvalue()