#!/usr/bin/env python3
from pygments import highlight
from pygments.lexers import get_lexer_by_name
from pygments.formatters import HtmlFormatter
from urllib.parse import urlparse
import urllib.parse
import lxml.html
import argparse
import database
import mistune
import houdini
import jinja2
import parser
import shutil
import sys
class MyRenderer(mistune.HTMLRenderer):
def blockcode(self, text, lang):
try:
lexer = get_lexer_by_name(lang, stripall=True)
except ClassNotFound:
lexer = None
if lexer:
formatter = HtmlFormatter()
return highlight(text, lexer, formatter)
return '\n
{}
\n'.format(houdini.escape_html(text.strip()))
def block_quote(self, content):
content = content[3:-5]
out = '\n'
for line in houdini.escape_html(content.strip()).split("\n"):
out += '\n{}
'.format(line)
return out + '\n
'
def image(self, link, text, title):
return "
" % (
urlparse(link)._replace(query='').geturl(), text, link
)
def heading(self, text, level):
hash_ = urllib.parse.quote_plus(text)
return "%s " % (
level, hash_, text, hash_, level
)
def get_thought_from_id(db, id_):
title, datetime, markdown, redirect, category_name = db.get_thought(id_)
html, headers = parse_text(markdown)
return title, datetime, redirect, category_name, html, headers
def parse_file(path):
with open(path, "r") as f:
unformatted = f.read()
return parse_text(unformatted)[0]
def parse_text(unformatted):
md = mistune.create_markdown(
renderer = MyRenderer(),
plugins = ["strikethrough", "table", "url", "task_lists", "def_list"]
)
html = md(unformatted)
if html == "":
return "", ""
return html, get_headers(html)
def get_headers(html):
root = lxml.html.fromstring(html)
headers = []
thesmallestlevel = 7
for node in root.xpath('//h1|//h2|//h3|//h4|//h5|//h6'):
level = int(node.tag[-1])
if level < thesmallestlevel:
thesmallestlevel = level
headers.append((
urllib.parse.unquote_plus(node.attrib["id"]),
level,
"#%s" % node.attrib["id"])
)
headers = [(i[0], i[1] - thesmallestlevel, i[2]) for i in headers]
md_template = jinja2.Template("""
{% for text, depth, link in contents %}
{{ " " * depth }} - [{{ text }}]({{ link }})
{% endfor %}
""")
return mistune.html(md_template.render(contents = headers))
def main():
p = argparse.ArgumentParser()
subparse = p.add_subparsers(help = "sub-command help")
save_parser = subparse.add_parser("save", help = "Add a markdown file to the database")
echo_parser = subparse.add_parser("echo", help = "Print markdown render to stdout")
update_parser = subparse.add_parser("update", help = "Replace a markdown file")
export_parser = subparse.add_parser("export", help = "Export a database markdown file to disk")
list_parser = subparse.add_parser("list", help = "List all the markdowns in the database")
for s in [save_parser, echo_parser, update_parser]:
s.add_argument(
"-m", "--markdown",
help = "Path to a markdown file",
type = str,
required = True
)
for s in [save_parser]:
s.add_argument(
"-t", "--title",
help = "Article title",
type = str,
required = True
)
s.add_argument(
"-c", "--category",
help = "Article category",
type = str,
required = True
)
for s in [export_parser, update_parser]:
s.add_argument(
"-i", "--id",
help = "Article's id",
type = int,
required = True
)
export_parser.add_argument(
"-o", "--out",
help = "Path to write the markdown file to",
type = str,
required = True
)
args = vars(p.parse_args())
try:
verb = sys.argv[1]
except IndexError:
print("Error! No verb specified. Nothing to do... Exiting...")
exit()
if verb in ["save", "export", "update", "list"]:
with database.Database() as db:
match verb:
case "save":
if db.add_category(args["category"]):
print("Added category.")
with open(args["markdown"], "r") as f:
db.add_thought(args["title"], f.read(), args["category"])
print("Added thought.")
case "export":
with open(args["out"], "w") as f:
f.writelines(db.get_thought(args["id"])[-3])
print(f"Written to {args["out"]}")
case "update":
with open(args["markdown"], "r") as f:
db.update_thought_markdown(args["id"], f.read())
print("Updated thought.")
case "list":
for id_, title, datetime, category in db.get_all_thoughts():
print(f"{id_}, {title}, {datetime}, {category}")
case _:
print("Error! Unknown verb... Exiting...")
exit()
elif verb == "echo":
print(parse_file(args["markdown"]))
if __name__ == '__main__':
main()