about summary refs log tree commit diff
diff options
context:
space:
mode:
authorKang Seonghoon <public+git@mearie.org>2014-12-01 20:46:51 +0900
committerKang Seonghoon <public+git@mearie.org>2014-12-01 20:53:11 +0900
commit08fb9aa2d218399ed6d246c97fb6cdd0d1150b59 (patch)
tree568aa3e6c255e0c8d3f4eef376ec96adc902cbe3
parent09f04bf2c919725d5ee69b8cbb34cdcbb3433e25 (diff)
downloadrust-08fb9aa2d218399ed6d246c97fb6cdd0d1150b59.tar.gz
rust-08fb9aa2d218399ed6d246c97fb6cdd0d1150b59.zip
rustdoc: Use relative paths in source renders.
Before: doc/src/collections/home/lifthrasiir/git/rust/src/libcollections/vec.rs.html
After: doc/src/collections/vec.rs.html

If the source code is in the parent dirs relative to the crate root,
`..` is replaced with `up` as expected. Any other error like non-UTF-8
paths or drive-relative paths falls back to the absolute path.

There might be a way to improve on false negatives, but this alone
should be enough for fixing #18370.
-rw-r--r--src/librustdoc/clean/mod.rs3
-rw-r--r--src/librustdoc/html/render.rs19
2 files changed, 17 insertions, 5 deletions
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 8270c8f3a20..a18804be275 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -53,6 +53,7 @@ use std::rc::Rc;
 use std::u32;
 use std::str::Str as StrTrait; // Conflicts with Str variant
 use std::char::Char as CharTrait; // Conflicts with Char variant
+use std::path::Path as FsPath; // Conflicts with Path struct
 
 use core::DocContext;
 use doctree;
@@ -115,6 +116,7 @@ impl<T: Clean<U>, U> Clean<Vec<U>> for syntax::owned_slice::OwnedSlice<T> {
 #[deriving(Clone, Encodable, Decodable)]
 pub struct Crate {
     pub name: String,
+    pub src: FsPath,
     pub module: Option<Item>,
     pub externs: Vec<(ast::CrateNum, ExternalCrate)>,
     pub primitives: Vec<PrimitiveType>,
@@ -194,6 +196,7 @@ impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
 
         Crate {
             name: name.to_string(),
+            src: cx.src.clone(),
             module: Some(module),
             externs: externs,
             primitives: primitives,
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 3fbb2a8749f..492517bad93 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -83,6 +83,9 @@ 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: Path,
     /// The current destination folder of where HTML artifacts should be placed.
     /// This changes as the context descends into the module hierarchy.
     pub dst: Path,
@@ -249,6 +252,7 @@ pub fn run(mut krate: clean::Crate,
            passes: HashSet<String>) -> io::IoResult<()> {
     let mut cx = Context {
         dst: dst,
+        src_root: krate.src.dir_path(),
         passes: passes,
         current: Vec::new(),
         root_path: String::new(),
@@ -642,8 +646,13 @@ fn mkdir(path: &Path) -> io::IoResult<()> {
 /// things like ".." to components which preserve the "top down" hierarchy of a
 /// static HTML tree.
 // FIXME (#9639): The closure should deal with &[u8] instead of &str
-fn clean_srcpath(src: &[u8], f: |&str|) {
+// FIXME (#9639): This is too conservative, rejecting non-UTF-8 paths
+fn clean_srcpath(src_root: &Path, src: &[u8], f: |&str|) {
     let p = Path::new(src);
+
+    // make it relative, if possible
+    let p = p.path_relative_from(src_root).unwrap_or(p);
+
     if p.as_vec() != b"." {
         for c in p.str_components().map(|x|x.unwrap()) {
             if ".." == c {
@@ -749,7 +758,7 @@ impl<'a> SourceCollector<'a> {
         // Create the intermediate directories
         let mut cur = self.dst.clone();
         let mut root_path = String::from_str("../../");
-        clean_srcpath(p.dirname(), |component| {
+        clean_srcpath(&self.cx.src_root, p.dirname(), |component| {
             cur.push(component);
             mkdir(&cur).unwrap();
             root_path.push_str("../");
@@ -1299,13 +1308,13 @@ impl<'a> Item<'a> {
     /// 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) -> Option<String> {
+    fn href(&self, cx: &Context) -> Option<String> {
         // If this item is part of the local crate, then we're guaranteed to
         // 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.
         if ast_util::is_local(self.item.def_id) {
             let mut path = Vec::new();
-            clean_srcpath(self.item.source.filename.as_bytes(), |component| {
+            clean_srcpath(&cx.src_root, self.item.source.filename.as_bytes(), |component| {
                 path.push(component.to_string());
             });
             let href = if self.item.source.loline == self.item.source.hiline {
@@ -1412,7 +1421,7 @@ impl<'a> fmt::Show for Item<'a> {
         // 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() {
+            match self.href(self.cx) {
                 Some(l) => {
                     try!(write!(fmt, "<a id='src-{}' href='{}'>[src]</a>",
                                 self.item.def_id.node, l));