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:
2
CHANGES
2
CHANGES
@@ -7,6 +7,8 @@ Release 1.0 (in development)
|
|||||||
|
|
||||||
* Support for docutils 0.4 has been removed.
|
* Support for docutils 0.4 has been removed.
|
||||||
|
|
||||||
|
* Added the ``viewcode`` extension.
|
||||||
|
|
||||||
* Added ``html-collect-pages`` event.
|
* Added ``html-collect-pages`` event.
|
||||||
|
|
||||||
* Added ``tab-width`` option to ``literalinclude`` directive.
|
* 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
|
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||||
# coming with Sphinx (named 'sphinx.addons.*') or your custom ones.
|
# coming with Sphinx (named 'sphinx.addons.*') or your custom ones.
|
||||||
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo',
|
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.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
templates_path = ['_templates']
|
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/coverage
|
||||||
ext/todo
|
ext/todo
|
||||||
ext/extlinks
|
ext/extlinks
|
||||||
|
ext/viewcode
|
||||||
|
|
||||||
|
|
||||||
Third-party extensions
|
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;
|
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 --------------------------------------------------------- */
|
/* -- code displays --------------------------------------------------------- */
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
|
|||||||
Reference in New Issue
Block a user