Move source HTML generation to own module
This commit is contained in:
@@ -72,6 +72,7 @@ use crate::html::format::fmt_impl_for_trait_page;
|
||||
use crate::html::item_type::ItemType;
|
||||
use crate::html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine, ErrorCodes, IdMap};
|
||||
use crate::html::{highlight, layout, static_files};
|
||||
use crate::html::sources;
|
||||
|
||||
use minifier;
|
||||
|
||||
@@ -173,7 +174,7 @@ struct Context {
|
||||
playground: Option<markdown::Playground>,
|
||||
}
|
||||
|
||||
struct SharedContext {
|
||||
crate 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,
|
||||
@@ -218,7 +219,7 @@ struct SharedContext {
|
||||
}
|
||||
|
||||
impl SharedContext {
|
||||
fn ensure_dir(&self, dst: &Path) -> Result<(), Error> {
|
||||
crate fn ensure_dir(&self, dst: &Path) -> Result<(), Error> {
|
||||
let mut dirs = self.created_dirs.borrow_mut();
|
||||
if !dirs.contains(dst) {
|
||||
try_err!(self.fs.create_dir_all(dst), dst);
|
||||
@@ -389,18 +390,6 @@ pub struct RenderInfo {
|
||||
pub owned_box_did: Option<DefId>,
|
||||
}
|
||||
|
||||
/// Helper struct to render all source code to HTML pages
|
||||
struct SourceCollector<'a> {
|
||||
scx: &'a mut SharedContext,
|
||||
|
||||
/// Root destination to place all HTML output into
|
||||
dst: PathBuf,
|
||||
}
|
||||
|
||||
/// Wrapper struct to render the source code of a file. This will do things like
|
||||
/// adding line numbers to the left-hand side.
|
||||
struct Source<'a>(&'a str);
|
||||
|
||||
// Helper structs for rendering items/sidebars and carrying along contextual
|
||||
// information
|
||||
|
||||
@@ -612,7 +601,7 @@ pub fn run(mut krate: clean::Crate,
|
||||
}
|
||||
let dst = output;
|
||||
scx.ensure_dir(&dst)?;
|
||||
krate = render_sources(&dst, &mut scx, krate)?;
|
||||
krate = sources::render(&dst, &mut scx, krate)?;
|
||||
let mut cx = Context {
|
||||
current: Vec::new(),
|
||||
dst,
|
||||
@@ -1293,18 +1282,6 @@ themePicker.onblur = handleThemeButtonsBlur;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn render_sources(dst: &Path, scx: &mut SharedContext,
|
||||
krate: clean::Crate) -> Result<clean::Crate, Error> {
|
||||
info!("emitting source files");
|
||||
let dst = dst.join("src").join(&krate.name);
|
||||
scx.ensure_dir(&dst)?;
|
||||
let mut folder = SourceCollector {
|
||||
dst,
|
||||
scx,
|
||||
};
|
||||
Ok(folder.fold_crate(krate))
|
||||
}
|
||||
|
||||
fn write_minify(fs:&DocFS, dst: PathBuf, contents: &str, enable_minification: bool
|
||||
) -> Result<(), Error> {
|
||||
if enable_minification {
|
||||
@@ -1384,33 +1361,6 @@ fn write_minify_replacer<W: Write>(
|
||||
}
|
||||
}
|
||||
|
||||
/// Takes a path to a source file and cleans the path to it. This canonicalizes
|
||||
/// things like ".." to components which preserve the "top down" hierarchy of a
|
||||
/// static HTML tree. Each component in the cleaned path will be passed as an
|
||||
/// argument to `f`. The very last component of the path (ie the file name) will
|
||||
/// be passed to `f` if `keep_filename` is true, and ignored otherwise.
|
||||
fn clean_srcpath<F>(src_root: &Path, p: &Path, keep_filename: bool, mut f: F)
|
||||
where
|
||||
F: FnMut(&OsStr),
|
||||
{
|
||||
// make it relative, if possible
|
||||
let p = p.strip_prefix(src_root).unwrap_or(p);
|
||||
|
||||
let mut iter = p.components().peekable();
|
||||
|
||||
while let Some(c) = iter.next() {
|
||||
if !keep_filename && iter.peek().is_none() {
|
||||
break;
|
||||
}
|
||||
|
||||
match c {
|
||||
Component::ParentDir => f("up".as_ref()),
|
||||
Component::Normal(c) => f(c),
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to find where an external crate is located, given that we're
|
||||
/// rendering in to the specified source destination.
|
||||
fn extern_location(e: &clean::ExternalCrate, extern_url: Option<&str>, dst: &Path)
|
||||
@@ -1444,102 +1394,6 @@ fn extern_location(e: &clean::ExternalCrate, extern_url: Option<&str>, dst: &Pat
|
||||
}).next().unwrap_or(Unknown) // Well, at least we tried.
|
||||
}
|
||||
|
||||
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.scx.include_sources
|
||||
// skip all invalid or macro spans
|
||||
&& item.source.filename.is_real()
|
||||
// skip non-local items
|
||||
&& item.def_id.is_local() {
|
||||
|
||||
// If it turns out that we couldn't read this file, then we probably
|
||||
// can't read any of the files (generating html output from json or
|
||||
// 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.scx
|
||||
.include_sources = match self.emit_source(&item.source.filename) {
|
||||
Ok(()) => true,
|
||||
Err(e) => {
|
||||
println!("warning: source code was requested to be rendered, \
|
||||
but processing `{}` had an error: {}",
|
||||
item.source.filename, e);
|
||||
println!(" skipping rendering of source code");
|
||||
false
|
||||
}
|
||||
};
|
||||
}
|
||||
self.fold_item_recur(item)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SourceCollector<'a> {
|
||||
/// Renders the given filename into its corresponding HTML source file.
|
||||
fn emit_source(&mut self, filename: &FileName) -> Result<(), Error> {
|
||||
let p = match *filename {
|
||||
FileName::Real(ref file) => file,
|
||||
_ => return Ok(()),
|
||||
};
|
||||
if self.scx.local_sources.contains_key(&**p) {
|
||||
// We've already emitted this source
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let contents = try_err!(fs::read_to_string(&p), &p);
|
||||
|
||||
// Remove the utf-8 BOM if any
|
||||
let contents = if contents.starts_with("\u{feff}") {
|
||||
&contents[3..]
|
||||
} else {
|
||||
&contents[..]
|
||||
};
|
||||
|
||||
// Create the intermediate directories
|
||||
let mut cur = self.dst.clone();
|
||||
let mut root_path = String::from("../../");
|
||||
let mut href = String::new();
|
||||
clean_srcpath(&self.scx.src_root, &p, false, |component| {
|
||||
cur.push(component);
|
||||
root_path.push_str("../");
|
||||
href.push_str(&component.to_string_lossy());
|
||||
href.push('/');
|
||||
});
|
||||
self.scx.ensure_dir(&cur)?;
|
||||
let mut fname = p.file_name()
|
||||
.expect("source has no filename")
|
||||
.to_os_string();
|
||||
fname.push(".html");
|
||||
cur.push(&fname);
|
||||
href.push_str(&fname.to_string_lossy());
|
||||
|
||||
let mut v = Vec::new();
|
||||
let title = format!("{} -- source", cur.file_name().expect("failed to get file name")
|
||||
.to_string_lossy());
|
||||
let desc = format!("Source to the Rust file `{}`.", filename);
|
||||
let page = layout::Page {
|
||||
title: &title,
|
||||
css_class: "source",
|
||||
root_path: &root_path,
|
||||
static_root_path: self.scx.static_root_path.as_deref(),
|
||||
description: &desc,
|
||||
keywords: BASIC_KEYWORDS,
|
||||
resource_suffix: &self.scx.resource_suffix,
|
||||
extra_scripts: &[&format!("source-files{}", self.scx.resource_suffix)],
|
||||
static_extra_scripts: &[&format!("source-script{}", self.scx.resource_suffix)],
|
||||
};
|
||||
try_err!(layout::render(&mut v, &self.scx.layout,
|
||||
&page, &(""), &Source(contents),
|
||||
self.scx.css_file_extension.is_some(),
|
||||
&self.scx.themes,
|
||||
self.scx.generate_search_filter), &cur);
|
||||
self.scx.fs.write(&cur, &v)?;
|
||||
self.scx.local_sources.insert(p.clone(), href);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl DocFolder for Cache {
|
||||
fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
|
||||
if item.def_id.is_local() {
|
||||
@@ -2399,7 +2253,7 @@ impl<'a> Item<'a> {
|
||||
(_, _, Unknown) => return None,
|
||||
};
|
||||
|
||||
clean_srcpath(&src_root, file, false, |component| {
|
||||
sources::clean_path(&src_root, file, false, |component| {
|
||||
path.push_str(&component.to_string_lossy());
|
||||
path.push('/');
|
||||
});
|
||||
@@ -5048,27 +4902,6 @@ fn sidebar_foreign_type(fmt: &mut fmt::Formatter<'_>, it: &clean::Item) -> fmt::
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl<'a> fmt::Display for Source<'a> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let Source(s) = *self;
|
||||
let lines = s.lines().count();
|
||||
let mut cols = 0;
|
||||
let mut tmp = lines;
|
||||
while tmp > 0 {
|
||||
cols += 1;
|
||||
tmp /= 10;
|
||||
}
|
||||
write!(fmt, "<pre class=\"line-numbers\">")?;
|
||||
for i in 1..=lines {
|
||||
write!(fmt, "<span id=\"{0}\">{0:1$}</span>\n", i, cols)?;
|
||||
}
|
||||
write!(fmt, "</pre>")?;
|
||||
write!(fmt, "{}",
|
||||
highlight::render_with_highlighting(s, None, None, None))?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn item_macro(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
|
||||
t: &clean::Macro) -> fmt::Result {
|
||||
wrap_into_docblock(w, |w| {
|
||||
@@ -5125,7 +4958,7 @@ fn item_keyword(w: &mut fmt::Formatter<'_>, cx: &Context,
|
||||
document(w, cx, it)
|
||||
}
|
||||
|
||||
const BASIC_KEYWORDS: &'static str = "rust, rustlang, rust-lang";
|
||||
crate const BASIC_KEYWORDS: &'static str = "rust, rustlang, rust-lang";
|
||||
|
||||
fn make_item_keywords(it: &clean::Item) -> String {
|
||||
format!("{}, {}", BASIC_KEYWORDS, it.name.as_ref().unwrap())
|
||||
|
||||
Reference in New Issue
Block a user