Started working on command execution, added direct code execution, removed some bugs.
This commit is contained in:
parent
f04ce0693b
commit
4aeadd3c71
6 changed files with 77 additions and 20 deletions
|
@ -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.")
|
||||||
|
|
|
@ -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
Normal file
10
command_wrappers.py
Normal file
|
@ -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
|
|
@ -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
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}
|
||||||
|
|
||||||
[!woah]{a=b} <!-- A special command! WOW -->
|
[An inline command with contents and **bold** and another [!builtin_commands.nop]{} inside!]{c=builtin_commands.nop}
|
||||||
|
|
||||||
|
[!builtin_commands.nop]{a=b} <!-- A special command! WOW -->
|
||||||
|
|
||||||
|
|
||||||
|
|
7
util.py
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…
Reference in a new issue