diff --git a/docs/conf.py b/docs/conf.py index 07ececd3..c6af1781 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -50,8 +50,11 @@ 'hoverxref.extension', 'versionwarning.extension', 'notfound.extension', + 'sphinxcontrib.bibtex', ] +bibtex_bibfiles = ['refs.bib'] + intersphinx_mapping = { 'readthedocs': ('https://docs.readthedocs.io/en/stable/', None), 'sphinx': ('https://www.sphinx-doc.org/en/master/', None), @@ -95,6 +98,7 @@ hoverxref_auto_ref = True hoverxref_roles = [ 'confval', + 'term', ] hoverxref_role_types = { @@ -107,6 +111,7 @@ } hoverxref_domains = [ 'py', + 'cite', ] hoverxref_sphinxtabs = True hoverxref_mathjax = True diff --git a/docs/configuration.rst b/docs/configuration.rst index c3092e03..647023f2 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -65,10 +65,6 @@ These settings are global and have effect on both, tooltips and modal dialogues. Description: List containing the Sphinx Domain's names where ``hoverxref`` has to be applied. - .. warning:: - - Only Python Domain (``py``) is currently supported. - Default: ``[]`` Type: list diff --git a/docs/refs.bib b/docs/refs.bib new file mode 100644 index 00000000..8be9d662 --- /dev/null +++ b/docs/refs.bib @@ -0,0 +1,6 @@ +@Book{1987:nelson, + author = {Edward Nelson}, + title = {Radically Elementary Probability Theory}, + publisher = {Princeton University Press}, + year = {1987} +} diff --git a/docs/requirements.txt b/docs/requirements.txt index e5845dfa..0cf0b7d7 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -6,3 +6,4 @@ sphinx-prompt==1.4.0 sphinx-version-warning==1.1.2 sphinx-notfound-page==0.7.1 sphinx-autobuild==2021.3.14 +sphinxcontrib-bibtex==2.4.1 diff --git a/docs/usage.rst b/docs/usage.rst index 1e33d782..0c9b3874 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -113,6 +113,44 @@ To enable ``hoverxref`` on a domain, you need to use the config :confval:`hoverx indicating which are the domains you desire. +Tooltip on glossary terms +------------------------- + +You can add tooltips to glossary terms: + +.. code-block:: rst + + See the :term:`sphinx:environment` definition in the glossary. + +That will render to: + +See the :term:`sphinx:environment` definition in the glossary. + +To enable ``hoverxref`` on glossary terms, you need to add ``'term'`` to :confval:`hoverxref_roles`. + + +Tooltip on sphinxcontrib-bibtex cites +------------------------------------- + +If you want to show a tooltip on `sphinxcontrib-bibtex `_ cites, +you just need to enable it in :confval:`hoverxref_domains` by adding ``'cite'`` to that list. +Example: + +.. code-block:: rst + + See :cite:t:`1987:nelson` for an introduction to non-standard analysis. + Non-standard analysis is fun :cite:p:`1987:nelson`. + +See :cite:t:`1987:nelson` for an introduction to non-standard analysis. +Non-standard analysis is fun :cite:p:`1987:nelson`. + +.. note:: + + Note that tooltips on sphinxcontrib-bibtex are supported on ``Sphinx>=2.1`` only. + +.. bibliography:: + + Tooltip with content that needs extra rendering steps ----------------------------------------------------- diff --git a/hoverxref/domains.py b/hoverxref/domains.py index 44a85dd5..20e12c7c 100644 --- a/hoverxref/domains.py +++ b/hoverxref/domains.py @@ -1,3 +1,5 @@ +import docutils + from sphinx.util import logging logger = logging.getLogger(__name__) @@ -138,3 +140,38 @@ def _resolve_numref_xref(self, env, fromdocname, builder, typ, target, node, con self._inject_hoverxref_data(env, refnode, typ) return refnode + + +class HoverXRefBibtexDomainMixin(HoverXRefBaseDomain): + """ + Mixin for ``BibtexDomain`` to save the values after the xref resolution. + + This class add the required ``hoverxref`` and ``modal``/``tooltip`` to tell + the frontend to show a modal/tooltip on this element. + + https://github.com/mcmtroffaes/sphinxcontrib-bibtex/blob/2.4.1/src/sphinxcontrib/bibtex/domain.py#L281 + """ + + def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode): + textnode = super().resolve_xref(env, fromdocname, builder, typ, target, node, contnode) + if textnode is None: + return textnode + + if any([ + self._is_ignored_ref(env, target), + not (env.config.hoverxref_auto_ref or typ in self.hoverxref_types or 'cite' in env.config.hoverxref_domains) + ]): + return textnode + + # The structure of the node generated by bibtex is between two + # ``#text`` nodes and we need to add the classes into the ``reference`` + # node to get the ``href=`` attribute from it + # + # (Pdb++) textnode.children + # [<#text: 'Nelson ['>, >, <#text: ']'>] + refnode_index = textnode.first_child_matching_class(docutils.nodes.reference) + if refnode_index: + refnode = textnode.children[refnode_index] + self._inject_hoverxref_data(env, refnode, typ) + + return textnode diff --git a/hoverxref/extension.py b/hoverxref/extension.py index 20a09bdd..dcca54f3 100644 --- a/hoverxref/extension.py +++ b/hoverxref/extension.py @@ -12,6 +12,7 @@ from . import version from .domains import ( HoverXRefBaseDomain, + HoverXRefBibtexDomainMixin, HoverXRefPythonDomainMixin, HoverXRefStandardDomainMixin, ) @@ -119,6 +120,17 @@ def setup_domains(app, config): ) app.add_domain(domain, override=True) + if 'cite' in app.config.hoverxref_domains: + domain = types.new_class( + 'HoverXRefBibtexDomain', + ( + HoverXRefBibtexDomainMixin, + app.registry.domains.get('cite'), + ), + {} + ) + app.add_domain(domain, override=True) + def setup_sphinx_tabs(app, config): """ diff --git a/tests/examples/bibtex-domain/conf.py b/tests/examples/bibtex-domain/conf.py new file mode 100644 index 00000000..04bf3162 --- /dev/null +++ b/tests/examples/bibtex-domain/conf.py @@ -0,0 +1,11 @@ +# conf.py to run tests + +master_doc = 'index' +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.autosectionlabel', + 'hoverxref.extension', + 'sphinxcontrib.bibtex', +] + +bibtex_bibfiles = ['refs.bib'] diff --git a/tests/examples/bibtex-domain/index.rst b/tests/examples/bibtex-domain/index.rst new file mode 100644 index 00000000..f70372a7 --- /dev/null +++ b/tests/examples/bibtex-domain/index.rst @@ -0,0 +1,10 @@ +sphinxcontrib-bibtex Domain +=========================== + +This is an example page with a sphinxcontrib-bibtex Domain role usage. + +See :cite:t:`1987:nelson` for an introduction to non-standard analysis. +Non-standard analysis is fun :cite:p:`1987:nelson`. + + +.. bibliography:: diff --git a/tests/examples/bibtex-domain/refs.bib b/tests/examples/bibtex-domain/refs.bib new file mode 100644 index 00000000..8be9d662 --- /dev/null +++ b/tests/examples/bibtex-domain/refs.bib @@ -0,0 +1,6 @@ +@Book{1987:nelson, + author = {Edward Nelson}, + title = {Radically Elementary Probability Theory}, + publisher = {Princeton University Press}, + year = {1987} +} diff --git a/tests/examples/default/glossary.rst b/tests/examples/default/glossary.rst new file mode 100644 index 00000000..4ea70a16 --- /dev/null +++ b/tests/examples/default/glossary.rst @@ -0,0 +1,25 @@ +Glossary +======== + +Example page showing the usage of ``.. glossary`` and ``term``. + +See definition :term:`builder` for more information. + +.. copied from https://www.sphinx-doc.org/en/master/glossary.html + +.. glossary:: + + builder + A class (inheriting from :class:`~sphinx.builders.Builder`) that takes + parsed documents and performs an action on them. Normally, builders + translate the documents to an output format, but it is also possible to + use builders that e.g. check for broken links in the documentation, or + build coverage information. + + See :doc:`/usage/builders/index` for an overview over Sphinx's built-in + builders. + + configuration directory + The directory containing :file:`conf.py`. By default, this is the same as + the :term:`source directory`, but can be set differently with the **-c** + command-line option. diff --git a/tests/test_htmltag.py b/tests/test_htmltag.py index b127b557..64a580c2 100644 --- a/tests/test_htmltag.py +++ b/tests/test_htmltag.py @@ -3,7 +3,7 @@ import sphinx import textwrap -from .utils import srcdir, prefixdocumentsrcdir, customobjectsrcdir, pythondomainsrcdir, intersphinxsrc +from .utils import srcdir, prefixdocumentsrcdir, customobjectsrcdir, pythondomainsrcdir, intersphinxsrc, bibtexdomainsrcdir @pytest.mark.sphinx( @@ -121,6 +121,50 @@ def test_python_domain(app, status, warning): assert chunk in content +@pytest.mark.skipif( + sphinx.version_info < (2, 1, 0), + reason='sphinxcontrib-bibtex requires Sphinx>=2.1 to work', +) +@pytest.mark.sphinx( + srcdir=bibtexdomainsrcdir, + confoverrides={ + 'hoverxref_domains': ['cite'], + }, +) +def test_bibtex_domain(app, status, warning): + app.build() + path = app.outdir / 'index.html' + assert path.exists() is True + content = open(path).read() + + chunks = [ + '

See Nelson [Nel87] for an introduction to non-standard analysis.\nNon-standard analysis is fun [Nel87].

', + ] + + for chunk in chunks: + assert chunk in content + + +@pytest.mark.sphinx( + srcdir=srcdir, + confoverrides={ + 'hoverxref_roles': ['term'], + }, +) +def test_glossary_term_domain(app, status, warning): + app.build() + path = app.outdir / 'glossary.html' + assert path.exists() is True + content = open(path).read() + + chunks = [ + '

See definition builder for more information.

', + ] + + for chunk in chunks: + assert chunk in content + + @pytest.mark.sphinx( srcdir=srcdir, confoverrides={ diff --git a/tests/utils.py b/tests/utils.py index 5f62b2ec..8072c7da 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -28,6 +28,13 @@ 'python-domain', ) +# srcdir with ``:cite:`` call +bibtexdomainsrcdir = os.path.join( + os.path.dirname(os.path.abspath(__file__)), + 'examples', + 'bibtex-domain', +) + # srcdir with intersphinx configured intersphinxsrc = os.path.join( os.path.dirname(os.path.abspath(__file__)), diff --git a/tox.ini b/tox.ini index c31030dc..998c31d3 100644 --- a/tox.ini +++ b/tox.ini @@ -7,6 +7,7 @@ envlist = deps = pytest pdbpp + sphinxcontrib-bibtex . sphinx18: sphinx~=1.8.0 sphinx20: sphinx~=2.0.0