Skip to content

Commit 3e525e3

Browse files
committed
Auto merge of #54733 - GuillaumeGomez:stabilize-rustdoc-theme, r=ollie27,Dylan-DPC
Stabilize rustdoc theme options Closes #54730 This PR stabilizes the `--themes` (now `--theme`) and `--theme-checker` (now `--check-theme`) options, for allowing users to add custom themes to their documentation. Rustdoc includes two themes by default: `light` and `dark`. Using the `--theme` option, you can give rustdoc a CSS file to include as an extra theme for that render. Themes are named after the CSS file used, so using `--theme /path/to/your/custom-theme.css` will add a theme called `custom-theme` to the documentation. Even though the CLI flag to add a theme is getting stabilized, there's no guarantee that a theme file will always have the same effect on documentation generated with future versions of rustdoc. To aid in ensuring that a theme will work, the flag `--check-theme` is also available, which compares the CSS rules defined by a custom theme against the ones used in the `light` theme. If the `light` theme defines a CSS rule that the custom theme does not, rustdoc will report an error. (Rustdoc also performs this check for themes given to `--theme`, but only reports a warning when a difference is found.)
2 parents a0d40f8 + 45b83c9 commit 3e525e3

File tree

12 files changed

+88
-52
lines changed

12 files changed

+88
-52
lines changed

src/doc/rustdoc/src/command-line-arguments.md

+32-1
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,38 @@ $ rustdoc src/lib.rs --edition 2018
355355
$ rustdoc --test src/lib.rs --edition 2018
356356
```
357357

358-
This flag allows rustdoc to treat your rust code as the given edition. It will compile doctests with
358+
This flag allows `rustdoc` to treat your rust code as the given edition. It will compile doctests with
359359
the given edition as well. As with `rustc`, the default edition that `rustdoc` will use is `2015`
360360
(the first edition).
361361

362+
## `--theme`: add a theme to the documentation output
363+
364+
Using this flag looks like this:
365+
366+
```bash
367+
$ rustdoc src/lib.rs --theme /path/to/your/custom-theme.css
368+
```
369+
370+
`rustdoc`'s default output includes two themes: `light` (the default) and
371+
`dark`. This flag allows you to add custom themes to the output. Giving a CSS
372+
file to this flag adds it to your documentation as an additional theme choice.
373+
The theme's name is determined by its filename; a theme file named
374+
`custom-theme.css` will add a theme named `custom-theme` to the documentation.
375+
376+
## `--check-theme`: verify custom themes against the default theme
377+
378+
Using this flag looks like this:
379+
380+
```bash
381+
$ rustdoc --check-theme /path/to/your/custom-theme.css
382+
```
383+
384+
While `rustdoc`'s HTML output is more-or-less consistent between versions, there
385+
is no guarantee that a theme file will have the same effect. The `--theme` flag
386+
will still allow you to add the theme to your documentation, but to ensure that
387+
your theme works as expected, you can use this flag to verify that it implements
388+
the same CSS rules as the official `light` theme.
389+
390+
`--check-theme` is a separate mode in `rustdoc`. When `rustdoc` sees the
391+
`--check-theme` flag, it discards all other flags and only performs the CSS rule
392+
comparison operation.

src/doc/rustdoc/src/unstable-features.md

-24
Original file line numberDiff line numberDiff line change
@@ -294,30 +294,6 @@ some consideration for their stability, and names that end in a number). Giving
294294
`rustdoc` will disable this sorting and instead make it print the items in the order they appear in
295295
the source.
296296

297-
### `--themes`: provide additional themes
298-
299-
Using this flag looks like this:
300-
301-
```bash
302-
$ rustdoc src/lib.rs -Z unstable-options --themes theme.css
303-
```
304-
305-
Giving this flag to `rustdoc` will make it copy your theme into the generated crate docs and enable
306-
it in the theme selector. Note that `rustdoc` will reject your theme file if it doesn't style
307-
everything the "light" theme does. See `--theme-checker` below for details.
308-
309-
### `--theme-checker`: verify theme CSS for validity
310-
311-
Using this flag looks like this:
312-
313-
```bash
314-
$ rustdoc -Z unstable-options --theme-checker theme.css
315-
```
316-
317-
Before including your theme in crate docs, `rustdoc` will compare all the CSS rules it contains
318-
against the "light" theme included by default. Using this flag will allow you to see which rules are
319-
missing if `rustdoc` rejects your theme.
320-
321297
### `--resource-suffix`: modifying the name of CSS/JavaScript in crate docs
322298

323299
Using this flag looks like this:

src/librustdoc/config.rs

+22-9
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::collections::BTreeMap;
2+
use std::ffi::OsStr;
23
use std::fmt;
34
use std::path::PathBuf;
45

@@ -281,12 +282,12 @@ impl Options {
281282
// check for deprecated options
282283
check_deprecated_options(&matches, &diag);
283284

284-
let to_check = matches.opt_strs("theme-checker");
285+
let to_check = matches.opt_strs("check-theme");
285286
if !to_check.is_empty() {
286287
let paths = theme::load_css_paths(static_files::themes::LIGHT.as_bytes());
287288
let mut errors = 0;
288289

289-
println!("rustdoc: [theme-checker] Starting tests!");
290+
println!("rustdoc: [check-theme] Starting tests! (Ignoring all other arguments)");
290291
for theme_file in to_check.iter() {
291292
print!(" - Checking \"{}\"...", theme_file);
292293
let (success, differences) = theme::test_theme_against(theme_file, &paths, &diag);
@@ -357,23 +358,35 @@ impl Options {
357358
}
358359

359360
let mut themes = Vec::new();
360-
if matches.opt_present("themes") {
361+
if matches.opt_present("theme") {
361362
let paths = theme::load_css_paths(static_files::themes::LIGHT.as_bytes());
362363

363-
for (theme_file, theme_s) in matches.opt_strs("themes")
364+
for (theme_file, theme_s) in matches.opt_strs("theme")
364365
.iter()
365366
.map(|s| (PathBuf::from(&s), s.to_owned())) {
366367
if !theme_file.is_file() {
367-
diag.struct_err("option --themes arguments must all be files").emit();
368+
diag.struct_err(&format!("invalid argument: \"{}\"", theme_s))
369+
.help("arguments to --theme must be files")
370+
.emit();
368371
return Err(1);
369372
}
370-
let (success, ret) = theme::test_theme_against(&theme_file, &paths, &diag);
371-
if !success || !ret.is_empty() {
372-
diag.struct_err(&format!("invalid theme: \"{}\"", theme_s))
373-
.help("check what's wrong with the --theme-checker option")
373+
if theme_file.extension() != Some(OsStr::new("css")) {
374+
diag.struct_err(&format!("invalid argument: \"{}\"", theme_s))
374375
.emit();
375376
return Err(1);
376377
}
378+
let (success, ret) = theme::test_theme_against(&theme_file, &paths, &diag);
379+
if !success {
380+
diag.struct_err(&format!("error loading theme file: \"{}\"", theme_s)).emit();
381+
return Err(1);
382+
} else if !ret.is_empty() {
383+
diag.struct_warn(&format!("theme file \"{}\" is missing CSS rules from the \
384+
default theme", theme_s))
385+
.warn("the theme may appear incorrect when loaded")
386+
.help(&format!("to see what rules are missing, call `rustdoc \
387+
--check-theme \"{}\"`", theme_s))
388+
.emit();
389+
}
377390
themes.push(theme_file);
378391
}
379392
}

src/librustdoc/html/layout.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::path::PathBuf;
22

33
use crate::externalfiles::ExternalHtml;
4+
use crate::html::escape::Escape;
45
use crate::html::render::ensure_trailing_slash;
56
use crate::html::format::{Buffer, Print};
67

@@ -166,10 +167,11 @@ pub fn render<T: Print, S: Print>(
166167
themes = themes.iter()
167168
.filter_map(|t| t.file_stem())
168169
.filter_map(|t| t.to_str())
169-
.map(|t| format!(r#"<link rel="stylesheet" type="text/css" href="{}{}{}.css">"#,
170-
static_root_path,
171-
t,
172-
page.resource_suffix))
170+
.map(|t| format!(r#"<link rel="stylesheet" type="text/css" href="{}.css">"#,
171+
Escape(&format!("{}{}{}",
172+
static_root_path,
173+
t,
174+
page.resource_suffix))))
173175
.collect::<String>(),
174176
suffix=page.resource_suffix,
175177
static_extra_scripts=page.static_extra_scripts.iter().map(|e| {

src/librustdoc/html/render.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -633,19 +633,16 @@ function handleThemeButtonsBlur(e) {{
633633
634634
themePicker.onclick = switchThemeButtonState;
635635
themePicker.onblur = handleThemeButtonsBlur;
636-
[{}].forEach(function(item) {{
636+
{}.forEach(function(item) {{
637637
var but = document.createElement('button');
638-
but.innerHTML = item;
638+
but.textContent = item;
639639
but.onclick = function(el) {{
640640
switchTheme(currentTheme, mainTheme, item, true);
641641
}};
642642
but.onblur = handleThemeButtonsBlur;
643643
themes.appendChild(but);
644644
}});"#,
645-
themes.iter()
646-
.map(|s| format!("\"{}\"", s))
647-
.collect::<Vec<String>>()
648-
.join(","));
645+
as_json(&themes));
649646
write(cx.dst.join(&format!("theme{}.js", cx.shared.resource_suffix)),
650647
theme_js.as_bytes()
651648
)?;

src/librustdoc/html/static_files.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ pub static RUST_FAVICON: &'static [u8] = include_bytes!("static/favicon.ico");
5959
/// The built-in themes given to every documentation site.
6060
pub mod themes {
6161
/// The "light" theme, selected by default when no setting is available. Used as the basis for
62-
/// the `--theme-checker` functionality.
62+
/// the `--check-theme` functionality.
6363
pub static LIGHT: &'static str = include_str!("static/themes/light.css");
6464

6565
/// The "dark" theme.

src/librustdoc/lib.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -252,13 +252,13 @@ fn opts() -> Vec<RustcOptGroup> {
252252
o.optflag("", "sort-modules-by-appearance", "sort modules by where they appear in the \
253253
program, rather than alphabetically")
254254
}),
255-
unstable("themes", |o| {
256-
o.optmulti("", "themes",
255+
stable("theme", |o| {
256+
o.optmulti("", "theme",
257257
"additional themes which will be added to the generated docs",
258258
"FILES")
259259
}),
260-
unstable("theme-checker", |o| {
261-
o.optmulti("", "theme-checker",
260+
stable("check-theme", |o| {
261+
o.optmulti("", "check-theme",
262262
"check if given theme is valid",
263263
"FILES")
264264
}),

src/librustdoc/theme.rs

+1
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ pub fn test_theme_against<P: AsRef<Path>>(
273273
diag: &Handler,
274274
) -> (bool, Vec<String>) {
275275
let data = try_something!(fs::read(f), diag, (false, vec![]));
276+
276277
let paths = load_css_paths(&data);
277278
let mut ret = vec![];
278279
get_differences(against, &paths, &mut ret);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
-include ../tools.mk
2+
3+
# Test that rustdoc will properly load in a theme file and display it in the theme selector.
4+
5+
OUTPUT_DIR := "$(TMPDIR)/rustdoc-themes"
6+
7+
all:
8+
cp $(S)/src/librustdoc/html/static/themes/light.css $(TMPDIR)/test.css
9+
$(RUSTDOC) -o $(OUTPUT_DIR) foo.rs --theme $(TMPDIR)/test.css
10+
$(HTMLDOCCK) $(OUTPUT_DIR) foo.rs
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// @has test.css
2+
// @has foo/struct.Foo.html
3+
// @has - '//link[@rel="stylesheet"]/@href' '../test.css'
4+
pub struct Foo;

src/test/run-make-fulldeps/tools.mk

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ RUSTC := $(RUSTC) -Clinker=$(RUSTC_LINKER)
1515
RUSTDOC := $(RUSTDOC) -Clinker=$(RUSTC_LINKER)
1616
endif
1717
#CC := $(CC) -L $(TMPDIR)
18-
HTMLDOCCK := $(PYTHON) $(S)/src/etc/htmldocck.py
18+
HTMLDOCCK := '$(PYTHON)' '$(S)/src/etc/htmldocck.py'
1919
CGREP := "$(S)/src/etc/cat-and-grep.sh"
2020

2121
# This is the name of the binary we will generate and run; use this

src/tools/rustdoc-themes/main.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,11 @@ fn main() {
3838
eprintln!("No theme found in \"{}\"...", themes_folder);
3939
exit(1);
4040
}
41+
let arg_name = "--check-theme".to_owned();
4142
let status = Command::new(rustdoc_bin)
42-
.args(&["-Z", "unstable-options", "--theme-checker"])
43-
.args(&themes)
43+
.args(&themes.iter()
44+
.flat_map(|t| vec![&arg_name, t].into_iter())
45+
.collect::<Vec<_>>())
4446
.status()
4547
.expect("failed to execute child");
4648
if !status.success() {

0 commit comments

Comments
 (0)