summaryrefslogtreecommitdiffstats
path: root/src/librustdoc/html/static
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustdoc/html/static')
-rw-r--r--src/librustdoc/html/static/css/noscript.css213
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css512
-rw-r--r--src/librustdoc/html/static/css/settings.css63
-rw-r--r--src/librustdoc/html/static/css/themes/ayu.css180
-rw-r--r--src/librustdoc/html/static/css/themes/dark.css101
-rw-r--r--src/librustdoc/html/static/css/themes/light.css98
-rw-r--r--src/librustdoc/html/static/js/externs.js54
-rw-r--r--src/librustdoc/html/static/js/main.js49
-rw-r--r--src/librustdoc/html/static/js/search.js752
-rw-r--r--src/librustdoc/html/static/js/settings.js8
-rw-r--r--src/librustdoc/html/static/js/storage.js36
11 files changed, 1312 insertions, 754 deletions
diff --git a/src/librustdoc/html/static/css/noscript.css b/src/librustdoc/html/static/css/noscript.css
index 93aa11a58..fe0cf6dc8 100644
--- a/src/librustdoc/html/static/css/noscript.css
+++ b/src/librustdoc/html/static/css/noscript.css
@@ -28,3 +28,216 @@ nav.sub {
https://github.com/rust-lang/rust/issues/102576 */
display: none;
}
+
+/* Begin: styles for themes
+ Keep the default light and dark themes synchronized with the ones
+ in rustdoc.css */
+
+/* Begin theme: light */
+:root {
+ --main-background-color: white;
+ --main-color: black;
+ --settings-input-color: #2196f3;
+ --settings-input-border-color: #717171;
+ --settings-button-color: #000;
+ --settings-button-border-focus: #717171;
+ --sidebar-background-color: #f5f5f5;
+ --sidebar-background-color-hover: #e0e0e0;
+ --code-block-background-color: #f5f5f5;
+ --scrollbar-track-background-color: #dcdcdc;
+ --scrollbar-thumb-background-color: rgba(36, 37, 39, 0.6);
+ --scrollbar-color: rgba(36, 37, 39, 0.6) #d9d9d9;
+ --headings-border-bottom-color: #ddd;
+ --border-color: #e0e0e0;
+ --button-background-color: #fff;
+ --right-side-color: grey;
+ --code-attribute-color: #999;
+ --toggles-color: #999;
+ --toggle-filter: none;
+ --search-input-focused-border-color: #66afe9;
+ --copy-path-button-color: #999;
+ --copy-path-img-filter: invert(50%);
+ --copy-path-img-hover-filter: invert(35%);
+ --codeblock-error-hover-color: rgb(255, 0, 0);
+ --codeblock-error-color: rgba(255, 0, 0, .5);
+ --codeblock-ignore-hover-color: rgb(255, 142, 0);
+ --codeblock-ignore-color: rgba(255, 142, 0, .6);
+ --warning-border-color: #ff8e00;
+ --type-link-color: #ad378a;
+ --trait-link-color: #6e4fc9;
+ --assoc-item-link-color: #3873ad;
+ --function-link-color: #ad7c37;
+ --macro-link-color: #068000;
+ --keyword-link-color: #3873ad;
+ --mod-link-color: #3873ad;
+ --link-color: #3873ad;
+ --sidebar-link-color: #356da4;
+ --sidebar-current-link-background-color: #fff;
+ --search-result-link-focus-background-color: #ccc;
+ --search-result-border-color: #aaa3;
+ --search-color: #000;
+ --search-error-code-background-color: #d0cccc;
+ --search-results-alias-color: #000;
+ --search-results-grey-color: #999;
+ --search-tab-title-count-color: #888;
+ --search-tab-button-not-selected-border-top-color: #e6e6e6;
+ --search-tab-button-not-selected-background: #e6e6e6;
+ --search-tab-button-selected-border-top-color: #0089ff;
+ --search-tab-button-selected-background: #fff;
+ --stab-background-color: #fff5d6;
+ --stab-code-color: #000;
+ --code-highlight-kw-color: #8959a8;
+ --code-highlight-kw-2-color: #4271ae;
+ --code-highlight-lifetime-color: #b76514;
+ --code-highlight-prelude-color: #4271ae;
+ --code-highlight-prelude-val-color: #c82829;
+ --code-highlight-number-color: #718c00;
+ --code-highlight-string-color: #718c00;
+ --code-highlight-literal-color: #c82829;
+ --code-highlight-attribute-color: #c82829;
+ --code-highlight-self-color: #c82829;
+ --code-highlight-macro-color: #3e999f;
+ --code-highlight-question-mark-color: #ff9011;
+ --code-highlight-comment-color: #8e908c;
+ --code-highlight-doc-comment-color: #4d4d4c;
+ --src-line-numbers-span-color: #c67e2d;
+ --src-line-number-highlighted-background-color: #fdffd3;
+ --test-arrow-color: #f5f5f5;
+ --test-arrow-background-color: rgba(78, 139, 202, 0.2);
+ --test-arrow-hover-color: #f5f5f5;
+ --test-arrow-hover-background-color: rgb(78, 139, 202);
+ --target-background-color: #fdffd3;
+ --target-border-color: #ad7c37;
+ --kbd-color: #000;
+ --kbd-background: #fafbfc;
+ --kbd-box-shadow-color: #c6cbd1;
+ --rust-logo-filter: initial;
+ /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
+ --crate-search-div-filter: invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg)
+ brightness(114%) contrast(76%);
+ --crate-search-div-hover-filter: invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg)
+ brightness(96%) contrast(93%);
+ --crate-search-hover-border: #717171;
+ --src-sidebar-background-selected: #fff;
+ --src-sidebar-background-hover: #e0e0e0;
+ --table-alt-row-background-color: #f5f5f5;
+ --codeblock-link-background: #eee;
+ --scrape-example-toggle-line-background: #ccc;
+ --scrape-example-toggle-line-hover-background: #999;
+ --scrape-example-code-line-highlight: #fcffd6;
+ --scrape-example-code-line-highlight-focus: #f6fdb0;
+ --scrape-example-help-border-color: #555;
+ --scrape-example-help-color: #333;
+ --scrape-example-help-hover-border-color: #000;
+ --scrape-example-help-hover-color: #000;
+ --scrape-example-code-wrapper-background-start: rgba(255, 255, 255, 1);
+ --scrape-example-code-wrapper-background-end: rgba(255, 255, 255, 0);
+}
+/* End theme: light */
+
+@media (prefers-color-scheme: dark) {
+ /* Begin theme: dark */
+ :root {
+ --main-background-color: #353535;
+ --main-color: #ddd;
+ --settings-input-color: #2196f3;
+ --settings-input-border-color: #999;
+ --settings-button-color: #000;
+ --settings-button-border-focus: #ffb900;
+ --sidebar-background-color: #505050;
+ --sidebar-background-color-hover: #676767;
+ --code-block-background-color: #2A2A2A;
+ --scrollbar-track-background-color: #717171;
+ --scrollbar-thumb-background-color: rgba(32, 34, 37, .6);
+ --scrollbar-color: rgba(32,34,37,.6) #5a5a5a;
+ --headings-border-bottom-color: #d2d2d2;
+ --border-color: #e0e0e0;
+ --button-background-color: #f0f0f0;
+ --right-side-color: grey;
+ --code-attribute-color: #999;
+ --toggles-color: #999;
+ --toggle-filter: invert(100%);
+ --search-input-focused-border-color: #008dfd;
+ --copy-path-button-color: #999;
+ --copy-path-img-filter: invert(50%);
+ --copy-path-img-hover-filter: invert(65%);
+ --codeblock-error-hover-color: rgb(255, 0, 0);
+ --codeblock-error-color: rgba(255, 0, 0, .5);
+ --codeblock-ignore-hover-color: rgb(255, 142, 0);
+ --codeblock-ignore-color: rgba(255, 142, 0, .6);
+ --warning-border-color: #ff8e00;
+ --type-link-color: #2dbfb8;
+ --trait-link-color: #b78cf2;
+ --assoc-item-link-color: #d2991d;
+ --function-link-color: #2bab63;
+ --macro-link-color: #09bd00;
+ --keyword-link-color: #d2991d;
+ --mod-link-color: #d2991d;
+ --link-color: #d2991d;
+ --sidebar-link-color: #fdbf35;
+ --sidebar-current-link-background-color: #444;
+ --search-result-link-focus-background-color: #616161;
+ --search-result-border-color: #aaa3;
+ --search-color: #111;
+ --search-error-code-background-color: #484848;
+ --search-results-alias-color: #fff;
+ --search-results-grey-color: #ccc;
+ --search-tab-title-count-color: #888;
+ --search-tab-button-not-selected-border-top-color: #252525;
+ --search-tab-button-not-selected-background: #252525;
+ --search-tab-button-selected-border-top-color: #0089ff;
+ --search-tab-button-selected-background: #353535;
+ --stab-background-color: #314559;
+ --stab-code-color: #e6e1cf;
+ --code-highlight-kw-color: #ab8ac1;
+ --code-highlight-kw-2-color: #769acb;
+ --code-highlight-lifetime-color: #d97f26;
+ --code-highlight-prelude-color: #769acb;
+ --code-highlight-prelude-val-color: #ee6868;
+ --code-highlight-number-color: #83a300;
+ --code-highlight-string-color: #83a300;
+ --code-highlight-literal-color: #ee6868;
+ --code-highlight-attribute-color: #ee6868;
+ --code-highlight-self-color: #ee6868;
+ --code-highlight-macro-color: #3e999f;
+ --code-highlight-question-mark-color: #ff9011;
+ --code-highlight-comment-color: #8d8d8b;
+ --code-highlight-doc-comment-color: #8ca375;
+ --src-line-numbers-span-color: #3b91e2;
+ --src-line-number-highlighted-background-color: #0a042f;
+ --test-arrow-color: #dedede;
+ --test-arrow-background-color: rgba(78, 139, 202, 0.2);
+ --test-arrow-hover-color: #dedede;
+ --test-arrow-hover-background-color: #4e8bca;
+ --target-background-color: #494a3d;
+ --target-border-color: #bb7410;
+ --kbd-color: #000;
+ --kbd-background: #fafbfc;
+ --kbd-box-shadow-color: #c6cbd1;
+ --rust-logo-filter: drop-shadow(1px 0 0px #fff)
+ drop-shadow(0 1px 0 #fff)
+ drop-shadow(-1px 0 0 #fff)
+ drop-shadow(0 -1px 0 #fff);
+ /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
+ --crate-search-div-filter: invert(94%) sepia(0%) saturate(721%) hue-rotate(255deg)
+ brightness(90%) contrast(90%);
+ --crate-search-div-hover-filter: invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg)
+ brightness(100%) contrast(91%);
+ --crate-search-hover-border: #2196f3;
+ --src-sidebar-background-selected: #333;
+ --src-sidebar-background-hover: #444;
+ --table-alt-row-background-color: #2a2a2a;
+ --codeblock-link-background: #333;
+ --scrape-example-toggle-line-background: #999;
+ --scrape-example-toggle-line-hover-background: #c5c5c5;
+ --scrape-example-code-line-highlight: #5b3b01;
+ --scrape-example-code-line-highlight-focus: #7c4b0f;
+ --scrape-example-help-border-color: #aaa;
+ --scrape-example-help-color: #eee;
+ --scrape-example-help-hover-border-color: #fff;
+ --scrape-example-help-hover-color: #fff;
+ --scrape-example-code-wrapper-background-start: rgba(53, 53, 53, 1);
+ --scrape-example-code-wrapper-background-end: rgba(53, 53, 53, 0);
+ }
+/* End theme: dark */
+}
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index b1de8c152..47f9e6502 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -270,7 +270,7 @@ ul ul, ol ul, ul ol, ol ol {
margin-bottom: .625em;
}
-p {
+p, .docblock > .warning {
/* Paragraph spacing at least 1.5 times line spacing per Web Content Accessibility Guidelines.
Line-height is 1.5rem, so line spacing is .5rem; .75em is 1.5 times that.
https://www.w3.org/WAI/WCAG21/Understanding/visual-presentation.html */
@@ -278,7 +278,7 @@ p {
}
/* For the last child of a div, the margin will be taken care of
by the margin-top of the next item. */
-p:last-child {
+p:last-child, .docblock > .warning:last-child {
margin: 0;
}
@@ -925,6 +925,70 @@ so that we can apply CSS-filters to change the arrow color in themes */
top: -5px;
}
+.setting-line {
+ margin: 1.2em 0.6em;
+}
+
+.setting-radio input, .setting-check input {
+ margin-right: 0.3em;
+ height: 1.2rem;
+ width: 1.2rem;
+ border: 2px solid var(--settings-input-border-color);
+ outline: none;
+ -webkit-appearance: none;
+ cursor: pointer;
+}
+.setting-radio input {
+ border-radius: 50%;
+}
+
+.setting-radio span, .setting-check span {
+ padding-bottom: 1px;
+}
+
+.setting-radio {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+ min-width: 3.8em;
+ padding: 0.3em;
+ display: inline-flex;
+ align-items: center;
+ cursor: pointer;
+}
+.setting-radio + .setting-radio {
+ margin-left: 0.5em;
+}
+
+.setting-check {
+ margin-right: 20px;
+ display: flex;
+ align-items: center;
+ cursor: pointer;
+}
+
+.setting-radio input:checked {
+ box-shadow: inset 0 0 0 3px var(--main-background-color);
+ background-color: var(--settings-input-color);
+}
+.setting-check input:checked {
+ background-color: var(--settings-input-color);
+ border-width: 1px;
+ content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40">\
+ <path d="M7,25L17,32L33,12" fill="none" stroke="black" stroke-width="5"/>\
+ <path d="M7,23L17,30L33,10" fill="none" stroke="white" stroke-width="5"/></svg>');
+}
+.setting-radio input:focus, .setting-check input:focus {
+ box-shadow: 0 0 1px 1px var(--settings-input-color);
+}
+/* In here we combine both `:focus` and `:checked` properties. */
+.setting-radio input:checked:focus {
+ box-shadow: inset 0 0 0 3px var(--main-background-color),
+ 0 0 2px 2px var(--settings-input-color);
+}
+.setting-radio input:hover, .setting-check input:hover {
+ border-color: var(--settings-input-color) !important;
+}
+
/* use larger max-width for help popover, but not for help.html */
#help.popover {
max-width: 600px;
@@ -1096,7 +1160,7 @@ pre.rust .doccomment {
}
.example-wrap.ignore .tooltip {
- color: var(--codeblock-ignore-color);
+ color: var(--codeblock-ignore-color);
}
.example-wrap.compile_fail:hover .tooltip,
@@ -1124,6 +1188,26 @@ pre.rust .doccomment {
font-size: 1.25rem;
}
+/* This class only exists for users who want to draw attention to a particular element in their
+documentation. */
+.content .docblock .warning {
+ border-left: 2px solid var(--warning-border-color);
+ padding: 14px;
+ position: relative;
+ /* The "!important" part is required because the rule is otherwise overruled in this CSS
+ selector: ".docblock > :not(.more-examples-toggle):not(.example-wrap)" */
+ overflow-x: visible !important;
+}
+.content .docblock .warning::before {
+ color: var(--warning-border-color);
+ content: "ⓘ";
+ position: absolute;
+ left: -25px;
+ top: 5px;
+ font-weight: bold;
+ font-size: 1.25rem;
+}
+
a.test-arrow {
visibility: hidden;
position: absolute;
@@ -1271,6 +1355,7 @@ a.tooltip:hover::after {
#search-tabs .count {
font-size: 1rem;
+ font-variant-numeric: tabular-nums;
color: var(--search-tab-title-count-color);
}
@@ -1553,6 +1638,13 @@ However, it's not needed with smaller screen width because the doc/code block is
/* Media Queries */
+/* Make sure all the buttons line wrap at the same time */
+@media (max-width: 850px) {
+ #search-tabs .count {
+ display: block;
+ }
+}
+
/*
WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY
If you update this line, then you also need to update the line with the same warning
@@ -1680,10 +1772,6 @@ in src-script.js
display: none !important;
}
- #search-tabs .count {
- display: block;
- }
-
#main-content > details.toggle > summary::before,
#main-content > div > details.toggle > summary::before {
left: -11px;
@@ -2014,3 +2102,413 @@ in src-script.js
}
/* End: styles for --scrape-examples feature */
+
+/* Begin: styles for themes
+
+ Keep the default light and dark themes synchronized with the ones
+ in noscript.css
+
+ The special "Begin theme" and "End theme" below are used by a lot of
+ tooling to ensure different themes all define all the variables. Do not
+ alter their formatting. */
+
+/* Begin theme: light */
+:root[data-theme="light"] {
+ --main-background-color: white;
+ --main-color: black;
+ --settings-input-color: #2196f3;
+ --settings-input-border-color: #717171;
+ --settings-button-color: #000;
+ --settings-button-border-focus: #717171;
+ --sidebar-background-color: #f5f5f5;
+ --sidebar-background-color-hover: #e0e0e0;
+ --code-block-background-color: #f5f5f5;
+ --scrollbar-track-background-color: #dcdcdc;
+ --scrollbar-thumb-background-color: rgba(36, 37, 39, 0.6);
+ --scrollbar-color: rgba(36, 37, 39, 0.6) #d9d9d9;
+ --headings-border-bottom-color: #ddd;
+ --border-color: #e0e0e0;
+ --button-background-color: #fff;
+ --right-side-color: grey;
+ --code-attribute-color: #999;
+ --toggles-color: #999;
+ --toggle-filter: none;
+ --search-input-focused-border-color: #66afe9;
+ --copy-path-button-color: #999;
+ --copy-path-img-filter: invert(50%);
+ --copy-path-img-hover-filter: invert(35%);
+ --codeblock-error-hover-color: rgb(255, 0, 0);
+ --codeblock-error-color: rgba(255, 0, 0, .5);
+ --codeblock-ignore-hover-color: rgb(255, 142, 0);
+ --codeblock-ignore-color: rgba(255, 142, 0, .6);
+ --warning-border-color: #ff8e00;
+ --type-link-color: #ad378a;
+ --trait-link-color: #6e4fc9;
+ --assoc-item-link-color: #3873ad;
+ --function-link-color: #ad7c37;
+ --macro-link-color: #068000;
+ --keyword-link-color: #3873ad;
+ --mod-link-color: #3873ad;
+ --link-color: #3873ad;
+ --sidebar-link-color: #356da4;
+ --sidebar-current-link-background-color: #fff;
+ --search-result-link-focus-background-color: #ccc;
+ --search-result-border-color: #aaa3;
+ --search-color: #000;
+ --search-error-code-background-color: #d0cccc;
+ --search-results-alias-color: #000;
+ --search-results-grey-color: #999;
+ --search-tab-title-count-color: #888;
+ --search-tab-button-not-selected-border-top-color: #e6e6e6;
+ --search-tab-button-not-selected-background: #e6e6e6;
+ --search-tab-button-selected-border-top-color: #0089ff;
+ --search-tab-button-selected-background: #fff;
+ --stab-background-color: #fff5d6;
+ --stab-code-color: #000;
+ --code-highlight-kw-color: #8959a8;
+ --code-highlight-kw-2-color: #4271ae;
+ --code-highlight-lifetime-color: #b76514;
+ --code-highlight-prelude-color: #4271ae;
+ --code-highlight-prelude-val-color: #c82829;
+ --code-highlight-number-color: #718c00;
+ --code-highlight-string-color: #718c00;
+ --code-highlight-literal-color: #c82829;
+ --code-highlight-attribute-color: #c82829;
+ --code-highlight-self-color: #c82829;
+ --code-highlight-macro-color: #3e999f;
+ --code-highlight-question-mark-color: #ff9011;
+ --code-highlight-comment-color: #8e908c;
+ --code-highlight-doc-comment-color: #4d4d4c;
+ --src-line-numbers-span-color: #c67e2d;
+ --src-line-number-highlighted-background-color: #fdffd3;
+ --test-arrow-color: #f5f5f5;
+ --test-arrow-background-color: rgba(78, 139, 202, 0.2);
+ --test-arrow-hover-color: #f5f5f5;
+ --test-arrow-hover-background-color: rgb(78, 139, 202);
+ --target-background-color: #fdffd3;
+ --target-border-color: #ad7c37;
+ --kbd-color: #000;
+ --kbd-background: #fafbfc;
+ --kbd-box-shadow-color: #c6cbd1;
+ --rust-logo-filter: initial;
+ /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
+ --crate-search-div-filter: invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg)
+ brightness(114%) contrast(76%);
+ --crate-search-div-hover-filter: invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg)
+ brightness(96%) contrast(93%);
+ --crate-search-hover-border: #717171;
+ --src-sidebar-background-selected: #fff;
+ --src-sidebar-background-hover: #e0e0e0;
+ --table-alt-row-background-color: #f5f5f5;
+ --codeblock-link-background: #eee;
+ --scrape-example-toggle-line-background: #ccc;
+ --scrape-example-toggle-line-hover-background: #999;
+ --scrape-example-code-line-highlight: #fcffd6;
+ --scrape-example-code-line-highlight-focus: #f6fdb0;
+ --scrape-example-help-border-color: #555;
+ --scrape-example-help-color: #333;
+ --scrape-example-help-hover-border-color: #000;
+ --scrape-example-help-hover-color: #000;
+ --scrape-example-code-wrapper-background-start: rgba(255, 255, 255, 1);
+ --scrape-example-code-wrapper-background-end: rgba(255, 255, 255, 0);
+}
+/* End theme: light */
+
+/* Begin theme: dark */
+:root[data-theme="dark"] {
+ --main-background-color: #353535;
+ --main-color: #ddd;
+ --settings-input-color: #2196f3;
+ --settings-input-border-color: #999;
+ --settings-button-color: #000;
+ --settings-button-border-focus: #ffb900;
+ --sidebar-background-color: #505050;
+ --sidebar-background-color-hover: #676767;
+ --code-block-background-color: #2A2A2A;
+ --scrollbar-track-background-color: #717171;
+ --scrollbar-thumb-background-color: rgba(32, 34, 37, .6);
+ --scrollbar-color: rgba(32,34,37,.6) #5a5a5a;
+ --headings-border-bottom-color: #d2d2d2;
+ --border-color: #e0e0e0;
+ --button-background-color: #f0f0f0;
+ --right-side-color: grey;
+ --code-attribute-color: #999;
+ --toggles-color: #999;
+ --toggle-filter: invert(100%);
+ --search-input-focused-border-color: #008dfd;
+ --copy-path-button-color: #999;
+ --copy-path-img-filter: invert(50%);
+ --copy-path-img-hover-filter: invert(65%);
+ --codeblock-error-hover-color: rgb(255, 0, 0);
+ --codeblock-error-color: rgba(255, 0, 0, .5);
+ --codeblock-ignore-hover-color: rgb(255, 142, 0);
+ --codeblock-ignore-color: rgba(255, 142, 0, .6);
+ --warning-border-color: #ff8e00;
+ --type-link-color: #2dbfb8;
+ --trait-link-color: #b78cf2;
+ --assoc-item-link-color: #d2991d;
+ --function-link-color: #2bab63;
+ --macro-link-color: #09bd00;
+ --keyword-link-color: #d2991d;
+ --mod-link-color: #d2991d;
+ --link-color: #d2991d;
+ --sidebar-link-color: #fdbf35;
+ --sidebar-current-link-background-color: #444;
+ --search-result-link-focus-background-color: #616161;
+ --search-result-border-color: #aaa3;
+ --search-color: #111;
+ --search-error-code-background-color: #484848;
+ --search-results-alias-color: #fff;
+ --search-results-grey-color: #ccc;
+ --search-tab-title-count-color: #888;
+ --search-tab-button-not-selected-border-top-color: #252525;
+ --search-tab-button-not-selected-background: #252525;
+ --search-tab-button-selected-border-top-color: #0089ff;
+ --search-tab-button-selected-background: #353535;
+ --stab-background-color: #314559;
+ --stab-code-color: #e6e1cf;
+ --code-highlight-kw-color: #ab8ac1;
+ --code-highlight-kw-2-color: #769acb;
+ --code-highlight-lifetime-color: #d97f26;
+ --code-highlight-prelude-color: #769acb;
+ --code-highlight-prelude-val-color: #ee6868;
+ --code-highlight-number-color: #83a300;
+ --code-highlight-string-color: #83a300;
+ --code-highlight-literal-color: #ee6868;
+ --code-highlight-attribute-color: #ee6868;
+ --code-highlight-self-color: #ee6868;
+ --code-highlight-macro-color: #3e999f;
+ --code-highlight-question-mark-color: #ff9011;
+ --code-highlight-comment-color: #8d8d8b;
+ --code-highlight-doc-comment-color: #8ca375;
+ --src-line-numbers-span-color: #3b91e2;
+ --src-line-number-highlighted-background-color: #0a042f;
+ --test-arrow-color: #dedede;
+ --test-arrow-background-color: rgba(78, 139, 202, 0.2);
+ --test-arrow-hover-color: #dedede;
+ --test-arrow-hover-background-color: #4e8bca;
+ --target-background-color: #494a3d;
+ --target-border-color: #bb7410;
+ --kbd-color: #000;
+ --kbd-background: #fafbfc;
+ --kbd-box-shadow-color: #c6cbd1;
+ --rust-logo-filter: drop-shadow(1px 0 0px #fff)
+ drop-shadow(0 1px 0 #fff)
+ drop-shadow(-1px 0 0 #fff)
+ drop-shadow(0 -1px 0 #fff);
+ /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
+ --crate-search-div-filter: invert(94%) sepia(0%) saturate(721%) hue-rotate(255deg)
+ brightness(90%) contrast(90%);
+ --crate-search-div-hover-filter: invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg)
+ brightness(100%) contrast(91%);
+ --crate-search-hover-border: #2196f3;
+ --src-sidebar-background-selected: #333;
+ --src-sidebar-background-hover: #444;
+ --table-alt-row-background-color: #2a2a2a;
+ --codeblock-link-background: #333;
+ --scrape-example-toggle-line-background: #999;
+ --scrape-example-toggle-line-hover-background: #c5c5c5;
+ --scrape-example-code-line-highlight: #5b3b01;
+ --scrape-example-code-line-highlight-focus: #7c4b0f;
+ --scrape-example-help-border-color: #aaa;
+ --scrape-example-help-color: #eee;
+ --scrape-example-help-hover-border-color: #fff;
+ --scrape-example-help-hover-color: #fff;
+ --scrape-example-code-wrapper-background-start: rgba(53, 53, 53, 1);
+ --scrape-example-code-wrapper-background-end: rgba(53, 53, 53, 0);
+}
+/* End theme: dark */
+
+/* Begin theme: ayu */
+/*
+Based off of the Ayu theme
+Original by Dempfi (https://github.com/dempfi/ayu)
+*/
+:root[data-theme="ayu"] {
+ --main-background-color: #0f1419;
+ --main-color: #c5c5c5;
+ --settings-input-color: #ffb454;
+ --settings-input-border-color: #999;
+ --settings-button-color: #fff;
+ --settings-button-border-focus: #e0e0e0;
+ --sidebar-background-color: #14191f;
+ --sidebar-background-color-hover: rgba(70, 70, 70, 0.33);
+ --code-block-background-color: #191f26;
+ --scrollbar-track-background-color: transparent;
+ --scrollbar-thumb-background-color: #5c6773;
+ --scrollbar-color: #5c6773 #24292f;
+ --headings-border-bottom-color: #5c6773;
+ --border-color: #5c6773;
+ --button-background-color: #141920;
+ --right-side-color: grey;
+ --code-attribute-color: #999;
+ --toggles-color: #999;
+ --toggle-filter: invert(100%);
+ --search-input-focused-border-color: #5c6773; /* Same as `--border-color`. */
+ --copy-path-button-color: #fff;
+ --copy-path-img-filter: invert(70%);
+ --copy-path-img-hover-filter: invert(100%);
+ --codeblock-error-hover-color: rgb(255, 0, 0);
+ --codeblock-error-color: rgba(255, 0, 0, .5);
+ --codeblock-ignore-hover-color: rgb(255, 142, 0);
+ --codeblock-ignore-color: rgba(255, 142, 0, .6);
+ --warning-border-color: #ff8e00;
+ --type-link-color: #ffa0a5;
+ --trait-link-color: #39afd7;
+ --assoc-item-link-color: #39afd7;
+ --function-link-color: #fdd687;
+ --macro-link-color: #a37acc;
+ --keyword-link-color: #39afd7;
+ --mod-link-color: #39afd7;
+ --link-color: #39afd7;
+ --sidebar-link-color: #53b1db;
+ --sidebar-current-link-background-color: transparent;
+ --search-result-link-focus-background-color: #3c3c3c;
+ --search-result-border-color: #aaa3;
+ --search-color: #fff;
+ --search-error-code-background-color: #4f4c4c;
+ --search-results-alias-color: #c5c5c5;
+ --search-results-grey-color: #999;
+ --search-tab-title-count-color: #888;
+ --search-tab-button-not-selected-border-top-color: none;
+ --search-tab-button-not-selected-background: transparent !important;
+ --search-tab-button-selected-border-top-color: none;
+ --search-tab-button-selected-background: #141920 !important;
+ --stab-background-color: #314559;
+ --stab-code-color: #e6e1cf;
+ --code-highlight-kw-color: #ff7733;
+ --code-highlight-kw-2-color: #ff7733;
+ --code-highlight-lifetime-color: #ff7733;
+ --code-highlight-prelude-color: #69f2df;
+ --code-highlight-prelude-val-color: #ff7733;
+ --code-highlight-number-color: #b8cc52;
+ --code-highlight-string-color: #b8cc52;
+ --code-highlight-literal-color: #ff7733;
+ --code-highlight-attribute-color: #e6e1cf;
+ --code-highlight-self-color: #36a3d9;
+ --code-highlight-macro-color: #a37acc;
+ --code-highlight-question-mark-color: #ff9011;
+ --code-highlight-comment-color: #788797;
+ --code-highlight-doc-comment-color: #a1ac88;
+ --src-line-numbers-span-color: #5c6773;
+ --src-line-number-highlighted-background-color: rgba(255, 236, 164, 0.06);
+ --test-arrow-color: #788797;
+ --test-arrow-background-color: rgba(57, 175, 215, 0.09);
+ --test-arrow-hover-color: #c5c5c5;
+ --test-arrow-hover-background-color: rgba(57, 175, 215, 0.368);
+ --target-background-color: rgba(255, 236, 164, 0.06);
+ --target-border-color: rgba(255, 180, 76, 0.85);
+ --kbd-color: #c5c5c5;
+ --kbd-background: #314559;
+ --kbd-box-shadow-color: #5c6773;
+ --rust-logo-filter: drop-shadow(1px 0 0px #fff)
+ drop-shadow(0 1px 0 #fff)
+ drop-shadow(-1px 0 0 #fff)
+ drop-shadow(0 -1px 0 #fff);
+ /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
+ --crate-search-div-filter: invert(41%) sepia(12%) saturate(487%) hue-rotate(171deg)
+ brightness(94%) contrast(94%);
+ --crate-search-div-hover-filter: invert(98%) sepia(12%) saturate(81%) hue-rotate(343deg)
+ brightness(113%) contrast(76%);
+ --crate-search-hover-border: #e0e0e0;
+ --src-sidebar-background-selected: #14191f;
+ --src-sidebar-background-hover: #14191f;
+ --table-alt-row-background-color: #191f26;
+ --codeblock-link-background: #333;
+ --scrape-example-toggle-line-background: #999;
+ --scrape-example-toggle-line-hover-background: #c5c5c5;
+ --scrape-example-code-line-highlight: #5b3b01;
+ --scrape-example-code-line-highlight-focus: #7c4b0f;
+ --scrape-example-help-border-color: #aaa;
+ --scrape-example-help-color: #eee;
+ --scrape-example-help-hover-border-color: #fff;
+ --scrape-example-help-hover-color: #fff;
+ --scrape-example-code-wrapper-background-start: rgba(15, 20, 25, 1);
+ --scrape-example-code-wrapper-background-end: rgba(15, 20, 25, 0);
+}
+
+:root[data-theme="ayu"] h1,
+:root[data-theme="ayu"] h2,
+:root[data-theme="ayu"] h3,
+:root[data-theme="ayu"] h4,
+:where(:root[data-theme="ayu"]) h1 a,
+:root[data-theme="ayu"] .sidebar h2 a,
+:root[data-theme="ayu"] .sidebar h3 a,
+:root[data-theme="ayu"] #source-sidebar > .title {
+ color: #fff;
+}
+
+:root[data-theme="ayu"] .docblock code {
+ color: #ffb454;
+}
+
+:root[data-theme="ayu"] .docblock a > code {
+ color: #39AFD7 !important;
+}
+
+:root[data-theme="ayu"] .code-header,
+:root[data-theme="ayu"] .docblock pre > code,
+:root[data-theme="ayu"] pre,
+:root[data-theme="ayu"] pre > code,
+:root[data-theme="ayu"] .item-info code,
+:root[data-theme="ayu"] .rustdoc.source .example-wrap {
+ color: #e6e1cf;
+}
+
+:root[data-theme="ayu"] .sidebar .current,
+:root[data-theme="ayu"] .sidebar a:hover,
+:root[data-theme="ayu"] #src-sidebar div.files > a:hover,
+:root[data-theme="ayu"] details.dir-entry summary:hover,
+:root[data-theme="ayu"] #src-sidebar div.files > a:focus,
+:root[data-theme="ayu"] details.dir-entry summary:focus,
+:root[data-theme="ayu"] #src-sidebar div.files > a.selected {
+ color: #ffb44c;
+}
+
+:root[data-theme="ayu"] .sidebar-elems .location {
+ color: #ff7733;
+}
+
+:root[data-theme="ayu"] .src-line-numbers .line-highlighted {
+ color: #708090;
+ padding-right: 7px;
+ border-right: 1px solid #ffb44c;
+}
+
+:root[data-theme="ayu"] .search-results a:hover,
+:root[data-theme="ayu"] .search-results a:focus {
+ color: #fff !important;
+ background-color: #3c3c3c;
+}
+
+:root[data-theme="ayu"] .search-results a {
+ color: #0096cf;
+}
+
+:root[data-theme="ayu"] .search-results a div.desc {
+ color: #c5c5c5;
+}
+
+:root[data-theme="ayu"] .result-name .primitive > i,
+:root[data-theme="ayu"] .result-name .keyword > i {
+ color: #788797;
+}
+
+:root[data-theme="ayu"] #search-tabs > button.selected {
+ border-bottom: 1px solid #ffb44c !important;
+ border-top: none;
+}
+:root[data-theme="ayu"] #search-tabs > button:not(.selected) {
+ border: none;
+ background-color: transparent !important;
+}
+:root[data-theme="ayu"] #search-tabs > button:hover {
+ border-bottom: 1px solid rgba(242, 151, 24, 0.3);
+}
+
+:root[data-theme="ayu"] #settings-menu > a img {
+ filter: invert(100);
+}
+/* End theme: ayu */
+
+/* End: styles for themes */
diff --git a/src/librustdoc/html/static/css/settings.css b/src/librustdoc/html/static/css/settings.css
deleted file mode 100644
index c1324c076..000000000
--- a/src/librustdoc/html/static/css/settings.css
+++ /dev/null
@@ -1,63 +0,0 @@
-.setting-line {
- margin: 1.2em 0.6em;
-}
-
-.setting-radio input, .setting-check input {
- margin-right: 0.3em;
- height: 1.2rem;
- width: 1.2rem;
- border: 2px solid var(--settings-input-border-color);
- outline: none;
- -webkit-appearance: none;
- cursor: pointer;
-}
-.setting-radio input {
- border-radius: 50%;
-}
-
-.setting-radio span, .setting-check span {
- padding-bottom: 1px;
-}
-
-.setting-radio {
- margin-top: 0.1em;
- margin-bottom: 0.1em;
- min-width: 3.8em;
- padding: 0.3em;
- display: inline-flex;
- align-items: center;
- cursor: pointer;
-}
-.setting-radio + .setting-radio {
- margin-left: 0.5em;
-}
-
-.setting-check {
- margin-right: 20px;
- display: flex;
- align-items: center;
- cursor: pointer;
-}
-
-.setting-radio input:checked {
- box-shadow: inset 0 0 0 3px var(--main-background-color);
- background-color: var(--settings-input-color);
-}
-.setting-check input:checked {
- background-color: var(--settings-input-color);
- border-width: 1px;
- content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40">\
- <path d="M7,25L17,32L33,12" fill="none" stroke="black" stroke-width="5"/>\
- <path d="M7,23L17,30L33,10" fill="none" stroke="white" stroke-width="5"/></svg>');
-}
-.setting-radio input:focus, .setting-check input:focus {
- box-shadow: 0 0 1px 1px var(--settings-input-color);
-}
-/* In here we combine both `:focus` and `:checked` properties. */
-.setting-radio input:checked:focus {
- box-shadow: inset 0 0 0 3px var(--main-background-color),
- 0 0 2px 2px var(--settings-input-color);
-}
-.setting-radio input:hover, .setting-check input:hover {
- border-color: var(--settings-input-color) !important;
-}
diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css
deleted file mode 100644
index d8dae51eb..000000000
--- a/src/librustdoc/html/static/css/themes/ayu.css
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
-Based off of the Ayu theme
-Original by Dempfi (https://github.com/dempfi/ayu)
-*/
-
-:root {
- --main-background-color: #0f1419;
- --main-color: #c5c5c5;
- --settings-input-color: #ffb454;
- --settings-input-border-color: #999;
- --settings-button-color: #fff;
- --settings-button-border-focus: #e0e0e0;
- --sidebar-background-color: #14191f;
- --sidebar-background-color-hover: rgba(70, 70, 70, 0.33);
- --code-block-background-color: #191f26;
- --scrollbar-track-background-color: transparent;
- --scrollbar-thumb-background-color: #5c6773;
- --scrollbar-color: #5c6773 #24292f;
- --headings-border-bottom-color: #5c6773;
- --border-color: #5c6773;
- --button-background-color: #141920;
- --right-side-color: grey;
- --code-attribute-color: #999;
- --toggles-color: #999;
- --toggle-filter: invert(100%);
- --search-input-focused-border-color: #5c6773; /* Same as `--border-color`. */
- --copy-path-button-color: #fff;
- --copy-path-img-filter: invert(70%);
- --copy-path-img-hover-filter: invert(100%);
- --codeblock-error-hover-color: rgb(255, 0, 0);
- --codeblock-error-color: rgba(255, 0, 0, .5);
- --codeblock-ignore-hover-color: rgb(255, 142, 0);
- --codeblock-ignore-color: rgba(255, 142, 0, .6);
- --type-link-color: #ffa0a5;
- --trait-link-color: #39afd7;
- --assoc-item-link-color: #39afd7;
- --function-link-color: #fdd687;
- --macro-link-color: #a37acc;
- --keyword-link-color: #39afd7;
- --mod-link-color: #39afd7;
- --link-color: #39afd7;
- --sidebar-link-color: #53b1db;
- --sidebar-current-link-background-color: transparent;
- --search-result-link-focus-background-color: #3c3c3c;
- --search-result-border-color: #aaa3;
- --search-color: #fff;
- --search-error-code-background-color: #4f4c4c;
- --search-results-alias-color: #c5c5c5;
- --search-results-grey-color: #999;
- --search-tab-title-count-color: #888;
- --search-tab-button-not-selected-border-top-color: none;
- --search-tab-button-not-selected-background: transparent !important;
- --search-tab-button-selected-border-top-color: none;
- --search-tab-button-selected-background: #141920 !important;
- --stab-background-color: #314559;
- --stab-code-color: #e6e1cf;
- --code-highlight-kw-color: #ff7733;
- --code-highlight-kw-2-color: #ff7733;
- --code-highlight-lifetime-color: #ff7733;
- --code-highlight-prelude-color: #69f2df;
- --code-highlight-prelude-val-color: #ff7733;
- --code-highlight-number-color: #b8cc52;
- --code-highlight-string-color: #b8cc52;
- --code-highlight-literal-color: #ff7733;
- --code-highlight-attribute-color: #e6e1cf;
- --code-highlight-self-color: #36a3d9;
- --code-highlight-macro-color: #a37acc;
- --code-highlight-question-mark-color: #ff9011;
- --code-highlight-comment-color: #788797;
- --code-highlight-doc-comment-color: #a1ac88;
- --src-line-numbers-span-color: #5c6773;
- --src-line-number-highlighted-background-color: rgba(255, 236, 164, 0.06);
- --test-arrow-color: #788797;
- --test-arrow-background-color: rgba(57, 175, 215, 0.09);
- --test-arrow-hover-color: #c5c5c5;
- --test-arrow-hover-background-color: rgba(57, 175, 215, 0.368);
- --target-background-color: rgba(255, 236, 164, 0.06);
- --target-border-color: rgba(255, 180, 76, 0.85);
- --kbd-color: #c5c5c5;
- --kbd-background: #314559;
- --kbd-box-shadow-color: #5c6773;
- --rust-logo-filter: drop-shadow(1px 0 0px #fff)
- drop-shadow(0 1px 0 #fff)
- drop-shadow(-1px 0 0 #fff)
- drop-shadow(0 -1px 0 #fff);
- /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
- --crate-search-div-filter: invert(41%) sepia(12%) saturate(487%) hue-rotate(171deg)
- brightness(94%) contrast(94%);
- --crate-search-div-hover-filter: invert(98%) sepia(12%) saturate(81%) hue-rotate(343deg)
- brightness(113%) contrast(76%);
- --crate-search-hover-border: #e0e0e0;
- --src-sidebar-background-selected: #14191f;
- --src-sidebar-background-hover: #14191f;
- --table-alt-row-background-color: #191f26;
- --codeblock-link-background: #333;
- --scrape-example-toggle-line-background: #999;
- --scrape-example-toggle-line-hover-background: #c5c5c5;
- --scrape-example-code-line-highlight: rgb(91, 59, 1);
- --scrape-example-code-line-highlight-focus: rgb(124, 75, 15);
- --scrape-example-help-border-color: #aaa;
- --scrape-example-help-color: #eee;
- --scrape-example-help-hover-border-color: #fff;
- --scrape-example-help-hover-color: #fff;
- --scrape-example-code-wrapper-background-start: rgba(15, 20, 25, 1);
- --scrape-example-code-wrapper-background-end: rgba(15, 20, 25, 0);
-}
-
-h1, h2, h3, h4,
-h1 a, .sidebar h2 a, .sidebar h3 a,
-#src-sidebar > .title {
- color: #fff;
-}
-h4 {
- border: none;
-}
-
-.docblock code {
- color: #ffb454;
-}
-.docblock a > code {
- color: #39AFD7 !important;
-}
-.code-header,
-.docblock pre > code,
-pre, pre > code,
-.item-info code,
-.rustdoc.src .example-wrap {
- color: #e6e1cf;
-}
-
-.sidebar .current,
-.sidebar a:hover,
-#src-sidebar div.files > a:hover, details.dir-entry summary:hover,
-#src-sidebar div.files > a:focus, details.dir-entry summary:focus,
-#src-sidebar div.files > a.selected {
- color: #ffb44c;
-}
-
-.sidebar-elems .location {
- color: #ff7733;
-}
-
-.src-line-numbers .line-highlighted {
- color: #708090;
- padding-right: 7px;
- border-right: 1px solid #ffb44c;
-}
-
-.search-results a:hover,
-.search-results a:focus {
- color: #fff !important;
- background-color: #3c3c3c;
-}
-
-.search-results a {
- color: #0096cf;
-}
-.search-results a div.desc {
- color: #c5c5c5;
-}
-
-.result-name .primitive > i, .result-name .keyword > i {
- color: #788797;
-}
-
-#search-tabs > button.selected {
- border-bottom: 1px solid #ffb44c !important;
- border-top: none;
-}
-#search-tabs > button:not(.selected) {
- border: none;
- background-color: transparent !important;
-}
-#search-tabs > button:hover {
- border-bottom: 1px solid rgba(242, 151, 24, 0.3);
-}
-
-#settings-menu > a img {
- filter: invert(100);
-}
diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css
deleted file mode 100644
index 2b3029887..000000000
--- a/src/librustdoc/html/static/css/themes/dark.css
+++ /dev/null
@@ -1,101 +0,0 @@
-:root {
- --main-background-color: #353535;
- --main-color: #ddd;
- --settings-input-color: #2196f3;
- --settings-input-border-color: #999;
- --settings-button-color: #000;
- --settings-button-border-focus: #ffb900;
- --sidebar-background-color: #505050;
- --sidebar-background-color-hover: #676767;
- --code-block-background-color: #2A2A2A;
- --scrollbar-track-background-color: #717171;
- --scrollbar-thumb-background-color: rgba(32, 34, 37, .6);
- --scrollbar-color: rgba(32,34,37,.6) #5a5a5a;
- --headings-border-bottom-color: #d2d2d2;
- --border-color: #e0e0e0;
- --button-background-color: #f0f0f0;
- --right-side-color: grey;
- --code-attribute-color: #999;
- --toggles-color: #999;
- --toggle-filter: invert(100%);
- --search-input-focused-border-color: #008dfd;
- --copy-path-button-color: #999;
- --copy-path-img-filter: invert(50%);
- --copy-path-img-hover-filter: invert(65%);
- --codeblock-error-hover-color: rgb(255, 0, 0);
- --codeblock-error-color: rgba(255, 0, 0, .5);
- --codeblock-ignore-hover-color: rgb(255, 142, 0);
- --codeblock-ignore-color: rgba(255, 142, 0, .6);
- --type-link-color: #2dbfb8;
- --trait-link-color: #b78cf2;
- --assoc-item-link-color: #d2991d;
- --function-link-color: #2bab63;
- --macro-link-color: #09bd00;
- --keyword-link-color: #d2991d;
- --mod-link-color: #d2991d;
- --link-color: #d2991d;
- --sidebar-link-color: #fdbf35;
- --sidebar-current-link-background-color: #444;
- --search-result-link-focus-background-color: #616161;
- --search-result-border-color: #aaa3;
- --search-color: #111;
- --search-error-code-background-color: #484848;
- --search-results-alias-color: #fff;
- --search-results-grey-color: #ccc;
- --search-tab-title-count-color: #888;
- --search-tab-button-not-selected-border-top-color: #252525;
- --search-tab-button-not-selected-background: #252525;
- --search-tab-button-selected-border-top-color: #0089ff;
- --search-tab-button-selected-background: #353535;
- --stab-background-color: #314559;
- --stab-code-color: #e6e1cf;
- --code-highlight-kw-color: #ab8ac1;
- --code-highlight-kw-2-color: #769acb;
- --code-highlight-lifetime-color: #d97f26;
- --code-highlight-prelude-color: #769acb;
- --code-highlight-prelude-val-color: #ee6868;
- --code-highlight-number-color: #83a300;
- --code-highlight-string-color: #83a300;
- --code-highlight-literal-color: #ee6868;
- --code-highlight-attribute-color: #ee6868;
- --code-highlight-self-color: #ee6868;
- --code-highlight-macro-color: #3e999f;
- --code-highlight-question-mark-color: #ff9011;
- --code-highlight-comment-color: #8d8d8b;
- --code-highlight-doc-comment-color: #8ca375;
- --src-line-numbers-span-color: #3b91e2;
- --src-line-number-highlighted-background-color: #0a042f;
- --test-arrow-color: #dedede;
- --test-arrow-background-color: rgba(78, 139, 202, 0.2);
- --test-arrow-hover-color: #dedede;
- --test-arrow-hover-background-color: rgb(78, 139, 202);
- --target-background-color: #494a3d;
- --target-border-color: #bb7410;
- --kbd-color: #000;
- --kbd-background: #fafbfc;
- --kbd-box-shadow-color: #c6cbd1;
- --rust-logo-filter: drop-shadow(1px 0 0px #fff)
- drop-shadow(0 1px 0 #fff)
- drop-shadow(-1px 0 0 #fff)
- drop-shadow(0 -1px 0 #fff);
- /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
- --crate-search-div-filter: invert(94%) sepia(0%) saturate(721%) hue-rotate(255deg)
- brightness(90%) contrast(90%);
- --crate-search-div-hover-filter: invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg)
- brightness(100%) contrast(91%);
- --crate-search-hover-border: #2196f3;
- --src-sidebar-background-selected: #333;
- --src-sidebar-background-hover: #444;
- --table-alt-row-background-color: #2A2A2A;
- --codeblock-link-background: #333;
- --scrape-example-toggle-line-background: #999;
- --scrape-example-toggle-line-hover-background: #c5c5c5;
- --scrape-example-code-line-highlight: rgb(91, 59, 1);
- --scrape-example-code-line-highlight-focus: rgb(124, 75, 15);
- --scrape-example-help-border-color: #aaa;
- --scrape-example-help-color: #eee;
- --scrape-example-help-hover-border-color: #fff;
- --scrape-example-help-hover-color: #fff;
- --scrape-example-code-wrapper-background-start: rgba(53, 53, 53, 1);
- --scrape-example-code-wrapper-background-end: rgba(53, 53, 53, 0);
-}
diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css
deleted file mode 100644
index 56fd8cbef..000000000
--- a/src/librustdoc/html/static/css/themes/light.css
+++ /dev/null
@@ -1,98 +0,0 @@
-:root {
- --main-background-color: white;
- --main-color: black;
- --settings-input-color: #2196f3;
- --settings-input-border-color: #717171;
- --settings-button-color: #000;
- --settings-button-border-focus: #717171;
- --sidebar-background-color: #F5F5F5;
- --sidebar-background-color-hover: #E0E0E0;
- --code-block-background-color: #F5F5F5;
- --scrollbar-track-background-color: #dcdcdc;
- --scrollbar-thumb-background-color: rgba(36, 37, 39, 0.6);
- --scrollbar-color: rgba(36, 37, 39, 0.6) #d9d9d9;
- --headings-border-bottom-color: #ddd;
- --border-color: #e0e0e0;
- --button-background-color: #fff;
- --right-side-color: grey;
- --code-attribute-color: #999;
- --toggles-color: #999;
- --toggle-filter: none;
- --search-input-focused-border-color: #66afe9;
- --copy-path-button-color: #999;
- --copy-path-img-filter: invert(50%);
- --copy-path-img-hover-filter: invert(35%);
- --codeblock-error-hover-color: rgb(255, 0, 0);
- --codeblock-error-color: rgba(255, 0, 0, .5);
- --codeblock-ignore-hover-color: rgb(255, 142, 0);
- --codeblock-ignore-color: rgba(255, 142, 0, .6);
- --type-link-color: #ad378a;
- --trait-link-color: #6e4fc9;
- --assoc-item-link-color: #3873ad;
- --function-link-color: #ad7c37;
- --macro-link-color: #068000;
- --keyword-link-color: #3873ad;
- --mod-link-color: #3873ad;
- --link-color: #3873ad;
- --sidebar-link-color: #356da4;
- --sidebar-current-link-background-color: #fff;
- --search-result-link-focus-background-color: #ccc;
- --search-result-border-color: #aaa3;
- --search-color: #000;
- --search-error-code-background-color: #d0cccc;
- --search-results-alias-color: #000;
- --search-results-grey-color: #999;
- --search-tab-title-count-color: #888;
- --search-tab-button-not-selected-border-top-color: #e6e6e6;
- --search-tab-button-not-selected-background: #e6e6e6;
- --search-tab-button-selected-border-top-color: #0089ff;
- --search-tab-button-selected-background: #ffffff;
- --stab-background-color: #fff5d6;
- --stab-code-color: #000;
- --code-highlight-kw-color: #8959a8;
- --code-highlight-kw-2-color: #4271ae;
- --code-highlight-lifetime-color: #b76514;
- --code-highlight-prelude-color: #4271ae;
- --code-highlight-prelude-val-color: #c82829;
- --code-highlight-number-color: #718c00;
- --code-highlight-string-color: #718c00;
- --code-highlight-literal-color: #c82829;
- --code-highlight-attribute-color: #c82829;
- --code-highlight-self-color: #c82829;
- --code-highlight-macro-color: #3e999f;
- --code-highlight-question-mark-color: #ff9011;
- --code-highlight-comment-color: #8e908c;
- --code-highlight-doc-comment-color: #4d4d4c;
- --src-line-numbers-span-color: #c67e2d;
- --src-line-number-highlighted-background-color: #fdffd3;
- --test-arrow-color: #f5f5f5;
- --test-arrow-background-color: rgba(78, 139, 202, 0.2);
- --test-arrow-hover-color: #f5f5f5;
- --test-arrow-hover-background-color: rgb(78, 139, 202);
- --target-background-color: #fdffd3;
- --target-border-color: #ad7c37;
- --kbd-color: #000;
- --kbd-background: #fafbfc;
- --kbd-box-shadow-color: #c6cbd1;
- --rust-logo-filter: initial;
- /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
- --crate-search-div-filter: invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg)
- brightness(114%) contrast(76%);
- --crate-search-div-hover-filter: invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg)
- brightness(96%) contrast(93%);
- --crate-search-hover-border: #717171;
- --src-sidebar-background-selected: #fff;
- --src-sidebar-background-hover: #e0e0e0;
- --table-alt-row-background-color: #F5F5F5;
- --codeblock-link-background: #eee;
- --scrape-example-toggle-line-background: #ccc;
- --scrape-example-toggle-line-hover-background: #999;
- --scrape-example-code-line-highlight: #fcffd6;
- --scrape-example-code-line-highlight-focus: #f6fdb0;
- --scrape-example-help-border-color: #555;
- --scrape-example-help-color: #333;
- --scrape-example-help-hover-border-color: #000;
- --scrape-example-help-hover-color: #000;
- --scrape-example-code-wrapper-background-start: rgba(255, 255, 255, 1);
- --scrape-example-code-wrapper-background-end: rgba(255, 255, 255, 0);
-}
diff --git a/src/librustdoc/html/static/js/externs.js b/src/librustdoc/html/static/js/externs.js
index f697abd07..c7811b43d 100644
--- a/src/librustdoc/html/static/js/externs.js
+++ b/src/librustdoc/html/static/js/externs.js
@@ -9,7 +9,7 @@ function initSearch(searchIndex){}
/**
* @typedef {{
* name: string,
- * id: integer,
+ * id: integer|null,
* fullPath: Array<string>,
* pathWithoutLast: Array<string>,
* pathLast: string,
@@ -37,6 +37,7 @@ let ParserState;
* args: Array<QueryElement>,
* returned: Array<QueryElement>,
* foundElems: number,
+ * totalElems: number,
* literalSearch: boolean,
* corrections: Array<{from: string, to: integer}>,
* }}
@@ -103,7 +104,7 @@ let ResultObject;
*
* fn something() -> Result<usize, usize>
*
- * If output was allowed to be any RawFunctionType, it would look like this
+ * If output was allowed to be any RawFunctionType, it would look like thi
*
* [[], [50, [3, 3]]]
*
@@ -113,10 +114,56 @@ let ResultObject;
* in favor of the pair of types interpretation. This is why the `(number|Array<RawFunctionType>)`
* is used instead of `(RawFunctionType|Array<RawFunctionType>)`.
*
+ * The output can be skipped if it's actually unit and there's no type constraints. If thi
+ * function accepts constrained generics, then the output will be unconditionally emitted, and
+ * after it will come a list of trait constraints. The position of the item in the list will
+ * determine which type parameter it is. For example:
+ *
+ * [1, 2, 3, 4, 5]
+ * ^ ^ ^ ^ ^
+ * | | | | - generic parameter (-3) of trait 5
+ * | | | - generic parameter (-2) of trait 4
+ * | | - generic parameter (-1) of trait 3
+ * | - this function returns a single value (type 2)
+ * - this function takes a single input parameter (type 1)
+ *
+ * Or, for a less contrived version:
+ *
+ * [[[4, -1], 3], [[5, -1]], 11]
+ * -^^^^^^^---- ^^^^^^^ ^^
+ * | | | - generic parameter, roughly `where -1: 11`
+ * | | | since -1 is the type parameter and 11 the trait
+ * | | - function output 5<-1>
+ * | - the overall function signature is something like
+ * | `fn(4<-1>, 3) -> 5<-1> where -1: 11`
+ * - function input, corresponds roughly to 4<-1>
+ * 4 is an index into the `p` array for a type
+ * -1 is the generic parameter, given by 11
+ *
+ * If a generic parameter has multiple trait constraints, it gets wrapped in an array, just like
+ * function inputs and outputs:
+ *
+ * [-1, -1, [4, 3]]
+ * ^^^^^^ where -1: 4 + 3
+ *
+ * If a generic parameter's trait constraint has generic parameters, it gets wrapped in the array
+ * even if only one exists. In other words, the ambiguity of `4<3>` and `4 + 3` is resolved in
+ * favor of `4 + 3`:
+ *
+ * [-1, -1, [[4, 3]]]
+ * ^^^^^^^^ where -1: 4 + 3
+ *
+ * [-1, -1, [5, [4, 3]]]
+ * ^^^^^^^^^^^ where -1: 5, -2: 4 + 3
+ *
+ * If a generic parameter has no trait constraints (like in Rust, the `Sized` constraint i
+ * implied and a fake `?Sized` constraint used to note its absence), it will be filled in with 0.
+ *
* @typedef {(
* 0 |
* [(number|Array<RawFunctionType>)] |
- * [(number|Array<RawFunctionType>), (number|Array<RawFunctionType>)]
+ * [(number|Array<RawFunctionType>), (number|Array<RawFunctionType>)] |
+ * Array<(number|Array<RawFunctionType>)>
* )}
*/
let RawFunctionSearchType;
@@ -136,6 +183,7 @@ let RawFunctionType;
* @typedef {{
* inputs: Array<FunctionType>,
* output: Array<FunctionType>,
+ * where_clause: Array<Array<FunctionType>>,
* }}
*/
let FunctionSearchType;
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 254b0d8bf..eb256455b 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -49,10 +49,12 @@ window.currentCrate = getVar("current-crate");
function setMobileTopbar() {
// FIXME: It would be nicer to generate this text content directly in HTML,
// but with the current code it's hard to get the right information in the right place.
- const mobileLocationTitle = document.querySelector(".mobile-topbar h2");
+ const mobileTopbar = document.querySelector(".mobile-topbar");
const locationTitle = document.querySelector(".sidebar h2.location");
- if (mobileLocationTitle && locationTitle) {
- mobileLocationTitle.innerHTML = locationTitle.innerHTML;
+ if (mobileTopbar && locationTitle) {
+ const mobileTitle = document.createElement("h2");
+ mobileTitle.innerHTML = locationTitle.innerHTML;
+ mobileTopbar.appendChild(mobileTitle);
}
}
@@ -176,13 +178,6 @@ function browserSupportsHistoryApi() {
return window.history && typeof window.history.pushState === "function";
}
-function loadCss(cssUrl) {
- const link = document.createElement("link");
- link.href = cssUrl;
- link.rel = "stylesheet";
- document.getElementsByTagName("head")[0].appendChild(link);
-}
-
function preLoadCss(cssUrl) {
// https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/preload
const link = document.createElement("link");
@@ -210,11 +205,7 @@ function preLoadCss(cssUrl) {
event.preventDefault();
// Sending request for the CSS and the JS files at the same time so it will
// hopefully be loaded when the JS will generate the settings content.
- loadCss(getVar("static-root-path") + getVar("settings-css"));
loadScript(getVar("static-root-path") + getVar("settings-js"));
- preLoadCss(getVar("static-root-path") + getVar("theme-light-css"));
- preLoadCss(getVar("static-root-path") + getVar("theme-dark-css"));
- preLoadCss(getVar("static-root-path") + getVar("theme-ayu-css"));
// Pre-load all theme CSS files, so that switching feels seamless.
//
// When loading settings.html as a standalone page, the equivalent HTML is
@@ -499,7 +490,7 @@ function preLoadCss(cssUrl) {
block("static", "static", "Statics");
block("trait", "traits", "Traits");
block("fn", "functions", "Functions");
- block("type", "types", "Type Definitions");
+ block("type", "types", "Type Aliases");
block("foreigntype", "foreign-types", "Foreign Types");
block("keyword", "keywords", "Keywords");
block("traitalias", "trait-aliases", "Trait Aliases");
@@ -852,14 +843,14 @@ function preLoadCss(cssUrl) {
window.CURRENT_TOOLTIP_ELEMENT = wrapper;
window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE = e;
clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT);
- wrapper.onpointerenter = function(ev) {
+ wrapper.onpointerenter = ev => {
// If this is a synthetic touch event, ignore it. A click event will be along shortly.
if (ev.pointerType !== "mouse") {
return;
}
clearTooltipHoverTimeout(e);
};
- wrapper.onpointerleave = function(ev) {
+ wrapper.onpointerleave = ev => {
// If this is a synthetic touch event, ignore it. A click event will be along shortly.
if (ev.pointerType !== "mouse") {
return;
@@ -963,38 +954,38 @@ function preLoadCss(cssUrl) {
}
onEachLazy(document.getElementsByClassName("tooltip"), e => {
- e.onclick = function() {
- this.TOOLTIP_FORCE_VISIBLE = this.TOOLTIP_FORCE_VISIBLE ? false : true;
- if (window.CURRENT_TOOLTIP_ELEMENT && !this.TOOLTIP_FORCE_VISIBLE) {
+ e.onclick = () => {
+ e.TOOLTIP_FORCE_VISIBLE = e.TOOLTIP_FORCE_VISIBLE ? false : true;
+ if (window.CURRENT_TOOLTIP_ELEMENT && !e.TOOLTIP_FORCE_VISIBLE) {
hideTooltip(true);
} else {
- showTooltip(this);
+ showTooltip(e);
window.CURRENT_TOOLTIP_ELEMENT.setAttribute("tabindex", "0");
window.CURRENT_TOOLTIP_ELEMENT.focus();
window.CURRENT_TOOLTIP_ELEMENT.onblur = tooltipBlurHandler;
}
return false;
};
- e.onpointerenter = function(ev) {
+ e.onpointerenter = ev => {
// If this is a synthetic touch event, ignore it. A click event will be along shortly.
if (ev.pointerType !== "mouse") {
return;
}
- setTooltipHoverTimeout(this, true);
+ setTooltipHoverTimeout(e, true);
};
- e.onpointermove = function(ev) {
+ e.onpointermove = ev => {
// If this is a synthetic touch event, ignore it. A click event will be along shortly.
if (ev.pointerType !== "mouse") {
return;
}
- setTooltipHoverTimeout(this, true);
+ setTooltipHoverTimeout(e, true);
};
- e.onpointerleave = function(ev) {
+ e.onpointerleave = ev => {
// If this is a synthetic touch event, ignore it. A click event will be along shortly.
if (ev.pointerType !== "mouse") {
return;
}
- if (!this.TOOLTIP_FORCE_VISIBLE &&
+ if (!e.TOOLTIP_FORCE_VISIBLE &&
!elemIsInParent(ev.relatedTarget, window.CURRENT_TOOLTIP_ELEMENT)) {
// Tooltip pointer leave gesture:
//
@@ -1139,7 +1130,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/how-to-read-rustdoc.html\
*
* Pass "true" to reset focus for tooltip popovers.
*/
- window.hideAllModals = function(switchFocus) {
+ window.hideAllModals = switchFocus => {
hideSidebar();
window.hidePopoverMenus();
hideTooltip(switchFocus);
@@ -1148,7 +1139,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/how-to-read-rustdoc.html\
/**
* Hide all the popover menus.
*/
- window.hidePopoverMenus = function() {
+ window.hidePopoverMenus = () => {
onEachLazy(document.querySelectorAll(".search-form .popover"), elem => {
elem.style.display = "none";
});
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 42088e735..2f0cae0a4 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -3,6 +3,17 @@
"use strict";
+// polyfill
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toSpliced
+if (!Array.prototype.toSpliced) {
+ // Can't use arrow functions, because we want `this`
+ Array.prototype.toSpliced = function() {
+ const me = this.slice();
+ Array.prototype.splice.apply(me, arguments);
+ return me;
+ };
+}
+
(function() {
// This mapping table should match the discriminants of
// `rustdoc::formats::item_type::ItemType` type in Rust.
@@ -33,6 +44,7 @@ const itemTypes = [
"attr",
"derive",
"traitalias",
+ "generic",
];
const longItemTypes = [
@@ -67,6 +79,7 @@ const longItemTypes = [
// used for special search precedence
const TY_PRIMITIVE = itemTypes.indexOf("primitive");
const TY_KEYWORD = itemTypes.indexOf("keyword");
+const TY_GENERIC = itemTypes.indexOf("generic");
const ROOT_PATH = typeof window !== "undefined" ? window.rootPath : "../";
function hasOwnPropertyRustdoc(obj, property) {
@@ -252,7 +265,7 @@ function initSearch(rawSearchIndex) {
/**
* Add an item to the type Name->ID map, or, if one already exists, use it.
- * Returns the number. If name is "" or null, return -1 (pure generic).
+ * Returns the number. If name is "" or null, return null (pure generic).
*
* This is effectively string interning, so that function matching can be
* done more quickly. Two types with the same name but different item kinds
@@ -263,9 +276,8 @@ function initSearch(rawSearchIndex) {
* @returns {integer}
*/
function buildTypeMapIndex(name) {
-
if (name === "" || name === null) {
- return -1;
+ return null;
}
if (typeNameIdMap.has(name)) {
@@ -490,7 +502,7 @@ function initSearch(rawSearchIndex) {
}
return {
name: "never",
- id: -1,
+ id: null,
fullPath: ["never"],
pathWithoutLast: [],
pathLast: "never",
@@ -532,7 +544,7 @@ function initSearch(rawSearchIndex) {
}
return {
name: name.trim(),
- id: -1,
+ id: null,
fullPath: pathSegments,
pathWithoutLast: pathSegments.slice(0, pathSegments.length - 1),
pathLast: pathSegments[pathSegments.length - 1],
@@ -661,7 +673,7 @@ function initSearch(rawSearchIndex) {
}
elems.push({
name: "[]",
- id: -1,
+ id: null,
fullPath: ["[]"],
pathWithoutLast: [],
pathLast: "[]",
@@ -972,9 +984,13 @@ function initSearch(rawSearchIndex) {
returned: [],
// Total number of "top" elements (does not include generics).
foundElems: 0,
+ // Total number of elements (includes generics).
+ totalElems: 0,
literalSearch: false,
error: null,
correction: null,
+ proposeCorrectionFrom: null,
+ proposeCorrectionTo: null,
};
}
@@ -1015,64 +1031,10 @@ function initSearch(rawSearchIndex) {
/**
* Parses the query.
*
- * The supported syntax by this parser is as follow:
- *
- * ident = *(ALPHA / DIGIT / "_")
- * path = ident *(DOUBLE-COLON/{WS} ident) [!]
- * slice = OPEN-SQUARE-BRACKET [ nonempty-arg-list ] CLOSE-SQUARE-BRACKET
- * arg = [type-filter *WS COLON *WS] (path [generics] / slice)
- * type-sep = *WS COMMA *(COMMA)
- * nonempty-arg-list = *(type-sep) arg *(type-sep arg) *(type-sep)
- * generics = OPEN-ANGLE-BRACKET [ nonempty-arg-list ] *(type-sep)
- * CLOSE-ANGLE-BRACKET
- * return-args = RETURN-ARROW *(type-sep) nonempty-arg-list
- *
- * exact-search = [type-filter *WS COLON] [ RETURN-ARROW ] *WS QUOTE ident QUOTE [ generics ]
- * type-search = [ nonempty-arg-list ] [ return-args ]
- *
- * query = *WS (exact-search / type-search) *WS
+ * The supported syntax by this parser is given in the rustdoc book chapter
+ * /src/doc/rustdoc/src/read-documentation/search.md
*
- * type-filter = (
- * "mod" /
- * "externcrate" /
- * "import" /
- * "struct" /
- * "enum" /
- * "fn" /
- * "type" /
- * "static" /
- * "trait" /
- * "impl" /
- * "tymethod" /
- * "method" /
- * "structfield" /
- * "variant" /
- * "macro" /
- * "primitive" /
- * "associatedtype" /
- * "constant" /
- * "associatedconstant" /
- * "union" /
- * "foreigntype" /
- * "keyword" /
- * "existential" /
- * "attr" /
- * "derive" /
- * "traitalias")
- *
- * OPEN-ANGLE-BRACKET = "<"
- * CLOSE-ANGLE-BRACKET = ">"
- * OPEN-SQUARE-BRACKET = "["
- * CLOSE-SQUARE-BRACKET = "]"
- * COLON = ":"
- * DOUBLE-COLON = "::"
- * QUOTE = %x22
- * COMMA = ","
- * RETURN-ARROW = "->"
- *
- * ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
- * DIGIT = %x30-39
- * WS = %x09 / " "
+ * When adding new things to the parser, add them there, too!
*
* @param {string} val - The user query
*
@@ -1125,6 +1087,7 @@ function initSearch(rawSearchIndex) {
query.literalSearch = parserState.totalElems > 1;
}
query.foundElems = query.elems.length + query.returned.length;
+ query.totalElems = parserState.totalElems;
return query;
}
@@ -1173,7 +1136,7 @@ function initSearch(rawSearchIndex) {
const out = [];
for (const result of results) {
- if (result.id > -1) {
+ if (result.id !== -1) {
const obj = searchIndex[result.id];
obj.dist = result.dist;
const res = buildHrefAndPath(obj);
@@ -1349,166 +1312,311 @@ function initSearch(rawSearchIndex) {
* This function checks generics in search query `queryElem` can all be found in the
* search index (`fnType`),
*
- * @param {FunctionType} fnType - The object to check.
- * @param {QueryElement} queryElem - The element from the parsed query.
+ * This function returns `true` if it matches, and also writes the results to mgensInout.
+ * It returns `false` if no match is found, and leaves mgensInout untouched.
+ *
+ * @param {FunctionType} fnType - The object to check.
+ * @param {QueryElement} queryElem - The element from the parsed query.
+ * @param {[FunctionType]} whereClause - Trait bounds for generic items.
+ * @param {Map<number,number>|null} mgensInout - Map functions generics to query generics.
*
* @return {boolean} - Returns true if a match, false otherwise.
*/
- function checkGenerics(fnType, queryElem) {
- return unifyFunctionTypes(fnType.generics, queryElem.generics);
+ function checkGenerics(fnType, queryElem, whereClause, mgensInout) {
+ return unifyFunctionTypes(
+ fnType.generics,
+ queryElem.generics,
+ whereClause,
+ mgensInout,
+ mgens => {
+ if (mgensInout) {
+ for (const [fid, qid] of mgens.entries()) {
+ mgensInout.set(fid, qid);
+ }
+ }
+ return true;
+ }
+ );
}
/**
* This function checks if a list of search query `queryElems` can all be found in the
* search index (`fnTypes`).
*
- * @param {Array<FunctionType>} fnTypes - The objects to check.
+ * This function returns `true` on a match, or `false` if none. If `solutionCb` is
+ * supplied, it will call that function with mgens, and that callback can accept or
+ * reject the result bu returning `true` or `false`. If the callback returns false,
+ * then this function will try with a different solution, or bail with false if it
+ * runs out of candidates.
+ *
+ * @param {Array<FunctionType>} fnTypes - The objects to check.
* @param {Array<QueryElement>} queryElems - The elements from the parsed query.
+ * @param {[FunctionType]} whereClause - Trait bounds for generic items.
+ * @param {Map<number,number>|null} mgensIn
+ * - Map functions generics to query generics (never modified).
+ * @param {null|Map<number,number> -> bool} solutionCb - Called for each `mgens` solution.
*
* @return {boolean} - Returns true if a match, false otherwise.
*/
- function unifyFunctionTypes(fnTypes, queryElems) {
- // This search engine implements order-agnostic unification. There
- // should be no missing duplicates (generics have "bag semantics"),
- // and the row is allowed to have extras.
+ function unifyFunctionTypes(fnTypesIn, queryElems, whereClause, mgensIn, solutionCb) {
+ /**
+ * @type Map<integer, integer>
+ */
+ let mgens = new Map(mgensIn);
if (queryElems.length === 0) {
- return true;
+ return !solutionCb || solutionCb(mgens);
}
- if (!fnTypes || fnTypes.length === 0) {
+ if (!fnTypesIn || fnTypesIn.length === 0) {
return false;
}
+ const ql = queryElems.length;
+ let fl = fnTypesIn.length;
/**
- * @type Map<integer, QueryElement[]>
+ * @type Array<FunctionType>
*/
- const queryElemSet = new Map();
- const addQueryElemToQueryElemSet = function addQueryElemToQueryElemSet(queryElem) {
- let currentQueryElemList;
- if (queryElemSet.has(queryElem.id)) {
- currentQueryElemList = queryElemSet.get(queryElem.id);
- } else {
- currentQueryElemList = [];
- queryElemSet.set(queryElem.id, currentQueryElemList);
- }
- currentQueryElemList.push(queryElem);
- };
- for (const queryElem of queryElems) {
- addQueryElemToQueryElemSet(queryElem);
- }
+ let fnTypes = fnTypesIn.slice();
/**
- * @type Map<integer, FunctionType[]>
+ * loop works by building up a solution set in the working arrays
+ * fnTypes gets mutated in place to make this work, while queryElems
+ * is left alone
+ *
+ * vvvvvvv `i` points here
+ * queryElems = [ good, good, good, unknown, unknown ],
+ * fnTypes = [ good, good, good, unknown, unknown ],
+ * ---------------- ^^^^^^^^^^^^^^^^ `j` iterates after `i`,
+ * | looking for candidates
+ * everything before `i` is the
+ * current working solution
+ *
+ * Everything in the current working solution is known to be a good
+ * match, but it might not be the match we wind up going with, because
+ * there might be more than one candidate match, and we need to try them all
+ * before giving up. So, to handle this, it backtracks on failure.
+ *
+ * @type Array<{
+ * "fnTypesScratch": Array<FunctionType>,
+ * "queryElemsOffset": integer,
+ * "fnTypesOffset": integer
+ * }>
*/
- const fnTypeSet = new Map();
- const addFnTypeToFnTypeSet = function addFnTypeToFnTypeSet(fnType) {
- // Pure generic, or an item that's not matched by any query elems.
- // Try [unboxing] it.
- //
- // [unboxing]:
- // http://ndmitchell.com/downloads/slides-hoogle_fast_type_searching-09_aug_2008.pdf
- const queryContainsArrayOrSliceElem = queryElemSet.has(typeNameIdOfArrayOrSlice);
- if (fnType.id === -1 || !(
- queryElemSet.has(fnType.id) ||
- (fnType.id === typeNameIdOfSlice && queryContainsArrayOrSliceElem) ||
- (fnType.id === typeNameIdOfArray && queryContainsArrayOrSliceElem)
- )) {
- for (const innerFnType of fnType.generics) {
- addFnTypeToFnTypeSet(innerFnType);
- }
- return;
- }
- let currentQueryElemList = queryElemSet.get(fnType.id) || [];
- let matchIdx = currentQueryElemList.findIndex(queryElem => {
- return typePassesFilter(queryElem.typeFilter, fnType.ty) &&
- checkGenerics(fnType, queryElem);
- });
- if (matchIdx === -1 &&
- (fnType.id === typeNameIdOfSlice || fnType.id === typeNameIdOfArray) &&
- queryContainsArrayOrSliceElem
- ) {
- currentQueryElemList = queryElemSet.get(typeNameIdOfArrayOrSlice) || [];
- matchIdx = currentQueryElemList.findIndex(queryElem => {
- return typePassesFilter(queryElem.typeFilter, fnType.ty) &&
- checkGenerics(fnType, queryElem);
- });
- }
- // None of the query elems match the function type.
- // Try [unboxing] it.
- if (matchIdx === -1) {
- for (const innerFnType of fnType.generics) {
- addFnTypeToFnTypeSet(innerFnType);
+ const backtracking = [];
+ let i = 0;
+ let j = 0;
+ const backtrack = () => {
+ while (backtracking.length !== 0) {
+ // this session failed, but there are other possible solutions
+ // to backtrack, reset to (a copy of) the old array, do the swap or unboxing
+ const {
+ fnTypesScratch,
+ mgensScratch,
+ queryElemsOffset,
+ fnTypesOffset,
+ unbox,
+ } = backtracking.pop();
+ mgens = new Map(mgensScratch);
+ const fnType = fnTypesScratch[fnTypesOffset];
+ const queryElem = queryElems[queryElemsOffset];
+ if (unbox) {
+ if (fnType.id < 0) {
+ if (mgens.has(fnType.id) && mgens.get(fnType.id) !== 0) {
+ continue;
+ }
+ mgens.set(fnType.id, 0);
+ }
+ const generics = fnType.id < 0 ?
+ whereClause[(-fnType.id) - 1] :
+ fnType.generics;
+ fnTypes = fnTypesScratch.toSpliced(fnTypesOffset, 1, ...generics);
+ fl = fnTypes.length;
+ // re-run the matching algorithm on this item
+ i = queryElemsOffset - 1;
+ } else {
+ if (fnType.id < 0) {
+ if (mgens.has(fnType.id) && mgens.get(fnType.id) !== queryElem.id) {
+ continue;
+ }
+ mgens.set(fnType.id, queryElem.id);
+ }
+ fnTypes = fnTypesScratch.slice();
+ fl = fnTypes.length;
+ const tmp = fnTypes[queryElemsOffset];
+ fnTypes[queryElemsOffset] = fnTypes[fnTypesOffset];
+ fnTypes[fnTypesOffset] = tmp;
+ // this is known as a good match; go to the next one
+ i = queryElemsOffset;
}
- return;
- }
- let currentFnTypeList;
- if (fnTypeSet.has(fnType.id)) {
- currentFnTypeList = fnTypeSet.get(fnType.id);
- } else {
- currentFnTypeList = [];
- fnTypeSet.set(fnType.id, currentFnTypeList);
+ return true;
}
- currentFnTypeList.push(fnType);
+ return false;
};
- for (const fnType of fnTypes) {
- addFnTypeToFnTypeSet(fnType);
- }
- const doHandleQueryElemList = (currentFnTypeList, queryElemList) => {
- if (queryElemList.length === 0) {
- return true;
+ for (i = 0; i !== ql; ++i) {
+ const queryElem = queryElems[i];
+ /**
+ * list of potential function types that go with the current query element.
+ * @type Array<integer>
+ */
+ const matchCandidates = [];
+ let fnTypesScratch = null;
+ let mgensScratch = null;
+ // don't try anything before `i`, because they've already been
+ // paired off with the other query elements
+ for (j = i; j !== fl; ++j) {
+ const fnType = fnTypes[j];
+ if (unifyFunctionTypeIsMatchCandidate(fnType, queryElem, whereClause, mgens)) {
+ if (!fnTypesScratch) {
+ fnTypesScratch = fnTypes.slice();
+ }
+ unifyFunctionTypes(
+ fnType.generics,
+ queryElem.generics,
+ whereClause,
+ mgens,
+ mgensScratch => {
+ matchCandidates.push({
+ fnTypesScratch,
+ mgensScratch,
+ queryElemsOffset: i,
+ fnTypesOffset: j,
+ unbox: false,
+ });
+ return false; // "reject" all candidates to gather all of them
+ }
+ );
+ }
+ if (unifyFunctionTypeIsUnboxCandidate(fnType, queryElem, whereClause, mgens)) {
+ if (!fnTypesScratch) {
+ fnTypesScratch = fnTypes.slice();
+ }
+ if (!mgensScratch) {
+ mgensScratch = new Map(mgens);
+ }
+ backtracking.push({
+ fnTypesScratch,
+ mgensScratch,
+ queryElemsOffset: i,
+ fnTypesOffset: j,
+ unbox: true,
+ });
+ }
}
- // Multiple items in one list might match multiple items in another.
- // Since an item with fewer generics can match an item with more, we
- // need to check all combinations for a potential match.
- const queryElem = queryElemList.pop();
- const l = currentFnTypeList.length;
- for (let i = 0; i < l; i += 1) {
- const fnType = currentFnTypeList[i];
- if (!typePassesFilter(queryElem.typeFilter, fnType.ty)) {
+ if (matchCandidates.length === 0) {
+ if (backtrack()) {
continue;
+ } else {
+ return false;
}
- if (queryElem.generics.length === 0 || checkGenerics(fnType, queryElem)) {
- currentFnTypeList.splice(i, 1);
- const result = doHandleQueryElemList(currentFnTypeList, queryElemList);
- if (result) {
- return true;
- }
- currentFnTypeList.splice(i, 0, fnType);
+ }
+ // use the current candidate
+ const {fnTypesOffset: candidate, mgensScratch: mgensNew} = matchCandidates.pop();
+ if (fnTypes[candidate].id < 0 && queryElems[i].id < 0) {
+ mgens.set(fnTypes[candidate].id, queryElems[i].id);
+ }
+ for (const [fid, qid] of mgensNew) {
+ mgens.set(fid, qid);
+ }
+ // `i` and `j` are paired off
+ // `queryElems[i]` is left in place
+ // `fnTypes[j]` is swapped with `fnTypes[i]` to pair them off
+ const tmp = fnTypes[candidate];
+ fnTypes[candidate] = fnTypes[i];
+ fnTypes[i] = tmp;
+ // write other candidates to backtracking queue
+ for (const otherCandidate of matchCandidates) {
+ backtracking.push(otherCandidate);
+ }
+ // If we're on the last item, check the solution with the callback
+ // backtrack if the callback says its unsuitable
+ while (i === (ql - 1) && solutionCb && !solutionCb(mgens)) {
+ if (!backtrack()) {
+ return false;
}
}
+ }
+ return true;
+ }
+ function unifyFunctionTypeIsMatchCandidate(fnType, queryElem, whereClause, mgens) {
+ // type filters look like `trait:Read` or `enum:Result`
+ if (!typePassesFilter(queryElem.typeFilter, fnType.ty)) {
return false;
- };
- const handleQueryElemList = (id, queryElemList) => {
- if (!fnTypeSet.has(id)) {
- if (id === typeNameIdOfArrayOrSlice) {
- return handleQueryElemList(typeNameIdOfSlice, queryElemList) ||
- handleQueryElemList(typeNameIdOfArray, queryElemList);
+ }
+ // fnType.id < 0 means generic
+ // queryElem.id < 0 does too
+ // mgens[fnType.id] = queryElem.id
+ // or, if mgens[fnType.id] = 0, then we've matched this generic with a bare trait
+ // and should make that same decision everywhere it appears
+ if (fnType.id < 0 && queryElem.id < 0) {
+ if (mgens.has(fnType.id) && mgens.get(fnType.id) !== queryElem.id) {
+ return false;
+ }
+ for (const [fid, qid] of mgens.entries()) {
+ if (fnType.id !== fid && queryElem.id === qid) {
+ return false;
+ }
+ if (fnType.id === fid && queryElem.id !== qid) {
+ return false;
}
+ }
+ } else if (fnType.id !== null) {
+ if (queryElem.id === typeNameIdOfArrayOrSlice &&
+ (fnType.id === typeNameIdOfSlice || fnType.id === typeNameIdOfArray)
+ ) {
+ // [] matches primitive:array or primitive:slice
+ // if it matches, then we're fine, and this is an appropriate match candidate
+ } else if (fnType.id !== queryElem.id) {
return false;
}
- const currentFnTypeList = fnTypeSet.get(id);
- if (currentFnTypeList.length < queryElemList.length) {
- // It's not possible for all the query elems to find a match.
+ // If the query elem has generics, and the function doesn't,
+ // it can't match.
+ if (fnType.generics.length === 0 && queryElem.generics.length !== 0) {
return false;
}
- const result = doHandleQueryElemList(currentFnTypeList, queryElemList);
- if (result) {
- // Found a solution.
- // Any items that weren't used for it can be unboxed, and might form
- // part of the solution for another item.
- for (const innerFnType of currentFnTypeList) {
- addFnTypeToFnTypeSet(innerFnType);
+ // If the query element is a path (it contains `::`), we need to check if this
+ // path is compatible with the target type.
+ const queryElemPathLength = queryElem.pathWithoutLast.length;
+ if (queryElemPathLength > 0) {
+ const fnTypePath = fnType.path !== undefined && fnType.path !== null ?
+ fnType.path.split("::") : [];
+ // If the path provided in the query element is longer than this type,
+ // no need to check it since it won't match in any case.
+ if (queryElemPathLength > fnTypePath.length) {
+ return false;
}
- fnTypeSet.delete(id);
- }
- return result;
- };
- let queryElemSetSize = -1;
- while (queryElemSetSize !== queryElemSet.size) {
- queryElemSetSize = queryElemSet.size;
- for (const [id, queryElemList] of queryElemSet) {
- if (handleQueryElemList(id, queryElemList)) {
- queryElemSet.delete(id);
+ let i = 0;
+ for (const path of fnTypePath) {
+ if (path === queryElem.pathWithoutLast[i]) {
+ i += 1;
+ if (i >= queryElemPathLength) {
+ break;
+ }
+ }
+ }
+ if (i < queryElemPathLength) {
+ // If we didn't find all parts of the path of the query element inside
+ // the fn type, then it's not the right one.
+ return false;
}
}
}
- return queryElemSetSize === 0;
+ return true;
+ }
+ function unifyFunctionTypeIsUnboxCandidate(fnType, queryElem, whereClause, mgens) {
+ if (fnType.id < 0 && queryElem.id >= 0) {
+ if (!whereClause) {
+ return false;
+ }
+ // mgens[fnType.id] === 0 indicates that we committed to unboxing this generic
+ // mgens[fnType.id] === null indicates that we haven't decided yet
+ if (mgens.has(fnType.id) && mgens.get(fnType.id) !== 0) {
+ return false;
+ }
+ // This is only a potential unbox if the search query appears in the where clause
+ // for example, searching `Read -> usize` should find
+ // `fn read_all<R: Read>(R) -> Result<usize>`
+ // generic `R` is considered "unboxed"
+ return checkIfInList(whereClause[(-fnType.id) - 1], queryElem, whereClause);
+ } else if (fnType.generics && fnType.generics.length > 0) {
+ return checkIfInList(fnType.generics, queryElem, whereClause);
+ }
+ return false;
}
/**
@@ -1516,13 +1624,14 @@ function initSearch(rawSearchIndex) {
* generics (if any).
*
* @param {Array<FunctionType>} list
- * @param {QueryElement} elem - The element from the parsed query.
+ * @param {QueryElement} elem - The element from the parsed query.
+ * @param {[FunctionType]} whereClause - Trait bounds for generic items.
*
* @return {boolean} - Returns true if found, false otherwise.
*/
- function checkIfInList(list, elem) {
+ function checkIfInList(list, elem, whereClause) {
for (const entry of list) {
- if (checkType(entry, elem)) {
+ if (checkType(entry, elem, whereClause)) {
return true;
}
}
@@ -1534,14 +1643,26 @@ function initSearch(rawSearchIndex) {
* generics (if any).
*
* @param {Row} row
- * @param {QueryElement} elem - The element from the parsed query.
+ * @param {QueryElement} elem - The element from the parsed query.
+ * @param {[FunctionType]} whereClause - Trait bounds for generic items.
*
* @return {boolean} - Returns true if the type matches, false otherwise.
*/
- function checkType(row, elem) {
- if (row.id === -1) {
+ function checkType(row, elem, whereClause) {
+ if (row.id === null) {
// This is a pure "generic" search, no need to run other checks.
- return row.generics.length > 0 ? checkIfInList(row.generics, elem) : false;
+ return row.generics.length > 0
+ ? checkIfInList(row.generics, elem, whereClause)
+ : false;
+ }
+
+ if (row.id < 0 && elem.id >= 0) {
+ const gid = (-row.id) - 1;
+ return checkIfInList(whereClause[gid], elem, whereClause);
+ }
+
+ if (row.id < 0 && elem.id < 0) {
+ return true;
}
const matchesExact = row.id === elem.id;
@@ -1551,7 +1672,7 @@ function initSearch(rawSearchIndex) {
if ((matchesExact || matchesArrayOrSlice) &&
typePassesFilter(elem.typeFilter, row.ty)) {
if (elem.generics.length > 0) {
- return checkGenerics(row, elem);
+ return checkGenerics(row, elem, whereClause, new Map());
}
return true;
}
@@ -1559,7 +1680,7 @@ function initSearch(rawSearchIndex) {
// If the current item does not match, try [unboxing] the generic.
// [unboxing]:
// https://ndmitchell.com/downloads/slides-hoogle_fast_type_searching-09_aug_2008.pdf
- return checkIfInList(row.generics, elem);
+ return checkIfInList(row.generics, elem, whereClause);
}
function checkPath(contains, ty, maxEditDistance) {
@@ -1760,13 +1881,15 @@ function initSearch(rawSearchIndex) {
const fullId = row.id;
const searchWord = searchWords[pos];
- const in_args = row.type && row.type.inputs && checkIfInList(row.type.inputs, elem);
+ const in_args = row.type && row.type.inputs
+ && checkIfInList(row.type.inputs, elem, row.type.where_clause);
if (in_args) {
// path_dist is 0 because no parent path information is currently stored
// in the search index
addIntoResults(results_in_args, fullId, pos, -1, 0, 0, maxEditDistance);
}
- const returned = row.type && row.type.output && checkIfInList(row.type.output, elem);
+ const returned = row.type && row.type.output
+ && checkIfInList(row.type.output, elem, row.type.where_clause);
if (returned) {
addIntoResults(results_returned, fullId, pos, -1, 0, 0, maxEditDistance);
}
@@ -1828,10 +1951,20 @@ function initSearch(rawSearchIndex) {
}
// If the result is too "bad", we return false and it ends this search.
- if (!unifyFunctionTypes(row.type.inputs, parsedQuery.elems)) {
- return;
- }
- if (!unifyFunctionTypes(row.type.output, parsedQuery.returned)) {
+ if (!unifyFunctionTypes(
+ row.type.inputs,
+ parsedQuery.elems,
+ row.type.where_clause,
+ null,
+ mgens => {
+ return unifyFunctionTypes(
+ row.type.output,
+ parsedQuery.returned,
+ row.type.where_clause,
+ mgens
+ );
+ }
+ )) {
return;
}
@@ -1851,6 +1984,11 @@ function initSearch(rawSearchIndex) {
const maxEditDistance = Math.floor(queryLen / 3);
/**
+ * @type {Map<string, integer>}
+ */
+ const genericSymbols = new Map();
+
+ /**
* Convert names to ids in parsed query elements.
* This is not used for the "In Names" tab, but is used for the
* "In Params", "In Returns", and "In Function Signature" tabs.
@@ -1863,14 +2001,14 @@ function initSearch(rawSearchIndex) {
* @param {QueryElement} elem
*/
function convertNameToId(elem) {
- if (typeNameIdMap.has(elem.name)) {
- elem.id = typeNameIdMap.get(elem.name);
+ if (typeNameIdMap.has(elem.pathLast)) {
+ elem.id = typeNameIdMap.get(elem.pathLast);
} else if (!parsedQuery.literalSearch) {
- let match = -1;
+ let match = null;
let matchDist = maxEditDistance + 1;
let matchName = "";
for (const [name, id] of typeNameIdMap) {
- const dist = editDistance(name, elem.name, maxEditDistance);
+ const dist = editDistance(name, elem.pathLast, maxEditDistance);
if (dist <= matchDist && dist <= maxEditDistance) {
if (dist === matchDist && matchName > name) {
continue;
@@ -1880,11 +2018,52 @@ function initSearch(rawSearchIndex) {
matchName = name;
}
}
- if (match !== -1) {
+ if (match !== null) {
parsedQuery.correction = matchName;
}
elem.id = match;
}
+ if ((elem.id === null && parsedQuery.totalElems > 1 && elem.typeFilter === -1
+ && elem.generics.length === 0)
+ || elem.typeFilter === TY_GENERIC) {
+ if (genericSymbols.has(elem.name)) {
+ elem.id = genericSymbols.get(elem.name);
+ } else {
+ elem.id = -(genericSymbols.size + 1);
+ genericSymbols.set(elem.name, elem.id);
+ }
+ if (elem.typeFilter === -1 && elem.name.length >= 3) {
+ // Silly heuristic to catch if the user probably meant
+ // to not write a generic parameter. We don't use it,
+ // just bring it up.
+ const maxPartDistance = Math.floor(elem.name.length / 3);
+ let matchDist = maxPartDistance + 1;
+ let matchName = "";
+ for (const name of typeNameIdMap.keys()) {
+ const dist = editDistance(name, elem.name, maxPartDistance);
+ if (dist <= matchDist && dist <= maxPartDistance) {
+ if (dist === matchDist && matchName > name) {
+ continue;
+ }
+ matchDist = dist;
+ matchName = name;
+ }
+ }
+ if (matchName !== "") {
+ parsedQuery.proposeCorrectionFrom = elem.name;
+ parsedQuery.proposeCorrectionTo = matchName;
+ }
+ }
+ elem.typeFilter = TY_GENERIC;
+ }
+ if (elem.generics.length > 0 && elem.typeFilter === TY_GENERIC) {
+ // Rust does not have HKT
+ parsedQuery.error = [
+ "Generic type parameter ",
+ elem.name,
+ " does not accept generic parameters",
+ ];
+ }
for (const elem2 of elem.generics) {
convertNameToId(elem2);
}
@@ -1918,8 +2097,11 @@ function initSearch(rawSearchIndex) {
elem = parsedQuery.returned[0];
for (i = 0, nSearchWords = searchWords.length; i < nSearchWords; ++i) {
row = searchIndex[i];
- in_returned = row.type &&
- unifyFunctionTypes(row.type.output, parsedQuery.returned);
+ in_returned = row.type && unifyFunctionTypes(
+ row.type.output,
+ parsedQuery.returned,
+ row.type.where_clause
+ );
if (in_returned) {
addIntoResults(
results_others,
@@ -2152,11 +2334,20 @@ ${item.displayPath}<span class="${type}">${name}</span>\
}
function makeTabHeader(tabNb, text, nbElems) {
+ // https://blog.horizon-eda.org/misc/2020/02/19/ui.html
+ //
+ // CSS runs with `font-variant-numeric: tabular-nums` to ensure all
+ // digits are the same width. \u{2007} is a Unicode space character
+ // that is defined to be the same width as a digit.
+ const fmtNbElems =
+ nbElems < 10 ? `\u{2007}(${nbElems})\u{2007}\u{2007}` :
+ nbElems < 100 ? `\u{2007}(${nbElems})\u{2007}` :
+ `\u{2007}(${nbElems})`;
if (searchState.currentTab === tabNb) {
return "<button class=\"selected\">" + text +
- " <span class=\"count\">(" + nbElems + ")</span></button>";
+ "<span class=\"count\">" + fmtNbElems + "</span></button>";
}
- return "<button>" + text + " <span class=\"count\">(" + nbElems + ")</span></button>";
+ return "<button>" + text + "<span class=\"count\">" + fmtNbElems + "</span></button>";
}
/**
@@ -2270,6 +2461,13 @@ ${item.displayPath}<span class="${type}">${name}</span>\
"Showing results for closest type name " +
`"${results.query.correction}" instead.</h3>`;
}
+ if (results.query.proposeCorrectionFrom !== null) {
+ const orig = results.query.proposeCorrectionFrom;
+ const targ = results.query.proposeCorrectionTo;
+ output += "<h3 class=\"search-corrections\">" +
+ `Type "${orig}" not found and used as generic parameter. ` +
+ `Consider searching for "${targ}" instead.</h3>`;
+ }
const resultsElem = document.createElement("div");
resultsElem.id = "results";
@@ -2371,29 +2569,54 @@ ${item.displayPath}<span class="${type}">${name}</span>\
* @return {Array<FunctionSearchType>}
*/
function buildItemSearchTypeAll(types, lowercasePaths) {
+ return types.map(type => buildItemSearchType(type, lowercasePaths));
+ }
+
+ /**
+ * Converts a single type.
+ *
+ * @param {RawFunctionType} type
+ */
+ function buildItemSearchType(type, lowercasePaths) {
const PATH_INDEX_DATA = 0;
const GENERICS_DATA = 1;
- return types.map(type => {
- let pathIndex, generics;
- if (typeof type === "number") {
- pathIndex = type;
- generics = [];
- } else {
- pathIndex = type[PATH_INDEX_DATA];
- generics = buildItemSearchTypeAll(
- type[GENERICS_DATA],
- lowercasePaths
- );
- }
+ let pathIndex, generics;
+ if (typeof type === "number") {
+ pathIndex = type;
+ generics = [];
+ } else {
+ pathIndex = type[PATH_INDEX_DATA];
+ generics = buildItemSearchTypeAll(
+ type[GENERICS_DATA],
+ lowercasePaths
+ );
+ }
+ if (pathIndex < 0) {
+ // types less than 0 are generic parameters
+ // the actual names of generic parameters aren't stored, since they aren't API
return {
- // `0` is used as a sentinel because it's fewer bytes than `null`
- id: pathIndex === 0
- ? -1
- : buildTypeMapIndex(lowercasePaths[pathIndex - 1].name),
- ty: pathIndex === 0 ? null : lowercasePaths[pathIndex - 1].ty,
- generics: generics,
+ id: pathIndex,
+ ty: TY_GENERIC,
+ path: null,
+ generics,
};
- });
+ }
+ if (pathIndex === 0) {
+ // `0` is used as a sentinel because it's fewer bytes than `null`
+ return {
+ id: null,
+ ty: null,
+ path: null,
+ generics,
+ };
+ }
+ const item = lowercasePaths[pathIndex - 1];
+ return {
+ id: buildTypeMapIndex(item.name),
+ ty: item.ty,
+ path: item.path,
+ generics,
+ };
}
/**
@@ -2421,14 +2644,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\
}
let inputs, output;
if (typeof functionSearchType[INPUTS_DATA] === "number") {
- const pathIndex = functionSearchType[INPUTS_DATA];
- inputs = [{
- id: pathIndex === 0
- ? -1
- : buildTypeMapIndex(lowercasePaths[pathIndex - 1].name),
- ty: pathIndex === 0 ? null : lowercasePaths[pathIndex - 1].ty,
- generics: [],
- }];
+ inputs = [buildItemSearchType(functionSearchType[INPUTS_DATA], lowercasePaths)];
} else {
inputs = buildItemSearchTypeAll(
functionSearchType[INPUTS_DATA],
@@ -2437,14 +2653,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\
}
if (functionSearchType.length > 1) {
if (typeof functionSearchType[OUTPUT_DATA] === "number") {
- const pathIndex = functionSearchType[OUTPUT_DATA];
- output = [{
- id: pathIndex === 0
- ? -1
- : buildTypeMapIndex(lowercasePaths[pathIndex - 1].name),
- ty: pathIndex === 0 ? null : lowercasePaths[pathIndex - 1].ty,
- generics: [],
- }];
+ output = [buildItemSearchType(functionSearchType[OUTPUT_DATA], lowercasePaths)];
} else {
output = buildItemSearchTypeAll(
functionSearchType[OUTPUT_DATA],
@@ -2454,8 +2663,15 @@ ${item.displayPath}<span class="${type}">${name}</span>\
} else {
output = [];
}
+ const where_clause = [];
+ const l = functionSearchType.length;
+ for (let i = 2; i < l; ++i) {
+ where_clause.push(typeof functionSearchType[i] === "number"
+ ? [buildItemSearchType(functionSearchType[i], lowercasePaths)]
+ : buildItemSearchTypeAll(functionSearchType[i], lowercasePaths));
+ }
return {
- inputs, output,
+ inputs, output, where_clause,
};
}
@@ -2486,18 +2702,25 @@ ${item.displayPath}<span class="${type}">${name}</span>\
let crateSize = 0;
/**
- * The raw search data for a given crate. `n`, `t`, `d`, and `q`, `i`, and `f`
- * are arrays with the same length. n[i] contains the name of an item.
- * t[i] contains the type of that item (as a string of characters that represent an
- * offset in `itemTypes`). d[i] contains the description of that item.
+ * The raw search data for a given crate. `n`, `t`, `d`, `i`, and `f`
+ * are arrays with the same length. `q`, `a`, and `c` use a sparse
+ * representation for compactness.
+ *
+ * `n[i]` contains the name of an item.
+ *
+ * `t[i]` contains the type of that item
+ * (as a string of characters that represent an offset in `itemTypes`).
*
- * q[i] contains the full path of the item, or an empty string indicating
- * "same as q[i-1]".
+ * `d[i]` contains the description of that item.
*
- * i[i] contains an item's parent, usually a module. For compactness,
+ * `q` contains the full paths of the items. For compactness, it is a set of
+ * (index, path) pairs used to create a map. If a given index `i` is
+ * not present, this indicates "same as the last index present".
+ *
+ * `i[i]` contains an item's parent, usually a module. For compactness,
* it is a set of indexes into the `p` array.
*
- * f[i] contains function signatures, or `0` if the item isn't a function.
+ * `f[i]` contains function signatures, or `0` if the item isn't a function.
* Functions are themselves encoded as arrays. The first item is a list of
* types representing the function's inputs, and the second list item is a list
* of types representing the function's output. Tuples are flattened.
@@ -2511,6 +2734,8 @@ ${item.displayPath}<span class="${type}">${name}</span>\
*
* `p` is a list of path/type pairs. It is used for parents and function parameters.
*
+ * `c` is an array of item indices that are deprecated.
+ *
* @type {{
* doc: string,
* a: Object,
@@ -2577,9 +2802,19 @@ ${item.displayPath}<span class="${type}">${name}</span>\
// convert `rawPaths` entries into object form
// generate normalizedPaths for function search mode
let len = paths.length;
+ let lastPath = itemPaths.get(0);
for (let i = 0; i < len; ++i) {
- lowercasePaths.push({ty: paths[i][0], name: paths[i][1].toLowerCase()});
- paths[i] = {ty: paths[i][0], name: paths[i][1]};
+ const elem = paths[i];
+ const ty = elem[0];
+ const name = elem[1];
+ let path = null;
+ if (elem.length > 2) {
+ path = itemPaths.has(elem[2]) ? itemPaths.get(elem[2]) : lastPath;
+ lastPath = path;
+ }
+
+ lowercasePaths.push({ty: ty, name: name.toLowerCase(), path: path});
+ paths[i] = {ty: ty, name: name, path: path};
}
// convert `item*` into an object form, and construct word indices.
@@ -2589,8 +2824,8 @@ ${item.displayPath}<span class="${type}">${name}</span>\
// operation that is cached for the life of the page state so that
// all other search operations have access to this cached data for
// faster analysis operations
+ lastPath = "";
len = itemTypes.length;
- let lastPath = "";
for (let i = 0; i < len; ++i) {
let word = "";
// This object should have exactly the same set of fields as the "crateRow"
@@ -2599,11 +2834,12 @@ ${item.displayPath}<span class="${type}">${name}</span>\
word = itemNames[i].toLowerCase();
}
searchWords.push(word);
+ const path = itemPaths.has(i) ? itemPaths.get(i) : lastPath;
const row = {
crate: crate,
ty: itemTypes.charCodeAt(i) - charA,
name: itemNames[i],
- path: itemPaths.has(i) ? itemPaths.get(i) : lastPath,
+ path: path,
desc: itemDescs[i],
parent: itemParentIdxs[i] > 0 ? paths[itemParentIdxs[i] - 1] : undefined,
type: buildFunctionSearchType(
diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js
index 2cba32c1b..63947789c 100644
--- a/src/librustdoc/html/static/js/settings.js
+++ b/src/librustdoc/html/static/js/settings.js
@@ -59,8 +59,8 @@
if (settingValue !== null) {
toggle.checked = settingValue === "true";
}
- toggle.onchange = function() {
- changeSetting(this.id, this.checked);
+ toggle.onchange = () => {
+ changeSetting(toggle.id, toggle.checked);
};
});
onEachLazy(settingsElement.querySelectorAll("input[type=\"radio\"]"), elem => {
@@ -224,14 +224,14 @@
if (isSettingsPage) {
// We replace the existing "onclick" callback to do nothing if clicked.
- getSettingsButton().onclick = function(event) {
+ getSettingsButton().onclick = event => {
event.preventDefault();
};
} else {
// We replace the existing "onclick" callback.
const settingsButton = getSettingsButton();
const settingsMenu = document.getElementById("settings");
- settingsButton.onclick = function(event) {
+ settingsButton.onclick = event => {
if (elemIsInParent(event.target, settingsMenu)) {
return;
}
diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js
index af3ca42a6..c69641092 100644
--- a/src/librustdoc/html/static/js/storage.js
+++ b/src/librustdoc/html/static/js/storage.js
@@ -5,6 +5,7 @@
// the page, so we don't see major layout changes during the load of the page.
"use strict";
+const builtinThemes = ["light", "dark", "ayu"];
const darkThemes = ["dark", "ayu"];
window.currentTheme = document.getElementById("themeStyle");
@@ -119,19 +120,32 @@ function switchTheme(newThemeName, saveTheme) {
updateLocalStorage("theme", newThemeName);
}
- let newHref;
+ document.documentElement.setAttribute("data-theme", newThemeName);
- if (newThemeName === "light" || newThemeName === "dark" || newThemeName === "ayu") {
- newHref = getVar("static-root-path") + getVar("theme-" + newThemeName + "-css");
+ if (builtinThemes.indexOf(newThemeName) !== -1) {
+ if (window.currentTheme) {
+ window.currentTheme.parentNode.removeChild(window.currentTheme);
+ window.currentTheme = null;
+ }
} else {
- newHref = getVar("root-path") + newThemeName + getVar("resource-suffix") + ".css";
- }
-
- if (!window.currentTheme) {
- document.write(`<link rel="stylesheet" id="themeStyle" href="${newHref}">`);
- window.currentTheme = document.getElementById("themeStyle");
- } else if (newHref !== window.currentTheme.href) {
- window.currentTheme.href = newHref;
+ const newHref = getVar("root-path") + newThemeName +
+ getVar("resource-suffix") + ".css";
+ if (!window.currentTheme) {
+ // If we're in the middle of loading, document.write blocks
+ // rendering, but if we are done, it would blank the page.
+ if (document.readyState === "loading") {
+ document.write(`<link rel="stylesheet" id="themeStyle" href="${newHref}">`);
+ window.currentTheme = document.getElementById("themeStyle");
+ } else {
+ window.currentTheme = document.createElement("link");
+ window.currentTheme.rel = "stylesheet";
+ window.currentTheme.id = "themeStyle";
+ window.currentTheme.href = newHref;
+ document.documentElement.appendChild(window.currentTheme);
+ }
+ } else if (newHref !== window.currentTheme.href) {
+ window.currentTheme.href = newHref;
+ }
}
}