Skip to content

Commit

Permalink
Slim down rustdoc::html::render::Context
Browse files Browse the repository at this point in the history
Like the comment on `Context` explains, `Context` is supposed to be
lightweight, so we're putting everything that's immutable after
creation of the Context behind an `Arc<SharedContext>`.
  • Loading branch information
mitaa committed Apr 2, 2016
1 parent 0ef85c1 commit 95eb8a6
Showing 1 changed file with 47 additions and 40 deletions.
87 changes: 47 additions & 40 deletions src/librustdoc/html/render.rs
Expand Up @@ -91,12 +91,20 @@ pub struct Context {
/// String representation of how to get back to the root path of the 'doc/'
/// folder in terms of a relative URL.
pub root_path: String,
/// The path to the crate root source minus the file name.
/// Used for simplifying paths to the highlighted source code files.
pub src_root: PathBuf,
/// The current destination folder of where HTML artifacts should be placed.
/// This changes as the context descends into the module hierarchy.
pub 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.
pub render_redirect_pages: bool,
pub shared: Arc<SharedContext>,
}

pub struct SharedContext {
/// The path to the crate root source minus the file name.
/// Used for simplifying paths to the highlighted source code files.
pub src_root: PathBuf,
/// This describes the layout of each page, and is not modified after
/// creation of the context (contains info like the favicon and added html).
pub layout: layout::Layout,
Expand All @@ -106,10 +114,6 @@ pub struct Context {
pub include_sources: bool,
/// The local file sources we've emitted and their respective url-paths.
pub local_sources: HashMap<PathBuf, String>,
/// A flag, which when turned off, 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.
pub render_redirect_pages: bool,
/// All the passes that were run on this crate.
pub passes: HashSet<String>,
/// The base-URL of the issue tracker for when an item has been tagged with
Expand Down Expand Up @@ -259,7 +263,7 @@ pub struct Cache {

/// Helper struct to render all source code to HTML pages
struct SourceCollector<'a> {
cx: &'a mut Context,
scx: &'a mut SharedContext,

/// Root destination to place all HTML output into
dst: PathBuf,
Expand Down Expand Up @@ -412,43 +416,37 @@ pub fn run(mut krate: clean::Crate,
Some(p) => p.to_path_buf(),
None => PathBuf::new(),
};
let mut cx = Context {
dst: dst,
let mut scx = SharedContext {
src_root: src_root,
passes: passes,
current: Vec::new(),
root_path: String::new(),
include_sources: true,
local_sources: HashMap::new(),
issue_tracker_base_url: None,
layout: layout::Layout {
logo: "".to_string(),
favicon: "".to_string(),
external_html: external_html.clone(),
krate: krate.name.clone(),
playground_url: "".to_string(),
},
include_sources: true,
local_sources: HashMap::new(),
render_redirect_pages: false,
issue_tracker_base_url: None,
};

try_err!(mkdir(&cx.dst), &cx.dst);

// Crawl the crate attributes looking for attributes which control how we're
// going to emit HTML
if let Some(attrs) = krate.module.as_ref().map(|m| m.attrs.list("doc")) {
for attr in attrs {
match *attr {
clean::NameValue(ref x, ref s)
if "html_favicon_url" == *x => {
cx.layout.favicon = s.to_string();
scx.layout.favicon = s.to_string();
}
clean::NameValue(ref x, ref s)
if "html_logo_url" == *x => {
cx.layout.logo = s.to_string();
scx.layout.logo = s.to_string();
}
clean::NameValue(ref x, ref s)
if "html_playground_url" == *x => {
cx.layout.playground_url = s.to_string();
scx.layout.playground_url = s.to_string();
markdown::PLAYGROUND_KRATE.with(|slot| {
if slot.borrow().is_none() {
let name = krate.name.clone();
Expand All @@ -458,16 +456,25 @@ pub fn run(mut krate: clean::Crate,
}
clean::NameValue(ref x, ref s)
if "issue_tracker_base_url" == *x => {
cx.issue_tracker_base_url = Some(s.to_string());
scx.issue_tracker_base_url = Some(s.to_string());
}
clean::Word(ref x)
if "html_no_source" == *x => {
cx.include_sources = false;
scx.include_sources = false;
}
_ => {}
}
}
}
try_err!(mkdir(&dst), &dst);
krate = render_sources(&dst, &mut scx, krate)?;
let cx = Context {
current: Vec::new(),
root_path: String::new(),
dst: dst,
render_redirect_pages: false,
shared: Arc::new(scx),
};

// Crawl the crate to build various caches used for the output
let analysis = ::ANALYSISKEY.with(|a| a.clone());
Expand Down Expand Up @@ -538,7 +545,6 @@ pub fn run(mut krate: clean::Crate,
CURRENT_LOCATION_KEY.with(|s| s.borrow_mut().clear());

write_shared(&cx, &krate, &*cache, index)?;
let krate = render_sources(&mut cx, krate)?;

// And finally render the whole crate's documentation
cx.krate(krate)
Expand Down Expand Up @@ -760,16 +766,16 @@ fn write_shared(cx: &Context,
Ok(())
}

fn render_sources(cx: &mut Context,
fn render_sources(dst: &Path, scx: &mut SharedContext,
krate: clean::Crate) -> Result<clean::Crate, Error> {
info!("emitting source files");
let dst = cx.dst.join("src");
let dst = dst.join("src");
try_err!(mkdir(&dst), &dst);
let dst = dst.join(&krate.name);
try_err!(mkdir(&dst), &dst);
let mut folder = SourceCollector {
dst: dst,
cx: cx,
scx: scx,
};
Ok(folder.fold_crate(krate))
}
Expand Down Expand Up @@ -847,7 +853,7 @@ impl<'a> DocFolder for SourceCollector<'a> {
fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
// If we're including source files, and we haven't seen this file yet,
// then we need to render it out to the filesystem
if self.cx.include_sources
if self.scx.include_sources
// skip all invalid spans
&& item.source.filename != ""
// macros from other libraries get special filenames which we can
Expand All @@ -860,7 +866,7 @@ impl<'a> DocFolder for SourceCollector<'a> {
// something like that), so just don't include sources for the
// entire crate. The other option is maintaining this mapping on a
// per-file basis, but that's probably not worth it...
self.cx
self.scx
.include_sources = match self.emit_source(&item.source.filename) {
Ok(()) => true,
Err(e) => {
Expand All @@ -880,7 +886,7 @@ impl<'a> SourceCollector<'a> {
/// Renders the given filename into its corresponding HTML source file.
fn emit_source(&mut self, filename: &str) -> io::Result<()> {
let p = PathBuf::from(filename);
if self.cx.local_sources.contains_key(&p) {
if self.scx.local_sources.contains_key(&p) {
// We've already emitted this source
return Ok(());
}
Expand All @@ -901,7 +907,7 @@ impl<'a> SourceCollector<'a> {
let mut cur = self.dst.clone();
let mut root_path = String::from("../../");
let mut href = String::new();
clean_srcpath(&self.cx.src_root, &p, false, |component| {
clean_srcpath(&self.scx.src_root, &p, false, |component| {
cur.push(component);
mkdir(&cur).unwrap();
root_path.push_str("../");
Expand All @@ -925,10 +931,10 @@ impl<'a> SourceCollector<'a> {
description: &desc,
keywords: BASIC_KEYWORDS,
};
layout::render(&mut w, &self.cx.layout,
layout::render(&mut w, &self.scx.layout,
&page, &(""), &Source(contents))?;
w.flush()?;
self.cx.local_sources.insert(p, href);
self.scx.local_sources.insert(p, href);
Ok(())
}
}
Expand Down Expand Up @@ -1265,10 +1271,10 @@ impl Context {
let tyname = shortty(it).to_static_str();
let desc = if it.is_crate() {
format!("API documentation for the Rust `{}` crate.",
cx.layout.krate)
cx.shared.layout.krate)
} else {
format!("API documentation for the Rust `{}` {} in crate `{}`.",
it.name.as_ref().unwrap(), tyname, cx.layout.krate)
it.name.as_ref().unwrap(), tyname, cx.shared.layout.krate)
};
let keywords = make_item_keywords(it);
let page = layout::Page {
Expand All @@ -1286,7 +1292,7 @@ impl Context {
// write syscall all the time.
let mut writer = BufWriter::new(w);
if !cx.render_redirect_pages {
layout::render(&mut writer, &cx.layout, &page,
layout::render(&mut writer, &cx.shared.layout, &page,
&Sidebar{ cx: cx, item: it },
&Item{ cx: cx, item: it })?;

Expand Down Expand Up @@ -1434,10 +1440,11 @@ impl<'a> Item<'a> {
// know the span, so we plow forward and generate a proper url. The url
// has anchors for the line numbers that we're linking to.
} else if self.item.def_id.is_local() {
self.cx.local_sources.get(&PathBuf::from(&self.item.source.filename)).map(|path| {
let path = PathBuf::from(&self.item.source.filename);
self.cx.shared.local_sources.get(&path).map(|path| {
format!("{root}src/{krate}/{path}#{href}",
root = self.cx.root_path,
krate = self.cx.layout.krate,
krate = self.cx.shared.layout.krate,
path = path,
href = href)
})
Expand Down Expand Up @@ -1520,7 +1527,7 @@ impl<'a> fmt::Display for Item<'a> {
// [src] link in the downstream documentation will actually come back to
// this page, and this link will be auto-clicked. The `id` attribute is
// used to find the link to auto-click.
if self.cx.include_sources && !is_primitive {
if self.cx.shared.include_sources && !is_primitive {
if let Some(l) = self.href() {
write!(fmt, "<a id='src-{}' class='srclink' \
href='{}' title='{}'>[src]</a>",
Expand Down Expand Up @@ -1752,7 +1759,7 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Optio
format!("Deprecated{}{}", since, Markdown(&reason))
} else if stab.level == stability::Unstable {
let unstable_extra = if show_reason {
match (!stab.feature.is_empty(), &cx.issue_tracker_base_url, stab.issue) {
match (!stab.feature.is_empty(), &cx.shared.issue_tracker_base_url, stab.issue) {
(true, &Some(ref tracker_url), Some(issue_no)) if issue_no > 0 =>
format!(" (<code>{}</code> <a href=\"{}{}\">#{}</a>)",
Escape(&stab.feature), tracker_url, issue_no, issue_no),
Expand Down

0 comments on commit 95eb8a6

Please sign in to comment.