Skip to content

Commit fc3e12a

Browse files
committed
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">
2 parents f3b900c + 6fa521c commit fc3e12a

File tree

3 files changed

+142
-48
lines changed

3 files changed

+142
-48
lines changed

src/librustdoc/html/render.rs

+104-42
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ pub use self::ExternalLocation::*;
3737
use std::ascii::AsciiExt;
3838
use std::cell::RefCell;
3939
use std::cmp::Ordering;
40-
use std::collections::BTreeMap;
40+
use std::collections::{BTreeMap, HashSet};
4141
use std::default::Default;
4242
use std::error;
4343
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,
32073207
}
32083208
}
32093209

3210+
fn should_render_item(item: &clean::Item, deref_mut_: bool) -> bool {
3211+
let self_type_opt = match item.inner {
3212+
clean::MethodItem(ref method) => method.decl.self_type(),
3213+
clean::TyMethodItem(ref method) => method.decl.self_type(),
3214+
_ => None
3215+
};
3216+
3217+
if let Some(self_ty) = self_type_opt {
3218+
let (by_mut_ref, by_box) = match self_ty {
3219+
SelfTy::SelfBorrowed(_, mutability) |
3220+
SelfTy::SelfExplicit(clean::BorrowedRef { mutability, .. }) => {
3221+
(mutability == Mutability::Mutable, false)
3222+
},
3223+
SelfTy::SelfExplicit(clean::ResolvedPath { did, .. }) => {
3224+
(false, Some(did) == cache().owned_box_did)
3225+
},
3226+
_ => (false, false),
3227+
};
3228+
3229+
(deref_mut_ || !by_mut_ref) && !by_box
3230+
} else {
3231+
false
3232+
}
3233+
}
3234+
32103235
fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLink,
32113236
render_mode: RenderMode, outer_version: Option<&str>,
32123237
show_def_docs: bool) -> fmt::Result {
32133238
if render_mode == RenderMode::Normal {
32143239
let id = derive_id(match i.inner_impl().trait_ {
3215-
Some(ref t) => format!("impl-{}", Escape(&format!("{:#}", t))),
3240+
Some(ref t) => format!("impl-{}", small_url_encode(&format!("{:#}", t))),
32163241
None => "impl".to_string(),
32173242
});
32183243
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
32443269

32453270
let render_method_item: bool = match render_mode {
32463271
RenderMode::Normal => true,
3247-
RenderMode::ForDeref { mut_: deref_mut_ } => {
3248-
let self_type_opt = match item.inner {
3249-
clean::MethodItem(ref method) => method.decl.self_type(),
3250-
clean::TyMethodItem(ref method) => method.decl.self_type(),
3251-
_ => None
3252-
};
3253-
3254-
if let Some(self_ty) = self_type_opt {
3255-
let (by_mut_ref, by_box) = match self_ty {
3256-
SelfTy::SelfBorrowed(_, mutability) |
3257-
SelfTy::SelfExplicit(clean::BorrowedRef { mutability, .. }) => {
3258-
(mutability == Mutability::Mutable, false)
3259-
},
3260-
SelfTy::SelfExplicit(clean::ResolvedPath { did, .. }) => {
3261-
(false, Some(did) == cache().owned_box_did)
3262-
},
3263-
_ => (false, false),
3264-
};
3265-
3266-
(deref_mut_ || !by_mut_ref) && !by_box
3267-
} else {
3268-
false
3269-
}
3270-
},
3272+
RenderMode::ForDeref { mut_: deref_mut_ } => should_render_item(&item, deref_mut_),
32713273
};
32723274

32733275
match item.inner {
@@ -3514,12 +3516,48 @@ impl<'a> fmt::Display for Sidebar<'a> {
35143516
}
35153517
}
35163518

3519+
fn get_methods(i: &clean::Impl, for_deref: bool) -> Vec<String> {
3520+
i.items.iter().filter_map(|item| {
3521+
match item.name {
3522+
// Maybe check with clean::Visibility::Public as well?
3523+
Some(ref name) if !name.is_empty() && item.visibility.is_some() && item.is_method() => {
3524+
if !for_deref || should_render_item(item, false) {
3525+
Some(format!("<a href=\"#method.{name}\">{name}</a>", name = name))
3526+
} else {
3527+
None
3528+
}
3529+
}
3530+
_ => None,
3531+
}
3532+
}).collect::<Vec<_>>()
3533+
}
3534+
3535+
// The point is to url encode any potential character from a type with genericity.
3536+
fn small_url_encode(s: &str) -> String {
3537+
s.replace("<", "%3C")
3538+
.replace(">", "%3E")
3539+
.replace(" ", "%20")
3540+
.replace("?", "%3F")
3541+
.replace("'", "%27")
3542+
.replace("&", "%26")
3543+
.replace(",", "%2C")
3544+
.replace(":", "%3A")
3545+
.replace(";", "%3B")
3546+
.replace("[", "%5B")
3547+
.replace("]", "%5D")
3548+
}
3549+
35173550
fn sidebar_assoc_items(it: &clean::Item) -> String {
35183551
let mut out = String::new();
35193552
let c = cache();
35203553
if let Some(v) = c.impls.get(&it.def_id) {
3521-
if v.iter().any(|i| i.inner_impl().trait_.is_none()) {
3522-
out.push_str("<li><a href=\"#methods\">Methods</a></li>");
3554+
let ret = v.iter()
3555+
.filter(|i| i.inner_impl().trait_.is_none())
3556+
.flat_map(|i| get_methods(i.inner_impl(), false))
3557+
.collect::<String>();
3558+
if !ret.is_empty() {
3559+
out.push_str(&format!("<a class=\"sidebar-title\" href=\"#methods\">Methods\
3560+
</a><div class=\"sidebar-links\">{}</div>", ret));
35233561
}
35243562

35253563
if v.iter().any(|i| i.inner_impl().trait_.is_some()) {
@@ -3535,16 +3573,40 @@ fn sidebar_assoc_items(it: &clean::Item) -> String {
35353573
let inner_impl = target.def_id().or(target.primitive_type().and_then(|prim| {
35363574
c.primitive_locations.get(&prim).cloned()
35373575
})).and_then(|did| c.impls.get(&did));
3538-
if inner_impl.is_some() {
3539-
out.push_str("<li><a href=\"#deref-methods\">");
3576+
if let Some(impls) = inner_impl {
3577+
out.push_str("<a class=\"sidebar-title\" href=\"#deref-methods\">");
35403578
out.push_str(&format!("Methods from {:#}&lt;Target={:#}&gt;",
3541-
impl_.inner_impl().trait_.as_ref().unwrap(),
3542-
target));
3543-
out.push_str("</a></li>");
3579+
impl_.inner_impl().trait_.as_ref().unwrap(),
3580+
target));
3581+
out.push_str("</a>");
3582+
let ret = impls.iter()
3583+
.filter(|i| i.inner_impl().trait_.is_none())
3584+
.flat_map(|i| get_methods(i.inner_impl(), true))
3585+
.collect::<String>();
3586+
out.push_str(&format!("<div class=\"sidebar-links\">{}</div>", ret));
35443587
}
35453588
}
35463589
}
3547-
out.push_str("<li><a href=\"#implementations\">Trait Implementations</a></li>");
3590+
let mut links = HashSet::new();
3591+
let ret = v.iter()
3592+
.filter_map(|i| if let Some(ref i) = i.inner_impl().trait_ {
3593+
let out = format!("{:#}", i).replace("<", "&lt;").replace(">", "&gt;");
3594+
let encoded = small_url_encode(&format!("{:#}", i));
3595+
let generated = format!("<a href=\"#impl-{}\">{}</a>", encoded, out);
3596+
if !links.contains(&generated) && links.insert(generated.clone()) {
3597+
Some(generated)
3598+
} else {
3599+
None
3600+
}
3601+
} else {
3602+
None
3603+
})
3604+
.collect::<String>();
3605+
if !ret.is_empty() {
3606+
out.push_str("<a class=\"sidebar-title\" href=\"#implementations\">\
3607+
Trait Implementations</a>");
3608+
out.push_str(&format!("<div class=\"sidebar-links\">{}</div>", ret));
3609+
}
35483610
}
35493611
}
35503612

@@ -3565,7 +3627,7 @@ fn sidebar_struct(fmt: &mut fmt::Formatter, it: &clean::Item,
35653627
sidebar.push_str(&sidebar_assoc_items(it));
35663628

35673629
if !sidebar.is_empty() {
3568-
write!(fmt, "<div class=\"block items\"><ul>{}</ul></div>", sidebar)?;
3630+
write!(fmt, "<div class=\"block items\">{}</div>", sidebar)?;
35693631
}
35703632
Ok(())
35713633
}
@@ -3592,8 +3654,6 @@ fn sidebar_trait(fmt: &mut fmt::Formatter, it: &clean::Item,
35923654
sidebar.push_str("<li><a href=\"#provided-methods\">Provided Methods</a></li>");
35933655
}
35943656

3595-
sidebar.push_str(&sidebar_assoc_items(it));
3596-
35973657
let c = cache();
35983658

35993659
if let Some(implementors) = c.implementors.get(&it.def_id) {
@@ -3607,15 +3667,17 @@ fn sidebar_trait(fmt: &mut fmt::Formatter, it: &clean::Item,
36073667

36083668
sidebar.push_str("<li><a href=\"#implementors\">Implementors</a></li>");
36093669

3610-
write!(fmt, "<div class=\"block items\"><ul>{}</ul></div>", sidebar)
3670+
sidebar.push_str(&sidebar_assoc_items(it));
3671+
3672+
write!(fmt, "<div class=\"block items\">{}</div>", sidebar)
36113673
}
36123674

36133675
fn sidebar_primitive(fmt: &mut fmt::Formatter, it: &clean::Item,
36143676
_p: &clean::PrimitiveType) -> fmt::Result {
36153677
let sidebar = sidebar_assoc_items(it);
36163678

36173679
if !sidebar.is_empty() {
3618-
write!(fmt, "<div class=\"block items\"><ul>{}</ul></div>", sidebar)?;
3680+
write!(fmt, "<div class=\"block items\">{}</div>", sidebar)?;
36193681
}
36203682
Ok(())
36213683
}
@@ -3625,7 +3687,7 @@ fn sidebar_typedef(fmt: &mut fmt::Formatter, it: &clean::Item,
36253687
let sidebar = sidebar_assoc_items(it);
36263688

36273689
if !sidebar.is_empty() {
3628-
write!(fmt, "<div class=\"block items\"><ul>{}</ul></div>", sidebar)?;
3690+
write!(fmt, "<div class=\"block items\">{}</div>", sidebar)?;
36293691
}
36303692
Ok(())
36313693
}
@@ -3642,7 +3704,7 @@ fn sidebar_union(fmt: &mut fmt::Formatter, it: &clean::Item,
36423704
sidebar.push_str(&sidebar_assoc_items(it));
36433705

36443706
if !sidebar.is_empty() {
3645-
write!(fmt, "<div class=\"block items\"><ul>{}</ul></div>", sidebar)?;
3707+
write!(fmt, "<div class=\"block items\">{}</div>", sidebar)?;
36463708
}
36473709
Ok(())
36483710
}
@@ -3658,7 +3720,7 @@ fn sidebar_enum(fmt: &mut fmt::Formatter, it: &clean::Item,
36583720
sidebar.push_str(&sidebar_assoc_items(it));
36593721

36603722
if !sidebar.is_empty() {
3661-
write!(fmt, "<div class=\"block items\"><ul>{}</ul></div>", sidebar)?;
3723+
write!(fmt, "<div class=\"block items\">{}</div>", sidebar)?;
36623724
}
36633725
Ok(())
36643726
}

src/librustdoc/html/static/rustdoc.css

+21-6
Original file line numberDiff line numberDiff line change
@@ -188,18 +188,16 @@ nav.sub {
188188

189189
.js-only, .hidden { display: none !important; }
190190

191-
.sidebar {
192-
padding: 10px;
193-
}
194191
.sidebar img {
195192
margin: 20px auto;
196193
display: block;
194+
margin-top: 10px;
197195
}
198196

199197
.sidebar .location {
200198
border: 1px solid;
201199
font-size: 17px;
202-
margin: 30px 0 20px 0;
200+
margin: 30px 10px 20px 10px;
203201
text-align: center;
204202
word-wrap: break-word;
205203
}
@@ -220,7 +218,7 @@ nav.sub {
220218
.location a:first-child { font-weight: 500; }
221219

222220
.block {
223-
padding: 0 10px;
221+
padding: 0;
224222
margin-bottom: 14px;
225223
}
226224
.block h2, .block h3 {
@@ -229,7 +227,7 @@ nav.sub {
229227
text-align: center;
230228
}
231229
.block ul, .block li {
232-
margin: 0;
230+
margin: 0 10px;
233231
padding: 0;
234232
list-style: none;
235233
}
@@ -245,6 +243,23 @@ nav.sub {
245243
transition: border 500ms ease-out;
246244
}
247245

246+
.sidebar-title {
247+
border-top: 1px solid #777;
248+
border-bottom: 1px solid #777;
249+
text-align: center;
250+
font-size: 17px;
251+
margin-bottom: 5px;
252+
}
253+
254+
.sidebar-links {
255+
margin-bottom: 15px;
256+
}
257+
258+
.sidebar-links > a {
259+
padding-left: 10px;
260+
width: 100%;
261+
}
262+
248263
.content {
249264
padding: 15px 0;
250265
}

src/tools/linkchecker/main.rs

+17
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,32 @@ struct FileEntry {
6969

7070
type Cache = HashMap<PathBuf, FileEntry>;
7171

72+
fn small_url_encode(s: &str) -> String {
73+
s.replace("<", "%3C")
74+
.replace(">", "%3E")
75+
.replace(" ", "%20")
76+
.replace("?", "%3F")
77+
.replace("'", "%27")
78+
.replace("&", "%26")
79+
.replace(",", "%2C")
80+
.replace(":", "%3A")
81+
.replace(";", "%3B")
82+
.replace("[", "%5B")
83+
.replace("]", "%5D")
84+
}
85+
7286
impl FileEntry {
7387
fn parse_ids(&mut self, file: &Path, contents: &str, errors: &mut bool) {
7488
if self.ids.is_empty() {
7589
with_attrs_in_source(contents, " id", |fragment, i, _| {
7690
let frag = fragment.trim_left_matches("#").to_owned();
91+
let encoded = small_url_encode(&frag);
7792
if !self.ids.insert(frag) {
7893
*errors = true;
7994
println!("{}:{}: id is not unique: `{}`", file.display(), i, fragment);
8095
}
96+
// Just in case, we also add the encoded id.
97+
self.ids.insert(encoded);
8198
});
8299
}
83100
}

0 commit comments

Comments
 (0)