mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Add the "viewcode" extension.
This commit is contained in:
parent
177e0d19ee
commit
edb89b1940
2
CHANGES
2
CHANGES
@ -7,6 +7,8 @@ Release 1.0 (in development)
|
||||
|
||||
* Support for docutils 0.4 has been removed.
|
||||
|
||||
* Added the ``viewcode`` extension.
|
||||
|
||||
* Added ``html-collect-pages`` event.
|
||||
|
||||
* Added ``tab-width`` option to ``literalinclude`` directive.
|
||||
|
@ -7,7 +7,7 @@ import sys, os, re
|
||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||
# coming with Sphinx (named 'sphinx.addons.*') or your custom ones.
|
||||
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo',
|
||||
'sphinx.ext.autosummary']
|
||||
'sphinx.ext.autosummary', 'sphinx.ext.viewcode']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
19
doc/ext/viewcode.rst
Normal file
19
doc/ext/viewcode.rst
Normal file
@ -0,0 +1,19 @@
|
||||
:mod:`sphinx.ext.viewcode` -- Add links to highlighted source code
|
||||
==================================================================
|
||||
|
||||
.. module:: sphinx.ext.viewcode
|
||||
:synopsis: Add links to a highlighted version of the source code.
|
||||
.. moduleauthor:: Georg Brandl
|
||||
|
||||
.. versionadded:: 1.0
|
||||
|
||||
|
||||
This extension looks at your Python object descriptions (``.. class::``,
|
||||
``.. function::`` etc.) and tries to find the source files where the objects are
|
||||
contained. When found, a separate HTML page will be output for each module with
|
||||
a highlighted version of the source code, and a link will be added to all object
|
||||
descriptions that leads to the source code of the described object. A link back
|
||||
from the source to the description will also be inserted.
|
||||
|
||||
There are currently no configuration values for this extension; you just need to
|
||||
add ``'sphinx.ext.viewcode'`` to your :confval:`extensions` value for it to work.
|
@ -52,6 +52,7 @@ These extensions are built in and can be activated by respective entries in the
|
||||
ext/coverage
|
||||
ext/todo
|
||||
ext/extlinks
|
||||
ext/viewcode
|
||||
|
||||
|
||||
Third-party extensions
|
||||
|
162
sphinx/ext/viewcode.py
Normal file
162
sphinx/ext/viewcode.py
Normal file
@ -0,0 +1,162 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
sphinx.ext.viewcode
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Add links to module code in Python object descriptions.
|
||||
|
||||
:copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from docutils import nodes
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.util import make_refnode
|
||||
from sphinx.pycode import ModuleAnalyzer
|
||||
|
||||
|
||||
def doctree_read(app, doctree):
|
||||
env = app.builder.env
|
||||
if not hasattr(env, '_viewcode_modules'):
|
||||
env._viewcode_modules = {}
|
||||
|
||||
def has_tag(modname, fullname, docname):
|
||||
entry = env._viewcode_modules.get(modname, None)
|
||||
if entry is None:
|
||||
try:
|
||||
analyzer = ModuleAnalyzer.for_module(modname)
|
||||
except Exception:
|
||||
env._viewcode_modules[modname] = False
|
||||
return
|
||||
analyzer.find_tags()
|
||||
entry = analyzer.code, analyzer.tags, {}
|
||||
env._viewcode_modules[modname] = entry
|
||||
elif entry is False:
|
||||
return
|
||||
code, tags, used = entry
|
||||
if fullname in tags:
|
||||
used[fullname] = docname
|
||||
return True
|
||||
|
||||
for objnode in doctree.traverse(addnodes.desc):
|
||||
if objnode['domain'] != 'py':
|
||||
continue
|
||||
names = set()
|
||||
for signode in objnode.traverse(addnodes.desc_signature):
|
||||
modname = signode['module']
|
||||
if not modname:
|
||||
continue
|
||||
fullname = signode['fullname']
|
||||
if not has_tag(modname, fullname, env.docname):
|
||||
continue
|
||||
if fullname in names:
|
||||
# only one link per name, please
|
||||
continue
|
||||
names.add(fullname)
|
||||
pagename = '_modules/' + modname.replace('.', '/')
|
||||
onlynode = addnodes.only(expr='html')
|
||||
onlynode += addnodes.pending_xref(
|
||||
'', reftype='viewcode', refdomain='std', refexplicit=False,
|
||||
reftarget=pagename, refid=fullname,
|
||||
refdoc=env.docname)
|
||||
onlynode[0] += nodes.inline('', _('[source]'),
|
||||
classes=['viewcode-link'])
|
||||
signode += onlynode
|
||||
|
||||
|
||||
def missing_reference(app, env, node, contnode):
|
||||
# resolve our "viewcode" reference nodes -- they need special treatment
|
||||
if node['reftype'] == 'viewcode':
|
||||
return make_refnode(app.builder, node['refdoc'], node['reftarget'],
|
||||
node['refid'], contnode)
|
||||
|
||||
|
||||
def collect_pages(app):
|
||||
env = app.builder.env
|
||||
if not hasattr(env, '_viewcode_modules'):
|
||||
return
|
||||
highlighter = app.builder.highlighter
|
||||
urito = app.builder.get_relative_uri
|
||||
|
||||
modnames = set(env._viewcode_modules)
|
||||
|
||||
for modname, (code, tags, used) in env._viewcode_modules.iteritems():
|
||||
# construct a page name for the highlighted source
|
||||
pagename = '_modules/' + modname.replace('.', '/')
|
||||
# highlight the source using the builder's highlighter
|
||||
highlighted = highlighter.highlight_block(code, 'python', False)
|
||||
# split the code into lines
|
||||
lines = highlighted.splitlines()
|
||||
# split off wrap markup from the first line of the actual code
|
||||
before, after = lines[0].split('<pre>')
|
||||
lines[0:1] = [before + '<pre>', after]
|
||||
# nothing to do for the last line; it always starts with </pre> anyway
|
||||
# now that we have code lines (starting at index 1), insert anchors for
|
||||
# the collected tags (HACK: this only works if the tag boundaries are
|
||||
# properly nested!)
|
||||
for name, docname in used.iteritems():
|
||||
type, start, end = tags[name]
|
||||
backlink = urito(pagename, docname) + '#' + modname + '.' + name
|
||||
lines[start] = (
|
||||
'<div class="viewcode-block" id="%s"><a class="viewcode-back" '
|
||||
'href="%s">%s</a>' % (name, backlink, _('[docs]')) + lines[start])
|
||||
lines[end - 1] += '</div>'
|
||||
# try to find parents (for submodules)
|
||||
parents = []
|
||||
parent = modname
|
||||
while '.' in parent:
|
||||
parent = parent.rsplit('.', 1)[0]
|
||||
if parent in modnames:
|
||||
parents.append({
|
||||
'link': urito(pagename, '_modules/' +
|
||||
parent.replace('.', '/')),
|
||||
'title': parent})
|
||||
parents.append({'link': urito(pagename, '_modules/index'),
|
||||
'title': _('Module code')})
|
||||
parents.reverse()
|
||||
# putting it all together
|
||||
context = {
|
||||
'parents': parents,
|
||||
'title': modname,
|
||||
'body': _('<h2>Source code for %s</h2>') % modname + '\n'.join(lines)
|
||||
}
|
||||
app.builder.info(' '+pagename, nonl=1)
|
||||
yield (pagename, context, 'page.html')
|
||||
|
||||
if not modnames:
|
||||
return
|
||||
|
||||
app.builder.info(' _modules/index')
|
||||
html = ['\n']
|
||||
# the stack logic is needed for using nested lists for submodules
|
||||
stack = ['']
|
||||
for modname in sorted(modnames):
|
||||
if modname.startswith(stack[-1]):
|
||||
stack.append(modname + '.')
|
||||
html.append('<ul>')
|
||||
else:
|
||||
stack.pop()
|
||||
while not modname.startswith(stack[-1]):
|
||||
stack.pop()
|
||||
html.append('</ul>')
|
||||
stack.append(modname + '.')
|
||||
html.append('<li><a href="%s">%s</a></li>\n' % (
|
||||
urito('_modules/index', '_modules/' + modname.replace('.', '/')),
|
||||
modname))
|
||||
html.append('</ul>' * (len(stack) - 1))
|
||||
context = {
|
||||
'title': _('Overview: module code'),
|
||||
'body': _('<h2>All modules for which code is available</h2>') + \
|
||||
''.join(html),
|
||||
}
|
||||
|
||||
yield ('_modules/index', context, 'page.html')
|
||||
|
||||
|
||||
def setup(app):
|
||||
app.connect('doctree-read', doctree_read)
|
||||
app.connect('html-collect-pages', collect_pages)
|
||||
app.connect('missing-reference', missing_reference)
|
||||
#app.add_config_value('viewcode_include_modules', [], 'env')
|
||||
#app.add_config_value('viewcode_exclude_modules', [], 'env')
|
@ -368,6 +368,22 @@ dl.glossary dt {
|
||||
margin-left: 1.5em;
|
||||
}
|
||||
|
||||
.viewcode-link {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.viewcode-back {
|
||||
float: right;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
div.viewcode-block:target {
|
||||
background-color: #f4debf;
|
||||
border: 1px solid #D5BB73;
|
||||
margin: -1px -10px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
/* -- code displays --------------------------------------------------------- */
|
||||
|
||||
pre {
|
||||
|
Loading…
Reference in New Issue
Block a user