Skip to content

Commit c7cbe9b

Browse files
authored
Merge pull request readthedocs#49 from readthedocs/humitos/ignore-refs
Add `hoverxref_ignore_refs` to ignore user-defined references
2 parents ed542fd + c104a7a commit c7cbe9b

File tree

4 files changed

+120
-51
lines changed

4 files changed

+120
-51
lines changed

docs/configuration.rst

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ These settings are global and have effect on both, tooltips and modal dialogues.
1616

1717
.. confval:: hoverxref_default_types
1818

19-
Description: Style to use by default when for the embedded content when using ``:hoverxref:`` role.
20-
It also affect the style of and ``:ref:``
19+
Description: Style to use by default when hover each type of reference (role).
2120

2221
Default: ``{}``
2322

@@ -53,6 +52,14 @@ These settings are global and have effect on both, tooltips and modal dialogues.
5352

5453
Type: bool
5554

55+
.. confval:: hoverxref_ignore_refs
56+
57+
Description: Ignore to add tooltip on specific references. Useful when using :confval:`hoverxref_auto_ref`
58+
59+
Default: ``['genindex', 'modindex', 'search']``
60+
61+
Type: list
62+
5663
.. confval:: hoverxref_domains
5764

5865
Description: List containing the Sphinx Domain's names where ``hoverxref`` has to be applied.

hoverxref/domains.py

Lines changed: 60 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,6 @@ class HoverXRefBaseDomain:
1212
'hoverxrefmodal',
1313
)
1414

15-
def _is_hoverxref_configured(self, env):
16-
project = env.config.hoverxref_project
17-
version = env.config.hoverxref_version
18-
return project and version
19-
2015
def _inject_hoverxref_data(self, env, refnode, typ, docname, docpath, labelid):
2116
classes = ['hoverxref']
2217
type_class = None
@@ -56,13 +51,28 @@ def _get_docpath(self, builder, docname):
5651
docpath = docpath.replace(builder.outdir, '')
5752
return docpath
5853

54+
def _is_ignored_ref(self, env, target):
55+
if target in env.config.hoverxref_ignore_refs:
56+
logger.info(
57+
'Ignoring reference in hoverxref_ignore_refs. target=%s',
58+
target,
59+
)
60+
return True
61+
return False
62+
5963

6064
class HoverXRefPythonDomainMixin(HoverXRefBaseDomain):
6165

6266
def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode):
6367
refnode = super().resolve_xref(env, fromdocname, builder, typ, target, node, contnode)
6468
if refnode is None:
65-
return
69+
return refnode
70+
71+
if any([
72+
not env.config.hoverxref_is_configured,
73+
self._is_ignored_ref(env, target),
74+
]):
75+
return refnode
6676

6777
modname = node.get('py:module')
6878
clsname = node.get('py:class')
@@ -71,16 +81,14 @@ def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode):
7181
typ, searchmode)
7282
name, obj = matches[0]
7383

74-
if self._is_hoverxref_configured(env):
75-
docname, labelid = obj[0], name
76-
docpath = self._get_docpath(builder, docname)
77-
78-
self._inject_hoverxref_data(env, refnode, typ, docname, docpath, labelid)
79-
logger.info(
80-
':ref: _hoverxref injected: fromdocname=%s %s',
81-
fromdocname,
82-
refnode._hoverxref,
83-
)
84+
docname, labelid = obj[0], name
85+
docpath = self._get_docpath(builder, docname)
86+
self._inject_hoverxref_data(env, refnode, typ, docname, docpath, labelid)
87+
logger.info(
88+
':ref: _hoverxref injected: fromdocname=%s %s',
89+
fromdocname,
90+
refnode._hoverxref,
91+
)
8492
return refnode
8593

8694

@@ -107,40 +115,45 @@ def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode):
107115
def _resolve_ref_xref(self, env, fromdocname, builder, typ, target, node, contnode):
108116
refnode = super()._resolve_ref_xref(env, fromdocname, builder, typ, target, node, contnode)
109117
if refnode is None:
110-
return
111-
112-
if not self._is_hoverxref_configured(env) and typ in self.hoverxref_types:
113-
# Using ``:hoverxref:`` role without having hoverxref configured
114-
# properly. Log a warning.
115-
logger.warning('hoverxref role is not fully configured.')
116-
117-
if self._is_hoverxref_configured(env) and (env.config.hoverxref_auto_ref or typ in self.hoverxref_types):
118-
docname, labelid, _ = get_ref_xref_data(self, node, target)
119-
docpath = self._get_docpath(builder, docname)
120-
121-
self._inject_hoverxref_data(env, refnode, typ, docname, docpath, labelid)
122-
logger.info(
123-
':ref: _hoverxref injected: fromdocname=%s %s',
124-
fromdocname,
125-
refnode._hoverxref,
126-
)
118+
return refnode
119+
120+
if any([
121+
not env.config.hoverxref_is_configured,
122+
self._is_ignored_ref(env, target),
123+
not (env.config.hoverxref_auto_ref or typ in self.hoverxref_types)
124+
]):
125+
return refnode
126+
127+
128+
docname, labelid, _ = get_ref_xref_data(self, node, target)
129+
docpath = self._get_docpath(builder, docname)
130+
self._inject_hoverxref_data(env, refnode, typ, docname, docpath, labelid)
131+
logger.info(
132+
':ref: _hoverxref injected: fromdocname=%s %s',
133+
fromdocname,
134+
refnode._hoverxref,
135+
)
127136
return refnode
128137

129138
def _resolve_obj_xref(self, env, fromdocname, builder, typ, target, node, contnode):
130139
refnode = super()._resolve_obj_xref(env, fromdocname, builder, typ, target, node, contnode)
131140
if refnode is None:
132-
return
133-
134-
if typ in env.config.hoverxref_roles:
135-
docname, labelid = get_ref_obj_data(self, node, typ, target)
136-
if self._is_hoverxref_configured(env):
137-
docpath = self._get_docpath(builder, docname)
138-
139-
self._inject_hoverxref_data(env, refnode, typ, docname, docpath, labelid)
140-
logger.info(
141-
':%s: _hoverxref injected: fromdocname=%s %s',
142-
typ,
143-
fromdocname,
144-
refnode._hoverxref,
145-
)
141+
return refnode
142+
143+
if any([
144+
not env.config.hoverxref_is_configured,
145+
self._is_ignored_ref(env, target),
146+
typ not in env.config.hoverxref_roles,
147+
]):
148+
return refnode
149+
150+
docname, labelid = get_ref_obj_data(self, node, typ, target)
151+
docpath = self._get_docpath(builder, docname)
152+
self._inject_hoverxref_data(env, refnode, typ, docname, docpath, labelid)
153+
logger.info(
154+
':%s: _hoverxref injected: fromdocname=%s %s',
155+
typ,
156+
fromdocname,
157+
refnode._hoverxref,
158+
)
146159
return refnode

hoverxref/extension.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,26 @@ def setup_translators(app):
174174
app.set_translator(name, translator, override=True)
175175

176176

177+
def is_hoverxref_configured(app, config):
178+
"""
179+
Save a config if hoverxref is properly configured.
180+
181+
It checks for ``hoverxref_project`` and ``hoverxref_version`` being defined
182+
and set ``hoverxref_is_configured=True`` if configured.
183+
"""
184+
config.hoverxref_is_configured = True
185+
186+
project = config.hoverxref_project
187+
version = config.hoverxref_version
188+
if not project or not version:
189+
config.hoverxref_is_configured = False
190+
# ``hoverxref`` extension is not fully configured
191+
logger.warning(
192+
'hoverxref extension is not fully configured. '
193+
'Set hoverxref_project and hoverxref_version in your conf.py file.',
194+
)
195+
196+
177197
def setup_theme(app, exception):
178198
"""
179199
Auto-configure default settings for known themes.
@@ -230,10 +250,9 @@ def setup(app):
230250
app.add_config_value('hoverxref_sphinxtabs', False, 'env')
231251
app.add_config_value('hoverxref_roles', [], 'env')
232252
app.add_config_value('hoverxref_domains', [], 'env')
233-
253+
app.add_config_value('hoverxref_ignore_refs', ['genindex', 'modindex', 'search'], 'env')
234254
app.add_config_value('hoverxref_default_types', {}, 'env')
235255
app.add_config_value('hoverxref_default_type', 'tooltip', 'env')
236-
237256
app.add_config_value('hoverxref_api_host', 'https://readthedocs.org', 'env')
238257

239258
# Tooltipster settings
@@ -267,6 +286,7 @@ def setup(app):
267286

268287
app.connect('config-inited', setup_domains)
269288
app.connect('config-inited', setup_sphinx_tabs)
289+
app.connect('config-inited', is_hoverxref_configured)
270290
app.connect('config-inited', setup_theme)
271291
app.connect('build-finished', copy_asset_files)
272292

tests/test_htmltag.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,3 +192,32 @@ def test_default_types(app, status, warning):
192192

193193
for chunk in chunks:
194194
assert chunk in content
195+
196+
197+
@pytest.mark.sphinx(
198+
srcdir=srcdir,
199+
confoverrides={
200+
'hoverxref_ignore_refs': [
201+
'section i',
202+
],
203+
},
204+
)
205+
def test_ignore_refs(app, status, warning):
206+
app.build()
207+
path = app.outdir / 'index.html'
208+
assert path.exists() is True
209+
content = open(path).read()
210+
211+
chunks = [
212+
'<a class="reference internal" href="chapter-i.html#chapter-i"><span class="std std-ref">This a :ref: to Chapter I</span></a>',
213+
'<a class="reference internal" href="chapter-i.html#section-i"><span class="std std-ref">This a :hoverxref: to Chapter I, Section I</span></a>',
214+
]
215+
216+
for chunk in chunks:
217+
assert chunk in content
218+
219+
ignored_chunks = [
220+
'<a class="hoverxref reference internal" data-doc="chapter-i" data-project="myproject" data-section="section-i" data-version="myversion" href="chapter-i.html#section-i"><span class="std std-ref">This a :hoverxref: to Chapter I, Section I</span></a>',
221+
]
222+
for chunk in ignored_chunks:
223+
assert chunk not in content

0 commit comments

Comments
 (0)