OSDN Git Service

Add a document generating script.
[sawarabi-fonts/sawarabi-fonts.git] / html / bin / gen.py
1 import argparse
2 import re
3 import lxml.html as html
4 import markdown
5
6 class Section:
7     def __init__(self, name: str):
8         self._name = name
9         self._buffer = []
10         self._html = None
11
12     def append(self, line: str):
13         self._buffer.append(line)
14
15     @property
16     def buffer(self) -> str:
17         if not self._html:
18             buf = "\n".join(self._buffer)
19             self._html = markdown.markdown(buf)
20
21         return self._html
22
23     @property
24     def name(self) -> str:
25         return self._name
26
27 class Document:
28     def __init__(self):
29         self._props = {}
30         self._items = {}
31
32     @property
33     def property(self) -> dict:
34         return self._props
35
36     def __getitem__(self, key: str) -> dict:
37         return self._items[key]
38
39     def __setitem__(self, key: str, value: str):
40         self._items[key] = value
41
42     def __str__(self) -> str:
43         d = dict({'property': self._props}, **self._items)
44         return str(d)
45
46 class Parser:
47     def __init__(self, clazz, rules = {}):
48         self._item_class = clazz
49         self._doc = Document()
50         self._item = None
51         self.rules = {
52             re.compile(v): getattr(self, k) for k, v in rules.items()
53         }
54
55     def parse(self, lines):
56         for line in lines:
57             self._parse_line(line)
58         self.flash()
59
60         return self._doc
61
62     def flash(self):
63         if self._item:
64             self._doc[self._item.name] = self._item.buffer
65
66     def on_property(self, buf: tuple):
67         key, value = buf
68         self._doc.property[key] = value
69
70     def on_section_title(self, value: tuple):
71         title = value[0]
72         self.flash()
73         self._item = self._item_class(title)
74
75     def on_content(self, value: tuple):
76         content = value[0]
77         if self._item:
78             self._item.append(content)
79
80     def _parse_line(self, line: str):
81         def apply(k: str, v: str):
82             m = k.fullmatch(line)
83             return v(m.groups()) if m else None
84
85         for k, v in self.rules.items():
86             apply(k, v)
87
88 rules = {
89     'on_section_title': r'%\s*(.+?)\s*%*\n?',
90     'on_property':      r'=\((.+?)\)\s*(.+?)\s*=*\n?',
91     'on_content':       r'([^%=].*)\n?',
92 }
93
94 def convert_sections(lines: list):
95     p = Parser(Section).parse(lines)
96     sections = p.buffer
97     return sections
98
99 def parse_args():
100     ps = argparse.ArgumentParser()
101     ps.add_argument("source")
102     ps.add_argument("-o", dest="out_path", default="out.html")
103     ps.add_argument("-t", dest="template_path", default="template.html")
104
105     return ps.parse_args()
106
107 if __name__ == "__main__":
108     args = parse_args()
109     print(args.source)
110     print(args.out_path)
111     print(args.template_path)
112
113     with open(args.source) as f:
114         lines = f.readlines()
115     doc = Parser(Section, rules).parse(lines)
116
117     print(doc)
118
119     temp = html.parse(args.template_path)
120     temp.getroot().attrib['lang'] = doc.property['lang']
121     temp.xpath('//title')[0].text = doc.property['title']
122     img = temp.xpath('//div[contains(@class, "logo")]/img')[0]
123     img.attrib['src'] = f"/img/logo-{doc.property['lang']}"
124     img.attrib['alt'] = doc.property['title']
125
126     for sec in temp.xpath('//section'):
127         id = sec.attrib['id']
128         fg = html.fromstring(doc[id])
129         sec.append(fg)
130
131     with open(args.out_path, 'w') as f:
132         f.write(html.tostring(temp, encoding='utf-8').decode())