# # tohtml.py # # A sub-class container of the `Formatter' class to produce HTML. # # Copyright 2002-2018 by # David Turner. # # This file is part of the FreeType project, and may only be used, # modified, and distributed under the terms of the FreeType project # license, LICENSE.TXT. By continuing to use, modify, or distribute # this file you indicate that you have read the license and # understand and accept it fully. # The parent class is contained in file `formatter.py'. from sources import * from content import * from formatter import * import time # The following strings define the HTML header used by all generated pages. html_header_1 = """\ \ """ html_header_2 = """\ API Reference """ html_header_3l = """

\ """ html_header_5i = """\ ">Index]

\ """ html_header_6 = """\ API Reference

""" # The HTML footer used by all generated pages. html_footer = """\ \ """ # The header and footer used for each section. section_title_header1 = '

' section_title_footer = "

" # The header and footer used for code segments. code_header = '
'
code_footer = '
' # Paragraph header and footer. para_header = "

" para_footer = "

" # Block header and footer. block_header = '
' block_footer_start = """\
\ \
""" # Description header/footer. description_header = "" description_footer = "" # Marker header/inter/footer combination. marker_header = "

" marker_inter = "

" marker_footer = "" # Header location header/footer. header_location_header = "

" header_location_footer = "

" # Source code extracts header/footer. source_header = "
"
source_footer = "
" # Chapter header/inter/footer. chapter_header = """\

\ """ chapter_inter = '

' chapter_footer = '
' # Index footer. index_footer_start = """\
""" # TOC footer. toc_footer_start = """\
""" # Source language keyword coloration and styling. keyword_prefix = '' keyword_suffix = '' section_synopsis_header = '

Synopsis

' section_synopsis_footer = '' # Translate a single line of source to HTML. This converts `<', `>', and # `&' into `<',`>', and `&'. # def html_quote( line ): result = string.replace( line, "&", "&" ) result = string.replace( result, "<", "<" ) result = string.replace( result, ">", ">" ) return result ################################################################ ## ## HTML FORMATTER CLASS ## class HtmlFormatter( Formatter ): def __init__( self, processor, project_title, file_prefix ): Formatter.__init__( self, processor ) global html_header_1 global html_header_2 global html_header_3l, html_header_3r global html_header_4 global html_header_5t, html_header_5i global html_header_6 global html_footer if file_prefix: file_prefix = file_prefix + "-" else: file_prefix = "" self.headers = processor.headers self.project_title = project_title self.file_prefix = file_prefix self.html_header = ( html_header_1 + project_title + html_header_2 + html_header_3l + file_prefix + "index.html" + html_header_4 + file_prefix + "toc.html" + html_header_5t + project_title + html_header_6 ) self.html_index_header = ( html_header_1 + project_title + html_header_2 + html_header_3r + file_prefix + "toc.html" + html_header_5t + project_title + html_header_6 ) self.html_toc_header = ( html_header_1 + project_title + html_header_2 + html_header_3l + file_prefix + "index.html" + html_header_5i + project_title + html_header_6 ) self.html_footer = ( '
generated on ' + time.asctime( time.localtime( time.time() ) ) + "
" + html_footer ) self.columns = 3 def make_section_url( self, section ): return self.file_prefix + section.name + ".html" def make_block_url( self, block, name = None ): if name == None: name = block.name try: section_url = self.make_section_url( block.section ) except: # we already have a section section_url = self.make_section_url( block ) return section_url + "#" + name def make_html_word( self, word ): """Analyze a simple word to detect cross-references and markup.""" # handle cross-references m = re_crossref.match( word ) if m: try: name = m.group( 'name' ) rest = m.group( 'rest' ) block = self.identifiers[name] url = self.make_block_url( block ) # display `foo[bar]' as `foo' name = re.sub( r'\[.*\]', '', name ) # normalize url, following RFC 3986 url = string.replace( url, "[", "(" ) url = string.replace( url, "]", ")" ) try: # for sections, display title url = ( '‘' + block.title + '’' + rest ) except: url = ( '' + name + '' + rest ) return url except: # we detected a cross-reference to an unknown item sys.stderr.write( "WARNING: undefined cross reference" + " '" + name + "'.\n" ) return '?' + name + '?' + rest # handle markup for italic and bold m = re_italic.match( word ) if m: name = m.group( 1 ) rest = m.group( 2 ) return '' + name + '' + rest m = re_bold.match( word ) if m: name = m.group( 1 ) rest = m.group( 2 ) return '' + name + '' + rest return html_quote( word ) def make_html_para( self, words ): """Convert words of a paragraph into tagged HTML text. Also handle cross references.""" line = "" if words: line = self.make_html_word( words[0] ) for word in words[1:]: line = line + " " + self.make_html_word( word ) # handle hyperlinks line = re_url.sub( r'\1', line ) # convert `...' quotations into real left and right single quotes line = re.sub( r"(^|\W)`(.*?)'(\W|$)", r'\1‘\2’\3', line ) # convert tilde into non-breakable space line = string.replace( line, "~", " " ) return para_header + line + para_footer def make_html_code( self, lines ): """Convert a code sequence to HTML.""" line = code_header + '\n' for l in lines: line = line + html_quote( l ).rstrip() + '\n' return line + code_footer def make_html_items( self, items ): """Convert a field's content into HTML.""" lines = [] for item in items: if item.lines: lines.append( self.make_html_code( item.lines ) ) else: lines.append( self.make_html_para( item.words ) ) return string.join( lines, '\n' ) def print_html_items( self, items ): print(self.make_html_items( items )) def print_html_field( self, field ): if field.name: print( '
' + field.name + "" ) print(self.make_html_items( field.items )) if field.name: print("
") def html_source_quote( self, line, block_name = None ): result = "" while line: m = re_source_crossref.match( line ) if m: name = m.group( 2 ) prefix = html_quote( m.group( 1 ) ) length = len( m.group( 0 ) ) if name == block_name: # this is the current block name, if any result = result + prefix + '' + name + '' elif re_source_keywords.match( name ): # this is a C keyword result = ( result + prefix + keyword_prefix + name + keyword_suffix ) elif name in self.identifiers: # this is a known identifier block = self.identifiers[name] id = block.name # link to a field ID if possible try: for markup in block.markups: if markup.tag == 'values': for field in markup.fields: if field.name: id = name result = ( result + prefix + '' + name + '' ) except: # sections don't have `markups'; however, we don't # want references to sections here anyway result = result + html_quote( line[:length] ) else: result = result + html_quote( line[:length] ) line = line[length:] else: result = result + html_quote( line ) line = [] return result def print_html_field_list( self, fields ): print('') for field in fields: print ( '") print("
' + field.name + '' ) self.print_html_items( field.items ) print("
") def print_html_markup( self, markup ): table_fields = [] for field in markup.fields: if field.name: # We begin a new series of field or value definitions. We # record them in the `table_fields' list before outputting # all of them as a single table. table_fields.append( field ) else: if table_fields: self.print_html_field_list( table_fields ) table_fields = [] self.print_html_items( field.items ) if table_fields: self.print_html_field_list( table_fields ) # # formatting the index # def index_enter( self ): print(self.html_index_header) self.index_items = {} def index_name_enter( self, name ): block = self.identifiers[name] url = self.make_block_url( block ) self.index_items[name] = url def index_exit( self ): # `block_index' already contains the sorted list of index names count = len( self.block_index ) rows = ( count + self.columns - 1 ) // self.columns print('') for r in range( rows ): line = "" for c in range( self.columns ): i = r + c * rows if i < count: bname = self.block_index[r + c * rows] url = self.index_items[bname] # display `foo[bar]' as `foo (bar)' bname = string.replace( bname, "[", " (" ) bname = string.replace( bname, "]", ")" ) # normalize url, following RFC 3986 url = string.replace( url, "[", "(" ) url = string.replace( url, "]", ")" ) line = ( line + '' ) else: line = line + '' line = line + "" print(line) print("
' + bname + '
") print( index_footer_start + self.file_prefix + "toc.html" + index_footer_end ) print(self.html_footer) self.index_items = {} def index_dump( self, index_filename = None ): if index_filename == None: index_filename = self.file_prefix + "index.html" Formatter.index_dump( self, index_filename ) # # formatting the table of contents # def toc_enter( self ): print(self.html_toc_header) print("

Table of Contents

") def toc_chapter_enter( self, chapter ): print(chapter_header + string.join( chapter.title ) + chapter_inter) print('') def toc_section_enter( self, section ): print ( '") def toc_chapter_exit( self, chapter ): print("
' ) print(self.make_html_para( section.abstract )) def toc_section_exit( self, section ): print("
") print(chapter_footer) def toc_index( self, index_filename ): print( chapter_header + 'Global Index' + chapter_inter + chapter_footer ) def toc_exit( self ): print( toc_footer_start + self.file_prefix + "index.html" + toc_footer_end ) print (self.html_footer) def toc_dump( self, toc_filename = None, index_filename = None ): if toc_filename == None: toc_filename = self.file_prefix + "toc.html" if index_filename == None: index_filename = self.file_prefix + "index.html" Formatter.toc_dump( self, toc_filename, index_filename ) # # formatting sections # def section_enter( self, section ): print(self.html_header) print ( section_title_header1 + section.name + section_title_header2 + section.title + section_title_footer ) maxwidth = 0 for b in section.blocks.values(): if len( b.name ) > maxwidth: maxwidth = len( b.name ) width = 70 # XXX magic number if maxwidth > 0: # print section synopsis print(section_synopsis_header) print('') columns = width // maxwidth if columns < 1: columns = 1 count = len( section.block_names ) # don't handle last entry if it is empty if section.block_names[-1] == "/empty/": count -= 1 rows = ( count + columns - 1 ) // columns for r in range( rows ): line = "" for c in range( columns ): i = r + c * rows line = line + '' line = line + "" print(line) print("
' if i < count: name = section.block_names[i] if name == "/empty/": # it can happen that a complete row is empty, and # without a proper `filler' the browser might # collapse the row to a much smaller height (or # even omit it completely) line = line + " " else: url = name # display `foo[bar]' as `foo' name = re.sub( r'\[.*\]', '', name ) # normalize url, following RFC 3986 url = string.replace( url, "[", "(" ) url = string.replace( url, "]", ")" ) line = ( line + '' + name + '' ) line = line + '
") print(section_synopsis_footer) print(description_header) print(self.make_html_items( section.description )) print(description_footer) def block_enter( self, block ): print(block_header) # place html anchor if needed if block.name: url = block.name # display `foo[bar]' as `foo' name = re.sub( r'\[.*\]', '', block.name ) # normalize url, following RFC 3986 url = string.replace( url, "[", "(" ) url = string.replace( url, "]", ")" ) print( '

' + name + '

' ) # dump the block C source lines now if block.code: header = '' for f in self.headers.keys(): if block.source.filename.find( f ) >= 0: header = self.headers[f] + ' (' + f + ')' break # if not header: # sys.stderr.write( # "WARNING: No header macro for" # + " '" + block.source.filename + "'.\n" ) if header: print ( header_location_header + 'Defined in ' + header + '.' + header_location_footer ) print(source_header) for l in block.code: print(self.html_source_quote( l, block.name )) print(source_footer) def markup_enter( self, markup, block ): if markup.tag == "description": print(description_header) else: print(marker_header + markup.tag + marker_inter) self.print_html_markup( markup ) def markup_exit( self, markup, block ): if markup.tag == "description": print(description_footer) else: print(marker_footer) def block_exit( self, block ): print( block_footer_start + self.file_prefix + "index.html" + block_footer_middle + self.file_prefix + "toc.html" + block_footer_end ) def section_exit( self, section ): print(html_footer) def section_dump_all( self ): for section in self.sections: self.section_dump( section, self.file_prefix + section.name + '.html' ) # eof