Skip to content

Commit 760e389

Browse files
Add page to list all crate's items
1 parent 8dd24c8 commit 760e389

File tree

4 files changed

+238
-36
lines changed

4 files changed

+238
-36
lines changed

src/librustdoc/html/render.rs

+206-36
Original file line numberDiff line numberDiff line change
@@ -1087,7 +1087,8 @@ impl<'a> SourceCollector<'a> {
10871087
href.push_str(component);
10881088
href.push('/');
10891089
});
1090-
let mut fname = p.file_name().expect("source has no filename")
1090+
let mut fname = p.file_name()
1091+
.expect("source has no filename")
10911092
.to_os_string();
10921093
fname.push(".html");
10931094
cur.push(&fname);
@@ -1373,6 +1374,135 @@ impl<'a> Cache {
13731374
}
13741375
}
13751376

1377+
#[derive(Debug, Eq, PartialEq, Hash)]
1378+
struct ItemEntry {
1379+
url: String,
1380+
name: String,
1381+
}
1382+
1383+
impl ItemEntry {
1384+
fn new(mut url: String, name: String) -> ItemEntry {
1385+
while url.starts_with('/') {
1386+
url.remove(0);
1387+
}
1388+
ItemEntry {
1389+
url,
1390+
name,
1391+
}
1392+
}
1393+
}
1394+
1395+
impl fmt::Display for ItemEntry {
1396+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1397+
write!(f, "<a href='{}'>{}</a>", self.url, Escape(&self.name))
1398+
}
1399+
}
1400+
1401+
impl PartialOrd for ItemEntry {
1402+
fn partial_cmp(&self, other: &ItemEntry) -> Option<::std::cmp::Ordering> {
1403+
Some(self.cmp(other))
1404+
}
1405+
}
1406+
1407+
impl Ord for ItemEntry {
1408+
fn cmp(&self, other: &ItemEntry) -> ::std::cmp::Ordering {
1409+
self.name.cmp(&other.name)
1410+
}
1411+
}
1412+
1413+
#[derive(Debug)]
1414+
struct AllTypes {
1415+
structs: HashSet<ItemEntry>,
1416+
enums: HashSet<ItemEntry>,
1417+
unions: HashSet<ItemEntry>,
1418+
primitives: HashSet<ItemEntry>,
1419+
traits: HashSet<ItemEntry>,
1420+
macros: HashSet<ItemEntry>,
1421+
functions: HashSet<ItemEntry>,
1422+
typedefs: HashSet<ItemEntry>,
1423+
statics: HashSet<ItemEntry>,
1424+
constants: HashSet<ItemEntry>,
1425+
}
1426+
1427+
impl AllTypes {
1428+
fn new() -> AllTypes {
1429+
AllTypes {
1430+
structs: HashSet::with_capacity(100),
1431+
enums: HashSet::with_capacity(100),
1432+
unions: HashSet::with_capacity(100),
1433+
primitives: HashSet::with_capacity(26),
1434+
traits: HashSet::with_capacity(100),
1435+
macros: HashSet::with_capacity(100),
1436+
functions: HashSet::with_capacity(100),
1437+
typedefs: HashSet::with_capacity(100),
1438+
statics: HashSet::with_capacity(100),
1439+
constants: HashSet::with_capacity(100),
1440+
}
1441+
}
1442+
1443+
fn append(&mut self, item_name: String, item_type: &str) {
1444+
let mut url: Vec<_> = item_name.split("::").skip(1).collect();
1445+
if let Some(name) = url.pop() {
1446+
let new_url = format!("{}/{}.{}.html", url.join("/"), item_type, name);
1447+
url.push(name);
1448+
let name = url.join("::");
1449+
match item_type {
1450+
"struct" => self.structs.insert(ItemEntry::new(new_url, name)),
1451+
"enum" => self.enums.insert(ItemEntry::new(new_url, name)),
1452+
"union" => self.unions.insert(ItemEntry::new(new_url, name)),
1453+
"primitive" => self.primitives.insert(ItemEntry::new(new_url, name)),
1454+
"trait" => self.traits.insert(ItemEntry::new(new_url, name)),
1455+
"macro" => self.macros.insert(ItemEntry::new(new_url, name)),
1456+
"fn" => self.functions.insert(ItemEntry::new(new_url, name)),
1457+
"typedef" => self.typedefs.insert(ItemEntry::new(new_url, name)),
1458+
"static" => self.statics.insert(ItemEntry::new(new_url, name)),
1459+
"constant" => self.constants.insert(ItemEntry::new(new_url, name)),
1460+
_ => true,
1461+
};
1462+
}
1463+
}
1464+
}
1465+
1466+
fn print_entries(f: &mut fmt::Formatter, e: &HashSet<ItemEntry>, title: &str,
1467+
class: &str) -> fmt::Result {
1468+
if !e.is_empty() {
1469+
let mut e: Vec<&ItemEntry> = e.iter().collect();
1470+
e.sort();
1471+
write!(f, "<h3 id='{}'>{}</h3><ul class='{} docblock'>{}</ul>",
1472+
title,
1473+
Escape(title),
1474+
class,
1475+
e.iter().map(|s| format!("<li>{}</li>", s)).collect::<String>())?;
1476+
}
1477+
Ok(())
1478+
}
1479+
1480+
impl fmt::Display for AllTypes {
1481+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1482+
write!(f,
1483+
"<h1 class='fqn'>\
1484+
<span class='in-band'>List of all items</span>\
1485+
<span class='out-of-band'>\
1486+
<span id='render-detail'>\
1487+
<a id=\"toggle-all-docs\" href=\"javascript:void(0)\" title=\"collapse all docs\">\
1488+
[<span class='inner'>&#x2212;</span>]\
1489+
</a>\
1490+
</span>
1491+
</span>
1492+
</h1>")?;
1493+
print_entries(f, &self.structs, "Structs", "structs")?;
1494+
print_entries(f, &self.enums, "Enums", "enums")?;
1495+
print_entries(f, &self.unions, "Unions", "unions")?;
1496+
print_entries(f, &self.primitives, "Primitives", "primitives")?;
1497+
print_entries(f, &self.traits, "Traits", "traits")?;
1498+
print_entries(f, &self.macros, "Macros", "macros")?;
1499+
print_entries(f, &self.functions, "Functions", "functions")?;
1500+
print_entries(f, &self.typedefs, "Typedefs", "typedefs")?;
1501+
print_entries(f, &self.statics, "Statics", "statics")?;
1502+
print_entries(f, &self.constants, "Constants", "constants")
1503+
}
1504+
}
1505+
13761506
impl Context {
13771507
/// String representation of how to get back to the root path of the 'doc/'
13781508
/// folder in terms of a relative URL.
@@ -1414,16 +1544,52 @@ impl Context {
14141544
Some(i) => i,
14151545
None => return Ok(()),
14161546
};
1547+
let final_file = self.dst.join(&krate.name)
1548+
.join("all.html");
1549+
let crate_name = krate.name.clone();
14171550
item.name = Some(krate.name);
14181551

1419-
// Render the crate documentation
1420-
let mut work = vec![(self, item)];
1552+
let mut all = AllTypes::new();
14211553

1422-
while let Some((mut cx, item)) = work.pop() {
1423-
cx.item(item, |cx, item| {
1424-
work.push((cx.clone(), item))
1425-
})?
1554+
{
1555+
// Render the crate documentation
1556+
let mut work = vec![(self.clone(), item)];
1557+
1558+
while let Some((mut cx, item)) = work.pop() {
1559+
cx.item(item, &mut all, |cx, item| {
1560+
work.push((cx.clone(), item))
1561+
})?
1562+
}
14261563
}
1564+
1565+
let mut w = BufWriter::new(File::create(&final_file)
1566+
.expect("failed to create all.html"));
1567+
let mut root_path = self.dst.to_str().expect("invalid path").to_owned();
1568+
if !root_path.ends_with('/') {
1569+
root_path.push('/');
1570+
}
1571+
let page = layout::Page {
1572+
title: "List of all items in this crate",
1573+
css_class: "mod",
1574+
root_path: "../",
1575+
description: "List of all items in this crate",
1576+
keywords: BASIC_KEYWORDS,
1577+
resource_suffix: &self.shared.resource_suffix,
1578+
};
1579+
let sidebar = if let Some(ref version) = cache().crate_version {
1580+
format!("<p class='location'>Crate {}</p>\
1581+
<div class='block version'>\
1582+
<p>Version {}</p>\
1583+
</div>\
1584+
<a id='all-types' href='index.html'><p>Back to index</p></a>",
1585+
crate_name, version)
1586+
} else {
1587+
String::new()
1588+
};
1589+
layout::render(&mut w, &self.shared.layout,
1590+
&page, &sidebar, &all,
1591+
self.shared.css_file_extension.is_some(),
1592+
&self.shared.themes).expect("layout rendering failed");
14271593
Ok(())
14281594
}
14291595

@@ -1496,8 +1662,8 @@ impl Context {
14961662
/// all sub-items which need to be rendered.
14971663
///
14981664
/// The rendering driver uses this closure to queue up more work.
1499-
fn item<F>(&mut self, item: clean::Item, mut f: F) -> Result<(), Error> where
1500-
F: FnMut(&mut Context, clean::Item),
1665+
fn item<F>(&mut self, item: clean::Item, all: &mut AllTypes, mut f: F) -> Result<(), Error>
1666+
where F: FnMut(&mut Context, clean::Item),
15011667
{
15021668
// Stripped modules survive the rustdoc passes (i.e. `strip-private`)
15031669
// if they contain impls for public types. These modules can also
@@ -1544,7 +1710,7 @@ impl Context {
15441710
}
15451711

15461712
for item in m.items {
1547-
f(this,item);
1713+
f(this, item);
15481714
}
15491715

15501716
Ok(())
@@ -1562,13 +1728,14 @@ impl Context {
15621728
let mut dst = try_err!(File::create(&joint_dst), &joint_dst);
15631729
try_err!(dst.write_all(&buf), &joint_dst);
15641730

1731+
all.append(full_path(self, &item), item_type.css_class());
15651732
// Redirect from a sane URL using the namespace to Rustdoc's
15661733
// URL for the page.
15671734
let redir_name = format!("{}.{}.html", name, item_type.name_space());
15681735
let redir_dst = self.dst.join(redir_name);
15691736
if let Ok(redirect_out) = OpenOptions::new().create_new(true)
1570-
.write(true)
1571-
.open(&redir_dst) {
1737+
.write(true)
1738+
.open(&redir_dst) {
15721739
let mut redirect_out = BufWriter::new(redirect_out);
15731740
try_err!(layout::redirect(&mut redirect_out, file_name), &redir_dst);
15741741
}
@@ -1730,11 +1897,12 @@ impl<'a> fmt::Display for Item<'a> {
17301897
version)?;
17311898
}
17321899
write!(fmt,
1733-
r##"<span id='render-detail'>
1734-
<a id="toggle-all-docs" href="javascript:void(0)" title="collapse all docs">
1735-
[<span class='inner'>&#x2212;</span>]
1736-
</a>
1737-
</span>"##)?;
1900+
"<span id='render-detail'>\
1901+
<a id=\"toggle-all-docs\" href=\"javascript:void(0)\" \
1902+
title=\"collapse all docs\">\
1903+
[<span class='inner'>&#x2212;</span>]\
1904+
</a>\
1905+
</span>")?;
17381906

17391907
// Write `src` tag
17401908
//
@@ -3540,33 +3708,35 @@ impl<'a> fmt::Display for Sidebar<'a> {
35403708

35413709
if it.is_struct() || it.is_trait() || it.is_primitive() || it.is_union()
35423710
|| it.is_enum() || it.is_mod() || it.is_typedef() {
3543-
write!(fmt, "<p class='location'>")?;
3544-
match it.inner {
3545-
clean::StructItem(..) => write!(fmt, "Struct ")?,
3546-
clean::TraitItem(..) => write!(fmt, "Trait ")?,
3547-
clean::PrimitiveItem(..) => write!(fmt, "Primitive Type ")?,
3548-
clean::UnionItem(..) => write!(fmt, "Union ")?,
3549-
clean::EnumItem(..) => write!(fmt, "Enum ")?,
3550-
clean::TypedefItem(..) => write!(fmt, "Type Definition ")?,
3551-
clean::ForeignTypeItem => write!(fmt, "Foreign Type ")?,
3552-
clean::ModuleItem(..) => if it.is_crate() {
3553-
write!(fmt, "Crate ")?;
3554-
} else {
3555-
write!(fmt, "Module ")?;
3711+
write!(fmt, "<p class='location'>{}{}</p>",
3712+
match it.inner {
3713+
clean::StructItem(..) => "Struct ",
3714+
clean::TraitItem(..) => "Trait ",
3715+
clean::PrimitiveItem(..) => "Primitive Type ",
3716+
clean::UnionItem(..) => "Union ",
3717+
clean::EnumItem(..) => "Enum ",
3718+
clean::TypedefItem(..) => "Type Definition ",
3719+
clean::ForeignTypeItem => "Foreign Type ",
3720+
clean::ModuleItem(..) => if it.is_crate() {
3721+
"Crate "
3722+
} else {
3723+
"Module "
3724+
},
3725+
_ => "",
35563726
},
3557-
_ => (),
3558-
}
3559-
write!(fmt, "{}", it.name.as_ref().unwrap())?;
3560-
write!(fmt, "</p>")?;
3727+
it.name.as_ref().unwrap())?;
35613728
}
35623729

35633730
if it.is_crate() {
35643731
if let Some(ref version) = cache().crate_version {
35653732
write!(fmt,
35663733
"<div class='block version'>\
35673734
<p>Version {}</p>\
3568-
</div>",
3569-
version)?;
3735+
</div>
3736+
<a id='all-types' href='all{}.html'><p>See all {}'s items</p></a>",
3737+
version,
3738+
cx.shared.resource_suffix,
3739+
it.name.as_ref().unwrap())?;
35703740
}
35713741
}
35723742

src/librustdoc/html/static/rustdoc.css

+18
Original file line numberDiff line numberDiff line change
@@ -1291,3 +1291,21 @@ kbd {
12911291
font-size: 19px;
12921292
display: block;
12931293
}
1294+
1295+
#main > ul {
1296+
padding-left: 10px;
1297+
}
1298+
#main > ul > li {
1299+
list-style: none;
1300+
}
1301+
#all-types {
1302+
text-align: center;
1303+
border: 1px solid;
1304+
margin: 0 10px;
1305+
margin-bottom: 10px;
1306+
display: block;
1307+
border-radius: 7px;
1308+
}
1309+
#all-types > p {
1310+
margin: 5px 0;
1311+
}

src/librustdoc/html/static/themes/dark.css

+7
Original file line numberDiff line numberDiff line change
@@ -389,3 +389,10 @@ kbd {
389389
background: #f0f0f0;
390390
}
391391
}
392+
393+
#all-types {
394+
background-color: #505050;
395+
}
396+
#all-types:hover {
397+
background-color: #606060;
398+
}

src/librustdoc/html/static/themes/light.css

+7
Original file line numberDiff line numberDiff line change
@@ -383,3 +383,10 @@ kbd {
383383
background: #fff;
384384
}
385385
}
386+
387+
#all-types {
388+
background-color: #fff;
389+
}
390+
#all-types:hover {
391+
background-color: #f9f9f9;
392+
}

0 commit comments

Comments
 (0)