Skip to content

Commit e99ab4e

Browse files
Add version switcher
1 parent 1349c84 commit e99ab4e

File tree

8 files changed

+166
-21
lines changed

8 files changed

+166
-21
lines changed

src/bootstrap/doc.rs

+47-11
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,27 @@ book!(
6969
RustdocBook, "src/doc/rustdoc", "rustdoc", RustbookVersion::MdBook1;
7070
);
7171

72+
fn generate_jump_version_js(p: &Path) -> String {
73+
let content = fs::read(p).expect("file not found");
74+
let s = String::from_utf8_lossy(&content);
75+
let version_parts = crate::channel::CFG_RELEASE_NUM.split(".").collect::<Vec<_>>();
76+
let mut versions = vec!["\"nightly\"".to_owned(),
77+
"\"beta\"".to_owned(),
78+
"\"stable\"".to_owned()];
79+
let mut middle_version = i32::from_str_radix(version_parts[1], 10).expect("unknown number");
80+
81+
while middle_version >= 0 {
82+
versions.push(format!("\"1.{}.0\"", middle_version));
83+
middle_version -= 1;
84+
}
85+
s.replace("var VERSIONS = [];", &format!("var VERSIONS = [{}];", versions.join(",")))
86+
}
87+
88+
fn generate_jump_version_css(p: &Path) -> String {
89+
let content = fs::read(p).expect("file not found");
90+
String::from_utf8(content).expect("invalid UTF8")
91+
}
92+
7293
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
7394
enum RustbookVersion {
7495
MdBook1,
@@ -329,21 +350,23 @@ fn invoke_rustdoc(builder: &Builder, compiler: Compiler, target: Interned<String
329350
let favicon = builder.src.join("src/doc/favicon.inc");
330351
let footer = builder.src.join("src/doc/footer.inc");
331352
let version_info = out.join("version_info.html");
353+
let jump_version_js = builder.src.join("src/doc/jump-version.js");
354+
let jump_version_css = builder.src.join("src/doc/jump-version.css");
332355

333356
let mut cmd = builder.rustdoc_cmd(compiler.host);
334357

335358
let out = out.join("book");
336359

337360
cmd.arg("--html-after-content").arg(&footer)
338-
.arg("--html-before-content").arg(&version_info)
339-
.arg("--html-in-header").arg(&favicon)
340-
.arg("--markdown-no-toc")
341-
.arg("--markdown-playground-url")
342-
.arg("https://play.rust-lang.org/")
343-
.arg("-o").arg(&out)
344-
.arg(&path)
345-
.arg("--markdown-css")
346-
.arg("../rust.css");
361+
.arg("--html-before-content").arg(&version_info)
362+
.arg("--html-in-header").arg(&favicon)
363+
.arg("--raw-js-in-header").arg(&generate_jump_version_js(&jump_version_js))
364+
.arg("--raw-css-in-header").arg(&generate_jump_version_css(&jump_version_css))
365+
.arg("--markdown-no-toc")
366+
.arg("--markdown-playground-url").arg("https://play.rust-lang.org/")
367+
.arg("-o").arg(&out)
368+
.arg("--markdown-css").arg("../rust.css")
369+
.arg(&path);
347370

348371
builder.run(&mut cmd);
349372
}
@@ -388,6 +411,8 @@ impl Step for Standalone {
388411
let favicon = builder.src.join("src/doc/favicon.inc");
389412
let footer = builder.src.join("src/doc/footer.inc");
390413
let full_toc = builder.src.join("src/doc/full-toc.inc");
414+
let jump_version_js = builder.src.join("src/doc/jump-version.js");
415+
let jump_version_css = builder.src.join("src/doc/jump-version.css");
391416
t!(fs::copy(builder.src.join("src/doc/rust.css"), out.join("rust.css")));
392417

393418
let version_input = builder.src.join("src/doc/version_info.html.template");
@@ -424,10 +449,13 @@ impl Step for Standalone {
424449
cmd.arg("--html-after-content").arg(&footer)
425450
.arg("--html-before-content").arg(&version_info)
426451
.arg("--html-in-header").arg(&favicon)
452+
.arg("--raw-js-in-header")
453+
.arg(&generate_jump_version_js(&jump_version_js))
454+
.arg("--raw-css-in-header")
455+
.arg(&generate_jump_version_css(&jump_version_css))
427456
.arg("--markdown-no-toc")
428457
.arg("--index-page").arg(&builder.src.join("src/doc/index.md"))
429-
.arg("--markdown-playground-url")
430-
.arg("https://play.rust-lang.org/")
458+
.arg("--markdown-playground-url").arg("https://play.rust-lang.org/")
431459
.arg("-o").arg(&out)
432460
.arg(&path);
433461

@@ -506,6 +534,10 @@ impl Step for Std {
506534
let mut cargo = builder.cargo(compiler, Mode::Std, target, "rustdoc");
507535
compile::std_cargo(builder, &compiler, target, &mut cargo);
508536

537+
538+
let jump_version_js = builder.src.join("src/doc/jump-version.js");
539+
let jump_version_css = builder.src.join("src/doc/jump-version.css");
540+
509541
// Keep a whitelist so we do not build internal stdlib crates, these will be
510542
// build by the rustc step later if enabled.
511543
cargo.arg("-Z").arg("unstable-options")
@@ -518,6 +550,10 @@ impl Step for Std {
518550
.arg("--markdown-css").arg("rust.css")
519551
.arg("--markdown-no-toc")
520552
.arg("--generate-redirect-pages")
553+
.arg("--raw-js-in-header")
554+
.arg(&generate_jump_version_js(&jump_version_js))
555+
.arg("--raw-css-in-header")
556+
.arg(&generate_jump_version_css(&jump_version_css))
521557
.arg("--index-page").arg(&builder.src.join("src/doc/index.md"));
522558

523559
builder.run(&mut cargo);

src/doc/jump-version.css

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#jump-version {
2+
position: fixed;
3+
right: 5px;
4+
bottom: 5px;
5+
border: 1px solid #ccc;
6+
border-radius: 3px;
7+
background-color: #eee;
8+
color: #000;
9+
padding: 4px;
10+
font-size: 1.1em;
11+
}

src/doc/jump-version.js

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
(function(){
2+
var VERSIONS = [];
3+
if (window.location.protocol === "file:" || window.location.host !== "doc.rust-lang.org") {
4+
return;
5+
}
6+
var version = window.location.pathname.split("/").filter(function(x) {
7+
return x.length > 0;
8+
})[0];
9+
if (version === "std") {
10+
version = "stable";
11+
}
12+
var s = document.createElement("select");
13+
for (var i = 0; i < VERSIONS.length; ++i) {
14+
var entry = document.createElement("option");
15+
entry.innerText = VERSIONS[i];
16+
entry.value = VERSIONS[i];
17+
if (VERSIONS[i] === version) {
18+
entry.selected = true;
19+
}
20+
s.append(entry);
21+
}
22+
s.id = "jump-version";
23+
s.onchange = function() {
24+
var parts = window.location.pathname.split("/").filter(function(x) {
25+
return x.length > 0;
26+
});
27+
if (parts[0] !== "std") {
28+
parts.shift();
29+
}
30+
window.location.pathname = this.value + "/" + parts.join("/");
31+
};
32+
document.body.appendChild(s);
33+
}());

src/librustdoc/config.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,10 @@ pub struct RenderOptions {
194194
pub generate_search_filter: bool,
195195
/// Option (disabled by default) to generate files used by RLS and some other tools.
196196
pub generate_redirect_pages: bool,
197+
/// Additional JS file (through "--raw-js-in-header" option).
198+
pub additional_js: Option<String>,
199+
/// Additional JS file (through "--raw-css-in-header" option).
200+
pub additional_css: Option<String>,
197201
}
198202

199203
impl Options {
@@ -360,14 +364,18 @@ impl Options {
360364
}
361365
}
362366

367+
let resource_suffix = matches.opt_str("resource-suffix").unwrap_or_default();
368+
363369
let mut id_map = html::markdown::IdMap::new();
364370
id_map.populate(html::render::initial_ids());
365371
let external_html = match ExternalHtml::load(
366372
&matches.opt_strs("html-in-header"),
367373
&matches.opt_strs("html-before-content"),
368374
&matches.opt_strs("html-after-content"),
369375
&matches.opt_strs("markdown-before-content"),
370-
&matches.opt_strs("markdown-after-content"), &diag, &mut id_map) {
376+
&matches.opt_strs("markdown-after-content"),
377+
&diag,
378+
&mut id_map) {
371379
Some(eh) => eh,
372380
None => return Err(3),
373381
};
@@ -428,7 +436,6 @@ impl Options {
428436
let display_warnings = matches.opt_present("display-warnings");
429437
let linker = matches.opt_str("linker").map(PathBuf::from);
430438
let sort_modules_alphabetically = !matches.opt_present("sort-modules-by-appearance");
431-
let resource_suffix = matches.opt_str("resource-suffix").unwrap_or_default();
432439
let enable_minification = !matches.opt_present("disable-minification");
433440
let markdown_no_toc = matches.opt_present("markdown-no-toc");
434441
let markdown_css = matches.opt_strs("markdown-css");
@@ -439,6 +446,8 @@ impl Options {
439446
let generate_search_filter = !matches.opt_present("disable-per-crate-search");
440447
let persist_doctests = matches.opt_str("persist-doctests").map(PathBuf::from);
441448
let generate_redirect_pages = matches.opt_present("generate-redirect-pages");
449+
let additional_js = matches.opt_str("raw-js-in-header");
450+
let additional_css = matches.opt_str("raw-css-in-header");
442451

443452
let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
444453

@@ -484,6 +493,8 @@ impl Options {
484493
markdown_playground_url,
485494
generate_search_filter,
486495
generate_redirect_pages,
496+
additional_js,
497+
additional_css,
487498
}
488499
})
489500
}

src/librustdoc/externalfiles.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ pub struct ExternalHtml {
2121

2222
impl ExternalHtml {
2323
pub fn load(in_header: &[String], before_content: &[String], after_content: &[String],
24-
md_before_content: &[String], md_after_content: &[String], diag: &errors::Handler,
25-
id_map: &mut IdMap)
24+
md_before_content: &[String], md_after_content: &[String],
25+
diag: &errors::Handler, id_map: &mut IdMap)
2626
-> Option<ExternalHtml> {
2727
let codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build());
2828
load_external_files(in_header, diag)

src/librustdoc/html/layout.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ pub fn render<T: fmt::Display, S: fmt::Display>(
3535
css_file_extension: bool,
3636
themes: &[PathBuf],
3737
generate_search_filter: bool,
38+
additional_js: bool,
39+
additional_css: bool,
3840
) -> io::Result<()> {
3941
let static_root_path = page.static_root_path.unwrap_or(page.root_path);
4042
write!(dst,
@@ -61,7 +63,7 @@ pub fn render<T: fmt::Display, S: fmt::Display>(
6163
{in_header}\
6264
<style type=\"text/css\">\
6365
#crate-search{{background-image:url(\"{static_root_path}down-arrow{suffix}.svg\");}}\
64-
</style>\
66+
</style>{additional_js}{additional_css}\
6567
</head>\
6668
<body class=\"rustdoc {css_class}\">\
6769
<!--[if lte IE 8]>\
@@ -236,6 +238,18 @@ pub fn render<T: fmt::Display, S: fmt::Display>(
236238
} else {
237239
""
238240
},
241+
additional_js = if additional_js {
242+
format!("<script src=\"{}additional{}.js\"></script>",
243+
static_root_path, page.resource_suffix)
244+
} else {
245+
String::new()
246+
},
247+
additional_css = if additional_css {
248+
format!("<link rel=\"stylesheet\" type=\"text/css\" href=\"{}additional{}.css\">",
249+
static_root_path, page.resource_suffix)
250+
} else {
251+
String::new()
252+
},
239253
)
240254
}
241255

src/librustdoc/html/render.rs

+33-5
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,10 @@ struct SharedContext {
150150
pub generate_search_filter: bool,
151151
/// Option disabled by default to generate files used by RLS and some other tools.
152152
pub generate_redirect_pages: bool,
153+
/// Is additional JS content present.
154+
pub additional_js: bool,
155+
/// Is additional CSS content present.
156+
pub additional_css: bool,
153157
}
154158

155159
impl SharedContext {
@@ -519,6 +523,8 @@ pub fn run(mut krate: clean::Crate,
519523
static_root_path,
520524
generate_search_filter,
521525
generate_redirect_pages,
526+
additional_js,
527+
additional_css,
522528
..
523529
} = options;
524530

@@ -549,6 +555,8 @@ pub fn run(mut krate: clean::Crate,
549555
static_root_path,
550556
generate_search_filter,
551557
generate_redirect_pages,
558+
additional_js: additional_js.is_some(),
559+
additional_css: additional_css.is_some(),
552560
};
553561

554562
// If user passed in `--playground-url` arg, we fill in crate name here
@@ -885,6 +893,16 @@ themePicker.onblur = handleThemeButtonsBlur;
885893
write_minify(cx.dst.join(&format!("settings{}.js", cx.shared.resource_suffix)),
886894
static_files::SETTINGS_JS,
887895
options.enable_minification)?;
896+
if let Some(ref additional_js) = options.additional_js {
897+
write_minify(cx.dst.join(&format!("additional{}.js", cx.shared.resource_suffix)),
898+
additional_js,
899+
options.enable_minification)?;
900+
}
901+
if let Some(ref additional_css) = options.additional_css {
902+
write_minify(cx.dst.join(&format!("additional{}.css", cx.shared.resource_suffix)),
903+
additional_css,
904+
options.enable_minification)?;
905+
}
888906
if cx.shared.include_sources {
889907
write_minify(cx.dst.join(&format!("source-script{}.js", cx.shared.resource_suffix)),
890908
static_files::sidebar::SOURCE_SCRIPT,
@@ -1164,7 +1182,9 @@ themePicker.onblur = handleThemeButtonsBlur;
11641182
&page, &(""), &content,
11651183
cx.shared.css_file_extension.is_some(),
11661184
&cx.shared.themes,
1167-
cx.shared.generate_search_filter), &dst);
1185+
cx.shared.generate_search_filter,
1186+
options.additional_js.is_some(),
1187+
options.additional_css.is_some()), &dst);
11681188
try_err!(w.flush(), &dst);
11691189
}
11701190
}
@@ -1476,7 +1496,9 @@ impl<'a> SourceCollector<'a> {
14761496
&page, &(""), &Source(contents),
14771497
self.scx.css_file_extension.is_some(),
14781498
&self.scx.themes,
1479-
self.scx.generate_search_filter)?;
1499+
self.scx.generate_search_filter,
1500+
self.scx.additional_js,
1501+
self.scx.additional_css)?;
14801502
w.flush()?;
14811503
self.scx.local_sources.insert(p.clone(), href);
14821504
Ok(())
@@ -2084,7 +2106,9 @@ impl Context {
20842106
&page, &sidebar, &all,
20852107
self.shared.css_file_extension.is_some(),
20862108
&self.shared.themes,
2087-
self.shared.generate_search_filter),
2109+
self.shared.generate_search_filter,
2110+
self.shared.additional_js,
2111+
self.shared.additional_css),
20882112
&final_file);
20892113

20902114
// Generating settings page.
@@ -2102,7 +2126,9 @@ impl Context {
21022126
&page, &sidebar, &settings,
21032127
self.shared.css_file_extension.is_some(),
21042128
&themes,
2105-
self.shared.generate_search_filter),
2129+
self.shared.generate_search_filter,
2130+
self.shared.additional_js,
2131+
self.shared.additional_css),
21062132
&settings_file);
21072133

21082134
Ok(())
@@ -2164,7 +2190,9 @@ impl Context {
21642190
&Item{ cx: self, item: it },
21652191
self.shared.css_file_extension.is_some(),
21662192
&self.shared.themes,
2167-
self.shared.generate_search_filter)?;
2193+
self.shared.generate_search_filter,
2194+
self.shared.additional_js,
2195+
self.shared.additional_css)?;
21682196
} else {
21692197
let mut url = self.root_path();
21702198
if let Some(&(ref names, ty)) = cache().paths.get(&it.def_id) {

src/librustdoc/lib.rs

+12
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,18 @@ fn opts() -> Vec<RustcOptGroup> {
201201
Markdown file or generated documentation",
202202
"FILES")
203203
}),
204+
unstable("raw-js-in-header", |o| {
205+
o.optopt("", "raw-js-in-header",
206+
"JS to include in the <head> section of a rendered Markdown file \
207+
or generated documentation",
208+
"text")
209+
}),
210+
unstable("raw-css-in-header", |o| {
211+
o.optopt("", "raw-css-in-header",
212+
"CSS to include in the <head> section of a rendered Markdown file \
213+
or generated documentation",
214+
"text")
215+
}),
204216
unstable("markdown-before-content", |o| {
205217
o.optmulti("", "markdown-before-content",
206218
"files to include inline between <body> and the content of a rendered \

0 commit comments

Comments
 (0)