Files
hrtime/md.py
2026-01-04 04:08:32 -05:00

150 lines
4.2 KiB
Python
Executable File

#!/bin/python3
# hrtime - transgender research website
# Copyright (C) 2025 Olive <hello@grasswren.net>
# see LICENCE file for licensing information
import re
import sys
def ch(st: str) -> str:
st = re.sub(r'&', r'&amp;', st)
st = re.sub(r'>', r'&gt;', st)
st = re.sub(r'<', r'&lt;', st)
return st
def qch(st: str) -> str:
return re.sub('\'', r'&apos;', ch(st))
def mdh(line: str) -> str:
ret = ''
while len(line) > 0:
match = re.match(r'!\[(.*?)\]\((.*?)\)', line)
if match != None:
line = line[match.span()[1]:]
ret += f"<span class='n' title='{qch(match.group(2))}'>" + \
f'{ch(match.group(1))}</span>'
continue
match = re.match(r'\[(.*?)\]\(([^ ]*)\)', line)
if match != None:
line = line[match.span()[1]:]
ret += f"<a href='{qch(match.group(2))}' target='_blank'" \
+ f'>{ch(match.group(1))}</a>'
continue
match = re.match(r'`(.)(.*?)`', line)
if match != None:
line = line[match.span()[1]:]
ret += r"<code" + (f" class='{match.group(1)}'" if match.group(1) \
!= '/' else '') + f'>{ch(match.group(2))}</code>'
continue
ret += ch(line[0])
line = line[1:]
ret = re.sub(r'NOBREAK', r'&NoBreak;', ret)
return ret
def md(line: str) -> str:
# allows '|' and '||' escaping to work
ret, do = '', True
for sec in line.strip().split('|'):
if len(sec) == 0:
ret += '|'
else:
ret += mdh(sec) if do else sec
do = not do
return ret
def media(line: str):
file, alt = tuple(line.strip().split('|'))
file = qch(file)
if file[-5:] in ('.webp'):
print(f"<img src='{file}' alt='{qch(alt)}'>")
if file[-4:] in ('.mp4'):
print('<video controls>')
print(f"<source src='{file}' type='video/mp4' alt='{qch(alt)}'>")
print('</video>')
if file[-4:] in ('.pdf'):
print(f"<object data='{file}' type='application/pdf' height='80%'>")
print(f"<a href='{file}'>{ch(alt)}</a>")
print('</object>')
def doc(lines: list[str]):
head = ''
with open('head.html', 'r') as file:
head = file.read()
lines[0] = lines[0].strip()
if len(lines[0]) > 0:
lines[0] = '' + lines[0]
head = re.sub(r'TITLE', lines[0], head, count=2)
print(head, end='')
lines = lines[1:]
mode=''
for line in lines:
if line[1:4] == ' ':
if mode != '</code></pre>':
if line[0] != '/':
cls = f" class='{line[0]}'"
print(f'<pre><code{cls}>', end='')
mode = '</code></pre>'
print(ch(line[4:].rstrip()))
continue
elif line[:2] == ' ':
if mode != '</ul>':
print("<ul class='l'>")
mode = '</ul>'
print(f'<li>{md(line[2:])}</li>')
continue
elif line[:2] == '- ':
if mode != '</ul>':
print('<ul>')
mode = '</ul>'
print(f'<li>{md(line[2:])}</li>')
continue
if mode != '':
print(mode)
mode = ''
if len(line) == 1:
print('</section>\n<section>')
elif line[:2] == '# ':
print(f'<h1>{md(line[2:])}</h1>')
elif line[:3] == '## ':
print(f'<h2>{md(line[3:])}</h2>')
elif line[:2] == '! ':
media(line[2:])
elif line[:2] == '@ ':
title, link, desc, date = tuple(line[2:].split('|'))
print('<article>\n<div>')
print(f"<h1><a href='{qch(link)}'>{md(title)}</a></h1>")
print('</div>\n<div>')
print(f'<p>{md(desc)}</p>')
print(f'<p>(<time>{date.strip()}</time>)</p>')
print('</div>\n</article>')
else:
print('<p>' + md(line) + '</p>')
if mode != '':
print(mode)
with open('foot.html', 'r') as file:
print(file.read(), end='')
if __name__ == '__main__':
if len(sys.argv) != 2:
print('usage: md [file]')
else:
with open(sys.argv[1], 'r') as file:
doc(list(file))