]> git.lizzy.rs Git - rust.git/commitdiff
Add more elements in the sidebar
authorGuillaume Gomez <guillaume1.gomez@gmail.com>
Sat, 4 Nov 2017 19:45:12 +0000 (20:45 +0100)
committerGuillaume Gomez <guillaume1.gomez@gmail.com>
Tue, 7 Nov 2017 22:45:06 +0000 (23:45 +0100)
src/librustdoc/html/render.rs
src/test/rustdoc/sidebar-items.rs [new file with mode: 0644]

index 88e1f780d0342520f9b4315758a8649392cf80b1..eb59c57603aaed77eb0a1946e12b1ecf65cd17dd 100644 (file)
@@ -2498,7 +2498,7 @@ fn trait_item(w: &mut fmt::Formatter, cx: &Context, m: &clean::Item, t: &clean::
 
         if !foreign.is_empty() {
             write!(w, "
-                <h2 id='foreign-impls' class='section-header'>
+                <h2 id='foreign-impls' class='small-section-header'>
                   Implementations on Foreign Types<a href='#foreign-impls' class='anchor'></a>
                 </h2>
             ")?;
@@ -3591,7 +3591,8 @@ fn sidebar_assoc_items(it: &clean::Item) -> String {
             let mut links = HashSet::new();
             let ret = v.iter()
                        .filter_map(|i| if let Some(ref i) = i.inner_impl().trait_ {
-                           let out = format!("{:#}", i).replace("<", "&lt;").replace(">", "&gt;");
+                           let i_display = format!("{:#}", i);
+                           let out = Escape(&i_display);
                            let encoded = small_url_encode(&format!("{:#}", i));
                            let generated = format!("<a href=\"#impl-{}\">{}</a>", encoded, out);
                            if !links.contains(&generated) && links.insert(generated.clone()) {
@@ -3617,11 +3618,12 @@ fn sidebar_assoc_items(it: &clean::Item) -> String {
 fn sidebar_struct(fmt: &mut fmt::Formatter, it: &clean::Item,
                   s: &clean::Struct) -> fmt::Result {
     let mut sidebar = String::new();
+    let fields = get_struct_fields_name(&s.fields);
 
-    if s.fields.iter()
-               .any(|f| if let clean::StructFieldItem(..) = f.inner { true } else { false }) {
+    if !fields.is_empty() {
         if let doctree::Plain = s.struct_type {
-            sidebar.push_str("<li><a href=\"#fields\">Fields</a></li>");
+            sidebar.push_str(&format!("<a class=\"sidebar-title\" href=\"#fields\">Fields</a>\
+                                       <div class=\"sidebar-links\">{}</div>", fields));
         }
     }
 
@@ -3633,40 +3635,122 @@ fn sidebar_struct(fmt: &mut fmt::Formatter, it: &clean::Item,
     Ok(())
 }
 
+fn extract_for_impl_name(item: &clean::Item) -> Option<(String, String)> {
+    match item.inner {
+        clean::ItemEnum::ImplItem(ref i) => {
+            if let Some(ref trait_) = i.trait_ {
+                Some((format!("{:#}", i.for_), format!("{:#}", trait_)))
+            } else {
+                None
+            }
+        },
+        _ => None,
+    }
+}
+
 fn sidebar_trait(fmt: &mut fmt::Formatter, it: &clean::Item,
                  t: &clean::Trait) -> fmt::Result {
     let mut sidebar = String::new();
 
-    let has_types = t.items.iter().any(|m| m.is_associated_type());
-    let has_consts = t.items.iter().any(|m| m.is_associated_const());
-    let has_required = t.items.iter().any(|m| m.is_ty_method());
-    let has_provided = t.items.iter().any(|m| m.is_method());
+    let types = t.items
+                 .iter()
+                 .filter_map(|m| {
+                     match m.name {
+                         Some(ref name) if m.is_associated_type() => {
+                             Some(format!("<a href=\"#associatedtype.{name}\">{name}</a>",
+                                          name=name))
+                         }
+                         _ => None,
+                     }
+                 })
+                 .collect::<String>();
+    let consts = t.items
+                  .iter()
+                  .filter_map(|m| {
+                      match m.name {
+                          Some(ref name) if m.is_associated_const() => {
+                              Some(format!("<a href=\"#associatedconstant.{name}\">{name}</a>",
+                                           name=name))
+                          }
+                          _ => None,
+                      }
+                  })
+                  .collect::<String>();
+    let required = t.items
+                    .iter()
+                    .filter_map(|m| {
+                        match m.name {
+                            Some(ref name) if m.is_ty_method() => {
+                                Some(format!("<a href=\"#tymethod.{name}\">{name}</a>",
+                                             name=name))
+                            }
+                            _ => None,
+                        }
+                    })
+                    .collect::<String>();
+    let provided = t.items
+                    .iter()
+                    .filter_map(|m| {
+                        match m.name {
+                            Some(ref name) if m.is_method() => {
+                                Some(format!("<a href=\"#method.{name}\">{name}</a>", name=name))
+                            }
+                            _ => None,
+                        }
+                    })
+                    .collect::<String>();
 
-    if has_types {
-        sidebar.push_str("<li><a href=\"#associated-types\">Associated Types</a></li>");
+    if !types.is_empty() {
+        sidebar.push_str(&format!("<a class=\"sidebar-title\" href=\"#associated-types\">\
+                                   Associated Types</a><div class=\"sidebar-links\">{}</div>",
+                                  types));
     }
-    if has_consts {
-        sidebar.push_str("<li><a href=\"#associated-const\">Associated Constants</a></li>");
+    if !consts.is_empty() {
+        sidebar.push_str(&format!("<a class=\"sidebar-title\" href=\"#associated-const\">\
+                                   Associated Constants</a><div class=\"sidebar-links\">{}</div>",
+                                  consts));
     }
-    if has_required {
-        sidebar.push_str("<li><a href=\"#required-methods\">Required Methods</a></li>");
+    if !required.is_empty() {
+        sidebar.push_str(&format!("<a class=\"sidebar-title\" href=\"#required-methods\">\
+                                   Required Methods</a><div class=\"sidebar-links\">{}</div>",
+                                  required));
     }
-    if has_provided {
-        sidebar.push_str("<li><a href=\"#provided-methods\">Provided Methods</a></li>");
+    if !provided.is_empty() {
+        sidebar.push_str(&format!("<a class=\"sidebar-title\" href=\"#provided-methods\">\
+                                   Provided Methods</a><div class=\"sidebar-links\">{}</div>",
+                                  provided));
     }
 
     let c = cache();
 
     if let Some(implementors) = c.implementors.get(&it.def_id) {
-        if implementors.iter().any(|i| i.impl_.for_.def_id()
-                                   .map_or(false, |d| !c.paths.contains_key(&d)))
-        {
-            sidebar.push_str("<li><a href=\"#foreign-impls\">\
-                             Implementations on Foreign Types</a></li>");
-        }
-    }
-
-    sidebar.push_str("<li><a href=\"#implementors\">Implementors</a></li>");
+        let res = implementors.iter()
+                              .filter(|i| i.impl_.for_.def_id()
+                                                      .map_or(false, |d| !c.paths.contains_key(&d)))
+                              .filter_map(|i| {
+                                  if let Some(item) = implementor2item(&c, i) {
+                                      match extract_for_impl_name(&item) {
+                                          Some((ref name, ref url)) => {
+                                              Some(format!("<a href=\"#impl-{}\">{}</a>",
+                                                           small_url_encode(url),
+                                                           Escape(name)))
+                                          }
+                                          _ => None,
+                                      }
+                                  } else {
+                                      None
+                                  }
+                              })
+                              .collect::<String>();
+        if !res.is_empty() {
+            sidebar.push_str(&format!("<a class=\"sidebar-title\" href=\"#foreign-impls\">\
+                                       Implementations on Foreign Types</a><div \
+                                       class=\"sidebar-links\">{}</div>",
+                                      res));
+        }
+    }
+
+    sidebar.push_str("<a class=\"sidebar-title\" href=\"#implementors\">Implementors</a>");
 
     sidebar.push_str(&sidebar_assoc_items(it));
 
@@ -3693,13 +3777,29 @@ fn sidebar_typedef(fmt: &mut fmt::Formatter, it: &clean::Item,
     Ok(())
 }
 
+fn get_struct_fields_name(fields: &[clean::Item]) -> String {
+    fields.iter()
+          .filter(|f| if let clean::StructFieldItem(..) = f.inner {
+              true
+          } else {
+              false
+          })
+          .filter_map(|f| match f.name {
+              Some(ref name) => Some(format!("<a href=\"#structfield.{name}\">\
+                                              {name}</a>", name=name)),
+              _ => None,
+          })
+          .collect()
+}
+
 fn sidebar_union(fmt: &mut fmt::Formatter, it: &clean::Item,
                  u: &clean::Union) -> fmt::Result {
     let mut sidebar = String::new();
+    let fields = get_struct_fields_name(&u.fields);
 
-    if u.fields.iter()
-               .any(|f| if let clean::StructFieldItem(..) = f.inner { true } else { false }) {
-        sidebar.push_str("<li><a href=\"#fields\">Fields</a></li>");
+    if !fields.is_empty() {
+        sidebar.push_str(&format!("<a class=\"sidebar-title\" href=\"#fields\">Fields</a>\
+                                   <div class=\"sidebar-links\">{}</div>", fields));
     }
 
     sidebar.push_str(&sidebar_assoc_items(it));
@@ -3714,8 +3814,16 @@ fn sidebar_enum(fmt: &mut fmt::Formatter, it: &clean::Item,
                 e: &clean::Enum) -> fmt::Result {
     let mut sidebar = String::new();
 
-    if !e.variants.is_empty() {
-        sidebar.push_str("<li><a href=\"#variants\">Variants</a></li>");
+    let variants = e.variants.iter()
+                             .filter_map(|v| match v.name {
+                                 Some(ref name) => Some(format!("<a href=\"#variant.{name}\">{name}\
+                                                                 </a>", name = name)),
+                                 _ => None,
+                             })
+                             .collect::<String>();
+    if !variants.is_empty() {
+        sidebar.push_str(&format!("<a class=\"sidebar-title\" href=\"#variants\">Variants</a>\
+                                   <div class=\"sidebar-links\">{}</div>", variants));
     }
 
     sidebar.push_str(&sidebar_assoc_items(it));
diff --git a/src/test/rustdoc/sidebar-items.rs b/src/test/rustdoc/sidebar-items.rs
new file mode 100644 (file)
index 0000000..9be4044
--- /dev/null
@@ -0,0 +1,59 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_name = "foo"]
+
+// @has foo/trait.Foo.html
+// @has - '//*[@class="sidebar-title"][@href="#required-methods"]' 'Required Methods'
+// @has - '//*[@class="sidebar-links"]/a' 'bar'
+// @has - '//*[@class="sidebar-title"][@href="#provided-methods"]' 'Provided Methods'
+// @has - '//*[@class="sidebar-links"]/a' 'foo'
+// @has - '//*[@class="sidebar-title"][@href="#associated-const"]' 'Associated Constants'
+// @has - '//*[@class="sidebar-links"]/a' 'BAR'
+// @has - '//*[@class="sidebar-title"][@href="#associated-types"]' 'Associated Types'
+// @has - '//*[@class="sidebar-links"]/a' 'Output'
+pub trait Foo {
+    const BAR: u32 = 0;
+    type Output: ?Sized;
+
+    fn foo() {}
+    fn bar() -> Self::Output;
+}
+
+// @has foo/struct.Bar.html
+// @has - '//*[@class="sidebar-title"][@href="#fields"]' 'Fields'
+// @has - '//*[@class="sidebar-links"]/a[@href="#structfield.f"]' 'f'
+// @has - '//*[@class="sidebar-links"]/a[@href="#structfield.u"]' 'u'
+// @!has - '//*[@class="sidebar-links"]/a' 'w'
+pub struct Bar {
+    pub f: u32,
+    pub u: u32,
+    w: u32,
+}
+
+// @has foo/enum.En.html
+// @has - '//*[@class="sidebar-title"][@href="#variants"]' 'Variants'
+// @has - '//*[@class="sidebar-links"]/a' 'foo'
+// @has - '//*[@class="sidebar-links"]/a' 'bar'
+pub enum En {
+    foo,
+    bar,
+}
+
+// @has foo/union.MyUnion.html
+// @has - '//*[@class="sidebar-title"][@href="#fields"]' 'Fields'
+// @has - '//*[@class="sidebar-links"]/a[@href="#structfield.f1"]' 'f1'
+// @has - '//*[@class="sidebar-links"]/a[@href="#structfield.f2"]' 'f2'
+// @!has - '//*[@class="sidebar-links"]/a' 'w'
+pub union MyUnion {
+    pub f1: u32,
+    pub f2: f32,
+    w: u32,
+}