From 75acee2bdee0278e0dc9610bfd05eb4367e41c20 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Tue, 9 Feb 2016 21:15:29 -0500 Subject: [PATCH] Rustdoc - display `since` version for stable items Fixes #27607 --- src/librustdoc/clean/mod.rs | 8 +++ src/librustdoc/html/render.rs | 98 +++++++++++++++++++------- src/librustdoc/html/static/rustdoc.css | 15 ++++ 3 files changed, 94 insertions(+), 27 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 03e2a7139b2..5e8b1194da0 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -339,6 +339,14 @@ pub fn stability_class(&self) -> String { _ => String::new(), } } + + pub fn stable_since(&self) -> Option<&str> { + if let Some(ref s) = self.stability { + return Some(&s.since[..]); + } + + None + } } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index dfbe08a0e42..12a17afcc7c 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1913,6 +1913,7 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, generics = f.generics, where_clause = WhereClause(&f.generics), decl = f.decl)); + try!(render_stability_since_raw(w, it.stable_since(), None)); document(w, cx, it) } @@ -1992,7 +1993,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, // Trait documentation try!(document(w, cx, it)); - fn trait_item(w: &mut fmt::Formatter, cx: &Context, m: &clean::Item) + fn trait_item(w: &mut fmt::Formatter, cx: &Context, m: &clean::Item, t: &clean::Item) -> fmt::Result { let name = m.name.as_ref().unwrap(); let id = derive_id(format!("{}.{}", shortty(m), name)); @@ -2000,7 +2001,9 @@ fn trait_item(w: &mut fmt::Formatter, cx: &Context, m: &clean::Item) id = id, stab = m.stability_class())); try!(render_assoc_item(w, m, AssocItemLink::Anchor)); - try!(write!(w, "")); + try!(write!(w, "")); + try!(render_stability_since(w, m, t)); + try!(write!(w, "")); try!(document(w, cx, m)); Ok(()) } @@ -2011,7 +2014,7 @@ fn trait_item(w: &mut fmt::Formatter, cx: &Context, m: &clean::Item)
")); for t in &types { - try!(trait_item(w, cx, *t)); + try!(trait_item(w, cx, *t, it)); } try!(write!(w, "
")); } @@ -2022,7 +2025,7 @@ fn trait_item(w: &mut fmt::Formatter, cx: &Context, m: &clean::Item)
")); for t in &consts { - try!(trait_item(w, cx, *t)); + try!(trait_item(w, cx, *t, it)); } try!(write!(w, "
")); } @@ -2034,7 +2037,7 @@ fn trait_item(w: &mut fmt::Formatter, cx: &Context, m: &clean::Item)
")); for m in &required { - try!(trait_item(w, cx, *m)); + try!(trait_item(w, cx, *m, it)); } try!(write!(w, "
")); } @@ -2044,13 +2047,13 @@ fn trait_item(w: &mut fmt::Formatter, cx: &Context, m: &clean::Item)
")); for m in &provided { - try!(trait_item(w, cx, *m)); + try!(trait_item(w, cx, *m, it)); } try!(write!(w, "
")); } // If there are methods directly on this trait object, render them here. - try!(render_assoc_items(w, cx, it.def_id, AssocItemRender::All)); + try!(render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)); let cache = cache(); try!(write!(w, " @@ -2106,6 +2109,29 @@ fn assoc_type(w: &mut fmt::Formatter, it: &clean::Item, Ok(()) } +fn render_stability_since_raw<'a>(w: &mut fmt::Formatter, + ver: Option<&'a str>, + containing_ver: Option<&'a str>) -> fmt::Result { + if containing_ver != ver { + match ver { + Some(v) => + if v.len() > 0 { + try!(write!(w, "{}", + v)) + }, + None => {} + } + } + + Ok(()) +} + +fn render_stability_since(w: &mut fmt::Formatter, + item: &clean::Item, + containing_item: &clean::Item) -> fmt::Result { + render_stability_since_raw(w, item.stable_since(), containing_item.stable_since()) +} + fn render_assoc_item(w: &mut fmt::Formatter, meth: &clean::Item, link: AssocItemLink) -> fmt::Result { fn method(w: &mut fmt::Formatter, @@ -2178,6 +2204,7 @@ fn item_struct(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, "", true)); try!(write!(w, "")); + try!(render_stability_since_raw(w, it.stable_since(), None)); try!(document(w, cx, it)); let mut fields = s.fields.iter().filter(|f| { @@ -2202,7 +2229,7 @@ fn item_struct(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, try!(write!(w, "")); } } - render_assoc_items(w, cx, it.def_id, AssocItemRender::All) + render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All) } fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, @@ -2257,10 +2284,11 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, try!(write!(w, "}}")); } try!(write!(w, "")); + try!(render_stability_since_raw(w, it.stable_since(), None)); try!(document(w, cx, it)); if !e.variants.is_empty() { - try!(write!(w, "

Variants

\n")); + try!(write!(w, "

Variants

\n
")); for variant in &e.variants { try!(write!(w, "")); } try!(write!(w, "
{name}", name = variant.name.as_ref().unwrap())); @@ -2296,12 +2324,14 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, } _ => () } + try!(write!(w, "")); + try!(render_stability_since(w, variant, it)); try!(write!(w, "
")); } - try!(render_assoc_items(w, cx, it.def_id, AssocItemRender::All)); + try!(render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)); Ok(()) } @@ -2397,6 +2427,7 @@ enum AssocItemRender<'a> { fn render_assoc_items(w: &mut fmt::Formatter, cx: &Context, + containing_item: &clean::Item, it: DefId, what: AssocItemRender) -> fmt::Result { let c = cache(); @@ -2420,7 +2451,8 @@ fn render_assoc_items(w: &mut fmt::Formatter, } }; for i in &non_trait { - try!(render_impl(w, cx, i, AssocItemLink::Anchor, render_header)); + try!(render_impl(w, cx, i, AssocItemLink::Anchor, render_header, + containing_item.stable_since())); } } if let AssocItemRender::DerefFor { .. } = what { @@ -2436,7 +2468,7 @@ fn render_assoc_items(w: &mut fmt::Formatter, } }); if let Some(impl_) = deref_impl { - try!(render_deref_methods(w, cx, impl_)); + try!(render_deref_methods(w, cx, impl_, containing_item)); } try!(write!(w, "

Trait \ Implementations

")); @@ -2445,7 +2477,8 @@ fn render_assoc_items(w: &mut fmt::Formatter, }); for i in &manual { let did = i.trait_did().unwrap(); - try!(render_impl(w, cx, i, AssocItemLink::GotoSource(did), true)); + try!(render_impl(w, cx, i, AssocItemLink::GotoSource(did), true, + containing_item.stable_since())); } if !derived.is_empty() { try!(write!(w, "

\ @@ -2453,14 +2486,16 @@ fn render_assoc_items(w: &mut fmt::Formatter,

")); for i in &derived { let did = i.trait_did().unwrap(); - try!(render_impl(w, cx, i, AssocItemLink::GotoSource(did), true)); + try!(render_impl(w, cx, i, AssocItemLink::GotoSource(did), true, + containing_item.stable_since())); } } } Ok(()) } -fn render_deref_methods(w: &mut fmt::Formatter, cx: &Context, impl_: &Impl) -> fmt::Result { +fn render_deref_methods(w: &mut fmt::Formatter, cx: &Context, impl_: &Impl, + container_item: &clean::Item) -> fmt::Result { let deref_type = impl_.impl_.trait_.as_ref().unwrap(); let target = impl_.impl_.items.iter().filter_map(|item| { match item.inner { @@ -2470,12 +2505,12 @@ fn render_deref_methods(w: &mut fmt::Formatter, cx: &Context, impl_: &Impl) -> f }).next().expect("Expected associated type binding"); let what = AssocItemRender::DerefFor { trait_: deref_type, type_: target }; match *target { - clean::ResolvedPath { did, .. } => render_assoc_items(w, cx, did, what), + clean::ResolvedPath { did, .. } => render_assoc_items(w, cx, container_item, did, what), _ => { if let Some(prim) = target.primitive_type() { if let Some(c) = cache().primitive_locations.get(&prim) { let did = DefId { krate: *c, index: prim.to_def_index() }; - try!(render_assoc_items(w, cx, did, what)); + try!(render_assoc_items(w, cx, container_item, did, what)); } } Ok(()) @@ -2487,24 +2522,30 @@ fn render_deref_methods(w: &mut fmt::Formatter, cx: &Context, impl_: &Impl) -> f // otherwise. If render_header is false, we will avoid rendering static // methods, since they are not accessible for the type implementing `Deref` fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLink, - render_header: bool) -> fmt::Result { + render_header: bool, outer_version: Option<&str>) -> fmt::Result { if render_header { - try!(write!(w, "

{}

", i.impl_)); + try!(write!(w, "

{}", i.impl_)); + let since = i.stability.as_ref().map(|s| &s.since[..]); + try!(render_stability_since_raw(w, since, outer_version)); + try!(write!(w, "

")); if let Some(ref dox) = i.dox { try!(write!(w, "
{}
", Markdown(dox))); } } fn doctraititem(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item, - link: AssocItemLink, render_static: bool) -> fmt::Result { + link: AssocItemLink, render_static: bool, + outer_version: Option<&str>) -> fmt::Result { let name = item.name.as_ref().unwrap(); match item.inner { clean::MethodItem(..) | clean::TyMethodItem(..) => { // Only render when the method is not static or we allow static methods if !is_static_method(item) || render_static { let id = derive_id(format!("method.{}", name)); - try!(write!(w, "

", id, shortty(item))); - try!(render_assoc_item(w, item, link)); + try!(write!(w, "

", id, shortty(item))); + try!(render_stability_since_raw(w, item.stable_since(), outer_version)); + try!(write!(w, "")); + try!(render_assoc_item(w, item, link)); try!(write!(w, "

\n")); } } @@ -2556,7 +2597,7 @@ fn is_static_method(item: &clean::Item) -> bool { try!(write!(w, "
")); for trait_item in &i.impl_.items { - try!(doctraititem(w, cx, trait_item, link, render_header)); + try!(doctraititem(w, cx, trait_item, link, render_header, outer_version)); } fn render_default_items(w: &mut fmt::Formatter, @@ -2564,7 +2605,8 @@ fn render_default_items(w: &mut fmt::Formatter, did: DefId, t: &clean::Trait, i: &clean::Impl, - render_static: bool) -> fmt::Result { + render_static: bool, + outer_version: Option<&str>) -> fmt::Result { for trait_item in &t.items { let n = trait_item.name.clone(); match i.items.iter().find(|m| { m.name == n }) { @@ -2572,7 +2614,8 @@ fn render_default_items(w: &mut fmt::Formatter, None => {} } - try!(doctraititem(w, cx, trait_item, AssocItemLink::GotoSource(did), render_static)); + try!(doctraititem(w, cx, trait_item, AssocItemLink::GotoSource(did), render_static, + outer_version)); } Ok(()) } @@ -2583,7 +2626,7 @@ fn render_default_items(w: &mut fmt::Formatter, // for them work. if let Some(clean::ResolvedPath { did, .. }) = i.impl_.trait_ { if let Some(t) = cache().traits.get(&did) { - try!(render_default_items(w, cx, did, t, &i.impl_, render_header)); + try!(render_default_items(w, cx, did, t, &i.impl_, render_header, outer_version)); } } @@ -2675,6 +2718,7 @@ fn item_macro(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, try!(w.write_str(&highlight::highlight(&t.source, Some("macro"), None))); + try!(render_stability_since_raw(w, it.stable_since(), None)); document(w, cx, it) } @@ -2682,7 +2726,7 @@ fn item_primitive(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, _p: &clean::PrimitiveType) -> fmt::Result { try!(document(w, cx, it)); - render_assoc_items(w, cx, it.def_id, AssocItemRender::All) + render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All) } fn get_basic_keywords() -> &'static str { diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index c751cdeb6f7..1cadc4e476a 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -498,6 +498,21 @@ em.stab p { opacity: 0.65; } +span.since { + float: right; + font-weight: normal; + font-size: initial; + color: grey; +} + +.variants_table { + width: 100%; +} + +.variants_table tbody tr td:first-child { + width: 1%; /* make the variant name as small as possible */ +} + td.summary-column { width: 100%; } -- 2.44.0