Source code for sphinx.ext.linkcode

"""Add external links to module code in Python object descriptions."""

from __future__ import annotations

from types import FunctionType, NoneType
from typing import TYPE_CHECKING

from docutils import nodes

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

if TYPE_CHECKING:
    from docutils.nodes import Node

    from sphinx.application import Sphinx
    from sphinx.util.typing import ExtensionMetadata


_DOMAIN_KEYS = {
    'py': ['module', 'fullname'],
    'c': ['names'],
    'cpp': ['names'],
    'js': ['object', 'fullname'],
}


[docs] def add_linkcode_domain(domain: str, keys: list[str], override: bool = False) -> None: """Register a new list of keys to use for a domain. .. versionadded:: 8.2 """ if override or domain not in _DOMAIN_KEYS: _DOMAIN_KEYS[domain] = list(keys)
class LinkcodeError(SphinxError): category = 'linkcode error' def doctree_read(app: Sphinx, doctree: Node) -> None: env = app.env resolve_target = getattr(env.config, 'linkcode_resolve', None) if not callable(env.config.linkcode_resolve): msg = 'Function `linkcode_resolve` is not given in conf.py' raise LinkcodeError(msg) assert resolve_target is not None # for mypy # By default, the linkcode extension will only inject references # for an ``html`` builder. If a builder wishes to support managing # references generated by linkcode as well, it can define the # ``supported_linkcode`` attribute. node_only_expr = getattr(app.builder, 'supported_linkcode', 'html') for objnode in list(doctree.findall(addnodes.desc)): domain = objnode.get('domain') uris: set[str] = 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) inline = nodes.inline('', _('[source]'), classes=['viewcode-link']) onlynode = addnodes.only(expr=node_only_expr) onlynode += nodes.reference('', '', inline, internal=False, refuri=uri) signode += onlynode def setup(app: Sphinx) -> ExtensionMetadata: app.connect('doctree-read', doctree_read) app.add_config_value( 'linkcode_resolve', None, '', types=frozenset({FunctionType, NoneType}) ) return { 'version': sphinx.__display_version__, 'parallel_read_safe': True, }