From 539cfe9f1f430f7b86fe716266b8b0a4fb88f348 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Mon, 12 Sep 2022 22:45:13 +0100 Subject: [PATCH 1/4] Support searching for index entries --- sphinx/search/__init__.py | 41 ++++++++++++++++++++++- sphinx/themes/basic/static/searchtools.js | 18 ++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/sphinx/search/__init__.py b/sphinx/search/__init__.py index a3dd07d3f25..488a5739768 100644 --- a/sphinx/search/__init__.py +++ b/sphinx/search/__init__.py @@ -14,6 +14,7 @@ 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 @@ def __init__(self, env: BuildEnvironment, lang: str, options: Dict, scoring: str # 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 @@ def freeze(self) -> Dict[str, Any]: for title, titleid in titlelist: alltitles.setdefault(title.lower(), []).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 @@ def stem(word: str) -> str: 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 e80592c14f1..6bb4cbb6392 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)) From cc54460e7f34e5ff3655f796329e129d7fa6303b Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Tue, 13 Sep 2022 09:33:12 +0100 Subject: [PATCH 2/4] Fix tests --- tests/test_search.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/test_search.py b/tests/test_search.py index cbe1be54f73..c47c6c69594 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'), From 7322276c6b631602233983d6eb20ad60ba23b3ef Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Tue, 20 Sep 2022 22:01:43 +0100 Subject: [PATCH 3/4] changes --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 90ec78048fe..6d1675f4fab 100644 --- a/CHANGES +++ b/CHANGES @@ -22,6 +22,8 @@ Features added subtitle matches in search results * #10718: HTML Search: Save search result score to the HTML element for debugging * #10673: Make toctree accept 'genindex', 'modindex' and 'search' docnames +* #6692: HTML Search: Include explicit :rst:dir:`index` directive index entries + in the search index and search results. Patch by Adam Turner. Bugs fixed ---------- From 94ab6e8d86d0a82aebdf773e58fc2cb5aee82fc5 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Tue, 20 Sep 2022 22:02:22 +0100 Subject: [PATCH 4/4] CHANGES --- CHANGES | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index c240137f7cd..9c9596fcc64 100644 --- a/CHANGES +++ b/CHANGES @@ -28,7 +28,7 @@ Features added * #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. + in the search index and search results. Patch by Adam Turner Bugs fixed ----------