How Sphinx Index Works#
Sphinx's Domain provides custom indices support by implementing sphinx.domains.Index
abstract class:
An Index is the description for a domain-specific index. To add an index to a domain, subclass Index, overriding the three name attributes:
name
is an identifier used for generating file names. It is also used for a hyperlink target for the index. Therefore, users can refer the index page usingref
role and a string which is combined domain name andname
attribute (ex.:ref:`py-modindex`
).
localname
is the section title for the index.
shortname
is a short name for the index, for use in the relation bar in HTML output. Can be empty to disable entries in the relation bar.and providing a
sphinx.domains.Index.generate()
method.Then, add the index class to your domain'sindices
list. Extensions can add indices to existing domains usingadd_index_to_domain()
.
Index Entry Generation#
Every Index instance should implementation the generarte function, and returns
groups of sphinx.domains.IndexEntry
:
@abstractmethod
def generate(self, docnames: Iterable[str] | None = None,
) -> tuple[list[tuple[str, list[IndexEntry]]], bool]:
The function is well documented:
Get entries for the index.
If
docnames
is given, restrict to entries referring to these docnames.The return value is a tuple of
(content, collapse)
:
collapse
A boolean that determines if sub-entries should start collapsed (for output formats that support collapsing sub-entries).
content
:A sequence of
(letter, entries)
tuples, whereletter
is the "heading" for the givenentries
, usually the starting letter, andentries
is a sequence of single entries. Each entry is a sequence[name, subtype, docname, anchor, extra, qualifier, descr]
.
Check out sphinx.domains.IndexEntry
for more details. The text alone may not be intuitive enough, so let's create an example, the following code implements an Index (code for adding Index to Domain is omitted):
from typing import Iterable
from sphinx.domains import Index, IndexEntry
class MyIndex(Index):
name = 'metavar'
localname = 'Meta Variable Reference Index'
shortname = 'references'
def generate(
self, docnames: Iterable[str] | None = None
) -> tuple[list[tuple[str, list[IndexEntry]]], bool]:
idx1 = IndexEntry('foo', 0, 'docname', 'anchor', 'extra', 'qualifier', 'desc')
idx2 = IndexEntry('bar', 0, 'docname', 'anchor', 'extra', 'qualifier', 'desc')
idx3 = IndexEntry('baz', 1, 'docname', 'anchor', 'extra', 'qualifier', 'desc')
idx4 = IndexEntry('qux', 2, 'docname', 'anchor', 'extra', 'qualifier', 'desc')
idx5 = IndexEntry('quux', 1, 'docname', 'anchor', 'extra', 'qualifier', 'desc')
return (
# entry list
[
("letter1", [idx1, idx2]),
("letter2", [idx3, idx4, idx5]),
],
# collapse
False,
)
Then index page is generated:
The hyperlink of name targets to document whose docname is "docname"
IndexEntry
are grouped byletter
, A.K.A category提示
In General Index (genindex), the category is usually a single first letter, this is why category is called "letter" here.
Entry with sub-entries (
subtype=1
) is collapsible (baz
,quux
)Sub-entry (
subtype=2
) follow after with its entry withsubtype=1
in thelist[IndexEntry]
(baz
has 1 sub-entry whilequxx
has not)
General Index (genindex)#
Sphinx also provides index
role and index
directive to create index entries from reStructuredText, which are hard to understand for me :'(and I personally don't use them.
Index generated by these markups are quite special: It does not logically belong to any Domain (such as py
, std
, and so on...), so it is called General Index (genindex), and can be referenced by :ref:`genindex`
.
These markups generate node sphinx.addnodes.index
, which carries a list of 5-tuples:
Node for index entries.
This node is created by the
index
directive and has one attribute,entries
. Its value is a list of 5-tuples of(entrytype, entryname, target, ignored, key)
.entrytype is one of "single", "pair", "double", "triple".
key is categorization characters (usually a single character) for general index page. For the details of this, please see also:
glossary
and issue sphinx-doc/sphinx#2302
Nodes are collected by sphinx.domains.index.IndexDomain.process_doc()
' (yes, genindex actually belongs to a domain called "index") ` and stored in domain's data storage sphinx.domains.Domain.data
, so builders can access it by sphinx.environment.BuildEnvironment
.domains['index']
.
For sphinx.builders.html.StandaloneHTMLBuilder
, the write_genindex
method loads 5-tuple list from buildenv, it is quite complex and I don't fully understand its
备注
We found that there is not any call to sphinx.domains.Index.generate()
. This shows that genindex is another independent implementation. I don’t know why this is done, maybe for historical reasons.
B.T.W the wirting of non-genindex is done in write_domain_indices
.
如果你有任何意见,请在此评论。 如果你留下了电子邮箱,我可能会通过 回复你。