aboutsummaryrefslogtreecommitdiffstats
path: root/parser.py
blob: 8677342fbe9240b8befc5e7536d32c72ad4c4a97 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import argparse
from urllib.parse import urlparse
import webbrowser
import app
import re
import os

HEADER_INCREMENTER = 1
IMAGE_TYPES = [".png", ".jpg"]

def parse_file(path):
    with open(path, "r") as f:
        unformatted = f.read()

    formatted = parse_headers(unformatted)
    formatted = parse_asteriscs(formatted)
    formatted = parse_links(formatted)
    formatted = add_linebreaks(formatted)

    return '{% extends "template.html" %}\n{% block content %}\n' + formatted + '\n{% endblock %}'

def parse_headers(test_str):
    regex = r"^#{1,5}\s\w.*$"
    matches = re.finditer(regex, test_str, re.MULTILINE)
    offset = 0

    for match in matches:
        # work out if its h2, h3 etc. from the number of #s
        headerNo = len(match.group().split(" ")[0]) + HEADER_INCREMENTER
        
        replacement = "<h%i>%s</h%i>" % (headerNo, " ".join(match.group().split(" ")[1:]), headerNo)

        #don't use .replace() in the unlikely case the the regex hit appears in a block
        test_str = test_str[:match.start()+offset] + replacement + test_str[match.end()+offset:]
        #replacing the hits fucks up the indexes, accommodate for this
        offset += (len(replacement) - (match.end() - match.start()))

    return test_str

def parse_asteriscs(test_str):
    regex = r"(?<!\\)\*{1,3}.*?\*{1,3}"
    matches = re.finditer(regex, test_str, re.MULTILINE)
    offset = 0

    for match in matches:
        if len(re.findall(r"\*{1,3}.*?\\\*{1,3}", match.group())) == 0:     #need to find a way of doing this with regexes
            if match.group().startswith(re.findall(r"\w\*{1,3}", match.group())[0][1:]):    #this too
                if match.group().startswith("***"):
                    replacement = "<b><i>%s</i></b>" % (match.group()[3:-3])
                elif match.group().startswith("**"):
                    replacement = "<b>%s</b>" % (match.group()[2:-2])
                else:
                    replacement = "<i>%s</i>" % (match.group()[1:-1])
        
                test_str = test_str[:match.start()+offset] + replacement + test_str[match.end()+offset:]
                offset += (len(replacement) - (match.end() - match.start()))

    return test_str

def parse_links(test_str):
    regex = r"(?<!\\)\[.*?\]\(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+\)"
    matches = re.finditer(regex, test_str, re.MULTILINE)
    offset = 0

    for match in matches:
        s = match.group().split("(")
        label = s[0][1:-1]
        url = s[1][:-1]

        if os.path.splitext(urlparse(url).path)[1] in IMAGE_TYPES:
            replacement = "<img alt='%s' src=%s>" % (label, url)
        else:
            replacement = "<a href=%s>%s</a>" % (url, label)

        test_str = test_str[:match.start()+offset] + replacement + test_str[match.end()+offset:]
        offset += (len(replacement) - (match.end() - match.start()))

    return test_str

def add_linebreaks(test_str):
    return re.sub(r"^$", "<br><br>", test_str, 0, re.MULTILINE)

def preview_markdown(path, title):
    def startBrowser():
        webbrowser.get("firefox").open("http://localhost:5000/preview")
        del os.environ["PREVIEW"]
        del os.environ["PREVIEW_TITLE"]

    os.environ["PREVIEW"] = parse_file(path)
    os.environ["PREVIEW_TITLE"] = title

    import threading
    threading.Timer(1.25, startBrowser ).start()
    
    app.app.run(host = "0.0.0.0", debug = True)

def main():
    p = argparse.ArgumentParser()
    p.add_argument(
        "-m", "--markdown",
        help = "Path to a markdown file",
        required = True,
        type = str
    )
    p.add_argument(
        "-t", "--title",
        help = "Article title",
        required = True,
        type = str
    )
    p.add_argument(
        "-p", "--preview",
        help = "Preview markdown rendering",
        action='store_true'
    )
    args = vars(p.parse_args())
    if args["preview"]:
        preview_markdown(args["markdown"], args["title"])
    else:
        print(parse_file(args["markdown"]))

if __name__ == "__main__":
    main()