diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 975b4d3636f2..8b2e84974985 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -28,11 +28,12 @@ pub struct Page<'a> { pub ty: &'a str, pub root_path: &'a str, pub description: &'a str, - pub keywords: &'a str + pub keywords: &'a str, } pub fn render( - dst: &mut io::Write, layout: &Layout, page: &Page, sidebar: &S, t: &T) + dst: &mut io::Write, layout: &Layout, page: &Page, sidebar: &S, t: &T, + css_file_extension: bool) -> io::Result<()> { write!(dst, @@ -49,6 +50,7 @@ r##" + {css_extension} {favicon} {in_header} @@ -141,6 +143,12 @@ r##" "##, + css_extension = if css_file_extension { + format!("", + root_path = page.root_path) + } else { + "".to_owned() + }, content = *t, root_path = page.root_path, ty = page.ty, diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 1427dfcbaf17..f5749d647dd9 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -119,6 +119,9 @@ pub struct SharedContext { /// The base-URL of the issue tracker for when an item has been tagged with /// an issue number. pub issue_tracker_base_url: Option, + /// The given user css file which allow to customize the generated + /// documentation theme. + pub css_file_extension: Option, } /// Indicates where an external crate can be found. @@ -411,7 +414,8 @@ pub fn derive_id(candidate: String) -> String { pub fn run(mut krate: clean::Crate, external_html: &ExternalHtml, dst: PathBuf, - passes: HashSet) -> Result<(), Error> { + passes: HashSet, + css_file_extension: Option) -> Result<(), Error> { let src_root = match krate.src.parent() { Some(p) => p.to_path_buf(), None => PathBuf::new(), @@ -429,6 +433,11 @@ pub fn run(mut krate: clean::Crate, krate: krate.name.clone(), playground_url: "".to_string(), }, + include_sources: true, + local_sources: HashMap::new(), + render_redirect_pages: false, + issue_tracker_base_url: None, + css_file_extension: css_file_extension, }; // Crawl the crate attributes looking for attributes which control how we're @@ -637,6 +646,7 @@ 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("jquery.js"), include_bytes!("static/jquery-2.1.4.min.js"))?; write(cx.dst.join("main.js"), @@ -647,6 +657,17 @@ fn write_shared(cx: &Context, include_bytes!("static/rustdoc.css"))?; write(cx.dst.join("main.css"), include_bytes!("static/styles/main.css"))?; + if let Some(ref css) = cx.css_file_extension { + let mut content = String::new(); + let css = css.as_path(); + let mut f = try_err!(File::open(css), css); + + try_err!(f.read_to_string(&mut content), css); + let css = cx.dst.join("theme.css"); + let css = css.as_path(); + let mut f = try_err!(File::create(css), css); + try_err!(write!(f, "{}", &content), css); + } write(cx.dst.join("normalize.css"), include_bytes!("static/normalize.css"))?; write(cx.dst.join("FiraSans-Regular.woff"), @@ -931,8 +952,9 @@ impl<'a> SourceCollector<'a> { description: &desc, keywords: BASIC_KEYWORDS, }; - layout::render(&mut w, &self.scx.layout, - &page, &(""), &Source(contents))?; + layout::render(&mut w, &self.cx.layout, + &page, &(""), &Source(contents), + self.cx.css_file_extension.is_some())?; w.flush()?; self.scx.local_sources.insert(p, href); Ok(()) @@ -1294,8 +1316,8 @@ impl Context { if !cx.render_redirect_pages { layout::render(&mut writer, &cx.shared.layout, &page, &Sidebar{ cx: cx, item: it }, - &Item{ cx: cx, item: it })?; - + &Item{ cx: cx, item: it }, + cx.css_file_extension.is_some())?; } else { let mut url = repeat("../").take(cx.current.len()) .collect::(); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index a35fe20b6b6f..75652cc17aeb 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -185,7 +185,10 @@ pub fn opts() -> Vec { "FILES"), optopt("", "markdown-playground-url", "URL to send code snippets to", "URL"), - optflag("", "markdown-no-toc", "don't include table of contents") + optflag("", "markdown-no-toc", "don't include table of contents"), + optopt("e", "extend-css", + "to redefine some css rules with a given file to generate doc with your \ + own theme", "PATH"), ) } @@ -254,8 +257,16 @@ pub fn main_args(args: &[String]) -> isize { let markdown_input = input.ends_with(".md") || input.ends_with(".markdown"); let output = matches.opt_str("o").map(|s| PathBuf::from(&s)); + let css_file_extension = matches.opt_str("e").map(|s| PathBuf::from(&s)); let cfgs = matches.opt_strs("cfg"); + if let Some(ref p) = css_file_extension { + if !p.is_file() { + println!("{}", "--extend-css option must take a css file as input"); + return 1; + } + } + let external_html = match ExternalHtml::load( &matches.opt_strs("html-in-header"), &matches.opt_strs("html-before-content"), @@ -291,7 +302,8 @@ pub fn main_args(args: &[String]) -> isize { Some("html") | None => { html::render::run(krate, &external_html, output.unwrap_or(PathBuf::from("doc")), - passes.into_iter().collect()) + passes.into_iter().collect(), + css_file_extension) .expect("failed to generate documentation") } Some("json") => {