Sphinx 7.1.2__py3-none-any.whl → 7.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of Sphinx might be problematic. Click here for more details.
- sphinx/__init__.py +6 -6
- sphinx/__main__.py +3 -1
- sphinx/addnodes.py +35 -22
- sphinx/application.py +40 -38
- sphinx/builders/__init__.py +16 -12
- sphinx/builders/_epub_base.py +15 -11
- sphinx/builders/changes.py +6 -4
- sphinx/builders/dirhtml.py +4 -2
- sphinx/builders/dummy.py +6 -4
- sphinx/builders/epub3.py +16 -8
- sphinx/builders/gettext.py +40 -43
- sphinx/builders/html/__init__.py +166 -196
- sphinx/builders/html/_assets.py +116 -0
- sphinx/builders/html/transforms.py +4 -2
- sphinx/builders/latex/__init__.py +12 -7
- sphinx/builders/latex/theming.py +5 -2
- sphinx/builders/latex/transforms.py +6 -3
- sphinx/builders/linkcheck.py +18 -11
- sphinx/builders/manpage.py +6 -4
- sphinx/builders/singlehtml.py +16 -9
- sphinx/builders/texinfo.py +11 -6
- sphinx/builders/text.py +8 -3
- sphinx/builders/xml.py +9 -4
- sphinx/cmd/build.py +27 -14
- sphinx/cmd/make_mode.py +13 -4
- sphinx/cmd/quickstart.py +13 -4
- sphinx/config.py +17 -14
- sphinx/deprecation.py +4 -2
- sphinx/directives/__init__.py +44 -12
- sphinx/directives/code.py +5 -4
- sphinx/directives/other.py +92 -44
- sphinx/directives/patches.py +1 -1
- sphinx/domains/__init__.py +11 -8
- sphinx/domains/c.py +67 -57
- sphinx/domains/changeset.py +3 -2
- sphinx/domains/citation.py +2 -1
- sphinx/domains/cpp.py +136 -93
- sphinx/domains/index.py +9 -5
- sphinx/domains/javascript.py +32 -19
- sphinx/domains/math.py +5 -3
- sphinx/domains/python.py +69 -57
- sphinx/domains/rst.py +20 -11
- sphinx/domains/std.py +21 -15
- sphinx/environment/__init__.py +97 -65
- sphinx/environment/adapters/indexentries.py +13 -10
- sphinx/environment/adapters/toctree.py +485 -308
- sphinx/environment/collectors/__init__.py +3 -4
- sphinx/environment/collectors/asset.py +10 -4
- sphinx/environment/collectors/dependencies.py +7 -4
- sphinx/environment/collectors/metadata.py +7 -5
- sphinx/environment/collectors/title.py +5 -3
- sphinx/environment/collectors/toctree.py +13 -8
- sphinx/errors.py +1 -1
- sphinx/events.py +5 -5
- sphinx/ext/apidoc.py +49 -27
- sphinx/ext/autodoc/__init__.py +179 -161
- sphinx/ext/autodoc/directive.py +10 -6
- sphinx/ext/autodoc/importer.py +22 -13
- sphinx/ext/autodoc/mock.py +4 -1
- sphinx/ext/autodoc/preserve_defaults.py +80 -12
- sphinx/ext/autodoc/type_comment.py +14 -10
- sphinx/ext/autodoc/typehints.py +7 -3
- sphinx/ext/autosectionlabel.py +6 -3
- sphinx/ext/autosummary/__init__.py +21 -15
- sphinx/ext/autosummary/generate.py +176 -126
- sphinx/ext/coverage.py +93 -8
- sphinx/ext/doctest.py +28 -17
- sphinx/ext/duration.py +19 -17
- sphinx/ext/extlinks.py +11 -6
- sphinx/ext/githubpages.py +8 -7
- sphinx/ext/graphviz.py +61 -17
- sphinx/ext/ifconfig.py +7 -4
- sphinx/ext/imgconverter.py +4 -2
- sphinx/ext/imgmath.py +29 -23
- sphinx/ext/inheritance_diagram.py +41 -27
- sphinx/ext/intersphinx.py +45 -38
- sphinx/ext/linkcode.py +8 -5
- sphinx/ext/mathjax.py +13 -9
- sphinx/ext/napoleon/__init__.py +3 -3
- sphinx/ext/napoleon/docstring.py +40 -31
- sphinx/ext/todo.py +10 -7
- sphinx/ext/viewcode.py +46 -25
- sphinx/extension.py +1 -1
- sphinx/highlighting.py +20 -12
- sphinx/io.py +5 -4
- sphinx/jinja2glue.py +24 -19
- sphinx/locale/__init__.py +8 -2
- sphinx/locale/ar/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ar/LC_MESSAGES/sphinx.po +756 -740
- sphinx/locale/bg/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/bg/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/bn/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/bn/LC_MESSAGES/sphinx.po +755 -739
- sphinx/locale/ca/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ca/LC_MESSAGES/sphinx.po +768 -752
- sphinx/locale/cak/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/cak/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/cs/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/cs/LC_MESSAGES/sphinx.po +758 -742
- sphinx/locale/cy/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/cy/LC_MESSAGES/sphinx.po +759 -743
- sphinx/locale/da/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/da/LC_MESSAGES/sphinx.po +760 -744
- sphinx/locale/de/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/de/LC_MESSAGES/sphinx.po +759 -743
- sphinx/locale/de_DE/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/de_DE/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/el/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/el/LC_MESSAGES/sphinx.po +763 -747
- sphinx/locale/en_DE/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_DE/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/en_FR/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_FR/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/en_GB/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_GB/LC_MESSAGES/sphinx.po +768 -752
- sphinx/locale/en_HK/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_HK/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/eo/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/eo/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/es/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/es/LC_MESSAGES/sphinx.po +767 -751
- sphinx/locale/es_CO/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/es_CO/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/et/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/et/LC_MESSAGES/sphinx.po +762 -746
- sphinx/locale/eu/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/eu/LC_MESSAGES/sphinx.po +755 -739
- sphinx/locale/fa/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fa/LC_MESSAGES/sphinx.po +766 -750
- sphinx/locale/fi/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fi/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/fr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fr/LC_MESSAGES/sphinx.po +768 -752
- sphinx/locale/fr_FR/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fr_FR/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/gl/LC_MESSAGES/sphinx.js +60 -0
- sphinx/locale/gl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/gl/LC_MESSAGES/sphinx.po +3695 -0
- sphinx/locale/he/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/he/LC_MESSAGES/sphinx.po +755 -739
- sphinx/locale/hi/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hi/LC_MESSAGES/sphinx.po +763 -747
- sphinx/locale/hi_IN/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hi_IN/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/hr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hr/LC_MESSAGES/sphinx.po +760 -744
- sphinx/locale/hu/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hu/LC_MESSAGES/sphinx.po +759 -743
- sphinx/locale/id/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/id/LC_MESSAGES/sphinx.po +765 -749
- sphinx/locale/is/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/is/LC_MESSAGES/sphinx.po +760 -744
- sphinx/locale/it/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/it/LC_MESSAGES/sphinx.po +760 -744
- sphinx/locale/ja/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ja/LC_MESSAGES/sphinx.po +767 -751
- sphinx/locale/ka/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ka/LC_MESSAGES/sphinx.po +759 -743
- sphinx/locale/ko/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ko/LC_MESSAGES/sphinx.po +767 -751
- sphinx/locale/lt/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/lt/LC_MESSAGES/sphinx.po +755 -739
- sphinx/locale/lv/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/lv/LC_MESSAGES/sphinx.po +755 -739
- sphinx/locale/mk/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/mk/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/nb_NO/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/nb_NO/LC_MESSAGES/sphinx.po +755 -739
- sphinx/locale/ne/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ne/LC_MESSAGES/sphinx.po +755 -739
- sphinx/locale/nl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/nl/LC_MESSAGES/sphinx.po +760 -744
- sphinx/locale/pl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pl/LC_MESSAGES/sphinx.po +762 -745
- sphinx/locale/pt/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pt/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/pt_BR/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po +768 -752
- sphinx/locale/pt_PT/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pt_PT/LC_MESSAGES/sphinx.po +755 -739
- sphinx/locale/ro/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ro/LC_MESSAGES/sphinx.po +759 -743
- sphinx/locale/ru/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ru/LC_MESSAGES/sphinx.po +760 -744
- sphinx/locale/si/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/si/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/sk/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sk/LC_MESSAGES/sphinx.po +765 -749
- sphinx/locale/sl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sl/LC_MESSAGES/sphinx.po +755 -739
- sphinx/locale/sphinx.pot +748 -740
- sphinx/locale/sq/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sq/LC_MESSAGES/sphinx.po +768 -752
- sphinx/locale/sr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sr/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/sr@latin/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sr@latin/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/sr_RS/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sr_RS/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/sv/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sv/LC_MESSAGES/sphinx.po +755 -739
- sphinx/locale/ta/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ta/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/te/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/te/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/tr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/tr/LC_MESSAGES/sphinx.po +763 -747
- sphinx/locale/uk_UA/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/uk_UA/LC_MESSAGES/sphinx.po +760 -749
- sphinx/locale/ur/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ur/LC_MESSAGES/sphinx.po +759 -748
- sphinx/locale/vi/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/vi/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/yue/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/yue/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/zh_CN/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_CN/LC_MESSAGES/sphinx.po +768 -752
- sphinx/locale/zh_HK/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_HK/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/zh_TW/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_TW/LC_MESSAGES/sphinx.po +767 -751
- sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.po +754 -738
- sphinx/parsers.py +5 -4
- sphinx/project.py +52 -34
- sphinx/pycode/__init__.py +2 -1
- sphinx/pycode/ast.py +7 -13
- sphinx/pycode/parser.py +42 -38
- sphinx/registry.py +35 -29
- sphinx/roles.py +9 -4
- sphinx/search/__init__.py +5 -17
- sphinx/search/da.py +1 -1
- sphinx/search/de.py +1 -1
- sphinx/search/en.py +1 -1
- sphinx/search/es.py +1 -1
- sphinx/search/fi.py +1 -1
- sphinx/search/fr.py +1 -1
- sphinx/search/hu.py +1 -1
- sphinx/search/it.py +1 -1
- sphinx/search/ja.py +1 -1
- sphinx/search/nl.py +1 -1
- sphinx/search/no.py +1 -1
- sphinx/search/pt.py +1 -1
- sphinx/search/ro.py +1 -1
- sphinx/search/ru.py +1 -1
- sphinx/search/sv.py +1 -1
- sphinx/search/tr.py +1 -1
- sphinx/search/zh.py +1 -1
- sphinx/testing/fixtures.py +23 -30
- sphinx/testing/path.py +9 -0
- sphinx/testing/restructuredtext.py +13 -5
- sphinx/testing/util.py +20 -63
- sphinx/texinputs/sphinxlatexobjects.sty +15 -15
- sphinx/themes/agogo/static/agogo.css_t +10 -4
- sphinx/themes/basic/layout.html +1 -1
- sphinx/themes/basic/static/basic.css_t +4 -0
- sphinx/themes/basic/static/documentation_options.js_t +1 -2
- sphinx/themes/basic/static/searchtools.js +17 -9
- sphinx/themes/basic/static/sphinx_highlight.js +13 -3
- sphinx/themes/bizstyle/static/bizstyle.css_t +4 -0
- sphinx/themes/classic/theme.conf +1 -1
- sphinx/themes/epub/static/epub.css_t +6 -1
- sphinx/themes/haiku/theme.conf +1 -1
- sphinx/themes/nature/static/nature.css_t +4 -0
- sphinx/themes/nonav/static/nonav.css_t +6 -1
- sphinx/themes/pyramid/static/pyramid.css_t +4 -0
- sphinx/themes/scrolls/static/scrolls.css_t +4 -0
- sphinx/themes/scrolls/theme.conf +1 -1
- sphinx/themes/sphinxdoc/static/sphinxdoc.css_t +4 -0
- sphinx/theming.py +9 -7
- sphinx/transforms/__init__.py +79 -3
- sphinx/transforms/compact_bullet_list.py +6 -3
- sphinx/transforms/i18n.py +26 -10
- sphinx/transforms/post_transforms/__init__.py +21 -8
- sphinx/transforms/post_transforms/code.py +6 -3
- sphinx/transforms/post_transforms/images.py +13 -9
- sphinx/util/__init__.py +21 -92
- sphinx/util/cfamily.py +7 -4
- sphinx/util/display.py +3 -2
- sphinx/util/docfields.py +7 -6
- sphinx/util/docstrings.py +1 -1
- sphinx/util/docutils.py +41 -31
- sphinx/util/fileutil.py +9 -6
- sphinx/util/i18n.py +21 -18
- sphinx/util/images.py +2 -1
- sphinx/util/index_entries.py +27 -0
- sphinx/util/inspect.py +83 -67
- sphinx/util/inventory.py +4 -2
- sphinx/util/logging.py +9 -6
- sphinx/util/matching.py +5 -2
- sphinx/util/math.py +6 -3
- sphinx/util/nodes.py +70 -31
- sphinx/util/osutil.py +22 -40
- sphinx/util/parallel.py +4 -1
- sphinx/util/rst.py +7 -3
- sphinx/util/tags.py +11 -4
- sphinx/util/template.py +17 -14
- sphinx/util/typing.py +61 -20
- sphinx/versioning.py +6 -4
- sphinx/writers/html.py +1 -1
- sphinx/writers/html5.py +32 -24
- sphinx/writers/latex.py +67 -53
- sphinx/writers/manpage.py +9 -5
- sphinx/writers/texinfo.py +11 -9
- sphinx/writers/text.py +14 -9
- sphinx/writers/xml.py +3 -2
- {sphinx-7.1.2.dist-info → sphinx-7.2.0.dist-info}/METADATA +7 -5
- sphinx-7.2.0.dist-info/RECORD +568 -0
- sphinx/testing/comparer.py +0 -97
- sphinx-7.1.2.dist-info/RECORD +0 -564
- {sphinx-7.1.2.dist-info → sphinx-7.2.0.dist-info}/LICENSE +0 -0
- {sphinx-7.1.2.dist-info → sphinx-7.2.0.dist-info}/WHEEL +0 -0
- {sphinx-7.1.2.dist-info → sphinx-7.2.0.dist-info}/entry_points.txt +0 -0
|
@@ -57,12 +57,12 @@ const _removeChildren = (element) => {
|
|
|
57
57
|
const _escapeRegExp = (string) =>
|
|
58
58
|
string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string
|
|
59
59
|
|
|
60
|
-
const _displayItem = (item, searchTerms) => {
|
|
60
|
+
const _displayItem = (item, searchTerms, highlightTerms) => {
|
|
61
61
|
const docBuilder = DOCUMENTATION_OPTIONS.BUILDER;
|
|
62
|
-
const docUrlRoot = DOCUMENTATION_OPTIONS.URL_ROOT;
|
|
63
62
|
const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX;
|
|
64
63
|
const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX;
|
|
65
64
|
const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY;
|
|
65
|
+
const contentRoot = document.documentElement.dataset.content_root;
|
|
66
66
|
|
|
67
67
|
const [docName, title, anchor, descr, score, _filename] = item;
|
|
68
68
|
|
|
@@ -75,20 +75,24 @@ const _displayItem = (item, searchTerms) => {
|
|
|
75
75
|
if (dirname.match(/\/index\/$/))
|
|
76
76
|
dirname = dirname.substring(0, dirname.length - 6);
|
|
77
77
|
else if (dirname === "index/") dirname = "";
|
|
78
|
-
requestUrl =
|
|
78
|
+
requestUrl = contentRoot + dirname;
|
|
79
79
|
linkUrl = requestUrl;
|
|
80
80
|
} else {
|
|
81
81
|
// normal html builders
|
|
82
|
-
requestUrl =
|
|
82
|
+
requestUrl = contentRoot + docName + docFileSuffix;
|
|
83
83
|
linkUrl = docName + docLinkSuffix;
|
|
84
84
|
}
|
|
85
85
|
let linkEl = listItem.appendChild(document.createElement("a"));
|
|
86
86
|
linkEl.href = linkUrl + anchor;
|
|
87
87
|
linkEl.dataset.score = score;
|
|
88
88
|
linkEl.innerHTML = title;
|
|
89
|
-
if (descr)
|
|
89
|
+
if (descr) {
|
|
90
90
|
listItem.appendChild(document.createElement("span")).innerHTML =
|
|
91
91
|
" (" + descr + ")";
|
|
92
|
+
// highlight search terms in the description
|
|
93
|
+
if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js
|
|
94
|
+
highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted"));
|
|
95
|
+
}
|
|
92
96
|
else if (showSearchSummary)
|
|
93
97
|
fetch(requestUrl)
|
|
94
98
|
.then((responseData) => responseData.text())
|
|
@@ -97,6 +101,9 @@ const _displayItem = (item, searchTerms) => {
|
|
|
97
101
|
listItem.appendChild(
|
|
98
102
|
Search.makeSearchSummary(data, searchTerms)
|
|
99
103
|
);
|
|
104
|
+
// highlight search terms in the summary
|
|
105
|
+
if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js
|
|
106
|
+
highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted"));
|
|
100
107
|
});
|
|
101
108
|
Search.output.appendChild(listItem);
|
|
102
109
|
};
|
|
@@ -115,14 +122,15 @@ const _finishSearch = (resultCount) => {
|
|
|
115
122
|
const _displayNextItem = (
|
|
116
123
|
results,
|
|
117
124
|
resultCount,
|
|
118
|
-
searchTerms
|
|
125
|
+
searchTerms,
|
|
126
|
+
highlightTerms,
|
|
119
127
|
) => {
|
|
120
128
|
// results left, load the summary and display it
|
|
121
129
|
// this is intended to be dynamic (don't sub resultsCount)
|
|
122
130
|
if (results.length) {
|
|
123
|
-
_displayItem(results.pop(), searchTerms);
|
|
131
|
+
_displayItem(results.pop(), searchTerms, highlightTerms);
|
|
124
132
|
setTimeout(
|
|
125
|
-
() => _displayNextItem(results, resultCount, searchTerms),
|
|
133
|
+
() => _displayNextItem(results, resultCount, searchTerms, highlightTerms),
|
|
126
134
|
5
|
|
127
135
|
);
|
|
128
136
|
}
|
|
@@ -360,7 +368,7 @@ const Search = {
|
|
|
360
368
|
// console.info("search results:", Search.lastresults);
|
|
361
369
|
|
|
362
370
|
// print the results
|
|
363
|
-
_displayNextItem(results, results.length, searchTerms);
|
|
371
|
+
_displayNextItem(results, results.length, searchTerms, highlightTerms);
|
|
364
372
|
},
|
|
365
373
|
|
|
366
374
|
/**
|
|
@@ -29,14 +29,19 @@ const _highlight = (node, addItems, text, className) => {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
span.appendChild(document.createTextNode(val.substr(pos, text.length)));
|
|
32
|
+
const rest = document.createTextNode(val.substr(pos + text.length));
|
|
32
33
|
parent.insertBefore(
|
|
33
34
|
span,
|
|
34
35
|
parent.insertBefore(
|
|
35
|
-
|
|
36
|
+
rest,
|
|
36
37
|
node.nextSibling
|
|
37
38
|
)
|
|
38
39
|
);
|
|
39
40
|
node.nodeValue = val.substr(0, pos);
|
|
41
|
+
/* There may be more occurrences of search term in this node. So call this
|
|
42
|
+
* function recursively on the remaining fragment.
|
|
43
|
+
*/
|
|
44
|
+
_highlight(rest, addItems, text, className);
|
|
40
45
|
|
|
41
46
|
if (isInSVG) {
|
|
42
47
|
const rect = document.createElementNS(
|
|
@@ -140,5 +145,10 @@ const SphinxHighlight = {
|
|
|
140
145
|
},
|
|
141
146
|
};
|
|
142
147
|
|
|
143
|
-
_ready(
|
|
144
|
-
|
|
148
|
+
_ready(() => {
|
|
149
|
+
/* Do not call highlightSearchWords() when we are on the search page.
|
|
150
|
+
* It will highlight words from the *previous* search query.
|
|
151
|
+
*/
|
|
152
|
+
if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords();
|
|
153
|
+
SphinxHighlight.initEscapeListener();
|
|
154
|
+
});
|
sphinx/themes/classic/theme.conf
CHANGED
|
@@ -26,11 +26,16 @@ div.clearer {
|
|
|
26
26
|
clear: both;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
a:link
|
|
29
|
+
a:link {
|
|
30
30
|
color: #3333ff;
|
|
31
31
|
text-decoration: underline;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
a:visited {
|
|
35
|
+
color: #551a8b;
|
|
36
|
+
text-decoration: underline;
|
|
37
|
+
}
|
|
38
|
+
|
|
34
39
|
img {
|
|
35
40
|
border: 0;
|
|
36
41
|
max-width: 100%;
|
sphinx/themes/haiku/theme.conf
CHANGED
|
@@ -15,11 +15,16 @@ div.clearer {
|
|
|
15
15
|
clear: both;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
a:link
|
|
18
|
+
a:link {
|
|
19
19
|
color: #3333ff;
|
|
20
20
|
text-decoration: underline;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
a:visited {
|
|
24
|
+
color: #551a8b;
|
|
25
|
+
text-decoration: underline;
|
|
26
|
+
}
|
|
27
|
+
|
|
23
28
|
img {
|
|
24
29
|
border: 0;
|
|
25
30
|
max-width: 100%;
|
sphinx/themes/scrolls/theme.conf
CHANGED
sphinx/theming.py
CHANGED
|
@@ -16,6 +16,8 @@ if sys.version_info >= (3, 10):
|
|
|
16
16
|
else:
|
|
17
17
|
from importlib_metadata import entry_points
|
|
18
18
|
|
|
19
|
+
import contextlib
|
|
20
|
+
|
|
19
21
|
from sphinx import package_dir
|
|
20
22
|
from sphinx.errors import ThemeError
|
|
21
23
|
from sphinx.locale import __
|
|
@@ -107,17 +109,18 @@ class Theme:
|
|
|
107
109
|
'searched theme configs') % (section, name)) from exc
|
|
108
110
|
return default
|
|
109
111
|
|
|
110
|
-
def get_options(self, overrides: dict[str, Any] =
|
|
112
|
+
def get_options(self, overrides: dict[str, Any] | None = None) -> dict[str, Any]:
|
|
111
113
|
"""Return a dictionary of theme options and their values."""
|
|
114
|
+
if overrides is None:
|
|
115
|
+
overrides = {}
|
|
116
|
+
|
|
112
117
|
if self.base:
|
|
113
118
|
options = self.base.get_options()
|
|
114
119
|
else:
|
|
115
120
|
options = {}
|
|
116
121
|
|
|
117
|
-
|
|
122
|
+
with contextlib.suppress(configparser.NoSectionError):
|
|
118
123
|
options.update(self.config.items('options'))
|
|
119
|
-
except configparser.NoSectionError:
|
|
120
|
-
pass
|
|
121
124
|
|
|
122
125
|
for option, value in overrides.items():
|
|
123
126
|
if option not in options:
|
|
@@ -130,10 +133,9 @@ class Theme:
|
|
|
130
133
|
def cleanup(self) -> None:
|
|
131
134
|
"""Remove temporary directories."""
|
|
132
135
|
if self.rootdir:
|
|
133
|
-
|
|
136
|
+
with contextlib.suppress(Exception):
|
|
134
137
|
shutil.rmtree(self.rootdir)
|
|
135
|
-
|
|
136
|
-
pass
|
|
138
|
+
|
|
137
139
|
if self.base:
|
|
138
140
|
self.base.cleanup()
|
|
139
141
|
|
sphinx/transforms/__init__.py
CHANGED
|
@@ -4,10 +4,9 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import re
|
|
6
6
|
import unicodedata
|
|
7
|
-
from typing import TYPE_CHECKING, Any,
|
|
7
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
8
8
|
|
|
9
9
|
from docutils import nodes
|
|
10
|
-
from docutils.nodes import Node, Text
|
|
11
10
|
from docutils.transforms import Transform, Transformer
|
|
12
11
|
from docutils.transforms.parts import ContentsFilter
|
|
13
12
|
from docutils.transforms.universal import SmartQuotes
|
|
@@ -15,7 +14,6 @@ from docutils.utils import normalize_language_tag
|
|
|
15
14
|
from docutils.utils.smartquotes import smartchars
|
|
16
15
|
|
|
17
16
|
from sphinx import addnodes
|
|
18
|
-
from sphinx.config import Config
|
|
19
17
|
from sphinx.locale import _, __
|
|
20
18
|
from sphinx.util import logging
|
|
21
19
|
from sphinx.util.docutils import new_document
|
|
@@ -23,7 +21,12 @@ from sphinx.util.i18n import format_date
|
|
|
23
21
|
from sphinx.util.nodes import apply_source_workaround, is_smartquotable
|
|
24
22
|
|
|
25
23
|
if TYPE_CHECKING:
|
|
24
|
+
from collections.abc import Generator
|
|
25
|
+
|
|
26
|
+
from docutils.nodes import Node, Text
|
|
27
|
+
|
|
26
28
|
from sphinx.application import Sphinx
|
|
29
|
+
from sphinx.config import Config
|
|
27
30
|
from sphinx.domains.std import StandardDomain
|
|
28
31
|
from sphinx.environment import BuildEnvironment
|
|
29
32
|
|
|
@@ -412,6 +415,78 @@ class GlossarySorter(SphinxTransform):
|
|
|
412
415
|
)
|
|
413
416
|
|
|
414
417
|
|
|
418
|
+
class ReorderConsecutiveTargetAndIndexNodes(SphinxTransform):
|
|
419
|
+
"""Index nodes interspersed between target nodes prevent other
|
|
420
|
+
Transformations from combining those target nodes,
|
|
421
|
+
e.g. ``PropagateTargets``. This transformation reorders them:
|
|
422
|
+
|
|
423
|
+
Given the following ``document`` as input::
|
|
424
|
+
|
|
425
|
+
<document>
|
|
426
|
+
<target ids="id1" ...>
|
|
427
|
+
<index entries="...1...">
|
|
428
|
+
<target ids="id2" ...>
|
|
429
|
+
<target ids="id3" ...>
|
|
430
|
+
<index entries="...2...">
|
|
431
|
+
<target ids="id4" ...>
|
|
432
|
+
|
|
433
|
+
The transformed result will be::
|
|
434
|
+
|
|
435
|
+
<document>
|
|
436
|
+
<index entries="...1...">
|
|
437
|
+
<index entries="...2...">
|
|
438
|
+
<target ids="id1" ...>
|
|
439
|
+
<target ids="id2" ...>
|
|
440
|
+
<target ids="id3" ...>
|
|
441
|
+
<target ids="id4" ...>
|
|
442
|
+
"""
|
|
443
|
+
|
|
444
|
+
# This transform MUST run before ``PropagateTargets``.
|
|
445
|
+
default_priority = 220
|
|
446
|
+
|
|
447
|
+
def apply(self, **kwargs: Any) -> None:
|
|
448
|
+
for target in self.document.findall(nodes.target):
|
|
449
|
+
_reorder_index_target_nodes(target)
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
def _reorder_index_target_nodes(start_node: nodes.target) -> None:
|
|
453
|
+
"""Sort target and index nodes.
|
|
454
|
+
|
|
455
|
+
Find all consecutive target and index nodes starting from ``start_node``,
|
|
456
|
+
and move all index nodes to before the first target node.
|
|
457
|
+
"""
|
|
458
|
+
nodes_to_reorder: list[nodes.target | addnodes.index] = []
|
|
459
|
+
|
|
460
|
+
# Note that we cannot use 'condition' to filter,
|
|
461
|
+
# as we want *consecutive* target & index nodes.
|
|
462
|
+
node: nodes.Node
|
|
463
|
+
for node in start_node.findall(descend=False, siblings=True):
|
|
464
|
+
if isinstance(node, (nodes.target, addnodes.index)):
|
|
465
|
+
nodes_to_reorder.append(node)
|
|
466
|
+
continue
|
|
467
|
+
break # must be a consecutive run of target or index nodes
|
|
468
|
+
|
|
469
|
+
if len(nodes_to_reorder) < 2:
|
|
470
|
+
return # Nothing to reorder
|
|
471
|
+
|
|
472
|
+
parent = nodes_to_reorder[0].parent
|
|
473
|
+
if parent == nodes_to_reorder[-1].parent:
|
|
474
|
+
first_idx = parent.index(nodes_to_reorder[0])
|
|
475
|
+
last_idx = parent.index(nodes_to_reorder[-1])
|
|
476
|
+
if first_idx + len(nodes_to_reorder) - 1 == last_idx:
|
|
477
|
+
parent[first_idx:last_idx + 1] = sorted(nodes_to_reorder, key=_sort_key)
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
def _sort_key(node: nodes.Node) -> int:
|
|
481
|
+
# Must be a stable sort.
|
|
482
|
+
if isinstance(node, addnodes.index):
|
|
483
|
+
return 0
|
|
484
|
+
if isinstance(node, nodes.target):
|
|
485
|
+
return 1
|
|
486
|
+
msg = f'_sort_key called with unexpected node type {type(node)!r}'
|
|
487
|
+
raise ValueError(msg)
|
|
488
|
+
|
|
489
|
+
|
|
415
490
|
def setup(app: Sphinx) -> dict[str, Any]:
|
|
416
491
|
app.add_transform(ApplySourceWorkaround)
|
|
417
492
|
app.add_transform(ExtraTranslatableNodes)
|
|
@@ -428,6 +503,7 @@ def setup(app: Sphinx) -> dict[str, Any]:
|
|
|
428
503
|
app.add_transform(DoctreeReadEvent)
|
|
429
504
|
app.add_transform(ManpageLink)
|
|
430
505
|
app.add_transform(GlossarySorter)
|
|
506
|
+
app.add_transform(ReorderConsecutiveTargetAndIndexNodes)
|
|
431
507
|
|
|
432
508
|
return {
|
|
433
509
|
'version': 'builtin',
|
|
@@ -2,15 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from typing import Any, cast
|
|
5
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
6
6
|
|
|
7
7
|
from docutils import nodes
|
|
8
|
-
from docutils.nodes import Node
|
|
9
8
|
|
|
10
9
|
from sphinx import addnodes
|
|
11
|
-
from sphinx.application import Sphinx
|
|
12
10
|
from sphinx.transforms import SphinxTransform
|
|
13
11
|
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from docutils.nodes import Node
|
|
14
|
+
|
|
15
|
+
from sphinx.application import Sphinx
|
|
16
|
+
|
|
14
17
|
|
|
15
18
|
class RefOnlyListChecker(nodes.GenericNodeVisitor):
|
|
16
19
|
"""Raise `nodes.NodeFound` if non-simple list item is encountered.
|
sphinx/transforms/i18n.py
CHANGED
|
@@ -6,20 +6,20 @@ import contextlib
|
|
|
6
6
|
from os import path
|
|
7
7
|
from re import DOTALL, match
|
|
8
8
|
from textwrap import indent
|
|
9
|
-
from typing import TYPE_CHECKING, Any,
|
|
9
|
+
from typing import TYPE_CHECKING, Any, TypeVar
|
|
10
10
|
|
|
11
11
|
from docutils import nodes
|
|
12
12
|
from docutils.io import StringInput
|
|
13
13
|
|
|
14
14
|
from sphinx import addnodes
|
|
15
|
-
from sphinx.config import Config
|
|
16
15
|
from sphinx.domains.std import make_glossary_term, split_term_classifiers
|
|
17
16
|
from sphinx.errors import ConfigError
|
|
18
17
|
from sphinx.locale import __
|
|
19
18
|
from sphinx.locale import init as init_locale
|
|
20
19
|
from sphinx.transforms import SphinxTransform
|
|
21
|
-
from sphinx.util import get_filetype, logging
|
|
20
|
+
from sphinx.util import get_filetype, logging
|
|
22
21
|
from sphinx.util.i18n import docname_to_domain
|
|
22
|
+
from sphinx.util.index_entries import split_index_msg
|
|
23
23
|
from sphinx.util.nodes import (
|
|
24
24
|
IMAGE_TYPE_NODES,
|
|
25
25
|
LITERAL_TYPE_NODES,
|
|
@@ -29,7 +29,10 @@ from sphinx.util.nodes import (
|
|
|
29
29
|
)
|
|
30
30
|
|
|
31
31
|
if TYPE_CHECKING:
|
|
32
|
+
from collections.abc import Sequence
|
|
33
|
+
|
|
32
34
|
from sphinx.application import Sphinx
|
|
35
|
+
from sphinx.config import Config
|
|
33
36
|
|
|
34
37
|
|
|
35
38
|
logger = logging.getLogger(__name__)
|
|
@@ -311,7 +314,8 @@ class _NodeUpdater:
|
|
|
311
314
|
return (
|
|
312
315
|
node["refdomain"],
|
|
313
316
|
node["reftype"],
|
|
314
|
-
node['reftarget'],
|
|
317
|
+
node['reftarget'],
|
|
318
|
+
)
|
|
315
319
|
|
|
316
320
|
for old in old_xrefs:
|
|
317
321
|
key = get_ref_key(old)
|
|
@@ -350,9 +354,16 @@ class Locale(SphinxTransform):
|
|
|
350
354
|
if not has_catalog:
|
|
351
355
|
return
|
|
352
356
|
|
|
357
|
+
catalogues = [getattr(catalog, '_catalog', None)]
|
|
358
|
+
while (catalog := catalog._fallback) is not None: # type: ignore[attr-defined]
|
|
359
|
+
catalogues.append(getattr(catalog, '_catalog', None))
|
|
360
|
+
merged: dict[str, str] = {}
|
|
361
|
+
for catalogue in filter(None, reversed(catalogues)): # type: dict[str, str]
|
|
362
|
+
merged |= catalogue
|
|
363
|
+
|
|
353
364
|
# phase1: replace reference ids with translated names
|
|
354
365
|
for node, msg in extract_messages(self.document):
|
|
355
|
-
msgstr =
|
|
366
|
+
msgstr = merged.get(msg, '')
|
|
356
367
|
|
|
357
368
|
# There is no point in having #noqa on literal blocks because
|
|
358
369
|
# they cannot contain references. Recognizing it would just
|
|
@@ -361,10 +372,14 @@ class Locale(SphinxTransform):
|
|
|
361
372
|
if not isinstance(node, LITERAL_TYPE_NODES):
|
|
362
373
|
msgstr, _ = parse_noqa(msgstr)
|
|
363
374
|
|
|
364
|
-
if
|
|
375
|
+
if msgstr.strip() == '':
|
|
365
376
|
# as-of-yet untranslated
|
|
366
377
|
node['translated'] = False
|
|
367
378
|
continue
|
|
379
|
+
if msgstr == msg:
|
|
380
|
+
# identical source and translated messages
|
|
381
|
+
node['translated'] = True
|
|
382
|
+
continue
|
|
368
383
|
|
|
369
384
|
# Avoid "Literal block expected; none found." warnings.
|
|
370
385
|
# If msgstr ends with '::' then it cause warning message at
|
|
@@ -413,7 +428,7 @@ class Locale(SphinxTransform):
|
|
|
413
428
|
if node.setdefault('translated', False): # to avoid double translation
|
|
414
429
|
continue # skip if the node is already translated by phase1
|
|
415
430
|
|
|
416
|
-
msgstr =
|
|
431
|
+
msgstr = merged.get(msg, '')
|
|
417
432
|
noqa = False
|
|
418
433
|
|
|
419
434
|
# See above.
|
|
@@ -507,7 +522,7 @@ class Locale(SphinxTransform):
|
|
|
507
522
|
msg_parts = split_index_msg(entry_type, value)
|
|
508
523
|
msgstr_parts = []
|
|
509
524
|
for part in msg_parts:
|
|
510
|
-
msgstr =
|
|
525
|
+
msgstr = merged.get(part, '')
|
|
511
526
|
if not msgstr:
|
|
512
527
|
msgstr = part
|
|
513
528
|
msgstr_parts.append(msgstr)
|
|
@@ -565,8 +580,9 @@ class AddTranslationClasses(SphinxTransform):
|
|
|
565
580
|
add_translated = False
|
|
566
581
|
add_untranslated = True
|
|
567
582
|
else:
|
|
568
|
-
|
|
569
|
-
|
|
583
|
+
msg = ('translation_progress_classes must be '
|
|
584
|
+
'True, False, "translated" or "untranslated"')
|
|
585
|
+
raise ConfigError(msg)
|
|
570
586
|
|
|
571
587
|
for node in self.document.findall(NodeMatcher(translated=Any)): # type: nodes.Element
|
|
572
588
|
if node['translated']:
|
|
@@ -3,15 +3,12 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import re
|
|
6
|
-
from typing import
|
|
6
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
7
7
|
|
|
8
8
|
from docutils import nodes
|
|
9
9
|
from docutils.nodes import Element, Node
|
|
10
10
|
|
|
11
11
|
from sphinx import addnodes
|
|
12
|
-
from sphinx.addnodes import pending_xref
|
|
13
|
-
from sphinx.application import Sphinx
|
|
14
|
-
from sphinx.domains import Domain
|
|
15
12
|
from sphinx.errors import NoUri
|
|
16
13
|
from sphinx.locale import __
|
|
17
14
|
from sphinx.transforms import SphinxTransform
|
|
@@ -19,6 +16,13 @@ from sphinx.util import logging
|
|
|
19
16
|
from sphinx.util.docutils import SphinxTranslator
|
|
20
17
|
from sphinx.util.nodes import find_pending_xref_condition, process_only_nodes
|
|
21
18
|
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from collections.abc import Sequence
|
|
21
|
+
|
|
22
|
+
from sphinx.addnodes import pending_xref
|
|
23
|
+
from sphinx.application import Sphinx
|
|
24
|
+
from sphinx.domains import Domain
|
|
25
|
+
|
|
22
26
|
logger = logging.getLogger(__name__)
|
|
23
27
|
|
|
24
28
|
|
|
@@ -246,18 +250,27 @@ class SigElementFallbackTransform(SphinxPostTransform):
|
|
|
246
250
|
# subclass of SphinxTranslator supports desc_sig_element nodes automatically.
|
|
247
251
|
return
|
|
248
252
|
|
|
249
|
-
# for the leaf elements (desc_sig_element), the translator should support _all_
|
|
250
|
-
|
|
253
|
+
# for the leaf elements (desc_sig_element), the translator should support _all_,
|
|
254
|
+
# unless there exists a generic visit_desc_sig_element default visitor
|
|
255
|
+
if (not all(has_visitor(translator, node) for node in addnodes.SIG_ELEMENTS)
|
|
256
|
+
and not has_visitor(translator, addnodes.desc_sig_element)):
|
|
251
257
|
self.fallback(addnodes.desc_sig_element)
|
|
252
258
|
|
|
253
259
|
if not has_visitor(translator, addnodes.desc_inline):
|
|
254
260
|
self.fallback(addnodes.desc_inline)
|
|
255
261
|
|
|
256
|
-
def fallback(self,
|
|
257
|
-
|
|
262
|
+
def fallback(self, node_type: Any) -> None:
|
|
263
|
+
"""Translate nodes of type *node_type* to docutils inline nodes.
|
|
264
|
+
|
|
265
|
+
The original node type name is stored as a string in a private
|
|
266
|
+
``_sig_node_type`` attribute if the latter did not exist.
|
|
267
|
+
"""
|
|
268
|
+
for node in self.document.findall(node_type):
|
|
258
269
|
newnode = nodes.inline()
|
|
259
270
|
newnode.update_all_atts(node)
|
|
260
271
|
newnode.extend(node)
|
|
272
|
+
# Only set _sig_node_type if not defined by the user
|
|
273
|
+
newnode.setdefault('_sig_node_type', node.tagname)
|
|
261
274
|
node.replace_self(newnode)
|
|
262
275
|
|
|
263
276
|
|
|
@@ -3,17 +3,20 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import sys
|
|
6
|
-
from typing import Any, NamedTuple
|
|
6
|
+
from typing import TYPE_CHECKING, Any, NamedTuple
|
|
7
7
|
|
|
8
8
|
from docutils import nodes
|
|
9
|
-
from docutils.nodes import Node, TextElement
|
|
10
9
|
from pygments.lexers import PythonConsoleLexer, guess_lexer
|
|
11
10
|
|
|
12
11
|
from sphinx import addnodes
|
|
13
|
-
from sphinx.application import Sphinx
|
|
14
12
|
from sphinx.ext import doctest
|
|
15
13
|
from sphinx.transforms import SphinxTransform
|
|
16
14
|
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from docutils.nodes import Node, TextElement
|
|
17
|
+
|
|
18
|
+
from sphinx.application import Sphinx
|
|
19
|
+
|
|
17
20
|
|
|
18
21
|
class HighlightSetting(NamedTuple):
|
|
19
22
|
language: str
|