diff --git a/guzzle_sphinx_theme/__init__.py b/guzzle_sphinx_theme/__init__.py index 78363a2..09a5df4 100644 --- a/guzzle_sphinx_theme/__init__.py +++ b/guzzle_sphinx_theme/__init__.py @@ -4,8 +4,8 @@ import xml.etree.ElementTree as ET from docutils import nodes +from sphinx import version_info as sphinx_version from sphinx.locale import admonitionlabels -from sphinx.writers.html import HTMLTranslator as SphinxHTMLTranslator from pygments.style import Style from pygments.token import Keyword, Name, Comment, String, Error, \ @@ -16,7 +16,20 @@ def setup(app): """Setup conntects events to the sitemap builder""" app.connect('html-page-context', add_html_link) app.connect('build-finished', create_sitemap) - app.set_translator('html', HTMLTranslator) + + # Override several HTML translator methods. + # In Sphinx 1.4 and above, a warning is raised when adding a node that + # already exists, unless you pass `override=True`. + kwargs = {} if sphinx_version[:2] <= (1, 3) else {"override": True} + app.add_node(nodes.table, html=(visit_table, depart_table), **kwargs) + app.add_node(nodes.field, html=(visit_field, depart_field), **kwargs) + app.add_node(nodes.field_name, + html=(visit_field_name, depart_field_name), **kwargs) + app.add_node(nodes.field_body, + html=(visit_field_body, depart_field_body), **kwargs) + app.add_node(nodes.field_list, + html=(visit_field_list, depart_field_list), **kwargs) + app.sitemap_links = [] @@ -51,88 +64,96 @@ def html_theme_path(): return [os.path.dirname(os.path.abspath(__file__))] -class HTMLTranslator(SphinxHTMLTranslator): +# The subsequent functions affect how the document is translated to HTML, +# in most cases to work nicely with bootstrap. + +def visit_table(self, node, name=''): + """ + Override docutils default table formatter to not include a border + and to use Bootstrap CSS + See: http://sourceforge.net/p/docutils/code/HEAD/tree/trunk/docutils/docutils/writetml4css1/__init__.py#l1550 + """ + self.context.append(self.compact_p) + self.compact_p = True + classes = 'table table-bordered ' + self.settings.table_style + classes = classes.strip() + self.body.append( + self.starttag(node, 'table', CLASS=classes)) + + +def depart_table(self, node): """ - Handle translating to bootstrap structure. + This needs overridin' too """ - def visit_table(self, node, name=''): - """ - Override docutils default table formatter to not include a border - and to use Bootstrap CSS - See: http://sourceforge.net/p/docutils/code/HEAD/tree/trunk/docutils/docutils/writers/html4css1/__init__.py#l1550 - """ - self.context.append(self.compact_p) - self.compact_p = True - classes = 'table table-bordered ' + self.settings.table_style - classes = classes.strip() - self.body.append( - self.starttag(node, 'table', CLASS=classes)) - - def depart_table(self, node): - """ - This needs overridin' too - """ - self.compact_p = self.context.pop() - self.body.append('\n') - - def visit_field(self, node): - pass - - def depart_field(self, node): - pass - - def visit_field_name(self, node): - atts = {} - if self.in_docinfo: - atts['class'] = 'docinfo-name' - else: - atts['class'] = 'field-name' - self.context.append('') - self.body.append(self.starttag(node, 'dt', '', **atts)) - - def depart_field_name(self, node): - self.body.append('') - self.body.append(self.context.pop()) - - def visit_field_body(self, node): - self.body.append(self.starttag(node, 'dd', '', CLASS='field-body')) - self.set_class_on_child(node, 'first', 0) - field = node.parent - if (self.compact_field_list or - isinstance(field.parent, nodes.docinfo) or - field.parent.index(field) == len(field.parent) - 1): - # If we are in a compact list, the docinfo, or if this is - # the last field of the field list, do not add vertical - # space after last element. - self.set_class_on_child(node, 'last', -1) - - def depart_field_body(self, node): - self.body.append('\n') - - def visit_field_list(self, node): - self.context.append((self.compact_field_list, self.compact_p)) - self.compact_p = None - if 'compact' in node['classes']: - self.compact_field_list = True - elif (self.settings.compact_field_lists - and 'open' not in node['classes']): - self.compact_field_list = True - if self.compact_field_list: - for field in node: - field_body = field[-1] - assert isinstance(field_body, nodes.field_body) - children = [n for n in field_body - if not isinstance(n, nodes.Invisible)] - if not (len(children) == 0 or - len(children) == 1 and - isinstance(children[0], - (nodes.paragraph, nodes.line_block))): - self.compact_field_list = False - break - self.body.append(self.starttag(node, 'dl', frame='void', - rules='none', - CLASS='docutils field-list')) - - def depart_field_list(self, node): - self.body.append('\n') - self.compact_field_list, self.compact_p = self.context.pop() + self.compact_p = self.context.pop() + self.body.append('\n') + + +def visit_field(self, node): + pass + + +def depart_field(self, node): + pass + + +def visit_field_name(self, node): + atts = {} + if self.in_docinfo: + atts['class'] = 'docinfo-name' + else: + atts['class'] = 'field-name' + self.context.append('') + self.body.append(self.starttag(node, 'dt', '', **atts)) + + +def depart_field_name(self, node): + self.body.append('') + self.body.append(self.context.pop()) + + +def visit_field_body(self, node): + self.body.append(self.starttag(node, 'dd', '', CLASS='field-body')) + self.set_class_on_child(node, 'first', 0) + field = node.parent + if (self.compact_field_list or + isinstance(field.parent, nodes.docinfo) or + field.parent.index(field) == len(field.parent) - 1): + # If we are in a compact list, the docinfo, or if this is + # the last field of the field list, do not add vertical + # space after last element. + self.set_class_on_child(node, 'last', -1) + + +def depart_field_body(self, node): + self.body.append('\n') + + +def visit_field_list(self, node): + self.context.append((self.compact_field_list, self.compact_p)) + self.compact_p = None + if 'compact' in node['classes']: + self.compact_field_list = True + elif (self.settings.compact_field_lists + and 'open' not in node['classes']): + self.compact_field_list = True + if self.compact_field_list: + for field in node: + field_body = field[-1] + assert isinstance(field_body, nodes.field_body) + children = [n for n in field_body + if not isinstance(n, nodes.Invisible)] + if not (len(children) == 0 or + len(children) == 1 and + isinstance(children[0], + (nodes.paragraph, nodes.line_block))): + self.compact_field_list = False + break + self.body.append(self.starttag(node, 'dl', frame='void', + rules='none', + CLASS='docutils field-list')) + + +def depart_field_list(self, node): + self.body.append('\n') + self.compact_field_list, self.compact_p = self.context.pop() diff --git a/setup.py b/setup.py index ca2964b..147a753 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ url='https://github.com/guzzle/guzzle_sphinx_theme', packages=['guzzle_sphinx_theme'], include_package_data=True, - install_requires=['Sphinx>1.3'], + install_requires=['Sphinx>=1.2'], classifiers=( 'Development Status :: 3 - Alpha', 'Intended Audience :: Developers',