Browse Source
Je to furt docela solidní mess, ale IMO alespoň o trochu menší, než to bylo. Asi by to chtělo trochu zrefaktorovat, k tomu se dostanu možná po víkendu. Nakonec jsem se rozhodl nepředávat atributy pomocí kwargs, ale alespoň se commandy volají jako funkce.pull/28/head
Jan Černohorský
1 year ago
12 changed files with 120 additions and 104 deletions
@ -0,0 +1,7 @@ |
|||
import panflute as pf |
|||
import formatitko.elements as fe |
|||
from formatitko.util import import_md_list |
|||
|
|||
from formatitko.context import Context |
|||
from formatitko.command import Command |
|||
from panflute import Element |
@ -0,0 +1,37 @@ |
|||
from .context import Context, CommandCallable # This is there because of a wild circular import dependency between many functions and classes |
|||
from panflute import CodeBlock |
|||
|
|||
|
|||
from . import command_env |
|||
from .util import nullify |
|||
|
|||
def parse_command(code: str) -> CommandCallable: |
|||
code_lines = code.split("\n") |
|||
tabs = False |
|||
for line in code_lines: |
|||
if len(line) != 0 and line[0] == "\t": |
|||
tabs = True |
|||
break |
|||
indented_code_lines = [] |
|||
for line in code_lines: |
|||
indented_code_lines.append(("\t" if tabs else " ")+line) |
|||
code = "def command(element: Command, context: Context) -> list[Element]:\n"+"\n".join(indented_code_lines) |
|||
globals = command_env.__dict__ |
|||
exec(code, globals) |
|||
return globals["command"] |
|||
|
|||
# This function is called in trasform.py, defining a command which can be |
|||
# called later |
|||
def handle_command_define(e: CodeBlock, c: Context): |
|||
command = parse_command(e.text) |
|||
if "define" in e.attributes: |
|||
if not c.get_command(e.attributes["define"]): |
|||
c.set_command(e.attributes["define"], command) |
|||
return nullify(e) |
|||
else: |
|||
raise NameError(f"Command already defined: '{e.attributes['define']}'") |
|||
if "redefine" in e.attributes: |
|||
c.set_command(e.attributes["redefine"], command) |
|||
return nullify(e) |
|||
return e |
|||
|
@ -0,0 +1,15 @@ |
|||
from panflute import Quoted |
|||
|
|||
|
|||
from .command import Command, InlineCommand, BlockCommand |
|||
from .context import Group |
|||
from .whitespace import Whitespace, NBSP |
|||
|
|||
# This is a small extension to the Quoted panflute elements which allows to |
|||
# have language-aware quotation marks. |
|||
class FQuoted(Quoted): |
|||
def __init__(self, *args, **kwargs): |
|||
self.style = kwargs["style"] |
|||
del kwargs["style"] |
|||
super().__init__(*args, **kwargs) |
|||
|
@ -1,25 +1,38 @@ |
|||
from panflute import Element, Block, Inline, Null, Str, Doc, convert_text, Para, Plain |
|||
from panflute import Element, Block, Inline, Null, Str, Doc, convert_text, Para, Plain, Span |
|||
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: Element) -> Element: |
|||
if len(e.content) == 1 and (isinstance(e.content[0], Para) or isinstance(e.content[0], Plain)): |
|||
return e.content[0].content |
|||
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 |
|||
|
|||
# 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 |
|||
# iteration process through the tree. We replace them with null elements |
|||
# instead which never make it to the output. |
|||
def nullify(e: Element): |
|||
def nullify(e: Element) -> Union[Str, Null]: |
|||
if isinstance(e, Inline): |
|||
return Str("") |
|||
elif isinstance(e, Block): |
|||
else: |
|||
return Null() |
|||
|
|||
# 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. |
|||
def import_md(s: str, standalone: bool=True) -> Doc: |
|||
def import_md(s: str, standalone: bool=True) -> Union[Doc, list[Element]]: |
|||
return convert_text(s, standalone=standalone, input_format="markdown-definition_lists-citations-latex_macros") |
|||
|
|||
def import_md_list(s: str) -> list[Element]: |
|||
return import_md(s, standalone=False) |
|||
|
Loading…
Reference in new issue