Fix #1858: Support numbering custom nodes

This commit is contained in:
Takeshi KOMIYA
2016-02-14 14:49:34 +09:00
parent a391b1a1db
commit 2ec60d5919
7 changed files with 85 additions and 19 deletions
+14 -4
View File
@@ -125,12 +125,22 @@ package.
.. versionchanged:: 0.5
Added the support for keyword arguments giving visit functions.
.. method:: Sphinx.add_enumerable_node(node, figtype, **kwds)
.. method:: Sphinx.add_enumerable_node(node, figtype, title_getter=None, **kwds)
Register a Docutils node class as a numfig target. Sphinx treats the node as
figure, table or code-block. And then the node is numbered automatically.
Register a Docutils node class as a numfig target. Sphinx numbers the node
automatically. And then the users can refer it using :rst:role:`numref`.
*figtype* should be one of ``figure``, ``table`` or ``code-block``.
*figtype* is a type of enumerable nodes. Each figtypes have individual
numbering sequences. As a system figtypes, ``figure``, ``table`` and
``code-block`` are defined. It is able to add custom nodes to these
default figtypes. It is also able to define new custom figtype if new
figtype is given.
*title_getter* is a getter function to obtain the title of node. It takes
an instance of the enumerable node, and it must return its title as string.
The title is used to the default title of references for :rst:role:`ref`.
By default, Sphinx searches ``docutils.nodes.caption`` or
``docutils.nodes.title`` from the node as a title.
Other keyword arguments are used for node visitor functions. See the
:meth:`Sphinx.add_node` for details.
+2 -2
View File
@@ -608,8 +608,8 @@ class Sphinx(object):
if depart:
setattr(translator, 'depart_'+node.__name__, depart)
def add_enumerable_node(self, node, figtype, **kwds):
self.enumerable_nodes[node] = figtype
def add_enumerable_node(self, node, figtype, title_getter=None, **kwds):
self.enumerable_nodes[node] = (figtype, title_getter)
self.add_node(node, **kwds)
def _directive_helper(self, obj, content=None, arguments=None, **options):
+12 -8
View File
@@ -494,10 +494,10 @@ class StandardDomain(Domain):
'option': 'unknown option: %(target)s',
}
enumerable_nodes = { # node_class -> figtype
nodes.figure: 'figure',
nodes.table: 'table',
nodes.container: 'code-block',
enumerable_nodes = { # node_class -> (figtype, title_getter)
nodes.figure: ('figure', None),
nodes.table: ('table', None),
nodes.container: ('code-block', None),
}
def clear_doc(self, docname):
@@ -735,9 +735,13 @@ class StandardDomain(Domain):
def get_numfig_title(self, node):
"""Get the title of enumerable nodes to refer them using its title"""
if self.is_enumerable_node(node):
for subnode in node:
if subnode.tagname in ('caption', 'title'):
return clean_astext(subnode)
_, title_getter = self.enumerable_nodes.get(node.__class__, (None, None))
if title_getter:
return title_getter(node)
else:
for subnode in node:
if subnode.tagname in ('caption', 'title'):
return clean_astext(subnode)
return None
@@ -752,5 +756,5 @@ class StandardDomain(Domain):
else:
return None
else:
figtype = self.enumerable_nodes.get(node.__class__)
figtype, _ = self.enumerable_nodes.get(node.__class__, (None, None))
return figtype
+13 -5
View File
@@ -265,14 +265,22 @@ class HTMLTranslator(BaseTranslator):
def append_fignumber(figtype, figure_id):
if figure_id in self.builder.fignumbers.get(figtype, {}):
self.body.append('<span class="caption-number">')
prefix = self.builder.config.numfig_format.get(figtype, '')
numbers = self.builder.fignumbers[figtype][figure_id]
self.body.append(prefix % '.'.join(map(str, numbers)) + ' ')
self.body.append('</span>')
prefix = self.builder.config.numfig_format.get(figtype)
if prefix is None:
msg = 'numfig_format is not defined for %s' % figtype
self.builder.warn(msg)
else:
numbers = self.builder.fignumbers[figtype][figure_id]
self.body.append(prefix % '.'.join(map(str, numbers)) + ' ')
self.body.append('</span>')
figtype = self.builder.env.domains['std'].get_figtype(node)
if figtype:
append_fignumber(figtype, node['ids'][0])
if len(node['ids']) == 0:
msg = 'Any IDs not assiend for %s node' % node.tagname
self.builder.env.warn_node(msg, node)
else:
append_fignumber(figtype, node['ids'][0])
def add_permalink_ref(self, node, title):
if node['ids'] and self.permalink_text and self.builder.add_permalinks:
@@ -21,6 +21,14 @@ First section
First my figure
.. _first_numbered_text:
.. numbered-text:: Hello world
.. _second_numbered_text:
.. numbered-text:: Hello Sphinx
Second section
==============
@@ -36,3 +44,5 @@ Reference section
* first_figure is :numref:`first_figure`
* first_my_figure is :numref:`first_my_figure`
* second_my_figure is :numref:`second_my_figure`
* first numbered_text is :numref:`first_numbered_text`
* second numbered_text is :numref:`second_numbered_text`
@@ -28,8 +28,38 @@ class MyFigure(Directive):
return [figure_node]
class numbered_text(nodes.Element):
pass
def visit_numbered_text(self, node):
self.body.append(self.starttag(node, 'div'))
self.add_fignumber(node)
self.body.append(node['title'])
self.body.append('</div>')
raise nodes.SkipNode
def get_title(node):
return node['title']
class NumberedText(Directive):
required_arguments = 1
final_argument_whitespace = True
def run(self):
return [numbered_text(title=self.arguments[0])]
def setup(app):
# my-figure
app.add_enumerable_node(my_figure, 'figure',
html=(visit_my_figure, depart_my_figure))
app.add_directive('my-figure', MyFigure)
# numbered_label
app.add_enumerable_node(numbered_text, 'original', get_title,
html=(visit_numbered_text, None))
app.add_directive('numbered-text', NumberedText)
app.config.numfig_format.setdefault('original', 'No.%s')
+4
View File
@@ -953,9 +953,13 @@ def test_enumerable_node(app, status, warning):
"Fig. 2", True),
(".//div[@class='figure']/p[@class='caption']/span[@class='caption-number']",
"Fig. 3", True),
(".//div//span[@class='caption-number']", "No.1 ", True),
(".//div//span[@class='caption-number']", "No.2 ", True),
(".//li/a/span", 'Fig. 1', True),
(".//li/a/span", 'Fig. 2', True),
(".//li/a/span", 'Fig. 3', True),
(".//li/a/span", 'No.1', True),
(".//li/a/span", 'No.2', True),
],
}