gempher/gem2html.py

77 lines
2.3 KiB
Python

import random, functools, os
from html import escape
_rand_n = lambda: functools.reduce(lambda x, y: (x<<8)+y,os.urandom(4))
ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyz"
USED_IDS = set()
def rand_id():
n = _rand_n()
id = ""
while n>0:
n, index = divmod(n,len(ALPHABET))
id = ALPHABET[index]+id
if id in USED_IDS: return rand_id()
return id
def gem2html(content,link_callback=lambda url, text: (url, text)):
lines = content.splitlines()
out = "<body>\n"
pre = False
pre_alt = False
for line in lines:
if pre:
if line[:3]=="```":
pre=False
out+="</pre>\n"
if pre_alt:
out+="</figure>\n"
pre_alt=False
else:
out+=escape(line)+"\n"
else:
if line[:3]=="```":
if len(line)>3:
cap_id = rand_id()
out+="<figure role='img' aria-captionedby='{0}'><figcaption id='{0}' style='clip: rect(0 0 0 0); clip-path: inset(50%); height: 1px; overflow: hidden; position: absolute; white-space: nowrap; width: 1px;'>{1}</figcaption>\n".format(cap_id,escape(line[3:]))
pre_alt = True
pre = True
out+="<pre>\n"
elif line.startswith("#"):
if line[:3]=="###":
out+="<h3>{}</h3>".format(escape(line[3:].strip()))
elif line[:2]=="##":
out+="<h2>{}</h2>".format(escape(line[2:].strip()))
elif line[:1]=="#":
out+="<h1>{}</h1>".format(escape(line[1:].strip()))
elif line.startswith("* "):
out += "<ul>\n<li>{}</li>\n</ul>\n".format(escape(line[1:].strip()))
# combine consecutive unordered list items into one unordered list
out = out.replace("</ul>\n<ul>\n","")
elif line.startswith("=>"):
parts = line.split(None,2)
try:
url, text = parts[1:]
except ValueError:
try:
url=parts[1]
text=parts[1]
except:
# no link content at all
# just put a literal => in there
out+="<p></p>".format(escape(parts[0]))
continue
# now comes the fun part, use the link callback to mutilate these
url, text = link_callback(url, text)
# and now render
out+="<p><a href='{}'>{}</a></p>".format(escape(url),escape(text))
elif line.startswith(">"):
out+="<blockquote><p>{}</p></blockquote>".format(escape(line))
else: # any other line is a text line
if line:
out+="<p>{}</p>".format(escape(line))
else:
out+="<p><br></p>"
out+="</body>"
return out