]> git.lizzy.rs Git - rust.git/commitdiff
Refactor src-link creation for local sources
authormitaa <mitaa.ceb@gmail.com>
Sat, 27 Feb 2016 06:35:05 +0000 (07:35 +0100)
committermitaa <mitaa.ceb@gmail.com>
Thu, 3 Mar 2016 15:11:10 +0000 (16:11 +0100)
Since we emit the sources beforhand we actually **know** whether we
can safely create src-links to these files and where they are stored.

src/librustdoc/html/render.rs

index af6dec8dc868895a972afbcb1b3283d9304ae426..c9c9f1968133ee5789d01f99aad5af70e5fe3c91 100644 (file)
@@ -104,6 +104,8 @@ pub struct Context {
     /// the source files are present in the html rendering, then this will be
     /// `true`.
     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.
@@ -262,8 +264,6 @@ pub struct Cache {
 struct SourceCollector<'a> {
     cx: &'a mut Context,
 
-    /// Processed source-file paths
-    seen: HashSet<String>,
     /// Root destination to place all HTML output into
     dst: PathBuf,
 }
@@ -423,6 +423,7 @@ pub fn run(mut krate: clean::Crate,
             playground_url: "".to_string(),
         },
         include_sources: true,
+        local_sources: HashMap::new(),
         render_redirect_pages: false,
         issue_tracker_base_url: None,
     };
@@ -770,11 +771,8 @@ fn render_sources(cx: &mut Context,
     try_err!(mkdir(&dst), &dst);
     let mut folder = SourceCollector {
         dst: dst,
-        seen: HashSet::new(),
         cx: cx,
     };
-    // skip all invalid spans
-    folder.seen.insert("".to_string());
     Ok(folder.fold_crate(krate))
 }
 
@@ -866,7 +864,13 @@ 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 && !self.seen.contains(&item.source.filename) {
+        if self.cx.include_sources
+            // skip all invalid spans
+            && item.source.filename != ""
+            // macros from other libraries get special filenames which we can
+            // safely ignore
+            && !(item.source.filename.starts_with("<")
+                && item.source.filename.ends_with("macros>")) {
 
             // 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
@@ -884,7 +888,6 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
                     false
                 }
             };
-            self.seen.insert(item.source.filename.clone());
         }
 
         self.fold_item_recur(item)
@@ -895,19 +898,14 @@ 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) {
+            // We've already emitted this source
+            return Ok(());
+        }
 
-        // If we couldn't open this file, then just returns because it
-        // probably means that it's some standard library macro thing and we
-        // can't have the source to it anyway.
         let mut contents = Vec::new();
-        match File::open(&p).and_then(|mut f| f.read_to_end(&mut contents)) {
-            Ok(r) => r,
-            // macros from other libraries get special filenames which we can
-            // safely ignore
-            Err(..) if filename.starts_with("<") &&
-                       filename.ends_with("macros>") => return Ok(()),
-            Err(e) => return Err(e)
-        };
+        try!(File::open(&p).and_then(|mut f| f.read_to_end(&mut contents)));
+
         let contents = str::from_utf8(&contents).unwrap();
 
         // Remove the utf-8 BOM if any
@@ -920,16 +918,20 @@ fn emit_source(&mut self, filename: &str) -> io::Result<()> {
         // Create the intermediate directories
         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| {
             cur.push(component);
             mkdir(&cur).unwrap();
             root_path.push_str("../");
+            href.push_str(component);
+            href.push('/');
         });
-
         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 w = BufWriter::new(try!(File::create(&cur)));
         let title = format!("{} -- source", cur.file_name().unwrap()
                                                .to_string_lossy());
@@ -944,7 +946,8 @@ fn emit_source(&mut self, filename: &str) -> io::Result<()> {
         try!(layout::render(&mut w, &self.cx.layout,
                             &page, &(""), &Source(contents)));
         try!(w.flush());
-        return Ok(());
+        self.cx.local_sources.insert(p, href);
+        Ok(())
     }
 }
 
@@ -1459,7 +1462,7 @@ fn ismodule(&self) -> bool {
     /// If `None` is returned, then a source link couldn't be generated. This
     /// may happen, for example, with externally inlined items where the source
     /// of their crate documentation isn't known.
-    fn href(&self, cx: &Context) -> Option<String> {
+    fn href(&self) -> Option<String> {
         let href = if self.item.source.loline == self.item.source.hiline {
             format!("{}", self.item.source.loline)
         } else {
@@ -1492,25 +1495,13 @@ fn href(&self, cx: &Context) -> Option<String> {
         // 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() {
-            let mut path = Vec::new();
-            clean_srcpath(&cx.src_root, Path::new(&self.item.source.filename),
-                          true, |component| {
-                path.push(component.to_string());
-            });
-
-            // If the span points into an external macro the
-            // source-file will be bogus, i.e `<foo macros>`
-            let filename = &self.item.source.filename;
-            if !(filename.starts_with("<") && filename.ends_with("macros>")) {
-                Some(format!("{root}src/{krate}/{path}.html#{href}",
-                             root = self.cx.root_path,
-                             krate = self.cx.layout.krate,
-                             path = path.join("/"),
-                             href = href))
-            } else {
-                None
-            }
-
+            self.cx.local_sources.get(&PathBuf::from(&self.item.source.filename)).map(|path| {
+                format!("{root}src/{krate}/{path}.html#{href}",
+                        root = self.cx.root_path,
+                        krate = self.cx.layout.krate,
+                        path = path,
+                        href = href)
+            })
         // If this item is not part of the local crate, then things get a little
         // trickier. We don't actually know the span of the external item, but
         // we know that the documentation on the other end knows the span!
@@ -1590,7 +1581,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         // 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 {
-            match self.href(self.cx) {
+            match self.href() {
                 Some(l) => {
                     try!(write!(fmt, "<a id='src-{}' class='srclink' \
                                        href='{}' title='{}'>[src]</a>",