Refactor sphinx.environment: Reimplemnt process_refonly_bullet_lists() as a transform

This commit is contained in:
Takeshi KOMIYA 2016-09-10 23:31:43 +09:00
parent 7c99bd5d18
commit f8c1c65c21
6 changed files with 127 additions and 64 deletions

View File

@ -732,7 +732,6 @@ class BuildEnvironment(object):
self.process_images(docname, doctree) self.process_images(docname, doctree)
self.process_downloads(docname, doctree) self.process_downloads(docname, doctree)
self.process_metadata(docname, doctree) self.process_metadata(docname, doctree)
self.process_refonly_bullet_lists(docname, doctree)
self.create_title_from(docname, doctree) self.create_title_from(docname, doctree)
self.note_indexentries_from(docname, doctree) self.note_indexentries_from(docname, doctree)
self.build_toc_from(docname, doctree) self.build_toc_from(docname, doctree)
@ -977,67 +976,6 @@ class BuildEnvironment(object):
del doctree[0] del doctree[0]
def process_refonly_bullet_lists(self, docname, doctree):
"""Change refonly bullet lists to use compact_paragraphs.
Specifically implemented for 'Indices and Tables' section, which looks
odd when html_compact_lists is false.
"""
if self.config.html_compact_lists:
return
class RefOnlyListChecker(nodes.GenericNodeVisitor):
"""Raise `nodes.NodeFound` if non-simple list item is encountered.
Here 'simple' means a list item containing only a paragraph with a
single reference in it.
"""
def default_visit(self, node):
raise nodes.NodeFound
def visit_bullet_list(self, node):
pass
def visit_list_item(self, node):
children = []
for child in node.children:
if not isinstance(child, nodes.Invisible):
children.append(child)
if len(children) != 1:
raise nodes.NodeFound
if not isinstance(children[0], nodes.paragraph):
raise nodes.NodeFound
para = children[0]
if len(para) != 1:
raise nodes.NodeFound
if not isinstance(para[0], addnodes.pending_xref):
raise nodes.NodeFound
raise nodes.SkipChildren
def invisible_visit(self, node):
"""Invisible nodes should be ignored."""
pass
def check_refonly_list(node):
"""Check for list with only references in it."""
visitor = RefOnlyListChecker(doctree)
try:
node.walk(visitor)
except nodes.NodeFound:
return False
else:
return True
for node in doctree.traverse(nodes.bullet_list):
if check_refonly_list(node):
for item in node.traverse(nodes.list_item):
para = item[0]
ref = para[0]
compact_para = addnodes.compact_paragraph()
compact_para += ref
item.replace(para, compact_para)
def create_title_from(self, docname, document): def create_title_from(self, docname, document):
"""Add a title node to the document (just copy the first section title), """Add a title node to the document (just copy the first section title),
and store that title in the environment. and store that title in the environment.

View File

@ -18,6 +18,7 @@ from sphinx.transforms import (
DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks, SortIds, DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks, SortIds,
AutoNumbering, AutoIndexUpgrader, FilterSystemMessages, AutoNumbering, AutoIndexUpgrader, FilterSystemMessages,
) )
from sphinx.transforms.compact_bullet_list import RefOnlyBulletListTransform
from sphinx.transforms.i18n import ( from sphinx.transforms.i18n import (
PreserveTranslatableMessages, Locale, RemoveTranslatableInline, PreserveTranslatableMessages, Locale, RemoveTranslatableInline,
) )
@ -65,7 +66,8 @@ class SphinxStandaloneReader(SphinxBaseReader):
transforms = [ApplySourceWorkaround, ExtraTranslatableNodes, PreserveTranslatableMessages, transforms = [ApplySourceWorkaround, ExtraTranslatableNodes, PreserveTranslatableMessages,
Locale, CitationReferences, DefaultSubstitutions, MoveModuleTargets, Locale, CitationReferences, DefaultSubstitutions, MoveModuleTargets,
HandleCodeBlocks, AutoNumbering, AutoIndexUpgrader, SortIds, HandleCodeBlocks, AutoNumbering, AutoIndexUpgrader, SortIds,
RemoveTranslatableInline, PreserveTranslatableMessages, FilterSystemMessages] RemoveTranslatableInline, PreserveTranslatableMessages, FilterSystemMessages,
RefOnlyBulletListTransform]
class SphinxI18nReader(SphinxBaseReader): class SphinxI18nReader(SphinxBaseReader):
@ -79,7 +81,7 @@ class SphinxI18nReader(SphinxBaseReader):
transforms = [ApplySourceWorkaround, ExtraTranslatableNodes, CitationReferences, transforms = [ApplySourceWorkaround, ExtraTranslatableNodes, CitationReferences,
DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks, DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks,
AutoNumbering, SortIds, RemoveTranslatableInline, AutoNumbering, SortIds, RemoveTranslatableInline,
FilterSystemMessages] FilterSystemMessages, RefOnlyBulletListTransform]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
SphinxBaseReader.__init__(self, *args, **kwargs) SphinxBaseReader.__init__(self, *args, **kwargs)

View File

@ -0,0 +1,82 @@
# -*- coding: utf-8 -*-
"""
sphinx.transforms.compact_bullet_list
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Docutils transforms used by Sphinx when reading documents.
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
from docutils import nodes
from docutils.transforms import Transform
from sphinx import addnodes
class RefOnlyListChecker(nodes.GenericNodeVisitor):
"""Raise `nodes.NodeFound` if non-simple list item is encountered.
Here 'simple' means a list item containing only a paragraph with a
single reference in it.
"""
def default_visit(self, node):
raise nodes.NodeFound
def visit_bullet_list(self, node):
pass
def visit_list_item(self, node):
children = []
for child in node.children:
if not isinstance(child, nodes.Invisible):
children.append(child)
if len(children) != 1:
raise nodes.NodeFound
if not isinstance(children[0], nodes.paragraph):
raise nodes.NodeFound
para = children[0]
if len(para) != 1:
raise nodes.NodeFound
if not isinstance(para[0], addnodes.pending_xref):
raise nodes.NodeFound
raise nodes.SkipChildren
def invisible_visit(self, node):
"""Invisible nodes should be ignored."""
pass
class RefOnlyBulletListTransform(Transform):
"""Change refonly bullet lists to use compact_paragraphs.
Specifically implemented for 'Indices and Tables' section, which looks
odd when html_compact_lists is false.
"""
default_priority = 100
def apply(self):
env = self.document.settings.env
if env.config.html_compact_lists:
return
def check_refonly_list(node):
"""Check for list with only references in it."""
visitor = RefOnlyListChecker(self.document)
try:
node.walk(visitor)
except nodes.NodeFound:
return False
else:
return True
for node in self.document.traverse(nodes.bullet_list):
if check_refonly_list(node):
for item in node.traverse(nodes.list_item):
para = item[0]
ref = para[0]
compact_para = addnodes.compact_paragraph()
compact_para += ref
item.replace(para, compact_para)

View File

@ -0,0 +1,8 @@
# -*- coding: utf-8 -*-
master_doc = 'index'
html_compact_lists = False
latex_documents = [
(master_doc, 'test.tex', 'The basic Sphinx documentation for testing', 'Sphinx', 'report')
]

View File

@ -0,0 +1,14 @@
test-refonly_bullet_list
========================
List A:
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
List B:
* Hello
* Sphinx
* World

View File

@ -15,6 +15,7 @@ import pickle
from docutils import frontend, utils, nodes from docutils import frontend, utils, nodes
from docutils.parsers import rst from docutils.parsers import rst
from sphinx import addnodes
from sphinx.util import texescape from sphinx.util import texescape
from sphinx.writers.html import HTMLWriter, SmartyPantsHTMLTranslator from sphinx.writers.html import HTMLWriter, SmartyPantsHTMLTranslator
from sphinx.writers.latex import LaTeXWriter, LaTeXTranslator from sphinx.writers.latex import LaTeXWriter, LaTeXTranslator
@ -188,3 +189,21 @@ def test_keep_warnings_is_False(app, status, warning):
doctree = pickle.loads((app.doctreedir / 'index.doctree').bytes()) doctree = pickle.loads((app.doctreedir / 'index.doctree').bytes())
assert_node(doctree[0], nodes.section) assert_node(doctree[0], nodes.section)
assert len(doctree[0]) == 1 assert len(doctree[0]) == 1
@with_app(buildername='dummy', testroot='refonly_bullet_list')
def test_compact_refonly_bullet_list(app, status, warning):
app.builder.build_all()
doctree = pickle.loads((app.doctreedir / 'index.doctree').bytes())
assert_node(doctree[0], nodes.section)
assert len(doctree[0]) == 5
assert doctree[0][1].astext() == 'List A:'
assert_node(doctree[0][2], nodes.bullet_list)
assert_node(doctree[0][2][0][0], addnodes.compact_paragraph)
assert doctree[0][2][0][0].astext() == 'genindex'
assert doctree[0][3].astext() == 'List B:'
assert_node(doctree[0][4], nodes.bullet_list)
assert_node(doctree[0][4][0][0], nodes.paragraph)
assert doctree[0][4][0][0].astext() == 'Hello'