summaryrefslogtreecommitdiff
path: root/doc/sphinxext/linkcode.py
blob: 1b1ef4a773326a5ed1ee7cdd538141d7d744613e (plain)
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
# -*- coding: utf-8 -*-
"""
    linkcode
    ~~~~~~~~

    Add external links to module code in Python object descriptions.

    :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
    :license: BSD, see LICENSE for details.
"""

import warnings
warnings.warn("This extension has been submitted to Sphinx upstream. "
              "Use the version from there if it is accepted "
              "https://bitbucket.org/birkenfeld/sphinx/pull-request/47/sphinxextlinkcode",
              FutureWarning, stacklevel=1)


from docutils import nodes

from sphinx import addnodes
from sphinx.locale import _
from sphinx.errors import SphinxError

class LinkcodeError(SphinxError):
    category = "linkcode error"

def doctree_read(app, doctree):
    env = app.builder.env

    resolve_target = getattr(env.config, 'linkcode_resolve', None)
    if not callable(env.config.linkcode_resolve):
        raise LinkcodeError(
            "Function `linkcode_resolve` is not given in conf.py")

    domain_keys = dict(
        py=['module', 'fullname'],
        c=['names'],
        cpp=['names'],
        js=['object', 'fullname'],
    )

    for objnode in doctree.traverse(addnodes.desc):
        domain = objnode.get('domain')
        uris = set()
        for signode in objnode:
            if not isinstance(signode, addnodes.desc_signature):
                continue

            # Convert signode to a specified format
            info = {}
            for key in domain_keys.get(domain, []):
                value = signode.get(key)
                if not value:
                    value = ''
                info[key] = value
            if not info:
                continue

            # Call user code to resolve the link
            uri = resolve_target(domain, info)
            if not uri:
                # no source
                continue

            if uri in uris or not uri:
                # only one link per name, please
                continue
            uris.add(uri)

            onlynode = addnodes.only(expr='html')
            onlynode += nodes.reference('', '', internal=False, refuri=uri)
            onlynode[0] += nodes.inline('', _('[source]'),
                                        classes=['viewcode-link'])
            signode += onlynode

def setup(app):
    app.connect('doctree-read', doctree_read)
    app.add_config_value('linkcode_resolve', None, 'env')