diff --git a/src/formatitko/command.py b/src/formatitko/command.py index 249e080..5eb602c 100644 --- a/src/formatitko/command.py +++ b/src/formatitko/command.py @@ -1,7 +1,5 @@ from panflute import Span, Div, Element, Plain, Para -from .util import inlinify - class InlineError(Exception): pass @@ -11,18 +9,21 @@ class Command: # This distinction is needed because while transforming the tree, inline # elements cannot be replaced with block ones class InlineCommand(Span, Command): - def replaceSelf(self, content: list[Element]) -> Span: + def replaceSelf(self, *content: list[Element]) -> Span: try: return Span(*content) except TypeError: - if inlinify(content): - return Span(inlinify(content)) + if len(content) == 1 and (isinstance(content[0], Para) or isinstance(content[0], Plain)): + return Span(*content[0].content) else: raise InlineError(f"The command {self.attributes['c']} returned multiple Paragraphs and must be executed using `::: {{c={self.attributes['c']}}}\\n:::`.\n\n{content}") pass class BlockCommand(Div, Command): - def replaceSelf(self, content: list[Element]) -> Div: - return Div(*content) + def replaceSelf(self, *content: list[Element]) -> Div: + try: + return Div(*content) + except TypeError: + return Div(Para(*content)) pass diff --git a/src/formatitko/command_env.py b/src/formatitko/command_env.py index 15529ff..4775db4 100644 --- a/src/formatitko/command_env.py +++ b/src/formatitko/command_env.py @@ -1,6 +1,7 @@ import panflute as pf import formatitko.elements as fe from formatitko.util import import_md_list +from formatitko.util import parse_string from formatitko.context import Context from formatitko.command import Command diff --git a/src/formatitko/transform.py b/src/formatitko/transform.py index c96c6e6..e89447d 100644 --- a/src/formatitko/transform.py +++ b/src/formatitko/transform.py @@ -111,7 +111,7 @@ def transform(e: Element, c: Context) -> Element: if not c.trusted: return nullify(e) command_output = parse_command(e.text)(BlockCommand(), c) - e = Div(*([] if command_output is None else command_output)) + e = BlockCommand().replaceSelf(*([] if command_output is None else command_output)) e = e.walk(transform, c) # Command defines for calling using BlockCommand and InlineCommand. If @@ -164,7 +164,7 @@ def transform(e: Element, c: Context) -> Element: if not c.get_command(e.attributes["c"]): raise NameError(f"Command not defined '{e.attributes['c']}'.") command_output = c.get_command(e.attributes["c"])(e, c) - e = e.replaceSelf([] if command_output is None else command_output) + e = e.replaceSelf(*command_output) e = e.walk(transform, c) return e diff --git a/src/formatitko/util.py b/src/formatitko/util.py index 3710c72..1a37400 100644 --- a/src/formatitko/util.py +++ b/src/formatitko/util.py @@ -1,22 +1,13 @@ -from panflute import Element, Block, Inline, Null, Str, Doc, convert_text, Para, Plain, Span +from panflute import Element, Block, Inline, Null, Str, Doc, convert_text, Para, Plain, Span, Space import re from typing import Union # It sometimes happens that an element contains a single paragraph or even a # single plaintext line. It can be sometimes useful to extract this single # paragraph, which is inline. -def inlinify(e: Union[Element, list[Element]]) -> Union[Element, None]: - if isinstance(e, Element): - content = e.content - else: - content = e - if len(content) == 0: - return Str("") - if len(content) == 1 and (isinstance(content[0], Para) or isinstance(content[0], Plain)): - return Span(*content[0].content) - if len(content) == 1 and inlinify(content[0]) is not None: - return inlinify(content[0]) - return None +def inlinify(e: Element) -> Union[list[Element], None]: + if len(e.content) == 1 and (isinstance(e.content[0], Para) or isinstance(e.content[0], Plain)): + return e.content[0].content # In transform, inline elements cannot be replaced with Block ones and also # cannot be removed from the tree entirely, because that would mess up the @@ -28,6 +19,20 @@ def nullify(e: Element) -> Union[Str, Null]: else: return Null() + +def parse_string(s: str) -> list[Union[Str, Space]]: + words = s.split(" ") + output = [] + first_word, *words = words + if first_word != "": + output.append(Str(first_word)) + for word in words: + output.append(Space()) + if word != "": + output.append(Str(word)) + return output + + # A helper function to import markdown using panflute (which calls pandoc). If # we ever want to disable or enable some of panflute's markdown extensions, # this is the place to do it. diff --git a/test/test-files/test-import.md b/test/test-files/test-import.md index 3c90501..a6d3d7b 100644 --- a/test/test-files/test-import.md +++ b/test/test-files/test-import.md @@ -5,3 +5,6 @@ return element.content ```python {define=opendatatask} return import_md_list("Toto je praktická open-data úloha. V [odevzdávátku](https://ksp.mff.cuni.cz/h/odevzdavatko/) si necháte vygenerovat vstupy a odevzdáte příslušné výstupy. Záleží jen na vás, jak výstupy vyrobíte.") ``` +```python {define=opendatatask2} +return [*parse_string("Toto je praktická open-data úloha. V "),pf.Link(pf.Str("odevzdávátku"), url="https://ksp.mff.cuni.cz/h/odevzdavatko/"),*parse_string(" si necháte vygenertovat vstupy a odevzdáte příslušné výstupy. Záleží jen na vás, jak výstupy vyrobíte.")] +``` diff --git a/test/test-files/test-partial.md b/test/test-files/test-partial.md index 7c8b296..f50fa23 100644 --- a/test/test-files/test-partial.md +++ b/test/test-files/test-partial.md @@ -19,6 +19,14 @@ context.set_flag("cat", True) ```python {.run} return import_md_list(f"The subdocument's title is\n\n# {context.get_metadata('title')}\n\nThe subdocument's subtitle is\n\n## {context.get_metadata('subtitle')}") ``` +```python {.run} +return [ + pf.Para(*parse_string("The subdocument's title is")), + pf.Header(*parse_string(context.get_metadata('title')), level=1), + pf.Para(*parse_string("The subdocument's subtitle is")), + pf.Header(*parse_string(context.get_metadata('subtitle')), level=2) +] +``` ```markdown {.group} --- diff --git a/test/test.md b/test/test.md index f2b4e0f..161d6f1 100644 --- a/test/test.md +++ b/test/test.md @@ -38,7 +38,7 @@ context.set_flag("cat", True) context.set_metadata("a", {}) context.set_metadata("a.b", {}) context.set_metadata("a.b.c", "Bruh **bruh** bruh") -return import_md_list(f"The main document's title is '{context.get_metadata('title')}'") +return [*parse_string("The main document's title is "), fe.FQuoted(*parse_string(context.get_metadata('title')), style="simple"), pf.Str(".")] ``` ```python {style=native} @@ -64,6 +64,7 @@ V pravém jízdním bruhu. V pravém jízdním bruhu. [!opendatatask]{} +[!opendatatask2]{} ``` [This too!]{if=cat}