Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Respect the html_use_smartypants option #24

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
196 changes: 106 additions & 90 deletions guzzle_sphinx_theme/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,27 @@
import xml.etree.ElementTree as ET

from docutils import nodes
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, \
Number, Operator, Generic, Whitespace, Punctuation, Other, Literal
from sphinx import version_info as sphinx_version


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 = []


Expand All @@ -30,8 +38,8 @@ def add_html_link(app, pagename, templatename, context, doctree):
def create_sitemap(app, exception):
"""Generates the sitemap.xml from the collected HTML page links"""
if (not app.config['html_theme_options'].get('base_url', '') or
exception is not None or
not app.sitemap_links):
exception is not None or
not app.sitemap_links):
return

filename = app.outdir + "/sitemap.xml"
Expand All @@ -51,88 +59,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=''):
"""
Handle translating to bootstrap structure.
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
"""
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('</table>\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('</dt>')
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
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('</table>\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('</dt>')
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('</dd>\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('</dl>\n')
self.compact_field_list, self.compact_p = self.context.pop()
# 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('</dd>\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('</dl>\n')
self.compact_field_list, self.compact_p = self.context.pop()
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down