From 2e10475fdd764365255596e4cb0c21b521456823 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Wed, 23 Sep 2020 22:14:43 +0100 Subject: [PATCH 1/7] rustdoc: js: Use getSettingValue for all rustdoc-* values Currently, storage.js and main.js have many open-coded calls to getCurrentValue for "rustdoc-" values, but these are settings and should be handled by getSettingValue. So make getSettingValue part of storage.js (where everyone can call it) and use it everywhere. No functional change yet. We are going to make getSettingValue do something more sophisticated in a moment. Signed-off-by: Ian Jackson --- src/librustdoc/html/static/main.js | 22 +++++++++++----------- src/librustdoc/html/static/settings.js | 4 ---- src/librustdoc/html/static/storage.js | 23 ++++++++++++++--------- 3 files changed, 25 insertions(+), 24 deletions(-) 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..179d713205759 100644 --- a/src/librustdoc/html/static/storage.js +++ b/src/librustdoc/html/static/storage.js @@ -1,10 +1,15 @@ // 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"); + +function getSettingValue(settingName) { + return getCurrentValue('rustdoc-' + settingName); +} + +var localStoredTheme = getSettingValue("theme"); var savedHref = []; @@ -156,9 +161,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 +186,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 +201,7 @@ if (getCurrentValue("rustdoc-use-system-theme") !== "false" && window.matchMedia switchTheme( currentTheme, mainTheme, - getCurrentValue("rustdoc-theme") || "light", + getSettingValue("theme") || "light", false ); } From 5cd96d638c37dc7f92cb8b2fc84a3f7bfe7b7960 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Wed, 23 Sep 2020 22:44:54 +0100 Subject: [PATCH 2/7] rustdoc: Provide a way to set the default settings from Rust code rustdoc has various user-configurable preferences. These are recorded in web Local Storage (where available). But we want to provide a way to configure the default default, including for when web storage is not available. getSettingValue is the function responsible for looking up these settings. Here we make it fall back some in-DOM data, which ultimately comes from RenderOptions.default_settings. Using HTML data atrtributes is fairly convenient here, dsspite the need to transform between snake and kebab case to avoid the DOM converting kebab case to camel case (!) We cache the element and dataset lookup in a global variable, to ensure that getSettingValue remains fast. The DOM representation has to be in an element which precedes the inclusion of storage.js. That means it has to be in the and we should not use an empty
as the container (although most browsers will accept that). An empty \ \ \ {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/storage.js b/src/librustdoc/html/static/storage.js index 179d713205759..d081781f14be1 100644 --- a/src/librustdoc/html/static/storage.js +++ b/src/librustdoc/html/static/storage.js @@ -5,8 +5,30 @@ var darkThemes = ["dark", "ayu"]; var currentTheme = document.getElementById("themeStyle"); var mainTheme = document.getElementById("mainThemeStyle"); +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) { - return getCurrentValue('rustdoc-' + 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"); From d8a449756172f7be072b87a545bacf91e10d1bb9 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 13 Oct 2020 18:52:43 +0100 Subject: [PATCH 3/7] rustdoc: Provide a general --default-setting SETTING[=VALUE] option We just plumb through what the user tells us. This is flagged as unstable, mostly because I don't understand the compatibility rules that rustdoc obeys for local storage data, and how error handling of invalid data works. We collect() the needed HashMap from Vec of Vecs of (key, value) pairs, so that there is a nice place to add new more-specific options. It would have been possible to use Extend::extend but doing it this way ensures that all the used inputs are (and will stay) right next to each other. Signed-off-by: Ian Jackson --- src/librustdoc/config.rs | 16 +++++++++++++++- src/librustdoc/html/layout.rs | 2 +- src/librustdoc/lib.rs | 10 ++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index baa0a9341267a..45106c5dbf6a1 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -377,6 +377,20 @@ impl Options { } }; + let mut default_settings: Vec> = vec![ + matches + .opt_strs("default-setting") + .iter() + .map(|s| { + let mut kv = s.splitn(2, '='); + let k = kv.next().unwrap().to_string(); + let v = kv.next().unwrap_or("true").to_string(); + (k, v) + }) + .collect(), + ]; + let default_settings = default_settings.drain(..).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(); @@ -599,7 +613,7 @@ impl Options { themes, extension_css, extern_html_root_urls, - default_settings: Default::default(), + default_settings, resource_suffix, enable_minification, enable_index_page, diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 5489113366258..29e44922c76a2 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -178,7 +178,7 @@ pub fn render( default_settings = layout .default_settings .iter() - .map(|(k, v)| format!(r#" data-{}="{}""#, k.replace('-',"_"), Escape(v),)) + .map(|(k, v)| format!(r#" data-{}="{}""#, k.replace('-', "_"), Escape(v),)) .collect::(), style_files = style_files .iter() diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 616f0efcd7567..90c77488ee945 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -269,6 +269,16 @@ fn opts() -> Vec { "sort modules by where they appear in the program, rather than alphabetically", ) }), + 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( "", From 709efd9df6e21ca07c7c0cceea468663f8a52c23 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Wed, 28 Oct 2020 17:53:12 +0000 Subject: [PATCH 4/7] rustdoc: Provide a --default-theme THEME option This is a fairly simple special case of --default-eetting. We must set both "theme" and "use-system-theme". Providing it separately enables us to document a way to set the theme without expoosing the individual settings keywords, which are quite complex. Signed-off-by: Ian Jackson --- src/librustdoc/config.rs | 11 +++++++++++ src/librustdoc/lib.rs | 10 ++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 45106c5dbf6a1..2558f9e0d7897 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -378,6 +378,17 @@ impl Options { }; let mut 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() diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 90c77488ee945..54463d5c3758e 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -269,6 +269,16 @@ 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( "", From 39b80cb7c03ad3991679523b2c64e52d897d6673 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Wed, 28 Oct 2020 20:12:15 +0000 Subject: [PATCH 5/7] rustdoc: Fix some nits * Remove a needless comma in the Rust code * Replace double spaces after full stops with single spaces Requested-by: @GuillaumeGomez Signed-off-by: Ian Jackson --- src/librustdoc/config.rs | 2 +- src/librustdoc/html/layout.rs | 2 +- src/librustdoc/lib.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 2558f9e0d7897..3b6b3a826e2aa 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -216,7 +216,7 @@ 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 + /// 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. diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 29e44922c76a2..b089bcb0862a5 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -178,7 +178,7 @@ pub fn render( default_settings = layout .default_settings .iter() - .map(|(k, v)| format!(r#" data-{}="{}""#, k.replace('-', "_"), Escape(v),)) + .map(|(k, v)| format!(r#" data-{}="{}""#, k.replace('-', "_"), Escape(v))) .collect::(), style_files = style_files .iter() diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 54463d5c3758e..7efbca5c6c3b7 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -273,7 +273,7 @@ fn opts() -> Vec { o.optopt( "", "default-theme", - "Set the default theme. THEME should be the theme name, generally lowercase. \ + "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", @@ -284,7 +284,7 @@ fn opts() -> Vec { "", "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. \ + 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]", ) From 1d6c8602770675d0c2001e2f8675c8a31a5b5c42 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Wed, 28 Oct 2020 21:25:47 +0000 Subject: [PATCH 6/7] Add a comment about non-panicking of splitn().next().unwrap() Co-authored-by: Joshua Nelson --- src/librustdoc/config.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 3b6b3a826e2aa..7c6017b39dff2 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -394,6 +394,7 @@ impl Options { .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) From 776e204609fe4c664eb64af47703427807627c8e Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Wed, 28 Oct 2020 21:29:21 +0000 Subject: [PATCH 7/7] rustdoc: Use Vec::into_iter() rather than drain() This allows removing a `mut` which is nicer. Suggested-by: @jyn514 Signed-off-by: Ian Jackson --- src/librustdoc/config.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 7c6017b39dff2..02885f519363c 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -377,7 +377,7 @@ impl Options { } }; - let mut default_settings: Vec> = vec![ + let default_settings: Vec> = vec![ matches .opt_str("default-theme") .iter() @@ -401,7 +401,7 @@ impl Options { }) .collect(), ]; - let default_settings = default_settings.drain(..).flatten().collect(); + let default_settings = default_settings.into_iter().flatten().collect(); let test_args = matches.opt_strs("test-args"); let test_args: Vec =