-
Notifications
You must be signed in to change notification settings - Fork 13k
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
Multiple themes for rustdoc #47620
Changes from 2 commits
003b2bc
9aee164
aae6dc4
3c52acd
5f93159
5b85044
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,8 +47,8 @@ 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"> | ||
<link rel="stylesheet" type="text/css" href="{root_path}main.css" id="themeStyle"> | ||
{css_extension} | ||
|
||
{favicon} | ||
|
@@ -70,6 +70,10 @@ r##"<!DOCTYPE html> | |
{sidebar} | ||
</nav> | ||
|
||
<div id="theme-picker">🖌 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In mdbook it breaks elements alignment so I'd prefer not use the same mechanisms. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How does it break elements alignment? Also, this should be a button. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see the point of this being a button... :-/ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you click it? Then it should be a button or a link. |
||
<div id="theme-choices"></div> | ||
</div> | ||
<script src="{root_path}theme.js"></script> | ||
<nav class="sub"> | ||
<form class="search-form js-only"> | ||
<div class="search-container"> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 { | ||
|
@@ -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)) | ||
} | ||
}) | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. since rustdoc is on nightly anyway, why not just use ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need to make a conversion. I intended to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn't do the same as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. isn't that how There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 (I also didn't realize that there was a conversion available between |
||
|
||
macro_rules! try_err { | ||
($e:expr, $file:expr) => ({ | ||
match $e { | ||
|
@@ -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(), | ||
|
@@ -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 | ||
|
@@ -859,12 +874,84 @@ 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("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"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this might be signficantly nicer as an external file that's There was a problem hiding this comment. Choose a reason for hiding this commentThe 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") {{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Both branches should update |
||
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"; | ||
}} | ||
}}; | ||
var currentTheme = document.getElementById("themeStyle"); | ||
var mainTheme = document.getElementById("mainThemeStyle"); | ||
[{}].forEach(function(item) {{ | ||
var div = document.createElement('div'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
div.innerHTML = item; | ||
div.onclick = function(el) {{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will create an event listener for each theme if I understand correctly. What about just one (on There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I prefer to avoid js code as much as possible. Like this, no need to try to find which child sent the event. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, but that comes at a performance cost. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What performance cost? O.o The bottleneck is clearly not in js events. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. True, not a bottleneck, but why not avoid extra event listeners on a page? It is one or two extra lines of code. |
||
switchTheme(currentTheme, mainTheme, item); | ||
}}; | ||
themes.appendChild(div); | ||
}}); | ||
|
||
function updateLocalStorage(theme) {{ | ||
if (typeof(Storage) !== "undefined") {{ | ||
localStorage.theme = theme; | ||
}} else {{ | ||
// No Web Storage support so we do nothing | ||
}} | ||
}} | ||
function switchTheme(styleElem, mainStyleElem, newTheme) {{ | ||
styleElem.href = mainStyleElem.href.replace("rustdoc.css", newTheme + ".css"); | ||
updateLocalStorage(newTheme); | ||
}} | ||
function getCurrentTheme() {{ | ||
if (typeof(Storage) !== "undefined" && localStorage.theme !== undefined) {{ | ||
return localStorage.theme; | ||
}} | ||
return "main"; | ||
}} | ||
|
||
switchTheme(currentTheme, mainTheme, getCurrentTheme()); | ||
"#, themes.iter() | ||
.map(|s| format!("\"{}\"", s)) | ||
.collect::<Vec<String>>() | ||
.join(",")).as_bytes())?; | ||
|
||
write(cx.dst.join("main.js"), include_bytes!("static/main.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); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This icon is not present in the fonts we bundle with rustdoc, nor in the system fonts in Windows 7: