eorg/eorg/generate.py

154 lines
4.2 KiB
Python

import re
from html import escape
from io import StringIO
from eorg.const import Token, ESCAPE
from eorg import tokens
from eorg.tokens import Token
from pygments import highlight
from pygments.util import ClassNotFound
from pygments.lexers import PythonLexer
from pygments.lexers import get_lexer_by_name
from pygments.formatters import HtmlFormatter
def src(doc, code, cls="", root=True):
try:
lexer = get_lexer_by_name(code.attrs.get("language", "shell"))
except ClassNotFound as e:
lexer = get_lexer_by_name(code.attrs.get("language", "text"))
return highlight(code.value, lexer, HtmlFormatter(linenos=True))
def img(doc, item, cls="", root=True):
caption = doc.previous(tokens.CAPTION)
text = ""
if item.attrs:
caption = item.attrs.get('caption')
if caption:
text = f'<p class="center-align">{caption}</p>'
return f'<img{cls} style="margin:auto;" src="{item.value[0]}" alt="{item.value[1]}" />{text}'
def link(doc, item, cls="", root=True):
return f'<a {cls} style="margin:auto;" href="{item.value[0]}">{item.value[1]}</a>'
def parse_list_html(doc, token, cls="", root=True):
response = StringIO()
response.write(f"<p{cls}>")
for item in token.value:
response.write(handle_token(doc, item, False))
response.write(f"</p>")
response.seek(0)
return response.read()
def parse_bullets_html(doc, token, cls="", root=True):
response = StringIO()
bullet = 'ul'
if token.value[0].isdigit():
bullet = 'ol'
response.write(f"<{bullet}{cls}>")
for row in token.value.split("\n"):
if row:
text = ''
if row[0] in ['-', '+']:
text = re.sub(r'^\s*[-|+]+\s*', '', row, 1)
if row[0].isdigit():
text = re.sub(r'^\s*[0-9]+\.*\s*', '', row, 1)
response.write(f"<li class=\"collection-item\">{text}</li>")
response.write(f"</{bullet}>")
response.seek(0)
return response.read()
def parse_text_html(doc, token, cls="", root=True):
return f"{token.value}"
def blockquote(doc, token, cls="", root=True):
return "<blockquote%s>%s</blockquote>\n" % (
cls,
escape(token.value).replace("\n", "<br />"),
)
def header(doc, item, cls="", root=True):
depth = 1
if item.attrs:
depth = item.attrs.get("depth", depth)
depth += 1
return "<h%s%s>%s</h%s>\n" % (depth, cls, item.value, depth)
def table(doc, item, cls="", root=True):
tbl = "<tbody>"
tblhead = ""
newrow = None
for row in item.value.split("\n"):
if newrow:
if row.startswith("|-"):
tblhead += (
"<thead><th>"
+ "</th><th>".join(newrow)
+ "</th></thead>\n"
)
else:
tbl += f"<tr><td>" + "</td><td>".join(newrow) + "</td></tr>\n"
newrow = filter(None, row.split("|"))
if row.startswith("|-"):
newrow = None
tbl += "</tbody>"
return "<table%s>%s%s</table>\n" % (cls, tblhead, tbl)
builddoc = {
tokens.HEADER: (header, None),
tokens.IMAGE: (img, "materialboxed center-align responsive-img"),
tokens.LINK: (link, None),
tokens.BOLD: ("b", None),
tokens.UNDERLINED: ("u", None),
tokens.ITALIC: ("i", None),
tokens.VERBATIM: ("code", None),
tokens.LIST: (parse_list_html, "flow-text"),
tokens.TEXT: (parse_text_html, "flow-text"),
tokens.BULLET: (parse_bullets_html, "browser-default"),
tokens.SOURCE: (src, None),
tokens.EXAMPLE: (blockquote, None),
tokens.RESULTS: (blockquote, None),
tokens.TABLE: (table, "responsive-table striped"),
}
def handle_token(doc, item, root=False):
response = StringIO()
match = builddoc.get(item.token)
if not match:
return ""
tag, cls = match
if cls:
cls = f' class="{cls}"'
else:
cls = ""
if callable(tag):
return tag(doc, item, cls, root=root)
else:
return "<%s%s>%s</%s>\n" % (tag, cls, item.value, tag)
def html(doc):
response = StringIO()
for item in doc:
response.write(handle_token(doc, item, True))
response.seek(0)
return response