Skip to content

Commit 646a5d7

Browse files
timhoffmAA-Turnerjayaddison
authored
Support type-dependent search result highlighting via CSS (#12474)
Co-authored-by: Adam Turner <9087854+aa-turner@users.noreply.github.com> Co-authored-by: James Addison <55152140+jayaddison@users.noreply.github.com>
1 parent 9171f53 commit 646a5d7

File tree

6 files changed

+116
-16
lines changed

6 files changed

+116
-16
lines changed

CHANGES.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ Features added
2828

2929
* #11328: Mention evaluation of templated content during production of static
3030
output files.
31+
* #12474: Support type-dependent search result highlighting via CSS.
32+
Patch by Tim Hoffmann.
3133

3234
Bugs fixed
3335
----------

doc/_themes/sphinx13/static/sphinx13.css

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -691,7 +691,28 @@ div.sphinx-feature > p.admonition-title::before {
691691
justify-content: center;
692692
gap: 10px;
693693
}
694-
695694
.sphinx-users-logos .headerlink {
696695
display: none;
697696
}
697+
698+
/* -- search results -------------------------------------------------------- */
699+
700+
ul.search {
701+
padding-left: 30px;
702+
}
703+
ul.search li {
704+
padding: 5px 0 5px 10px;
705+
list-style-type: "\25A1"; /* Unicode: White Square */
706+
}
707+
ul.search li.context-index {
708+
list-style-type: "\1F4D1"; /* Unicode: Bookmark Tabs */
709+
}
710+
ul.search li.context-object {
711+
list-style-type: "\1F4E6"; /* Unicode: Package */
712+
}
713+
ul.search li.context-title {
714+
list-style-type: "\1F4C4"; /* Unicode: Page Facing Up */
715+
}
716+
ul.search li.context-text {
717+
list-style-type: "\1F4C4"; /* Unicode: Page Facing Up */
718+
}

doc/development/html_themes/index.rst

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,64 @@ If your theme package contains two or more themes, please call
221221
``sphinx.html_themes`` entry_points feature.
222222

223223

224+
Styling with CSS
225+
----------------
226+
227+
The :confval:`!stylesheets` setting can be used to add custom CSS files to a theme.
228+
229+
.. caution::
230+
231+
The structure of the HTML elements and their classes are currently not a
232+
well-defined public API. Please infer them from inspecting the built HTML
233+
pages. While we cannot guarantee full stability, they tend to be fairly
234+
stable.
235+
236+
Styling search result entries by category
237+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
238+
239+
.. versionadded:: 8.0
240+
241+
The search result items have classes indicating the context in which the
242+
search term was found. You can use the CSS selectors:
243+
244+
- ``ul.search li.context-index``:
245+
For results in an index, such as the glossary
246+
- ``ul.search li.context-object``:
247+
For results in source code, like Python function definitions
248+
- ``ul.search li.context-title``:
249+
For results found in section headings
250+
- ``ul.search li.context-text``:
251+
For results found anywhere else in the documentation text
252+
253+
As a base for inheritance by other themes, the ``basic`` theme is
254+
intentionally minimal and does not define CSS rules using these.
255+
Derived themes are encouraged to use these selectors as they see fit.
256+
For example, the following stylesheet adds contextual icons to the
257+
search result list:
258+
259+
.. code-block:: css
260+
261+
ul.search {
262+
padding-left: 30px;
263+
}
264+
ul.search li {
265+
padding: 5px 0 5px 10px;
266+
list-style-type: "\25A1"; /* Unicode: White Square */
267+
}
268+
ul.search li.context-index {
269+
list-style-type: "\1F4D1"; /* Unicode: Bookmark Tabs */
270+
}
271+
ul.search li.context-object {
272+
list-style-type: "\1F4E6"; /* Unicode: Package */
273+
}
274+
ul.search li.context-title {
275+
list-style-type: "\1F4C4"; /* Unicode: Page Facing Up */
276+
}
277+
ul.search li.context-text {
278+
list-style-type: "\1F4C4"; /* Unicode: Page Facing Up */
279+
}
280+
281+
224282
Templating
225283
----------
226284

sphinx/themes/basic/static/basic.css.jinja

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -115,15 +115,11 @@ img {
115115
/* -- search page ----------------------------------------------------------- */
116116

117117
ul.search {
118-
margin: 10px 0 0 20px;
119-
padding: 0;
118+
margin-top: 10px;
120119
}
121120

122121
ul.search li {
123-
padding: 5px 0 5px 20px;
124-
background-image: url(file.png);
125-
background-repeat: no-repeat;
126-
background-position: 0 7px;
122+
padding: 5px 0;
127123
}
128124

129125
ul.search li a {

sphinx/themes/basic/static/searchtools.js

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ if (typeof Scorer === "undefined") {
2020
// and returns the new score.
2121
/*
2222
score: result => {
23-
const [docname, title, anchor, descr, score, filename] = result
23+
const [docname, title, anchor, descr, score, filename, context] = result
2424
return score
2525
},
2626
*/
@@ -47,6 +47,14 @@ if (typeof Scorer === "undefined") {
4747
};
4848
}
4949

50+
// Global search result kind enum, used by themes to style search results.
51+
class SearchResultContext {
52+
static get index() { return "index"; }
53+
static get object() { return "object"; }
54+
static get text() { return "text"; }
55+
static get title() { return "title"; }
56+
}
57+
5058
const _removeChildren = (element) => {
5159
while (element && element.lastChild) element.removeChild(element.lastChild);
5260
};
@@ -64,9 +72,13 @@ const _displayItem = (item, searchTerms, highlightTerms) => {
6472
const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY;
6573
const contentRoot = document.documentElement.dataset.content_root;
6674

67-
const [docName, title, anchor, descr, score, _filename] = item;
75+
const [docName, title, anchor, descr, score, _filename, context] = item;
6876

6977
let listItem = document.createElement("li");
78+
// Add a class representing the item's type:
79+
// can be used by a theme's CSS selector for styling
80+
// See SearchResultContext for the class names.
81+
listItem.classList.add(`context-${context}`);
7082
let requestUrl;
7183
let linkUrl;
7284
if (docBuilder === "dirhtml") {
@@ -140,7 +152,7 @@ const _displayNextItem = (
140152
else _finishSearch(resultCount);
141153
};
142154
// Helper function used by query() to order search results.
143-
// Each input is an array of [docname, title, anchor, descr, score, filename].
155+
// Each input is an array of [docname, title, anchor, descr, score, filename, context].
144156
// Order the results by score (in opposite order of appearance, since the
145157
// `_displayNextItem` function uses pop() to retrieve items) and then alphabetically.
146158
const _orderResultsByScoreThenName = (a, b) => {
@@ -250,6 +262,7 @@ const Search = {
250262
searchSummary.classList.add("search-summary");
251263
searchSummary.innerText = "";
252264
const searchList = document.createElement("ul");
265+
searchList.setAttribute("role", "list");
253266
searchList.classList.add("search");
254267

255268
const out = document.getElementById("search-results");
@@ -320,7 +333,7 @@ const Search = {
320333
const indexEntries = Search._index.indexentries;
321334

322335
// Collect multiple result groups to be sorted separately and then ordered.
323-
// Each is an array of [docname, title, anchor, descr, score, filename].
336+
// Each is an array of [docname, title, anchor, descr, score, filename, context].
324337
const normalResults = [];
325338
const nonMainIndexResults = [];
326339

@@ -339,6 +352,7 @@ const Search = {
339352
null,
340353
score + boost,
341354
filenames[file],
355+
SearchResultContext.title,
342356
]);
343357
}
344358
}
@@ -356,6 +370,7 @@ const Search = {
356370
null,
357371
score,
358372
filenames[file],
373+
SearchResultContext.index,
359374
];
360375
if (isMain) {
361376
normalResults.push(result);
@@ -477,6 +492,7 @@ const Search = {
477492
descr,
478493
score,
479494
filenames[match[0]],
495+
SearchResultContext.object,
480496
]);
481497
};
482498
Object.keys(objects).forEach((prefix) =>
@@ -587,6 +603,7 @@ const Search = {
587603
null,
588604
score,
589605
filenames[file],
606+
SearchResultContext.text,
590607
]);
591608
}
592609
return results;

tests/js/searchtools.spec.js

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ describe('Basic html theme search', function() {
3838
"",
3939
null,
4040
5,
41-
"index.rst"
41+
"index.rst",
42+
"text"
4243
]];
4344
expect(Search.performTermsSearch(searchterms, excluded)).toEqual(hits);
4445
});
@@ -53,7 +54,9 @@ describe('Basic html theme search', function() {
5354
'',
5455
null,
5556
15,
56-
'index.rst']];
57+
'index.rst',
58+
'text'
59+
]];
5760
expect(Search.performTermsSearch(searchterms, excluded)).toEqual(hits);
5861
});
5962

@@ -68,7 +71,8 @@ describe('Basic html theme search', function() {
6871
"",
6972
null,
7073
7,
71-
"index.rst"
74+
"index.rst",
75+
"text"
7276
]];
7377
expect(Search.performTermsSearch(searchterms, excluded)).toEqual(hits);
7478
});
@@ -86,7 +90,8 @@ describe('Basic html theme search', function() {
8690
"",
8791
null,
8892
2,
89-
"index.rst"
93+
"index.rst",
94+
"text"
9095
]];
9196
expect(Search.performTermsSearch(searchterms, excluded, terms, titleterms)).toEqual(hits);
9297
});
@@ -107,7 +112,8 @@ describe('Basic html theme search', function() {
107112
'',
108113
null,
109114
16,
110-
'index.rst'
115+
'index.rst',
116+
'title'
111117
]
112118
];
113119
expect(Search._performSearch(...searchParameters)).toEqual(hits);

0 commit comments

Comments
 (0)