mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Add IndexEntries adapter
This commit is contained in:
parent
0b0637deb2
commit
e2c7b1db42
@ -22,6 +22,7 @@ from sphinx import addnodes
|
||||
from sphinx.util import logging
|
||||
from sphinx.util.osutil import make_filename
|
||||
from sphinx.builders.html import StandaloneHTMLBuilder
|
||||
from sphinx.environment.adapters.indexentries import IndexEntries
|
||||
|
||||
try:
|
||||
import xml.etree.ElementTree as etree
|
||||
@ -104,7 +105,7 @@ class DevhelpBuilder(StandaloneHTMLBuilder):
|
||||
|
||||
# Index
|
||||
functions = etree.SubElement(root, 'functions')
|
||||
index = self.env.create_index(self)
|
||||
index = IndexEntries(self.env).create_index(self)
|
||||
|
||||
def write_index(title, refs, subitems):
|
||||
# type: (unicode, List[Any], Any) -> None
|
||||
|
@ -46,6 +46,7 @@ from sphinx.util.console import bold, darkgreen # type: ignore
|
||||
from sphinx.writers.html import HTMLWriter, HTMLTranslator, \
|
||||
SmartyPantsHTMLTranslator
|
||||
from sphinx.environment.adapters.toctree import TocTree
|
||||
from sphinx.environment.adapters.indexentries import IndexEntries
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
@ -542,7 +543,7 @@ class StandaloneHTMLBuilder(Builder):
|
||||
# type: () -> None
|
||||
# the total count of lines for each index letter, used to distribute
|
||||
# the entries into two columns
|
||||
genindex = self.env.create_index(self)
|
||||
genindex = IndexEntries(self.env).create_index(self)
|
||||
indexcounts = []
|
||||
for _k, entries in genindex:
|
||||
indexcounts.append(sum(1 + len(subitems)
|
||||
|
@ -19,6 +19,7 @@ from docutils import nodes
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.builders.html import StandaloneHTMLBuilder
|
||||
from sphinx.environment.adapters.indexentries import IndexEntries
|
||||
from sphinx.util import logging
|
||||
from sphinx.util.osutil import make_filename
|
||||
from sphinx.util.pycompat import htmlescape
|
||||
@ -281,7 +282,7 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder):
|
||||
f.write(contents_footer)
|
||||
|
||||
logger.info('writing index file...')
|
||||
index = self.env.create_index(self)
|
||||
index = IndexEntries(self.env).create_index(self)
|
||||
with self.open_file(outdir, outname + '.hhk') as f:
|
||||
f.write('<UL>\n')
|
||||
|
||||
|
@ -21,6 +21,7 @@ from docutils import nodes
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.builders.html import StandaloneHTMLBuilder
|
||||
from sphinx.environment.adapters.indexentries import IndexEntries
|
||||
from sphinx.util import force_decode, logging
|
||||
from sphinx.util.osutil import make_filename
|
||||
from sphinx.util.pycompat import htmlescape
|
||||
@ -170,7 +171,7 @@ class QtHelpBuilder(StandaloneHTMLBuilder):
|
||||
|
||||
# keywords
|
||||
keywords = []
|
||||
index = self.env.create_index(self, group_entries=False)
|
||||
index = IndexEntries(self.env).create_index(self, group_entries=False)
|
||||
for (key, group) in index:
|
||||
for title, (refs, subitems, key_) in group:
|
||||
keywords.extend(self.build_keywords(title, refs, subitems))
|
||||
|
@ -47,8 +47,9 @@ from sphinx.util.websupport import is_commentable
|
||||
from sphinx.errors import SphinxError, ExtensionError
|
||||
from sphinx.versioning import add_uids, merge_doctrees
|
||||
from sphinx.deprecation import RemovedInSphinx20Warning
|
||||
from sphinx.environment.adapters.indexentries import IndexEntries
|
||||
from sphinx.environment.adapters.toctree import TocTree
|
||||
from sphinx.environment.managers.indexentries import IndexEntries
|
||||
from sphinx.environment.managers.indexentries import IndexEntries as IndexEntriesManager
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
@ -247,7 +248,7 @@ class BuildEnvironment(object):
|
||||
# type: () -> None
|
||||
managers = {}
|
||||
manager_class = None # type: Type[EnvironmentManager]
|
||||
for manager_class in [IndexEntries]: # type: ignore
|
||||
for manager_class in [IndexEntriesManager]: # type: ignore
|
||||
managers[manager_class.name] = manager_class(self)
|
||||
self.attach_managers(managers)
|
||||
|
||||
@ -1070,8 +1071,13 @@ class BuildEnvironment(object):
|
||||
|
||||
def create_index(self, builder, group_entries=True,
|
||||
_fixre=re.compile(r'(.*) ([(][^()]*[)])')):
|
||||
# type: (Builder, bool, Pattern) -> Any
|
||||
return self.indices.create_index(builder, group_entries=group_entries, _fixre=_fixre) # type: ignore # NOQA
|
||||
# type: (Builder, bool, Pattern) -> List[Tuple[unicode, List[Tuple[unicode, List[unicode]]]]] # NOQA
|
||||
warnings.warn('env.create_index() is deprecated. '
|
||||
'Use sphinx.environment.adapters.indexentreis.IndexEntries instead.',
|
||||
RemovedInSphinx20Warning)
|
||||
return IndexEntries(self).create_index(builder,
|
||||
group_entries=group_entries,
|
||||
_fixre=_fixre)
|
||||
|
||||
def collect_relations(self):
|
||||
# type: () -> Dict[unicode, List[unicode]]
|
||||
|
157
sphinx/environment/adapters/indexentries.py
Normal file
157
sphinx/environment/adapters/indexentries.py
Normal file
@ -0,0 +1,157 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
sphinx.environment.adapters.indexentries
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Index entries adapters for sphinx.environment.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
import re
|
||||
import bisect
|
||||
import unicodedata
|
||||
import string
|
||||
from itertools import groupby
|
||||
|
||||
from six import text_type
|
||||
|
||||
from sphinx.locale import _
|
||||
from sphinx.util import iteritems, split_into, logging
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any, Pattern, Tuple # NOQA
|
||||
from sphinx.builders import Builder # NOQA
|
||||
from sphinx.environment import BuildEnvironment # NOQA
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class IndexEntries(object):
|
||||
def __init__(self, env):
|
||||
# type: (BuildEnvironment) -> None
|
||||
self.env = env
|
||||
|
||||
def create_index(self, builder, group_entries=True,
|
||||
_fixre=re.compile(r'(.*) ([(][^()]*[)])')):
|
||||
# type: (Builder, bool, Pattern) -> List[Tuple[unicode, List[Tuple[unicode, Any]]]] # NOQA
|
||||
"""Create the real index from the collected index entries."""
|
||||
from sphinx.environment import NoUri
|
||||
|
||||
new = {} # type: Dict[unicode, List]
|
||||
|
||||
def add_entry(word, subword, main, link=True, dic=new, key=None):
|
||||
# Force the word to be unicode if it's a ASCII bytestring.
|
||||
# This will solve problems with unicode normalization later.
|
||||
# For instance the RFC role will add bytestrings at the moment
|
||||
word = text_type(word)
|
||||
entry = dic.get(word)
|
||||
if not entry:
|
||||
dic[word] = entry = [[], {}, key]
|
||||
if subword:
|
||||
add_entry(subword, '', main, link=link, dic=entry[1], key=key)
|
||||
elif link:
|
||||
try:
|
||||
uri = builder.get_relative_uri('genindex', fn) + '#' + tid
|
||||
except NoUri:
|
||||
pass
|
||||
else:
|
||||
# maintain links in sorted/deterministic order
|
||||
bisect.insort(entry[0], (main, uri))
|
||||
|
||||
for fn, entries in iteritems(self.env.indexentries):
|
||||
# new entry types must be listed in directives/other.py!
|
||||
for type, value, tid, main, index_key in entries:
|
||||
try:
|
||||
if type == 'single':
|
||||
try:
|
||||
entry, subentry = split_into(2, 'single', value)
|
||||
except ValueError:
|
||||
entry, = split_into(1, 'single', value)
|
||||
subentry = ''
|
||||
add_entry(entry, subentry, main, key=index_key)
|
||||
elif type == 'pair':
|
||||
first, second = split_into(2, 'pair', value)
|
||||
add_entry(first, second, main, key=index_key)
|
||||
add_entry(second, first, main, key=index_key)
|
||||
elif type == 'triple':
|
||||
first, second, third = split_into(3, 'triple', value)
|
||||
add_entry(first, second + ' ' + third, main, key=index_key)
|
||||
add_entry(second, third + ', ' + first, main, key=index_key)
|
||||
add_entry(third, first + ' ' + second, main, key=index_key)
|
||||
elif type == 'see':
|
||||
first, second = split_into(2, 'see', value)
|
||||
add_entry(first, _('see %s') % second, None,
|
||||
link=False, key=index_key)
|
||||
elif type == 'seealso':
|
||||
first, second = split_into(2, 'see', value)
|
||||
add_entry(first, _('see also %s') % second, None,
|
||||
link=False, key=index_key)
|
||||
else:
|
||||
logger.warning('unknown index entry type %r', type, location=fn)
|
||||
except ValueError as err:
|
||||
logger.warning(str(err), location=fn)
|
||||
|
||||
# sort the index entries; put all symbols at the front, even those
|
||||
# following the letters in ASCII, this is where the chr(127) comes from
|
||||
def keyfunc(entry, lcletters=string.ascii_lowercase + '_'):
|
||||
key, (void, void, category_key) = entry
|
||||
if category_key:
|
||||
# using specified category key to sort
|
||||
key = category_key
|
||||
lckey = unicodedata.normalize('NFD', key.lower())
|
||||
if lckey[0:1] in lcletters:
|
||||
lckey = chr(127) + lckey
|
||||
# ensure a determinstic order *within* letters by also sorting on
|
||||
# the entry itself
|
||||
return (lckey, entry[0])
|
||||
newlist = sorted(new.items(), key=keyfunc)
|
||||
|
||||
if group_entries:
|
||||
# fixup entries: transform
|
||||
# func() (in module foo)
|
||||
# func() (in module bar)
|
||||
# into
|
||||
# func()
|
||||
# (in module foo)
|
||||
# (in module bar)
|
||||
oldkey = '' # type: unicode
|
||||
oldsubitems = None # type: Dict[unicode, List]
|
||||
i = 0
|
||||
while i < len(newlist):
|
||||
key, (targets, subitems, _key) = newlist[i]
|
||||
# cannot move if it has subitems; structure gets too complex
|
||||
if not subitems:
|
||||
m = _fixre.match(key)
|
||||
if m:
|
||||
if oldkey == m.group(1):
|
||||
# prefixes match: add entry as subitem of the
|
||||
# previous entry
|
||||
oldsubitems.setdefault(m.group(2), [[], {}, _key])[0].\
|
||||
extend(targets)
|
||||
del newlist[i]
|
||||
continue
|
||||
oldkey = m.group(1)
|
||||
else:
|
||||
oldkey = key
|
||||
oldsubitems = subitems
|
||||
i += 1
|
||||
|
||||
# group the entries by letter
|
||||
def keyfunc2(item, letters=string.ascii_uppercase + '_'):
|
||||
# hack: mutating the subitems dicts to a list in the keyfunc
|
||||
k, v = item
|
||||
v[1] = sorted((si, se) for (si, (se, void, void)) in iteritems(v[1]))
|
||||
if v[2] is None:
|
||||
# now calculate the key
|
||||
letter = unicodedata.normalize('NFD', k[0])[0].upper()
|
||||
if letter in letters:
|
||||
return letter
|
||||
else:
|
||||
# get all other symbols under one heading
|
||||
return _('Symbols')
|
||||
else:
|
||||
return v[2]
|
||||
return [(key_, list(group))
|
||||
for (key_, group) in groupby(newlist, keyfunc2)]
|
@ -8,23 +8,14 @@
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
import re
|
||||
import bisect
|
||||
import unicodedata
|
||||
import string
|
||||
from itertools import groupby
|
||||
|
||||
from six import text_type
|
||||
from sphinx import addnodes
|
||||
from sphinx.util import iteritems, split_index_msg, split_into, logging
|
||||
from sphinx.locale import _
|
||||
from sphinx.util import split_index_msg, logging
|
||||
from sphinx.environment.managers import EnvironmentManager
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Pattern, Tuple # NOQA
|
||||
from docutils import nodes # NOQA
|
||||
from sphinx.builders import Builder # NOQA
|
||||
from sphinx.environment import BuildEnvironment # NOQA
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -68,126 +59,3 @@ class IndexEntries(EnvironmentManager):
|
||||
def get_updated_docs(self):
|
||||
# type: () -> List[unicode]
|
||||
return []
|
||||
|
||||
def create_index(self, builder, group_entries=True,
|
||||
_fixre=re.compile(r'(.*) ([(][^()]*[)])')):
|
||||
# type: (Builder, bool, Pattern) -> List[Tuple[unicode, List[Tuple[unicode, List[unicode]]]]] # NOQA
|
||||
"""Create the real index from the collected index entries."""
|
||||
from sphinx.environment import NoUri
|
||||
|
||||
new = {} # type: Dict[unicode, List]
|
||||
|
||||
def add_entry(word, subword, main, link=True, dic=new, key=None):
|
||||
# Force the word to be unicode if it's a ASCII bytestring.
|
||||
# This will solve problems with unicode normalization later.
|
||||
# For instance the RFC role will add bytestrings at the moment
|
||||
word = text_type(word)
|
||||
entry = dic.get(word)
|
||||
if not entry:
|
||||
dic[word] = entry = [[], {}, key]
|
||||
if subword:
|
||||
add_entry(subword, '', main, link=link, dic=entry[1], key=key)
|
||||
elif link:
|
||||
try:
|
||||
uri = builder.get_relative_uri('genindex', fn) + '#' + tid
|
||||
except NoUri:
|
||||
pass
|
||||
else:
|
||||
# maintain links in sorted/deterministic order
|
||||
bisect.insort(entry[0], (main, uri))
|
||||
|
||||
for fn, entries in iteritems(self.data):
|
||||
# new entry types must be listed in directives/other.py!
|
||||
for type, value, tid, main, index_key in entries:
|
||||
try:
|
||||
if type == 'single':
|
||||
try:
|
||||
entry, subentry = split_into(2, 'single', value)
|
||||
except ValueError:
|
||||
entry, = split_into(1, 'single', value)
|
||||
subentry = ''
|
||||
add_entry(entry, subentry, main, key=index_key)
|
||||
elif type == 'pair':
|
||||
first, second = split_into(2, 'pair', value)
|
||||
add_entry(first, second, main, key=index_key)
|
||||
add_entry(second, first, main, key=index_key)
|
||||
elif type == 'triple':
|
||||
first, second, third = split_into(3, 'triple', value)
|
||||
add_entry(first, second + ' ' + third, main, key=index_key)
|
||||
add_entry(second, third + ', ' + first, main, key=index_key)
|
||||
add_entry(third, first + ' ' + second, main, key=index_key)
|
||||
elif type == 'see':
|
||||
first, second = split_into(2, 'see', value)
|
||||
add_entry(first, _('see %s') % second, None,
|
||||
link=False, key=index_key)
|
||||
elif type == 'seealso':
|
||||
first, second = split_into(2, 'see', value)
|
||||
add_entry(first, _('see also %s') % second, None,
|
||||
link=False, key=index_key)
|
||||
else:
|
||||
logger.warning('unknown index entry type %r', type, location=fn)
|
||||
except ValueError as err:
|
||||
logger.warning(str(err), location=fn)
|
||||
|
||||
# sort the index entries; put all symbols at the front, even those
|
||||
# following the letters in ASCII, this is where the chr(127) comes from
|
||||
def keyfunc(entry, lcletters=string.ascii_lowercase + '_'):
|
||||
key, (void, void, category_key) = entry
|
||||
if category_key:
|
||||
# using specified category key to sort
|
||||
key = category_key
|
||||
lckey = unicodedata.normalize('NFD', key.lower())
|
||||
if lckey[0:1] in lcletters:
|
||||
lckey = chr(127) + lckey
|
||||
# ensure a determinstic order *within* letters by also sorting on
|
||||
# the entry itself
|
||||
return (lckey, entry[0])
|
||||
newlist = sorted(new.items(), key=keyfunc)
|
||||
|
||||
if group_entries:
|
||||
# fixup entries: transform
|
||||
# func() (in module foo)
|
||||
# func() (in module bar)
|
||||
# into
|
||||
# func()
|
||||
# (in module foo)
|
||||
# (in module bar)
|
||||
oldkey = '' # type: unicode
|
||||
oldsubitems = None # type: Dict[unicode, List]
|
||||
i = 0
|
||||
while i < len(newlist):
|
||||
key, (targets, subitems, _key) = newlist[i]
|
||||
# cannot move if it has subitems; structure gets too complex
|
||||
if not subitems:
|
||||
m = _fixre.match(key)
|
||||
if m:
|
||||
if oldkey == m.group(1):
|
||||
# prefixes match: add entry as subitem of the
|
||||
# previous entry
|
||||
oldsubitems.setdefault(m.group(2), [[], {}, _key])[0].\
|
||||
extend(targets)
|
||||
del newlist[i]
|
||||
continue
|
||||
oldkey = m.group(1)
|
||||
else:
|
||||
oldkey = key
|
||||
oldsubitems = subitems
|
||||
i += 1
|
||||
|
||||
# group the entries by letter
|
||||
def keyfunc2(item, letters=string.ascii_uppercase + '_'):
|
||||
# hack: mutating the subitems dicts to a list in the keyfunc
|
||||
k, v = item
|
||||
v[1] = sorted((si, se) for (si, (se, void, void)) in iteritems(v[1]))
|
||||
if v[2] is None:
|
||||
# now calculate the key
|
||||
letter = unicodedata.normalize('NFD', k[0])[0].upper()
|
||||
if letter in letters:
|
||||
return letter
|
||||
else:
|
||||
# get all other symbols under one heading
|
||||
return _('Symbols')
|
||||
else:
|
||||
return v[2]
|
||||
return [(key_, list(group))
|
||||
for (key_, group) in groupby(newlist, keyfunc2)]
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
from collections import namedtuple
|
||||
from sphinx import locale
|
||||
from sphinx.environment.managers.indexentries import IndexEntries
|
||||
from sphinx.environment.adapters.indexentries import IndexEntries
|
||||
|
||||
import mock
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user