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 |
import re |
||||
|
from typing import Union |
||||
|
|
||||
# It sometimes happens that an element contains a single paragraph or even a |
# 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 |
# single plaintext line. It can be sometimes useful to extract this single |
||||
# paragraph, which is inline. |
# paragraph, which is inline. |
||||
def inlinify(e: Element) -> Element: |
def inlinify(e: Union[Element, list[Element]]) -> Union[Element, None]: |
||||
if len(e.content) == 1 and (isinstance(e.content[0], Para) or isinstance(e.content[0], Plain)): |
if isinstance(e, Element): |
||||
return e.content[0].content |
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 |
# 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 |
# cannot be removed from the tree entirely, because that would mess up the |
||||
# iteration process through the tree. We replace them with null elements |
# iteration process through the tree. We replace them with null elements |
||||
# instead which never make it to the output. |
# instead which never make it to the output. |
||||
def nullify(e: Element): |
def nullify(e: Element) -> Union[Str, Null]: |
||||
if isinstance(e, Inline): |
if isinstance(e, Inline): |
||||
return Str("") |
return Str("") |
||||
elif isinstance(e, Block): |
else: |
||||
return Null() |
return Null() |
||||
|
|
||||
# A helper function to import markdown using panflute (which calls pandoc). If |
# 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, |
# we ever want to disable or enable some of panflute's markdown extensions, |
||||
# this is the place to do it. |
# 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") |
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