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
|
"""Sphinx extension to define external links that support anchors.
Sphinx comes bundled with a :py:mod:`sphinx.ext.extlinks` extension, which
allows a :file:`conf.py` to define roles for external links. These don't
support anchors, however, making it impossible to link to properly link in some
cases.
This is a wrapper around that module that looks for anchors and appends them to
the resulting URL.
Setup
=====
This extension works identically to :py:mod:`sphinx.ext.extlinks` and contains
the same configuration. To use it, configure external links the way you would
for that extension, but add ours instead to :file:`conf.py`::
extensions = [
...
'beanbag_docutils.sphinx.ext.extlinks',
...
]
"""
from sphinx import version_info as sphinx_version_info
from sphinx.ext.extlinks import make_link_role
class ExternalLink(object):
"""Wraps a URL and formats references to allow for using anchors.
This will work like a string, from the point of view of
:py:mod:`sphinx.ext.extlinks`. It takes the URL for the external link and
intercepts any string formatting, pulling out the anchor and appending it
to the final result.
"""
def __init__(self, base_url):
"""Initialize the class.
Args:
base_url (unicode):
The URL to wrap. This must contain a ``%s``.
"""
self.base_url = base_url
def __mod__(self, ref):
"""Return a URL based on the stored string format and the reference.
Args:
ref (unicode):
The reference to place into the URL. This may contain an
anchor starting with ``#``.
Returns:
unicode:
The formatted URL.
"""
parts = ref.split('#', 1)
url = self.base_url % parts[0]
if len(parts) == 2:
url = '%s#%s' % (url, parts[1])
return url
def __add__(self, s):
"""Return the concatenated string for the base URL and another string.
Args:
s (unicode):
A string to concatenate onto this base URL.
Returns:
unicode:
The concatenated string.
"""
return self.base_url + s
def setup_link_roles(app):
"""Register roles for each external link that's been defined.
Args:
app (sphinx.application.Sphinx):
The Sphinx application.
"""
if sphinx_version_info[:2] >= (4, 0):
for name, (base_url, prefix) in app.config.extlinks.items():
app.add_role(name, make_link_role(name, ExternalLink(base_url),
prefix))
else:
for name, (base_url, prefix) in app.config.extlinks.items():
app.add_role(name, make_link_role(ExternalLink(base_url), prefix))
def setup(app):
"""Set up the Sphinx extension.
This registers the configuration for external links and adds the roles
for each when the builder initializes.
Args:
app (sphinx.application.Sphinx):
The Sphinx application.
Returns:
dict:
Information about the extension. This is in the same format as what
:py:func:`sphinx.ext.extlinks.setup` returns.
"""
app.add_config_value('extlinks', {}, 'env')
app.connect('builder-inited', setup_link_roles)
return {
'version': '1.0',
'parallel_read_safe': True,
}
|