forked from rothos/chebsite
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathprocessors.py
146 lines (125 loc) · 5.13 KB
/
processors.py
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
from __future__ import unicode_literals
from io import open
from textwrap import dedent
import chebsitemd
import os, yaml, jinja2, markdown, re
#-----------------------------------------------------------------------------
def get_yaml_frontmatter(fn):
"""Return the YAML frontmatter of a Markdown document."""
with open(fn, 'r', encoding='utf-8-sig') as f:
line = f.readline()
if line.strip() != '---':
return {}
lines = []
while True:
line = f.readline()
if not line:
return {}
elif line.strip() == '---':
s = ''.join(lines)
meta = yaml.safe_load(s)
if isinstance(meta, dict):
return meta
else:
return {}
else:
lines.append(line)
def skip_yamlfm(fn):
"""Return source of a file without YAML frontmatter."""
fn.readline()
found = False
lines = []
for line in fn.readlines():
if found:
lines.append(line)
if line.strip() == '---':
found = True
return ''.join(lines)
def process_helptext(s):
phrase = 'is both a directory and a function.'
index = s.find(phrase)
if index != -1:
# This is a constructor.
nextline = s.find('\n', index) + 2
lastline = s.find('<!--Methods-->')
prefix = '<div class="helptext"><pre><!--helptext -->'
s = prefix + s[nextline:lastline]
else:
# This is probably not a constructor.
phrase = '<div class="title">'
index = s.find(phrase)
nextline = s.find('\n', index)
lastline = s.find('<\\body>')
s = s[nextline:lastline]
# Now rewrite the links. This feels dirty.
pattern = re.compile('<a href="matlab:helpwin\((\'|").*?(\'|")\)">(.*?)</a>')
repl = r'\3'
s = pattern.sub(repl, s)
pattern = re.compile('<a href="matlab:helpwin ([^/]+?)">')
repl = r'<a href="../\1/\1.html">'
s = pattern.sub(repl, s)
pattern = re.compile('<a href="matlab:helpwin (.+?)">')
repl = r'<a href="../\1.html">'
s = pattern.sub(repl, s)
return s
#-----------------------------------------------------------------------------
class ContentProcessor:
def __init__(self, nodes, sitedata, template_dir, build_dir, out_ext='.html'):
"""Process the content.
Conversion and rendering are done in separate phases, so
that the full content is available to the rendering process.
"""
self.nodes = nodes
self.sitedata = sitedata
self.template_dir = template_dir
self.build_dir = build_dir
self.out_extension = out_ext
# extensions = ['extra', 'codehilite', 'headerid', 'toc']
# extension_configs = { 'codehilite': [('guess_lang', 'False'), ('linenums', 'False')],
# 'headerid': [('level', 2)] }
chebmdext = chebsitemd.ChebsiteExtension()
extensions = ['extra', 'headerid', 'toc', chebmdext]
extension_configs = { 'headerid': [('level', 2)] }
self.md = markdown.Markdown(extensions=extensions,
extension_configs=extension_configs)
self.env = jinja2.Environment(loader=jinja2.FileSystemLoader([self.template_dir]),
lstrip_blocks=True,
trim_blocks=True)
# Add filters.
self.env.filters['dedent'] = dedent
self.env.filters['process_helptext'] = process_helptext
self.templates = self.get_templates()
def get_templates(self):
""" Load in all the (.html) templates from self.template_dir.
"""
templates = {}
for dirpath, dirnames, filenames in os.walk(self.template_dir):
for filename in filenames:
if filename.endswith('.html'):
slug = filename[:-5]
templates[slug] = self.env.get_template(filename)
return templates
def convert_markdown(self):
""" Convert Markdown to HTML and save as the 'body' field in a tree node.
"""
# Each node is a FileNode containing information about a particular .md file.
for node in self.nodes:
with open(node.abspath, encoding='utf-8-sig') as inf:
src = skip_yamlfm(inf)
# self.md.this = node.something # necessary?
node.data.update({
'body_src': src,
'body': self.md.convert(src)
})
self.md.reset()
def render_templates(self):
""" Do the jinja2 templating magic.
"""
for node in self.nodes:
# FIXME: Error handling?
template = node.data.layout
templ = self.templates[template]
html = templ.render(page=node.get_data(), site=self.sitedata)
outfn = os.path.join(self.build_dir, node.dir, node.slug+self.out_extension)
with open(outfn, 'w+', encoding='utf-8', errors='strict') as outf:
outf.write(html)