Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple themes for rustdoc #47620

Merged
merged 6 commits into from
Jan 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/librustdoc/externalfiles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use std::str;
use html::markdown::{Markdown, RenderType};

#[derive(Clone)]
pub struct ExternalHtml{
pub struct ExternalHtml {
/// Content that will be included inline in the <head> section of a
/// rendered Markdown file or generated documentation
pub in_header: String,
Expand Down
21 changes: 18 additions & 3 deletions src/librustdoc/html/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

use std::fmt;
use std::io;
use std::path::PathBuf;

use externalfiles::ExternalHtml;

Expand All @@ -31,7 +32,7 @@ pub struct Page<'a> {

pub fn render<T: fmt::Display, S: fmt::Display>(
dst: &mut io::Write, layout: &Layout, page: &Page, sidebar: &S, t: &T,
css_file_extension: bool)
css_file_extension: bool, themes: &[PathBuf])
-> io::Result<()>
{
write!(dst,
Expand All @@ -47,8 +48,11 @@ r##"<!DOCTYPE html>
<title>{title}</title>

<link rel="stylesheet" type="text/css" href="{root_path}normalize.css">
<link rel="stylesheet" type="text/css" href="{root_path}rustdoc.css">
<link rel="stylesheet" type="text/css" href="{root_path}main.css">
<link rel="stylesheet" type="text/css" href="{root_path}rustdoc.css" id="mainThemeStyle">
{themes}
<link rel="stylesheet" type="text/css" href="{root_path}dark.css">
<link rel="stylesheet" type="text/css" href="{root_path}main.css" id="themeStyle">
<script src="{root_path}storage.js"></script>
{css_extension}

{favicon}
Expand All @@ -70,6 +74,11 @@ r##"<!DOCTYPE html>
{sidebar}
</nav>

<button id="theme-picker">
<img src="{root_path}brush.svg" width="18" alt="Pick another theme!">
<div id="theme-choices"></div>
</button>
<script src="{root_path}theme.js"></script>
<nav class="sub">
<form class="search-form js-only">
<div class="search-container">
Expand Down Expand Up @@ -176,6 +185,12 @@ r##"<!DOCTYPE html>
after_content = layout.external_html.after_content,
sidebar = *sidebar,
krate = layout.krate,
themes = themes.iter()
.filter_map(|t| t.file_stem())
.filter_map(|t| t.to_str())
.map(|t| format!(r#"<link rel="stylesheet" type="text/css" href="{}{}">"#,
page.root_path, t))
.collect::<String>(),
)
}

Expand Down
82 changes: 76 additions & 6 deletions src/librustdoc/html/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ pub struct SharedContext {
/// This flag indicates whether listings of modules (in the side bar and documentation itself)
/// should be ordered alphabetically or in order of appearance (in the source code).
pub sort_modules_alphabetically: bool,
/// Additional themes to be added to the generated docs.
pub themes: Vec<PathBuf>,
}

impl SharedContext {
Expand Down Expand Up @@ -219,6 +221,17 @@ impl Error {
}
}

macro_rules! try_none {
($e:expr, $file:expr) => ({
use std::io;
match $e {
Some(e) => e,
None => return Err(Error::new(io::Error::new(io::ErrorKind::Other, "not found"),
$file))
}
})
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since rustdoc is on nightly anyway, why not just use ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to make a conversion. I intended to use ? but it cannot be used directly unfortunately...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't do the same as ? - it returns an Err instead of None.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't that how ? works on an Option inside something returning Result? You get https://doc.rust-lang.org/stable/std/option/struct.NoneError.html, and you can do the appropriate From impl if you want a custom thing

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It also takes the path of the file that caused the failure, which won't be there in the NoneError.

(I also didn't realize that there was a conversion available between NoneError and custom error types >_>)


macro_rules! try_err {
($e:expr, $file:expr) => ({
match $e {
Expand Down Expand Up @@ -489,7 +502,8 @@ pub fn run(mut krate: clean::Crate,
renderinfo: RenderInfo,
render_type: RenderType,
sort_modules_alphabetically: bool,
deny_render_differences: bool) -> Result<(), Error> {
deny_render_differences: bool,
themes: Vec<PathBuf>) -> Result<(), Error> {
let src_root = match krate.src {
FileName::Real(ref p) => match p.parent() {
Some(p) => p.to_path_buf(),
Expand All @@ -513,6 +527,7 @@ pub fn run(mut krate: clean::Crate,
markdown_warnings: RefCell::new(vec![]),
created_dirs: RefCell::new(FxHashSet()),
sort_modules_alphabetically,
themes,
};

// If user passed in `--playground-url` arg, we fill in crate name here
Expand Down Expand Up @@ -859,12 +874,65 @@ fn write_shared(cx: &Context,
// 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.

write(cx.dst.join("main.js"),
include_bytes!("static/main.js"))?;
write(cx.dst.join("rustdoc.css"),
include_bytes!("static/rustdoc.css"))?;

// To avoid "main.css" to be overwritten, we'll first run over the received themes and only
// then we'll run over the "official" styles.
let mut themes: HashSet<String> = HashSet::new();

for entry in &cx.shared.themes {
let mut content = Vec::with_capacity(100000);

let mut f = try_err!(File::open(&entry), &entry);
try_err!(f.read_to_end(&mut content), &entry);
write(cx.dst.join(try_none!(entry.file_name(), &entry)), content.as_slice())?;
themes.insert(try_none!(try_none!(entry.file_stem(), &entry).to_str(), &entry).to_owned());
}

write(cx.dst.join("brush.svg"),
include_bytes!("static/brush.svg"))?;
write(cx.dst.join("main.css"),
include_bytes!("static/styles/main.css"))?;
include_bytes!("static/themes/main.css"))?;
themes.insert("main".to_owned());
write(cx.dst.join("dark.css"),
include_bytes!("static/themes/dark.css"))?;
themes.insert("dark".to_owned());

let mut themes: Vec<&String> = themes.iter().collect();
themes.sort();
// To avoid theme switch latencies as much as possible, we put everything theme related
// at the beginning of the html files into another js file.
write(cx.dst.join("theme.js"), format!(
r#"var themes = document.getElementById("theme-choices");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this might be signficantly nicer as an external file that's include_bytes'd.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes but I need to generate the list of themes which can't be know at compile time. However, I intend to move most of this code into a js file later.

var themePicker = document.getElementById("theme-picker");
themePicker.onclick = function() {{
if (themes.style.display === "block") {{

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both branches should update aria-expanded (see mdBook).

themes.style.display = "none";
themePicker.style.borderBottomRightRadius = "3px";
themePicker.style.borderBottomLeftRadius = "3px";
}} else {{
themes.style.display = "block";
themePicker.style.borderBottomRightRadius = "0";
themePicker.style.borderBottomLeftRadius = "0";
}}
}};
[{}].forEach(function(item) {{
var div = document.createElement('div');
div.innerHTML = item;
div.onclick = function(el) {{
switchTheme(currentTheme, mainTheme, item);
}};
themes.appendChild(div);
}});
"#, themes.iter()
.map(|s| format!("\"{}\"", s))
.collect::<Vec<String>>()
.join(",")).as_bytes())?;

write(cx.dst.join("main.js"), include_bytes!("static/main.js"))?;
write(cx.dst.join("storage.js"), include_bytes!("static/storage.js"))?;

if let Some(ref css) = cx.shared.css_file_extension {
let out = cx.dst.join("theme.css");
try_err!(fs::copy(css, out), css);
Expand Down Expand Up @@ -1156,7 +1224,8 @@ impl<'a> SourceCollector<'a> {
};
layout::render(&mut w, &self.scx.layout,
&page, &(""), &Source(contents),
self.scx.css_file_extension.is_some())?;
self.scx.css_file_extension.is_some(),
&self.scx.themes)?;
w.flush()?;
self.scx.local_sources.insert(p.clone(), href);
Ok(())
Expand Down Expand Up @@ -1520,7 +1589,8 @@ impl Context {
layout::render(writer, &self.shared.layout, &page,
&Sidebar{ cx: self, item: it },
&Item{ cx: self, item: it },
self.shared.css_file_extension.is_some())?;
self.shared.css_file_extension.is_some(),
&self.shared.themes)?;
} else {
let mut url = self.root_path();
if let Some(&(ref names, ty)) = cache().paths.get(&it.def_id) {
Expand Down
1 change: 1 addition & 0 deletions src/librustdoc/html/static/brush.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 11 additions & 1 deletion src/librustdoc/html/static/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@
}
}
document.getElementsByTagName("body")[0].style.marginTop = '45px';
var themePicker = document.getElementById("theme-picker");
if (themePicker) {
themePicker.style.position = "fixed";
}
}

function hideSidebar() {
Expand All @@ -136,6 +140,10 @@
filler.remove();
}
document.getElementsByTagName("body")[0].style.marginTop = '';
var themePicker = document.getElementById("theme-picker");
if (themePicker) {
themePicker.style.position = "absolute";
}
}

// used for special search precedence
Expand Down Expand Up @@ -1532,7 +1540,9 @@
ul.appendChild(li);
}
div.appendChild(ul);
sidebar.appendChild(div);
if (sidebar) {
sidebar.appendChild(div);
}
}

block("primitive", "Primitive Types");
Expand Down
38 changes: 37 additions & 1 deletion src/librustdoc/html/static/rustdoc.css
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,8 @@ ul.item-list > li > .out-of-band {
}

h4 > code, h3 > code, .invisible > code {
position: inherit;
max-width: calc(100% - 41px);
display: block;
}

.in-band, code {
Expand All @@ -376,6 +377,7 @@ h4 > code, h3 > code, .invisible > code {
margin: 0px;
padding: 0px;
display: inline-block;
max-width: calc(100% - 43px);
}

.in-band > code {
Expand Down Expand Up @@ -1140,3 +1142,37 @@ kbd {
border-radius: 3px;
box-shadow: inset 0 -1px 0;
}

#theme-picker {
position: absolute;
left: 211px;
top: 17px;
padding: 4px;
border: 1px solid;
border-radius: 3px;
cursor: pointer;
}

#theme-choices {
display: none;
position: absolute;
left: -1px;
top: 30px;
border: 1px solid;
border-radius: 3px;
z-index: 1;
}

#theme-choices > div {
border-top: 1px solid;
padding: 4px;
text-align: center;
}

@media (max-width: 700px) {
#theme-picker {
left: 109px;
top: 7px;
z-index: 1;
}
}
36 changes: 36 additions & 0 deletions src/librustdoc/html/static/storage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*!
* Copyright 2018 The Rust Project Developers. See the COPYRIGHT
* file at the top-level directory of this distribution and at
* http://rust-lang.org/COPYRIGHT.
*
* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
* http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
* <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
* option. This file may not be copied, modified, or distributed
* except according to those terms.
*/

var currentTheme = document.getElementById("themeStyle");
var mainTheme = document.getElementById("mainThemeStyle");

function updateLocalStorage(name, value) {
if (typeof(Storage) !== "undefined") {
localStorage[name] = value;
} else {
// No Web Storage support so we do nothing
}
}

function getCurrentValue(name) {
if (typeof(Storage) !== "undefined" && localStorage[name] !== undefined) {
return localStorage[name];
}
return null;
}

function switchTheme(styleElem, mainStyleElem, newTheme) {
styleElem.href = mainStyleElem.href.replace("rustdoc.css", newTheme + ".css");
updateLocalStorage('theme', newTheme);
}

switchTheme(currentTheme, mainTheme, getCurrentValue('theme') || 'main');
Loading