Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ Incompatible changes
The :confval:`autodoc_use_legacy_class_based` option has been added to
use the legacy (pre-9.0) implementation of autodoc.
Patches by Adam Turner.
* #13355: Don't include escaped title content in the search index.
Patch by Will Lachance.

Deprecated
----------
Expand Down
3 changes: 2 additions & 1 deletion sphinx/builders/html/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -668,8 +668,9 @@ def write_doc(self, docname: str, doctree: nodes.document) -> None:
def write_doc_serialized(self, docname: str, doctree: nodes.document) -> None:
self.imgpath = relative_uri(self.get_target_uri(docname), self.imagedir)
self.post_process_images(doctree)
# get title as plain text
title_node = self.env.longtitles.get(docname)
title = self.render_partial(title_node)['title'] if title_node else ''
title = title_node.astext() if title_node else ''
self.index_page(docname, doctree, title)

def finish(self) -> None:
Expand Down
13 changes: 11 additions & 2 deletions sphinx/themes/basic/static/searchtools.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,15 @@ const _removeChildren = (element) => {
const _escapeRegExp = (string) =>
string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string

const _escapeHTML = (text) => {
return text
.replaceAll("&", "&")
.replaceAll("<", "&lt;")
.replaceAll(">", "&gt;")
.replaceAll('"', "&quot;")
.replaceAll("'", "&apos;");
};

const _displayItem = (item, searchTerms, highlightTerms) => {
const docBuilder = DOCUMENTATION_OPTIONS.BUILDER;
const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX;
Expand Down Expand Up @@ -91,10 +100,10 @@ const _displayItem = (item, searchTerms, highlightTerms) => {
let linkEl = listItem.appendChild(document.createElement("a"));
linkEl.href = linkUrl + anchor;
linkEl.dataset.score = score;
linkEl.innerHTML = title;
linkEl.innerHTML = _escapeHTML(title);
if (descr) {
listItem.appendChild(document.createElement("span")).innerHTML =
" (" + descr + ")";
` (${_escapeHTML(descr)})`;
// highlight search terms in the description
if (SPHINX_HIGHLIGHT_ENABLED)
// SPHINX_HIGHLIGHT_ENABLED is set in sphinx_highlight.js
Expand Down
2 changes: 1 addition & 1 deletion tests/js/fixtures/cpp/searchindex.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion tests/js/searchtools.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ describe("Basic html theme search", function () {
// prettier-ignore
hits = [[
"index",
"&lt;no title&gt;",
"<no title>",
"",
null,
5,
Expand Down
4 changes: 4 additions & 0 deletions tests/roots/test-search/escapedtitle.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
`escaped` title with < and > in it
==================================

this document has escaped content in the title but also the characters < and > in it
19 changes: 14 additions & 5 deletions tests/test_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,17 @@ def test_term_in_heading_and_section(app: SphinxTestApp) -> None:
# if search term is in the title of one doc and in the text of another
# both documents should be a hit in the search index as a title,
# respectively text hit
assert '"textinhead":2' in searchindex
assert '"textinhead":0' in searchindex
assert '"textinhead":3' in searchindex
assert '"textinhead":1' in searchindex


@pytest.mark.sphinx('html', testroot='search')
def test_escaped_title(app: SphinxTestApp) -> None:
app.build(force_all=True)
searchindex = load_searchindex(app.outdir / 'searchindex.js')
print(searchindex)
assert 'escapedtitle' in searchindex['docnames']
assert 'escaped title with < and > in it' in searchindex['titles']


@pytest.mark.sphinx('html', testroot='search')
Expand Down Expand Up @@ -388,15 +397,15 @@ def test_search_index_gen_zh(app: SphinxTestApp) -> None:
def test_nosearch(app: SphinxTestApp) -> None:
app.build()
index = load_searchindex(app.outdir / 'searchindex.js')
assert index['docnames'] == ['index', 'nosearch', 'tocitem']
assert index['docnames'] == ['escapedtitle', 'index', 'nosearch', 'tocitem']
# latex is in 'nosearch.rst', and nowhere else
assert 'latex' not in index['terms']
# cat is in 'index.rst' but is marked with the 'no-search' class
assert 'cat' not in index['terms']
# bat is indexed from 'index.rst' and 'tocitem.rst' (document IDs 0, 2), and
# not from 'nosearch.rst' (document ID 1)
assert 'bat' in index['terms']
assert index['terms']['bat'] == [0, 2]
assert index['terms']['bat'] == [1, 3]


@pytest.mark.sphinx(
Expand All @@ -408,7 +417,7 @@ def test_nosearch(app: SphinxTestApp) -> None:
def test_parallel(app: SphinxTestApp) -> None:
app.build()
index = load_searchindex(app.outdir / 'searchindex.js')
assert index['docnames'] == ['index', 'nosearch', 'tocitem']
assert index['docnames'] == ['escapedtitle', 'index', 'nosearch', 'tocitem']


@pytest.mark.sphinx('html', testroot='search')
Expand Down
Loading