diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index a5fc07578169e..02885f519363c 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -1,4 +1,4 @@ -use std::collections::BTreeMap; +use std::collections::{BTreeMap, HashMap}; use std::convert::TryFrom; use std::ffi::OsStr; use std::fmt; @@ -216,6 +216,9 @@ pub struct RenderOptions { pub extension_css: Option, /// A map of crate names to the URL to use instead of querying the crate's `html_root_url`. pub extern_html_root_urls: BTreeMap, + /// A map of the default settings (values are as for DOM storage API). Keys should lack the + /// `rustdoc-` prefix. + pub default_settings: HashMap, /// If present, suffix added to CSS/JavaScript files when referencing them in generated pages. pub resource_suffix: String, /// Whether to run the static CSS/JavaScript through a minifier when outputting them. `true` by @@ -374,6 +377,32 @@ impl Options { } }; + let default_settings: Vec> = vec![ + matches + .opt_str("default-theme") + .iter() + .map(|theme| { + vec![ + ("use-system-theme".to_string(), "false".to_string()), + ("theme".to_string(), theme.to_string()), + ] + }) + .flatten() + .collect(), + matches + .opt_strs("default-setting") + .iter() + .map(|s| { + let mut kv = s.splitn(2, '='); + // never panics because `splitn` always returns at least one element + let k = kv.next().unwrap().to_string(); + let v = kv.next().unwrap_or("true").to_string(); + (k, v) + }) + .collect(), + ]; + let default_settings = default_settings.into_iter().flatten().collect(); + let test_args = matches.opt_strs("test-args"); let test_args: Vec = test_args.iter().flat_map(|s| s.split_whitespace()).map(|s| s.to_string()).collect(); @@ -596,6 +625,7 @@ impl Options { themes, extension_css, extern_html_root_urls, + default_settings, resource_suffix, enable_minification, enable_index_page, diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 7239b3c5ba2f6..b089bcb0862a5 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::path::PathBuf; use crate::externalfiles::ExternalHtml; @@ -10,6 +11,7 @@ pub struct Layout { pub logo: String, pub favicon: String, pub external_html: ExternalHtml, + pub default_settings: HashMap, pub krate: String, /// The given user css file which allow to customize the generated /// documentation theme. @@ -53,6 +55,7 @@ pub fn render( \ {style_files}\ + \ \ \ {css_extension}\ @@ -172,6 +175,11 @@ pub fn render( after_content = layout.external_html.after_content, sidebar = Buffer::html().to_display(sidebar), krate = layout.krate, + default_settings = layout + .default_settings + .iter() + .map(|(k, v)| format!(r#" data-{}="{}""#, k.replace('-', "_"), Escape(v))) + .collect::(), style_files = style_files .iter() .filter_map(|t| { diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 2fd06d7e5730f..ca8b811681cc9 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1228,6 +1228,7 @@ fn init_id_map() -> FxHashMap { map.insert("render-detail".to_owned(), 1); map.insert("toggle-all-docs".to_owned(), 1); map.insert("all-types".to_owned(), 1); + map.insert("default-settings".to_owned(), 1); // This is the list of IDs used by rustdoc sections. map.insert("fields".to_owned(), 1); map.insert("variants".to_owned(), 1); diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 1726093c6facb..0621eafd91347 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -392,6 +392,7 @@ impl FormatRenderer for Context { playground_url, sort_modules_alphabetically, themes: style_files, + default_settings, extension_css, resource_suffix, static_root_path, @@ -415,6 +416,7 @@ impl FormatRenderer for Context { logo: String::new(), favicon: String::new(), external_html, + default_settings, krate: krate.name.clone(), css_file_extension: extension_css, generate_search_filter, diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index e382e5aa2348a..28bd1ba5247d6 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -89,7 +89,7 @@ function defocusSearchBar() { "derive", "traitalias"]; - var disableShortcuts = getCurrentValue("rustdoc-disable-shortcuts") === "true"; + var disableShortcuts = getSettingValue("disable-shortcuts") === "true"; var search_input = getSearchInput(); var searchTimeout = null; var toggleAllDocsId = "toggle-all-docs"; @@ -1580,7 +1580,7 @@ function defocusSearchBar() { function showResults(results) { var search = getSearchElement(); if (results.others.length === 1 - && getCurrentValue("rustdoc-go-to-only-result") === "true" + && getSettingValue("go-to-only-result") === "true" // By default, the search DOM element is "empty" (meaning it has no children not // text content). Once a search has been run, it won't be empty, even if you press // ESC or empty the search input (which also "cancels" the search). @@ -2296,7 +2296,7 @@ function defocusSearchBar() { function autoCollapse(pageId, collapse) { if (collapse) { toggleAllDocs(pageId, true); - } else if (getCurrentValue("rustdoc-auto-hide-trait-implementations") !== "false") { + } else if (getSettingValue("auto-hide-trait-implementations") !== "false") { var impl_list = document.getElementById("trait-implementations-list"); if (impl_list !== null) { @@ -2370,8 +2370,8 @@ function defocusSearchBar() { } var toggle = createSimpleToggle(false); - var hideMethodDocs = getCurrentValue("rustdoc-auto-hide-method-docs") === "true"; - var hideImplementors = getCurrentValue("rustdoc-auto-collapse-implementors") !== "false"; + var hideMethodDocs = getSettingValue("auto-hide-method-docs") === "true"; + var hideImplementors = getSettingValue("auto-collapse-implementors") !== "false"; var pageId = getPageId(); var func = function(e) { @@ -2487,7 +2487,7 @@ function defocusSearchBar() { }); } } - var showItemDeclarations = getCurrentValue("rustdoc-auto-hide-" + className); + var showItemDeclarations = getSettingValue("auto-hide-" + className); if (showItemDeclarations === null) { if (className === "enum" || className === "macro") { showItemDeclarations = "false"; @@ -2495,7 +2495,7 @@ function defocusSearchBar() { showItemDeclarations = "true"; } else { // In case we found an unknown type, we just use the "parent" value. - showItemDeclarations = getCurrentValue("rustdoc-auto-hide-declarations"); + showItemDeclarations = getSettingValue("auto-hide-declarations"); } } showItemDeclarations = showItemDeclarations === "false"; @@ -2569,7 +2569,7 @@ function defocusSearchBar() { onEachLazy(document.getElementsByClassName("sub-variant"), buildToggleWrapper); var pageId = getPageId(); - autoCollapse(pageId, getCurrentValue("rustdoc-collapse") === "true"); + autoCollapse(pageId, getSettingValue("collapse") === "true"); if (pageId !== null) { expandSection(pageId); @@ -2592,7 +2592,7 @@ function defocusSearchBar() { (function() { // To avoid checking on "rustdoc-item-attributes" value on every loop... var itemAttributesFunc = function() {}; - if (getCurrentValue("rustdoc-auto-hide-attributes") !== "false") { + if (getSettingValue("auto-hide-attributes") !== "false") { itemAttributesFunc = function(x) { collapseDocs(x.previousSibling.childNodes[0], "toggle"); }; @@ -2611,7 +2611,7 @@ function defocusSearchBar() { (function() { // To avoid checking on "rustdoc-line-numbers" value on every loop... var lineNumbersFunc = function() {}; - if (getCurrentValue("rustdoc-line-numbers") === "true") { + if (getSettingValue("line-numbers") === "true") { lineNumbersFunc = function(x) { var count = x.textContent.split("\n").length; var elems = []; @@ -2768,7 +2768,7 @@ function defocusSearchBar() { } return 0; }); - var savedCrate = getCurrentValue("rustdoc-saved-filter-crate"); + var savedCrate = getSettingValue("saved-filter-crate"); for (var i = 0; i < crates_text.length; ++i) { var option = document.createElement("option"); option.value = crates_text[i]; diff --git a/src/librustdoc/html/static/settings.js b/src/librustdoc/html/static/settings.js index 00a01ac30bcfa..da3378ccf0dd0 100644 --- a/src/librustdoc/html/static/settings.js +++ b/src/librustdoc/html/static/settings.js @@ -14,10 +14,6 @@ } } - function getSettingValue(settingName) { - return getCurrentValue("rustdoc-" + settingName); - } - function setEvents() { var elems = { toggles: document.getElementsByClassName("slider"), diff --git a/src/librustdoc/html/static/storage.js b/src/librustdoc/html/static/storage.js index ef734f260afd5..d081781f14be1 100644 --- a/src/librustdoc/html/static/storage.js +++ b/src/librustdoc/html/static/storage.js @@ -1,10 +1,37 @@ // From rust: -/* global resourcesSuffix */ +/* global resourcesSuffix, getSettingValue */ var darkThemes = ["dark", "ayu"]; var currentTheme = document.getElementById("themeStyle"); var mainTheme = document.getElementById("mainThemeStyle"); -var localStoredTheme = getCurrentValue("rustdoc-theme"); + +var settingsDataset = (function () { + var settingsElement = document.getElementById("default-settings"); + if (settingsElement === null) { + return null; + } + var dataset = settingsElement.dataset; + if (dataset === undefined) { + return null; + } + return dataset; +})(); + +function getSettingValue(settingName) { + var current = getCurrentValue('rustdoc-' + settingName); + if (current !== null) { + return current; + } + if (settingsDataset !== null) { + var def = settingsDataset[settingName.replace(/-/g,'_')]; + if (def !== undefined) { + return def; + } + } + return null; +} + +var localStoredTheme = getSettingValue("theme"); var savedHref = []; @@ -156,9 +183,9 @@ var updateSystemTheme = (function() { function handlePreferenceChange(mql) { // maybe the user has disabled the setting in the meantime! - if (getCurrentValue("rustdoc-use-system-theme") !== "false") { - var lightTheme = getCurrentValue("rustdoc-preferred-light-theme") || "light"; - var darkTheme = getCurrentValue("rustdoc-preferred-dark-theme") || "dark"; + if (getSettingValue("use-system-theme") !== "false") { + var lightTheme = getSettingValue("preferred-light-theme") || "light"; + var darkTheme = getSettingValue("preferred-dark-theme") || "dark"; if (mql.matches) { // prefers a dark theme @@ -181,11 +208,11 @@ var updateSystemTheme = (function() { }; })(); -if (getCurrentValue("rustdoc-use-system-theme") !== "false" && window.matchMedia) { +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 (getCurrentValue("rustdoc-use-system-theme") === null - && getCurrentValue("rustdoc-preferred-dark-theme") === null + if (getSettingValue("use-system-theme") === null + && getSettingValue("preferred-dark-theme") === null && darkThemes.indexOf(localStoredTheme) >= 0) { updateLocalStorage("rustdoc-preferred-dark-theme", localStoredTheme); } @@ -196,7 +223,7 @@ if (getCurrentValue("rustdoc-use-system-theme") !== "false" && window.matchMedia switchTheme( currentTheme, mainTheme, - getCurrentValue("rustdoc-theme") || "light", + getSettingValue("theme") || "light", false ); } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 616f0efcd7567..7efbca5c6c3b7 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -269,6 +269,26 @@ fn opts() -> Vec { "sort modules by where they appear in the program, rather than alphabetically", ) }), + unstable("default-theme", |o| { + o.optopt( + "", + "default-theme", + "Set the default theme. THEME should be the theme name, generally lowercase. \ + If an unknown default theme is specified, the builtin default is used. \ + The set of themes, and the rustdoc built-in default is not stable.", + "THEME", + ) + }), + unstable("default-setting", |o| { + o.optmulti( + "", + "default-setting", + "Default value for a rustdoc setting (used when \"rustdoc-SETTING\" is absent \ + from web browser Local Storage). If VALUE is not supplied, \"true\" is used. \ + Supported SETTINGs and VALUEs are not documented and not stable.", + "SETTING[=VALUE]", + ) + }), stable("theme", |o| { o.optmulti( "",