From 15b9c3af6b0d58f8d6bb0729a217dc6d9f4666e6 Mon Sep 17 00:00:00 2001 From: Qrius Date: Fri, 11 Apr 2025 17:14:32 +0200 Subject: Begin rewrite of internals to be more malleable --- src/smp/builtins.py | 105 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 93 insertions(+), 12 deletions(-) (limited to 'src/smp/builtins.py') diff --git a/src/smp/builtins.py b/src/smp/builtins.py index 3ff15c6..0997165 100644 --- a/src/smp/builtins.py +++ b/src/smp/builtins.py @@ -1,11 +1,14 @@ # import smp.exceptions +import os import subprocess import urllib.request import urllib.error import urllib.parse import datetime import markdown +from skaldpress.metadata_parser import extract_parse_yaml_metadata from gfm import AutolinkExtension, TaskListExtension # type: ignore +from typing import Any def smp_builtin_define(macro_processor, macro_name, macro_value=None): @@ -66,11 +69,38 @@ def smp_builtin_ifneq(macro_processor, a, b, iftrue, iffalse=None): return "" +def smp_builtin_add_metadata(macro_processor, metadata: dict[str, Any], overwrite=True): + """ + Not added to macro_processor as macro + """ + for macro_name, value in metadata.items(): + if not macro_name.startswith( + macro_processor._get_macro_with_prefix("metadata_prefix") + ): + macro_name = f"{macro_processor._get_macro_with_prefix('metadata_prefix')}{macro_name}" + + macro_value = str(value) + if isinstance(value, list): + macro_value = [str(el) for el in value] + + if macro_name in macro_processor.macros: + macro_value.extend(macro_processor.macros[macro_name]) + + if overwrite or macro_name not in macro_processor.macros: + macro_processor.define_macro(macro_name, macro_value) + + def smp_builtin_include(macro_processor, filename): - filename = macro_processor.process_input(filename) - with open(filename, "r") as f: - file_content = f.read() - return macro_processor.process_input(file_content) + return smp_builtin_read(macro_processor, filename, template_content=None) + + +def smp_builtin_parse_leading_yaml(macro_processor, content): + """ + Not added to macro_processor as macro + """ + metadata, content = extract_parse_yaml_metadata(content) + smp_builtin_add_metadata(macro_processor, metadata, overwrite=True) + return content def smp_builtin_include_verbatim(macro_processor, filename): @@ -147,6 +177,51 @@ def smp_builtin_html_from_markdown(macro_processor, text, extensions=list()): return markdown.markdown(text, extensions=extensions) +def _smp_builtin_template_content(content): + def inner(macro_processor): + """ + This should do some kind of stack thing, so we can track which file we are processing. + entering the CONTENT is fine, the question is how to handle exiting it. + + could have a "once" macro or something, that is added to the end of the content. + """ + return content + + return inner + + +def smp_builtin_template(macro_processor, template, content): + return smp_builtin_read(macro_processor, template, template_content=content) + + +def smp_builtin_read(macro_processor, filename, template_content=None): + with open(filename, "r") as f: + file_content = f.read() + + metadata = {} + if macro_processor._get_macro_with_prefix("parse_file_yaml"): + metadata, file_content = extract_parse_yaml_metadata(file_content) + smp_builtin_add_metadata(macro_processor, metadata, overwrite=False) + + extension = os.path.splitext(filename)[1][1:] or "" + macro_processor._define_macro_with_prefix("target_file_extension", extension) + + if template_content is not None: + macro_processor._get_macro_with_prefix("template_stack").append(filename) + macro_processor.macros["CONTENT"] = template_content + + content = macro_processor.process_input(file_content) + + if extension == "md": + content = smp_builtin_html_from_markdown(macro_processor, content) + + if (template := macro_processor.macros.get("METADATA_template")) is not None: + if template not in macro_processor._get_macro_with_prefix("template_stack"): + return smp_builtin_read(macro_processor, template, content) + + return content + + global LINK_CACHE LINK_CACHE: dict[str, tuple[bool, int, str]] = dict() @@ -168,14 +243,24 @@ def smp_builtin_wodl(macro_processor, link, timeout_seconds=5): working_link = (r.status == 200) and (r.reason == "OK") LINK_CACHE[link] = (working_link, r.status, r.reason) if not working_link: - macro_processor.warnings.append( - f"Dead link {link} ({r.status} {r.reason})!" - ) + macro_processor.log_warning(f"Dead link {link} ({r.status} {r.reason})!") except urllib.error.URLError as e: - macro_processor.warnings.append(f"Dead link {link} ({e})!") + macro_processor.log_warning(f"Dead link {link} ({e})!") return "" +def smp_builtin_once(macro_processor, content): + if (cache := macro_processor._get_macro_with_prefix("once_cache")) is not None: + if (exp := cache.get(content)) is not None: + return exp + else: + macro_processor._define_macro_with_prefix("once_cache", {}) + + expanded_content = macro_processor.process_input(content) + macro_processor._get_macro_with_prefix("once_cache", expanded_content) + return expanded_content + + def smp_builtin_dumpenv(macro_processor): out = "" out += "━ Macros ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n" @@ -188,7 +273,3 @@ def smp_builtin_dumpenv(macro_processor): out += f"{repr(key)}: {repr(val)}\n" out += "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" return out - - -# TODO Add macro that spawns a interactive shell with the python env. would allow interactive debugging :) -# needs to have a continue function or something (probably on C-d -- cgit v1.2.3