Skip to content

Commit

Permalink
Rollup merge of rust-lang#91062 - jsha:static-file-replace, r=jyn514,…
Browse files Browse the repository at this point in the history
…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`
  • Loading branch information
matthiaskrgr committed Nov 27, 2021
2 parents ec408c9 + d9afca5 commit bdcc293
Show file tree
Hide file tree
Showing 11 changed files with 118 additions and 132 deletions.
2 changes: 1 addition & 1 deletion src/librustdoc/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,7 @@ impl Options {
))
.emit();
}
themes.push(StylePath { path: theme_file, disabled: true });
themes.push(StylePath { path: theme_file });
}
}

Expand Down
5 changes: 4 additions & 1 deletion src/librustdoc/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
));
}
}
}};
Expand Down
26 changes: 11 additions & 15 deletions src/librustdoc/html/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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>(
Expand All @@ -66,29 +67,24 @@ crate fn render<T: Print, S: Print>(
) -> 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()
Expand Down
18 changes: 11 additions & 7 deletions src/librustdoc/html/render/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)?;
Expand Down Expand Up @@ -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 = "<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,
Expand All @@ -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 {
Expand Down
38 changes: 15 additions & 23 deletions src/librustdoc/html/render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<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) {
Expand Down Expand Up @@ -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>,
},
}

Expand Down Expand Up @@ -393,10 +396,9 @@ impl Setting {
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,
Expand All @@ -421,18 +423,7 @@ impl<T: Into<Setting>> From<(&'static str, Vec<T>)> for 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] = &[
(
Expand Down Expand Up @@ -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
))
}

Expand Down
86 changes: 24 additions & 62 deletions src/librustdoc/html/render/write_shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -228,12 +220,12 @@ pub(super) fn write_shared(
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)?,
Expand Down Expand Up @@ -265,45 +257,15 @@ 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)?;

if cx.include_sources {
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(
Expand Down
11 changes: 11 additions & 0 deletions src/librustdoc/html/static/css/rustdoc.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
Loading

0 comments on commit bdcc293

Please sign in to comment.