From b7220ca67a18feab70d356152825954c56ba42a5 Mon Sep 17 00:00:00 2001 From: Marvin Herbold Date: Tue, 21 Nov 2017 08:18:17 -0700 Subject: [PATCH 1/3] New exact phrase searching feature (for HTML) --- AUTHORS.rst | 1 + sphinx/themes/basic/static/searchtools.js | 36 +++++++++++++++++++---- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/AUTHORS.rst b/AUTHORS.rst index 1b4d6e7c85b..bad6231382d 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -64,6 +64,7 @@ Contributors * Łukasz Langa -- partial support for autodoc * Marco Buttu -- doctest extension (pyversion option) * Martin Hans -- autodoc improvements +* Marvin Herbold -- HTML exact phrase search support * Martin Larralde -- additional napoleon admonitions * Martin Mahner -- nature theme * Matthew Fernandez -- todo extension fix diff --git a/sphinx/themes/basic/static/searchtools.js b/sphinx/themes/basic/static/searchtools.js index b08d58c9b9b..b828421704f 100644 --- a/sphinx/themes/basic/static/searchtools.js +++ b/sphinx/themes/basic/static/searchtools.js @@ -57,7 +57,7 @@ const _removeChildren = (element) => { const _escapeRegExp = (string) => string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string -const _displayItem = (item, searchTerms, highlightTerms) => { +const _displayItem = (item, searchTerms, highlightTerms, exactSearchPhrases) => { const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; @@ -97,6 +97,17 @@ const _displayItem = (item, searchTerms, highlightTerms) => { fetch(requestUrl) .then((responseData) => responseData.text()) .then((data) => { + + // exclude results that don't contain exact phrases if we are searching for them + if (data) { + const lowercaseData = data.toLowerCase(); + for (const exactSearchPhrase of exactSearchPhrases) { + if (lowercaseData.search(exactSearchPhrase) === -1) { + return; + } + } + } + if (data) listItem.appendChild( Search.makeSearchSummary(data, searchTerms, anchor) @@ -124,13 +135,14 @@ const _displayNextItem = ( resultCount, searchTerms, highlightTerms, + exactSearchPhrases, ) => { // results left, load the summary and display it // this is intended to be dynamic (don't sub resultsCount) if (results.length) { - _displayItem(results.pop(), searchTerms, highlightTerms); + _displayItem(results.pop(), searchTerms, highlightTerms, exactSearchPhrases); setTimeout( - () => _displayNextItem(results, resultCount, searchTerms, highlightTerms), + () => _displayNextItem(results, resultCount, searchTerms, highlightTerms, exactSearchPhrases), 5 ); } @@ -275,6 +287,18 @@ const Search = { const excludedTerms = new Set(); const highlightTerms = new Set(); const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + + // prepare the exact phrase search feature + const exactSearchPhrases = []; + const exactSearchPattern = /"([^"]+?)"/g; + while (true) { + const exactSearchPhrase = exactSearchPattern.exec(query); + if (exactSearchPhrase === null) { + break; + } + exactSearchPhrases.push(exactSearchPhrase[1].toLowerCase()); + } + splitQuery(query.trim()).forEach((queryTerm) => { const queryTermLower = queryTerm.toLowerCase(); @@ -304,7 +328,7 @@ const Search = { // console.info("required: ", [...searchTerms]); // console.info("excluded: ", [...excludedTerms]); - return [query, searchTerms, excludedTerms, highlightTerms, objectTerms]; + return [query, searchTerms, excludedTerms, highlightTerms, objectTerms, exactSearchPhrases]; }, /** @@ -403,7 +427,7 @@ const Search = { }, query: (query) => { - const [searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms] = Search._parseQuery(query); + const [searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms, exactSearchPhrases] = Search._parseQuery(query); const results = Search._performSearch(searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms); // for debugging @@ -411,7 +435,7 @@ const Search = { // console.info("search results:", Search.lastresults); // print the results - _displayNextItem(results, results.length, searchTerms, highlightTerms); + _displayNextItem(results, results.length, searchTerms, highlightTerms, exactSearchPhrases); }, /** From e97f92f4c19259c467cc254a13f885299edbd20c Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Sat, 13 Jul 2024 17:25:55 +0100 Subject: [PATCH 2/3] Simplify MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- sphinx/themes/basic/static/searchtools.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/sphinx/themes/basic/static/searchtools.js b/sphinx/themes/basic/static/searchtools.js index b828421704f..49c5b9ace60 100644 --- a/sphinx/themes/basic/static/searchtools.js +++ b/sphinx/themes/basic/static/searchtools.js @@ -101,11 +101,8 @@ const _displayItem = (item, searchTerms, highlightTerms, exactSearchPhrases) => // exclude results that don't contain exact phrases if we are searching for them if (data) { const lowercaseData = data.toLowerCase(); - for (const exactSearchPhrase of exactSearchPhrases) { - if (lowercaseData.search(exactSearchPhrase) === -1) { - return; - } - } + const mismatch = (s) => lowercaseData.search(s) === -1; + if (exactSearchPhrases.some(mismatch)) return; } if (data) From c3df68bb9ed79d63b4ef882389124128caed2242 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Mon, 15 Jul 2024 13:48:20 +0100 Subject: [PATCH 3/3] Apply suggestions from code review Co-authored-by: Will Lachance --- sphinx/themes/basic/static/searchtools.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/sphinx/themes/basic/static/searchtools.js b/sphinx/themes/basic/static/searchtools.js index 49c5b9ace60..654219bcefc 100644 --- a/sphinx/themes/basic/static/searchtools.js +++ b/sphinx/themes/basic/static/searchtools.js @@ -101,7 +101,7 @@ const _displayItem = (item, searchTerms, highlightTerms, exactSearchPhrases) => // exclude results that don't contain exact phrases if we are searching for them if (data) { const lowercaseData = data.toLowerCase(); - const mismatch = (s) => lowercaseData.search(s) === -1; + const mismatch = (s) => !lowercaseData.includes(s); if (exactSearchPhrases.some(mismatch)) return; } @@ -288,12 +288,9 @@ const Search = { // prepare the exact phrase search feature const exactSearchPhrases = []; const exactSearchPattern = /"([^"]+?)"/g; - while (true) { - const exactSearchPhrase = exactSearchPattern.exec(query); - if (exactSearchPhrase === null) { - break; - } - exactSearchPhrases.push(exactSearchPhrase[1].toLowerCase()); + let match; + while (match = exactSearchPattern.exec(query)) { + exactSearchPhrases.push(match[1].toLowerCase()); } splitQuery(query.trim()).forEach((queryTerm) => {