diff options
| author | bors <bors@rust-lang.org> | 2017-11-01 01:45:58 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2017-11-01 01:45:58 +0000 |
| commit | fc3e12a03c8d5298ddfac6fb8c14c1b918eb55a8 (patch) | |
| tree | d78c6e67c4d7ee4061f03e7da07ae6c112d48cd0 | |
| parent | f3b900cc3b122c7e9eb78ca28bec18df68791b08 (diff) | |
| parent | 6fa521c491b365b354771213186e35c2e2e7a628 (diff) | |
Auto merge of #45187 - GuillaumeGomez:doc-ui-improvement, r=QuietMisdreavus
Improve sidebar rendering and add methods list I suppose it can be reviewed as is, but this is just the first step of a more global plan. cc @rust-lang/docs @nical And a screenshot of course: <img width="1440" alt="screen shot 2017-10-10 at 23 38 45" src="https://user-images.githubusercontent.com/3050060/31412170-657beaf6-ae14-11e7-9f01-1e562a034595.png">
| -rw-r--r-- | src/librustdoc/html/render.rs | 146 | ||||
| -rw-r--r-- | src/librustdoc/html/static/rustdoc.css | 27 | ||||
| -rw-r--r-- | src/tools/linkchecker/main.rs | 17 |
3 files changed, 142 insertions, 48 deletions
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index ac2cb1665a7..edd01a66075 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -37,7 +37,7 @@ pub use self::ExternalLocation::*; use std::ascii::AsciiExt; use std::cell::RefCell; use std::cmp::Ordering; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, HashSet}; use std::default::Default; use std::error; use std::fmt::{self, Display, Formatter, Write as FmtWrite}; @@ -3207,12 +3207,37 @@ fn render_deref_methods(w: &mut fmt::Formatter, cx: &Context, impl_: &Impl, } } +fn should_render_item(item: &clean::Item, deref_mut_: bool) -> bool { + let self_type_opt = match item.inner { + clean::MethodItem(ref method) => method.decl.self_type(), + clean::TyMethodItem(ref method) => method.decl.self_type(), + _ => None + }; + + if let Some(self_ty) = self_type_opt { + let (by_mut_ref, by_box) = match self_ty { + SelfTy::SelfBorrowed(_, mutability) | + SelfTy::SelfExplicit(clean::BorrowedRef { mutability, .. }) => { + (mutability == Mutability::Mutable, false) + }, + SelfTy::SelfExplicit(clean::ResolvedPath { did, .. }) => { + (false, Some(did) == cache().owned_box_did) + }, + _ => (false, false), + }; + + (deref_mut_ || !by_mut_ref) && !by_box + } else { + false + } +} + fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLink, render_mode: RenderMode, outer_version: Option<&str>, show_def_docs: bool) -> fmt::Result { if render_mode == RenderMode::Normal { let id = derive_id(match i.inner_impl().trait_ { - Some(ref t) => format!("impl-{}", Escape(&format!("{:#}", t))), + Some(ref t) => format!("impl-{}", small_url_encode(&format!("{:#}", t))), None => "impl".to_string(), }); write!(w, "<h3 id='{}' class='impl'><span class='in-band'><code>{}</code>", @@ -3244,30 +3269,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi let render_method_item: bool = match render_mode { RenderMode::Normal => true, - RenderMode::ForDeref { mut_: deref_mut_ } => { - let self_type_opt = match item.inner { - clean::MethodItem(ref method) => method.decl.self_type(), - clean::TyMethodItem(ref method) => method.decl.self_type(), - _ => None - }; - - if let Some(self_ty) = self_type_opt { - let (by_mut_ref, by_box) = match self_ty { - SelfTy::SelfBorrowed(_, mutability) | - SelfTy::SelfExplicit(clean::BorrowedRef { mutability, .. }) => { - (mutability == Mutability::Mutable, false) - }, - SelfTy::SelfExplicit(clean::ResolvedPath { did, .. }) => { - (false, Some(did) == cache().owned_box_did) - }, - _ => (false, false), - }; - - (deref_mut_ || !by_mut_ref) && !by_box - } else { - false - } - }, + RenderMode::ForDeref { mut_: deref_mut_ } => should_render_item(&item, deref_mut_), }; match item.inner { @@ -3514,12 +3516,48 @@ impl<'a> fmt::Display for Sidebar<'a> { } } +fn get_methods(i: &clean::Impl, for_deref: bool) -> Vec<String> { + i.items.iter().filter_map(|item| { + match item.name { + // Maybe check with clean::Visibility::Public as well? + Some(ref name) if !name.is_empty() && item.visibility.is_some() && item.is_method() => { + if !for_deref || should_render_item(item, false) { + Some(format!("<a href=\"#method.{name}\">{name}</a>", name = name)) + } else { + None + } + } + _ => None, + } + }).collect::<Vec<_>>() +} + +// The point is to url encode any potential character from a type with genericity. +fn small_url_encode(s: &str) -> String { + s.replace("<", "%3C") + .replace(">", "%3E") + .replace(" ", "%20") + .replace("?", "%3F") + .replace("'", "%27") + .replace("&", "%26") + .replace(",", "%2C") + .replace(":", "%3A") + .replace(";", "%3B") + .replace("[", "%5B") + .replace("]", "%5D") +} + fn sidebar_assoc_items(it: &clean::Item) -> String { let mut out = String::new(); let c = cache(); if let Some(v) = c.impls.get(&it.def_id) { - if v.iter().any(|i| i.inner_impl().trait_.is_none()) { - out.push_str("<li><a href=\"#methods\">Methods</a></li>"); + let ret = v.iter() + .filter(|i| i.inner_impl().trait_.is_none()) + .flat_map(|i| get_methods(i.inner_impl(), false)) + .collect::<String>(); + if !ret.is_empty() { + out.push_str(&format!("<a class=\"sidebar-title\" href=\"#methods\">Methods\ + </a><div class=\"sidebar-links\">{}</div>", ret)); } if v.iter().any(|i| i.inner_impl().trait_.is_some()) { @@ -3535,16 +3573,40 @@ fn sidebar_assoc_items(it: &clean::Item) -> String { let inner_impl = target.def_id().or(target.primitive_type().and_then(|prim| { c.primitive_locations.get(&prim).cloned() })).and_then(|did| c.impls.get(&did)); - if inner_impl.is_some() { - out.push_str("<li><a href=\"#deref-methods\">"); + if let Some(impls) = inner_impl { + out.push_str("<a class=\"sidebar-title\" href=\"#deref-methods\">"); out.push_str(&format!("Methods from {:#}<Target={:#}>", - impl_.inner_impl().trait_.as_ref().unwrap(), - target)); - out.push_str("</a></li>"); + impl_.inner_impl().trait_.as_ref().unwrap(), + target)); + out.push_str("</a>"); + let ret = impls.iter() + .filter(|i| i.inner_impl().trait_.is_none()) + .flat_map(|i| get_methods(i.inner_impl(), true)) + .collect::<String>(); + out.push_str(&format!("<div class=\"sidebar-links\">{}</div>", ret)); } } } - out.push_str("<li><a href=\"#implementations\">Trait Implementations</a></li>"); + 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("<", "<").replace(">", ">"); + let encoded = small_url_encode(&format!("{:#}", i)); + let generated = format!("<a href=\"#impl-{}\">{}</a>", encoded, out); + if !links.contains(&generated) && links.insert(generated.clone()) { + Some(generated) + } else { + None + } + } else { + None + }) + .collect::<String>(); + if !ret.is_empty() { + out.push_str("<a class=\"sidebar-title\" href=\"#implementations\">\ + Trait Implementations</a>"); + out.push_str(&format!("<div class=\"sidebar-links\">{}</div>", ret)); + } } } @@ -3565,7 +3627,7 @@ fn sidebar_struct(fmt: &mut fmt::Formatter, it: &clean::Item, sidebar.push_str(&sidebar_assoc_items(it)); if !sidebar.is_empty() { - write!(fmt, "<div class=\"block items\"><ul>{}</ul></div>", sidebar)?; + write!(fmt, "<div class=\"block items\">{}</div>", sidebar)?; } Ok(()) } @@ -3592,8 +3654,6 @@ fn sidebar_trait(fmt: &mut fmt::Formatter, it: &clean::Item, sidebar.push_str("<li><a href=\"#provided-methods\">Provided Methods</a></li>"); } - sidebar.push_str(&sidebar_assoc_items(it)); - let c = cache(); if let Some(implementors) = c.implementors.get(&it.def_id) { @@ -3607,7 +3667,9 @@ fn sidebar_trait(fmt: &mut fmt::Formatter, it: &clean::Item, sidebar.push_str("<li><a href=\"#implementors\">Implementors</a></li>"); - write!(fmt, "<div class=\"block items\"><ul>{}</ul></div>", sidebar) + sidebar.push_str(&sidebar_assoc_items(it)); + + write!(fmt, "<div class=\"block items\">{}</div>", sidebar) } fn sidebar_primitive(fmt: &mut fmt::Formatter, it: &clean::Item, @@ -3615,7 +3677,7 @@ fn sidebar_primitive(fmt: &mut fmt::Formatter, it: &clean::Item, let sidebar = sidebar_assoc_items(it); if !sidebar.is_empty() { - write!(fmt, "<div class=\"block items\"><ul>{}</ul></div>", sidebar)?; + write!(fmt, "<div class=\"block items\">{}</div>", sidebar)?; } Ok(()) } @@ -3625,7 +3687,7 @@ fn sidebar_typedef(fmt: &mut fmt::Formatter, it: &clean::Item, let sidebar = sidebar_assoc_items(it); if !sidebar.is_empty() { - write!(fmt, "<div class=\"block items\"><ul>{}</ul></div>", sidebar)?; + write!(fmt, "<div class=\"block items\">{}</div>", sidebar)?; } Ok(()) } @@ -3642,7 +3704,7 @@ fn sidebar_union(fmt: &mut fmt::Formatter, it: &clean::Item, sidebar.push_str(&sidebar_assoc_items(it)); if !sidebar.is_empty() { - write!(fmt, "<div class=\"block items\"><ul>{}</ul></div>", sidebar)?; + write!(fmt, "<div class=\"block items\">{}</div>", sidebar)?; } Ok(()) } @@ -3658,7 +3720,7 @@ fn sidebar_enum(fmt: &mut fmt::Formatter, it: &clean::Item, sidebar.push_str(&sidebar_assoc_items(it)); if !sidebar.is_empty() { - write!(fmt, "<div class=\"block items\"><ul>{}</ul></div>", sidebar)?; + write!(fmt, "<div class=\"block items\">{}</div>", sidebar)?; } Ok(()) } diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 9978435a112..dcb0de3bb92 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -188,18 +188,16 @@ nav.sub { .js-only, .hidden { display: none !important; } -.sidebar { - padding: 10px; -} .sidebar img { margin: 20px auto; display: block; + margin-top: 10px; } .sidebar .location { border: 1px solid; font-size: 17px; - margin: 30px 0 20px 0; + margin: 30px 10px 20px 10px; text-align: center; word-wrap: break-word; } @@ -220,7 +218,7 @@ nav.sub { .location a:first-child { font-weight: 500; } .block { - padding: 0 10px; + padding: 0; margin-bottom: 14px; } .block h2, .block h3 { @@ -229,7 +227,7 @@ nav.sub { text-align: center; } .block ul, .block li { - margin: 0; + margin: 0 10px; padding: 0; list-style: none; } @@ -245,6 +243,23 @@ nav.sub { transition: border 500ms ease-out; } +.sidebar-title { + border-top: 1px solid #777; + border-bottom: 1px solid #777; + text-align: center; + font-size: 17px; + margin-bottom: 5px; +} + +.sidebar-links { + margin-bottom: 15px; +} + +.sidebar-links > a { + padding-left: 10px; + width: 100%; +} + .content { padding: 15px 0; } diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index 3ea2e6313af..e0153e1e6f6 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -69,15 +69,32 @@ struct FileEntry { type Cache = HashMap<PathBuf, FileEntry>; +fn small_url_encode(s: &str) -> String { + s.replace("<", "%3C") + .replace(">", "%3E") + .replace(" ", "%20") + .replace("?", "%3F") + .replace("'", "%27") + .replace("&", "%26") + .replace(",", "%2C") + .replace(":", "%3A") + .replace(";", "%3B") + .replace("[", "%5B") + .replace("]", "%5D") +} + impl FileEntry { fn parse_ids(&mut self, file: &Path, contents: &str, errors: &mut bool) { if self.ids.is_empty() { with_attrs_in_source(contents, " id", |fragment, i, _| { let frag = fragment.trim_left_matches("#").to_owned(); + let encoded = small_url_encode(&frag); if !self.ids.insert(frag) { *errors = true; println!("{}:{}: id is not unique: `{}`", file.display(), i, fragment); } + // Just in case, we also add the encoded id. + self.ids.insert(encoded); }); } } |
