mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Add ReferenceResolver as a post-transform
This commit is contained in:
parent
7117206b2a
commit
eb40a36aa4
@ -105,6 +105,7 @@ builtin_extensions = (
|
||||
'sphinx.directives.other',
|
||||
'sphinx.directives.patches',
|
||||
'sphinx.roles',
|
||||
'sphinx.transforms.post_transforms',
|
||||
# collectors should be loaded by specific order
|
||||
'sphinx.environment.collectors.dependencies',
|
||||
'sphinx.environment.collectors.asset',
|
||||
|
@ -44,6 +44,7 @@ from sphinx.util.matching import compile_matchers
|
||||
from sphinx.util.parallel import ParallelTasks, parallel_available, make_chunks
|
||||
from sphinx.util.websupport import is_commentable
|
||||
from sphinx.errors import SphinxError, ExtensionError
|
||||
from sphinx.transforms import SphinxTransformer
|
||||
from sphinx.versioning import add_uids, merge_doctrees
|
||||
from sphinx.deprecation import RemovedInSphinx20Warning
|
||||
from sphinx.environment.adapters.indexentries import IndexEntries
|
||||
@ -920,38 +921,16 @@ class BuildEnvironment(object):
|
||||
|
||||
def resolve_references(self, doctree, fromdocname, builder):
|
||||
# type: (nodes.Node, unicode, Builder) -> None
|
||||
for node in doctree.traverse(addnodes.pending_xref):
|
||||
contnode = node[0].deepcopy()
|
||||
newnode = None
|
||||
|
||||
typ = node['reftype']
|
||||
target = node['reftarget']
|
||||
refdoc = node.get('refdoc', fromdocname)
|
||||
domain = None
|
||||
|
||||
# apply all post-transforms
|
||||
try:
|
||||
if 'refdomain' in node and node['refdomain']:
|
||||
# let the domain try to resolve the reference
|
||||
try:
|
||||
domain = self.domains[node['refdomain']]
|
||||
except KeyError:
|
||||
raise NoUri
|
||||
newnode = domain.resolve_xref(self, refdoc, builder,
|
||||
typ, target, node, contnode)
|
||||
# really hardwired reference types
|
||||
elif typ == 'any':
|
||||
newnode = self._resolve_any_reference(builder, refdoc, node, contnode)
|
||||
# no new node found? try the missing-reference event
|
||||
if newnode is None:
|
||||
newnode = builder.app.emit_firstresult(
|
||||
'missing-reference', self, node, contnode)
|
||||
# still not found? warn if node wishes to be warned about or
|
||||
# we are in nit-picky mode
|
||||
if newnode is None:
|
||||
self._warn_missing_reference(refdoc, typ, target, node, domain)
|
||||
except NoUri:
|
||||
newnode = contnode
|
||||
node.replace_self(newnode or contnode)
|
||||
# set env.docname during applying post-transforms
|
||||
self.temp_data['docname'] = fromdocname
|
||||
|
||||
transformer = SphinxTransformer(doctree)
|
||||
transformer.add_transforms(self.app.post_transforms)
|
||||
transformer.apply_transforms()
|
||||
finally:
|
||||
self.temp_data.clear()
|
||||
|
||||
# remove only-nodes that do not belong to our builder
|
||||
process_only_nodes(doctree, builder.tags)
|
||||
|
@ -10,8 +10,9 @@
|
||||
"""
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.transforms import Transform
|
||||
from docutils.transforms import Transform, Transformer
|
||||
from docutils.transforms.parts import ContentsFilter
|
||||
from docutils.utils import new_document
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.locale import _
|
||||
@ -69,6 +70,28 @@ class SphinxTransform(Transform):
|
||||
return self.document.settings.env.config
|
||||
|
||||
|
||||
class SphinxTransformer(Transformer):
|
||||
"""
|
||||
A transformer for Sphinx.
|
||||
"""
|
||||
|
||||
document = None # type: nodes.Node
|
||||
|
||||
def apply_transforms(self):
|
||||
# type: () -> None
|
||||
if isinstance(self.document, nodes.document):
|
||||
Transformer.apply_transforms(self)
|
||||
else:
|
||||
# wrap the target node by document node during transforming
|
||||
try:
|
||||
document = new_document('')
|
||||
document += self.document
|
||||
self.document = document
|
||||
Transformer.apply_transforms(self)
|
||||
finally:
|
||||
self.document = self.document[0]
|
||||
|
||||
|
||||
class DefaultSubstitutions(SphinxTransform):
|
||||
"""
|
||||
Replace some substitutions if they aren't defined in the document.
|
||||
|
74
sphinx/transforms/post_transforms.py
Normal file
74
sphinx/transforms/post_transforms.py
Normal file
@ -0,0 +1,74 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
sphinx.transforms.post_transforms
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Docutils transforms used by Sphinx.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.environment import NoUri
|
||||
from sphinx.transforms import SphinxTransform
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any, Dict # NOQA
|
||||
from sphinx.application import Sphinx # NOQA
|
||||
|
||||
|
||||
class ReferencesResolver(SphinxTransform):
|
||||
"""
|
||||
Resolves cross-references on doctrees.
|
||||
"""
|
||||
|
||||
default_priority = 10
|
||||
|
||||
def apply(self):
|
||||
# type: () -> None
|
||||
for node in self.document.traverse(addnodes.pending_xref):
|
||||
contnode = node[0].deepcopy()
|
||||
newnode = None
|
||||
|
||||
typ = node['reftype']
|
||||
target = node['reftarget']
|
||||
refdoc = node.get('refdoc', self.env.docname)
|
||||
domain = None
|
||||
|
||||
try:
|
||||
if 'refdomain' in node and node['refdomain']:
|
||||
# let the domain try to resolve the reference
|
||||
try:
|
||||
domain = self.env.domains[node['refdomain']]
|
||||
except KeyError:
|
||||
raise NoUri
|
||||
newnode = domain.resolve_xref(self.env, refdoc, self.app.builder,
|
||||
typ, target, node, contnode)
|
||||
# really hardwired reference types
|
||||
elif typ == 'any':
|
||||
newnode = self.env._resolve_any_reference(self.app.builder, refdoc,
|
||||
node, contnode)
|
||||
# no new node found? try the missing-reference event
|
||||
if newnode is None:
|
||||
newnode = self.app.emit_firstresult('missing-reference', self.env,
|
||||
node, contnode)
|
||||
# still not found? warn if node wishes to be warned about or
|
||||
# we are in nit-picky mode
|
||||
if newnode is None:
|
||||
self.env._warn_missing_reference(refdoc, typ, target, node, domain)
|
||||
except NoUri:
|
||||
newnode = contnode
|
||||
node.replace_self(newnode or contnode)
|
||||
|
||||
|
||||
def setup(app):
|
||||
# type: (Sphinx) -> Dict[unicode, Any]
|
||||
app.add_post_transform(ReferencesResolver)
|
||||
|
||||
return {
|
||||
'version': 'builtin',
|
||||
'parallel_read_safe': True,
|
||||
'parallel_write_safe': True,
|
||||
}
|
Loading…
Reference in New Issue
Block a user