mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2026-09-03 20:52:55 -05:00
Fix #1858: Support numbering custom nodes
This commit is contained in:
+14
-4
@@ -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.
|
||||
|
||||
@@ -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
@@ -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
@@ -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')
|
||||
|
||||
@@ -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),
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user