#!/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 ENV = jinja2.Environment(loader=jinja2.FileSystemLoader('templates')) class MyRenderer(mistune.HTMLRenderer): def block_code(self, code, info=None): if not info: return '\n
{}
\n'.format(houdini.escape_html(code.strip())) lexer = get_lexer_by_name(info, stripall=True) formatter = HtmlFormatter() return highlight(code, lexer, formatter) 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 [#]\n" % ( 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"])) 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()