This repository was archived by the owner on Apr 9, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 41
/
Copy pathdomains.py
205 lines (173 loc) · 7.54 KB
/
domains.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
from sphinx.util import logging
from .utils import get_ref_xref_data, get_ref_obj_data, get_ref_numref_data
logger = logging.getLogger(__name__)
class HoverXRefBaseDomain:
hoverxref_types = (
'hoverxref',
'hoverxreftooltip',
'hoverxrefmodal',
)
def _inject_hoverxref_data(self, env, refnode, typ, docname, docpath, labelid):
classes = ['hoverxref']
type_class = None
if typ == 'hoverxreftooltip':
type_class = 'tooltip'
classes.append(type_class)
elif typ == 'hoverxrefmodal':
type_class = 'modal'
classes.append(type_class)
if not type_class:
type_class = env.config.hoverxref_role_types.get(typ)
if not type_class:
default = env.config.hoverxref_default_type
type_class = default
logger.info(
'Using default style (%s) for unknown typ (%s). '
'Define it in hoverxref_role_types.',
default,
typ,
)
classes.append(type_class)
refnode.replace_attr('classes', classes)
project = env.config.hoverxref_project
version = env.config.hoverxref_version
refnode._hoverxref = {
'data-project': project,
'data-version': version,
'data-doc': docname,
'data-docpath': docpath,
'data-section': labelid,
}
url = refnode.get('refuri')
if url:
refnode._hoverxref.update({
# FIXME: data-url requires to use the full URL here. At this
# point, we need to know the domain where the project is hosted
'data-url': f'https://sphinx-hoverxref--146.org.readthedocs.build/en/146/{url}',
})
else:
logger.info(
'refuri not found for node. node=%s',
refnode.__dict__,
)
def _get_docpath(self, builder, docname):
docpath = builder.get_outfilename(docname)
docpath = docpath.replace(builder.outdir, '')
return docpath
def _is_ignored_ref(self, env, target):
# HACK: skip all references if the builder is non-html. We shouldn't
# have overridden the Domain in first instance at ``setup_domains``
# function, but at that time ``app.builder`` is not yet initialized. If
# we suscribe ourselves to ``builder-initied`` it's too late and our
# override does not take effect. Other builders (e.g. LatexBuilder) may
# fail with internal functions we use (e.g. builder.get_outfilename).
# So, we are skipping it here :(
if env.app.builder.format != 'html':
return True
if target in env.config.hoverxref_ignore_refs:
logger.info(
'Ignoring reference in hoverxref_ignore_refs. target=%s',
target,
)
return True
return False
class HoverXRefPythonDomainMixin(HoverXRefBaseDomain):
def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode):
refnode = super().resolve_xref(env, fromdocname, builder, typ, target, node, contnode)
if refnode is None:
return refnode
if any([
not env.config.hoverxref_is_configured,
self._is_ignored_ref(env, target),
]):
return refnode
modname = node.get('py:module')
clsname = node.get('py:class')
searchmode = node.hasattr('refspecific') and 1 or 0
matches = self.find_obj(env, modname, clsname, target,
typ, searchmode)
name, obj = matches[0]
docname, labelid = obj[0], name
docpath = self._get_docpath(builder, docname)
self._inject_hoverxref_data(env, refnode, typ, docname, docpath, labelid)
logger.debug(
':ref: _hoverxref injected: fromdocname=%s %s',
fromdocname,
refnode._hoverxref,
)
return refnode
class HoverXRefStandardDomainMixin(HoverXRefBaseDomain):
"""
Mixin for ``StandardDomain`` to save the values after the xref resolution.
``:ref:`` are treating as a different node in Sphinx
(``sphinx.addnodes.pending_xref``). These nodes are translated to regular
``docsutils.nodes.reference`` for this domain class.
Before loosing the data used to resolve the reference, our customized domain
saves it inside the node itself to be used later by the ``HTMLTranslator``.
"""
def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode):
if typ in self.hoverxref_types:
resolver = self._resolve_ref_xref
return resolver(env, fromdocname, builder, typ, target, node, contnode)
return super().resolve_xref(env, fromdocname, builder, typ, target, node, contnode)
# NOTE: We could override more ``_resolve_xref`` method apply hover in more places
def _resolve_ref_xref(self, env, fromdocname, builder, typ, target, node, contnode):
refnode = super()._resolve_ref_xref(env, fromdocname, builder, typ, target, node, contnode)
if refnode is None:
return refnode
if any([
not env.config.hoverxref_is_configured,
self._is_ignored_ref(env, target),
not (env.config.hoverxref_auto_ref or typ in self.hoverxref_types)
]):
return refnode
docname, labelid, _ = get_ref_xref_data(self, node, target)
docpath = self._get_docpath(builder, docname)
self._inject_hoverxref_data(env, refnode, typ, docname, docpath, labelid)
logger.debug(
':ref: _hoverxref injected: fromdocname=%s %s',
fromdocname,
refnode._hoverxref,
)
return refnode
def _resolve_obj_xref(self, env, fromdocname, builder, typ, target, node, contnode):
refnode = super()._resolve_obj_xref(env, fromdocname, builder, typ, target, node, contnode)
if refnode is None:
return refnode
if any([
not env.config.hoverxref_is_configured,
self._is_ignored_ref(env, target),
typ not in env.config.hoverxref_roles,
]):
return refnode
docname, labelid = get_ref_obj_data(self, node, typ, target)
docpath = self._get_docpath(builder, docname)
self._inject_hoverxref_data(env, refnode, typ, docname, docpath, labelid)
logger.debug(
':%s: _hoverxref injected: fromdocname=%s %s',
typ,
fromdocname,
refnode._hoverxref,
)
return refnode
# TODO: combine this method with ``_resolve_obj_xref``
def _resolve_numref_xref(self, env, fromdocname, builder, typ, target, node, contnode):
refnode = super()._resolve_numref_xref(env, fromdocname, builder, typ, target, node, contnode)
if refnode is None:
return refnode
if any([
not env.config.hoverxref_is_configured,
self._is_ignored_ref(env, target),
typ not in env.config.hoverxref_roles,
]):
return refnode
docname, labelid = get_ref_numref_data(self, node, typ, target)
docpath = self._get_docpath(builder, docname)
self._inject_hoverxref_data(env, refnode, typ, docname, docpath, labelid)
logger.debug(
':%s: _hoverxref injected: fromdocname=%s %s',
typ,
fromdocname,
refnode._hoverxref,
)
return refnode