diff options
author | Adam Turner <9087854+AA-Turner@users.noreply.github.com> | 2022-09-21 00:08:03 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-21 00:08:03 +0300 |
commit | 8ae81839be3b197007f9916406a7e44b97aa6171 (patch) | |
tree | 2b25d0da3a54755662d3cd7f3b7390b8b432ce26 | |
parent | 56fd7fb8ae1e11937285f6607c43552b9e729ba6 (diff) |
Support searching for index entries (#10819)
-rw-r--r-- | CHANGES | 2 | ||||
-rw-r--r-- | sphinx/search/__init__.py | 41 | ||||
-rw-r--r-- | sphinx/themes/basic/static/searchtools.js | 18 | ||||
-rw-r--r-- | tests/test_search.py | 6 |
4 files changed, 64 insertions, 3 deletions
@@ -27,6 +27,8 @@ Features added * #10718: HTML Search: Save search result score to the HTML element for debugging * #10673: Make toctree accept 'genindex', 'modindex' and 'search' docnames * #6316, #10804: Add domain objects to the table of contents. Patch by Adam Turner +* #6692: HTML Search: Include explicit :rst:dir:`index` directive index entries + in the search index and search results. Patch by Adam Turner Bugs fixed ---------- diff --git a/sphinx/search/__init__.py b/sphinx/search/__init__.py index eea262d82..0cff8fd25 100644 --- a/sphinx/search/__init__.py +++ b/sphinx/search/__init__.py @@ -14,6 +14,7 @@ from docutils.nodes import Element, Node from sphinx import addnodes, package_dir from sphinx.deprecation import RemovedInSphinx70Warning from sphinx.environment import BuildEnvironment +from sphinx.util import split_into class SearchLanguage: @@ -242,6 +243,7 @@ class IndexBuilder: # stemmed words in titles -> set(docname) self._title_mapping: Dict[str, Set[str]] = {} self._all_titles: Dict[str, List[Tuple[str, str]]] = {} # docname -> all titles + self._index_entries: Dict[str, List[Tuple[str, str, str]]] = {} # docname -> index entry self._stem_cache: Dict[str, str] = {} # word -> stemmed word self._objtypes: Dict[Tuple[str, str], int] = {} # objtype -> index # objtype index -> (domain, type, objname (localized)) @@ -380,10 +382,15 @@ class IndexBuilder: for title, titleid in titlelist: alltitles.setdefault(title, []).append((fn2index[docname], titleid)) + index_entries: Dict[str, List[Tuple[int, str]]] = {} + for docname, entries in self._index_entries.items(): + for entry, entry_id, main_entry in entries: + index_entries.setdefault(entry.lower(), []).append((fn2index[docname], entry_id)) + return dict(docnames=docnames, filenames=filenames, titles=titles, terms=terms, objects=objects, objtypes=objtypes, objnames=objnames, titleterms=title_terms, envversion=self.env.version, - alltitles=alltitles) + alltitles=alltitles, indexentries=index_entries) def label(self) -> str: return "%s (code: %s)" % (self.lang.language_name, self.lang.lang) @@ -441,6 +448,38 @@ class IndexBuilder: if _filter(stemmed_word) and not already_indexed: self._mapping.setdefault(stemmed_word, set()).add(docname) + # find explicit entries within index directives + _index_entries: Set[Tuple[str, str, str]] = set() + for node in doctree.findall(addnodes.index): + for entry_type, value, tid, main, *index_key in node['entries']: + tid = tid or '' + try: + if entry_type == 'single': + try: + entry, subentry = split_into(2, 'single', value) + except ValueError: + entry, = split_into(1, 'single', value) + subentry = '' + _index_entries.add((entry, tid, main)) + if subentry: + _index_entries.add((subentry, tid, main)) + elif entry_type == 'pair': + first, second = split_into(2, 'pair', value) + _index_entries.add((first, tid, main)) + _index_entries.add((second, tid, main)) + elif entry_type == 'triple': + first, second, third = split_into(3, 'triple', value) + _index_entries.add((first, tid, main)) + _index_entries.add((second, tid, main)) + _index_entries.add((third, tid, main)) + elif entry_type in {'see', 'seealso'}: + first, second = split_into(2, 'see', value) + _index_entries.add((first, tid, main)) + except ValueError: + pass + + self._index_entries[docname] = sorted(_index_entries) + def context_for_searchtool(self) -> Dict[str, Any]: if self.lang.js_splitter_code: js_splitter_code = self.lang.js_splitter_code diff --git a/sphinx/themes/basic/static/searchtools.js b/sphinx/themes/basic/static/searchtools.js index 4c0b8cf7e..d7ada9b46 100644 --- a/sphinx/themes/basic/static/searchtools.js +++ b/sphinx/themes/basic/static/searchtools.js @@ -242,6 +242,7 @@ const Search = { const docNames = Search._index.docnames; const titles = Search._index.titles; const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; // stem the search terms and add them to the correct list const stemmer = new Stemmer(); @@ -295,6 +296,23 @@ const Search = { } } + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id] of foundEntries) { + let score = Math.round(100 * queryLower.length / entry.length) + results.push([ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + // lookup as object objectTerms.forEach((term) => results.push(...Search.performObjectSearch(term, objectTerms)) diff --git a/tests/test_search.py b/tests/test_search.py index cbe1be54f..c47c6c695 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -178,7 +178,8 @@ def test_IndexBuilder(): 'test': [0, 1, 2, 3]}, 'titles': ('title1_1', 'title1_2', 'title2_1', 'title2_2'), 'titleterms': {'section_titl': [0, 1, 2, 3]}, - 'alltitles': {'section_title': [(0, 'section-title'), (1, 'section-title'), (2, 'section-title'), (3, 'section-title')]} + 'alltitles': {'section_title': [(0, 'section-title'), (1, 'section-title'), (2, 'section-title'), (3, 'section-title')]}, + 'indexentries': {}, } assert index._objtypes == {('dummy1', 'objtype1'): 0, ('dummy2', 'objtype1'): 1} assert index._objnames == {0: ('dummy1', 'objtype1', 'objtype1'), @@ -236,7 +237,8 @@ def test_IndexBuilder(): 'test': [0, 1]}, 'titles': ('title1_2', 'title2_2'), 'titleterms': {'section_titl': [0, 1]}, - 'alltitles': {'section_title': [(0, 'section-title'), (1, 'section-title')]} + 'alltitles': {'section_title': [(0, 'section-title'), (1, 'section-title')]}, + 'indexentries': {}, } assert index._objtypes == {('dummy1', 'objtype1'): 0, ('dummy2', 'objtype1'): 1} assert index._objnames == {0: ('dummy1', 'objtype1', 'objtype1'), |