mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merged in pv/sphinx-work/ext-linkcode (pull request #47)
This commit is contained in:
commit
201883d209
46
doc/ext/linkcode.rst
Normal file
46
doc/ext/linkcode.rst
Normal file
@ -0,0 +1,46 @@
|
||||
:mod:`sphinx.ext.linkcode` -- Add external links to source code
|
||||
===============================================================
|
||||
|
||||
.. module:: sphinx.ext.linkcode
|
||||
:synopsis: Add external links to source code.
|
||||
.. moduleauthor:: Pauli Virtanen
|
||||
|
||||
.. versionadded:: 1.1
|
||||
|
||||
This extension looks at your object descriptions (``.. class::``,
|
||||
``.. function::`` etc.) and adds external links to code hosted
|
||||
somewhere on the web. The intent is similar to the
|
||||
``sphinx.ext.viewcode`` extension, but assumes the source code can be
|
||||
found somewhere on the Internet.
|
||||
|
||||
In your configuration, you need to specify a :confval:`linkcode_resolve`
|
||||
function that returns an URL based on the object.
|
||||
|
||||
.. confval:: linkcode_resolve
|
||||
|
||||
This is a function ``linkcode_resolve(domain, info)``,
|
||||
which should return the URL to source code corresponding to
|
||||
the object in given domain with given information.
|
||||
|
||||
The function should return ``None`` if no link is to be added.
|
||||
|
||||
The argument ``domain`` specifies the language domain the object is
|
||||
in. ``info`` is a dictionary with the following keys guaranteed to
|
||||
be present (dependent on the domain):
|
||||
|
||||
- ``py``: ``module`` (name of the module), ``fullname`` (name of the object)
|
||||
- ``c``: ``names`` (list of names for the object)
|
||||
- ``cpp``: ``names`` (list of names for the object)
|
||||
- ``javascript``: ``object`` (name of the object), ``fullname`` (name of the item)
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def linkcode_resolve(domain, info):
|
||||
if domain != 'py':
|
||||
return None
|
||||
if not info['module']:
|
||||
return None
|
||||
filename = info['module'].replace('.', '/')
|
||||
return "http://somesite/sourcerepo/%s.py" % filename
|
@ -53,6 +53,7 @@ These extensions are built in and can be activated by respective entries in the
|
||||
ext/todo
|
||||
ext/extlinks
|
||||
ext/viewcode
|
||||
ext/linkcode
|
||||
ext/oldcmarkup
|
||||
|
||||
|
||||
|
72
sphinx/ext/linkcode.py
Normal file
72
sphinx/ext/linkcode.py
Normal file
@ -0,0 +1,72 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
sphinx.ext.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.
|
||||
"""
|
||||
|
||||
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')
|
@ -67,6 +67,28 @@ extlinks = {'issue': ('http://bugs.python.org/issue%s', 'issue '),
|
||||
# modify tags from conf.py
|
||||
tags.add('confpytag')
|
||||
|
||||
# -- linkcode
|
||||
|
||||
if 'test_linkcode' in tags:
|
||||
import glob
|
||||
|
||||
extensions.remove('sphinx.ext.viewcode')
|
||||
extensions.append('sphinx.ext.linkcode')
|
||||
|
||||
exclude_patterns.extend(glob.glob('*.txt') + glob.glob('*/*.txt'))
|
||||
exclude_patterns.remove('contents.txt')
|
||||
exclude_patterns.remove('objects.txt')
|
||||
|
||||
def linkcode_resolve(domain, info):
|
||||
if domain == 'py':
|
||||
fn = info['module'].replace('.', '/')
|
||||
return "http://foobar/source/%s.py" % fn
|
||||
elif domain == "js":
|
||||
return "http://foobar/js/" + info['fullname']
|
||||
elif domain in ("c", "cpp"):
|
||||
return "http://foobar/%s/%s" % (domain, "".join(info['names']))
|
||||
else:
|
||||
raise AssertionError()
|
||||
|
||||
# -- extension API
|
||||
|
||||
|
28
tests/test_linkcode.py
Normal file
28
tests/test_linkcode.py
Normal file
@ -0,0 +1,28 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
test_linkcode
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
Test the sphinx.ext.linkcode extension.
|
||||
|
||||
:copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import os
|
||||
from util import *
|
||||
|
||||
@with_app(srcdir='(temp)', buildername='html', tags=['test_linkcode'])
|
||||
def test_html(app):
|
||||
app.builder.build_all()
|
||||
|
||||
fp = open(os.path.join(app.outdir, 'objects.html'), 'rb')
|
||||
try:
|
||||
stuff = fp.read()
|
||||
finally:
|
||||
fp.close()
|
||||
|
||||
assert 'http://foobar/source/foolib.py' in stuff
|
||||
assert 'http://foobar/js/' in stuff
|
||||
assert 'http://foobar/c/' in stuff
|
||||
assert 'http://foobar/cpp/' in stuff
|
Loading…
Reference in New Issue
Block a user