diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 493aa56fce6ef..6523d0cf3fc89 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -556,7 +556,7 @@ impl Options { )) .emit(); } - themes.push(StylePath { path: theme_file, disabled: true }); + themes.push(StylePath { path: theme_file }); } } diff --git a/src/librustdoc/error.rs b/src/librustdoc/error.rs index 82d0002b98b18..8eadbf63f33d9 100644 --- a/src/librustdoc/error.rs +++ b/src/librustdoc/error.rs @@ -39,7 +39,10 @@ macro_rules! try_none { match $e { Some(e) => e, None => { - return Err(Error::new(io::Error::new(io::ErrorKind::Other, "not found"), $file)); + return Err(::new( + io::Error::new(io::ErrorKind::Other, "not found"), + $file, + )); } } }}; diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 71d7cc1a09dce..3d3fa3aaeaa51 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -2,8 +2,8 @@ use std::path::PathBuf; use rustc_data_structures::fx::FxHashMap; +use crate::error::Error; use crate::externalfiles::ExternalHtml; -use crate::html::escape::Escape; use crate::html::format::{Buffer, Print}; use crate::html::render::{ensure_trailing_slash, StylePath}; @@ -50,10 +50,11 @@ struct PageLayout<'a> { static_root_path: &'a str, page: &'a Page<'a>, layout: &'a Layout, - style_files: String, + themes: Vec, sidebar: String, content: String, krate_with_trailing_slash: String, + crate rustdoc_version: &'a str, } crate fn render( @@ -66,29 +67,24 @@ crate fn render( ) -> String { let static_root_path = page.get_static_root_path(); let krate_with_trailing_slash = ensure_trailing_slash(&layout.krate).to_string(); - let style_files = style_files + let mut themes: Vec = style_files .iter() - .filter_map(|t| t.path.file_stem().map(|stem| (stem, t.disabled))) - .filter_map(|t| t.0.to_str().map(|path| (path, t.1))) - .map(|t| { - format!( - r#""#, - Escape(&format!("{}{}{}", static_root_path, t.0, page.resource_suffix)), - if t.1 { "disabled" } else { "" }, - if t.0 == "light" { "id=\"themeStyle\"" } else { "" } - ) - }) - .collect::(); + .map(StylePath::basename) + .collect::>() + .unwrap_or_default(); + themes.sort(); + let rustdoc_version = rustc_interface::util::version_str().unwrap_or("unknown version"); let content = Buffer::html().to_display(t); // Note: This must happen before making the sidebar. let sidebar = Buffer::html().to_display(sidebar); let teractx = tera::Context::from_serialize(PageLayout { static_root_path, page, layout, - style_files, + themes, sidebar, content, krate_with_trailing_slash, + rustdoc_version, }) .unwrap(); templates.render("page.html", &teractx).unwrap() diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 069862efde640..365d959ad9f3b 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -504,9 +504,9 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { // by the browser as the theme stylesheet. The theme system (hackily) works by // changing the href to this stylesheet. All other themes are disabled to // prevent rule conflicts - scx.style_files.push(StylePath { path: PathBuf::from("light.css"), disabled: false }); - scx.style_files.push(StylePath { path: PathBuf::from("dark.css"), disabled: true }); - scx.style_files.push(StylePath { path: PathBuf::from("ayu.css"), disabled: true }); + scx.style_files.push(StylePath { path: PathBuf::from("light.css") }); + scx.style_files.push(StylePath { path: PathBuf::from("dark.css") }); + scx.style_files.push(StylePath { path: PathBuf::from("ayu.css") }); let dst = output; scx.ensure_dir(&dst)?; @@ -596,9 +596,13 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { page.description = "Settings of Rustdoc"; page.root_path = "./"; - let mut style_files = self.shared.style_files.clone(); let sidebar = "

Settings

"; - style_files.push(StylePath { path: PathBuf::from("settings.css"), disabled: false }); + let theme_names: Vec = self + .shared + .style_files + .iter() + .map(StylePath::basename) + .collect::>()?; let v = layout::render( &self.shared.templates, &self.shared.layout, @@ -607,9 +611,9 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { settings( self.shared.static_root_path.as_deref().unwrap_or("./"), &self.shared.resource_suffix, - &self.shared.style_files, + theme_names, )?, - &style_files, + &self.shared.style_files, ); self.shared.fs.write(settings_file, v)?; if let Some(ref redirections) = self.shared.redirections { diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 24baca285c6ff..39061a119faec 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -64,7 +64,6 @@ use serde::ser::SerializeSeq; use serde::{Serialize, Serializer}; use crate::clean::{self, ItemId, RenderedLink, SelfTy}; -use crate::docfs::PathError; use crate::error::Error; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; @@ -173,8 +172,12 @@ impl Serialize for TypeWithKind { crate struct StylePath { /// The path to the theme crate path: PathBuf, - /// What the `disabled` attribute should be set to in the HTML tag - crate disabled: bool, +} + +impl StylePath { + pub fn basename(&self) -> Result { + Ok(try_none!(try_none!(self.path.file_stem(), &self.path).to_str(), &self.path).to_string()) + } } fn write_srclink(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer) { @@ -353,7 +356,7 @@ enum Setting { js_data_name: &'static str, description: &'static str, default_value: &'static str, - options: Vec<(String, String)>, + options: Vec, }, } @@ -393,10 +396,9 @@ impl Setting { options .iter() .map(|opt| format!( - "", - opt.0, - if opt.0 == default_value { "selected" } else { "" }, - opt.1, + "", + if opt == default_value { "selected" } else { "" }, + name = opt, )) .collect::(), root_path, @@ -421,18 +423,7 @@ impl> From<(&'static str, Vec)> for Setting { } } -fn settings(root_path: &str, suffix: &str, themes: &[StylePath]) -> Result { - let theme_names: Vec<(String, String)> = themes - .iter() - .map(|entry| { - let theme = - try_none!(try_none!(entry.path.file_stem(), &entry.path).to_str(), &entry.path) - .to_string(); - - Ok((theme.clone(), theme)) - }) - .collect::>()?; - +fn settings(root_path: &str, suffix: &str, theme_names: Vec) -> Result { // (id, explanation, default value) let settings: &[Setting] = &[ ( @@ -469,10 +460,11 @@ fn settings(root_path: &str, suffix: &str, themes: &[StylePath]) -> ResultRustdoc settings\ \
{}
\ - ", + \ + ", settings.iter().map(|s| s.display(root_path, suffix)).collect::(), - root_path, - suffix + root_path = root_path, + suffix = suffix )) } diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 2d3b2490677e9..0d5ba8e80d242 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -181,42 +181,34 @@ pub(super) fn write_shared( cx.write_shared(SharedResource::InvocationSpecific { basename: p }, content, &options.emit) }; - fn add_background_image_to_css( - cx: &Context<'_>, - css: &mut String, - rule: &str, - file: &'static str, - ) { - css.push_str(&format!( - "{} {{ background-image: url({}); }}", - rule, - SharedResource::ToolchainSpecific { basename: file } + // Given "foo.svg", return e.g. "url(\"foo1.58.0.svg\")" + fn ver_url(cx: &Context<'_>, basename: &'static str) -> String { + format!( + "url(\"{}\")", + SharedResource::ToolchainSpecific { basename } .path(cx) .file_name() .unwrap() .to_str() .unwrap() - )) + ) } - // Add all the static files. These may already exist, but we just - // overwrite them anyway to make sure that they're fresh and up-to-date. - let mut rustdoc_css = static_files::RUSTDOC_CSS.to_owned(); - add_background_image_to_css( - cx, - &mut rustdoc_css, - "details.undocumented[open] > summary::before, \ - details.rustdoc-toggle[open] > summary::before, \ - details.rustdoc-toggle[open] > summary.hideme::before", - "toggle-minus.svg", - ); - add_background_image_to_css( + // We use the AUTOREPLACE mechanism to inject into our static JS and CSS certain + // values that are only known at doc build time. Since this mechanism is somewhat + // surprising when reading the code, please limit it to rustdoc.css. + write_minify( + "rustdoc.css", + static_files::RUSTDOC_CSS + .replace( + "/* AUTOREPLACE: */url(\"toggle-minus.svg\")", + &ver_url(cx, "toggle-minus.svg"), + ) + .replace("/* AUTOREPLACE: */url(\"toggle-plus.svg\")", &ver_url(cx, "toggle-plus.svg")) + .replace("/* AUTOREPLACE: */url(\"down-arrow.svg\")", &ver_url(cx, "down-arrow.svg")), cx, - &mut rustdoc_css, - "details.undocumented > summary::before, details.rustdoc-toggle > summary::before", - "toggle-plus.svg", - ); - write_minify("rustdoc.css", rustdoc_css, cx, options)?; + options, + )?; // Add all the static files. These may already exist, but we just // overwrite them anyway to make sure that they're fresh and up-to-date. @@ -228,12 +220,12 @@ pub(super) fn write_shared( let mut themes: FxHashSet = FxHashSet::default(); for entry in &cx.shared.style_files { - let theme = try_none!(try_none!(entry.path.file_stem(), &entry.path).to_str(), &entry.path); + let theme = entry.basename()?; let extension = try_none!(try_none!(entry.path.extension(), &entry.path).to_str(), &entry.path); // Handle the official themes - match theme { + match theme.as_str() { "light" => write_minify("light.css", static_files::themes::LIGHT, cx, options)?, "dark" => write_minify("dark.css", static_files::themes::DARK, cx, options)?, "ayu" => write_minify("ayu.css", static_files::themes::AYU, cx, options)?, @@ -265,26 +257,7 @@ pub(super) fn write_shared( let mut themes: Vec<&String> = themes.iter().collect(); themes.sort(); - // FIXME: this should probably not be a toolchain file since it depends on `--theme`. - // But it seems a shame to copy it over and over when it's almost always the same. - // Maybe we can change the representation to move this out of main.js? - write_minify( - "main.js", - static_files::MAIN_JS - .replace( - "/* INSERT THEMES HERE */", - &format!(" = {}", serde_json::to_string(&themes).unwrap()), - ) - .replace( - "/* INSERT RUSTDOC_VERSION HERE */", - &format!( - "rustdoc {}", - rustc_interface::util::version_str().unwrap_or("unknown version") - ), - ), - cx, - options, - )?; + write_minify("main.js", static_files::MAIN_JS, cx, options)?; write_minify("search.js", static_files::SEARCH_JS, cx, options)?; write_minify("settings.js", static_files::SETTINGS_JS, cx, options)?; @@ -292,18 +265,7 @@ pub(super) fn write_shared( write_minify("source-script.js", static_files::sidebar::SOURCE_SCRIPT, cx, options)?; } - { - write_minify( - "storage.js", - format!( - "var resourcesSuffix = \"{}\";{}", - cx.shared.resource_suffix, - static_files::STORAGE_JS - ), - cx, - options, - )?; - } + write_minify("storage.js", static_files::STORAGE_JS, cx, options)?; if cx.shared.layout.scrape_examples_extension { cx.write_minify( diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 0f3eb2ca07d23..61ab502a8503d 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -824,6 +824,7 @@ h2.small-section-header > .anchor { background-color: transparent; background-size: 20px; background-position: calc(100% - 1px) 56%; + background-image: /* AUTOREPLACE: */url("down-arrow.svg"); } .search-container > .top-button { position: absolute; @@ -1604,6 +1605,16 @@ details.rustdoc-toggle[open] > summary.hideme > span { display: none; } +details.undocumented[open] > summary::before, +details.rustdoc-toggle[open] > summary::before, +details.rustdoc-toggle[open] > summary.hideme::before { + background-image: /* AUTOREPLACE: */url("toggle-minus.svg"); +} + +details.undocumented > summary::before, 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: 17px; diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index c9fa72cbaab01..5661d4973342f 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -37,14 +37,29 @@ if (!DOMTokenList.prototype.remove) { }; } -(function () { - var rustdocVars = document.getElementById("rustdoc-vars"); - if (rustdocVars) { - window.rootPath = rustdocVars.attributes["data-root-path"].value; - window.currentCrate = rustdocVars.attributes["data-current-crate"].value; - window.searchJS = rustdocVars.attributes["data-search-js"].value; - window.searchIndexJS = rustdocVars.attributes["data-search-index-js"].value; +// Get a value from the rustdoc-vars div, which is used to convey data from +// Rust to the JS. If there is no such element, return null. +function getVar(name) { + var el = document.getElementById("rustdoc-vars"); + if (el) { + return el.attributes["data-" + name].value; + } else { + return null; } +} + +// Given a basename (e.g. "storage") and an extension (e.g. ".js"), return a URL +// for a resource under the root-path, with the resource-suffix. +function resourcePath(basename, extension) { + return getVar("root-path") + basename + getVar("resource-suffix") + extension; +} + + +(function () { + window.rootPath = getVar("root-path"); + window.currentCrate = getVar("current-crate"); + window.searchJS = resourcePath("search", ".js"); + window.searchIndexJS = resourcePath("search-index", ".js"); var sidebarVars = document.getElementById("sidebar-vars"); if (sidebarVars) { window.sidebarCurrent = { @@ -115,7 +130,7 @@ function hideThemeButtonState() { (function () { var themeChoices = getThemesElement(); var themePicker = getThemePickerElement(); - var availableThemes/* INSERT THEMES HERE */; + var availableThemes = getVar("themes").split(","); function switchThemeButtonState() { if (themeChoices.style.display === "block") { @@ -980,7 +995,7 @@ function hideThemeButtonState() { var rustdoc_version = document.createElement("span"); rustdoc_version.className = "bottom"; var rustdoc_version_code = document.createElement("code"); - rustdoc_version_code.innerText = "/* INSERT RUSTDOC_VERSION HERE */"; + rustdoc_version_code.innerText = "rustdoc " + getVar("rustdoc-version"); rustdoc_version.appendChild(rustdoc_version_code); container.appendChild(rustdoc_version); diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js index 78ed17e6899e9..606c237aea7d0 100644 --- a/src/librustdoc/html/static/js/storage.js +++ b/src/librustdoc/html/static/js/storage.js @@ -1,5 +1,3 @@ -// From rust: -/* global resourcesSuffix */ var darkThemes = ["dark", "ayu"]; window.currentTheme = document.getElementById("themeStyle"); window.mainTheme = document.getElementById("mainThemeStyle"); @@ -107,9 +105,8 @@ function getCurrentValue(name) { } function switchTheme(styleElem, mainStyleElem, newTheme, saveTheme) { - var fullBasicCss = "rustdoc" + resourcesSuffix + ".css"; - var fullNewTheme = newTheme + resourcesSuffix + ".css"; - var newHref = mainStyleElem.href.replace(fullBasicCss, fullNewTheme); + var 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. diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html index cf57d4cf3aa43..2a783c6da57e4 100644 --- a/src/librustdoc/html/templates/page.html +++ b/src/librustdoc/html/templates/page.html @@ -12,7 +12,16 @@ {#- -#} - {{- style_files | safe -}} + {%- for theme in themes -%} + + {%- endfor -%}