@@ -70,7 +70,7 @@ use html::markdown;
7070pub struct Context {
7171 /// Current hierarchy of components leading down to what's currently being
7272 /// rendered
73- pub current : Vec < String > ,
73+ pub current : Vec < String > ,
7474 /// String representation of how to get back to the root path of the 'doc/'
7575 /// folder in terms of a relative URL.
7676 pub root_path : String ,
@@ -90,6 +90,10 @@ pub struct Context {
9090 /// the source files are present in the html rendering, then this will be
9191 /// `true`.
9292 pub include_sources : bool ,
93+ /// A flag, which when turned off, will render pages which redirect to the
94+ /// real location of an item. This is used to allow external links to
95+ /// publicly reused items to redirect to the right location.
96+ pub render_redirect_pages : bool ,
9397}
9498
9599/// Indicates where an external crate can be found.
@@ -227,6 +231,7 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> {
227231 krate : krate. name . clone ( ) ,
228232 } ,
229233 include_sources : true ,
234+ render_redirect_pages : false ,
230235 } ;
231236 try!( mkdir ( & cx. dst ) ) ;
232237
@@ -493,7 +498,17 @@ fn write_shared(cx: &Context,
493498 let dst = cx. dst . join ( "implementors" ) ;
494499 try!( mkdir ( & dst) ) ;
495500 for ( & did, imps) in cache. implementors . iter ( ) {
496- let & ( ref remote_path, remote_item_type) = cache. paths . get ( & did) ;
501+ // Private modules can leak through to this phase of rustdoc, which
502+ // could contain implementations for otherwise private types. In some
503+ // rare cases we could find an implementation for an item which wasn't
504+ // indexed, so we just skip this step in that case.
505+ //
506+ // FIXME: this is a vague explanation for why this can't be a `get`, in
507+ // theory it should be...
508+ let & ( ref remote_path, remote_item_type) = match cache. paths . find ( & did) {
509+ Some ( p) => p,
510+ None => continue ,
511+ } ;
497512
498513 let mut mydst = dst. clone ( ) ;
499514 for part in remote_path. slice_to ( remote_path. len ( ) - 1 ) . iter ( ) {
@@ -823,7 +838,7 @@ impl DocFolder for Cache {
823838 clean:: StructItem ( ..) | clean:: EnumItem ( ..) |
824839 clean:: TypedefItem ( ..) | clean:: TraitItem ( ..) |
825840 clean:: FunctionItem ( ..) | clean:: ModuleItem ( ..) |
826- clean:: ForeignFunctionItem ( ..) => {
841+ clean:: ForeignFunctionItem ( ..) if ! self . privmod => {
827842 // Reexported items mean that the same id can show up twice
828843 // in the rustdoc ast that we're looking at. We know,
829844 // however, that a reexported item doesn't show up in the
@@ -840,7 +855,7 @@ impl DocFolder for Cache {
840855 }
841856 // link variants to their parent enum because pages aren't emitted
842857 // for each variant
843- clean:: VariantItem ( ..) => {
858+ clean:: VariantItem ( ..) if ! self . privmod => {
844859 let mut stack = self . stack . clone ( ) ;
845860 stack. pop ( ) ;
846861 self . paths . insert ( item. def_id , ( stack, item_type:: Enum ) ) ;
@@ -932,14 +947,6 @@ impl DocFolder for Cache {
932947 }
933948 None
934949 }
935- // Private modules may survive the strip-private pass if
936- // they contain impls for public types, but those will get
937- // stripped here
938- clean:: Item { inner : clean:: ModuleItem ( ref m) ,
939- visibility, .. }
940- if ( m. items . len ( ) == 0 &&
941- item. doc_value ( ) . is_none ( ) ) ||
942- visibility != Some ( ast:: Public ) => None ,
943950
944951 i => Some ( i) ,
945952 }
@@ -1020,7 +1027,7 @@ impl Context {
10201027 /// The rendering driver uses this closure to queue up more work.
10211028 fn item ( & mut self , item : clean:: Item ,
10221029 f : |& mut Context , clean:: Item |) -> io:: IoResult < ( ) > {
1023- fn render ( w : io:: File , cx : & mut Context , it : & clean:: Item ,
1030+ fn render ( w : io:: File , cx : & Context , it : & clean:: Item ,
10241031 pushname : bool ) -> io:: IoResult < ( ) > {
10251032 info ! ( "Rendering an item to {}" , w. path( ) . display( ) ) ;
10261033 // A little unfortunate that this is done like this, but it sure
@@ -1047,16 +1054,42 @@ impl Context {
10471054 // of the pain by using a buffered writer instead of invoking the
10481055 // write sycall all the time.
10491056 let mut writer = BufferedWriter :: new ( w) ;
1050- try!( layout:: render ( & mut writer as & mut Writer , & cx. layout , & page,
1051- & Sidebar { cx : cx, item : it } ,
1052- & Item { cx : cx, item : it } ) ) ;
1057+ if !cx. render_redirect_pages {
1058+ try!( layout:: render ( & mut writer, & cx. layout , & page,
1059+ & Sidebar { cx : cx, item : it } ,
1060+ & Item { cx : cx, item : it } ) ) ;
1061+ } else {
1062+ let mut url = "../" . repeat ( cx. current . len ( ) ) ;
1063+ match cache_key. get ( ) . unwrap ( ) . paths . find ( & it. def_id ) {
1064+ Some ( & ( ref names, _) ) => {
1065+ for name in names. slice_to ( names. len ( ) - 1 ) . iter ( ) {
1066+ url. push_str ( name. as_slice ( ) ) ;
1067+ url. push_str ( "/" ) ;
1068+ }
1069+ url. push_str ( item_path ( it) . as_slice ( ) ) ;
1070+ try!( layout:: redirect ( & mut writer, url. as_slice ( ) ) ) ;
1071+ }
1072+ None => { }
1073+ }
1074+ }
10531075 writer. flush ( )
10541076 }
10551077
10561078 match item. inner {
10571079 // modules are special because they add a namespace. We also need to
10581080 // recurse into the items of the module as well.
10591081 clean:: ModuleItem ( ..) => {
1082+ // Private modules may survive the strip-private pass if they
1083+ // contain impls for public types. These modules can also
1084+ // contain items such as publicly reexported structures.
1085+ //
1086+ // External crates will provide links to these structures, so
1087+ // these modules are recursed into, but not rendered normally (a
1088+ // flag on the context).
1089+ if !self . render_redirect_pages {
1090+ self . render_redirect_pages = ignore_private_module ( & item) ;
1091+ }
1092+
10601093 let name = item. name . get_ref ( ) . to_string ( ) ;
10611094 let mut item = Some ( item) ;
10621095 self . recurse ( name, |this| {
@@ -1289,8 +1322,9 @@ fn document(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result {
12891322fn item_module ( w : & mut fmt:: Formatter , cx : & Context ,
12901323 item : & clean:: Item , items : & [ clean:: Item ] ) -> fmt:: Result {
12911324 try!( document ( w, item) ) ;
1292- debug ! ( "{:?}" , items) ;
1293- let mut indices = Vec :: from_fn ( items. len ( ) , |i| i) ;
1325+ let mut indices = range ( 0 , items. len ( ) ) . filter ( |i| {
1326+ !ignore_private_module ( & items[ * i] )
1327+ } ) . collect :: < Vec < uint > > ( ) ;
12941328
12951329 fn cmp ( i1 : & clean:: Item , i2 : & clean:: Item , idx1 : uint , idx2 : uint ) -> Ordering {
12961330 if shortty ( i1) == shortty ( i2) {
@@ -1332,7 +1366,6 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
13321366 }
13331367 }
13341368
1335- debug ! ( "{:?}" , indices) ;
13361369 indices. sort_by ( |& i1, & i2| cmp ( & items[ i1] , & items[ i2] , i1, i2) ) ;
13371370
13381371 debug ! ( "{:?}" , indices) ;
@@ -1976,6 +2009,8 @@ impl<'a> fmt::Show for Sidebar<'a> {
19762009fn build_sidebar ( m : & clean:: Module ) -> HashMap < String , Vec < String > > {
19772010 let mut map = HashMap :: new ( ) ;
19782011 for item in m. items . iter ( ) {
2012+ if ignore_private_module ( item) { continue }
2013+
19792014 let short = shortty ( item) . to_static_str ( ) ;
19802015 let myname = match item. name {
19812016 None => continue ,
@@ -2023,3 +2058,13 @@ fn item_primitive(w: &mut fmt::Formatter,
20232058 try!( document ( w, it) ) ;
20242059 render_methods ( w, it)
20252060}
2061+
2062+ fn ignore_private_module ( it : & clean:: Item ) -> bool {
2063+ match it. inner {
2064+ clean:: ModuleItem ( ref m) => {
2065+ ( m. items . len ( ) == 0 && it. doc_value ( ) . is_none ( ) ) ||
2066+ it. visibility != Some ( ast:: Public )
2067+ }
2068+ _ => false ,
2069+ }
2070+ }
0 commit comments