diff --git a/src/formatitko/html.py b/src/formatitko/html.py
deleted file mode 100644
index 0403082..0000000
--- a/src/formatitko/html.py
+++ /dev/null
@@ -1,311 +0,0 @@
-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
-import os
-from typing import Union
-
-from .whitespace import NBSP
-from .elements import FQuoted
-from .katex import KatexClient
-from .util import inlinify
-from .context import Group
-from .images import ImageProcessor
-
-import warnings
-warnings.warn("The html function has been deprecated, is left only for reference and will be removed in future commits. HTML_generator should be used in its place.", DeprecationWarning)
-
-def html(e: Union[Element, ListContainer], k: KatexClient, i: ImageProcessor, indent_level: int=0, indent_str: str="\t") -> str:
-
- warnings.warn("The html function has been deprecated, is left only for reference and will be removed in future commits. HTML_generator should be used in its place.", DeprecationWarning)
-
- # `only` attribute which makes transformed elements appear only in tex
- # output or html output
- if hasattr(e, "attributes") and "only" in e.attributes and e.attributes["only"] != "html":
- return ""
-
- if isinstance(e, ListContainer):
- return ''.join([html(child, k, i, indent_level, indent_str) for child in e])
-
- # Bits from which the final element output is built at the end of this
- # function. Most elements override this by returning their own output.
- tag = e.tag.lower()
- attributes = ""
- content_foot = ""
- content_head = ""
-
- if isinstance(e, Str):
- return e.text.replace(" ", " ")
-
- # Most elements fit the general template at the end of the function, just
- # need their html tag specified.
- tags = {
- BulletList: "ul",
- Doc: "main",
- Emph: "em",
- Caption: "figcaption",
- Para: "p",
- Header: "h"+str(e.level) if isinstance(e, Header) else "",
- LineBlock: "p",
- ListItem: "li",
- SmallCaps: "span",
- Strikeout: "strike",
- Subscript: "sub",
- Superscript: "sup",
- Underline: "u",
- TableBody: "tbody",
- TableHead: "thead",
- TableFoot: "tfoot",
- TableRow: "tr",
- TableCell: "td",
- }
- if type(e) in tags:
- tag = tags[type(e)]
-
- # These are also disabled in pandoc so they shouldn't appear in the AST at all.
- not_implemented = {
- Citation: True,
- Cite: True,
- Definition: True,
- DefinitionItem: True,
- DefinitionList: True
- }
- if type(e) in not_implemented:
- return f''
-
- # Elements which can be represented by a simple string
- simple_string = {
- NBSP: " ",
- Space: " ",
- Null: "",
- LineBreak: f"\n{indent_level*indent_str}
\n{indent_level*indent_str}",
- SoftBreak: f" ",
- HorizontalRule: f"{indent_level*indent_str}
\n"
- }
- if type(e) in simple_string:
- return simple_string[type(e)]
-
- if hasattr(e, "identifier") and e.identifier != "":
- attributes += f' id="{e.identifier}"'
-
- if hasattr(e, "classes") and len(e.classes) != 0:
- attributes += f' class="{" ".join(e.classes)}"'
-
- # Attributes are only passed down manually, because we use them internally.
- # Maybe this should be a blocklist instead of an allowlist?
-
- # Overriding elements with their own returns
- if isinstance(e, CodeBlock):
- if len(e.classes) > 0 and (e.attributes["highlight"] == True or e.attributes["highlight"] == 'True'):
- # Syntax highlighting using pygments
- for cl in e.classes:
- try:
- lexer = get_lexer_by_name(cl)
- except ClassNotFound:
- continue
- break
- else:
- print(f"WARN: Syntax highligher does not have lexer for element with these classes: {e.classes}")
- formatter = HtmlFormatter(style=e.attributes["style"])
- result = highlight(e.text, lexer, formatter)
- return f'{result}'
- else:
- return f'{e.text}
'
-
- if isinstance(e, Doc):
- formatter = HtmlFormatter(style=e.get_metadata("highlight-style") if e.get_metadata("highlight-style") is not None else "default")
- content_head = f''
-
- if isinstance(e, Image):
- url = e.url
-
- # Attributes → image processor args
- additional_args = {}
- if "file-width" in e.attributes:
- additional_args["width"] = int(e.attributes["file-width"])
- if "file-height" in e.attributes:
- additional_args["height"] = int(e.attributes["file-height"])
- if "file-quality" in e.attributes:
- additional_args["quality"] = int(e.attributes["file-quality"])
- if "file-dpi" in e.attributes:
- additional_args["dpi"] = int(e.attributes["file-dpi"])
-
- # The directory of the current file, will also look for images there.
- source_dir = e.attributes["source_dir"]
-
- _, ext = os.path.splitext(url)
- ext = ext[1:]
-
- # Conversions between various formats.
- if ext in ["svg", "png", "jpeg", "gif"]:
- # Even supported elements have to be 'converted' because the
- # processing contains finding and moving them to the output
- # directory.
- url = i.process_image(url, ext, source_dir, **additional_args)
- elif ext in ["pdf", "epdf"]:
- if not "dpi" in additional_args:
- additional_args["dpi"] = 300
- url = i.process_image(url, "png", source_dir, **additional_args)
- elif ext in ["jpg"]:
- url = i.process_image(url, "jpeg", source_dir, **additional_args)
- else:
- url = i.process_image(url, "png", source_dir, **additional_args)
-
- # Srcset generation - multiple alternative sizes of images browsers can
- # choose from.
- _, ext = os.path.splitext(url)
- ext = ext[1:]
- srcset = []
- if ext in ["png", "jpeg"] and (not "no-srcset" in e.attributes or e.attributes["no-srcset"] == False or e.attributes["no-srcset"] == 'False'):
- # This is inspired by @vojta001's blogPhoto shortcode he made for
- # patek.cz:
- # https://gitlab.com/patek-devs/patek.cz/-/blob/master/themes/patek/layouts/shortcodes/blogPhoto.html
- width, height = i.get_image_size(url, [i.public_dir])
- sizes = [(640, 360, 85), (1280, 720, 85), (1920, 1080, 90)] # (widht, height, quality)
- for size in sizes:
- if width <= size[0] and height <= size[1]:
- srcset.append((f'{i.web_path}/{url}', f'{width}w'))
- break
- quality = size[2] if ext == "jpeg" else None
- srcset.append((f'{i.web_path}/{i.process_image(url, ext, i.public_dir, width=size[0], height=size[1], quality=quality)}', f'{size[0]}w'))
-
- url = i.web_path + "/" + url
-
- attributes = f'{" style=width:"+e.attributes["width"] if "width" in e.attributes else ""} alt="{e.title or html(e.content, k, i, 0, "")}"'
- if len(srcset) != 0:
- return f''
- else:
- return f''
-
- # See https://pandoc.org/MANUAL.html#line-blocks
- if isinstance(e, LineItem):
- return indent_level*indent_str + html(e.content, k, i) + "
\n"
-
- # Footnotes are placed into parentheses. (And not footnotes (This is how KSP did it before me))
- if isinstance(e, Note):
- content_head = "("
- content_foot = ")"
- if inlinify(e) is not None:
- return f' ({html(inlinify(e), k, i, 0, "")})'
-
- if isinstance(e, FQuoted):
- if e.style == "cs":
- if e.quote_type == "SingleQuote":
- return f'‚{html(e.content, k, i, 0, "")}‘'
- elif e.quote_type == "DoubleQuote":
- return f'„{html(e.content, k, i, 0, "")}“'
- elif e.style == "en":
- if e.quote_type == "SingleQuote":
- return f'‘{html(e.content, k, i, 0, "")}’'
- elif e.quote_type == "DoubleQuote":
- return f'“{html(e.content, k, i, 0, "")}”'
- else:
- if e.quote_type == "SingleQuote":
- return f'\'{html(e.content, k, i, 0, "")}\''
- elif e.quote_type == "DoubleQuote":
- return f'"{html(e.content, k, i, 0, "")}"'
- else:
- return f'"{html(e.content, k, i, 0, "")}"'
-
- if isinstance(e, Group):
- k.begingroup()
- ret = html(e.content, k, i, indent_level, indent_str)
- k.endgroup()
- return ret
-
- if isinstance(e, Math):
- formats = {
- "DisplayMath": True,
- "InlineMath": False
- }
- return indent_level*indent_str + k.render(e.text, {"displayMode": formats[e.format]})
-
- if isinstance(e, RawInline):
- if e.format == "html":
- return e.text
- else:
- return ""
-
- if isinstance(e, RawBlock):
- if e.format == "html":
- return f'{e.text}\n'
- else:
- return ""
-
-
- # Non-overriding elements, they get generated using the template at the end
- # of this function
- if isinstance(e, Header):
- tag = "h"+str(e.level)
-
- if isinstance(e, Figure):
- content_foot = html(e.caption, k, i, indent_level+1, indent_str)
-
- if isinstance(e, Caption):
- tag = "figcaption"
-
- if isinstance(e, Link):
- tag = "a"
- attributes += f' href="{e.url}"'
- if e.title:
- attributes += f' title="{e.title}"'
-
- if isinstance(e, OrderedList):
- tag = "ol"
- if e.start and e.start != 1:
- attributes += f' start="{e.start}"'
- html_styles = {
- "Decimal": "1",
- "LowerRoman": "i",
- "UpperRoman:": "I",
- "LowerAlpha": "a",
- "UpperAlpha": "A"
- }
- if e.style and e.style != "DefaultStyle":
- attributes += f' type="{html_styles[e.style]}"'
- # FIXME: Delimeter styles
-
- if isinstance(e, Table):
- content_head = html(e.head, k, i, indent_level+1, indent_str)
- content_foot = html(e.foot, k, i, indent_level+1, indent_str)
- # FIXME: Fancy pandoc tables, using colspec
-
- if isinstance(e, TableCell):
- tag = "td"
- if e.colspan != 1:
- attributes += f' colspan="{e.colspan}"'
- if e.rowspan != 1:
- attributes += f' rowspan="{e.rowspan}"'
- aligns = {
- "AlignLeft": "left",
- "AlignRight": "right",
- "AlignCenter": "center"
- }
- if e.alignment and e.alignment != "AlignDefault":
- attributes += f' style="text-align: {aligns[e.alignment]}"'
-
- # The default which all non-overriding elements get generated by. This
- # includes elements, which were not explicitly mentioned in this function,
- # e. g. Strong
-
- if isinstance(e, Inline):
- return f'<{tag}{attributes}>{content_head}{html(e.content, k, i, 0, "") if hasattr(e, "_content") else ""}{e.text if hasattr(e, "text") else ""}{content_foot}{tag}>'
-
- out_str = ""
- if not isinstance(e, Plain):
- out_str += f"{indent_level*indent_str}<{tag}{attributes}>\n"
- out_str += content_head
- if hasattr(e, "_content"):
- if len(e.content) > 0 and isinstance(e.content[0], Inline):
- out_str += (indent_level+1)*indent_str
- out_str += html(e.content, k, i, indent_level+1, indent_str)
- if hasattr(e, "text"):
- out_str += e.text
- out_str += f"{content_foot}\n"
- if not isinstance(e, Plain):
- out_str += f"{indent_level*indent_str}{tag}>\n"
-
- return out_str
-
-
diff --git a/src/formatitko/tex.py b/src/formatitko/tex.py
deleted file mode 100644
index 74b6e6f..0000000
--- a/src/formatitko/tex.py
+++ /dev/null
@@ -1,270 +0,0 @@
-from panflute import *
-import os
-from typing import Union
-
-from .whitespace import NBSP
-from .elements import FQuoted
-from .util import inlinify
-from .context import Group
-from .images import ImageProcessor
-
-# Heavily inspired by: git://git.ucw.cz/labsconf2022.git
-def tex(e: Union[Element, ListContainer], i: ImageProcessor, indent_level: int=0, indent_str: str="\t") -> str:
-
- # `only` attribute which makes transformed elements appear only in tex
- # output or html output
- if hasattr(e, "attributes") and "only" in e.attributes and e.attributes["only"] != "tex":
- return ""
-
- if isinstance(e, ListContainer):
- return ''.join([tex(child, i, indent_level, indent_str) for child in e])
-
- # Bits from which the final element output is built at the end of this
- # function. Most elements override this by returning their own output.
- content_foot = ""
- content_head = ""
-
- arguments = ""
- open = "{"
- close = "}"
-
- tag = e.tag.lower()
-
- tags = {
- Header: "h"+chr(64 + e.level) if isinstance(e, Header) else "",
- }
- if type(e) in tags:
- tag = tags[type(e)]
-
- # These are also disabled in pandoc so they shouldn't appear in the AST at all.
- not_implemented = {
- Citation: True,
- Cite: True,
- Definition: True,
- DefinitionItem: True,
- DefinitionList: True
- }
- if type(e) in not_implemented:
- return f'% FIXME: {type(e)}s not implemented \n'
-
- # Elements which can be represented by a simple string
- simple_string = {
- NBSP: "~",
- Space: " ",
- Null: "",
- LineBreak: f"\\\\",
- SoftBreak: f" ",
- HorizontalRule: "\\hr\n\n"
- }
- if type(e) in simple_string:
- return simple_string[type(e)]
-
- # Simplest basic elements
- if isinstance(e, Str):
- return e.text.replace(" ", "~")
-
- if isinstance(e, Para):
- return tex(e.content, i, 0, "")+"\n\n"
-
- if isinstance(e, Span) or isinstance(e, Plain):
- return tex(e.content, i, 0, "")
-
- # Overriding elements with their own returns
- if isinstance(e, Image):
- url = e.url
-
- # TODO: This should use OutputGenerator's get_image_processor_args
- # Attributes → image processor args
- additional_args = {}
- if "file-width" in e.attributes:
- additional_args["width"] = int(e.attributes["file-width"])
- if "file-height" in e.attributes:
- additional_args["height"] = int(e.attributes["file-height"])
- if "file-quality" in e.attributes:
- additional_args["quality"] = int(e.attributes["file-quality"])
- if "file-dpi" in e.attributes:
- additional_args["dpi"] = int(e.attributes["file-dpi"])
-
- # The directory of the current file, will also look for images there.
- source_dir = e.attributes["source_dir"]
-
- _, ext = os.path.splitext(url)
- ext = ext[1:]
-
- # Conversions between various formats.
- if ext in ["pdf", "png", "jpeg"]:
- # Even supported elements have to be 'converted' because the
- # processing contains finding and moving them to the cache
- # directory.
- url = i.process_image(url, ext, source_dir, **additional_args)
- elif ext in ["svg"]:
- url = i.process_image(url, "pdf", source_dir, **additional_args)
- elif ext in ["epdf"]:
- url = i.process_image(url, "pdf", source_dir, **additional_args)
- elif ext in ["jpg"]:
- url = i.process_image(url, "jpeg", source_dir, **additional_args)
- else:
- url = i.process_image(url, "pdf", source_dir, **additional_args)
-
- url = i.find_image(url, [i.cache_dir])
- width = ""
- if "width" in e.attributes:
- width = e.attributes["width"]
- # 50% → 0.5\hsize
- if e.attributes["width"][-1] == "%":
- width = str(int(e.attributes["width"][:-1])/100) + "\\hsize"
- width = "width " + width
- return f'\\image{{{width}}}{{{url}}}'
-
- if isinstance(e, FQuoted):
- if e.style == "cs":
- if e.quote_type == "SingleQuote":
- return f'‚{tex(e.content, i, 0, "")}‘'
- elif e.quote_type == "DoubleQuote":
- return f'„{tex(e.content, i, 0, "")}“'
- elif e.style == "en":
- if e.quote_type == "SingleQuote":
- return f'‘{tex(e.content, i, 0, "")}’'
- elif e.quote_type == "DoubleQuote":
- return f'“{tex(e.content, i, 0, "")}”'
- else:
- if e.quote_type == "SingleQuote":
- return f'\'{tex(e.content, i, 0, "")}\''
- elif e.quote_type == "DoubleQuote":
- return f'"{tex(e.content, i, 0, "")}"'
- else:
- return f'"{tex(e.content, i, 0, "")}"'
-
- if isinstance(e, Code):
- return f'\\verb`{e.text.replace("`", "backtick")}`'
-
- if isinstance(e, Figure):
- return f'\\figure{{{tex(e.content, i, indent_level+1, indent_str)}}}{{{tex(e.caption, i, indent_level+1, indent_str)}}}\n\n'
-
- # Figure caption
- if isinstance(e, Caption):
- if inlinify(e) is not None:
- return f'\\figcaption{{{tex(e.content, i, 0, "")}}}'
-
- if isinstance(e, Math):
- if e.format == "DisplayMath":
- return f'$${e.text}$$\n'
- else:
- return f'${e.text}$'
-
- # Footnote
- if isinstance(e, Note):
- tag = "fn"
- if inlinify(e) is not None:
- return f'\\fn{{{tex(inlinify(e), i, 0, "")}}}'
-
- if isinstance(e, Table):
- aligns = {
- "AlignLeft": "\\quad#\\quad\\hfil",
- "AlignRight": "\\quad\\hfil#\\quad",
- "AlignCenter": "\\quad\\hfil#\\hfil\\quad",
- "AlignDefault": "\\quad#\\quad\\hfil"
- }
- text = "\strut"+"&".join([aligns[col[0]] for col in e.colspec])+"\cr\n"
- text += tex(e.head.content, i, 0, "")
- text += "\\noalign{\\hrule}\n"
- text += tex(e.content[0].content, i, 0, "")
- text += "\\noalign{\\hrule}\n"
- text += tex(e.foot.content, i, 0, "")
- return "\\vskip1em\n\\halign{"+text+"}\n\\vskip1em\n"
- # FIXME: Implement rowspan
-
- if isinstance(e, TableRow):
- return "&".join([("\\multispan"+str(cell.colspan)+" " if cell.colspan > 1 else "")+tex(cell.content, i, 0, "") for cell in e.content])+"\cr\n"
-
- if isinstance(e, RawInline):
- if e.format == "tex":
- return e.text
- else:
- return ""
-
- if isinstance(e, RawBlock):
- if e.format == "tex":
- return f'{e.text}\n'
- else:
- return ""
-
- # See https://pandoc.org/MANUAL.html#line-blocks
- if isinstance(e, LineBlock):
- return f'{tex(e.content, i, indent_level+1, indent_str)}\n'
-
- if isinstance(e, LineItem):
- return tex(e.content, i, 0, "") + ("\\\\\n" if e.next else "\n")
-
- if type(e) is Div:
- return f'{tex(e.content, i, indent_level+1, indent_str)}'
-
- if isinstance(e, Doc):
- return tex(e.content, i, indent_level, indent_str)+"\n\\bye" # Is having the \bye a bad idea here?
-
-
- # Non-overriding elements, they get generated using the template at the end
- # of this function
- if isinstance(e, BulletList):
- tag = "list"
- open = ""
- arguments = "{o}"
- close = "\\endlist"
-
- elif isinstance(e, OrderedList):
- tag = "list"
- open = ""
- styles = {
- "DefaultStyle": "n",
- "Decimal": "n",
- "LowerRoman": "i",
- "UpperRoman:": "I",
- "LowerAlpha": "a",
- "UpperAlpha": "A"
- }
- style = styles[e.style]
- delimiters = {
- "DefaultDelim": f"{style}.",
- "Period": f"{style}.",
- "OneParen": f"{style})",
- "TwoParens": f"({style})"
- }
- style = delimiters[e.delimiter]
- arguments = f"{{{style}}}"
- close = "\\endlist"
- # FIXME: Starting number of list
-
- elif isinstance(e, ListItem):
- tag = ":"
-
- elif isinstance(e, Link):
- if len(e.content) == 1 and isinstance(e.content[0], Str) and e.content[0].text == e.url:
- tag = "url"
- else:
- tag = "linkurl"
- arguments = f'{{{e.url}}}'
-
- elif isinstance(e, Group):
- tag = "begingroup"
- open = ""
- if "lang" in e.metadata and e.metadata["lang"] is not None:
- open = "\\language"+e.metadata["lang"]
- close = "\\endgroup"
-
- # The default which all non-overriding elements get generated by. This
- # includes elements, which were not explicitly mentioned in this function,
- # e. g. Strong, Emph...
-
- if isinstance(e, Inline):
- return f'\\{tag}{arguments}{open}{content_head}{tex(e.content, i, 0, "") if hasattr(e, "_content") else ""}{e.text if hasattr(e, "text") else ""}{content_foot}{close}'
-
- out_str = ""
- out_str = f"\\{tag}{arguments}{open}\n"
- out_str += content_head
- if hasattr(e, "_content"):
- out_str += tex(e.content, i, indent_level+1, indent_str)
- if hasattr(e, "text"):
- out_str += e.text
- out_str += f"{content_foot}\n{close}\n\n"
-
- return out_str
diff --git a/src/formatitko/transform.py b/src/formatitko/transform.py
deleted file mode 100644
index 69679d9..0000000
--- a/src/formatitko/transform.py
+++ /dev/null
@@ -1,176 +0,0 @@
-from panflute import Element, Div, Span, Quoted, Image, CodeBlock, Str, MetaInlines, MetaString, MetaBool, RawBlock
-import re
-import os
-
-# Import local files
-from .whitespace import Whitespace, NBSP, bavlna
-from .util import nullify, import_md
-from .context import Context, BlockGroup
-from .command import Command, BlockCommand, InlineCommand
-from .command_util import handle_command_define, parse_command
-from .elements import FQuoted
-
-
-import warnings
-warnings.warn("The transform function has been deprecated, is left only for reference and will be removed in future commits. TransformProcessor should be used in its place.", DeprecationWarning)
-
-# This is where tha magic happens. This function transforms a single element,
-# to transform the entire tree, panflute's walk should be used.
-def transform(e: Element, c: Context) -> Element:
-
- warnings.warn("The transform function has been deprecated, is left only for reference and will be removed in future commits. TransformProcessor should be used in its place.", DeprecationWarning)
- # Determine if this space should be non-breakable. See whitespace.py.
- if isinstance(e, Whitespace) and bavlna(e, c):
- e = NBSP()
-
- if hasattr(e, "attributes"):
- # `if` attribute. Only show this element if flag is set.
- if "if" in e.attributes:
- if not c.is_flag_set(e.attributes["if"]):
- return nullify(e)
- # `ifn` attribute. Only show this element if flag is NOT set
- if "ifn" in e.attributes:
- if c.is_flag_set(e.attributes["ifn"]):
- return nullify(e)
-
- # There are multiple ways to call a command so we turn it into a
- # unified element first and then call it at the end. This handles the
- # []{c=commandname} and
- # :::{c=commandname}
- # :::
- # syntax.
- if (isinstance(e, Div) or isinstance(e, Span)) and "c" in e.attributes:
- if isinstance(e, Div):
- e = BlockCommand(*e.content, identifier=e.identifier, classes=e.classes, attributes=e.attributes)
- else:
- e = InlineCommand(*e.content, identifier=e.identifier, classes=e.classes, attributes=e.attributes)
-
- # Isolated subdocuments using Group and a different Context. Can be
- # separate files (using attribute `partial`) or be inline using the
- # following syntax:
- # ```markdown {.group}
- # * file content *
- # ```
- # Both can contain their own metadata in a FrontMatter (YAML header)
- if (isinstance(e, Div) and "partial" in e.attributes)\
- or (isinstance(e, CodeBlock) and "markdown" in e.classes and "group" in e.classes):
- if isinstance(e, Div):
- if not c.trusted: # If we're in an untrusted context, we shouldn't allow inclusion of files outside the PWD.
- full_path = os.path.abspath(c.dir + "/" + e.attributes["partial"])
- pwd = os.path.abspath(".")
- if os.path.commonpath([full_path, pwd]) != os.path.commonpath([pwd]):
- return nullify(e)
- text = open(c.dir + "/" + e.attributes["partial"], "r").read()
- path = c.dir + "/" + e.attributes["partial"]
- else:
- text = e.text
- path = c.path
- if "type" in e.attributes and e.attributes["type"] in ["tex", "html"]:
- e = RawBlock(text, e.attributes["type"])
- else:
- includedDoc = import_md(text)
- trusted = True
- if "untrusted" in e.attributes and (e.attributes["untrusted"] == True or e.attributes["untrusted"] == 'True'):
- trusted = False
- if not c.trusted:
- trusted = False
- nContext = Context(includedDoc, path, c, trusted=trusted)
- language = includedDoc.get_metadata("lang")
- includedDoc = includedDoc.walk(transform, nContext)
- e = BlockGroup(*includedDoc.content, context=nContext, metadata={"lang": language})
-
- # Transform panflute's Quoted to custom FQuoted, see above.
- if isinstance(e, Quoted):
- quote_styles = {
- "cs": "cs",
- "en": "en",
- "sk": "cs",
- None: None
- }
- e = FQuoted(*e.content, quote_type=e.quote_type, style=quote_styles[c.get_metadata("lang")])
-
- if isinstance(e, Image):
- # Pass down the directory of the current source file for finding image
- # files.
- e.attributes["source_dir"] = c.dir
- # Pass down "no-srcset" metadatum as attribute down to images.
- if not "no-srcset" in e.attributes:
- e.attributes["no-srcset"] = c.get_metadata("no-srcset") if c.get_metadata("no-srcset") is not None else False
-
- # 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"
- e.attributes["noclasses"] = False
- # I think this is supposed to enable inline styles for highlighting when the style differs from the document, but it clearly doesn't work. a) HTML_generator never accesses it and b) Only the top-level document contains a style so you have to ask the top level context, not the current context.
- else:
- e.attributes["noclasses"] = True
-
- # Execute python code inside source code block. Works the same as commands.
- # Syntax:
- # ```python {.run}
- # print("woo")
- # ```
- if isinstance(e, CodeBlock) and hasattr(e, "classes") and "python" in e.classes and "run" in e.classes:
- if not c.trusted:
- return nullify(e)
- command_output = parse_command(e.text)(BlockCommand(), c)
- e = BlockCommand().replaceSelf(*([] if command_output is None else command_output))
- e = e.walk(transform, c)
-
- # Command defines for calling using BlockCommand and InlineCommand. If
- # redefine is used instead of define, the program doesn't check if the
- # command already exists.
- # Syntax:
- # ```python {define=commandname}
- # print(wooo)
- # ```
- 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):
- if not c.trusted:
- return nullify(e)
- e = handle_command_define(e, c)
-
- ## Shorthands
- # Shorter (and sometimes the only) forms of certain features
- if isinstance(e, Span) and len(e.content) == 1 and isinstance(e.content[0], Str):
- ## Handle special command shorthand [!commandname]{}
- if re.match(r"^![\w.]+$", e.content[0].text):
- e = InlineCommand(identifier=e.identifier, classes=e.classes, attributes={**e.attributes, "c": e.content[0].text[1:]})
-
- ## Handle import [#path/file.md]{}
- # This is the exact opposite of partials. We take the commands, flags
- # and metadata but drop the content.
- elif re.match(r"^#.+$", e.content[0].text):
- importedDoc = import_md(open(c.dir + "/" + e.content[0].text[1:], "r").read())
- importedDoc.walk(transform, c)
- return nullify(e)
-
- ## Handle metadata print [$key1.key2]{}
- # This is a shorthand for just printing the content of some metadata.
- elif re.match(r"^\$[\w.]+$", e.content[0].text):
- val = c.get_metadata(e.content[0].text[1:], False)
- if isinstance(val, MetaInlines):
- e = Span(*val.content)
- e = e.walk(transform, c)
- elif isinstance(val, MetaString):
- e = Span(Str(val.string))
- elif isinstance(val, MetaBool):
- e = Span(Str(str(val.boolean)))
- else:
- raise TypeError(f"Cannot print value of metadatum '{e.content[0].text[1:]}' of type '{type(val)}'")
-
- ## Execute commands
- # panflute's walk function transforms the children first, then the root
- # element, so the content the command receives is already transformed.
- # The output from the command is then transformed manually again.
- if isinstance(e, Command):
- if not c.get_command(e.attributes["c"]):
- raise NameError(f"Command not defined '{e.attributes['c']}'.")
- command_output = c.get_command(e.attributes["c"])(e, c)
- e = e.replaceSelf(*command_output)
- e = e.walk(transform, c)
-
- return e