diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs index f8320330ad265..420e0b2e80706 100644 --- a/src/librustdoc/externalfiles.rs +++ b/src/librustdoc/externalfiles.rs @@ -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 section of a /// rendered Markdown file or generated documentation pub in_header: String, diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 007d663cf949c..95db6a8679e5d 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -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, } impl SharedContext { @@ -500,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) -> Result<(), Error> { let src_root = match krate.src { FileName::Real(ref p) => match p.parent() { Some(p) => p.to_path_buf(), @@ -524,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 @@ -872,19 +876,28 @@ fn write_shared(cx: &Context, write(cx.dst.join("rustdoc.css"), include_bytes!("static/rustdoc.css"))?; - let path = cx.shared.src_root.join("../librustdoc/html/static/themes"); - let mut themes: Vec = Vec::new(); - for entry in try_err!(fs::read_dir(path.clone()), &path) { - let entry = try_err!(entry, &path); + + // 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 = HashSet::new(); + + for entry in &cx.shared.themes { let mut content = Vec::with_capacity(100000); - let mut f = try_err!(File::open(entry.path()), &entry.path()); - try_err!(f.read_to_end(&mut content), &entry.path()); - write(cx.dst.join(entry.file_name()), content.as_slice())?; - themes.push(try_none!( - try_none!(entry.path().file_stem(), &entry.path()).to_str(), - &entry.path()).to_owned()); + 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/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. diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 2e2dba7681cc3..bf624c31d3d95 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -264,6 +264,11 @@ pub fn opts() -> Vec { o.optflag("", "deny-render-differences", "abort doc runs when markdown rendering \ differences are found") }), + unstable("themes", |o| { + o.optmulti("", "themes", + "additional themes which will be added to the generated docs", + "FILES") + }), ] } @@ -365,6 +370,15 @@ pub fn main_args(args: &[String]) -> isize { } } + let mut themes = Vec::new(); + for theme in matches.opt_strs("themes").iter().map(|s| PathBuf::from(&s)) { + if !theme.is_file() { + eprintln!("rustdoc: option --themes arguments must all be files"); + return 1; + } + themes.push(theme); + } + let external_html = match ExternalHtml::load( &matches.opt_strs("html-in-header"), &matches.opt_strs("html-before-content"), @@ -413,7 +427,8 @@ pub fn main_args(args: &[String]) -> isize { renderinfo, render_type, sort_modules_alphabetically, - deny_render_differences) + deny_render_differences, + themes) .expect("failed to generate documentation"); 0 }