Browse Source

Started working on command execution, added direct code execution, removed some bugs.

pull/28/head
Jan Černohorský 2 years ago
parent
commit
4aeadd3c71
  1. 10
      builtin_commands.py
  2. 4
      command.py
  3. 10
      command_wrappers.py
  4. 42
      formatitko.py
  5. 22
      test.md
  6. 7
      util.py

10
builtin_commands.py

@ -1,5 +1,7 @@
from panflute import Element from panflute import Element, Span
from command_wrappers import *
class commands: def nop(e: Element) -> Element:
def woah(e: Element) -> Element: return e
return e
opendatatask = basicTextCommand("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.")

4
command.py

@ -8,11 +8,15 @@ class Command:
class InlineCommand(Span, Command): class InlineCommand(Span, Command):
def call(self, f: Callable) -> Span: def call(self, f: Callable) -> Span:
r = f(self) r = f(self)
if "c" in r.attributes:
del r.attributes["c"]
return replaceEl(self, Span(*r.content, identifier=r.identifier, classes=r.classes, attributes=r.attributes)) return replaceEl(self, Span(*r.content, identifier=r.identifier, classes=r.classes, attributes=r.attributes))
pass pass
class MultilineCommand(Div, Command): class MultilineCommand(Div, Command):
def call(self, f: Callable) -> Div: def call(self, f: Callable) -> Div:
r = f(self) r = f(self)
if "c" in r.attributes:
del r.attributes["c"]
return replaceEl(self, Div(*r.content, identifier=r.identifier, classes=r.classes, attributes=r.attributes)) return replaceEl(self, Div(*r.content, identifier=r.identifier, classes=r.classes, attributes=r.attributes))
pass pass

10
command_wrappers.py

@ -0,0 +1,10 @@
from typing import Callable
from panflute import Element, Span, convert_text
def basicTextCommand(s: str) -> Callable:
content = convert_text(s)[0].content
def f(e: Element) -> Element:
element = Span()
element.content = content
return element
return f

42
formatitko.py

@ -4,10 +4,11 @@
from whitespace import * from whitespace import *
from command import * from command import *
from util import * from util import *
from builtin_commands import commands import builtin_commands
from panflute import * from panflute import *
import re import re
import sys
from mj_show import show from mj_show import show
@ -15,6 +16,7 @@ flags = ["dog"]
def transform(e: Element): def transform(e: Element):
"""Transform the AST, making format-agnostic changes.""" """Transform the AST, making format-agnostic changes."""
if isinstance(e, Whitespace) and bavlna(e): if isinstance(e, Whitespace) and bavlna(e):
e = replaceEl(e, NBSP()) e = replaceEl(e, NBSP())
@ -37,24 +39,50 @@ def transform(e: Element):
else: else:
e = replaceEl(e, InlineCommand(*e.content, identifier=e.identifier, classes=e.classes, attributes=e.attributes)) e = replaceEl(e, InlineCommand(*e.content, identifier=e.identifier, classes=e.classes, attributes=e.attributes))
if isinstance(e, CodeBlock) and hasattr(e, "classes") and "python" in e.classes and "run" in e.classes:
exec(e.text)
deleteEl(e)
return
# Handle special command shorthand [!commandname]{} # Handle special command shorthand [!commandname]{}
if isinstance(e, Span) and len(e.content) == 1 and isinstance(e.content[0], Str) and re.match(r"^!\w+$", e.content[0].text): if isinstance(e, Span) and len(e.content) == 1 and isinstance(e.content[0], Str) and re.match(r"^![\w.]+$", e.content[0].text):
e = replaceEl(e, InlineCommand(identifier=e.identifier, classes=e.classes, attributes={**e.attributes, "c": e.content[0].text[1:]})) e = replaceEl(e, InlineCommand(identifier=e.identifier, classes=e.classes, attributes={**e.attributes, "c": e.content[0].text[1:]}))
# The command is executed first and then its contents are transformed. TODO: Is this what we want?
if isinstance(e, Command):
if re.match(r"^[\w.]+$", e.attributes["c"]):
try:
e = e.call(eval(e.attributes["c"]))
except NameError:
raise NameError(f"Command not found: '{e.attributes['c']}'.")
else:
raise SyntaxError(f"Invalid command syntax: '{e.attributes['c']}'.")
# Recursively transform all contents.
if hasattr(e, "content"): if hasattr(e, "content"):
for c in e.content: for c in e.content:
# Deleted elements are only marked to be deleted with a class, because otherwise
# it would mess up this for cycle.
transform(c) transform(c)
# All commands on the inside execute first while being transformed # Delete elements marked to be deleted. This is somewhat inelegant.
if isinstance(e, Command): ci = 0
pass # TODO: Dodělat tohle while ci < len(e.content):
c = e.content[ci]
if hasattr(c, "classes") and "deleted" in c.classes:
del e.content[ci]
else:
ci+=1
doc = load()
doc = convert_text(open(sys.argv[1], "r").read(), standalone=True, extra_args=["-f", "markdown+fenced_code_attributes"])
print(show(doc)) print(show(doc))
transform(doc) transform(doc)
print("---------------------") print("---------------------")
print(show(doc)) print(convert_text(doc, input_format="panflute", output_format="markdown"))

22
test.md

@ -2,20 +2,30 @@
This is an *example* **yay**! This is an *example* **yay**!
```python3
def what():
return no way
```
:::{if=cat} :::{if=cat}
This should only be shown to cats This should only be shown to cats
::: :::
``` {.python .run}
flags.append("cat")
```
::::{if=cat}
This should only be shown to cats the second time
::::
This should be seen by all. This should be seen by all.
[!builtin_commands.opendatatask]{}
[This too!]{if=cat} [This too!]{if=cat}
[An inline command with contents and **bold** and another [!command]{} inside!]{c=bro} [What]{.co}
[An inline command with contents and **bold** and another [!builtin_commands.nop]{} inside!]{c=builtin_commands.nop}
[!woah]{a=b} <!-- A special command! WOW --> [!builtin_commands.nop]{a=b} <!-- A special command! WOW -->

7
util.py

@ -1,7 +1,10 @@
from panflute import Element from panflute import Element
import re
def replaceEl(e: Element, r: Element) -> Element: def replaceEl(e: Element, r: Element) -> Element:
e.parent.content[e.index] = r parent = e.parent
parent.content[e.index] = r
r.parent = parent
return r return r
def deleteEl(e: Element): def deleteEl(e: Element):
del e.parent.content[e.index] e.classes.append("deleted")

Loading…
Cancel
Save