diff options
author | Takeshi KOMIYA <i.tkomiya@gmail.com> | 2017-01-11 00:15:34 +0900 |
---|---|---|
committer | Takeshi KOMIYA <i.tkomiya@gmail.com> | 2017-01-28 20:43:54 +0900 |
commit | e2c7b1db4206542c72e0dfbfc78bae9a8d153dfd (patch) | |
tree | 9a014aff0077ee9408da986e7bf6946a8920de33 | |
parent | 0b0637deb2f093de80de102348de6c89fe432e11 (diff) | |
download | sphinx-git-e2c7b1db4206542c72e0dfbfc78bae9a8d153dfd.tar.gz |
Add IndexEntries adapter
-rw-r--r-- | sphinx/builders/devhelp.py | 3 | ||||
-rw-r--r-- | sphinx/builders/html.py | 3 | ||||
-rw-r--r-- | sphinx/builders/htmlhelp.py | 3 | ||||
-rw-r--r-- | sphinx/builders/qthelp.py | 3 | ||||
-rw-r--r-- | sphinx/environment/__init__.py | 14 | ||||
-rw-r--r-- | sphinx/environment/adapters/indexentries.py | 157 | ||||
-rw-r--r-- | sphinx/environment/managers/indexentries.py | 134 | ||||
-rw-r--r-- | tests/test_environment_indexentries.py | 2 |
8 files changed, 177 insertions, 142 deletions
diff --git a/sphinx/builders/devhelp.py b/sphinx/builders/devhelp.py index af8bcfeed..031c55184 100644 --- a/sphinx/builders/devhelp.py +++ b/sphinx/builders/devhelp.py @@ -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 diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index 5c3d9601e..062c56669 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -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) diff --git a/sphinx/builders/htmlhelp.py b/sphinx/builders/htmlhelp.py index 08e6f9df4..68fd3b1db 100644 --- a/sphinx/builders/htmlhelp.py +++ b/sphinx/builders/htmlhelp.py @@ -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') diff --git a/sphinx/builders/qthelp.py b/sphinx/builders/qthelp.py index 27178676f..25dec7586 100644 --- a/sphinx/builders/qthelp.py +++ b/sphinx/builders/qthelp.py @@ -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)) diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index 46cdc21ef..d41b90871 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -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]] diff --git a/sphinx/environment/adapters/indexentries.py b/sphinx/environment/adapters/indexentries.py new file mode 100644 index 000000000..9eeb50833 --- /dev/null +++ b/sphinx/environment/adapters/indexentries.py @@ -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)] diff --git a/sphinx/environment/managers/indexentries.py b/sphinx/environment/managers/indexentries.py index cb972b54c..680ef374d 100644 --- a/sphinx/environment/managers/indexentries.py +++ b/sphinx/environment/managers/indexentries.py @@ -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)] diff --git a/tests/test_environment_indexentries.py b/tests/test_environment_indexentries.py index 57a3cf52f..53e0ad65d 100644 --- a/tests/test_environment_indexentries.py +++ b/tests/test_environment_indexentries.py @@ -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 |