about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustdoc/html/render.rs179
-rw-r--r--src/librustdoc/html/sources.rs187
-rw-r--r--src/librustdoc/lib.rs1
3 files changed, 194 insertions, 173 deletions
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index b64e74468e6..c8921a92d33 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -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())
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
new file mode 100644
index 00000000000..c1f1f59d914
--- /dev/null
+++ b/src/librustdoc/html/sources.rs
@@ -0,0 +1,187 @@
+use crate::clean;
+use crate::docfs::PathError;
+use crate::fold::DocFolder;
+use crate::html::layout;
+use crate::html::render::{Error, SharedContext, BASIC_KEYWORDS};
+use crate::html::highlight;
+use std::ffi::OsStr;
+use std::fs;
+use std::path::{Component, Path, PathBuf};
+use std::fmt;
+use syntax::source_map::FileName;
+
+crate fn render(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))
+}
+
+/// 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,
+}
+
+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 = match fs::read_to_string(&p) {
+            Ok(contents) => contents,
+            Err(e) => {
+                return Err(Error::new(e, &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_path(&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)],
+        };
+        let result = 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);
+        if let Err(e) = result {
+            return Err(Error::new(e, &cur));
+        }
+        self.scx.fs.write(&cur, &v)?;
+        self.scx.local_sources.insert(p.clone(), href);
+        Ok(())
+    }
+}
+
+/// 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.
+pub fn clean_path<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,
+        }
+    }
+}
+
+/// 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);
+
+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(())
+    }
+}
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index e30b35937db..968578f957c 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -67,6 +67,7 @@ pub mod html {
     crate mod render;
     crate mod static_files;
     crate mod toc;
+    crate mod sources;
 }
 mod markdown;
 mod passes;