-
Notifications
You must be signed in to change notification settings - Fork 47
/
lean_sphinx.py
111 lines (86 loc) · 3.54 KB
/
lean_sphinx.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
from docutils import nodes
from docutils.parsers.rst import Directive
from sphinx.builders import Builder
from sphinx.directives.code import CodeBlock
from sphinx.errors import SphinxError
import os, os.path, fnmatch, subprocess
import codecs
import urllib
import re
try:
urlquote = urllib.parse.quote
except:
# Python 2
def urlquote(s, safe='/'):
return urllib.quote(s.encode('utf-8'), safe)
# "Try it!" button
class lean_code_goodies(nodes.General, nodes.Element): pass
def mk_try_it_uri(code):
uri = 'https://leanprover-community.github.io/lean-web-editor/#code='
uri += urlquote(code, safe='~()*!.\'')
return uri
def process_lean_nodes(app, doctree, fromdocname):
for node in doctree.traverse(nodes.literal_block):
if node['language'] != 'lean': continue
new_node = lean_code_goodies()
new_node['full_code'] = node.rawsource
node.replace_self([new_node])
code = node.rawsource
m = re.search(r'--[^\n]*BEGIN[^\n]*\n(.*)--[^\n]*END', code, re.DOTALL)
if m:
node = nodes.literal_block(m.group(1), m.group(1))
node['language'] = 'lean'
new_node += node
if app.builder.name.startswith('epub'):
new_node.replace_self([node])
def html_visit_lean_code_goodies(self, node):
self.body.append(self.starttag(node, 'div', style='position: relative'))
self.body.append("<div style='position: absolute; right: 0; top: 0; padding: 1ex'>")
self.body.append(self.starttag(node, 'a', target='_blank', href=mk_try_it_uri(node['full_code'])))
self.body.append('try it!</a></div>')
def html_depart_lean_code_goodies(self, node):
self.body.append('</div>')
def latex_visit_lean_code_goodies(self, node):
pass
def latex_depart_lean_code_goodies(self, node):
pass
# Extract code snippets for testing.
class LeanTestBuilder(Builder):
'''
Extract ``..code-block:: lean`` directives for testing.
'''
name = 'leantest'
def init(self):
self.written_files = set()
def write_doc(self, docname, doctree):
i = 0
for node in doctree.traverse(lean_code_goodies):
i += 1
fn = os.path.join(self.outdir, '{0}_{1}.lean'.format(docname, i))
self.written_files.add(fn)
out = codecs.open(fn, 'w', encoding='utf-8')
out.write(node['full_code'])
def finish(self):
for root, _, filenames in os.walk(self.outdir):
for fn in fnmatch.filter(filenames, '*.lean'):
fn = os.path.join(root, fn)
if fn not in self.written_files:
os.remove(fn)
proc = subprocess.Popen(['lean', '--make', self.outdir], stdout=subprocess.PIPE)
stdout, stderr = proc.communicate()
errors = '\n'.join(l for l in stdout.decode('utf-8').split('\n') if ': error:' in l)
if errors != '': raise SphinxError('\nlean exited with errors:\n{0}\n'.format(errors))
retcode = proc.wait()
if retcode: raise SphinxError('lean exited with error code {0}'.format(retcode))
def prepare_writing(self, docnames): pass
def get_target_uri(self, docname, typ=None):
return ''
def get_outdated_docs(self):
return self.env.found_docs
def setup(app):
app.add_node(lean_code_goodies,
html=(html_visit_lean_code_goodies, html_depart_lean_code_goodies),
latex=(latex_visit_lean_code_goodies, latex_depart_lean_code_goodies))
app.connect('doctree-resolved', process_lean_nodes)
app.add_builder(LeanTestBuilder)
return {'version': '0.1'}