mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Add :numref: role to refer figures, tables and code-blocks by its fignum
This commit is contained in:
parent
86ff9589bc
commit
4c82a16564
@ -22,7 +22,7 @@ from sphinx.roles import XRefRole
|
|||||||
from sphinx.locale import l_, _
|
from sphinx.locale import l_, _
|
||||||
from sphinx.domains import Domain, ObjType
|
from sphinx.domains import Domain, ObjType
|
||||||
from sphinx.directives import ObjectDescription
|
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.nodes import clean_astext, make_refnode
|
||||||
from sphinx.util.compat import Directive
|
from sphinx.util.compat import Directive
|
||||||
|
|
||||||
@ -466,6 +466,9 @@ class StandardDomain(Domain):
|
|||||||
# links to headings or arbitrary labels
|
# links to headings or arbitrary labels
|
||||||
'ref': XRefRole(lowercase=True, innernodeclass=nodes.emphasis,
|
'ref': XRefRole(lowercase=True, innernodeclass=nodes.emphasis,
|
||||||
warn_dangling=True),
|
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
|
# links to labels, without a different title
|
||||||
'keyword': XRefRole(warn_dangling=True),
|
'keyword': XRefRole(warn_dangling=True),
|
||||||
}
|
}
|
||||||
@ -489,6 +492,7 @@ class StandardDomain(Domain):
|
|||||||
'term': 'term not in glossary: %(target)s',
|
'term': 'term not in glossary: %(target)s',
|
||||||
'ref': 'undefined label: %(target)s (if the link has no caption '
|
'ref': 'undefined label: %(target)s (if the link has no caption '
|
||||||
'the label must precede a section header)',
|
'the label must precede a section header)',
|
||||||
|
'numref': 'undefined label: %(target)s',
|
||||||
'keyword': 'unknown keyword: %(target)s',
|
'keyword': 'unknown keyword: %(target)s',
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -574,6 +578,26 @@ class StandardDomain(Domain):
|
|||||||
continue
|
continue
|
||||||
labels[name] = docname, labelid, sectname
|
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,
|
def resolve_xref(self, env, fromdocname, builder,
|
||||||
typ, target, node, contnode):
|
typ, target, node, contnode):
|
||||||
if typ == 'ref':
|
if typ == 'ref':
|
||||||
@ -589,23 +613,35 @@ class StandardDomain(Domain):
|
|||||||
('', '', ''))
|
('', '', ''))
|
||||||
if not docname:
|
if not docname:
|
||||||
return None
|
return None
|
||||||
newnode = nodes.reference('', '', internal=True)
|
|
||||||
innernode = nodes.emphasis(sectname, sectname)
|
return self.build_reference_node(fromdocname, builder,
|
||||||
if docname == fromdocname:
|
docname, labelid, sectname)
|
||||||
newnode['refid'] = labelid
|
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:
|
else:
|
||||||
# set more info in contnode; in case the
|
title = title.replace('#', '.'.join(map(str, fignumber)))
|
||||||
# get_relative_uri call raises NoUri,
|
|
||||||
# the builder will then have to resolve these
|
return self.build_reference_node(fromdocname, builder,
|
||||||
contnode = addnodes.pending_xref('')
|
docname, labelid, title)
|
||||||
contnode['refdocname'] = docname
|
|
||||||
contnode['refsectname'] = sectname
|
|
||||||
newnode['refuri'] = builder.get_relative_uri(
|
|
||||||
fromdocname, docname)
|
|
||||||
if labelid:
|
|
||||||
newnode['refuri'] += '#' + labelid
|
|
||||||
newnode.append(innernode)
|
|
||||||
return newnode
|
|
||||||
elif typ == 'keyword':
|
elif typ == 'keyword':
|
||||||
# keywords are oddballs: they are referenced by named labels
|
# keywords are oddballs: they are referenced by named labels
|
||||||
docname, labelid, _ = self.data['labels'].get(target, ('', '', ''))
|
docname, labelid, _ = self.data['labels'].get(target, ('', '', ''))
|
||||||
|
@ -37,7 +37,7 @@ from docutils.frontend import OptionParser
|
|||||||
|
|
||||||
from sphinx import addnodes
|
from sphinx import addnodes
|
||||||
from sphinx.util import url_re, get_matching_docs, docname_join, split_into, \
|
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.nodes import clean_astext, make_refnode, WarningStream
|
||||||
from sphinx.util.osutil import SEP, find_catalog_files, getcwd, fs_encoding
|
from sphinx.util.osutil import SEP, find_catalog_files, getcwd, fs_encoding
|
||||||
from sphinx.util.console import bold, purple
|
from sphinx.util.console import bold, purple
|
||||||
@ -1705,9 +1705,6 @@ class BuildEnvironment:
|
|||||||
self.toc_fignumbers = {}
|
self.toc_fignumbers = {}
|
||||||
fignum_counter = {}
|
fignum_counter = {}
|
||||||
|
|
||||||
def has_child(node, cls):
|
|
||||||
return any(isinstance(child, cls) for child in node)
|
|
||||||
|
|
||||||
def get_section_number(docname, section):
|
def get_section_number(docname, section):
|
||||||
anchorname = '#' + section['ids'][0]
|
anchorname = '#' + section['ids'][0]
|
||||||
secnumbers = self.toc_secnumbers.get(docname, {})
|
secnumbers = self.toc_secnumbers.get(docname, {})
|
||||||
@ -1749,16 +1746,10 @@ class BuildEnvironment:
|
|||||||
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if isinstance(subnode, nodes.figure):
|
figtype = get_figtype(subnode)
|
||||||
figure_id = subnode['ids'][0]
|
if figtype:
|
||||||
register_fignumber(docname, secnum, 'figure', figure_id)
|
register_fignumber(docname, secnum,
|
||||||
elif isinstance(subnode, nodes.table):
|
figtype, subnode['ids'][0])
|
||||||
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)
|
|
||||||
|
|
||||||
_walk_doctree(docname, subnode, secnum)
|
_walk_doctree(docname, subnode, secnum)
|
||||||
|
|
||||||
|
@ -475,3 +475,20 @@ class PeekableIterator(object):
|
|||||||
item = next(self)
|
item = next(self)
|
||||||
self.push(item)
|
self.push(item)
|
||||||
return 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
|
||||||
|
Loading…
Reference in New Issue
Block a user