#!/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 "%s" % ( 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()