summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortk0miya <i.tkomiya@gmail.com>2014-10-01 00:33:00 +0900
committertk0miya <i.tkomiya@gmail.com>2014-10-01 00:33:00 +0900
commit52ec28b5cd5b0298fc9a9f4ca7c4edb6035d3326 (patch)
tree3089f29ff326a5a3a8bc663cf60383f1f1efd2a3
parent1408088af1431281e53f8f2aa862d802d8dcb234 (diff)
downloadsphinx-52ec28b5cd5b0298fc9a9f4ca7c4edb6035d3326.tar.gz
Add :numref: role to refer figures, tables and code-blocks by its fignum
-rw-r--r--sphinx/domains/std.py70
-rw-r--r--sphinx/environment.py19
-rw-r--r--sphinx/util/__init__.py17
3 files changed, 75 insertions, 31 deletions
diff --git a/sphinx/domains/std.py b/sphinx/domains/std.py
index 0338a6b5..c2290f91 100644
--- a/sphinx/domains/std.py
+++ b/sphinx/domains/std.py
@@ -22,7 +22,7 @@ from sphinx.roles import XRefRole
from sphinx.locale import l_, _
from sphinx.domains import Domain, ObjType
from sphinx.directives import ObjectDescription
-from sphinx.util import ws_re
+from sphinx.util import ws_re, get_figtype
from sphinx.util.nodes import clean_astext, make_refnode
from sphinx.util.compat import Directive
@@ -466,6 +466,9 @@ class StandardDomain(Domain):
# links to headings or arbitrary labels
'ref': XRefRole(lowercase=True, innernodeclass=nodes.emphasis,
warn_dangling=True),
+ # links to labels of numbered figures, tables and code-blocks
+ 'numref': XRefRole(lowercase=True,
+ warn_dangling=True),
# links to labels, without a different title
'keyword': XRefRole(warn_dangling=True),
}
@@ -489,6 +492,7 @@ class StandardDomain(Domain):
'term': 'term not in glossary: %(target)s',
'ref': 'undefined label: %(target)s (if the link has no caption '
'the label must precede a section header)',
+ 'numref': 'undefined label: %(target)s',
'keyword': 'unknown keyword: %(target)s',
}
@@ -574,6 +578,26 @@ class StandardDomain(Domain):
continue
labels[name] = docname, labelid, sectname
+ def build_reference_node(self, fromdocname, builder,
+ docname, labelid, sectname):
+ newnode = nodes.reference('', '', internal=True)
+ innernode = nodes.emphasis(sectname, sectname)
+ if docname == fromdocname:
+ newnode['refid'] = labelid
+ else:
+ # set more info in contnode; in case the
+ # get_relative_uri call raises NoUri,
+ # the builder will then have to resolve these
+ contnode = addnodes.pending_xref('')
+ contnode['refdocname'] = docname
+ contnode['refsectname'] = sectname
+ newnode['refuri'] = builder.get_relative_uri(
+ fromdocname, docname)
+ if labelid:
+ newnode['refuri'] += '#' + labelid
+ newnode.append(innernode)
+ return newnode
+
def resolve_xref(self, env, fromdocname, builder,
typ, target, node, contnode):
if typ == 'ref':
@@ -589,23 +613,35 @@ class StandardDomain(Domain):
('', '', ''))
if not docname:
return None
- newnode = nodes.reference('', '', internal=True)
- innernode = nodes.emphasis(sectname, sectname)
- if docname == fromdocname:
- newnode['refid'] = labelid
+
+ return self.build_reference_node(fromdocname, builder,
+ docname, labelid, sectname)
+ elif typ == 'numref':
+ docname, labelid = self.data['anonlabels'].get(target, ('', ''))
+ if not docname:
+ return None
+
+ if env.config.numfig is False:
+ env.warn(fromdocname, 'numfig is disabled. :numref: is ignored.')
+ return contnode
+
+ try:
+ target = env.get_doctree(docname).ids[labelid]
+ figtype = get_figtype(target)
+ figure_id = target['ids'][0]
+ fignumber = env.toc_fignumbers[docname][figtype][figure_id]
+ except IndexError:
+ return None
+
+ title = contnode.astext()
+ if labelid == title:
+ prefix = env.config.numfig_prefix.get(figtype, '')
+ title = prefix + '.'.join(map(str, fignumber))
else:
- # set more info in contnode; in case the
- # get_relative_uri call raises NoUri,
- # the builder will then have to resolve these
- contnode = addnodes.pending_xref('')
- contnode['refdocname'] = docname
- contnode['refsectname'] = sectname
- newnode['refuri'] = builder.get_relative_uri(
- fromdocname, docname)
- if labelid:
- newnode['refuri'] += '#' + labelid
- newnode.append(innernode)
- return newnode
+ title = title.replace('#', '.'.join(map(str, fignumber)))
+
+ return self.build_reference_node(fromdocname, builder,
+ docname, labelid, title)
elif typ == 'keyword':
# keywords are oddballs: they are referenced by named labels
docname, labelid, _ = self.data['labels'].get(target, ('', '', ''))
diff --git a/sphinx/environment.py b/sphinx/environment.py
index d9be0be5..52d5ff08 100644
--- a/sphinx/environment.py
+++ b/sphinx/environment.py
@@ -37,7 +37,7 @@ from docutils.frontend import OptionParser
from sphinx import addnodes
from sphinx.util import url_re, get_matching_docs, docname_join, split_into, \
- FilenameUniqDict
+ FilenameUniqDict, get_figtype
from sphinx.util.nodes import clean_astext, make_refnode, WarningStream
from sphinx.util.osutil import SEP, find_catalog_files, getcwd, fs_encoding
from sphinx.util.console import bold, purple
@@ -1705,9 +1705,6 @@ class BuildEnvironment:
self.toc_fignumbers = {}
fignum_counter = {}
- def has_child(node, cls):
- return any(isinstance(child, cls) for child in node)
-
def get_section_number(docname, section):
anchorname = '#' + section['ids'][0]
secnumbers = self.toc_secnumbers.get(docname, {})
@@ -1749,16 +1746,10 @@ class BuildEnvironment:
continue
- if isinstance(subnode, nodes.figure):
- figure_id = subnode['ids'][0]
- register_fignumber(docname, secnum, 'figure', figure_id)
- elif isinstance(subnode, nodes.table):
- table_id = subnode['ids'][0]
- register_fignumber(docname, secnum, 'table', table_id)
- elif isinstance(subnode, nodes.container):
- if has_child(subnode, nodes.literal_block):
- code_block_id = subnode['ids'][0]
- register_fignumber(docname, secnum, 'code-block', code_block_id)
+ figtype = get_figtype(subnode)
+ if figtype:
+ register_fignumber(docname, secnum,
+ figtype, subnode['ids'][0])
_walk_doctree(docname, subnode, secnum)
diff --git a/sphinx/util/__init__.py b/sphinx/util/__init__.py
index e7277520..024e25b1 100644
--- a/sphinx/util/__init__.py
+++ b/sphinx/util/__init__.py
@@ -475,3 +475,20 @@ class PeekableIterator(object):
item = next(self)
self.push(item)
return item
+
+
+def get_figtype(node):
+ """Return figtype for given node."""
+ def has_child(node, cls):
+ return any(isinstance(child, cls) for child in node)
+
+ from docutils import nodes
+ if isinstance(node, nodes.figure):
+ return 'figure'
+ elif isinstance(node, nodes.table):
+ return 'table'
+ elif isinstance(node, nodes.container):
+ if has_child(node, nodes.literal_block):
+ return 'code-block'
+
+ return None