1 # Copyright 2013 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
7 from document_parser import ParseDocument
8 from third_party.json_schema_compiler.model import UnixName
11 class DocumentRenderer(object):
12 '''Performs document-level rendering such as the title, references,
13 and table of contents: pulling that data out of the document, then
14 replacing the $(title), $(ref:...) and $(table_of_contents) tokens with them.
16 This can be thought of as a parallel to TemplateRenderer; while
17 TemplateRenderer is responsible for interpreting templates and rendering files
18 within the template engine, DocumentRenderer is responsible for interpreting
19 higher-level document concepts like the title and TOC, then performing string
20 replacement for them. The syntax for this replacement is $(...) where ... is
21 the concept. Currently title and table_of_contents are supported.
24 def __init__(self, table_of_contents_renderer, ref_resolver):
25 self._table_of_contents_renderer = table_of_contents_renderer
26 self._ref_resolver = ref_resolver
28 def _RenderLinks(self, document, path):
29 ''' Replaces all $(ref:...) references in |document| with html links
37 # Keeps track of position within |document|
39 start_ref_index = document.find(START_REF)
41 while start_ref_index != -1:
42 end_ref_index = document.find(END_REF, start_ref_index)
44 if (end_ref_index == -1 or
45 end_ref_index - start_ref_index > MAX_REF_LENGTH):
46 end_ref_index = document.find(' ', start_ref_index)
47 logging.error('%s:%s has no terminating ) at line %s' % (
49 document[start_ref_index:end_ref_index],
50 document.count('\n', 0, end_ref_index)))
52 new_document.append(document[cursor_index:end_ref_index + 1])
54 ref = document[start_ref_index:end_ref_index]
55 ref_parts = ref[len(START_REF):].split(' ', 1)
57 # Guess the api name from the html name, replacing '_' with '.' (e.g.
58 # if the page is app_window.html, guess the api name is app.window)
59 api_name = os.path.splitext(os.path.basename(path))[0].replace('_', '.')
60 title = ref_parts[0] if len(ref_parts) == 1 else ref_parts[1]
62 ref_dict = self._ref_resolver.SafeGetLink(ref_parts[0],
66 new_document.append(document[cursor_index:start_ref_index])
67 new_document.append('<a href=%s>%s</a>' % (ref_dict['href'],
70 cursor_index = end_ref_index + 1
71 start_ref_index = document.find(START_REF, cursor_index)
73 new_document.append(document[cursor_index:])
75 return ''.join(new_document)
77 def Render(self, document, path, render_title=False):
78 # Render links first so that parsing and later replacements aren't
79 # affected by $(ref...) substitutions
80 document = self._RenderLinks(document, path)
82 parsed_document = ParseDocument(document, expect_title=render_title)
83 toc_text, toc_warnings = self._table_of_contents_renderer.Render(
84 parsed_document.sections)
86 # Only 1 title and 1 table of contents substitution allowed; in the common
87 # case, save necessarily running over the entire file.
88 if parsed_document.title:
89 document = document.replace('$(title)', parsed_document.title, 1)
90 return (document.replace('$(table_of_contents)', toc_text, 1),
91 parsed_document.warnings + toc_warnings)