28
28
29
29
"""Create HTML files of the tutorial."""
30
30
31
+ import argparse
31
32
import os
32
33
import posixpath
33
34
import shutil
34
35
import string
35
36
import sys
37
+ import textwrap
36
38
import webbrowser
37
39
38
- import common
39
-
40
40
try :
41
41
import mistune
42
42
except ImportError :
43
- print ("mistune isn't installed. You can install it like this:" )
43
+ print ("mistune isn't installed." , file = sys .stderr )
44
+ print ("You can install it like this:" )
44
45
print ()
45
46
print (">>> import pip" )
46
47
print (">>> pip.main(['install', '--user', 'mistune'])" )
49
50
try :
50
51
import pygments .formatters
51
52
import pygments .lexers
53
+ import pygments .styles
52
54
except ImportError :
53
55
# we can work without pygments, but we won't get colors
54
56
pygments = None
55
57
58
+ import common
59
+
56
60
57
61
HTML_TEMPLATE = """\
58
62
<!DOCTYPE html>
59
63
<html>
60
64
<head>
61
65
<meta charset="UTF-8">
62
66
<title>{title}</title>
67
+ <link rel="stylesheet" type="text/css" href="{stylefile}">
63
68
</head>
64
69
<body>
65
70
{body}
@@ -77,19 +82,23 @@ def mkdir_slashfix_open(filename, mode):
77
82
78
83
79
84
def fix_filename (filename ):
80
- if posixpath .basename (filename ) == 'README.md' :
81
- # 'README.md' -> 'index.html'
82
- # 'some/place/README.md' -> 'some/place/index.html'
83
- return filename [:- 9 ] + 'index.html'
85
+ renames = [('README.md' , 'index.html' ),
86
+ ('LICENSE' , 'LICENSE.txt' )]
87
+ for before , after in renames :
88
+ if posixpath .basename (filename ) == before :
89
+ # BEFORE -> AFTER
90
+ # some/place/BEFORE -> some/place/AFTER
91
+ return filename [:- len (before )] + after
84
92
if filename .endswith ('.md' ):
85
- return filename [:- 3 ] + '.html'
93
+ filename = filename [:- 3 ] + '.html'
86
94
return filename
87
95
88
96
89
97
class TutorialRenderer (mistune .Renderer ):
90
98
91
- def __init__ (self ):
99
+ def __init__ (self , pygments_style ):
92
100
super ().__init__ ()
101
+ self .pygments_style = pygments_style
93
102
self .title = None # will be set by header()
94
103
self ._headercounts = {}
95
104
@@ -157,7 +166,7 @@ def block_code(self, code, lang=None):
157
166
else :
158
167
lexer = pygments .lexers .PythonLexer ()
159
168
formatter = pygments .formatters .HtmlFormatter (
160
- style = 'tango' , noclasses = True )
169
+ style = self . pygments_style , noclasses = True )
161
170
return pygments .highlight (code , lexer , formatter )
162
171
# we can't highlight it
163
172
return super ().block_code (code , lang )
@@ -173,51 +182,96 @@ def table(self, header, body):
173
182
return result .replace ('<table>' , '<table border="1">' , 1 )
174
183
175
184
185
+ def wrap_text (text ):
186
+ """Like textwrap.fill, but respects newlines."""
187
+ result = []
188
+ for part in text .split ('\n ' ):
189
+ result .append (textwrap .fill (part ))
190
+ return '\n ' .join (result )
191
+
192
+
176
193
def main ():
194
+ desc = ("Create HTML files of the tutorial.\n \n "
195
+ "The files have light text on a dark background by "
196
+ "default, and you can edit html-style.css to change that." )
197
+ if pygments is not None :
198
+ desc += (
199
+ " Editing the style file doesn't change the colors of the "
200
+ "code examples, but you can use the --pygments-style "
201
+ "option. Search for 'pygments style gallery' online or see "
202
+ "https://help.farbox.com/pygments.html to get an idea of "
203
+ "what different styles look like." )
204
+
205
+ parser = argparse .ArgumentParser (
206
+ description = wrap_text (desc ),
207
+ formatter_class = argparse .RawDescriptionHelpFormatter )
208
+ parser .add_argument (
209
+ '-o' , '--outdir' , default = 'html' ,
210
+ help = "write the HTML files here, defaults to %(default)r" )
211
+ if pygments is not None :
212
+ parser .add_argument (
213
+ '--pygments-style' , metavar = 'STYLE' , default = 'native' ,
214
+ choices = list (pygments .styles .get_all_styles ()),
215
+ help = ("the Pygments color style (see above), "
216
+ "%(default)r by default" ))
217
+ args = parser .parse_args ()
218
+
177
219
if pygments is None :
178
220
print ("Pygments isn't installed. You can install it like this:" )
179
221
print ()
180
222
print (">>> import pip" )
181
- print (">>> pip.main(['install', '--user', 'Pygments '])" )
223
+ print (">>> pip.main(['install', '--user', 'pygments '])" )
182
224
print ()
183
225
print ("You can also continue without Pygments, but the code examples" )
184
- print ("will not be in color ." )
226
+ print ("will not be colored ." )
185
227
if not common .askyesno ("Continue without pygments?" ):
186
228
print ("Interrupt." )
187
229
return
188
230
189
- if os .path .exists ('html' ):
190
- if not common .askyesno ("html exists. Do you want to remove it?" ):
231
+ if os .path .exists (args .outdir ):
232
+ if not common .askyesno ("%s exists. Do you want to remove it?"
233
+ % args .outdir ):
191
234
print ("Interrupt." )
192
235
return
193
- if os .path .isdir ('html' ):
194
- shutil .rmtree ('html' )
236
+ if os .path .isdir (args . outdir ):
237
+ shutil .rmtree (args . outdir )
195
238
else :
196
- os .remove ('html' )
239
+ os .remove (args . outdir )
197
240
198
241
print ("Generating HTML files..." )
199
242
for markdownfile in common .get_markdown_files ():
200
- htmlfile = posixpath .join ('html' , fix_filename (markdownfile ))
201
- print (' ' , markdownfile , '->' , htmlfile )
243
+ fixed_markdownfile = fix_filename (markdownfile )
244
+ htmlfile = posixpath .join (args .outdir , fixed_markdownfile )
245
+ print (' %-30.30s --> %-30.30s' % (markdownfile , htmlfile ), end = '\r ' )
246
+
202
247
with common .slashfix_open (markdownfile , 'r' ) as f :
203
248
markdown = f .read ()
204
- renderer = TutorialRenderer ()
249
+ renderer = TutorialRenderer (args . pygments_style )
205
250
body = mistune .markdown (markdown , renderer = renderer )
206
- html = HTML_TEMPLATE .format (title = renderer .title , body = body )
251
+ stylefile = posixpath .relpath (
252
+ 'style.css' , posixpath .dirname (fixed_markdownfile ))
253
+
254
+ html = HTML_TEMPLATE .format (
255
+ title = renderer .title ,
256
+ body = body ,
257
+ stylefile = stylefile ,
258
+ )
207
259
with mkdir_slashfix_open (htmlfile , 'w' ) as f :
208
260
print (html , file = f )
261
+ print ()
209
262
210
263
print ("Copying other files..." )
211
- shutil .copytree ('images' , os .path .join ('html' , 'images' ))
212
- shutil .copy ('LICENSE' , os .path .join ('html' , 'LICENSE' ))
264
+ shutil .copytree ('images' , os .path .join (args .outdir , 'images' ))
265
+ shutil .copy ('LICENSE' , os .path .join (args .outdir , 'LICENSE.txt' ))
266
+ shutil .copy ('html-style.css' , os .path .join (args .outdir , 'style.css' ))
213
267
214
268
print ("\n *********************\n " )
215
- print ("Ready! The files are in the html directory." )
216
- print ("Go to html and double-click index.html to read the tutorial." )
269
+ print ("Ready! The files are in %r." % args . outdir )
270
+ print ("You can go there and double-click index.html to read the tutorial." )
217
271
print ()
218
272
if common .askyesno ("Do you want to view the tutorial now?" , default = False ):
219
273
print ("Opening the tutorial..." )
220
- webbrowser .open (os .path .join ('html' , 'index.html' ))
274
+ webbrowser .open (os .path .join (args . outdir , 'index.html' ))
221
275
222
276
223
277
if __name__ == '__main__' :
0 commit comments