diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index d6025920e78b0..75ab3459c26fb 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -92,6 +92,8 @@ pub struct Context {
/// The current destination folder of where HTML artifacts should be placed.
/// This changes as the context descends into the module hierarchy.
pub dst: PathBuf,
+ /// The configurable destination folder for static resources (css, js, etc...).
+ pub resources_dst: PathBuf,
/// A flag, which when `true`, will render pages which redirect to the
/// real location of an item. This is used to allow external links to
/// publicly reused items to redirect to the right location.
@@ -128,6 +130,8 @@ pub struct SharedContext {
pub sort_modules_alphabetically: bool,
/// Additional themes to be added to the generated docs.
pub themes: Vec,
+ /// The path where all non-HTML resources will be stored.
+ pub root_path: String,
}
impl SharedContext {
@@ -476,12 +480,14 @@ pub fn derive_id(candidate: String) -> String {
pub fn run(mut krate: clean::Crate,
external_html: &ExternalHtml,
playground_url: Option,
+ html_dst: PathBuf,
dst: PathBuf,
passes: FxHashSet,
css_file_extension: Option,
renderinfo: RenderInfo,
sort_modules_alphabetically: bool,
- themes: Vec) -> Result<(), Error> {
+ themes: Vec,
+ root_path: String) -> Result<(), Error> {
let src_root = match krate.src {
FileName::Real(ref p) => match p.parent() {
Some(p) => p.to_path_buf(),
@@ -505,6 +511,7 @@ pub fn run(mut krate: clean::Crate,
created_dirs: RefCell::new(FxHashSet()),
sort_modules_alphabetically,
themes,
+ root_path,
};
// If user passed in `--playground-url` arg, we fill in crate name here
@@ -543,10 +550,12 @@ pub fn run(mut krate: clean::Crate,
}
}
try_err!(fs::create_dir_all(&dst), &dst);
- krate = render_sources(&dst, &mut scx, krate)?;
+ try_err!(fs::create_dir_all(&html_dst), &html_dst);
+ krate = render_sources(&html_dst, &mut scx, krate)?;
let cx = Context {
current: Vec::new(),
- dst,
+ dst: html_dst,
+ resources_dst: dst,
render_redirect_pages: false,
shared: Arc::new(scx),
};
@@ -717,7 +726,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("rustdoc.css"),
+ write(cx.resources_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
@@ -729,16 +738,16 @@ fn write_shared(cx: &Context,
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())?;
+ write(cx.resources_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"),
+ write(cx.resources_dst.join("brush.svg"),
include_bytes!("static/brush.svg"))?;
- write(cx.dst.join("main.css"),
+ write(cx.resources_dst.join("main.css"),
include_bytes!("static/themes/main.css"))?;
themes.insert("main".to_owned());
- write(cx.dst.join("dark.css"),
+ write(cx.resources_dst.join("dark.css"),
include_bytes!("static/themes/dark.css"))?;
themes.insert("dark".to_owned());
@@ -746,7 +755,7 @@ fn write_shared(cx: &Context,
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!(
+ write(cx.resources_dst.join("theme.js"), format!(
r#"var themes = document.getElementById("theme-choices");
var themePicker = document.getElementById("theme-picker");
themePicker.onclick = function() {{
@@ -773,42 +782,42 @@ themePicker.onclick = function() {{
.collect::>()
.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"))?;
+ write(cx.resources_dst.join("main.js"), include_bytes!("static/main.js"))?;
+ write(cx.resources_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");
+ let out = cx.resources_dst.join("theme.css");
try_err!(fs::copy(css, out), css);
}
- write(cx.dst.join("normalize.css"),
+ write(cx.resources_dst.join("normalize.css"),
include_bytes!("static/normalize.css"))?;
- write(cx.dst.join("FiraSans-Regular.woff"),
+ write(cx.resources_dst.join("FiraSans-Regular.woff"),
include_bytes!("static/FiraSans-Regular.woff"))?;
- write(cx.dst.join("FiraSans-Medium.woff"),
+ write(cx.resources_dst.join("FiraSans-Medium.woff"),
include_bytes!("static/FiraSans-Medium.woff"))?;
- write(cx.dst.join("FiraSans-LICENSE.txt"),
+ write(cx.resources_dst.join("FiraSans-LICENSE.txt"),
include_bytes!("static/FiraSans-LICENSE.txt"))?;
- write(cx.dst.join("Heuristica-Italic.woff"),
+ write(cx.resources_dst.join("Heuristica-Italic.woff"),
include_bytes!("static/Heuristica-Italic.woff"))?;
- write(cx.dst.join("Heuristica-LICENSE.txt"),
+ write(cx.resources_dst.join("Heuristica-LICENSE.txt"),
include_bytes!("static/Heuristica-LICENSE.txt"))?;
- write(cx.dst.join("SourceSerifPro-Regular.woff"),
+ write(cx.resources_dst.join("SourceSerifPro-Regular.woff"),
include_bytes!("static/SourceSerifPro-Regular.woff"))?;
- write(cx.dst.join("SourceSerifPro-Bold.woff"),
+ write(cx.resources_dst.join("SourceSerifPro-Bold.woff"),
include_bytes!("static/SourceSerifPro-Bold.woff"))?;
- write(cx.dst.join("SourceSerifPro-LICENSE.txt"),
+ write(cx.resources_dst.join("SourceSerifPro-LICENSE.txt"),
include_bytes!("static/SourceSerifPro-LICENSE.txt"))?;
- write(cx.dst.join("SourceCodePro-Regular.woff"),
+ write(cx.resources_dst.join("SourceCodePro-Regular.woff"),
include_bytes!("static/SourceCodePro-Regular.woff"))?;
- write(cx.dst.join("SourceCodePro-Semibold.woff"),
+ write(cx.resources_dst.join("SourceCodePro-Semibold.woff"),
include_bytes!("static/SourceCodePro-Semibold.woff"))?;
- write(cx.dst.join("SourceCodePro-LICENSE.txt"),
+ write(cx.resources_dst.join("SourceCodePro-LICENSE.txt"),
include_bytes!("static/SourceCodePro-LICENSE.txt"))?;
- write(cx.dst.join("LICENSE-MIT.txt"),
+ write(cx.resources_dst.join("LICENSE-MIT.txt"),
include_bytes!("static/LICENSE-MIT.txt"))?;
- write(cx.dst.join("LICENSE-APACHE.txt"),
+ write(cx.resources_dst.join("LICENSE-APACHE.txt"),
include_bytes!("static/LICENSE-APACHE.txt"))?;
- write(cx.dst.join("COPYRIGHT.txt"),
+ write(cx.resources_dst.join("COPYRIGHT.txt"),
include_bytes!("static/COPYRIGHT.txt"))?;
fn collect(path: &Path, krate: &str,
@@ -830,7 +839,7 @@ themePicker.onclick = function() {{
}
// Update the search index
- let dst = cx.dst.join("search-index.js");
+ let dst = cx.resources_dst.join("search-index.js");
let mut all_indexes = try_err!(collect(&dst, &krate.name, "searchIndex"), &dst);
all_indexes.push(search_index);
// Sort the indexes by crate so the file will be generated identically even
@@ -1039,12 +1048,11 @@ impl<'a> SourceCollector<'a> {
// Create the intermediate directories
let mut cur = self.dst.clone();
- let mut root_path = String::from("../../");
+ let root_path = self.scx.root_path.clone();
let mut href = String::new();
clean_srcpath(&self.scx.src_root, &p, false, |component| {
cur.push(component);
fs::create_dir_all(&cur).unwrap();
- root_path.push_str("../");
href.push_str(component);
href.push('/');
});
@@ -1340,6 +1348,14 @@ impl Context {
repeat("../").take(self.current.len()).collect::()
}
+ /// String representation of how to get back to the root path of the
+ /// resources folder in terms of a relative URL.
+ fn resources_root_path(&self) -> String {
+ let mut s = repeat("../").take(self.current.len()).collect::();
+ s.push_str(&self.shared.root_path.replace("../../", ""));
+ s
+ }
+
/// Recurse in the directory structure and change the "root path" to make
/// sure it always points to the top (relatively).
fn recurse(&mut self, s: String, f: F) -> T where
@@ -1422,7 +1438,7 @@ impl Context {
let keywords = make_item_keywords(it);
let page = layout::Page {
css_class: tyname,
- root_path: &self.root_path(),
+ root_path: &self.resources_root_path(),
title: &title,
description: &desc,
keywords: &keywords,
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 825558648e1f8..45b3f937d97ab 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -260,6 +260,10 @@ pub fn opts() -> Vec {
"check if given theme is valid",
"FILES")
}),
+ unstable("root-path", |o| {
+ o.optopt("", "root-path", "Change default folder to store non-HTML resources",
+ "PATH")
+ }),
]
}
@@ -366,7 +370,7 @@ pub fn main_args(args: &[String]) -> isize {
let markdown_input = Path::new(input).extension()
.map_or(false, |e| e == "md" || e == "markdown");
- let output = matches.opt_str("o").map(|s| PathBuf::from(&s));
+ let mut 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");
@@ -434,18 +438,29 @@ pub fn main_args(args: &[String]) -> isize {
}
let output_format = matches.opt_str("w");
+ let option_root_path = matches.opt_str("root-path").unwrap_or(String::new());
+ let mut root_path = format!("../../{}", option_root_path);
+ if !root_path.ends_with("/") {
+ root_path.push('/');
+ }
let res = acquire_input(PathBuf::from(input), externs, &matches, move |out| {
let Output { krate, passes, renderinfo } = out;
info!("going to format");
match output_format.as_ref().map(|s| &**s) {
Some("html") | None => {
+ if let Some(ref mut output) = output {
+ output.push(&option_root_path);
+ }
html::render::run(krate, &external_html, playground_url,
- output.unwrap_or(PathBuf::from("doc")),
+ output.clone().unwrap_or(PathBuf::from("doc")),
+ output.unwrap_or(PathBuf::from(&format!("doc/{}",
+ &option_root_path))),
passes.into_iter().collect(),
css_file_extension,
renderinfo,
sort_modules_alphabetically,
- themes)
+ themes,
+ root_path)
.expect("failed to generate documentation");
0
}