2828
2929"""Create HTML files of the tutorial."""
3030
31+ import argparse
3132import os
3233import posixpath
3334import shutil
3435import string
3536import sys
37+ import textwrap
3638import webbrowser
3739
38- import common
39-
4040try :
4141 import mistune
4242except 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:" )
4445 print ()
4546 print (">>> import pip" )
4647 print (">>> pip.main(['install', '--user', 'mistune'])" )
4950try :
5051 import pygments .formatters
5152 import pygments .lexers
53+ import pygments .styles
5254except ImportError :
5355 # we can work without pygments, but we won't get colors
5456 pygments = None
5557
58+ import common
59+
5660
5761HTML_TEMPLATE = """\
5862 <!DOCTYPE html>
5963<html>
6064 <head>
6165 <meta charset="UTF-8">
6266 <title>{title}</title>
67+ <link rel="stylesheet" type="text/css" href="{stylefile}">
6368 </head>
6469 <body>
6570 {body}
@@ -77,19 +82,23 @@ def mkdir_slashfix_open(filename, mode):
7782
7883
7984def 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
8492 if filename .endswith ('.md' ):
85- return filename [:- 3 ] + '.html'
93+ filename = filename [:- 3 ] + '.html'
8694 return filename
8795
8896
8997class TutorialRenderer (mistune .Renderer ):
9098
91- def __init__ (self ):
99+ def __init__ (self , pygments_style ):
92100 super ().__init__ ()
101+ self .pygments_style = pygments_style
93102 self .title = None # will be set by header()
94103 self ._headercounts = {}
95104
@@ -157,7 +166,7 @@ def block_code(self, code, lang=None):
157166 else :
158167 lexer = pygments .lexers .PythonLexer ()
159168 formatter = pygments .formatters .HtmlFormatter (
160- style = 'tango' , noclasses = True )
169+ style = self . pygments_style , noclasses = True )
161170 return pygments .highlight (code , lexer , formatter )
162171 # we can't highlight it
163172 return super ().block_code (code , lang )
@@ -173,51 +182,96 @@ def table(self, header, body):
173182 return result .replace ('<table>' , '<table border="1">' , 1 )
174183
175184
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+
176193def 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+
177219 if pygments is None :
178220 print ("Pygments isn't installed. You can install it like this:" )
179221 print ()
180222 print (">>> import pip" )
181- print (">>> pip.main(['install', '--user', 'Pygments '])" )
223+ print (">>> pip.main(['install', '--user', 'pygments '])" )
182224 print ()
183225 print ("You can also continue without Pygments, but the code examples" )
184- print ("will not be in color ." )
226+ print ("will not be colored ." )
185227 if not common .askyesno ("Continue without pygments?" ):
186228 print ("Interrupt." )
187229 return
188230
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 ):
191234 print ("Interrupt." )
192235 return
193- if os .path .isdir ('html' ):
194- shutil .rmtree ('html' )
236+ if os .path .isdir (args . outdir ):
237+ shutil .rmtree (args . outdir )
195238 else :
196- os .remove ('html' )
239+ os .remove (args . outdir )
197240
198241 print ("Generating HTML files..." )
199242 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+
202247 with common .slashfix_open (markdownfile , 'r' ) as f :
203248 markdown = f .read ()
204- renderer = TutorialRenderer ()
249+ renderer = TutorialRenderer (args . pygments_style )
205250 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+ )
207259 with mkdir_slashfix_open (htmlfile , 'w' ) as f :
208260 print (html , file = f )
261+ print ()
209262
210263 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' ))
213267
214268 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." )
217271 print ()
218272 if common .askyesno ("Do you want to view the tutorial now?" , default = False ):
219273 print ("Opening the tutorial..." )
220- webbrowser .open (os .path .join ('html' , 'index.html' ))
274+ webbrowser .open (os .path .join (args . outdir , 'index.html' ))
221275
222276
223277if __name__ == '__main__' :
0 commit comments