File: extlinks.py

package info (click to toggle)
beanbag-docutils 2.4-3
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 472 kB
  • sloc: python: 2,671; makefile: 202; sh: 8
file content (119 lines) | stat: -rw-r--r-- 3,453 bytes parent folder | download | duplicates (3)
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,
    }