From 698f8c2f01ea549d77d7dc3338a12e04c11057b9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:02:58 +0200 Subject: Adding upstream version 1.64.0+dfsg1. Signed-off-by: Daniel Baumann --- src/librustdoc/html/static/.eslintrc.js | 96 + src/librustdoc/html/static/COPYRIGHT.txt | 46 + src/librustdoc/html/static/LICENSE-APACHE.txt | 201 ++ src/librustdoc/html/static/LICENSE-MIT.txt | 23 + src/librustdoc/html/static/css/normalize.css | 2 + src/librustdoc/html/static/css/noscript.css | 20 + src/librustdoc/html/static/css/rustdoc.css | 2335 ++++++++++++++++++++ src/librustdoc/html/static/css/settings.css | 90 + src/librustdoc/html/static/css/themes/ayu.css | 563 +++++ src/librustdoc/html/static/css/themes/dark.css | 409 ++++ src/librustdoc/html/static/css/themes/light.css | 395 ++++ .../html/static/fonts/FiraSans-LICENSE.txt | 94 + .../html/static/fonts/FiraSans-Medium.woff2 | Bin 0 -> 132780 bytes .../html/static/fonts/FiraSans-Regular.woff2 | Bin 0 -> 129188 bytes .../html/static/fonts/NanumBarunGothic-LICENSE.txt | 99 + .../html/static/fonts/NanumBarunGothic.ttf.woff2 | Bin 0 -> 399468 bytes .../html/static/fonts/SourceCodePro-It.ttf.woff2 | Bin 0 -> 44896 bytes .../html/static/fonts/SourceCodePro-LICENSE.txt | 93 + .../static/fonts/SourceCodePro-Regular.ttf.woff2 | Bin 0 -> 52228 bytes .../static/fonts/SourceCodePro-Semibold.ttf.woff2 | Bin 0 -> 52348 bytes .../html/static/fonts/SourceSerif4-Bold.ttf.woff2 | Bin 0 -> 81320 bytes .../html/static/fonts/SourceSerif4-It.ttf.woff2 | Bin 0 -> 59860 bytes .../html/static/fonts/SourceSerif4-LICENSE.md | 93 + .../static/fonts/SourceSerif4-Regular.ttf.woff2 | Bin 0 -> 76180 bytes src/librustdoc/html/static/images/clipboard.svg | 1 + src/librustdoc/html/static/images/down-arrow.svg | 1 + .../html/static/images/favicon-16x16.png | Bin 0 -> 715 bytes .../html/static/images/favicon-32x32.png | Bin 0 -> 1125 bytes src/librustdoc/html/static/images/favicon.svg | 24 + src/librustdoc/html/static/images/rust-logo.svg | 61 + src/librustdoc/html/static/images/toggle-minus.svg | 1 + src/librustdoc/html/static/images/toggle-plus.svg | 1 + src/librustdoc/html/static/images/wheel.svg | 1 + src/librustdoc/html/static/js/README.md | 15 + src/librustdoc/html/static/js/externs.js | 142 ++ src/librustdoc/html/static/js/main.js | 974 ++++++++ src/librustdoc/html/static/js/scrape-examples.js | 106 + src/librustdoc/html/static/js/search.js | 2297 +++++++++++++++++++ src/librustdoc/html/static/js/settings.js | 272 +++ src/librustdoc/html/static/js/source-script.js | 241 ++ src/librustdoc/html/static/js/storage.js | 268 +++ src/librustdoc/html/static/scrape-examples-help.md | 34 + 42 files changed, 8998 insertions(+) create mode 100644 src/librustdoc/html/static/.eslintrc.js create mode 100644 src/librustdoc/html/static/COPYRIGHT.txt create mode 100644 src/librustdoc/html/static/LICENSE-APACHE.txt create mode 100644 src/librustdoc/html/static/LICENSE-MIT.txt create mode 100644 src/librustdoc/html/static/css/normalize.css create mode 100644 src/librustdoc/html/static/css/noscript.css create mode 100644 src/librustdoc/html/static/css/rustdoc.css create mode 100644 src/librustdoc/html/static/css/settings.css create mode 100644 src/librustdoc/html/static/css/themes/ayu.css create mode 100644 src/librustdoc/html/static/css/themes/dark.css create mode 100644 src/librustdoc/html/static/css/themes/light.css create mode 100644 src/librustdoc/html/static/fonts/FiraSans-LICENSE.txt create mode 100644 src/librustdoc/html/static/fonts/FiraSans-Medium.woff2 create mode 100644 src/librustdoc/html/static/fonts/FiraSans-Regular.woff2 create mode 100644 src/librustdoc/html/static/fonts/NanumBarunGothic-LICENSE.txt create mode 100644 src/librustdoc/html/static/fonts/NanumBarunGothic.ttf.woff2 create mode 100644 src/librustdoc/html/static/fonts/SourceCodePro-It.ttf.woff2 create mode 100644 src/librustdoc/html/static/fonts/SourceCodePro-LICENSE.txt create mode 100644 src/librustdoc/html/static/fonts/SourceCodePro-Regular.ttf.woff2 create mode 100644 src/librustdoc/html/static/fonts/SourceCodePro-Semibold.ttf.woff2 create mode 100644 src/librustdoc/html/static/fonts/SourceSerif4-Bold.ttf.woff2 create mode 100644 src/librustdoc/html/static/fonts/SourceSerif4-It.ttf.woff2 create mode 100644 src/librustdoc/html/static/fonts/SourceSerif4-LICENSE.md create mode 100644 src/librustdoc/html/static/fonts/SourceSerif4-Regular.ttf.woff2 create mode 100644 src/librustdoc/html/static/images/clipboard.svg create mode 100644 src/librustdoc/html/static/images/down-arrow.svg create mode 100644 src/librustdoc/html/static/images/favicon-16x16.png create mode 100644 src/librustdoc/html/static/images/favicon-32x32.png create mode 100644 src/librustdoc/html/static/images/favicon.svg create mode 100644 src/librustdoc/html/static/images/rust-logo.svg create mode 100644 src/librustdoc/html/static/images/toggle-minus.svg create mode 100644 src/librustdoc/html/static/images/toggle-plus.svg create mode 100644 src/librustdoc/html/static/images/wheel.svg create mode 100644 src/librustdoc/html/static/js/README.md create mode 100644 src/librustdoc/html/static/js/externs.js create mode 100644 src/librustdoc/html/static/js/main.js create mode 100644 src/librustdoc/html/static/js/scrape-examples.js create mode 100644 src/librustdoc/html/static/js/search.js create mode 100644 src/librustdoc/html/static/js/settings.js create mode 100644 src/librustdoc/html/static/js/source-script.js create mode 100644 src/librustdoc/html/static/js/storage.js create mode 100644 src/librustdoc/html/static/scrape-examples-help.md (limited to 'src/librustdoc/html/static') diff --git a/src/librustdoc/html/static/.eslintrc.js b/src/librustdoc/html/static/.eslintrc.js new file mode 100644 index 000000000..fcd925bb3 --- /dev/null +++ b/src/librustdoc/html/static/.eslintrc.js @@ -0,0 +1,96 @@ +module.exports = { + "env": { + "browser": true, + "es6": true + }, + "extends": "eslint:recommended", + "parserOptions": { + "ecmaVersion": 2015, + "sourceType": "module" + }, + "rules": { + "linebreak-style": [ + "error", + "unix" + ], + "semi": [ + "error", + "always" + ], + "quotes": [ + "error", + "double" + ], + "linebreak-style": [ + "error", + "unix" + ], + "no-trailing-spaces": "error", + "no-var": ["error"], + "prefer-const": ["error"], + "prefer-arrow-callback": ["error"], + "brace-style": [ + "error", + "1tbs", + { "allowSingleLine": false } + ], + "keyword-spacing": [ + "error", + { "before": true, "after": true } + ], + "arrow-spacing": [ + "error", + { "before": true, "after": true } + ], + "key-spacing": [ + "error", + { "beforeColon": false, "afterColon": true, "mode": "strict" } + ], + "func-call-spacing": ["error", "never"], + "space-infix-ops": "error", + "space-before-function-paren": ["error", "never"], + "space-before-blocks": "error", + "comma-dangle": ["error", "always-multiline"], + "comma-style": ["error", "last"], + "max-len": ["error", { "code": 100, "tabWidth": 4 }], + "eol-last": ["error", "always"], + "arrow-parens": ["error", "as-needed"], + "no-unused-vars": [ + "error", + { + "argsIgnorePattern": "^_", + "varsIgnorePattern": "^_" + } + ], + "eqeqeq": "error", + "no-const-assign": "error", + "no-debugger": "error", + "no-dupe-args": "error", + "no-dupe-else-if": "error", + "no-dupe-keys": "error", + "no-duplicate-case": "error", + "no-ex-assign": "error", + "no-fallthrough": "error", + "no-invalid-regexp": "error", + "no-import-assign": "error", + "no-self-compare": "error", + "no-template-curly-in-string": "error", + "block-scoped-var": "error", + "guard-for-in": "error", + "no-alert": "error", + "no-confusing-arrow": "error", + "no-div-regex": "error", + "no-floating-decimal": "error", + "no-implicit-globals": "error", + "no-implied-eval": "error", + "no-label-var": "error", + "no-lonely-if": "error", + "no-mixed-operators": "error", + "no-multi-assign": "error", + "no-return-assign": "error", + "no-script-url": "error", + "no-sequences": "error", + "no-throw-literal": "error", + "no-div-regex": "error", + } +}; diff --git a/src/librustdoc/html/static/COPYRIGHT.txt b/src/librustdoc/html/static/COPYRIGHT.txt new file mode 100644 index 000000000..34e48134c --- /dev/null +++ b/src/librustdoc/html/static/COPYRIGHT.txt @@ -0,0 +1,46 @@ +These documentation pages include resources by third parties. This copyright +file applies only to those resources. The following third party resources are +included, and carry their own copyright notices and license terms: + +* Fira Sans (FiraSans-Regular.woff2, FiraSans-Medium.woff2): + + Copyright (c) 2014, Mozilla Foundation https://mozilla.org/ + with Reserved Font Name Fira Sans. + + Copyright (c) 2014, Telefonica S.A. + + Licensed under the SIL Open Font License, Version 1.1. + See FiraSans-LICENSE.txt. + +* rustdoc.css, main.js, and playpen.js: + + Copyright 2015 The Rust Developers. + Licensed under the Apache License, Version 2.0 (see LICENSE-APACHE.txt) or + the MIT license (LICENSE-MIT.txt) at your option. + +* normalize.css: + + Copyright (c) Nicolas Gallagher and Jonathan Neal. + Licensed under the MIT license (see LICENSE-MIT.txt). + +* Source Code Pro (SourceCodePro-Regular.ttf.woff2, + SourceCodePro-Semibold.ttf.woff2, SourceCodePro-It.ttf.woff2): + + Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), + with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark + of Adobe Systems Incorporated in the United States and/or other countries. + + Licensed under the SIL Open Font License, Version 1.1. + See SourceCodePro-LICENSE.txt. + +* Source Serif 4 (SourceSerif4-Regular.ttf.woff2, SourceSerif4-Bold.ttf.woff2, + SourceSerif4-It.ttf.woff2): + + Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name + 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United + States and/or other countries. + + Licensed under the SIL Open Font License, Version 1.1. + See SourceSerif4-LICENSE.md. + +This copyright file is intended to be distributed with rustdoc output. diff --git a/src/librustdoc/html/static/LICENSE-APACHE.txt b/src/librustdoc/html/static/LICENSE-APACHE.txt new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/src/librustdoc/html/static/LICENSE-APACHE.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/librustdoc/html/static/LICENSE-MIT.txt b/src/librustdoc/html/static/LICENSE-MIT.txt new file mode 100644 index 000000000..31aa79387 --- /dev/null +++ b/src/librustdoc/html/static/LICENSE-MIT.txt @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/librustdoc/html/static/css/normalize.css b/src/librustdoc/html/static/css/normalize.css new file mode 100644 index 000000000..fdb8a8c65 --- /dev/null +++ b/src/librustdoc/html/static/css/normalize.css @@ -0,0 +1,2 @@ +/* ignore-tidy-linelength */ +/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:0.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace, monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace, monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type="button"],[type="reset"],[type="submit"],button{-webkit-appearance:button}[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type="button"]:-moz-focusring,[type="reset"]:-moz-focusring,[type="submit"]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:0.35em 0.75em 0.625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type="checkbox"],[type="radio"]{box-sizing:border-box;padding:0}[type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button{height:auto}[type="search"]{-webkit-appearance:textfield;outline-offset:-2px}[type="search"]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none} diff --git a/src/librustdoc/html/static/css/noscript.css b/src/librustdoc/html/static/css/noscript.css new file mode 100644 index 000000000..0a19a99ab --- /dev/null +++ b/src/librustdoc/html/static/css/noscript.css @@ -0,0 +1,20 @@ +/* +This whole CSS file is used only in case rustdoc is rendered with javascript disabled. Since a lot +of content is hidden by default (depending on the settings too), we have to overwrite some of the +rules. +*/ + +#main-content .attributes { + /* Since there is no toggle (the "[-]") when JS is disabled, no need for this margin either. */ + margin-left: 0 !important; +} + +#copy-path { + /* It requires JS to work so no need to display it in this case. */ + display: none; +} + +.sub { + /* The search bar and related controls don't work without JS */ + display: none; +} diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css new file mode 100644 index 000000000..83fe14550 --- /dev/null +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -0,0 +1,2335 @@ +/* See FiraSans-LICENSE.txt for the Fira Sans license. */ +@font-face { + font-family: 'Fira Sans'; + font-style: normal; + font-weight: 400; + src: local('Fira Sans'), + url("FiraSans-Regular.woff2") format("woff2"); + font-display: swap; +} +@font-face { + font-family: 'Fira Sans'; + font-style: normal; + font-weight: 500; + src: local('Fira Sans Medium'), + url("FiraSans-Medium.woff2") format("woff2"); + font-display: swap; +} + +/* See SourceSerif4-LICENSE.md for the Source Serif 4 license. */ +@font-face { + font-family: 'Source Serif 4'; + font-style: normal; + font-weight: 400; + src: local('Source Serif 4'), + url("SourceSerif4-Regular.ttf.woff2") format("woff2"); + font-display: swap; +} +@font-face { + font-family: 'Source Serif 4'; + font-style: italic; + font-weight: 400; + src: local('Source Serif 4 Italic'), + url("SourceSerif4-It.ttf.woff2") format("woff2"); + font-display: swap; +} +@font-face { + font-family: 'Source Serif 4'; + font-style: normal; + font-weight: 700; + src: local('Source Serif 4 Bold'), + url("SourceSerif4-Bold.ttf.woff2") format("woff2"); + font-display: swap; +} + +/* See SourceCodePro-LICENSE.txt for the Source Code Pro license. */ +@font-face { + font-family: 'Source Code Pro'; + font-style: normal; + font-weight: 400; + /* Avoid using locally installed font because bad versions are in circulation: + * see https://github.com/rust-lang/rust/issues/24355 */ + src: url("SourceCodePro-Regular.ttf.woff2") format("woff2"); + font-display: swap; +} +@font-face { + font-family: 'Source Code Pro'; + font-style: italic; + font-weight: 400; + src: url("SourceCodePro-It.ttf.woff2") format("woff2"); + font-display: swap; +} +@font-face { + font-family: 'Source Code Pro'; + font-style: normal; + font-weight: 600; + src: url("SourceCodePro-Semibold.ttf.woff2") format("woff2"); + font-display: swap; +} + +/* Avoid using legacy CJK serif fonts in Windows like Batang. */ +@font-face { + font-family: 'NanumBarunGothic'; + src: url("NanumBarunGothic.ttf.woff2") format("woff2"); + font-display: swap; + unicode-range: U+AC00-D7AF, U+1100-11FF, U+3130-318F, U+A960-A97F, U+D7B0-D7FF; +} + +* { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +/* This part handles the "default" theme being used depending on the system one. */ +html { + content: ""; +} +@media (prefers-color-scheme: light) { + html { + content: "light"; + } +} +@media (prefers-color-scheme: dark) { + html { + content: "dark"; + } +} + +/* General structure and fonts */ + +body { + /* Line spacing at least 1.5 per Web Content Accessibility Guidelines + https://www.w3.org/WAI/WCAG21/Understanding/visual-presentation.html */ + font: 1rem/1.5 "Source Serif 4", NanumBarunGothic, serif; + margin: 0; + position: relative; + /* We use overflow-wrap: break-word for Safari, which doesn't recognize + `anywhere`: https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-wrap */ + overflow-wrap: break-word; + /* Then override it with `anywhere`, which is required to make non-Safari browsers break + more aggressively when we want them to. */ + overflow-wrap: anywhere; + + -webkit-font-feature-settings: "kern", "liga"; + -moz-font-feature-settings: "kern", "liga"; + font-feature-settings: "kern", "liga"; + + background-color: var(--main-background-color); + color: var(--main-color); +} + +h1 { + font-size: 1.5rem; /* 24px */ +} +h2 { + font-size: 1.375rem; /* 22px */ +} +h3 { + font-size: 1.25rem; /* 20px */ +} +h1, h2, h3, h4, h5, h6 { + font-weight: 500; +} +h1, h2, h3, h4 { + margin: 20px 0 15px 0; + padding-bottom: 6px; +} +.docblock h3, .docblock h4, h5, h6 { + margin: 15px 0 5px 0; +} +h1.fqn { + margin: 0; + padding: 0; + border-bottom-color: var(--headings-border-bottom-color); +} +h2, h3, h4 { + border-bottom-color: var(--headings-border-bottom-color); +} +.main-heading { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + padding-bottom: 6px; + margin-bottom: 15px; +} +.main-heading a:hover { + text-decoration: underline; +} +#toggle-all-docs { + text-decoration: none; +} +/* The only headings that get underlines are: + Markdown-generated headings within the top-doc + Rustdoc-generated h2 section headings (e.g. "Implementations", "Required Methods", etc) + Underlines elsewhere in the documentation break up visual flow and tend to invert + section hierarchies. */ +h2, +.top-doc .docblock > h3, +.top-doc .docblock > h4 { + border-bottom: 1px solid var(--headings-border-bottom-color); +} +h3.code-header { + font-size: 1.125rem; /* 18px */ +} +h4.code-header { + font-size: 1rem; +} +.code-header { + font-weight: 600; + border-bottom-style: none; + margin: 0; + padding: 0; + margin-top: 0.6em; + margin-bottom: 0.4em; +} +.impl, +.impl-items .method, +.methods .method, +.impl-items .type, +.methods .type, +.impl-items .associatedconstant, +.methods .associatedconstant, +.impl-items .associatedtype, +.methods .associatedtype { + flex-basis: 100%; + font-weight: 600; + position: relative; +} + +div.impl-items > div { + padding-left: 0; +} + +h1, h2, h3, h4, h5, h6, +.sidebar, +.mobile-topbar, +a.source, +.search-input, +.search-results .result-name, +.content table td:first-child > a, +.item-left > a, +.out-of-band, +span.since, +#source-sidebar, #sidebar-toggle, +details.rustdoc-toggle > summary::before, +div.impl-items > div:not(.docblock):not(.item-info), +.content ul.crate a.crate, +a.srclink, +#main-content > .since, +#help-button > button, +details.rustdoc-toggle.top-doc > summary, +details.rustdoc-toggle.top-doc > summary::before, +details.rustdoc-toggle.non-exhaustive > summary, +details.rustdoc-toggle.non-exhaustive > summary::before, +.scraped-example-title, +.more-examples-toggle summary, .more-examples-toggle .hide-more, +.example-links a, +/* This selector is for the items listed in the "all items" page. */ +#main-content > ul.docblock > li > a { + font-family: "Fira Sans", Arial, NanumBarunGothic, sans-serif; +} + +h1, h2, h3, h4, +a#toggle-all-docs, +a.anchor, +.small-section-header a, +#source-sidebar a, +pre.rust a, +.sidebar h2 a, +.sidebar h3 a, +.mobile-topbar h2 a, +.in-band a, +.search-results a, +.module-item .stab, +.import-item .stab, +.result-name .primitive > i, .result-name .keyword > i, +.content .method .where, +.content .fn .where, +.content .where.fmt-newline { + color: var(--main-color); +} + +ol, ul { + padding-left: 24px; +} +ul ul, ol ul, ul ol, ol ol { + margin-bottom: .625em; +} + +p { + /* 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 */ + margin: 0 0 .75em 0; +} + +summary { + outline: none; +} + +/* Fix some style changes due to normalize.css 8 */ + +td, +th { + padding: 0; +} + +table { + border-collapse: collapse; +} + +button, +input, +optgroup, +select, +textarea { + color: inherit; + font: inherit; + margin: 0; +} + +button { + /* Buttons on Safari have different default padding than other platforms. Make them the same. */ + padding: 1px 6px; +} + +/* end tweaks for normalize.css 8 */ + +.rustdoc { + display: flex; + flex-direction: row; + flex-wrap: nowrap; +} + +main { + position: relative; + flex-grow: 1; + padding: 10px 15px 40px 45px; + min-width: 0; +} + +.source main { + padding: 15px; +} + +.width-limiter { + max-width: 960px; + margin-right: auto; +} + +.source .width-limiter { + max-width: unset; +} + +details:not(.rustdoc-toggle) summary { + margin-bottom: .6em; +} + +code, pre, a.test-arrow, .code-header { + font-family: "Source Code Pro", monospace; +} +.docblock code, .docblock-short code { + border-radius: 3px; + padding: 0 0.125em; +} +.docblock pre code, .docblock-short pre code { + padding: 0; +} +pre { + padding: 14px; +} +.docblock.item-decl { + margin-left: 0; +} +.item-decl pre { + overflow-x: auto; +} + +.source .content pre { + padding: 20px; +} + +img { + max-width: 100%; +} + +li { + position: relative; +} + +.source .content { + max-width: none; + overflow: visible; + margin-left: 0px; +} + +nav.sub { + position: relative; + font-size: 1rem; +} + +.sub-container { + display: flex; + flex-direction: row; + flex-wrap: nowrap; +} + +.sub-logo-container { + display: none; + margin-right: 20px; +} + +.source .sub-logo-container { + display: block; +} + +.source .sub-logo-container > img { + height: 60px; + width: 60px; + object-fit: contain; +} + +.sidebar, .mobile-topbar, .sidebar-menu-toggle { + background-color: var(--sidebar-background-color); +} + +.sidebar { + font-size: 0.875rem; + width: 250px; + min-width: 200px; + overflow-y: scroll; + position: sticky; + height: 100vh; + top: 0; + left: 0; +} + +.sidebar-elems, +.sidebar > .location { + padding-left: 24px; +} + +.sidebar .location { + overflow-wrap: anywhere; +} + +.rustdoc.source .sidebar { + width: 50px; + min-width: 0px; + max-width: 300px; + flex-grow: 0; + flex-shrink: 0; + flex-basis: auto; + border-right: 1px solid; + overflow-x: hidden; + /* The sidebar is by default hidden */ + overflow-y: hidden; +} + +.rustdoc.source .sidebar .sidebar-logo { + display: none; +} + +.source .sidebar, #sidebar-toggle, #source-sidebar { + background-color: var(--sidebar-background-color); +} + +#sidebar-toggle > button:hover, #sidebar-toggle > button:focus { + background-color: var(--sidebar-background-color-hover); +} + +.source .sidebar > *:not(#sidebar-toggle) { + opacity: 0; + visibility: hidden; +} + +.source-sidebar-expanded .source .sidebar { + overflow-y: auto; +} + +.source-sidebar-expanded .source .sidebar > *:not(#sidebar-toggle) { + opacity: 1; + visibility: visible; +} + +#all-types { + margin-top: 1em; +} + +/* Improve the scrollbar display on firefox */ +* { + scrollbar-width: initial; + scrollbar-color: var(--scrollbar-color); +} +.sidebar { + scrollbar-width: thin; + scrollbar-color: var(--scrollbar-color); +} + +/* Improve the scrollbar display on webkit-based browsers */ +::-webkit-scrollbar { + width: 12px; +} +.sidebar::-webkit-scrollbar { + width: 8px; +} +::-webkit-scrollbar-track { + -webkit-box-shadow: inset 0; + background-color: var(--scrollbar-track-background-color); +} +.sidebar::-webkit-scrollbar-track { + background-color: var(--scrollbar-track-background-color); +} +::-webkit-scrollbar-thumb, .sidebar::-webkit-scrollbar-thumb { + background-color: var(--scrollbar-thumb-background-color); +} + +/* Everything else */ + +.hidden { + display: none !important; +} + +.sidebar .logo-container { + display: flex; + margin-top: 10px; + margin-bottom: 10px; + justify-content: center; +} + +.version { + overflow-wrap: break-word; +} + +.logo-container > img { + height: 100px; + width: 100px; +} + +.location:empty { + border: none; +} + +.location a:first-of-type { + font-weight: 500; +} + +.block { + padding: 0; +} +.block ul, .block li { + padding: 0; + margin: 0; + list-style: none; +} + +.block a, +h2.location a { + display: block; + padding: 0.25rem; + margin-left: -0.25rem; + + text-overflow: ellipsis; + overflow: hidden; +} + +.sidebar h2 { + border-bottom: none; + font-weight: 500; + padding: 0; + margin: 0; + margin-top: 0.7rem; + margin-bottom: 0.7rem; +} + +.sidebar h3 { + font-size: 1.125rem; /* 18px */ + font-weight: 500; + padding: 0; + margin: 0; +} + +.sidebar-elems .block { + margin-bottom: 2em; +} + +.sidebar-elems .block li a { + white-space: nowrap; +} + +.mobile-topbar { + display: none; +} + +.source .content pre.rust { + white-space: pre; + overflow: auto; + padding-left: 0; +} + +.rustdoc .example-wrap { + display: inline-flex; + margin-bottom: 10px; +} + +.example-wrap { + position: relative; + width: 100%; +} + +.example-wrap > pre.line-number { + overflow: initial; + border: 1px solid; + padding: 13px 8px; + text-align: right; + border-top-left-radius: 5px; + border-bottom-left-radius: 5px; +} + +.example-wrap > pre.rust a:hover { + text-decoration: underline; +} + +.line-numbers { + text-align: right; +} +.rustdoc:not(.source) .example-wrap > pre:not(.line-number) { + width: 100%; + overflow-x: auto; +} + +.rustdoc:not(.source) .example-wrap > pre.line-numbers { + width: auto; + overflow-x: visible; +} + +.rustdoc .example-wrap > pre { + margin: 0; +} + +#search { + position: relative; +} + +.search-loading { + text-align: center; +} + +#results > table { + width: 100%; + table-layout: fixed; +} + +.content > .example-wrap pre.line-numbers { + position: relative; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.line-numbers span { + cursor: pointer; +} + +.docblock-short { + overflow-wrap: break-word; + overflow-wrap: anywhere; +} +.docblock-short p { + display: inline; +} + +.docblock-short p { + overflow: hidden; + text-overflow: ellipsis; + margin: 0; +} +/* Wrap non-pre code blocks (`text`) but not (```text```). */ +.docblock > :not(pre) > code, +.docblock-short > :not(pre) > code { + white-space: pre-wrap; +} + +.top-doc .docblock h2 { font-size: 1.375rem; } +.top-doc .docblock h3 { font-size: 1.25rem; } +.top-doc .docblock h4, +.top-doc .docblock h5 { + font-size: 1.125rem; +} +.top-doc .docblock h6 { + font-size: 1rem; +} + +.docblock h5 { font-size: 1rem; } +.docblock h6 { font-size: 0.875rem; } +.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 { + border-bottom-color: var(--headings-border-bottom-color); +} + +.docblock { + margin-left: 24px; + position: relative; +} + +.docblock > :not(.information):not(.more-examples-toggle) { + max-width: 100%; + overflow-x: auto; +} + +.content .out-of-band { + flex-grow: 0; + font-size: 1.125rem; + font-weight: normal; + float: right; +} + +.method > .code-header, .trait-impl > .code-header { + max-width: calc(100% - 41px); + display: block; +} + +.content .in-band { + flex-grow: 1; + margin: 0px; + padding: 0px; + overflow-wrap: break-word; + overflow-wrap: anywhere; +} + +.in-band > code, .in-band > .code-header { + display: inline-block; +} + +.docblock code, .docblock-short code, +pre, .rustdoc.source .example-wrap { + background-color: var(--code-block-background-color); +} + +#main-content { + position: relative; +} +#main-content > .since { + top: inherit; +} + +.content table:not(.table-display) { + border-spacing: 0 5px; +} +.content td { vertical-align: top; } +.content td:first-child { padding-right: 20px; } +.content td p:first-child { margin-top: 0; } +.content td h1, .content td h2 { margin-left: 0; font-size: 1.125rem; } +.content tr:first-child td { border-top: 0; } + +.docblock table { + margin: .5em 0; + width: calc(100% - 2px); + overflow-x: auto; + display: block; +} + +.docblock table td { + padding: .5em; + border: 1px dashed; +} + +.docblock table th { + padding: .5em; + text-align: left; + border: 1px solid; +} + +.fields + table { + margin-bottom: 1em; +} + +.content .item-list { + list-style-type: none; + padding: 0; +} + +.content .multi-column { + -moz-column-count: 5; + -moz-column-gap: 2.5em; + -webkit-column-count: 5; + -webkit-column-gap: 2.5em; + column-count: 5; + column-gap: 2.5em; +} +.content .multi-column li { width: 100%; display: inline-block; } + +.content > .methods > .method { + font-size: 1rem; + position: relative; +} +/* Shift "where ..." part of method or fn definition down a line */ +.content .method .where, +.content .fn .where, +.content .where.fmt-newline { + display: block; + font-size: 0.875rem; +} + +.content .methods > div:not(.notable-traits):not(.method) { + margin-left: 40px; + margin-bottom: 15px; +} + +.content .docblock > .impl-items { + margin-left: 20px; + margin-top: -34px; +} +.content .docblock >.impl-items .table-display { + margin: 0; +} +.content .docblock >.impl-items table td { + padding: 0; +} +.content .docblock > .impl-items .table-display, .impl-items table td { + border: none; +} + +.item-info { + display: block; +} + +.content .item-info code { + font-size: 0.875rem; +} + +.content .item-info { + position: relative; + margin-left: 24px; +} + +.sub-variant > div > .item-info { + margin-top: initial; +} + +.content .impl-items .docblock, .content .impl-items .item-info { + margin-bottom: .6em; +} + +.content .impl-items > .item-info { + margin-left: 40px; +} + +.methods > .item-info, .content .impl-items > .item-info { + margin-top: -8px; +} + +.impl-items { + flex-basis: 100%; +} + +#main-content > .item-info { + margin-top: 0; + margin-left: 0; +} + +nav.sub { + flex-grow: 1; + margin-bottom: 25px; +} +.source nav.sub { + margin-left: 32px; +} +nav.main { + padding: 20px 0; + text-align: center; +} +nav.main .current { + border-top: 1px solid; + border-bottom: 1px solid; +} +nav.main .separator { + border: 1px solid; + display: inline-block; + height: 23px; + margin: 0 20px; +} +nav.sum { text-align: right; } +nav.sub form { display: inline; } + +a { + text-decoration: none; + background: transparent; +} + +.small-section-header { + display: flex; + justify-content: space-between; + position: relative; +} + +.small-section-header:hover > .anchor { + display: initial; +} + +.in-band:hover > .anchor, .impl:hover > .anchor, .method.trait-impl:hover > .anchor, +.type.trait-impl:hover > .anchor, .associatedconstant.trait-impl:hover > .anchor, +.associatedtype.trait-impl:hover > .anchor { + display: inline-block; + position: absolute; +} +.anchor { + display: none; + position: absolute; + left: -0.5em; + background: none !important; +} +.anchor.field { + left: -5px; +} +.small-section-header > .anchor { + left: -15px; + padding-right: 8px; +} +h2.small-section-header > .anchor { + padding-right: 6px; +} +.anchor::before { + content: '§'; +} + +.docblock a:not(.srclink):not(.test-arrow):not(.scrape-help):hover, +.docblock-short a:not(.srclink):not(.test-arrow):not(.scrape-help):hover, .item-info a { + text-decoration: underline; +} + +.block a.current.crate { font-weight: 500; } + +/* In most contexts we use `overflow-wrap: anywhere` to ensure that we can wrap + as much as needed on mobile (see + src/test/rustdoc-gui/type-declaration-overflow.goml for an example of why + this matters). The `anywhere` value means: + + "Soft wrap opportunities introduced by the word break are considered when + calculating min-content intrinsic sizes." + + https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-wrap#values + + For table layouts, that becomes a problem: the browser tries to make each + column as narrow as possible, and `overflow-wrap: anywhere` means it can do + so by breaking words - even if some other column could be shrunk without + breaking words! This shows up, for instance, in the `Structs` / `Modules` / + `Functions` (etcetera) sections of a module page, and when a docblock + contains a table. + + So, for table layouts, override the default with break-word, which does + _not_ affect min-content intrinsic sizes. +*/ +table, +.item-table { + overflow-wrap: break-word; +} + +.item-table { + display: table; +} +.item-row { + display: table-row; +} +.item-left, .item-right { + display: table-cell; +} +.item-left { + padding-right: 1.25rem; +} + +.search-container { + position: relative; + display: flex; + height: 34px; +} +.search-container > * { + height: 100%; +} +.search-results-title { + display: inline; +} +#search-settings { + font-size: 1.5rem; + font-weight: 500; + margin-bottom: 20px; +} +#crate-search { + min-width: 115px; + margin-top: 5px; + padding-left: 0.15em; + padding-right: 23px; + border: 1px solid; + border-radius: 4px; + outline: none; + cursor: pointer; + -moz-appearance: none; + -webkit-appearance: none; + /* Removes default arrow from firefox */ + background-repeat: no-repeat; + background-color: transparent; + background-size: 20px; + background-position: calc(100% - 1px) 56%; + background-image: /* AUTOREPLACE: */url("down-arrow.svg"); + max-width: 100%; + text-overflow: ellipsis; +} +.search-container { + margin-top: 4px; +} +.search-input { + /* Override Normalize.css: it has a rule that sets + -webkit-appearance: textfield for search inputs. That + causes rounded corners and no border on iOS Safari. */ + -webkit-appearance: none; + /* Override Normalize.css: we have margins and do + not want to overflow - the `moz` attribute is necessary + until Firefox 29, too early to drop at this point */ + -moz-box-sizing: border-box !important; + box-sizing: border-box !important; + outline: none; + border: 1px solid; + border-radius: 2px; + padding: 8px; + font-size: 1rem; + width: 100%; +} + +.search-results { + display: none; + padding-bottom: 2em; +} + +.search-results.active { + display: block; + /* prevent overhanging tabs from moving the first result */ + clear: both; +} + +.search-results .desc > span { + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + display: block; +} + +.search-results > a { + display: block; + width: 100%; + /* A little margin ensures the browser's outlining of focused links has room to display. */ + margin-left: 2px; + margin-right: 2px; + border-bottom: 1px solid #aaa3; +} + +.search-results > a > div { + display: flex; + flex-flow: row wrap; +} + +.search-results .result-name, .search-results div.desc, .search-results .result-description { + width: 50%; +} +.search-results .result-name { + padding-right: 1em; +} + +.search-results .result-name > span { + display: inline-block; + margin: 0; + font-weight: normal; +} + +.popover { + font-size: 1rem; + position: absolute; + right: 0; + z-index: 2; + display: block; + margin-top: 7px; + border-radius: 3px; + border: 1px solid; + font-size: 1rem; +} + +/* This rule is to draw the little arrow connecting the settings menu to the gear icon. */ +.popover::before { + content: ''; + position: absolute; + right: 11px; + border: solid; + border-width: 1px 1px 0 0; + display: inline-block; + padding: 4px; + transform: rotate(-45deg); + top: -5px; +} + +.popover, .popover::before { + background-color: var(--main-background-color); + color: var(--main-color); +} + +#help-button .popover { + max-width: 600px; +} + +#help-button .popover::before { + right: 48px; +} + +#help-button dt { + float: left; + clear: left; + display: block; + margin-right: 0.5rem; +} +#help-button span.top, #help-button span.bottom { + text-align: center; + display: block; + font-size: 1.125rem; +} +#help-button span.top { + text-align: center; + display: block; + margin: 10px 0; + border-bottom: 1px solid; + padding-bottom: 4px; + margin-bottom: 6px; +} +#help-button span.bottom { + clear: both; + border-top: 1px solid; +} +.side-by-side { + text-align: initial; +} +.side-by-side > div { + width: 50%; + float: left; + padding: 0 20px 20px 17px; +} + +.item-info .stab { + width: fit-content; + /* This min-height is needed to unify the height of the stab elements because some of them + have emojis. + */ + min-height: 36px; + display: flex; + align-items: center; + white-space: pre-wrap; +} +.stab { + padding: 3px; + margin-bottom: 5px; + font-size: 0.875rem; + font-weight: normal; +} +.stab p { + display: inline; + margin: 0; +} + +.stab .emoji { + font-size: 1.25rem; +} + +/* Black one-pixel outline around emoji shapes */ +.emoji { + text-shadow: + 1px 0 0 black, + -1px 0 0 black, + 0 1px 0 black, + 0 -1px 0 black; +} + +.module-item .stab, +.import-item .stab { + border-radius: 3px; + display: inline-block; + font-size: 0.875rem; + line-height: 1.2; + margin-bottom: 0; + margin-left: 0.3125em; + padding: 2px; + vertical-align: text-bottom; +} + +.module-item.unstable, +.import-item.unstable { + opacity: 0.65; +} + +.since { + font-weight: normal; + font-size: initial; +} + +.rightside { + padding-left: 12px; + padding-right: 2px; + position: initial; +} + +.impl-items .srclink, .impl .srclink, .methods .srclink { + /* Override header settings otherwise it's too bold */ + font-weight: normal; + font-size: 1rem; +} + +.rightside { + float: right; +} + +.variants_table { + width: 100%; +} + +.variants_table tbody tr td:first-child { + width: 1%; /* make the variant name as small as possible */ +} + +td.summary-column { + width: 100%; +} + +.summary { + padding-right: 0px; +} + +pre.rust .question-mark { + font-weight: bold; +} + +a.test-arrow { + display: inline-block; + visibility: hidden; + position: absolute; + padding: 5px 10px 5px 10px; + border-radius: 5px; + font-size: 1.375rem; + top: 5px; + right: 5px; + z-index: 1; +} +.example-wrap:hover .test-arrow { + visibility: visible; +} +a.test-arrow:hover{ + text-decoration: none; +} + +.code-attribute { + font-weight: 300; +} + +.item-spacer { + width: 100%; + height: 12px; +} + +.out-of-band > span.since { + position: initial; + font-size: 1.25rem; +} + +h3.variant { + font-weight: 600; + font-size: 1.125rem; + margin-bottom: 10px; + border-bottom: none; +} + +.sub-variant h4 { + font-size: 1rem; + font-weight: 400; + border-bottom: none; + margin-top: 0; + margin-bottom: 0; +} + +.sub-variant { + margin-left: 24px; + margin-bottom: 40px; +} + +.sub-variant > .sub-variant-field { + margin-left: 24px; +} + +.toggle-label { + display: inline-block; + margin-left: 4px; + margin-top: 3px; +} + +:target > code, :target > .code-header { + opacity: 1; +} + +:target { + padding-right: 3px; +} + +.information { + position: absolute; + left: -25px; + margin-top: 7px; + z-index: 1; +} + +.tooltip { + position: relative; + display: inline-block; + cursor: pointer; +} + +.tooltip::after { + display: none; + text-align: center; + padding: 5px 3px 3px 3px; + border-radius: 6px; + margin-left: 5px; + font-size: 1rem; +} + +.tooltip.ignore::after { + content: "This example is not tested"; +} +.tooltip.compile_fail::after { + content: "This example deliberately fails to compile"; +} +.tooltip.should_panic::after { + content: "This example panics"; +} +.tooltip.edition::after { + content: "This code runs with edition " attr(data-edition); +} + +.tooltip::before { + content: " "; + position: absolute; + top: 50%; + left: 16px; + margin-top: -5px; + border-width: 5px; + border-style: solid; + display: none; +} + +.tooltip:hover::before, .tooltip:hover::after { + display: inline; +} + +.tooltip.compile_fail, .tooltip.should_panic, .tooltip.ignore { + font-weight: bold; + font-size: 1.25rem; +} + +.notable-traits-tooltip { + display: inline-block; + cursor: pointer; +} + +.notable-traits:hover .notable-traits-tooltiptext, +.notable-traits .notable-traits-tooltiptext.force-tooltip { + display: inline-block; +} + +.notable-traits .notable-traits-tooltiptext { + display: none; + padding: 5px 3px 3px 3px; + border-radius: 6px; + margin-left: 5px; + z-index: 10; + font-size: 1rem; + cursor: default; + position: absolute; + border: 1px solid; +} + +.notable-traits-tooltip::after { + /* The margin on the tooltip does not capture hover events, + this extends the area of hover enough so that mouse hover is not + lost when moving the mouse to the tooltip */ + content: "\00a0\00a0\00a0"; +} + +.notable-traits .notable, .notable-traits .docblock { + margin: 0; +} + +.notable-traits .notable { + margin: 0; + margin-bottom: 13px; + font-size: 1.1875rem; + font-weight: 600; + display: block; +} + +.notable-traits .docblock code.content{ + margin: 0; + padding: 0; + font-size: 1.25rem; +} + +/* Example code has the "Run" button that needs to be positioned relative to the pre */ +pre.rust.rust-example-rendered { + position: relative; +} + +pre.rust { + tab-size: 4; + -moz-tab-size: 4; +} + +.search-failed { + text-align: center; + margin-top: 20px; + display: none; +} + +.search-failed.active { + display: block; +} + +.search-failed > ul { + text-align: left; + max-width: 570px; + margin-left: auto; + margin-right: auto; +} + +#titles { + height: 35px; +} + +#titles > button { + float: left; + width: 33.3%; + text-align: center; + font-size: 1.125rem; + cursor: pointer; + border: 0; + border-top: 2px solid; +} + +#titles > button:first-child:last-child { + margin-right: 1px; + width: calc(100% - 1px); +} + +#titles > button:not(:last-child) { + margin-right: 1px; + width: calc(33.3% - 1px); +} + +#titles > button > div.count { + display: inline-block; + font-size: 1rem; +} + +.notable-traits { + cursor: pointer; + z-index: 2; + margin-left: 5px; +} + +#sidebar-toggle { + position: sticky; + top: 0; + left: 0; + font-weight: bold; + font-size: 1.25rem; + border-bottom: 1px solid; + display: flex; + height: 40px; + justify-content: center; + align-items: center; + z-index: 10; +} +#source-sidebar { + width: 100%; + z-index: 1; + overflow: auto; +} +#source-sidebar > .title { + font-size: 1.5rem; + text-align: center; + border-bottom: 1px solid; + margin-bottom: 6px; +} +#sidebar-toggle > button { + background: none; + color: inherit; + cursor: pointer; + text-align: center; + border: none; + outline: none; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + /* work around button layout strangeness: https://stackoverflow.com/q/7271561 */ + width: 100%; + /* iOS button gradient: https://stackoverflow.com/q/5438567 */ + -webkit-appearance: none; + opacity: 1; +} +#settings-menu, #help-button { + margin-left: 4px; + outline: none; +} + +#copy-path { + height: 34px; +} +#settings-menu > a, #help-button > button, #copy-path { + padding: 5px; + width: 33px; + border: 1px solid; + border-radius: 2px; + cursor: pointer; +} +#settings-menu { + padding: 0; +} +#settings-menu > a, #help-button > button { + padding: 5px; + height: 100%; + display: block; +} + +@keyframes rotating { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} +#settings-menu.rotate > a img { + animation: rotating 2s linear infinite; +} + +.setting-line .radio-line input:checked { + box-shadow: inset 0 0 0 3px var(--main-background-color); + background-color: var(--settings-input-color); +} +.setting-line .radio-line input:focus { + box-shadow: 0 0 1px 1px var(--settings-input-color); +} +/* In here we combine both `:focus` and `:checked` properties. */ +.setting-line .radio-line input:checked:focus { + box-shadow: inset 0 0 0 3px var(--main-background-color), + 0 0 2px 2px var(--settings-input-color); +} +.setting-line .radio-line input:hover { + border-color: var(--settings-input-color) !important; +} +input:checked + .slider { + background-color: var(--settings-input-color); +} + +#help-button > button { + text-align: center; + /* Rare exception to specifying font sizes in rem. Since this is acting + as an icon, it's okay to specify their sizes in pixels. */ + font-size: 20px; + padding-top: 2px; +} + +#copy-path { + background: initial; + margin-left: 10px; + padding: 0; + padding-left: 2px; + border: 0; +} + +#theme-choices { + display: none; + position: absolute; + left: 0; + top: 28px; + border: 1px solid; + border-radius: 3px; + z-index: 1; + cursor: pointer; +} + +#theme-choices > button { + border: none; + width: 100%; + padding: 4px 8px; + text-align: center; + background: rgba(0,0,0,0); + overflow-wrap: normal; +} + +#theme-choices > button:not(:first-child) { + border-top: 1px solid; +} + +kbd { + display: inline-block; + padding: 3px 5px; + font: 15px monospace; + line-height: 10px; + vertical-align: middle; + border: solid 1px; + border-radius: 3px; + cursor: default; +} + +.hidden-by-impl-hider, +.hidden-by-usual-hider { + /* important because of conflicting rule for small screens */ + display: none !important; +} + +#implementations-list > h3 > span.in-band { + width: 100%; +} + +.table-display { + width: 100%; + border: 0; + border-collapse: collapse; + border-spacing: 0; + font-size: 1rem; +} + +.table-display tr td:first-child { + padding-right: 0; +} + +.table-display tr td:last-child { + float: right; +} +.table-display .out-of-band { + position: relative; + font-size: 1.125rem; + display: block; +} + +.table-display td:hover .anchor { + display: block; + top: 2px; + left: -5px; +} + +#main-content > ul { + padding-left: 10px; +} +#main-content > ul > li { + list-style: none; +} + +.non-exhaustive { + margin-bottom: 1em; +} + +details.dir-entry { + padding-left: 4px; +} + +details.dir-entry > summary { + margin: 0 0 0 13px; + list-style-position: outside; + cursor: pointer; +} + +details.dir-entry div.folders, details.dir-entry div.files { + padding-left: 23px; +} + +details.dir-entry a { + display: block; +} + +/* The hideme class is used on summary tags that contain a span with + placeholder text shown only when the toggle is closed. For instance, + "Expand description" or "Show methods". */ +details.rustdoc-toggle > summary.hideme { + cursor: pointer; +} + +details.rustdoc-toggle > summary { + list-style: none; +} +details.rustdoc-toggle > summary::-webkit-details-marker, +details.rustdoc-toggle > summary::marker { + display: none; +} + +details.rustdoc-toggle > summary.hideme > span { + margin-left: 9px; +} + +details.rustdoc-toggle > summary::before { + content: ""; + cursor: pointer; + width: 16px; + height: 16px; + background-repeat: no-repeat; + background-position: top left; + display: inline-block; + vertical-align: middle; + opacity: .5; +} + +/* Screen readers see the text version at the end the line. + Visual readers see the icon at the start of the line, but small and transparent. */ +details.rustdoc-toggle > summary::after { + content: "Expand"; + overflow: hidden; + width: 0; + height: 0; + position: absolute; +} + +details.rustdoc-toggle > summary.hideme::after { + /* "hideme" toggles already have a description when they're contracted */ + content: ""; +} + +details.rustdoc-toggle > summary:focus::before, +details.rustdoc-toggle > summary:hover::before { + opacity: 1; +} + +details.rustdoc-toggle.top-doc > summary, +details.rustdoc-toggle.top-doc > summary::before, +details.rustdoc-toggle.non-exhaustive > summary, +details.rustdoc-toggle.non-exhaustive > summary::before { + font-size: 1rem; +} + +details.non-exhaustive { + margin-bottom: 8px; +} + +details.rustdoc-toggle > summary.hideme::before { + position: relative; +} + +details.rustdoc-toggle > summary:not(.hideme)::before { + position: absolute; + left: -24px; + top: 4px; +} + +.impl-items > details.rustdoc-toggle > summary:not(.hideme)::before { + position: absolute; + left: -24px; +} + +/* When a "hideme" summary is open and the "Expand description" or "Show + methods" text is hidden, we want the [-] toggle that remains to not + affect the layout of the items to its right. To do that, we use + absolute positioning. Note that we also set position: relative + on the parent
to make this work properly. */ +details.rustdoc-toggle[open] > summary.hideme { + position: absolute; +} + +details.rustdoc-toggle { + position: relative; +} + +details.rustdoc-toggle[open] > summary.hideme > span { + display: none; +} + +details.rustdoc-toggle[open] > summary::before, +details.rustdoc-toggle[open] > summary.hideme::before { + background-image: /* AUTOREPLACE: */url("toggle-minus.svg"); +} + +details.rustdoc-toggle > summary::before { + background-image: /* AUTOREPLACE: */url("toggle-plus.svg"); +} + +details.rustdoc-toggle[open] > summary::before, +details.rustdoc-toggle[open] > summary.hideme::before { + width: 16px; + height: 16px; + background-repeat: no-repeat; + background-position: top left; + display: inline-block; + content: ""; +} + +details.rustdoc-toggle[open] > summary::after, +details.rustdoc-toggle[open] > summary.hideme::after { + content: "Collapse"; +} + +/* This is needed in docblocks to have the "▶" element to be on the same line. */ +.docblock summary > * { + display: inline-block; +} + +/* Media Queries */ + +/* +WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY; +If you update this line, then you also need to update the line with the same warning +in storage.js plus the media query with (max-width: 700px) +*/ +@media (min-width: 701px) { + /* In case there is no documentation before a code block, we need to add some margin at the top + to prevent an overlay between the "collapse toggle" and the information tooltip. + However, it's not needed with smaller screen width because the doc/code block is always put + "one line" below. */ + .docblock > .information:first-child > .tooltip { + margin-top: 16px; + } + + /* When we expand the sidebar on the source code page, we hide the logo on the left of the + search bar to have more space. */ + .source-sidebar-expanded .source .sidebar + main .width-limiter .sub-logo-container.rust-logo { + display: none; + } + + .source-sidebar-expanded .source .sidebar { + width: 300px; + } +} + +/* +WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY +If you update this line, then you also need to update the line with the same warning +in storage.js plus the media query with (min-width: 701px) +*/ +@media (max-width: 700px) { + /* When linking to an item with an `id` (for instance, by clicking a link in the sidebar, + or visiting a URL with a fragment like `#method.new`, we don't want the item to be obscured + by the topbar. Anything with an `id` gets scroll-margin-top equal to .mobile-topbar's size. + */ + *[id] { + scroll-margin-top: 45px; + } + + .rustdoc { + padding-top: 0px; + /* Sidebar should overlay main content, rather than pushing main content to the right. + Turn off `display: flex` on the body element. */ + display: block; + } + + main { + padding-left: 15px; + padding-top: 0px; + } + + .rustdoc, + .main-heading { + flex-direction: column; + } + + .content .out-of-band { + text-align: left; + margin-left: initial; + padding: initial; + } + + .content .out-of-band .since::before { + content: "Since "; + } + + #copy-path { + display: none; + } + + /* Hide the logo and item name from the sidebar. Those are displayed + in the mobile-topbar instead. */ + .sidebar .sidebar-logo, + .sidebar .location { + display: none; + } + + .sidebar-elems { + margin-top: 1em; + } + + .sidebar { + position: fixed; + top: 45px; + /* Hide the sidebar offscreen while not in use. Doing this instead of display: none means + the sidebar stays visible for screen readers, which is useful for navigation. */ + left: -1000px; + margin-left: 0; + margin: 0; + padding: 0; + z-index: 11; + /* Reduce height slightly to account for mobile topbar. */ + height: calc(100vh - 45px); + } + + /* The source view uses a different design for the sidebar toggle, and doesn't have a topbar, + so don't bump down the main content or the sidebar. */ + .source main, + .rustdoc.source .sidebar { + top: 0; + padding: 0; + height: 100vh; + border: 0; + } + + .sidebar.shown, + .source-sidebar-expanded .source .sidebar, + .sidebar:focus-within { + left: 0; + } + + .rustdoc.source > .sidebar { + position: fixed; + margin: 0; + z-index: 11; + width: 0; + } + + .mobile-topbar .location a { + padding: 0; + margin: 0; + } + + .mobile-topbar .location { + border: none; + padding: 0; + margin: auto 0.5em auto auto; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + /* Rare exception to specifying font sizes in rem. Since the topbar + height is specified in pixels, this also has to be specified in + pixels to avoid overflowing the topbar when the user sets a bigger + font size. */ + font-size: 24px; + } + + .mobile-topbar .logo-container { + max-height: 45px; + } + + .mobile-topbar .logo-container > img { + max-width: 35px; + max-height: 35px; + margin-left: 20px; + margin-top: 5px; + margin-bottom: 5px; + } + + .mobile-topbar { + display: flex; + flex-direction: row; + position: sticky; + z-index: 10; + font-size: 2rem; + height: 45px; + width: 100%; + left: 0; + top: 0; + } + + .source .mobile-topbar { + display: none; + } + + .sidebar-menu-toggle { + width: 45px; + /* Rare exception to specifying font sizes in rem. Since this is acting + as an icon, it's okay to specify its sizes in pixels. */ + font-size: 32px; + border: none; + } + + .sidebar-elems { + background-color: var(--sidebar-background-color); + } + + .source nav:not(.sidebar).sub { + margin-left: 32px; + } + + .content { + margin-left: 0px; + } + + .source .content { + margin-top: 10px; + } + + #search { + margin-left: 0; + padding: 0; + } + + .anchor { + display: none !important; + } + + .notable-traits { + position: absolute; + left: -22px; + top: 24px; + } + + #titles > button > div.count { + float: left; + width: 100%; + } + + #titles { + height: 50px; + } + + /* Because of ios, we need to actually have a full height sidebar title so the + * actual sidebar can show up. But then we need to make it transparent so we don't + * hide content. The filler just allows to create the background for the sidebar + * title. But because of the absolute position, I had to lower the z-index. + */ + #sidebar-filler { + position: fixed; + left: 45px; + width: calc(100% - 45px); + top: 0; + height: 45px; + z-index: -1; + border-bottom: 1px solid; + } + + #main-content > details.rustdoc-toggle > summary::before, + #main-content > div > details.rustdoc-toggle > summary::before { + left: -11px; + } + + #sidebar-toggle { + position: fixed; + left: 1px; + top: 100px; + width: 30px; + font-size: 1.5rem; + text-align: center; + padding: 0; + z-index: 10; + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; + cursor: pointer; + font-weight: bold; + border: 1px solid; + border-left: 0; + } + + .source-sidebar-expanded #sidebar-toggle { + left: unset; + top: unset; + width: unset; + border-top-right-radius: unset; + border-bottom-right-radius: unset; + position: sticky; + border: 0; + border-bottom: 1px solid; + } + + #source-sidebar { + z-index: 11; + } + + #main-content > .line-numbers { + margin-top: 0; + } + + .notable-traits .notable-traits-tooltiptext { + left: 0; + top: 100%; + } + + /* We don't display the help button on mobile devices. */ + #help-button { + display: none; + } + + /* Display an alternating layout on tablets and phones */ + .item-table { + display: block; + } + .item-row { + display: flex; + flex-flow: column wrap; + } + .item-left, .item-right { + width: 100%; + } + + /* Display an alternating layout on tablets and phones */ + .search-results > a { + border-bottom: 1px solid #aaa9; + padding: 5px 0px; + } + .search-results .result-name, .search-results div.desc, .search-results .result-description { + width: 100%; + } + .search-results div.desc, .search-results .result-description, .item-right { + padding-left: 2em; + } + + .source-sidebar-expanded .source .sidebar { + max-width: 100vw; + width: 100vw; + } + + /* Position of the "[-]" element. */ + details.rustdoc-toggle:not(.top-doc) > summary { + margin-left: 10px; + } + .impl-items > details.rustdoc-toggle > summary:not(.hideme)::before, + #main-content > details.rustdoc-toggle:not(.top-doc) > summary::before, + #main-content > div > details.rustdoc-toggle > summary::before { + left: -11px; + } +} + +@media print { + nav.sidebar, nav.sub, .content .out-of-band, a.srclink, #copy-path, + details.rustdoc-toggle[open] > summary::before, details.rustdoc-toggle > summary::before, + details.rustdoc-toggle.top-doc > summary { + display: none; + } + + .docblock { + margin-left: 0; + } + + main { + padding: 10px; + } +} + +@media (max-width: 464px) { + #titles, #titles > button { + height: 73px; + } + + #main-content > table:not(.table-display) td { + word-break: break-word; + width: 50%; + } + + #crate-search { + border-radius: 4px; + } + + .docblock { + margin-left: 12px; + } + + .docblock code { + overflow-wrap: break-word; + overflow-wrap: anywhere; + } + + .sub-container { + flex-direction: column; + } + + .sub-logo-container { + align-self: center; + } + + .source .sub-logo-container > img { + height: 35px; + width: 35px; + } + + #sidebar-toggle { + top: 10px; + } + .source-sidebar-expanded #sidebar-toggle { + top: unset; + } +} + +.method-toggle summary, +.implementors-toggle summary, +.impl { + margin-bottom: 0.75em; +} + +.method-toggle[open] { + margin-bottom: 2em; +} + +.implementors-toggle[open] { + margin-bottom: 2em; +} + +#trait-implementations-list .method-toggle, +#synthetic-implementations-list .method-toggle, +#blanket-implementations-list .method-toggle { + margin-bottom: 1em; +} + +/* Begin: styles for --scrape-examples feature */ + +.scraped-example-list .scrape-help { + margin-left: 10px; + padding: 0 4px; + font-weight: normal; + font-size: 12px; + position: relative; + bottom: 1px; + background: transparent; + border-width: 1px; + border-style: solid; + border-radius: 50px; +} + +.scraped-example .code-wrapper { + position: relative; + display: flex; + flex-direction: row; + flex-wrap: wrap; + width: 100%; +} + +.scraped-example:not(.expanded) .code-wrapper { + max-height: 240px; +} + +.scraped-example:not(.expanded) .code-wrapper pre { + overflow-y: hidden; + max-height: 240px; + padding-bottom: 0; +} + +.scraped-example:not(.expanded) .code-wrapper pre.line-numbers { + overflow-x: hidden; +} + +.scraped-example .code-wrapper .prev { + position: absolute; + top: 0.25em; + right: 2.25em; + z-index: 100; + cursor: pointer; +} + +.scraped-example .code-wrapper .next { + position: absolute; + top: 0.25em; + right: 1.25em; + z-index: 100; + cursor: pointer; +} + +.scraped-example .code-wrapper .expand { + position: absolute; + top: 0.25em; + right: 0.25em; + z-index: 100; + cursor: pointer; +} + +.scraped-example:not(.expanded) .code-wrapper:before { + content: " "; + width: 100%; + height: 5px; + position: absolute; + z-index: 100; + top: 0; +} + +.scraped-example:not(.expanded) .code-wrapper:after { + content: " "; + width: 100%; + height: 5px; + position: absolute; + z-index: 100; + bottom: 0; +} + +.scraped-example .code-wrapper .line-numbers { + margin: 0; + padding: 14px 0; +} + +.scraped-example .code-wrapper .line-numbers span { + padding: 0 14px; +} + +.scraped-example .code-wrapper .example-wrap { + flex: 1; + overflow-x: auto; + overflow-y: hidden; + margin-bottom: 0; +} + +.scraped-example:not(.expanded) .code-wrapper .example-wrap { + overflow-x: hidden; +} + +.scraped-example .code-wrapper .example-wrap pre.rust { + overflow-x: inherit; + width: inherit; + overflow-y: hidden; +} + + +.more-examples-toggle { + max-width: calc(100% + 25px); + margin-top: 10px; + margin-left: -25px; +} + +.more-examples-toggle .hide-more { + margin-left: 25px; + margin-bottom: 5px; + cursor: pointer; +} + +.more-scraped-examples { + margin-left: 5px; + display: flex; + flex-direction: row; +} + +.more-scraped-examples-inner { + /* 20px is width of toggle-line + toggle-line-inner */ + width: calc(100% - 20px); +} + +.toggle-line { + align-self: stretch; + margin-right: 10px; + margin-top: 5px; + padding: 0 4px; + cursor: pointer; +} + +.toggle-line-inner { + min-width: 2px; + height: 100%; +} + +.more-scraped-examples .scraped-example { + margin-bottom: 20px; +} + +.more-scraped-examples .scraped-example:last-child { + margin-bottom: 0; +} + +.example-links a { + margin-top: 20px; +} + +.example-links ul { + margin-bottom: 0; +} + +/* End: styles for --scrape-examples feature */ diff --git a/src/librustdoc/html/static/css/settings.css b/src/librustdoc/html/static/css/settings.css new file mode 100644 index 000000000..e82ec0426 --- /dev/null +++ b/src/librustdoc/html/static/css/settings.css @@ -0,0 +1,90 @@ +.setting-line { + margin: 0.6em 0 0.6em 0.3em; + position: relative; +} + +.setting-line .choices { + display: flex; + flex-wrap: wrap; +} + +.setting-line .radio-line input { + margin-right: 0.3em; + height: 1.2rem; + width: 1.2rem; + border: 1px solid; + outline: none; + -webkit-appearance: none; + cursor: pointer; + border-radius: 50%; +} +.setting-line .radio-line input + span { + padding-bottom: 1px; +} + +.radio-line .setting-name { + width: 100%; +} + +.radio-line .choice { + margin-top: 0.1em; + margin-bottom: 0.1em; + min-width: 3.8em; + padding: 0.3em; + display: flex; + align-items: center; + cursor: pointer; +} +.radio-line .choice + .choice { + margin-left: 0.5em; +} + +.toggle { + position: relative; + width: 100%; + margin-right: 20px; + display: flex; + align-items: center; + cursor: pointer; +} + +.toggle input { + opacity: 0; + position: absolute; +} + +.slider { + position: relative; + width: 45px; + min-width: 45px; + display: block; + height: 28px; + margin-right: 20px; + cursor: pointer; + background-color: #ccc; + transition: .3s; +} + +.slider:before { + position: absolute; + content: ""; + height: 19px; + width: 19px; + left: 4px; + bottom: 4px; + transition: .3s; +} + +input:checked + .slider:before { + transform: translateX(19px); +} + +.setting-line > .sub-settings { + padding-left: 42px; + width: 100%; + display: block; +} + +#settings .setting-line { + margin: 1.2em 0.6em; +} diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css new file mode 100644 index 000000000..c42cac59b --- /dev/null +++ b/src/librustdoc/html/static/css/themes/ayu.css @@ -0,0 +1,563 @@ +/* +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; + --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; +} + +.slider { + background-color: #ccc; +} +.slider:before { + background-color: white; +} +input:focus + .slider { + box-shadow: 0 0 0 2px #0a84ff, 0 0 0 6px rgba(10, 132, 255, 0.3); +} + +h1, h2, h3, h4 { + color: white; +} +h1.fqn a { + color: #fff; +} +h4 { + border: none; +} + +.in-band { + background-color: #0f1419; +} + +.docblock code { + color: #ffb454; +} +.code-header { + color: #e6e1cf; +} +.docblock pre > code, pre > code { + color: #e6e1cf; +} +span code { + color: #e6e1cf; +} +.docblock a > code { + color: #39AFD7 !important; +} +pre, .rustdoc.source .example-wrap { + color: #e6e1cf; +} + +.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); +} + +.sidebar .current, +.sidebar a:hover { + background-color: transparent; + color: #ffb44c; +} + +.sidebar-elems .location { + color: #ff7733; +} + +.line-numbers span { color: #5c6773; } +.line-numbers .line-highlighted { + color: #708090; + background-color: rgba(255, 236, 164, 0.06); + padding-right: 4px; + border-right: 1px solid #ffb44c; +} + +.docblock table td, .docblock table th { + border-color: #5c6773; +} + +.search-results a:hover { + background-color: #777; +} + +.search-results a:focus { + color: #000 !important; + background-color: #c6afb3; +} +.search-results a { + color: #0096cf; +} +.search-results a div.desc { + color: #c5c5c5; +} + +.content .item-info::before { color: #ccc; } + +.content span.foreigntype, .content a.foreigntype { color: #ffa0a5; } +.content span.union, .content a.union { color: #ffa0a5; } +.content span.constant, .content a.constant, +.content span.static, .content a.static { color: #39AFD7; } +.content span.primitive, .content a.primitive { color: #ffa0a5; } +.content span.traitalias, .content a.traitalias { color: #39AFD7; } +.content span.keyword, .content a.keyword { color: #39AFD7; } + +.content span.externcrate, .content span.mod, .content a.mod { + color: #39AFD7; +} +.content span.struct, .content a.struct { + color: #ffa0a5; +} +.content span.enum, .content a.enum { + color: #ffa0a5; +} +.content span.trait, .content a.trait { + color: #39AFD7; +} +.content span.type, .content a.type { + color: #39AFD7; +} +.content span.type, +.content a.type, +.block a.current.type { color: #39AFD7; } +.content span.associatedtype, +.content a.associatedtype, +.block a.current.associatedtype { color: #39AFD7; } +.content span.fn, .content a.fn, .content span.method, +.content a.method, .content span.tymethod, +.content a.tymethod, .content .fnname { + color: #fdd687; +} +.content span.attr, .content a.attr, .content span.derive, +.content a.derive, .content span.macro, .content a.macro { + color: #a37acc; +} + +.sidebar a { color: #53b1db; } +.sidebar a.current.type { color: #53b1db; } +.sidebar a.current.associatedtype { color: #53b1db; } + +pre.rust .comment { color: #788797; } +pre.rust .doccomment { color: #a1ac88; } + +nav.main .current { + border-top-color: #5c6773; + border-bottom-color: #5c6773; +} +nav.main .separator { + border: 1px solid #5c6773; +} +a { + color: #39AFD7; +} + +.sidebar h2 a, +.sidebar h3 a { + color: white; +} +.search-results a { + color: #0096cf; +} +body.source .example-wrap pre.rust a { + background: #333; +} + +details.rustdoc-toggle > summary.hideme > span, +details.rustdoc-toggle > summary::before { + color: #999; +} + +details.rustdoc-toggle > summary::before { + filter: invert(100%); +} + +#crate-search, .search-input { + background-color: #141920; + border-color: #424c57; +} + +#crate-search { + /* Without the `!important`, the border-color is ignored for ``... + It cannot be in the group above because `.search-input` has a different border color on + hover. */ + border-color: #f0f0f0 !important; +} + +.search-input { + border-color: #e0e0e0; +} + +.search-input:focus { + border-color: #008dfd; +} + +.stab.empty-impl { background: #FFF5D6; border-color: #FFC600; color: #2f2f2f; } +.stab.unstable { background: #FFF5D6; border-color: #FFC600; color: #2f2f2f; } +.stab.deprecated { background: #ffc4c4; border-color: #db7b7b; color: #2f2f2f; } +.stab.must_implement { background: #F3DFFF; border-color: #b07bdb; color: #2f2f2f; } +.stab.portability { background: #F3DFFF; border-color: #b07bdb; color: #2f2f2f; } +.stab.portability > code { background: none; } + +.rightside, +.out-of-band { + color: grey; +} + +.line-numbers :target { background-color: transparent; } + +/* Code highlighting */ +pre.rust .kw { color: #ab8ac1; } +pre.rust .kw-2, pre.rust .prelude-ty { color: #769acb; } +pre.rust .number, pre.rust .string { color: #83a300; } +pre.rust .self, pre.rust .bool-val, pre.rust .prelude-val, +pre.rust .attribute, pre.rust .attribute .ident { color: #ee6868; } +pre.rust .macro, pre.rust .macro-nonterminal { color: #3E999F; } +pre.rust .lifetime { color: #d97f26; } +pre.rust .question-mark { + color: #ff9011; +} + +.example-wrap > pre.line-number { + border-color: #4a4949; +} + +a.test-arrow { + color: #dedede; + background-color: rgba(78, 139, 202, 0.2); +} + +a.test-arrow:hover{ + background-color: #4e8bca; +} + +.toggle-label, +.code-attribute { + color: #999; +} + +:target { + background-color: #494a3d; + border-right: 3px solid #bb7410; +} + +pre.compile_fail { + border-left: 2px solid rgba(255,0,0,.8); +} + +pre.compile_fail:hover, .information:hover + pre.compile_fail { + border-left: 2px solid #f00; +} + +pre.should_panic { + border-left: 2px solid rgba(255,0,0,.8); +} + +pre.should_panic:hover, .information:hover + pre.should_panic { + border-left: 2px solid #f00; +} + +pre.ignore { + border-left: 2px solid rgba(255,142,0,.6); +} + +pre.ignore:hover, .information:hover + pre.ignore { + border-left: 2px solid #ff9200; +} + +.tooltip.compile_fail { + color: rgba(255,0,0,.8); +} + +.information > .compile_fail:hover { + color: #f00; +} + +.tooltip.should_panic { + color: rgba(255,0,0,.8); +} + +.information > .should_panic:hover { + color: #f00; +} + +.tooltip.ignore { + color: rgba(255,142,0,.6); +} + +.information > .ignore:hover { + color: #ff9200; +} + +.search-failed a { + color: #0089ff; +} + +.tooltip::after { + background-color: #000; + color: #fff; + border-color: #000; +} + +.tooltip::before { + border-color: transparent black transparent transparent; +} + +.notable-traits-tooltiptext { + background-color: #111; + border-color: #777; +} + +.notable-traits-tooltiptext .notable { + border-bottom-color: #d2d2d2; +} + +#titles > button:not(.selected) { + background-color: #252525; + border-top-color: #252525; +} + +#titles > button:hover, #titles > button.selected { + border-top-color: #0089ff; + background-color: #353535; +} + +#titles > button > div.count { + color: #888; +} + +@media (max-width: 700px) { + .sidebar-elems { + border-right-color: #000; + } +} + +kbd { + color: #000; + background-color: #fafbfc; + border-color: #d1d5da; + border-bottom-color: #c6cbd1; + box-shadow: inset 0 -1px 0 #c6cbd1; +} + +#settings-menu > a, #help-button > button { + border-color: #e0e0e0; + background: #f0f0f0; + color: #000; +} + +#settings-menu > a:hover, #settings-menu > a:focus, +#help-button > button:hover, #help-button > button:focus { + border-color: #ffb900; +} + +.popover, .popover::before, +#help-button span.top, #help-button span.bottom { + border-color: #d2d2d2; +} + +#copy-path { + color: #999; +} +#copy-path > img { + filter: invert(50%); +} +#copy-path:hover > img { + filter: invert(65%); +} + +#theme-choices { + border-color: #e0e0e0; + background-color: #353535; +} + +#theme-choices > button:not(:first-child) { + border-top-color: #e0e0e0; +} + +#theme-choices > button:hover, #theme-choices > button:focus { + background-color: #4e4e4e; +} + +.search-results .result-name span.alias { + color: #fff; +} +.search-results .result-name span.grey { + color: #ccc; +} + +#source-sidebar > .title { + border-bottom-color: #ccc; +} +#source-sidebar div.files > a:hover, details.dir-entry summary:hover, +#source-sidebar div.files > a:focus, details.dir-entry summary:focus { + background-color: #444; +} +#source-sidebar div.files > a.selected { + background-color: #333; +} + +.scraped-example-list .scrape-help { + border-color: #aaa; + color: #eee; +} +.scraped-example-list .scrape-help:hover { + border-color: white; + color: white; +} +.more-examples-toggle summary, .more-examples-toggle .hide-more { + color: #999; +} +.scraped-example .example-wrap .rust span.highlight { + background: rgb(91, 59, 1); +} +.scraped-example .example-wrap .rust span.highlight.focus { + background: rgb(124, 75, 15); +} +.scraped-example:not(.expanded) .code-wrapper:before { + background: linear-gradient(to bottom, rgba(53, 53, 53, 1), rgba(53, 53, 53, 0)); +} +.scraped-example:not(.expanded) .code-wrapper:after { + background: linear-gradient(to top, rgba(53, 53, 53, 1), rgba(53, 53, 53, 0)); +} +.toggle-line-inner { + background: #999; +} +.toggle-line:hover .toggle-line-inner { + background: #c5c5c5; +} diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css new file mode 100644 index 000000000..b751acff1 --- /dev/null +++ b/src/librustdoc/html/static/css/themes/light.css @@ -0,0 +1,395 @@ +:root { + --main-background-color: white; + --main-color: black; + --settings-input-color: #2196f3; + --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; +} + +.slider { + background-color: #ccc; +} +.slider:before { + background-color: white; +} +input:focus + .slider { + box-shadow: 0 0 0 2px #0a84ff, 0 0 0 6px rgba(10, 132, 255, 0.3); +} + +.in-band { + background-color: white; +} + +.rust-logo { + /* This rule exists to force other themes to explicitly style the logo. + * Rustdoc has a custom linter for this purpose. + */ +} + +.sidebar .current, +.sidebar a:hover { + background-color: #fff; +} + +.line-numbers span { color: #c67e2d; } +.line-numbers .line-highlighted { + background-color: #FDFFD3 !important; +} + +.docblock table td, .docblock table th { + border-color: #ddd; +} + +.search-results a:hover { + background-color: #ddd; +} + +.search-results a:focus { + color: #000 !important; + background-color: #ccc; +} +.search-results a:focus span { color: #000 !important; } +a.result-trait:focus { background-color: #c7b6ff; } +a.result-traitalias:focus { background-color: #c7b6ff; } +a.result-mod:focus, +a.result-externcrate:focus { background-color: #afc6e4; } +a.result-enum:focus { background-color: #e7b1a0; } +a.result-struct:focus { background-color: #e7b1a0; } +a.result-union:focus { background-color: #e7b1a0; } +a.result-fn:focus, +a.result-method:focus, +a.result-tymethod:focus { background-color: #c6afb3; } +a.result-type:focus { background-color: #e7b1a0; } +a.result-associatedtype:focus { background-color: #afc6e4; } +a.result-foreigntype:focus { background-color: #e7b1a0; } +a.result-attr:focus, +a.result-derive:focus, +a.result-macro:focus { background-color: #8ce488; } +a.result-constant:focus, +a.result-static:focus { background-color: #afc6e4; } +a.result-primitive:focus { background-color: #e7b1a0; } +a.result-keyword:focus { background-color: #afc6e4; } + +.content .item-info::before { color: #ccc; } + +.content span.enum, .content a.enum, .block a.current.enum { color: #AD378A; } +.content span.struct, .content a.struct, .block a.current.struct { color: #AD378A; } +.content span.type, .content a.type, .block a.current.type { color: #AD378A; } +.content span.foreigntype, .content a.foreigntype, .block a.current.foreigntype { color: #3873AD; } +.content span.associatedtype, +.content a.associatedtype, +.block a.current.associatedtype { color: #3873AD; } +.content span.attr, .content a.attr, .block a.current.attr, +.content span.derive, .content a.derive, .block a.current.derive, +.content span.macro, .content a.macro, .block a.current.macro { color: #068000; } +.content span.union, .content a.union, .block a.current.union { color: #AD378A; } +.content span.constant, .content a.constant, .block a.current.constant, +.content span.static, .content a.static, .block a.current.static { color: #3873AD; } +.content span.primitive, .content a.primitive, .block a.current.primitive { color: #AD378A; } +.content span.externcrate, +.content span.mod, .content a.mod, .block a.current.mod { color: #3873AD; } +.content span.trait, .content a.trait, .block a.current.trait { color: #6E4FC9; } +.content span.traitalias, .content a.traitalias, .block a.current.traitalias { color: #5137AD; } +.content span.fn, .content a.fn, .block a.current.fn, +.content span.method, .content a.method, .block a.current.method, +.content span.tymethod, .content a.tymethod, .block a.current.tymethod, +.content .fnname { color: #AD7C37; } +.content span.keyword, .content a.keyword, .block a.current.keyword { color: #3873AD; } + +.sidebar a { color: #356da4; } +.sidebar a.current.enum { color: #a63283; } +.sidebar a.current.struct { color: #a63283; } +.sidebar a.current.type { color: #a63283; } +.sidebar a.current.associatedtype { color: #356da4; } +.sidebar a.current.foreigntype { color: #356da4; } +.sidebar a.current.attr, +.sidebar a.current.derive, +.sidebar a.current.macro { color: #067901; } +.sidebar a.current.union { color: #a63283; } +.sidebar a.current.constant +.sidebar a.current.static { color: #356da4; } +.sidebar a.current.primitive { color: #a63283; } +.sidebar a.current.externcrate +.sidebar a.current.mod { color: #356da4; } +.sidebar a.current.trait { color: #6849c3; } +.sidebar a.current.traitalias { color: #4b349e; } +.sidebar a.current.fn, +.sidebar a.current.method, +.sidebar a.current.tymethod { color: #a67736; } +.sidebar a.current.keyword { color: #356da4; } + +nav.main .current { + border-top-color: #000; + border-bottom-color: #000; +} +nav.main .separator { + border: 1px solid #000; +} + +a { + color: #3873AD; +} + +body.source .example-wrap pre.rust a { + background: #eee; +} + +details.rustdoc-toggle > summary.hideme > span, +details.rustdoc-toggle > summary::before { + color: #999; +} + +#crate-search, .search-input { + background-color: white; + border-color: #e0e0e0; +} + +#crate-search { + /* Without the `!important`, the border-color is ignored for `"; + for (const c of crates_list) { + crates += ``; + } + crates += ""; + } + + let typeFilter = ""; + if (results.query.typeFilter !== NO_TYPE_FILTER) { + typeFilter = " (type: " + escape(itemTypes[results.query.typeFilter]) + ")"; + } + + let output = "
" + + `

Results for ${escape(results.query.userQuery)}` + + `${typeFilter}

${crates}
`; + if (results.query.error !== null) { + output += `

Query parser error: "${results.query.error}".

`; + output += "
" + + makeTabHeader(0, "In Names", ret_others[1]) + + "
"; + currentTab = 0; + } else if (results.query.foundElems <= 1 && results.query.returned.length === 0) { + output += "
" + + makeTabHeader(0, "In Names", ret_others[1]) + + makeTabHeader(1, "In Parameters", ret_in_args[1]) + + makeTabHeader(2, "In Return Types", ret_returned[1]) + + "
"; + } else { + const signatureTabTitle = + results.query.elems.length === 0 ? "In Function Return Types" : + results.query.returned.length === 0 ? "In Function Parameters" : + "In Function Signatures"; + output += "
" + + makeTabHeader(0, signatureTabTitle, ret_others[1]) + + "
"; + currentTab = 0; + } + + const resultsElem = document.createElement("div"); + resultsElem.id = "results"; + resultsElem.appendChild(ret_others[0]); + resultsElem.appendChild(ret_in_args[0]); + resultsElem.appendChild(ret_returned[0]); + + search.innerHTML = output; + const crateSearch = document.getElementById("crate-search"); + if (crateSearch) { + crateSearch.addEventListener("input", updateCrate); + } + search.appendChild(resultsElem); + // Reset focused elements. + searchState.showResults(search); + const elems = document.getElementById("titles").childNodes; + searchState.focusedByTab = []; + let i = 0; + for (const elem of elems) { + const j = i; + elem.onclick = () => printTab(j); + searchState.focusedByTab.push(null); + i += 1; + } + printTab(currentTab); + } + + /** + * Perform a search based on the current state of the search input element + * and display the results. + * @param {Event} [e] - The event that triggered this search, if any + * @param {boolean} [forced] + */ + function search(e, forced) { + const params = searchState.getQueryStringParams(); + const query = parseQuery(searchState.input.value.trim()); + + if (e) { + e.preventDefault(); + } + + if (!forced && query.userQuery === currentResults) { + if (query.userQuery.length > 0) { + putBackSearch(); + } + return; + } + + let filterCrates = getFilterCrates(); + + // In case we have no information about the saved crate and there is a URL query parameter, + // we override it with the URL query parameter. + if (filterCrates === null && params["filter-crate"] !== undefined) { + filterCrates = params["filter-crate"]; + } + + // Update document title to maintain a meaningful browser history + searchState.title = "Results for " + query.original + " - Rust"; + + // Because searching is incremental by character, only the most + // recent search query is added to the browser history. + if (browserSupportsHistoryApi()) { + const newURL = buildUrl(query.original, filterCrates); + + if (!history.state && !params.search) { + history.pushState(null, "", newURL); + } else { + history.replaceState(null, "", newURL); + } + } + + showResults( + execQuery(query, searchWords, filterCrates, window.currentCrate), + params.go_to_first, + filterCrates); + } + + /** + * Convert a list of RawFunctionType / ID to object-based FunctionType. + * + * Crates often have lots of functions in them, and it's common to have a large number of + * functions that operate on a small set of data types, so the search index compresses them + * by encoding function parameter and return types as indexes into an array of names. + * + * Even when a general-purpose compression algorithm is used, this is still a win. I checked. + * https://github.com/rust-lang/rust/pull/98475#issue-1284395985 + * + * The format for individual function types is encoded in + * librustdoc/html/render/mod.rs: impl Serialize for RenderType + * + * @param {null|Array} types + * @param {Array<{name: string, ty: number}>} lowercasePaths + * + * @return {Array} + */ + function buildItemSearchTypeAll(types, 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); + } + return { + // `0` is used as a sentinel because it's fewer bytes than `null` + name: pathIndex === 0 ? null : lowercasePaths[pathIndex - 1].name, + ty: pathIndex === 0 ? null : lowercasePaths[pathIndex - 1].ty, + generics: generics, + }; + }); + } + + /** + * Convert from RawFunctionSearchType to FunctionSearchType. + * + * Crates often have lots of functions in them, and function signatures are sometimes complex, + * so rustdoc uses a pretty tight encoding for them. This function converts it to a simpler, + * object-based encoding so that the actual search code is more readable and easier to debug. + * + * The raw function search type format is generated using serde in + * librustdoc/html/render/mod.rs: impl Serialize for IndexItemFunctionType + * + * @param {RawFunctionSearchType} functionSearchType + * @param {Array<{name: string, ty: number}>} lowercasePaths + * + * @return {null|FunctionSearchType} + */ + function buildFunctionSearchType(functionSearchType, lowercasePaths) { + const INPUTS_DATA = 0; + const OUTPUT_DATA = 1; + // `0` is used as a sentinel because it's fewer bytes than `null` + if (functionSearchType === 0) { + return null; + } + let inputs, output; + if (typeof functionSearchType[INPUTS_DATA] === "number") { + const pathIndex = functionSearchType[INPUTS_DATA]; + inputs = [{ + name: pathIndex === 0 ? null : lowercasePaths[pathIndex - 1].name, + ty: pathIndex === 0 ? null : lowercasePaths[pathIndex - 1].ty, + generics: [], + }]; + } else { + inputs = buildItemSearchTypeAll(functionSearchType[INPUTS_DATA], lowercasePaths); + } + if (functionSearchType.length > 1) { + if (typeof functionSearchType[OUTPUT_DATA] === "number") { + const pathIndex = functionSearchType[OUTPUT_DATA]; + output = [{ + name: pathIndex === 0 ? null : lowercasePaths[pathIndex - 1].name, + ty: pathIndex === 0 ? null : lowercasePaths[pathIndex - 1].ty, + generics: [], + }]; + } else { + output = buildItemSearchTypeAll(functionSearchType[OUTPUT_DATA], lowercasePaths); + } + } else { + output = []; + } + return { + inputs, output, + }; + } + + function buildIndex(rawSearchIndex) { + searchIndex = []; + /** + * @type {Array} + */ + const searchWords = []; + let i, word; + let currentIndex = 0; + let id = 0; + + for (const crate in rawSearchIndex) { + if (!hasOwnPropertyRustdoc(rawSearchIndex, crate)) { + continue; + } + + 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 small integer that represents an + * offset in `itemTypes`). d[i] contains the description of that item. + * + * q[i] contains the full path of the item, or an empty string indicating + * "same as q[i-1]". + * + * 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. + * 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. + * Types are also represented as arrays; the first item is an index into the `p` + * array, while the second is a list of types representing any generic parameters. + * + * `a` defines aliases with an Array of pairs: [name, offset], where `offset` + * points into the n/t/d/q/i/f arrays. + * + * `doc` contains the description of the crate. + * + * `p` is a list of path/type pairs. It is used for parents and function parameters. + * + * @type {{ + * doc: string, + * a: Object, + * n: Array, + * t: Array, + * d: Array, + * q: Array, + * i: Array, + * f: Array, + * p: Array, + * }} + */ + const crateCorpus = rawSearchIndex[crate]; + + searchWords.push(crate); + // This object should have exactly the same set of fields as the "row" + // object defined below. Your JavaScript runtime will thank you. + // https://mathiasbynens.be/notes/shapes-ics + const crateRow = { + crate: crate, + ty: 1, // == ExternCrate + name: crate, + path: "", + desc: crateCorpus.doc, + parent: undefined, + type: null, + id: id, + normalizedName: crate.indexOf("_") === -1 ? crate : crate.replace(/_/g, ""), + }; + id += 1; + searchIndex.push(crateRow); + currentIndex += 1; + + // an array of (Number) item types + const itemTypes = crateCorpus.t; + // an array of (String) item names + const itemNames = crateCorpus.n; + // an array of (String) full paths (or empty string for previous path) + const itemPaths = crateCorpus.q; + // an array of (String) descriptions + const itemDescs = crateCorpus.d; + // an array of (Number) the parent path index + 1 to `paths`, or 0 if none + const itemParentIdxs = crateCorpus.i; + // an array of (Object | null) the type of the function, if any + const itemFunctionSearchTypes = crateCorpus.f; + // an array of [(Number) item type, + // (String) name] + const paths = crateCorpus.p; + // an array of [(String) alias name + // [Number] index to items] + const aliases = crateCorpus.a; + + // an array of [{name: String, ty: Number}] + const lowercasePaths = []; + + // convert `rawPaths` entries into object form + // generate normalizedPaths for function search mode + let len = paths.length; + for (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]}; + } + + // convert `item*` into an object form, and construct word indices. + // + // before any analysis is performed lets gather the search terms to + // search against apart from the rest of the data. This is a quick + // 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 + len = itemTypes.length; + let lastPath = ""; + for (i = 0; i < len; ++i) { + // This object should have exactly the same set of fields as the "crateRow" + // object defined above. + if (typeof itemNames[i] === "string") { + word = itemNames[i].toLowerCase(); + searchWords.push(word); + } else { + word = ""; + searchWords.push(""); + } + const row = { + crate: crate, + ty: itemTypes[i], + name: itemNames[i], + path: itemPaths[i] ? itemPaths[i] : lastPath, + desc: itemDescs[i], + parent: itemParentIdxs[i] > 0 ? paths[itemParentIdxs[i] - 1] : undefined, + type: buildFunctionSearchType(itemFunctionSearchTypes[i], lowercasePaths), + id: id, + normalizedName: word.indexOf("_") === -1 ? word : word.replace(/_/g, ""), + }; + id += 1; + searchIndex.push(row); + lastPath = row.path; + crateSize += 1; + } + + if (aliases) { + ALIASES[crate] = Object.create(null); + for (const alias_name in aliases) { + if (!hasOwnPropertyRustdoc(aliases, alias_name)) { + continue; + } + + if (!hasOwnPropertyRustdoc(ALIASES[crate], alias_name)) { + ALIASES[crate][alias_name] = []; + } + for (const local_alias of aliases[alias_name]) { + ALIASES[crate][alias_name].push(local_alias + currentIndex); + } + } + } + currentIndex += crateSize; + } + return searchWords; + } + + /** + * Callback for when the search form is submitted. + * @param {Event} [e] - The event that triggered this call, if any + */ + function onSearchSubmit(e) { + e.preventDefault(); + searchState.clearInputTimeout(); + search(); + } + + function putBackSearch() { + const search_input = searchState.input; + if (!searchState.input) { + return; + } + if (search_input.value !== "" && !searchState.isDisplayed()) { + searchState.showResults(); + if (browserSupportsHistoryApi()) { + history.replaceState(null, "", + buildUrl(search_input.value, getFilterCrates())); + } + document.title = searchState.title; + } + } + + function registerSearchEvents() { + const params = searchState.getQueryStringParams(); + + // Populate search bar with query string search term when provided, + // but only if the input bar is empty. This avoid the obnoxious issue + // where you start trying to do a search, and the index loads, and + // suddenly your search is gone! + if (searchState.input.value === "") { + searchState.input.value = params.search || ""; + } + + const searchAfter500ms = () => { + searchState.clearInputTimeout(); + if (searchState.input.value.length === 0) { + if (browserSupportsHistoryApi()) { + history.replaceState(null, window.currentCrate + " - Rust", + getNakedUrl() + window.location.hash); + } + searchState.hideResults(); + } else { + searchState.timeout = setTimeout(search, 500); + } + }; + searchState.input.onkeyup = searchAfter500ms; + searchState.input.oninput = searchAfter500ms; + document.getElementsByClassName("search-form")[0].onsubmit = onSearchSubmit; + searchState.input.onchange = e => { + if (e.target !== document.activeElement) { + // To prevent doing anything when it's from a blur event. + return; + } + // Do NOT e.preventDefault() here. It will prevent pasting. + searchState.clearInputTimeout(); + // zero-timeout necessary here because at the time of event handler execution the + // pasted content is not in the input field yet. Shouldn’t make any difference for + // change, though. + setTimeout(search, 0); + }; + searchState.input.onpaste = searchState.input.onchange; + + searchState.outputElement().addEventListener("keydown", e => { + // We only handle unmodified keystrokes here. We don't want to interfere with, + // for instance, alt-left and alt-right for history navigation. + if (e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) { + return; + } + // up and down arrow select next/previous search result, or the + // search box if we're already at the top. + if (e.which === 38) { // up + const previous = document.activeElement.previousElementSibling; + if (previous) { + previous.focus(); + } else { + searchState.focus(); + } + e.preventDefault(); + } else if (e.which === 40) { // down + const next = document.activeElement.nextElementSibling; + if (next) { + next.focus(); + } + const rect = document.activeElement.getBoundingClientRect(); + if (window.innerHeight - rect.bottom < rect.height) { + window.scrollBy(0, rect.height); + } + e.preventDefault(); + } else if (e.which === 37) { // left + nextTab(-1); + e.preventDefault(); + } else if (e.which === 39) { // right + nextTab(1); + e.preventDefault(); + } + }); + + searchState.input.addEventListener("keydown", e => { + if (e.which === 40) { // down + focusSearchResult(); + e.preventDefault(); + } + }); + + searchState.input.addEventListener("focus", () => { + putBackSearch(); + }); + + searchState.input.addEventListener("blur", () => { + searchState.input.placeholder = searchState.input.origPlaceholder; + }); + + // Push and pop states are used to add search results to the browser + // history. + if (browserSupportsHistoryApi()) { + // Store the previous so we can revert back to it later. + const previousTitle = document.title; + + window.addEventListener("popstate", e => { + const params = searchState.getQueryStringParams(); + // Revert to the previous title manually since the History + // API ignores the title parameter. + document.title = previousTitle; + // When browsing forward to search results the previous + // search will be repeated, so the currentResults are + // cleared to ensure the search is successful. + currentResults = null; + // Synchronize search bar with query string state and + // perform the search. This will empty the bar if there's + // nothing there, which lets you really go back to a + // previous state with nothing in the bar. + if (params.search && params.search.length > 0) { + searchState.input.value = params.search; + // Some browsers fire "onpopstate" for every page load + // (Chrome), while others fire the event only when actually + // popping a state (Firefox), which is why search() is + // called both here and at the end of the startSearch() + // function. + search(e); + } else { + searchState.input.value = ""; + // When browsing back from search results the main page + // visibility must be reset. + searchState.hideResults(); + } + }); + } + + // This is required in firefox to avoid this problem: Navigating to a search result + // with the keyboard, hitting enter, and then hitting back would take you back to + // the doc page, rather than the search that should overlay it. + // This was an interaction between the back-forward cache and our handlers + // that try to sync state between the URL and the search input. To work around it, + // do a small amount of re-init on page show. + window.onpageshow = () => { + const qSearch = searchState.getQueryStringParams().search; + if (searchState.input.value === "" && qSearch) { + searchState.input.value = qSearch; + } + search(); + }; + } + + function updateCrate(ev) { + if (ev.target.value === "All crates") { + // If we don't remove it from the URL, it'll be picked up again by the search. + const params = searchState.getQueryStringParams(); + const query = searchState.input.value.trim(); + if (!history.state && !params.search) { + history.pushState(null, "", buildUrl(query, null)); + } else { + history.replaceState(null, "", buildUrl(query, null)); + } + } + // In case you "cut" the entry from the search input, then change the crate filter + // before paste back the previous search, you get the old search results without + // the filter. To prevent this, we need to remove the previous results. + currentResults = null; + search(undefined, true); + } + + /** + * @type {Array<string>} + */ + const searchWords = buildIndex(rawSearchIndex); + if (typeof window !== "undefined") { + registerSearchEvents(); + // If there's a search term in the URL, execute the search now. + if (window.searchState.getQueryStringParams().search) { + search(); + } + } + + if (typeof exports !== "undefined") { + exports.initSearch = initSearch; + exports.execQuery = execQuery; + exports.parseQuery = parseQuery; + } + return searchWords; +} + +if (typeof window !== "undefined") { + window.initSearch = initSearch; + if (window.searchIndex !== undefined) { + initSearch(window.searchIndex); + } +} else { + // Running in Node, not a browser. Run initSearch just to produce the + // exports. + initSearch({}); +} + + +})(); diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js new file mode 100644 index 000000000..797b931af --- /dev/null +++ b/src/librustdoc/html/static/js/settings.js @@ -0,0 +1,272 @@ +// Local js definitions: +/* global getSettingValue, getVirtualKey, updateLocalStorage, updateSystemTheme */ +/* global addClass, removeClass, onEach, onEachLazy, blurHandler, elemIsInParent */ +/* global MAIN_ID, getVar, getSettingsButton */ + +"use strict"; + +(function() { + const isSettingsPage = window.location.pathname.endsWith("/settings.html"); + + function changeSetting(settingName, value) { + updateLocalStorage(settingName, value); + + switch (settingName) { + case "theme": + case "preferred-dark-theme": + case "preferred-light-theme": + case "use-system-theme": + updateSystemTheme(); + updateLightAndDark(); + break; + } + } + + function handleKey(ev) { + // Don't interfere with browser shortcuts + if (ev.ctrlKey || ev.altKey || ev.metaKey) { + return; + } + switch (getVirtualKey(ev)) { + case "Enter": + case "Return": + case "Space": + ev.target.checked = !ev.target.checked; + ev.preventDefault(); + break; + } + } + + function showLightAndDark() { + addClass(document.getElementById("theme").parentElement, "hidden"); + removeClass(document.getElementById("preferred-light-theme").parentElement, "hidden"); + removeClass(document.getElementById("preferred-dark-theme").parentElement, "hidden"); + } + + function hideLightAndDark() { + addClass(document.getElementById("preferred-light-theme").parentElement, "hidden"); + addClass(document.getElementById("preferred-dark-theme").parentElement, "hidden"); + removeClass(document.getElementById("theme").parentElement, "hidden"); + } + + function updateLightAndDark() { + if (getSettingValue("use-system-theme") !== "false") { + showLightAndDark(); + } else { + hideLightAndDark(); + } + } + + function setEvents(settingsElement) { + updateLightAndDark(); + onEachLazy(settingsElement.getElementsByClassName("slider"), elem => { + const toggle = elem.previousElementSibling; + const settingId = toggle.id; + const settingValue = getSettingValue(settingId); + if (settingValue !== null) { + toggle.checked = settingValue === "true"; + } + toggle.onchange = function() { + changeSetting(this.id, this.checked); + }; + toggle.onkeyup = handleKey; + toggle.onkeyrelease = handleKey; + }); + onEachLazy(settingsElement.getElementsByClassName("select-wrapper"), elem => { + const select = elem.getElementsByTagName("select")[0]; + const settingId = select.id; + const settingValue = getSettingValue(settingId); + if (settingValue !== null) { + select.value = settingValue; + } + select.onchange = function() { + changeSetting(this.id, this.value); + }; + }); + onEachLazy(settingsElement.querySelectorAll("input[type=\"radio\"]"), elem => { + const settingId = elem.name; + const settingValue = getSettingValue(settingId); + if (settingValue !== null && settingValue !== "null") { + elem.checked = settingValue === elem.value; + } + elem.addEventListener("change", ev => { + changeSetting(ev.target.name, ev.target.value); + }); + }); + } + + /** + * This function builds the sections inside the "settings page". It takes a `settings` list + * as argument which describes each setting and how to render it. It returns a string + * representing the raw HTML. + * + * @param {Array<Object>} settings + * + * @return {string} + */ + function buildSettingsPageSections(settings) { + let output = ""; + + for (const setting of settings) { + output += "<div class=\"setting-line\">"; + const js_data_name = setting["js_name"]; + const setting_name = setting["name"]; + + if (setting["options"] !== undefined) { + // This is a select setting. + output += `<div class="radio-line" id="${js_data_name}">\ + <span class="setting-name">${setting_name}</span>\ + <div class="choices">`; + onEach(setting["options"], option => { + const checked = option === setting["default"] ? " checked" : ""; + + output += `<label for="${js_data_name}-${option}" class="choice">\ + <input type="radio" name="${js_data_name}" \ + id="${js_data_name}-${option}" value="${option}"${checked}>\ + <span>${option}</span>\ + </label>`; + }); + output += "</div></div>"; + } else { + // This is a toggle. + const checked = setting["default"] === true ? " checked" : ""; + output += `<label class="toggle">\ + <input type="checkbox" id="${js_data_name}"${checked}>\ + <span class="slider"></span>\ + <span class="label">${setting_name}</span>\ + </label>`; + } + output += "</div>"; + } + return output; + } + + /** + * This function builds the "settings page" and returns the generated HTML element. + * + * @return {HTMLElement} + */ + function buildSettingsPage() { + const themes = getVar("themes").split(","); + const settings = [ + { + "name": "Use system theme", + "js_name": "use-system-theme", + "default": true, + }, + { + "name": "Theme", + "js_name": "theme", + "default": "light", + "options": themes, + }, + { + "name": "Preferred light theme", + "js_name": "preferred-light-theme", + "default": "light", + "options": themes, + }, + { + "name": "Preferred dark theme", + "js_name": "preferred-dark-theme", + "default": "dark", + "options": themes, + }, + { + "name": "Auto-hide item contents for large items", + "js_name": "auto-hide-large-items", + "default": true, + }, + { + "name": "Auto-hide item methods' documentation", + "js_name": "auto-hide-method-docs", + "default": false, + }, + { + "name": "Auto-hide trait implementation documentation", + "js_name": "auto-hide-trait-implementations", + "default": false, + }, + { + "name": "Directly go to item in search if there is only one result", + "js_name": "go-to-only-result", + "default": false, + }, + { + "name": "Show line numbers on code examples", + "js_name": "line-numbers", + "default": false, + }, + { + "name": "Disable keyboard shortcuts", + "js_name": "disable-shortcuts", + "default": false, + }, + ]; + + // Then we build the DOM. + const elementKind = isSettingsPage ? "section" : "div"; + const innerHTML = `<div class="settings">${buildSettingsPageSections(settings)}</div>`; + const el = document.createElement(elementKind); + el.id = "settings"; + el.className = "popover"; + el.innerHTML = innerHTML; + + if (isSettingsPage) { + document.getElementById(MAIN_ID).appendChild(el); + } else { + el.setAttribute("tabindex", "-1"); + getSettingsButton().appendChild(el); + } + return el; + } + + const settingsMenu = buildSettingsPage(); + + function displaySettings() { + settingsMenu.style.display = ""; + } + + function settingsBlurHandler(event) { + blurHandler(event, getSettingsButton(), window.hidePopoverMenus); + } + + if (isSettingsPage) { + // We replace the existing "onclick" callback to do nothing if clicked. + getSettingsButton().onclick = function(event) { + event.preventDefault(); + }; + } else { + // We replace the existing "onclick" callback. + const settingsButton = getSettingsButton(); + const settingsMenu = document.getElementById("settings"); + settingsButton.onclick = function(event) { + if (elemIsInParent(event.target, settingsMenu)) { + return; + } + event.preventDefault(); + const shouldDisplaySettings = settingsMenu.style.display === "none"; + + window.hidePopoverMenus(); + if (shouldDisplaySettings) { + displaySettings(); + } + }; + settingsButton.onblur = settingsBlurHandler; + settingsButton.querySelector("a").onblur = settingsBlurHandler; + onEachLazy(settingsMenu.querySelectorAll("input"), el => { + el.onblur = settingsBlurHandler; + }); + settingsMenu.onblur = settingsBlurHandler; + } + + // We now wait a bit for the web browser to end re-computing the DOM... + setTimeout(() => { + setEvents(settingsMenu); + // The setting menu is already displayed if we're on the settings page. + if (!isSettingsPage) { + displaySettings(); + } + removeClass(getSettingsButton(), "rotate"); + }, 0); +})(); diff --git a/src/librustdoc/html/static/js/source-script.js b/src/librustdoc/html/static/js/source-script.js new file mode 100644 index 000000000..c45d61429 --- /dev/null +++ b/src/librustdoc/html/static/js/source-script.js @@ -0,0 +1,241 @@ +// From rust: +/* global sourcesIndex */ + +// Local js definitions: +/* global addClass, getCurrentValue, onEachLazy, removeClass, browserSupportsHistoryApi */ +/* global updateLocalStorage */ + +"use strict"; + +(function() { + +const rootPath = document.getElementById("rustdoc-vars").attributes["data-root-path"].value; +let oldScrollPosition = 0; + +const NAME_OFFSET = 0; +const DIRS_OFFSET = 1; +const FILES_OFFSET = 2; + +function closeSidebarIfMobile() { + if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) { + updateLocalStorage("source-sidebar-show", "false"); + } +} + +function createDirEntry(elem, parent, fullPath, hasFoundFile) { + const dirEntry = document.createElement("details"); + const summary = document.createElement("summary"); + + dirEntry.className = "dir-entry"; + + fullPath += elem[NAME_OFFSET] + "/"; + + summary.innerText = elem[NAME_OFFSET]; + dirEntry.appendChild(summary); + + const folders = document.createElement("div"); + folders.className = "folders"; + if (elem[DIRS_OFFSET]) { + for (const dir of elem[DIRS_OFFSET]) { + if (createDirEntry(dir, folders, fullPath, false)) { + dirEntry.open = true; + hasFoundFile = true; + } + } + } + dirEntry.appendChild(folders); + + const files = document.createElement("div"); + files.className = "files"; + if (elem[FILES_OFFSET]) { + for (const file_text of elem[FILES_OFFSET]) { + const file = document.createElement("a"); + file.innerText = file_text; + file.href = rootPath + "src/" + fullPath + file_text + ".html"; + file.addEventListener("click", closeSidebarIfMobile); + const w = window.location.href.split("#")[0]; + if (!hasFoundFile && w === file.href) { + file.className = "selected"; + dirEntry.open = true; + hasFoundFile = true; + } + files.appendChild(file); + } + } + dirEntry.appendChild(files); + parent.appendChild(dirEntry); + return hasFoundFile; +} + +function toggleSidebar() { + const child = this.parentNode.children[0]; + if (child.innerText === ">") { + if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) { + // This is to keep the scroll position on mobile. + oldScrollPosition = window.scrollY; + document.body.style.position = "fixed"; + document.body.style.top = `-${oldScrollPosition}px`; + } + addClass(document.documentElement, "source-sidebar-expanded"); + child.innerText = "<"; + updateLocalStorage("source-sidebar-show", "true"); + } else { + if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) { + // This is to keep the scroll position on mobile. + document.body.style.position = ""; + document.body.style.top = ""; + // The scroll position is lost when resetting the style, hence why we store it in + // `oldScroll`. + window.scrollTo(0, oldScrollPosition); + } + removeClass(document.documentElement, "source-sidebar-expanded"); + child.innerText = ">"; + updateLocalStorage("source-sidebar-show", "false"); + } +} + +function createSidebarToggle() { + const sidebarToggle = document.createElement("div"); + sidebarToggle.id = "sidebar-toggle"; + + const inner = document.createElement("button"); + + if (getCurrentValue("source-sidebar-show") === "true") { + inner.innerText = "<"; + } else { + inner.innerText = ">"; + } + inner.onclick = toggleSidebar; + + sidebarToggle.appendChild(inner); + return sidebarToggle; +} + +// This function is called from "source-files.js", generated in `html/render/mod.rs`. +// eslint-disable-next-line no-unused-vars +function createSourceSidebar() { + const container = document.querySelector("nav.sidebar"); + + const sidebarToggle = createSidebarToggle(); + container.insertBefore(sidebarToggle, container.firstChild); + + const sidebar = document.createElement("div"); + sidebar.id = "source-sidebar"; + + let hasFoundFile = false; + + const title = document.createElement("div"); + title.className = "title"; + title.innerText = "Files"; + sidebar.appendChild(title); + Object.keys(sourcesIndex).forEach(key => { + sourcesIndex[key][NAME_OFFSET] = key; + hasFoundFile = createDirEntry(sourcesIndex[key], sidebar, "", + hasFoundFile); + }); + + container.appendChild(sidebar); + // Focus on the current file in the source files sidebar. + const selected_elem = sidebar.getElementsByClassName("selected")[0]; + if (typeof selected_elem !== "undefined") { + selected_elem.focus(); + } +} + +const lineNumbersRegex = /^#?(\d+)(?:-(\d+))?$/; + +function highlightSourceLines(match) { + if (typeof match === "undefined") { + match = window.location.hash.match(lineNumbersRegex); + } + if (!match) { + return; + } + let from = parseInt(match[1], 10); + let to = from; + if (typeof match[2] !== "undefined") { + to = parseInt(match[2], 10); + } + if (to < from) { + const tmp = to; + to = from; + from = tmp; + } + let elem = document.getElementById(from); + if (!elem) { + return; + } + const x = document.getElementById(from); + if (x) { + x.scrollIntoView(); + } + onEachLazy(document.getElementsByClassName("line-numbers"), e => { + onEachLazy(e.getElementsByTagName("span"), i_e => { + removeClass(i_e, "line-highlighted"); + }); + }); + for (let i = from; i <= to; ++i) { + elem = document.getElementById(i); + if (!elem) { + break; + } + addClass(elem, "line-highlighted"); + } +} + +const handleSourceHighlight = (function() { + let prev_line_id = 0; + + const set_fragment = name => { + const x = window.scrollX, + y = window.scrollY; + if (browserSupportsHistoryApi()) { + history.replaceState(null, null, "#" + name); + highlightSourceLines(); + } else { + location.replace("#" + name); + } + // Prevent jumps when selecting one or many lines + window.scrollTo(x, y); + }; + + return ev => { + let cur_line_id = parseInt(ev.target.id, 10); + // It can happen when clicking not on a line number span. + if (isNaN(cur_line_id)) { + return; + } + ev.preventDefault(); + + if (ev.shiftKey && prev_line_id) { + // Swap selection if needed + if (prev_line_id > cur_line_id) { + const tmp = prev_line_id; + prev_line_id = cur_line_id; + cur_line_id = tmp; + } + + set_fragment(prev_line_id + "-" + cur_line_id); + } else { + prev_line_id = cur_line_id; + + set_fragment(cur_line_id); + } + }; +}()); + +window.addEventListener("hashchange", () => { + const match = window.location.hash.match(lineNumbersRegex); + if (match) { + return highlightSourceLines(match); + } +}); + +onEachLazy(document.getElementsByClassName("line-numbers"), el => { + el.addEventListener("click", handleSourceHighlight); +}); + +highlightSourceLines(); + +window.createSourceSidebar = createSourceSidebar; +})(); diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js new file mode 100644 index 000000000..0c5389d45 --- /dev/null +++ b/src/librustdoc/html/static/js/storage.js @@ -0,0 +1,268 @@ +// storage.js is loaded in the `<head>` of all rustdoc pages and doesn't +// use `async` or `defer`. That means it blocks further parsing and rendering +// of the page: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script. +// This makes it the correct place to act on settings that affect the display of +// the page, so we don't see major layout changes during the load of the page. +"use strict"; + +const darkThemes = ["dark", "ayu"]; +window.currentTheme = document.getElementById("themeStyle"); +window.mainTheme = document.getElementById("mainThemeStyle"); + +// WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY +// If you update this line, then you also need to update the two media queries with the same +// warning in rustdoc.css +window.RUSTDOC_MOBILE_BREAKPOINT = 701; + +const settingsDataset = (function() { + const settingsElement = document.getElementById("default-settings"); + if (settingsElement === null) { + return null; + } + const dataset = settingsElement.dataset; + if (dataset === undefined) { + return null; + } + return dataset; +})(); + +function getSettingValue(settingName) { + const current = getCurrentValue(settingName); + if (current !== null) { + return current; + } + if (settingsDataset !== null) { + // See the comment for `default_settings.into_iter()` etc. in + // `Options::from_matches` in `librustdoc/config.rs`. + const def = settingsDataset[settingName.replace(/-/g,"_")]; + if (def !== undefined) { + return def; + } + } + return null; +} + +const localStoredTheme = getSettingValue("theme"); + +const savedHref = []; + +// eslint-disable-next-line no-unused-vars +function hasClass(elem, className) { + return elem && elem.classList && elem.classList.contains(className); +} + +// eslint-disable-next-line no-unused-vars +function addClass(elem, className) { + if (!elem || !elem.classList) { + return; + } + elem.classList.add(className); +} + +// eslint-disable-next-line no-unused-vars +function removeClass(elem, className) { + if (!elem || !elem.classList) { + return; + } + elem.classList.remove(className); +} + +/** + * Run a callback for every element of an Array. + * @param {Array<?>} arr - The array to iterate over + * @param {function(?)} func - The callback + * @param {boolean} [reversed] - Whether to iterate in reverse + */ +function onEach(arr, func, reversed) { + if (arr && arr.length > 0 && func) { + if (reversed) { + const length = arr.length; + for (let i = length - 1; i >= 0; --i) { + if (func(arr[i])) { + return true; + } + } + } else { + for (const elem of arr) { + if (func(elem)) { + return true; + } + } + } + } + return false; +} + +/** + * Turn an HTMLCollection or a NodeList into an Array, then run a callback + * for every element. This is useful because iterating over an HTMLCollection + * or a "live" NodeList while modifying it can be very slow. + * https://developer.mozilla.org/en-US/docs/Web/API/HTMLCollection + * https://developer.mozilla.org/en-US/docs/Web/API/NodeList + * @param {NodeList<?>|HTMLCollection<?>} lazyArray - An array to iterate over + * @param {function(?)} func - The callback + * @param {boolean} [reversed] - Whether to iterate in reverse + */ +function onEachLazy(lazyArray, func, reversed) { + return onEach( + Array.prototype.slice.call(lazyArray), + func, + reversed); +} + +function updateLocalStorage(name, value) { + try { + window.localStorage.setItem("rustdoc-" + name, value); + } catch (e) { + // localStorage is not accessible, do nothing + } +} + +function getCurrentValue(name) { + try { + return window.localStorage.getItem("rustdoc-" + name); + } catch (e) { + return null; + } +} + +function switchTheme(styleElem, mainStyleElem, newTheme, saveTheme) { + const newHref = mainStyleElem.href.replace( + /\/rustdoc([^/]*)\.css/, "/" + newTheme + "$1" + ".css"); + + // If this new value comes from a system setting or from the previously + // saved theme, no need to save it. + if (saveTheme) { + updateLocalStorage("theme", newTheme); + } + + if (styleElem.href === newHref) { + return; + } + + let found = false; + if (savedHref.length === 0) { + onEachLazy(document.getElementsByTagName("link"), el => { + savedHref.push(el.href); + }); + } + onEach(savedHref, el => { + if (el === newHref) { + found = true; + return true; + } + }); + if (found) { + styleElem.href = newHref; + } +} + +// This function is called from "main.js". +// eslint-disable-next-line no-unused-vars +function useSystemTheme(value) { + if (value === undefined) { + value = true; + } + + updateLocalStorage("use-system-theme", value); + + // update the toggle if we're on the settings page + const toggle = document.getElementById("use-system-theme"); + if (toggle && toggle instanceof HTMLInputElement) { + toggle.checked = value; + } +} + +const updateSystemTheme = (function() { + if (!window.matchMedia) { + // fallback to the CSS computed value + return () => { + const cssTheme = getComputedStyle(document.documentElement) + .getPropertyValue("content"); + + switchTheme( + window.currentTheme, + window.mainTheme, + JSON.parse(cssTheme) || "light", + true + ); + }; + } + + // only listen to (prefers-color-scheme: dark) because light is the default + const mql = window.matchMedia("(prefers-color-scheme: dark)"); + + function handlePreferenceChange(mql) { + const use = theme => { + switchTheme(window.currentTheme, window.mainTheme, theme, true); + }; + // maybe the user has disabled the setting in the meantime! + if (getSettingValue("use-system-theme") !== "false") { + const lightTheme = getSettingValue("preferred-light-theme") || "light"; + const darkTheme = getSettingValue("preferred-dark-theme") || "dark"; + + if (mql.matches) { + use(darkTheme); + } else { + // prefers a light theme, or has no preference + use(lightTheme); + } + // note: we save the theme so that it doesn't suddenly change when + // the user disables "use-system-theme" and reloads the page or + // navigates to another page + } else { + use(getSettingValue("theme")); + } + } + + mql.addListener(handlePreferenceChange); + + return () => { + handlePreferenceChange(mql); + }; +})(); + +function switchToSavedTheme() { + switchTheme( + window.currentTheme, + window.mainTheme, + getSettingValue("theme") || "light", + false + ); +} + +if (getSettingValue("use-system-theme") !== "false" && window.matchMedia) { + // update the preferred dark theme if the user is already using a dark theme + // See https://github.com/rust-lang/rust/pull/77809#issuecomment-707875732 + if (getSettingValue("use-system-theme") === null + && getSettingValue("preferred-dark-theme") === null + && darkThemes.indexOf(localStoredTheme) >= 0) { + updateLocalStorage("preferred-dark-theme", localStoredTheme); + } + + // call the function to initialize the theme at least once! + updateSystemTheme(); +} else { + switchToSavedTheme(); +} + +if (getSettingValue("source-sidebar-show") === "true") { + // At this point in page load, `document.body` is not available yet. + // Set a class on the `<html>` element instead. + addClass(document.documentElement, "source-sidebar-expanded"); +} + +// If we navigate away (for example to a settings page), and then use the back or +// forward button to get back to a page, the theme may have changed in the meantime. +// But scripts may not be re-loaded in such a case due to the bfcache +// (https://web.dev/bfcache/). The "pageshow" event triggers on such navigations. +// Use that opportunity to update the theme. +// We use a setTimeout with a 0 timeout here to put the change on the event queue. +// For some reason, if we try to change the theme while the `pageshow` event is +// running, it sometimes fails to take effect. The problem manifests on Chrome, +// specifically when talking to a remote website with no caching. +window.addEventListener("pageshow", ev => { + if (ev.persisted) { + setTimeout(switchToSavedTheme, 0); + } +}); diff --git a/src/librustdoc/html/static/scrape-examples-help.md b/src/librustdoc/html/static/scrape-examples-help.md new file mode 100644 index 000000000..035b2e18b --- /dev/null +++ b/src/librustdoc/html/static/scrape-examples-help.md @@ -0,0 +1,34 @@ +Rustdoc will automatically scrape examples of documented items from the `examples/` directory of a project. These examples will be included within the generated documentation for that item. For example, if your library contains a public function: + +```rust +// src/lib.rs +pub fn a_func() {} +``` + +And you have an example calling this function: + +```rust +// examples/ex.rs +fn main() { + a_crate::a_func(); +} +``` + +Then this code snippet will be included in the documentation for `a_func`. + +## How to read scraped examples + +Scraped examples are shown as blocks of code from a given file. The relevant item will be highlighted. If the file is larger than a couple lines, only a small window will be shown which you can expand by clicking ↕ in the top-right. If a file contains multiple instances of an item, you can use the ≺ and ≻ buttons to toggle through each instance. + +If there is more than one file that contains examples, then you should click "More examples" to see these examples. + + +## How Rustdoc scrapes examples + +When you run `cargo doc`, Rustdoc will analyze all the crates that match Cargo's `--examples` filter for instances of items that occur in the crates being documented. Then Rustdoc will include the source code of these instances in the generated documentation. + +Rustdoc has a few techniques to ensure this doesn't overwhelm documentation readers, and that it doesn't blow up the page size: + +1. For a given item, a maximum of 5 examples are included in the page. The remaining examples are just links to source code. +2. Only one example is shown by default, and the remaining examples are hidden behind a toggle. +3. For a given file that contains examples, only the item containing the examples will be included in the generated documentation. -- cgit v1.2.3