• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4
5import logging
6import os
7from document_parser import ParseDocument
8from third_party.json_schema_compiler.model import UnixName
9
10
11class 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.
15
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.
22  '''
23
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
27
28  def _RenderLinks(self, document, path):
29    ''' Replaces all $(ref:...) references in |document| with html links.
30
31        References have two forms:
32
33          $(ref:api.node) - Replaces the reference with a link to node on the
34                            API page. The title is set to the name of the node.
35
36          $(ref:api.node Title) - Same as the previous form, but title is set
37                                  to "Title".
38    '''
39    START_REF = '$(ref:'
40    END_REF = ')'
41    MAX_REF_LENGTH = 256
42
43    new_document = []
44
45    # Keeps track of position within |document|
46    cursor_index = 0
47    start_ref_index = document.find(START_REF)
48
49    while start_ref_index != -1:
50      end_ref_index = document.find(END_REF, start_ref_index)
51
52      if (end_ref_index == -1 or
53          end_ref_index - start_ref_index > MAX_REF_LENGTH):
54        end_ref_index = document.find(' ', start_ref_index)
55        logging.error('%s:%s has no terminating ) at line %s' % (
56            path,
57            document[start_ref_index:end_ref_index],
58            document.count('\n', 0, end_ref_index)))
59
60        new_document.append(document[cursor_index:end_ref_index + 1])
61      else:
62        ref = document[start_ref_index:end_ref_index]
63        ref_parts = ref[len(START_REF):].split(None, 1)
64
65        # Guess the api name from the html name, replacing '_' with '.' (e.g.
66        # if the page is app_window.html, guess the api name is app.window)
67        api_name = os.path.splitext(os.path.basename(path))[0].replace('_', '.')
68        title = ref_parts[0] if len(ref_parts) == 1 else ref_parts[1]
69
70        ref_dict = self._ref_resolver.SafeGetLink(ref_parts[0],
71                                                  namespace=api_name,
72                                                  title=title)
73
74        new_document.append(document[cursor_index:start_ref_index])
75        new_document.append('<a href=%s>%s</a>' % (ref_dict['href'],
76                                                   ref_dict['text']))
77
78      cursor_index = end_ref_index + 1
79      start_ref_index = document.find(START_REF, cursor_index)
80
81    new_document.append(document[cursor_index:])
82
83    return ''.join(new_document)
84
85  def Render(self, document, path, render_title=False):
86    # Render links first so that parsing and later replacements aren't
87    # affected by $(ref...) substitutions
88    document = self._RenderLinks(document, path)
89
90    parsed_document = ParseDocument(document, expect_title=render_title)
91    toc_text, toc_warnings = self._table_of_contents_renderer.Render(
92        parsed_document.sections)
93
94    # Only 1 title and 1 table of contents substitution allowed; in the common
95    # case, save necessarily running over the entire file.
96    if parsed_document.title:
97      document = document.replace('$(title)', parsed_document.title, 1)
98    return (document.replace('$(table_of_contents)', toc_text, 1),
99            parsed_document.warnings + toc_warnings)
100