From 1cf0de20fca668a501690067ca0bb703ef763599 Mon Sep 17 00:00:00 2001 From: Greenscreener Date: Tue, 31 Jan 2023 00:44:48 +0100 Subject: [PATCH] Finished partials. --- command.py | 2 +- formatitko.py | 45 +++++++++++++++--------------- test-include.md => test-partial.md | 3 ++ test.md | 3 +- util.py | 5 +++- 5 files changed, 32 insertions(+), 26 deletions(-) rename test-include.md => test-partial.md (87%) diff --git a/command.py b/command.py index 69d8b54..08c7308 100644 --- a/command.py +++ b/command.py @@ -16,7 +16,7 @@ class InlineCommand(Span, Command): raise SyntaxError(f"The command {self.attributes['c']} returned multiple Paragraphs and must be executed using `::: {{c={self.attributes['c']}}}\\n:::`.") pass -class MultilineCommand(Div, Command): +class BlockCommand(Div, Command): def replaceSelf(self, content: List[Element]) -> Div: return Div(*content) pass diff --git a/formatitko.py b/formatitko.py index 626bfc1..56b2644 100755 --- a/formatitko.py +++ b/formatitko.py @@ -72,18 +72,30 @@ def transform(e: Element, doc: Doc) -> Element: # Returns next sibling element t # `c` attribute. Execute a command with the name saved in this attribute. if (isinstance(e, Div) or isinstance(e, Span)) and "c" in e.attributes: if isinstance(e, Div): - e = MultilineCommand(*e.content, identifier=e.identifier, classes=e.classes, attributes=e.attributes) + e = BlockCommand(*e.content, identifier=e.identifier, classes=e.classes, attributes=e.attributes) else: e = InlineCommand(*e.content, identifier=e.identifier, classes=e.classes, attributes=e.attributes) - + + # `partial` attribute. + # This is for including content from files with their own flags + # and commands without affecting the state of the current + # document. + if (isinstance(e, Div)) and "partial" in e.attributes: + includedDoc = import_md(open(e.attributes["partial"], "r").read()) + oFlags = flags[:] + oCommands = commands.copy() + includedDoc = includedDoc.walk(transform) + flags = oFlags + commands = oCommands + e = Div(*includedDoc.content) # Execute python code inside source code block if isinstance(e, CodeBlock) and hasattr(e, "classes") and "python" in e.classes and "run" in e.classes: exec(e.text) return nullify(e) - ## Define commands - # TODO: def/longdef? + ## Command defines + # possible TODO: def/longdef? if isinstance(e, CodeBlock) and hasattr(e, "classes") and "python" in e.classes and hasattr(e, "attributes"): if "define" in e.attributes: if not e.attributes["define"] in commands: @@ -95,30 +107,17 @@ def transform(e: Element, doc: Doc) -> Element: # Returns next sibling element t commands[e.attributes["redefine"]] = compile(e.text, '', 'exec') return nullify(e) + ## Shorthands if isinstance(e, Span) and len(e.content) == 1 and isinstance(e.content[0], Str): - print(isinstance(e, Span)) ## Handle special command shorthand [!commandname]{} if re.match(r"^![\w.]+$", e.content[0].text): e = InlineCommand(identifier=e.identifier, classes=e.classes, attributes={**e.attributes, "c": e.content[0].text[1:]}) - - ## Handle include [>path/file.md]{} TODO: implement properly as commands - # This is for including content from files with their own flags - # and commands without affecting the state of the current - # document. - elif re.match(r"^>.+$", e.content[0].text): - includedDoc = convert_text(open(e.content[0].text[1:], "r").read(), standalone=True) # TODO: Put into function - oCommands = commands.copy() - oFlags = flags[:] - includedDoc = includedDoc.walk(transform) - commands = oCommands - flags = oFlags - #e = Div(*includedDoc.content) - - ## Handle import [#path/file.md]{} TODO: implement properly as commands + + ## Handle import [#path/file.md]{} # This is the exact opposite of include. We take the commands # and flags but drop the content. elif re.match(r"^#.+$", e.content[0].text): - importedDoc = convert_text(open(e.content[0].text[1:], "r").read(), standalone=True) # TODO: Put into function + importedDoc = import_md(open(e.content[0].text[1:], "r").read()) importedDoc.walk(transform) return nullify(e) @@ -126,16 +125,16 @@ def transform(e: Element, doc: Doc) -> Element: # Returns next sibling element t # Walk transforms the children first, then the root element, # so the content of the element the command receives is # already transformed. - # TODO: Transform content that comes out of commands. if isinstance(e, Command): if not e.attributes["c"] in commands: raise NameError(f"Command not defined '{e.attributes['c']}'.") e = e.replaceSelf(executeCommand(commands[e.attributes["c"]], e)) + e.walk(transform) return e +doc = import_md(open(sys.argv[1], "r").read()) -doc = convert_text(open(sys.argv[1], "r").read(), standalone=True) # TODO: Put into function so we can specify extensions and parameters globally. print(show(doc)) diff --git a/test-include.md b/test-partial.md similarity index 87% rename from test-include.md rename to test-partial.md index d4f3c09..cca0af5 100644 --- a/test-include.md +++ b/test-partial.md @@ -1,3 +1,6 @@ +--- +title: A subfile! +--- I am a little piece of content # With a title! diff --git a/test.md b/test.md index ac89762..de23e1a 100644 --- a/test.md +++ b/test.md @@ -7,7 +7,8 @@ title: 'Wooooo a title' This is an *example* **yay**! -[>test-include.md]{} +:::{partial=test-partial.md} +::: :::{if=cat} This should only be shown to cats diff --git a/util.py b/util.py index 190aaca..7e3c04a 100644 --- a/util.py +++ b/util.py @@ -1,4 +1,4 @@ -from panflute import Element, Block, Inline, Null, Str +from panflute import Element, Block, Inline, Null, Str, Doc, convert_text import re def replaceEl(e: Element, r: Element) -> Element: @@ -14,3 +14,6 @@ def nullify(e: Element): return Str("") elif isinstance(e, Block): return Null() + +def import_md(s: str) -> Doc: + return convert_text(s, standalone=True)