Rollup merge of #91062 - jsha:static-file-replace, r=jyn514,GuillaumeGomez
rustdoc: Consolidate static-file replacement mechanism There were a few places in rustdoc where we would take static JS or CSS and rewrite it at doc generation time to insert values. This consolidates all the CSS instances into one CSS file and replaces the JS examples with data- attributes on the rustdoc-vars div. Demo https://rustdoc.crud.net/jsha/static-file-replace/test_docs/ r? ``@GuillaumeGomez``
This commit is contained in:
commit
55f8b5f559
@ -552,7 +552,7 @@ fn println_condition(condition: Condition) {
|
||||
))
|
||||
.emit();
|
||||
}
|
||||
themes.push(StylePath { path: theme_file, disabled: true });
|
||||
themes.push(StylePath { path: theme_file });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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(<crate::error::Error as crate::docfs::PathError>::new(
|
||||
io::Error::new(io::ErrorKind::Other, "not found"),
|
||||
$file,
|
||||
));
|
||||
}
|
||||
}
|
||||
}};
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
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<String>,
|
||||
sidebar: String,
|
||||
content: String,
|
||||
krate_with_trailing_slash: String,
|
||||
crate rustdoc_version: &'a str,
|
||||
}
|
||||
|
||||
crate fn render<T: Print, S: Print>(
|
||||
@ -66,29 +67,24 @@ struct PageLayout<'a> {
|
||||
) -> 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<String> = 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#"<link rel="stylesheet" type="text/css" href="{}.css" {} {}>"#,
|
||||
Escape(&format!("{}{}{}", static_root_path, t.0, page.resource_suffix)),
|
||||
if t.1 { "disabled" } else { "" },
|
||||
if t.0 == "light" { "id=\"themeStyle\"" } else { "" }
|
||||
)
|
||||
})
|
||||
.collect::<String>();
|
||||
.map(StylePath::basename)
|
||||
.collect::<Result<_, Error>>()
|
||||
.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()
|
||||
|
@ -504,9 +504,9 @@ fn init(
|
||||
// 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 @@ fn after_krate(&mut self) -> Result<(), Error> {
|
||||
page.description = "Settings of Rustdoc";
|
||||
page.root_path = "./";
|
||||
|
||||
let mut style_files = self.shared.style_files.clone();
|
||||
let sidebar = "<h2 class=\"location\">Settings</h2><div class=\"sidebar-elems\"></div>";
|
||||
style_files.push(StylePath { path: PathBuf::from("settings.css"), disabled: false });
|
||||
let theme_names: Vec<String> = self
|
||||
.shared
|
||||
.style_files
|
||||
.iter()
|
||||
.map(StylePath::basename)
|
||||
.collect::<Result<_, Error>>()?;
|
||||
let v = layout::render(
|
||||
&self.shared.templates,
|
||||
&self.shared.layout,
|
||||
@ -607,9 +611,9 @@ fn after_krate(&mut self) -> Result<(), Error> {
|
||||
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 {
|
||||
|
@ -64,7 +64,6 @@
|
||||
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 @@ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
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<String, Error> {
|
||||
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<String>,
|
||||
},
|
||||
}
|
||||
|
||||
@ -393,10 +396,9 @@ fn display(&self, root_path: &str, suffix: &str) -> String {
|
||||
options
|
||||
.iter()
|
||||
.map(|opt| format!(
|
||||
"<option value=\"{}\" {}>{}</option>",
|
||||
opt.0,
|
||||
if opt.0 == default_value { "selected" } else { "" },
|
||||
opt.1,
|
||||
"<option value=\"{name}\" {}>{name}</option>",
|
||||
if opt == default_value { "selected" } else { "" },
|
||||
name = opt,
|
||||
))
|
||||
.collect::<String>(),
|
||||
root_path,
|
||||
@ -421,18 +423,7 @@ fn from(values: (&'static str, Vec<T>)) -> Setting {
|
||||
}
|
||||
}
|
||||
|
||||
fn settings(root_path: &str, suffix: &str, themes: &[StylePath]) -> Result<String, Error> {
|
||||
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::<Result<_, Error>>()?;
|
||||
|
||||
fn settings(root_path: &str, suffix: &str, theme_names: Vec<String>) -> Result<String, Error> {
|
||||
// (id, explanation, default value)
|
||||
let settings: &[Setting] = &[
|
||||
(
|
||||
@ -469,10 +460,11 @@ fn settings(root_path: &str, suffix: &str, themes: &[StylePath]) -> Result<Strin
|
||||
<span class=\"in-band\">Rustdoc settings</span>\
|
||||
</h1>\
|
||||
<div class=\"settings\">{}</div>\
|
||||
<script src=\"{}settings{}.js\"></script>",
|
||||
<link rel=\"stylesheet\" href=\"{root_path}settings{suffix}.css\">\
|
||||
<script src=\"{root_path}settings{suffix}.js\"></script>",
|
||||
settings.iter().map(|s| s.display(root_path, suffix)).collect::<String>(),
|
||||
root_path,
|
||||
suffix
|
||||
root_path = root_path,
|
||||
suffix = suffix
|
||||
))
|
||||
}
|
||||
|
||||
|
@ -181,42 +181,34 @@ fn write_minify(
|
||||
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(
|
||||
// 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[open] > summary::before, \
|
||||
details.rustdoc-toggle[open] > summary::before, \
|
||||
details.rustdoc-toggle[open] > summary.hideme::before",
|
||||
"toggle-minus.svg",
|
||||
);
|
||||
add_background_image_to_css(
|
||||
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 @@ fn add_background_image_to_css(
|
||||
let mut themes: FxHashSet<String> = 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 @@ fn add_background_image_to_css(
|
||||
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 @@ fn add_background_image_to_css(
|
||||
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(
|
||||
|
@ -828,6 +828,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;
|
||||
@ -1610,6 +1611,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;
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -12,7 +12,16 @@
|
||||
<link rel="stylesheet" type="text/css" {# -#}
|
||||
href="{{static_root_path | safe}}rustdoc{{page.resource_suffix}}.css" {# -#}
|
||||
id="mainThemeStyle"> {#- -#}
|
||||
{{- style_files | safe -}}
|
||||
{%- for theme in themes -%}
|
||||
<link rel="stylesheet" type="text/css" {# -#}
|
||||
href="{{static_root_path | safe}}{{theme}}{{page.resource_suffix}}.css" {#- -#}
|
||||
{%- if theme == "light" -%}
|
||||
id="themeStyle"
|
||||
{%- else -%}
|
||||
disabled
|
||||
{%- endif -%}
|
||||
>
|
||||
{%- endfor -%}
|
||||
<script id="default-settings" {# -#}
|
||||
{% for k, v in layout.default_settings %}
|
||||
data-{{k}}="{{v}}"
|
||||
@ -49,11 +58,6 @@
|
||||
href="{{static_root_path | safe}}favicon{{page.resource_suffix}}.svg"> {#- -#}
|
||||
{%- endif -%}
|
||||
{{- layout.external_html.in_header | safe -}}
|
||||
<style type="text/css"> {#- -#}
|
||||
#crate-search{ {#- -#}
|
||||
background-image:url("{{static_root_path | safe}}down-arrow{{page.resource_suffix}}.svg"); {#- -#}
|
||||
} {#- -#}
|
||||
</style> {#- -#}
|
||||
</head> {#- -#}
|
||||
<body class="rustdoc {{page.css_class}}"> {#- -#}
|
||||
<!--[if lte IE 11]> {#- -#}
|
||||
@ -114,8 +118,10 @@
|
||||
<div id="rustdoc-vars" {# -#}
|
||||
data-root-path="{{page.root_path | safe}}" {# -#}
|
||||
data-current-crate="{{layout.krate}}" {# -#}
|
||||
data-search-index-js="{{page.root_path | safe}}search-index{{page.resource_suffix}}.js" {# -#}
|
||||
data-search-js="{{static_root_path | safe}}search{{page.resource_suffix}}.js"> {#- -#}
|
||||
data-themes="{{themes | join(sep=",") }}" {# -#}
|
||||
data-resource-suffix="{{page.resource_suffix}}" {# -#}
|
||||
data-rustdoc-version="{{rustdoc_version}}" {# -#}
|
||||
> {#- -#}
|
||||
</div>
|
||||
</body> {#- -#}
|
||||
</html> {#- -#}
|
||||
|
@ -3,7 +3,7 @@
|
||||
// @has static_root_path/struct.SomeStruct.html
|
||||
// @matches - '"/cache/main\.js"'
|
||||
// @!matches - '"\.\./main\.js"'
|
||||
// @matches - '"\.\./search-index\.js"'
|
||||
// @matches - 'data-root-path="\.\./"'
|
||||
// @!matches - '"/cache/search-index\.js"'
|
||||
pub struct SomeStruct;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user