Syntax highlighting and miscellaneous fixes.
This commit is contained in:
parent
be2d8ed723
commit
a5e87aefde
8 changed files with 58 additions and 24 deletions
|
@ -33,9 +33,10 @@ def handle_command_define(e: Element, c: Context):
|
||||||
return nullify(e)
|
return nullify(e)
|
||||||
else:
|
else:
|
||||||
raise NameError(f"Command already defined: '{e.attributes['define']}'")
|
raise NameError(f"Command already defined: '{e.attributes['define']}'")
|
||||||
if "redefine" in e.attributes:
|
if "redefine" in e.attributes:
|
||||||
c.set_command(e.attributes["redefine"], compile(e.text, '<string>', 'exec'))
|
c.set_command(e.attributes["redefine"], compile(e.text, '<string>', 'exec'))
|
||||||
return nullify(e)
|
return nullify(e)
|
||||||
|
return e
|
||||||
|
|
||||||
|
|
||||||
def executeCommand(source, element: Element, ctx: Context) -> List[Element]:
|
def executeCommand(source, element: Element, ctx: Context) -> List[Element]:
|
||||||
|
|
24
context.py
24
context.py
|
@ -2,11 +2,13 @@
|
||||||
from panflute import Doc
|
from panflute import Doc
|
||||||
|
|
||||||
class Context:
|
class Context:
|
||||||
def __init__(self, doc: Doc=None, parent: 'Context'=None):
|
def __init__(self, doc: Doc, path: str, parent: 'Context'=None):
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
self._commands = {}
|
self._commands = {}
|
||||||
self._flags = {}
|
|
||||||
self.doc = doc
|
self.doc = doc
|
||||||
|
self.path = path
|
||||||
|
if self.get_metadata("flags", immediate=True) is None:
|
||||||
|
self.set_metadata("flags", {})
|
||||||
|
|
||||||
def get_command(self, command: str):
|
def get_command(self, command: str):
|
||||||
if command in self._commands:
|
if command in self._commands:
|
||||||
|
@ -23,24 +25,27 @@ class Context:
|
||||||
del self._commands[command]
|
del self._commands[command]
|
||||||
|
|
||||||
def is_flag_set(self, flag: str):
|
def is_flag_set(self, flag: str):
|
||||||
if flag in self._flags and self._flags[flag]:
|
if self.get_metadata("flags."+flag):
|
||||||
return True
|
if self.get_metadata("flags."+flag):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
elif self.parent:
|
elif self.parent:
|
||||||
return self.parent.is_set(flag)
|
return self.parent.is_flag_set(flag)
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def set_flag(self, flag: str, val: bool):
|
def set_flag(self, flag: str, val: bool):
|
||||||
self._flags[flag] = val
|
self.set_metadata("flags."+flag, val)
|
||||||
|
|
||||||
def unset_flag(self, flag):
|
def unset_flag(self, flag):
|
||||||
del self._flags[flag]
|
self.unset_metadata("flags."+flag)
|
||||||
|
|
||||||
def get_metadata(self, key, simple=True):
|
def get_metadata(self, key, simple=True, immediate=False):
|
||||||
value = self.doc.get_metadata(key, None, simple)
|
value = self.doc.get_metadata(key, None, simple)
|
||||||
if value is not None:
|
if value is not None:
|
||||||
return value
|
return value
|
||||||
elif self.parent:
|
elif self.parent and not immediate:
|
||||||
return self.parent.get_metadata(key)
|
return self.parent.get_metadata(key)
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
@ -57,6 +62,5 @@ class Context:
|
||||||
key = key.split(".")
|
key = key.split(".")
|
||||||
for k in key[:-1]:
|
for k in key[:-1]:
|
||||||
meta = meta[k]
|
meta = meta[k]
|
||||||
print(type(meta))
|
|
||||||
del meta.content[key[-1]] # A hack because MetaMap doesn't have a __delitem__
|
del meta.content[key[-1]] # A hack because MetaMap doesn't have a __delitem__
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ doc = import_md(open(sys.argv[1], "r").read())
|
||||||
|
|
||||||
|
|
||||||
print(show(doc))
|
print(show(doc))
|
||||||
context = Context(doc)
|
context = Context(doc, sys.argv[1])
|
||||||
doc = doc.walk(transform, context)
|
doc = doc.walk(transform, context)
|
||||||
print("---------------------")
|
print("---------------------")
|
||||||
#print(show(doc))
|
#print(show(doc))
|
||||||
|
|
21
html.py
21
html.py
|
@ -1,4 +1,9 @@
|
||||||
from panflute import *
|
from panflute import *
|
||||||
|
from pygments import highlight
|
||||||
|
from pygments.lexers import get_lexer_by_name
|
||||||
|
from pygments.formatters import HtmlFormatter
|
||||||
|
from pygments.util import ClassNotFound
|
||||||
|
|
||||||
from whitespace import NBSP
|
from whitespace import NBSP
|
||||||
from transform import FQuoted
|
from transform import FQuoted
|
||||||
from katex import KatexClient
|
from katex import KatexClient
|
||||||
|
@ -64,8 +69,20 @@ def html(e: Element, k: KatexClient, indent_level: int=0, indent_str: str="\t")
|
||||||
attributes += f' class="{" ".join(e.classes)}"'
|
attributes += f' class="{" ".join(e.classes)}"'
|
||||||
|
|
||||||
if isinstance(e, CodeBlock):
|
if isinstance(e, CodeBlock):
|
||||||
# TODO: Syntax highlighting
|
if e.attributes["highlight"] == True or e.attributes["highlight"] == 'True':
|
||||||
tag = "pre"
|
for cl in e.classes:
|
||||||
|
try:
|
||||||
|
lexer = get_lexer_by_name(cl)
|
||||||
|
except ClassNotFound:
|
||||||
|
continue
|
||||||
|
break
|
||||||
|
formatter = HtmlFormatter(style=e.attributes["style"])
|
||||||
|
result = highlight(e.text, lexer, formatter)
|
||||||
|
style = formatter.get_style_defs(".highlight")
|
||||||
|
return f'<style>{style}</style>{result}'
|
||||||
|
|
||||||
|
else:
|
||||||
|
return f'<pre>{e.text}</pre>'
|
||||||
|
|
||||||
if isinstance(e, Figure):
|
if isinstance(e, Figure):
|
||||||
content_foot = html(e.caption, k, indent_level+1, indent_str)
|
content_foot = html(e.caption, k, indent_level+1, indent_str)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
``` {.python define=nop}
|
```python {define=nop}
|
||||||
appendChildren(element.content)
|
appendChildren(element.content)
|
||||||
```
|
```
|
||||||
|
|
||||||
``` {.python define=opendatatask}
|
```python {define=opendatatask}
|
||||||
println("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.")
|
println("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.")
|
||||||
```
|
```
|
||||||
|
|
|
@ -7,6 +7,10 @@ I am a little piece of content
|
||||||
|
|
||||||
And things...
|
And things...
|
||||||
|
|
||||||
|
:::{if=cat}
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
``` {.python .run}
|
``` {.python .run}
|
||||||
# I set my own flags!
|
# I set my own flags!
|
||||||
ctx.set_flag("cat", True)
|
ctx.set_flag("cat", True)
|
||||||
|
@ -40,3 +44,4 @@ I am a duck.
|
||||||
:::{if=cat}
|
:::{if=cat}
|
||||||
This should be only shown to included cats.
|
This should be only shown to included cats.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
|
|
6
test.md
6
test.md
|
@ -16,18 +16,18 @@ This should only be shown to cats
|
||||||
:::
|
:::
|
||||||
|
|
||||||
|
|
||||||
``` {.python .run}
|
```python {.run}
|
||||||
ctx.set_flag("cat", True)
|
ctx.set_flag("cat", True)
|
||||||
```
|
```
|
||||||
|
|
||||||
``` {.python .run}
|
```python {.run}
|
||||||
println(f"The main document's title is '{ctx.get_metadata('title')}'")
|
println(f"The main document's title is '{ctx.get_metadata('title')}'")
|
||||||
ctx.set_metadata("a", {})
|
ctx.set_metadata("a", {})
|
||||||
ctx.set_metadata("a.b", {})
|
ctx.set_metadata("a.b", {})
|
||||||
ctx.set_metadata("a.b.c", "Bruh **bruh** bruh")
|
ctx.set_metadata("a.b.c", "Bruh **bruh** bruh")
|
||||||
```
|
```
|
||||||
|
|
||||||
```python
|
```python {style=native}
|
||||||
def bruh(no):
|
def bruh(no):
|
||||||
wat
|
wat
|
||||||
```
|
```
|
||||||
|
|
13
transform.py
13
transform.py
|
@ -15,7 +15,6 @@ class FQuoted(Quoted):
|
||||||
|
|
||||||
def transform(e: Element, c: Context) -> Element: # Returns next sibling element to transform
|
def transform(e: Element, c: Context) -> Element: # Returns next sibling element to transform
|
||||||
"""Transform the AST, making format-agnostic changes."""
|
"""Transform the AST, making format-agnostic changes."""
|
||||||
|
|
||||||
if isinstance(e, Whitespace) and bavlna(e, c):
|
if isinstance(e, Whitespace) and bavlna(e, c):
|
||||||
e = NBSP()
|
e = NBSP()
|
||||||
|
|
||||||
|
@ -41,7 +40,7 @@ def transform(e: Element, c: Context) -> Element: # Returns next sibling element
|
||||||
# commands without affecting the state of the current document.
|
# commands without affecting the state of the current document.
|
||||||
if (isinstance(e, Div)) and "partial" in e.attributes:
|
if (isinstance(e, Div)) and "partial" in e.attributes:
|
||||||
includedDoc = import_md(open(e.attributes["partial"], "r").read())
|
includedDoc = import_md(open(e.attributes["partial"], "r").read())
|
||||||
nContext = Context(includedDoc, c)
|
nContext = Context(includedDoc, e.attributes["partial"], c)
|
||||||
includedDoc = includedDoc.walk(transform, nContext)
|
includedDoc = includedDoc.walk(transform, nContext)
|
||||||
e = Div(*includedDoc.content)
|
e = Div(*includedDoc.content)
|
||||||
|
|
||||||
|
@ -60,9 +59,17 @@ def transform(e: Element, c: Context) -> Element: # Returns next sibling element
|
||||||
|
|
||||||
## Command defines
|
## Command defines
|
||||||
# possible TODO: def/longdef?
|
# possible TODO: def/longdef?
|
||||||
if isinstance(e, CodeBlock) and hasattr(e, "classes") and "python" in e.classes and hasattr(e, "attributes"):
|
if isinstance(e, CodeBlock) and hasattr(e, "classes") and "python" in e.classes and hasattr(e, "attributes")\
|
||||||
|
and ("define" in e.attributes or "redefine" in e.attributes):
|
||||||
e = handle_command_define(e, c)
|
e = handle_command_define(e, c)
|
||||||
|
|
||||||
|
# Pass down metadata 'highlight' and 'highlight_style' as attribute to CodeBlocks
|
||||||
|
if isinstance(e, CodeBlock):
|
||||||
|
if not "highlight" in e.attributes:
|
||||||
|
e.attributes["highlight"] = c.get_metadata("highlight") if c.get_metadata("highlight") is not None else True
|
||||||
|
if not "style" in e.attributes:
|
||||||
|
e.attributes["style"] = c.get_metadata("highlight_style") if c.get_metadata("highlight_style") is not None else "default"
|
||||||
|
|
||||||
## Shorthands
|
## Shorthands
|
||||||
if isinstance(e, Span) and len(e.content) == 1 and isinstance(e.content[0], Str):
|
if isinstance(e, Span) and len(e.content) == 1 and isinstance(e.content[0], Str):
|
||||||
## Handle special command shorthand [!commandname]{}
|
## Handle special command shorthand [!commandname]{}
|
||||||
|
|
Loading…
Reference in a new issue