1 # -*- coding: utf-8 -*-
6 docutils writers handling Sphinx' custom nodes.
8 :copyright: 2007 by Georg Brandl.
9 :license: Python license.
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
):
21 if config
.get('use_smartypants', False):
22 self
.translator_class
= SmartyPantsHTMLTranslator
24 self
.translator_class
= HTMLTranslator
28 'deprecated': 'Deprecated in version %s',
29 'versionchanged': 'Changed in version %s',
30 'versionadded': 'New in version %s',
33 class HTMLTranslator(BaseTranslator
):
35 Our custom HTML translator.
38 def __init__(self
, *args
, **kwds
):
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>')
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(', ')
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']
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
):
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
)
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']}
139 self
.body
.append(self
.starttag(node
, 'h%d' % h_level
, '', **attrs
))
140 self
.context
.append('</h%d>\n' % h_level
)
142 BaseTranslator
.visit_title(self
, node
, move_ids
)
145 def visit_literal_block(self
, node
):
146 from .highlighting
import highlight_block
147 self
.body
.append(highlight_block(node
.rawsource
, self
.highlightlang
))
150 def visit_productionlist(self
, node
):
151 self
.body
.append(self
.starttag(node
, 'pre'))
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
) +
161 lastname
= production
['tokenname']
163 self
.body
.append('%s ' % (' '*len(lastname
)))
164 production
.walkabout(self
)
165 self
.body
.append('\n')
166 self
.body
.append('</pre>\n')
168 def depart_productionlist(self
, node
):
171 def visit_production(self
, node
):
173 def depart_production(self
, node
):
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
):
183 def depart_compact_paragraph(self
, node
):
186 def visit_highlightlang(self
, node
):
187 self
.highlightlang
= node
['lang']
188 def depart_highlightlang(self
, node
):
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
196 def visit_index(self
, node
):
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
):
208 HTMLTranslator
.__init
__(self
, *args
, **kwds
)
210 def visit_literal(self
, node
):
213 # this raises SkipNode
214 HTMLTranslator
.visit_literal(self
, node
)
218 def visit_productionlist(self
, node
):
221 HTMLTranslator
.visit_productionlist(self
, node
)
225 def encode(self
, text
):
226 text
= HTMLTranslator
.encode(self
, text
)
227 if self
.no_smarty
<= 0:
228 text
= sphinx_smarty_pants(text
)