Skip to content

Commit 4d16de0

Browse files
committed
rustdoc: Add stability dashboard
This commit adds a crate-level dashboard summarizing the stability levels of all items for all submodules of the crate. The information is also written as a json file, intended for consumption by pages like http://huonw.github.io/isrustfastyet/ Closes #13541
1 parent b57d272 commit 4d16de0

File tree

5 files changed

+306
-6
lines changed

5 files changed

+306
-6
lines changed

src/librustdoc/html/format.rs

+70
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use syntax::ast;
2222
use syntax::ast_util;
2323

2424
use clean;
25+
use stability_summary::ModuleSummary;
2526
use html::item_type;
2627
use html::item_type::ItemType;
2728
use html::render;
@@ -631,3 +632,72 @@ impl<'a> fmt::Show for ConciseStability<'a> {
631632
}
632633
}
633634
}
635+
636+
impl fmt::Show for ModuleSummary {
637+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
638+
fn fmt_inner<'a>(f: &mut fmt::Formatter,
639+
context: &mut Vec<&'a str>,
640+
m: &'a ModuleSummary)
641+
-> fmt::Result {
642+
let cnt = m.counts;
643+
let tot = cnt.total();
644+
if tot == 0 { return Ok(()) }
645+
646+
context.push(m.name.as_slice());
647+
let path = context.connect("::");
648+
649+
// the total width of each row's stability summary, in pixels
650+
let width = 500;
651+
652+
try!(write!(f, "<tr>"));
653+
try!(write!(f, "<td class='summary'>\
654+
<a class='summary' href='{}'>{}</a></td>",
655+
Vec::from_slice(context.slice_from(1))
656+
.append_one("index.html").connect("/"),
657+
path));
658+
try!(write!(f, "<td>"));
659+
try!(write!(f, "<span class='summary Stable' \
660+
style='width: {}px; display: inline-block'>&nbsp</span>",
661+
(width * cnt.stable)/tot));
662+
try!(write!(f, "<span class='summary Unstable' \
663+
style='width: {}px; display: inline-block'>&nbsp</span>",
664+
(width * cnt.unstable)/tot));
665+
try!(write!(f, "<span class='summary Experimental' \
666+
style='width: {}px; display: inline-block'>&nbsp</span>",
667+
(width * cnt.experimental)/tot));
668+
try!(write!(f, "<span class='summary Deprecated' \
669+
style='width: {}px; display: inline-block'>&nbsp</span>",
670+
(width * cnt.deprecated)/tot));
671+
try!(write!(f, "<span class='summary Unmarked' \
672+
style='width: {}px; display: inline-block'>&nbsp</span>",
673+
(width * cnt.unmarked)/tot));
674+
try!(write!(f, "</td></tr>"));
675+
676+
for submodule in m.submodules.iter() {
677+
try!(fmt_inner(f, context, submodule));
678+
}
679+
context.pop();
680+
Ok(())
681+
}
682+
683+
let mut context = Vec::new();
684+
685+
try!(write!(f,
686+
r"<h1 class='fqn'>Stability dashboard: crate <a class='mod' href='index.html'>{}</a></h1>
687+
This dashboard summarizes the stability levels for all of the public modules of
688+
the crate, according to the total number of items at each level in the module and its children:
689+
<blockquote>
690+
<a class='stability Stable'></a> stable,<br/>
691+
<a class='stability Unstable'></a> unstable,<br/>
692+
<a class='stability Experimental'></a> experimental,<br/>
693+
<a class='stability Deprecated'></a> deprecated,<br/>
694+
<a class='stability Unmarked'></a> unmarked
695+
</blockquote>
696+
The counts do not include methods or trait
697+
implementations that are visible only through a re-exported type.",
698+
self.name));
699+
try!(write!(f, "<table>"))
700+
try!(fmt_inner(f, &mut context, self));
701+
write!(f, "</table>")
702+
}
703+
}

src/librustdoc/html/render.rs

+51-5
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ use std::sync::Arc;
4343

4444
use externalfiles::ExternalHtml;
4545

46+
use serialize::json;
47+
use serialize::Encodable;
4648
use serialize::json::ToJson;
4749
use syntax::ast;
4850
use syntax::ast_util;
@@ -59,6 +61,7 @@ use html::item_type;
5961
use html::layout;
6062
use html::markdown::Markdown;
6163
use html::markdown;
64+
use stability_summary;
6265

6366
/// Major driving force in all rustdoc rendering. This contains information
6467
/// about where in the tree-like hierarchy rendering is occurring and controls
@@ -249,6 +252,11 @@ pub fn run(mut krate: clean::Crate, external_html: &ExternalHtml, dst: Path) ->
249252

250253
try!(mkdir(&cx.dst));
251254

255+
// Crawl the crate, building a summary of the stability levels. NOTE: this
256+
// summary *must* be computed with the original `krate`; the folding below
257+
// removes the impls from their modules.
258+
let summary = stability_summary::build(&krate);
259+
252260
// Crawl the crate attributes looking for attributes which control how we're
253261
// going to emit HTML
254262
match krate.module.as_ref().map(|m| m.doc_list().unwrap_or(&[])) {
@@ -361,7 +369,7 @@ pub fn run(mut krate: clean::Crate, external_html: &ExternalHtml, dst: Path) ->
361369
let krate = try!(render_sources(&mut cx, krate));
362370

363371
// And finally render the whole crate's documentation
364-
cx.krate(krate)
372+
cx.krate(krate, summary)
365373
}
366374

367375
fn build_index(krate: &clean::Crate, cache: &mut Cache) -> io::IoResult<String> {
@@ -1045,13 +1053,34 @@ impl Context {
10451053
///
10461054
/// This currently isn't parallelized, but it'd be pretty easy to add
10471055
/// parallelization to this function.
1048-
fn krate(self, mut krate: clean::Crate) -> io::IoResult<()> {
1056+
fn krate(mut self, mut krate: clean::Crate,
1057+
stability: stability_summary::ModuleSummary) -> io::IoResult<()> {
10491058
let mut item = match krate.module.take() {
10501059
Some(i) => i,
10511060
None => return Ok(())
10521061
};
10531062
item.name = Some(krate.name);
10541063

1064+
// render stability dashboard
1065+
try!(self.recurse(stability.name.clone(), |this| {
1066+
let json_dst = &this.dst.join("stability.json");
1067+
let mut json_out = BufferedWriter::new(try!(File::create(json_dst)));
1068+
try!(stability.encode(&mut json::Encoder::new(&mut json_out)));
1069+
1070+
let title = stability.name.clone().append(" - Stability dashboard");
1071+
let page = layout::Page {
1072+
ty: "mod",
1073+
root_path: this.root_path.as_slice(),
1074+
title: title.as_slice(),
1075+
};
1076+
let html_dst = &this.dst.join("stability.html");
1077+
let mut html_out = BufferedWriter::new(try!(File::create(html_dst)));
1078+
layout::render(&mut html_out, &this.layout, &page,
1079+
&Sidebar{ cx: this, item: &item },
1080+
&stability)
1081+
}));
1082+
1083+
// render the crate documentation
10551084
let mut work = vec!((self, item));
10561085
loop {
10571086
match work.pop() {
@@ -1061,6 +1090,7 @@ impl Context {
10611090
None => break,
10621091
}
10631092
}
1093+
10641094
Ok(())
10651095
}
10661096

@@ -1233,6 +1263,8 @@ impl<'a> Item<'a> {
12331263
}
12341264
}
12351265

1266+
1267+
12361268
impl<'a> fmt::Show for Item<'a> {
12371269
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
12381270
// Write the breadcrumb trail header for the top
@@ -1269,6 +1301,17 @@ impl<'a> fmt::Show for Item<'a> {
12691301
// Write stability level
12701302
try!(write!(fmt, "{}", Stability(&self.item.stability)));
12711303

1304+
// Links to out-of-band information, i.e. src and stability dashboard
1305+
try!(write!(fmt, "<span class='out-of-band'>"));
1306+
1307+
// Write stability dashboard link
1308+
match self.item.inner {
1309+
clean::ModuleItem(ref m) if m.is_crate => {
1310+
try!(write!(fmt, "<a href='stability.html'>[stability dashboard]</a> "));
1311+
}
1312+
_ => {}
1313+
};
1314+
12721315
// Write `src` tag
12731316
//
12741317
// When this item is part of a `pub use` in a downstream crate, the
@@ -1278,14 +1321,15 @@ impl<'a> fmt::Show for Item<'a> {
12781321
if self.cx.include_sources && !is_primitive {
12791322
match self.href() {
12801323
Some(l) => {
1281-
try!(write!(fmt,
1282-
"<a class='source' id='src-{}' \
1283-
href='{}'>[src]</a>",
1324+
try!(write!(fmt, "<a id='src-{}' href='{}'>[src]</a>",
12841325
self.item.def_id.node, l));
12851326
}
12861327
None => {}
12871328
}
12881329
}
1330+
1331+
try!(write!(fmt, "</span>"));
1332+
12891333
try!(write!(fmt, "</h1>\n"));
12901334

12911335
match self.item.inner {
@@ -1355,6 +1399,7 @@ fn document(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result {
13551399
fn item_module(w: &mut fmt::Formatter, cx: &Context,
13561400
item: &clean::Item, items: &[clean::Item]) -> fmt::Result {
13571401
try!(document(w, item));
1402+
13581403
let mut indices = range(0, items.len()).filter(|i| {
13591404
!ignore_private_item(&items[*i])
13601405
}).collect::<Vec<uint>>();
@@ -1514,6 +1559,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
15141559
}
15151560
}
15161561
}
1562+
15171563
write!(w, "</table>")
15181564
}
15191565

src/librustdoc/html/static/main.css

+10-1
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ nav.sub {
238238
.docblock h2 { font-size: 1.15em; }
239239
.docblock h3, .docblock h4, .docblock h5 { font-size: 1em; }
240240

241-
.content .source {
241+
.content .out-of-band {
242242
float: right;
243243
font-size: 23px;
244244
}
@@ -409,6 +409,15 @@ h1 .stability {
409409
.stability.Locked { border-color: #0084B6; color: #00668c; }
410410
.stability.Unmarked { border-color: #FFFFFF; }
411411

412+
.summary {
413+
padding-right: 0px;
414+
}
415+
.summary.Deprecated { background-color: #A071A8; }
416+
.summary.Experimental { background-color: #D46D6A; }
417+
.summary.Unstable { background-color: #D4B16A; }
418+
.summary.Stable { background-color: #54A759; }
419+
.summary.Unmarked { background-color: #FFFFFF; }
420+
412421
:target { background: #FDFFD3; }
413422

414423
/* Code highlighting */

src/librustdoc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ pub mod html {
5656
pub mod markdown;
5757
pub mod passes;
5858
pub mod plugins;
59+
pub mod stability_summary;
5960
pub mod visit_ast;
6061
pub mod test;
6162
mod flock;

0 commit comments

Comments
 (0)