Trochu zpoužitelněný systém příkazů.
Asi nemá úplně smysl mít nějaký magický nedeterministický způsob, jak dělat výstupy příkazů víc inline. Pokud příkazy chtějí být volatelné inline, musí se postarat o to, že jejich výstup s tím bude kompatibilní. Příkaz si může ověřit, jestli se očekává inlinovost podle toho, jestli je parametr `e` třídy BlockCommand nebo `InlineCommand`.
This commit is contained in:
parent
f8c1cac18e
commit
8cc8ad383d
7 changed files with 42 additions and 23 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.")]
|
||||
```
|
||||
|
|
|
@ -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}
|
||||
---
|
||||
|
|
|
@ -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}
|
||||
|
|
Loading…
Reference in a new issue