Classifier Python :: 2.4 to 2.7
[docutils.git] / sandbox / py-rest-doc / sphinx / writer.py
blobcd081af524c6d012cadbfab11d9ad14d87e58896
1 # -*- coding: utf-8 -*-
2 """
3 sphinx.writer
4 ~~~~~~~~~~~~~
6 docutils writers handling Sphinx' custom nodes.
8 :copyright: 2007 by Georg Brandl.
9 :license: Python license.
10 """
12 from docutils import nodes
13 from docutils.writers.html4css1 import Writer, HTMLTranslator as BaseTranslator
15 from .smartypants import sphinx_smarty_pants
18 class HTMLWriter(Writer):
19 def __init__(self, config):
20 Writer.__init__(self)
21 if config.get('use_smartypants', False):
22 self.translator_class = SmartyPantsHTMLTranslator
23 else:
24 self.translator_class = HTMLTranslator
27 version_text = {
28 'deprecated': 'Deprecated in version %s',
29 'versionchanged': 'Changed in version %s',
30 'versionadded': 'New in version %s',
33 class HTMLTranslator(BaseTranslator):
34 """
35 Our custom HTML translator.
36 """
38 def __init__(self, *args, **kwds):
39 self.no_smarty = 0
40 BaseTranslator.__init__(self, *args, **kwds)
41 self.highlightlang = 'python'
43 def visit_desc(self, node):
44 self.body.append(self.starttag(node, 'dl', CLASS=node['desctype']))
45 def depart_desc(self, node):
46 self.body.append('</dl>\n\n')
48 def visit_desc_signature(self, node):
49 # the id is set automatically
50 self.body.append(self.starttag(node, 'dt'))
51 # anchor for per-desc interactive data
52 if node.parent['desctype'] != 'describe' and node['ids'] and node['first']:
53 self.body.append('<!--#%s#-->' % node['ids'][0])
54 if node.parent['desctype'] in ('class', 'exception'):
55 self.body.append('%s ' % node.parent['desctype'])
56 def depart_desc_signature(self, node):
57 self.body.append('</dt>\n')
59 def visit_desc_classname(self, node):
60 self.body.append(self.starttag(node, 'tt', '', CLASS='descclassname'))
61 def depart_desc_classname(self, node):
62 self.body.append('</tt>')
64 def visit_desc_name(self, node):
65 self.body.append(self.starttag(node, 'tt', '', CLASS='descname'))
66 def depart_desc_name(self, node):
67 self.body.append('</tt>')
69 def visit_desc_parameterlist(self, node):
70 self.body.append('<big>(</big>')
71 self.first_param = 1
72 def depart_desc_parameterlist(self, node):
73 self.body.append('<big>)</big>')
75 def visit_desc_parameter(self, node):
76 if not self.first_param:
77 self.body.append(', ')
78 else:
79 self.first_param = 0
80 if not node.hasattr('noemph'):
81 self.body.append('<em>')
82 def depart_desc_parameter(self, node):
83 if not node.hasattr('noemph'):
84 self.body.append('</em>')
86 def visit_desc_optional(self, node):
87 self.body.append('<span class="optional">[</span>')
88 def depart_desc_optional(self, node):
89 self.body.append('<span class="optional">]</span>')
91 def visit_desc_content(self, node):
92 self.body.append(self.starttag(node, 'dd', ''))
93 def depart_desc_content(self, node):
94 self.body.append('</dd>')
96 def visit_refcount(self, node):
97 self.body.append(self.starttag(node, 'em', '', CLASS='refcount'))
98 def depart_refcount(self, node):
99 self.body.append('</em>')
101 def visit_versionmodified(self, node):
102 self.body.append(self.starttag(node, 'p'))
103 text = version_text[node['type']] % node['version']
104 if len(node):
105 text += ': '
106 else:
107 text += '.'
108 self.body.append('<span class="versionmodified">%s</span>' % text)
109 def depart_versionmodified(self, node):
110 self.body.append('</p>\n')
112 # overwritten -- we don't want source comments to show up in the HTML
113 def visit_comment(self, node):
114 raise nodes.SkipNode
116 # overwritten
117 def visit_admonition(self, node, name=''):
118 self.body.append(self.start_tag_with_title(
119 node, 'div', CLASS=('admonition ' + name)))
120 if name and name != 'seealso':
121 node.insert(0, nodes.title(name, self.language.labels[name]))
122 self.set_first_last(node)
124 def visit_seealso(self, node):
125 self.visit_admonition(node, 'seealso')
126 def depart_seealso(self, node):
127 self.depart_admonition(node)
129 # overwritten
130 def visit_title(self, node, move_ids=1):
131 # if we have a section we do our own processing in order
132 # to have ids in the hN-tags and not in additional a-tags
133 if isinstance(node.parent, nodes.section):
134 h_level = self.section_level + self.initial_header_level - 1
135 if node.parent.get('ids'):
136 attrs = {'ids': node.parent['ids']}
137 else:
138 attrs = {}
139 self.body.append(self.starttag(node, 'h%d' % h_level, '', **attrs))
140 self.context.append('</h%d>\n' % h_level)
141 else:
142 BaseTranslator.visit_title(self, node, move_ids)
144 # overwritten
145 def visit_literal_block(self, node):
146 from .highlighting import highlight_block
147 self.body.append(highlight_block(node.rawsource, self.highlightlang))
148 raise nodes.SkipNode
150 def visit_productionlist(self, node):
151 self.body.append(self.starttag(node, 'pre'))
152 names = []
153 for production in node:
154 names.append(production['tokenname'])
155 maxlen = max(len(name) for name in names)
156 for production in node:
157 if production['tokenname']:
158 self.body.append(self.starttag(production, 'strong', ''))
159 self.body.append(production['tokenname'].ljust(maxlen) +
160 '</strong> ::= ')
161 lastname = production['tokenname']
162 else:
163 self.body.append('%s ' % (' '*len(lastname)))
164 production.walkabout(self)
165 self.body.append('\n')
166 self.body.append('</pre>\n')
167 raise nodes.SkipNode
168 def depart_productionlist(self, node):
169 pass
171 def visit_production(self, node):
172 pass
173 def depart_production(self, node):
174 pass
176 def visit_centered(self, node):
177 self.body.append(self.starttag(node, 'center') + '<strong>')
178 def depart_centered(self, node):
179 self.body.append('</strong></center>')
181 def visit_compact_paragraph(self, node):
182 pass
183 def depart_compact_paragraph(self, node):
184 pass
186 def visit_highlightlang(self, node):
187 self.highlightlang = node['lang']
188 def depart_highlightlang(self, node):
189 pass
191 def visit_toctree(self, node):
192 # this only happens when formatting a toc from env.tocs -- in this
193 # case we don't want to include the subtree
194 raise nodes.SkipNode
196 def visit_index(self, node):
197 raise nodes.SkipNode
200 class SmartyPantsHTMLTranslator(HTMLTranslator):
202 Handle ordinary text via smartypants, converting quotes and dashes
203 to the correct entities.
206 def __init__(self, *args, **kwds):
207 self.no_smarty = 0
208 HTMLTranslator.__init__(self, *args, **kwds)
210 def visit_literal(self, node):
211 self.no_smarty += 1
212 try:
213 # this raises SkipNode
214 HTMLTranslator.visit_literal(self, node)
215 finally:
216 self.no_smarty -= 1
218 def visit_productionlist(self, node):
219 self.no_smarty += 1
220 try:
221 HTMLTranslator.visit_productionlist(self, node)
222 finally:
223 self.no_smarty -= 1
225 def encode(self, text):
226 text = HTMLTranslator.encode(self, text)
227 if self.no_smarty <= 0:
228 text = sphinx_smarty_pants(text)
229 return text