Skip to content

Commit 55f8b5f

Browse files
authored
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``
2 parents 8fb58e5 + d9afca5 commit 55f8b5f

File tree

11 files changed

+118
-132
lines changed

11 files changed

+118
-132
lines changed

src/librustdoc/config.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ impl Options {
552552
))
553553
.emit();
554554
}
555-
themes.push(StylePath { path: theme_file, disabled: true });
555+
themes.push(StylePath { path: theme_file });
556556
}
557557
}
558558

src/librustdoc/error.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,10 @@ macro_rules! try_none {
3939
match $e {
4040
Some(e) => e,
4141
None => {
42-
return Err(Error::new(io::Error::new(io::ErrorKind::Other, "not found"), $file));
42+
return Err(<crate::error::Error as crate::docfs::PathError>::new(
43+
io::Error::new(io::ErrorKind::Other, "not found"),
44+
$file,
45+
));
4346
}
4447
}
4548
}};

src/librustdoc/html/layout.rs

+11-15
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ use std::path::PathBuf;
22

33
use rustc_data_structures::fx::FxHashMap;
44

5+
use crate::error::Error;
56
use crate::externalfiles::ExternalHtml;
6-
use crate::html::escape::Escape;
77
use crate::html::format::{Buffer, Print};
88
use crate::html::render::{ensure_trailing_slash, StylePath};
99

@@ -50,10 +50,11 @@ struct PageLayout<'a> {
5050
static_root_path: &'a str,
5151
page: &'a Page<'a>,
5252
layout: &'a Layout,
53-
style_files: String,
53+
themes: Vec<String>,
5454
sidebar: String,
5555
content: String,
5656
krate_with_trailing_slash: String,
57+
crate rustdoc_version: &'a str,
5758
}
5859

5960
crate fn render<T: Print, S: Print>(
@@ -66,29 +67,24 @@ crate fn render<T: Print, S: Print>(
6667
) -> String {
6768
let static_root_path = page.get_static_root_path();
6869
let krate_with_trailing_slash = ensure_trailing_slash(&layout.krate).to_string();
69-
let style_files = style_files
70+
let mut themes: Vec<String> = style_files
7071
.iter()
71-
.filter_map(|t| t.path.file_stem().map(|stem| (stem, t.disabled)))
72-
.filter_map(|t| t.0.to_str().map(|path| (path, t.1)))
73-
.map(|t| {
74-
format!(
75-
r#"<link rel="stylesheet" type="text/css" href="{}.css" {} {}>"#,
76-
Escape(&format!("{}{}{}", static_root_path, t.0, page.resource_suffix)),
77-
if t.1 { "disabled" } else { "" },
78-
if t.0 == "light" { "id=\"themeStyle\"" } else { "" }
79-
)
80-
})
81-
.collect::<String>();
72+
.map(StylePath::basename)
73+
.collect::<Result<_, Error>>()
74+
.unwrap_or_default();
75+
themes.sort();
76+
let rustdoc_version = rustc_interface::util::version_str().unwrap_or("unknown version");
8277
let content = Buffer::html().to_display(t); // Note: This must happen before making the sidebar.
8378
let sidebar = Buffer::html().to_display(sidebar);
8479
let teractx = tera::Context::from_serialize(PageLayout {
8580
static_root_path,
8681
page,
8782
layout,
88-
style_files,
83+
themes,
8984
sidebar,
9085
content,
9186
krate_with_trailing_slash,
87+
rustdoc_version,
9288
})
9389
.unwrap();
9490
templates.render("page.html", &teractx).unwrap()

src/librustdoc/html/render/context.rs

+11-7
Original file line numberDiff line numberDiff line change
@@ -504,9 +504,9 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
504504
// by the browser as the theme stylesheet. The theme system (hackily) works by
505505
// changing the href to this stylesheet. All other themes are disabled to
506506
// prevent rule conflicts
507-
scx.style_files.push(StylePath { path: PathBuf::from("light.css"), disabled: false });
508-
scx.style_files.push(StylePath { path: PathBuf::from("dark.css"), disabled: true });
509-
scx.style_files.push(StylePath { path: PathBuf::from("ayu.css"), disabled: true });
507+
scx.style_files.push(StylePath { path: PathBuf::from("light.css") });
508+
scx.style_files.push(StylePath { path: PathBuf::from("dark.css") });
509+
scx.style_files.push(StylePath { path: PathBuf::from("ayu.css") });
510510

511511
let dst = output;
512512
scx.ensure_dir(&dst)?;
@@ -596,9 +596,13 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
596596
page.description = "Settings of Rustdoc";
597597
page.root_path = "./";
598598

599-
let mut style_files = self.shared.style_files.clone();
600599
let sidebar = "<h2 class=\"location\">Settings</h2><div class=\"sidebar-elems\"></div>";
601-
style_files.push(StylePath { path: PathBuf::from("settings.css"), disabled: false });
600+
let theme_names: Vec<String> = self
601+
.shared
602+
.style_files
603+
.iter()
604+
.map(StylePath::basename)
605+
.collect::<Result<_, Error>>()?;
602606
let v = layout::render(
603607
&self.shared.templates,
604608
&self.shared.layout,
@@ -607,9 +611,9 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
607611
settings(
608612
self.shared.static_root_path.as_deref().unwrap_or("./"),
609613
&self.shared.resource_suffix,
610-
&self.shared.style_files,
614+
theme_names,
611615
)?,
612-
&style_files,
616+
&self.shared.style_files,
613617
);
614618
self.shared.fs.write(settings_file, v)?;
615619
if let Some(ref redirections) = self.shared.redirections {

src/librustdoc/html/render/mod.rs

+15-23
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ use serde::ser::SerializeSeq;
6464
use serde::{Serialize, Serializer};
6565

6666
use crate::clean::{self, ItemId, RenderedLink, SelfTy};
67-
use crate::docfs::PathError;
6867
use crate::error::Error;
6968
use crate::formats::cache::Cache;
7069
use crate::formats::item_type::ItemType;
@@ -173,8 +172,12 @@ impl Serialize for TypeWithKind {
173172
crate struct StylePath {
174173
/// The path to the theme
175174
crate path: PathBuf,
176-
/// What the `disabled` attribute should be set to in the HTML tag
177-
crate disabled: bool,
175+
}
176+
177+
impl StylePath {
178+
pub fn basename(&self) -> Result<String, Error> {
179+
Ok(try_none!(try_none!(self.path.file_stem(), &self.path).to_str(), &self.path).to_string())
180+
}
178181
}
179182

180183
fn write_srclink(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer) {
@@ -353,7 +356,7 @@ enum Setting {
353356
js_data_name: &'static str,
354357
description: &'static str,
355358
default_value: &'static str,
356-
options: Vec<(String, String)>,
359+
options: Vec<String>,
357360
},
358361
}
359362

@@ -393,10 +396,9 @@ impl Setting {
393396
options
394397
.iter()
395398
.map(|opt| format!(
396-
"<option value=\"{}\" {}>{}</option>",
397-
opt.0,
398-
if opt.0 == default_value { "selected" } else { "" },
399-
opt.1,
399+
"<option value=\"{name}\" {}>{name}</option>",
400+
if opt == default_value { "selected" } else { "" },
401+
name = opt,
400402
))
401403
.collect::<String>(),
402404
root_path,
@@ -421,18 +423,7 @@ impl<T: Into<Setting>> From<(&'static str, Vec<T>)> for Setting {
421423
}
422424
}
423425

424-
fn settings(root_path: &str, suffix: &str, themes: &[StylePath]) -> Result<String, Error> {
425-
let theme_names: Vec<(String, String)> = themes
426-
.iter()
427-
.map(|entry| {
428-
let theme =
429-
try_none!(try_none!(entry.path.file_stem(), &entry.path).to_str(), &entry.path)
430-
.to_string();
431-
432-
Ok((theme.clone(), theme))
433-
})
434-
.collect::<Result<_, Error>>()?;
435-
426+
fn settings(root_path: &str, suffix: &str, theme_names: Vec<String>) -> Result<String, Error> {
436427
// (id, explanation, default value)
437428
let settings: &[Setting] = &[
438429
(
@@ -469,10 +460,11 @@ fn settings(root_path: &str, suffix: &str, themes: &[StylePath]) -> Result<Strin
469460
<span class=\"in-band\">Rustdoc settings</span>\
470461
</h1>\
471462
<div class=\"settings\">{}</div>\
472-
<script src=\"{}settings{}.js\"></script>",
463+
<link rel=\"stylesheet\" href=\"{root_path}settings{suffix}.css\">\
464+
<script src=\"{root_path}settings{suffix}.js\"></script>",
473465
settings.iter().map(|s| s.display(root_path, suffix)).collect::<String>(),
474-
root_path,
475-
suffix
466+
root_path = root_path,
467+
suffix = suffix
476468
))
477469
}
478470

src/librustdoc/html/render/write_shared.rs

+24-62
Original file line numberDiff line numberDiff line change
@@ -181,42 +181,34 @@ pub(super) fn write_shared(
181181
cx.write_shared(SharedResource::InvocationSpecific { basename: p }, content, &options.emit)
182182
};
183183

184-
fn add_background_image_to_css(
185-
cx: &Context<'_>,
186-
css: &mut String,
187-
rule: &str,
188-
file: &'static str,
189-
) {
190-
css.push_str(&format!(
191-
"{} {{ background-image: url({}); }}",
192-
rule,
193-
SharedResource::ToolchainSpecific { basename: file }
184+
// Given "foo.svg", return e.g. "url(\"foo1.58.0.svg\")"
185+
fn ver_url(cx: &Context<'_>, basename: &'static str) -> String {
186+
format!(
187+
"url(\"{}\")",
188+
SharedResource::ToolchainSpecific { basename }
194189
.path(cx)
195190
.file_name()
196191
.unwrap()
197192
.to_str()
198193
.unwrap()
199-
))
194+
)
200195
}
201196

202-
// Add all the static files. These may already exist, but we just
203-
// overwrite them anyway to make sure that they're fresh and up-to-date.
204-
let mut rustdoc_css = static_files::RUSTDOC_CSS.to_owned();
205-
add_background_image_to_css(
206-
cx,
207-
&mut rustdoc_css,
208-
"details.undocumented[open] > summary::before, \
209-
details.rustdoc-toggle[open] > summary::before, \
210-
details.rustdoc-toggle[open] > summary.hideme::before",
211-
"toggle-minus.svg",
212-
);
213-
add_background_image_to_css(
197+
// We use the AUTOREPLACE mechanism to inject into our static JS and CSS certain
198+
// values that are only known at doc build time. Since this mechanism is somewhat
199+
// surprising when reading the code, please limit it to rustdoc.css.
200+
write_minify(
201+
"rustdoc.css",
202+
static_files::RUSTDOC_CSS
203+
.replace(
204+
"/* AUTOREPLACE: */url(\"toggle-minus.svg\")",
205+
&ver_url(cx, "toggle-minus.svg"),
206+
)
207+
.replace("/* AUTOREPLACE: */url(\"toggle-plus.svg\")", &ver_url(cx, "toggle-plus.svg"))
208+
.replace("/* AUTOREPLACE: */url(\"down-arrow.svg\")", &ver_url(cx, "down-arrow.svg")),
214209
cx,
215-
&mut rustdoc_css,
216-
"details.undocumented > summary::before, details.rustdoc-toggle > summary::before",
217-
"toggle-plus.svg",
218-
);
219-
write_minify("rustdoc.css", rustdoc_css, cx, options)?;
210+
options,
211+
)?;
220212

221213
// Add all the static files. These may already exist, but we just
222214
// overwrite them anyway to make sure that they're fresh and up-to-date.
@@ -228,12 +220,12 @@ pub(super) fn write_shared(
228220
let mut themes: FxHashSet<String> = FxHashSet::default();
229221

230222
for entry in &cx.shared.style_files {
231-
let theme = try_none!(try_none!(entry.path.file_stem(), &entry.path).to_str(), &entry.path);
223+
let theme = entry.basename()?;
232224
let extension =
233225
try_none!(try_none!(entry.path.extension(), &entry.path).to_str(), &entry.path);
234226

235227
// Handle the official themes
236-
match theme {
228+
match theme.as_str() {
237229
"light" => write_minify("light.css", static_files::themes::LIGHT, cx, options)?,
238230
"dark" => write_minify("dark.css", static_files::themes::DARK, cx, options)?,
239231
"ayu" => write_minify("ayu.css", static_files::themes::AYU, cx, options)?,
@@ -265,45 +257,15 @@ pub(super) fn write_shared(
265257
let mut themes: Vec<&String> = themes.iter().collect();
266258
themes.sort();
267259

268-
// FIXME: this should probably not be a toolchain file since it depends on `--theme`.
269-
// But it seems a shame to copy it over and over when it's almost always the same.
270-
// Maybe we can change the representation to move this out of main.js?
271-
write_minify(
272-
"main.js",
273-
static_files::MAIN_JS
274-
.replace(
275-
"/* INSERT THEMES HERE */",
276-
&format!(" = {}", serde_json::to_string(&themes).unwrap()),
277-
)
278-
.replace(
279-
"/* INSERT RUSTDOC_VERSION HERE */",
280-
&format!(
281-
"rustdoc {}",
282-
rustc_interface::util::version_str().unwrap_or("unknown version")
283-
),
284-
),
285-
cx,
286-
options,
287-
)?;
260+
write_minify("main.js", static_files::MAIN_JS, cx, options)?;
288261
write_minify("search.js", static_files::SEARCH_JS, cx, options)?;
289262
write_minify("settings.js", static_files::SETTINGS_JS, cx, options)?;
290263

291264
if cx.include_sources {
292265
write_minify("source-script.js", static_files::sidebar::SOURCE_SCRIPT, cx, options)?;
293266
}
294267

295-
{
296-
write_minify(
297-
"storage.js",
298-
format!(
299-
"var resourcesSuffix = \"{}\";{}",
300-
cx.shared.resource_suffix,
301-
static_files::STORAGE_JS
302-
),
303-
cx,
304-
options,
305-
)?;
306-
}
268+
write_minify("storage.js", static_files::STORAGE_JS, cx, options)?;
307269

308270
if cx.shared.layout.scrape_examples_extension {
309271
cx.write_minify(

src/librustdoc/html/static/css/rustdoc.css

+11
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,7 @@ h2.small-section-header > .anchor {
828828
background-color: transparent;
829829
background-size: 20px;
830830
background-position: calc(100% - 1px) 56%;
831+
background-image: /* AUTOREPLACE: */url("down-arrow.svg");
831832
}
832833
.search-container > .top-button {
833834
position: absolute;
@@ -1610,6 +1611,16 @@ details.rustdoc-toggle[open] > summary.hideme > span {
16101611
display: none;
16111612
}
16121613

1614+
details.undocumented[open] > summary::before,
1615+
details.rustdoc-toggle[open] > summary::before,
1616+
details.rustdoc-toggle[open] > summary.hideme::before {
1617+
background-image: /* AUTOREPLACE: */url("toggle-minus.svg");
1618+
}
1619+
1620+
details.undocumented > summary::before, details.rustdoc-toggle > summary::before {
1621+
background-image: /* AUTOREPLACE: */url("toggle-plus.svg");
1622+
}
1623+
16131624
details.rustdoc-toggle[open] > summary::before,
16141625
details.rustdoc-toggle[open] > summary.hideme::before {
16151626
width: 17px;

0 commit comments

Comments
 (0)