Auto merge of #49504 - GuillaumeGomez:doc-all-types, r=QuietMisdreavus
Add page to list all crate's items r? @QuietMisdreavus
This commit is contained in:
commit
a1c21ed7e2
@ -1087,7 +1087,8 @@ impl<'a> SourceCollector<'a> {
|
||||
href.push_str(component);
|
||||
href.push('/');
|
||||
});
|
||||
let mut fname = p.file_name().expect("source has no filename")
|
||||
let mut fname = p.file_name()
|
||||
.expect("source has no filename")
|
||||
.to_os_string();
|
||||
fname.push(".html");
|
||||
cur.push(&fname);
|
||||
@ -1373,6 +1374,135 @@ impl<'a> Cache {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Hash)]
|
||||
struct ItemEntry {
|
||||
url: String,
|
||||
name: String,
|
||||
}
|
||||
|
||||
impl ItemEntry {
|
||||
fn new(mut url: String, name: String) -> ItemEntry {
|
||||
while url.starts_with('/') {
|
||||
url.remove(0);
|
||||
}
|
||||
ItemEntry {
|
||||
url,
|
||||
name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ItemEntry {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "<a href='{}'>{}</a>", self.url, Escape(&self.name))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for ItemEntry {
|
||||
fn partial_cmp(&self, other: &ItemEntry) -> Option<::std::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for ItemEntry {
|
||||
fn cmp(&self, other: &ItemEntry) -> ::std::cmp::Ordering {
|
||||
self.name.cmp(&other.name)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct AllTypes {
|
||||
structs: HashSet<ItemEntry>,
|
||||
enums: HashSet<ItemEntry>,
|
||||
unions: HashSet<ItemEntry>,
|
||||
primitives: HashSet<ItemEntry>,
|
||||
traits: HashSet<ItemEntry>,
|
||||
macros: HashSet<ItemEntry>,
|
||||
functions: HashSet<ItemEntry>,
|
||||
typedefs: HashSet<ItemEntry>,
|
||||
statics: HashSet<ItemEntry>,
|
||||
constants: HashSet<ItemEntry>,
|
||||
}
|
||||
|
||||
impl AllTypes {
|
||||
fn new() -> AllTypes {
|
||||
AllTypes {
|
||||
structs: HashSet::with_capacity(100),
|
||||
enums: HashSet::with_capacity(100),
|
||||
unions: HashSet::with_capacity(100),
|
||||
primitives: HashSet::with_capacity(26),
|
||||
traits: HashSet::with_capacity(100),
|
||||
macros: HashSet::with_capacity(100),
|
||||
functions: HashSet::with_capacity(100),
|
||||
typedefs: HashSet::with_capacity(100),
|
||||
statics: HashSet::with_capacity(100),
|
||||
constants: HashSet::with_capacity(100),
|
||||
}
|
||||
}
|
||||
|
||||
fn append(&mut self, item_name: String, item_type: &ItemType) {
|
||||
let mut url: Vec<_> = item_name.split("::").skip(1).collect();
|
||||
if let Some(name) = url.pop() {
|
||||
let new_url = format!("{}/{}.{}.html", url.join("/"), item_type, name);
|
||||
url.push(name);
|
||||
let name = url.join("::");
|
||||
match *item_type {
|
||||
ItemType::Struct => self.structs.insert(ItemEntry::new(new_url, name)),
|
||||
ItemType::Enum => self.enums.insert(ItemEntry::new(new_url, name)),
|
||||
ItemType::Union => self.unions.insert(ItemEntry::new(new_url, name)),
|
||||
ItemType::Primitive => self.primitives.insert(ItemEntry::new(new_url, name)),
|
||||
ItemType::Trait => self.traits.insert(ItemEntry::new(new_url, name)),
|
||||
ItemType::Macro => self.macros.insert(ItemEntry::new(new_url, name)),
|
||||
ItemType::Function => self.functions.insert(ItemEntry::new(new_url, name)),
|
||||
ItemType::Typedef => self.typedefs.insert(ItemEntry::new(new_url, name)),
|
||||
ItemType::Static => self.statics.insert(ItemEntry::new(new_url, name)),
|
||||
ItemType::Constant => self.constants.insert(ItemEntry::new(new_url, name)),
|
||||
_ => true,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn print_entries(f: &mut fmt::Formatter, e: &HashSet<ItemEntry>, title: &str,
|
||||
class: &str) -> fmt::Result {
|
||||
if !e.is_empty() {
|
||||
let mut e: Vec<&ItemEntry> = e.iter().collect();
|
||||
e.sort();
|
||||
write!(f, "<h3 id='{}'>{}</h3><ul class='{} docblock'>{}</ul>",
|
||||
title,
|
||||
Escape(title),
|
||||
class,
|
||||
e.iter().map(|s| format!("<li>{}</li>", s)).collect::<String>())?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl fmt::Display for AllTypes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f,
|
||||
"<h1 class='fqn'>\
|
||||
<span class='in-band'>List of all items</span>\
|
||||
<span class='out-of-band'>\
|
||||
<span id='render-detail'>\
|
||||
<a id=\"toggle-all-docs\" href=\"javascript:void(0)\" title=\"collapse all docs\">\
|
||||
[<span class='inner'>−</span>]\
|
||||
</a>\
|
||||
</span>
|
||||
</span>
|
||||
</h1>")?;
|
||||
print_entries(f, &self.structs, "Structs", "structs")?;
|
||||
print_entries(f, &self.enums, "Enums", "enums")?;
|
||||
print_entries(f, &self.unions, "Unions", "unions")?;
|
||||
print_entries(f, &self.primitives, "Primitives", "primitives")?;
|
||||
print_entries(f, &self.traits, "Traits", "traits")?;
|
||||
print_entries(f, &self.macros, "Macros", "macros")?;
|
||||
print_entries(f, &self.functions, "Functions", "functions")?;
|
||||
print_entries(f, &self.typedefs, "Typedefs", "typedefs")?;
|
||||
print_entries(f, &self.statics, "Statics", "statics")?;
|
||||
print_entries(f, &self.constants, "Constants", "constants")
|
||||
}
|
||||
}
|
||||
|
||||
impl Context {
|
||||
/// String representation of how to get back to the root path of the 'doc/'
|
||||
/// folder in terms of a relative URL.
|
||||
@ -1414,16 +1544,52 @@ impl Context {
|
||||
Some(i) => i,
|
||||
None => return Ok(()),
|
||||
};
|
||||
let final_file = self.dst.join(&krate.name)
|
||||
.join("all.html");
|
||||
let crate_name = krate.name.clone();
|
||||
item.name = Some(krate.name);
|
||||
|
||||
// Render the crate documentation
|
||||
let mut work = vec![(self, item)];
|
||||
let mut all = AllTypes::new();
|
||||
|
||||
while let Some((mut cx, item)) = work.pop() {
|
||||
cx.item(item, |cx, item| {
|
||||
work.push((cx.clone(), item))
|
||||
})?
|
||||
{
|
||||
// Render the crate documentation
|
||||
let mut work = vec![(self.clone(), item)];
|
||||
|
||||
while let Some((mut cx, item)) = work.pop() {
|
||||
cx.item(item, &mut all, |cx, item| {
|
||||
work.push((cx.clone(), item))
|
||||
})?
|
||||
}
|
||||
}
|
||||
|
||||
let mut w = BufWriter::new(try_err!(File::create(&final_file), &final_file));
|
||||
let mut root_path = self.dst.to_str().expect("invalid path").to_owned();
|
||||
if !root_path.ends_with('/') {
|
||||
root_path.push('/');
|
||||
}
|
||||
let page = layout::Page {
|
||||
title: "List of all items in this crate",
|
||||
css_class: "mod",
|
||||
root_path: "../",
|
||||
description: "List of all items in this crate",
|
||||
keywords: BASIC_KEYWORDS,
|
||||
resource_suffix: &self.shared.resource_suffix,
|
||||
};
|
||||
let sidebar = if let Some(ref version) = cache().crate_version {
|
||||
format!("<p class='location'>Crate {}</p>\
|
||||
<div class='block version'>\
|
||||
<p>Version {}</p>\
|
||||
</div>\
|
||||
<a id='all-types' href='index.html'><p>Back to index</p></a>",
|
||||
crate_name, version)
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
try_err!(layout::render(&mut w, &self.shared.layout,
|
||||
&page, &sidebar, &all,
|
||||
self.shared.css_file_extension.is_some(),
|
||||
&self.shared.themes),
|
||||
&final_file);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -1496,8 +1662,8 @@ impl Context {
|
||||
/// all sub-items which need to be rendered.
|
||||
///
|
||||
/// The rendering driver uses this closure to queue up more work.
|
||||
fn item<F>(&mut self, item: clean::Item, mut f: F) -> Result<(), Error> where
|
||||
F: FnMut(&mut Context, clean::Item),
|
||||
fn item<F>(&mut self, item: clean::Item, all: &mut AllTypes, mut f: F) -> Result<(), Error>
|
||||
where F: FnMut(&mut Context, clean::Item),
|
||||
{
|
||||
// Stripped modules survive the rustdoc passes (i.e. `strip-private`)
|
||||
// if they contain impls for public types. These modules can also
|
||||
@ -1544,7 +1710,7 @@ impl Context {
|
||||
}
|
||||
|
||||
for item in m.items {
|
||||
f(this,item);
|
||||
f(this, item);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -1562,13 +1728,14 @@ impl Context {
|
||||
let mut dst = try_err!(File::create(&joint_dst), &joint_dst);
|
||||
try_err!(dst.write_all(&buf), &joint_dst);
|
||||
|
||||
all.append(full_path(self, &item), &item_type);
|
||||
// Redirect from a sane URL using the namespace to Rustdoc's
|
||||
// URL for the page.
|
||||
let redir_name = format!("{}.{}.html", name, item_type.name_space());
|
||||
let redir_dst = self.dst.join(redir_name);
|
||||
if let Ok(redirect_out) = OpenOptions::new().create_new(true)
|
||||
.write(true)
|
||||
.open(&redir_dst) {
|
||||
.write(true)
|
||||
.open(&redir_dst) {
|
||||
let mut redirect_out = BufWriter::new(redirect_out);
|
||||
try_err!(layout::redirect(&mut redirect_out, file_name), &redir_dst);
|
||||
}
|
||||
@ -1730,11 +1897,12 @@ impl<'a> fmt::Display for Item<'a> {
|
||||
version)?;
|
||||
}
|
||||
write!(fmt,
|
||||
r##"<span id='render-detail'>
|
||||
<a id="toggle-all-docs" href="javascript:void(0)" title="collapse all docs">
|
||||
[<span class='inner'>−</span>]
|
||||
</a>
|
||||
</span>"##)?;
|
||||
"<span id='render-detail'>\
|
||||
<a id=\"toggle-all-docs\" href=\"javascript:void(0)\" \
|
||||
title=\"collapse all docs\">\
|
||||
[<span class='inner'>−</span>]\
|
||||
</a>\
|
||||
</span>")?;
|
||||
|
||||
// Write `src` tag
|
||||
//
|
||||
@ -3567,24 +3735,23 @@ impl<'a> fmt::Display for Sidebar<'a> {
|
||||
|
||||
if it.is_struct() || it.is_trait() || it.is_primitive() || it.is_union()
|
||||
|| it.is_enum() || it.is_mod() || it.is_typedef() {
|
||||
write!(fmt, "<p class='location'>")?;
|
||||
match it.inner {
|
||||
clean::StructItem(..) => write!(fmt, "Struct ")?,
|
||||
clean::TraitItem(..) => write!(fmt, "Trait ")?,
|
||||
clean::PrimitiveItem(..) => write!(fmt, "Primitive Type ")?,
|
||||
clean::UnionItem(..) => write!(fmt, "Union ")?,
|
||||
clean::EnumItem(..) => write!(fmt, "Enum ")?,
|
||||
clean::TypedefItem(..) => write!(fmt, "Type Definition ")?,
|
||||
clean::ForeignTypeItem => write!(fmt, "Foreign Type ")?,
|
||||
clean::ModuleItem(..) => if it.is_crate() {
|
||||
write!(fmt, "Crate ")?;
|
||||
} else {
|
||||
write!(fmt, "Module ")?;
|
||||
write!(fmt, "<p class='location'>{}{}</p>",
|
||||
match it.inner {
|
||||
clean::StructItem(..) => "Struct ",
|
||||
clean::TraitItem(..) => "Trait ",
|
||||
clean::PrimitiveItem(..) => "Primitive Type ",
|
||||
clean::UnionItem(..) => "Union ",
|
||||
clean::EnumItem(..) => "Enum ",
|
||||
clean::TypedefItem(..) => "Type Definition ",
|
||||
clean::ForeignTypeItem => "Foreign Type ",
|
||||
clean::ModuleItem(..) => if it.is_crate() {
|
||||
"Crate "
|
||||
} else {
|
||||
"Module "
|
||||
},
|
||||
_ => "",
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
write!(fmt, "{}", it.name.as_ref().unwrap())?;
|
||||
write!(fmt, "</p>")?;
|
||||
it.name.as_ref().unwrap())?;
|
||||
}
|
||||
|
||||
if it.is_crate() {
|
||||
@ -3592,8 +3759,10 @@ impl<'a> fmt::Display for Sidebar<'a> {
|
||||
write!(fmt,
|
||||
"<div class='block version'>\
|
||||
<p>Version {}</p>\
|
||||
</div>",
|
||||
version)?;
|
||||
</div>
|
||||
<a id='all-types' href='all.html'><p>See all {}'s items</p></a>",
|
||||
version,
|
||||
it.name.as_ref().unwrap())?;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1294,3 +1294,21 @@ kbd {
|
||||
font-size: 19px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#main > ul {
|
||||
padding-left: 10px;
|
||||
}
|
||||
#main > ul > li {
|
||||
list-style: none;
|
||||
}
|
||||
#all-types {
|
||||
text-align: center;
|
||||
border: 1px solid;
|
||||
margin: 0 10px;
|
||||
margin-bottom: 10px;
|
||||
display: block;
|
||||
border-radius: 7px;
|
||||
}
|
||||
#all-types > p {
|
||||
margin: 5px 0;
|
||||
}
|
@ -389,3 +389,10 @@ kbd {
|
||||
background: #f0f0f0;
|
||||
}
|
||||
}
|
||||
|
||||
#all-types {
|
||||
background-color: #505050;
|
||||
}
|
||||
#all-types:hover {
|
||||
background-color: #606060;
|
||||
}
|
||||
|
@ -383,3 +383,10 @@ kbd {
|
||||
background: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
#all-types {
|
||||
background-color: #fff;
|
||||
}
|
||||
#all-types:hover {
|
||||
background-color: #f9f9f9;
|
||||
}
|
30
src/test/rustdoc/all.rs
Normal file
30
src/test/rustdoc/all.rs
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![crate_name = "foo"]
|
||||
|
||||
// @has foo/all.html '//a[@href="struct.Struct.html"]' 'Struct'
|
||||
// @has foo/all.html '//a[@href="enum.Enum.html"]' 'Enum'
|
||||
// @has foo/all.html '//a[@href="union.Union.html"]' 'Union'
|
||||
// @has foo/all.html '//a[@href="constant.CONST.html"]' 'CONST'
|
||||
// @has foo/all.html '//a[@href="static.STATIC.html"]' 'STATIC'
|
||||
// @has foo/all.html '//a[@href="fn.function.html"]' 'function'
|
||||
|
||||
pub struct Struct;
|
||||
pub enum Enum {
|
||||
X,
|
||||
Y,
|
||||
}
|
||||
pub union Union {
|
||||
x: u32,
|
||||
}
|
||||
pub const CONST: u32 = 0;
|
||||
pub static STATIC: &str = "baguette";
|
||||
pub fn function() {}
|
Loading…
Reference in New Issue
Block a user