@@ -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'>−</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+
13761506impl 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'>−</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'>−</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
0 commit comments