#504: Add an `index` role, to make inline index entries.

This commit is contained in:
Georg Brandl 2010-08-25 11:33:30 +00:00
parent 22b5751eb5
commit 40e692e6c3
8 changed files with 142 additions and 91 deletions

View File

@ -10,6 +10,8 @@ Release 1.1 (in development)
* #460: Allow limiting the depth of section numbers for HTML. * #460: Allow limiting the depth of section numbers for HTML.
* #504: Add an ``index`` role, to make inline index entries.
* #443: Allow referencing external graphviz files. * #443: Allow referencing external graphviz files.
* #221: Add Swedish locale. * #221: Add Swedish locale.

View File

@ -309,6 +309,7 @@ in a different style:
If you don't need the "variable part" indication, use the standard If you don't need the "variable part" indication, use the standard
````code```` instead. ````code```` instead.
There is also an :rst:role:`index` role to generate index entries.
The following roles generate external links: The following roles generate external links:

View File

@ -62,6 +62,85 @@ Meta-information markup
:confval:`show_authors` configuration value is True. :confval:`show_authors` configuration value is True.
Index-generating markup
-----------------------
Sphinx automatically creates index entries from all object descriptions (like
functions, classes or attributes) like discussed in :ref:`domains`.
However, there is also explicit markup available, to make the index more
comprehensive and enable index entries in documents where information is not
mainly contained in information units, such as the language reference.
.. rst:directive:: .. index:: <entries>
This directive contains one or more index entries. Each entry consists of a
type and a value, separated by a colon.
For example::
.. index::
single: execution; context
module: __main__
module: sys
triple: module; search; path
The execution context
---------------------
...
This directive contains five entries, which will be converted to entries in
the generated index which link to the exact location of the index statement
(or, in case of offline media, the corresponding page number).
Since index directives generate cross-reference targets at their location in
the source, it makes sense to put them *before* the thing they refer to --
e.g. a heading, as in the example above.
The possible entry types are:
single
Creates a single index entry. Can be made a subentry by separating the
subentry text with a semicolon (this notation is also used below to
describe what entries are created).
pair
``pair: loop; statement`` is a shortcut that creates two index entries,
namely ``loop; statement`` and ``statement; loop``.
triple
Likewise, ``triple: module; search; path`` is a shortcut that creates
three index entries, which are ``module; search path``, ``search; path,
module`` and ``path; module search``.
module, keyword, operator, object, exception, statement, builtin
These all create two index entries. For example, ``module: hashlib``
creates the entries ``module; hashlib`` and ``hashlib; module``. (These
are Python-specific and therefore deprecated.)
For index directives containing only "single" entries, there is a shorthand
notation::
.. index:: BNF, grammar, syntax, notation
This creates four index entries.
.. rst:role:: index
While the :rst:dir:`index` directive is a block-level markup and links to the
beginning of the next paragraph, there is also a corresponding role that sets
the link target directly where it is used.
The content of the role can be a simple phrase, which is then kept in the
text and used as an index entry. It can also be a combination of text and
index entry, styled like with explicit targets of cross-references. In that
case, the "target" part can be a full entry as described for the directive
above. For example::
This is a normal reST :index:`paragraph` that contains several
:index:`index entries <pair: index; entry>`.
.. versionadded:: 1.1
.. _tags: .. _tags:
Including content based on tags Including content based on tags

View File

@ -144,68 +144,6 @@ For local tables of contents, use the standard reST :dudir:`contents directive
<contents>`. <contents>`.
Index-generating markup
-----------------------
Sphinx automatically creates index entries from all object descriptions (like
functions, classes or attributes) like discussed in :ref:`domains`.
However, there is also an explicit directive available, to make the index more
comprehensive and enable index entries in documents where information is not
mainly contained in information units, such as the language reference.
.. rst:directive:: .. index:: <entries>
This directive contains one or more index entries. Each entry consists of a
type and a value, separated by a colon.
For example::
.. index::
single: execution; context
module: __main__
module: sys
triple: module; search; path
The execution context
---------------------
...
This directive contains five entries, which will be converted to entries in
the generated index which link to the exact location of the index statement
(or, in case of offline media, the corresponding page number).
Since index directives generate cross-reference targets at their location in
the source, it makes sense to put them *before* the thing they refer to --
e.g. a heading, as in the example above.
The possible entry types are:
single
Creates a single index entry. Can be made a subentry by separating the
subentry text with a semicolon (this notation is also used below to
describe what entries are created).
pair
``pair: loop; statement`` is a shortcut that creates two index entries,
namely ``loop; statement`` and ``statement; loop``.
triple
Likewise, ``triple: module; search; path`` is a shortcut that creates
three index entries, which are ``module; search path``, ``search; path,
module`` and ``path; module search``.
module, keyword, operator, object, exception, statement, builtin
These all create two index entries. For example, ``module: hashlib``
creates the entries ``module; hashlib`` and ``hashlib; module``. (These
are Python-specific and therefore deprecated.)
For index directives containing only "single" entries, there is a shorthand
notation::
.. index:: BNF, grammar, syntax, notation
This creates four index entries.
Glossary Glossary
-------- --------

View File

@ -13,9 +13,9 @@ from docutils import nodes
from docutils.parsers.rst import Directive, directives from docutils.parsers.rst import Directive, directives
from sphinx import addnodes from sphinx import addnodes
from sphinx.locale import pairindextypes, _ from sphinx.locale import _
from sphinx.util import url_re, docname_join from sphinx.util import url_re, docname_join
from sphinx.util.nodes import explicit_title_re from sphinx.util.nodes import explicit_title_re, process_index_entry
from sphinx.util.compat import make_admonition from sphinx.util.compat import make_admonition
from sphinx.util.matching import patfilter from sphinx.util.matching import patfilter
@ -157,10 +157,6 @@ class Index(Directive):
final_argument_whitespace = True final_argument_whitespace = True
option_spec = {} option_spec = {}
indextypes = [
'single', 'pair', 'double', 'triple',
]
def run(self): def run(self):
arguments = self.arguments[0].split('\n') arguments = self.arguments[0].split('\n')
env = self.state.document.settings.env env = self.state.document.settings.env
@ -170,28 +166,7 @@ class Index(Directive):
indexnode = addnodes.index() indexnode = addnodes.index()
indexnode['entries'] = ne = [] indexnode['entries'] = ne = []
for entry in arguments: for entry in arguments:
entry = entry.strip() ne.extend(process_index_entry(entry, targetid))
for type in pairindextypes:
if entry.startswith(type+':'):
value = entry[len(type)+1:].strip()
value = pairindextypes[type] + '; ' + value
ne.append(('pair', value, targetid, value))
break
else:
for type in self.indextypes:
if entry.startswith(type+':'):
value = entry[len(type)+1:].strip()
if type == 'double':
type = 'pair'
ne.append((type, value, targetid, value))
break
# shorthand notation for single entries
else:
for value in entry.split(','):
value = value.strip()
if not value:
continue
ne.append(('single', value, targetid, value))
return [indexnode, targetnode] return [indexnode, targetnode]

View File

@ -18,7 +18,7 @@ from docutils.parsers.rst import roles
from sphinx import addnodes from sphinx import addnodes
from sphinx.locale import _ from sphinx.locale import _
from sphinx.util import ws_re from sphinx.util import ws_re
from sphinx.util.nodes import split_explicit_title from sphinx.util.nodes import split_explicit_title, process_index_entry
generic_docroles = { generic_docroles = {
@ -268,6 +268,27 @@ def abbr_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
return [addnodes.abbreviation(abbr, abbr, explanation=expl)], [] return [addnodes.abbreviation(abbr, abbr, explanation=expl)], []
def index_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
# create new reference target
env = inliner.document.settings.env
targetid = 'index-%s' % env.new_serialno('index')
targetnode = nodes.target('', '', ids=[targetid])
# split text and target in role content
has_explicit_title, title, target = split_explicit_title(text)
title = utils.unescape(title)
target = utils.unescape(target)
# if an explicit target is given, we can process it as a full entry
if has_explicit_title:
entries = process_index_entry(target, targetid)
# otherwise we just create a "single" entry
else:
entries = [('single', target, targetid, target)]
indexnode = addnodes.index()
indexnode['entries'] = entries
textnode = nodes.Text(title, title)
return [indexnode, targetnode, textnode], []
specific_docroles = { specific_docroles = {
# links to download references # links to download references
'download': XRefRole(nodeclass=addnodes.download_reference), 'download': XRefRole(nodeclass=addnodes.download_reference),
@ -281,6 +302,7 @@ specific_docroles = {
'file': emph_literal_role, 'file': emph_literal_role,
'samp': emph_literal_role, 'samp': emph_literal_role,
'abbr': abbr_role, 'abbr': abbr_role,
'index': index_role,
} }
for rolename, func in specific_docroles.iteritems(): for rolename, func in specific_docroles.iteritems():

View File

@ -14,6 +14,7 @@ import re
from docutils import nodes from docutils import nodes
from sphinx import addnodes from sphinx import addnodes
from sphinx.locale import pairindextypes
from sphinx.util.pycompat import class_types from sphinx.util.pycompat import class_types
@ -72,6 +73,37 @@ def split_explicit_title(text):
return False, text, text return False, text, text
indextypes = [
'single', 'pair', 'double', 'triple',
]
def process_index_entry(entry, targetid):
indexentries = []
entry = entry.strip()
for type in pairindextypes:
if entry.startswith(type+':'):
value = entry[len(type)+1:].strip()
value = pairindextypes[type] + '; ' + value
indexentries.append(('pair', value, targetid, value))
break
else:
for type in indextypes:
if entry.startswith(type+':'):
value = entry[len(type)+1:].strip()
if type == 'double':
type = 'pair'
indexentries.append((type, value, targetid, value))
break
# shorthand notation for single entries
else:
for value in entry.split(','):
value = value.strip()
if not value:
continue
indexentries.append(('single', value, targetid, value))
return indexentries
def inline_all_toctrees(builder, docnameset, docname, tree, colorfunc): def inline_all_toctrees(builder, docnameset, docname, tree, colorfunc):
"""Inline all toctrees in the *tree*. """Inline all toctrees in the *tree*.

View File

@ -132,6 +132,8 @@ Adding \n to test unescaping.
Test :abbr:`abbr (abbreviation)` and another :abbr:`abbr (abbreviation)`. Test :abbr:`abbr (abbreviation)` and another :abbr:`abbr (abbreviation)`.
Testing the :index:`index` role, also available with
:index:`explicit <pair: title; explicit>` title.
.. _with: .. _with: