about summary refs log tree commit diff stats
path: root/wikme.py
blob: 2df5a0346e27652dce77712b5372ef436793dc3e (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
import os
import re
import argparse
import markdown
import datetime
import subprocess
import shutil
from typing import Optional

def kebab_case(s: str) -> str:
    return re.sub(r"[ _]", "-", s).lower()

def get_title(filename: str, content: Optional[str] = None) -> str:
    if content:
        # Check for a top-level header in the content
        top_level_header = re.search(r"^#\s(.+)$", content, re.MULTILINE)
        if top_level_header:
            return top_level_header.group(1).strip()

    # Extract the inferred title from the filename
    title = filename.replace(".md", "").replace("_", " ")
    return title.capitalize()

def parse_wikilinks(content: str) -> str:
    # Convert wikilinks with tildes and custom titles
    content = re.sub(r'\[\[(~[^|\]]+?)\|([^|\]]+?)\]\]', r'<a href="/\1">\2</a>', content)

    # Convert wikilinks with tildes and without custom titles
    content = re.sub(r'\[\[(~[^|\]]+?)\]\]', r'<a href="/\1">\1</a>', content)

    # Convert regular wikilinks with custom titles
    content = re.sub(r'\[\[([^~|\]]+?)\|([^~|\]]+?)\]\]', lambda match: f'<a href="./{kebab_case(match.group(1))}.html">{match.group(2)}</a>', content)

    # Convert regular wikilinks without custom titles
    content = re.sub(r'\[\[([^~|\]]+?)\]\]', lambda match: f'<a href="./{kebab_case(match.group(1))}.html">{match.group(1)}</a>', content)

    return content

def render_template(template: str, title: str, content: str, last_edited: str) -> str:
    # Insert title, content, and last_edited into the template
    rendered = template.replace("{{ title }}", title)
    rendered = rendered.replace("{{ content }}", content)
    rendered = rendered.replace("{{ last_edited }}", last_edited)
    return rendered

def get_last_edited(path: str) -> str:
    try:
        # Attempt to get the last Git commit date of the file
        last_edited = subprocess.check_output(
            ["git", "log", "-1", "--format=%cd", "--date=local", path])
        return last_edited.decode("utf-8").strip()
    except Exception:
        # Fallback to the file's modified timestamp
        return str(datetime.datetime.fromtimestamp(os.path.getmtime(path)))

def main(input_folder: str, output_folder: str, template_file: str):
    # Load the template
    with open(template_file, "r") as template_f:
        template = template_f.read()

    # Go through each markdown file
    for root, dirs, files in os.walk(input_folder):
        for file in files:
            if file.endswith(".md"):
                # Process the markdown file
                input_file = os.path.join(root, file)
                output_subfolder = os.path.join(
                    output_folder, os.path.relpath(root, input_folder))
                output_file = os.path.join(
                    output_subfolder, f"{kebab_case(file.replace('.md', ''))}.html")

                # Read the source file
                with open(input_file, "r") as source:
                    markdown_content = source.read()
                    html_content = markdown.markdown(
                        parse_wikilinks(markdown_content), extensions=['codehilite']
                    )

                # Create the output folder if needed
                if not os.path.exists(output_subfolder):
                    os.makedirs(output_subfolder)

                # Render the result
                title = get_title(file, markdown_content)
                last_edited = get_last_edited(input_file)
                rendered_content = render_template(template, title, html_content, last_edited)

                # Save the rendered HTML file
                with open(output_file, "w") as output_f:
                    output_f.write(rendered_content)

def cmd():
    parser = argparse.ArgumentParser(
        description="Convert a folder of Markdown files into a simple wiki-style website.")
    parser.add_argument('--input', dest='input_folder',
                        required=True, help='input folder containing Markdown files')
    parser.add_argument('--output', dest='output_folder',
                        required=True, help='output folder for generated HTML files')
    parser.add_argument('--template', dest='template_file',
                        required=True, help='HTML template for the generated files')
    args = parser.parse_args()

    main(args.input_folder, args.output_folder, args.template_file)

if __name__ == "__main__":
    cmd()