@@ -104,6 +104,8 @@ pub struct Context {
104
104
/// the source files are present in the html rendering, then this will be
105
105
/// `true`.
106
106
pub include_sources : bool ,
107
+ /// The local file sources we've emitted and their respective url-paths.
108
+ pub local_sources : HashMap < PathBuf , String > ,
107
109
/// A flag, which when turned off, will render pages which redirect to the
108
110
/// real location of an item. This is used to allow external links to
109
111
/// publicly reused items to redirect to the right location.
@@ -262,8 +264,6 @@ pub struct Cache {
262
264
struct SourceCollector < ' a > {
263
265
cx : & ' a mut Context ,
264
266
265
- /// Processed source-file paths
266
- seen : HashSet < String > ,
267
267
/// Root destination to place all HTML output into
268
268
dst : PathBuf ,
269
269
}
@@ -423,6 +423,7 @@ pub fn run(mut krate: clean::Crate,
423
423
playground_url : "" . to_string ( ) ,
424
424
} ,
425
425
include_sources : true ,
426
+ local_sources : HashMap :: new ( ) ,
426
427
render_redirect_pages : false ,
427
428
issue_tracker_base_url : None ,
428
429
} ;
@@ -770,11 +771,8 @@ fn render_sources(cx: &mut Context,
770
771
try_err ! ( mkdir( & dst) , & dst) ;
771
772
let mut folder = SourceCollector {
772
773
dst : dst,
773
- seen : HashSet :: new ( ) ,
774
774
cx : cx,
775
775
} ;
776
- // skip all invalid spans
777
- folder. seen . insert ( "" . to_string ( ) ) ;
778
776
Ok ( folder. fold_crate ( krate) )
779
777
}
780
778
@@ -866,7 +864,13 @@ impl<'a> DocFolder for SourceCollector<'a> {
866
864
fn fold_item ( & mut self , item : clean:: Item ) -> Option < clean:: Item > {
867
865
// If we're including source files, and we haven't seen this file yet,
868
866
// then we need to render it out to the filesystem
869
- if self . cx . include_sources && !self . seen . contains ( & item. source . filename ) {
867
+ if self . cx . include_sources
868
+ // skip all invalid spans
869
+ && item. source . filename != ""
870
+ // macros from other libraries get special filenames which we can
871
+ // safely ignore
872
+ && !( item. source . filename . starts_with ( "<" )
873
+ && item. source . filename . ends_with ( "macros>" ) ) {
870
874
871
875
// If it turns out that we couldn't read this file, then we probably
872
876
// can't read any of the files (generating html output from json or
@@ -884,7 +888,6 @@ impl<'a> DocFolder for SourceCollector<'a> {
884
888
false
885
889
}
886
890
} ;
887
- self . seen . insert ( item. source . filename . clone ( ) ) ;
888
891
}
889
892
890
893
self . fold_item_recur ( item)
@@ -895,19 +898,14 @@ impl<'a> SourceCollector<'a> {
895
898
/// Renders the given filename into its corresponding HTML source file.
896
899
fn emit_source ( & mut self , filename : & str ) -> io:: Result < ( ) > {
897
900
let p = PathBuf :: from ( filename) ;
901
+ if self . cx . local_sources . contains_key ( & p) {
902
+ // We've already emitted this source
903
+ return Ok ( ( ) ) ;
904
+ }
898
905
899
- // If we couldn't open this file, then just returns because it
900
- // probably means that it's some standard library macro thing and we
901
- // can't have the source to it anyway.
902
906
let mut contents = Vec :: new ( ) ;
903
- match File :: open ( & p) . and_then ( |mut f| f. read_to_end ( & mut contents) ) {
904
- Ok ( r) => r,
905
- // macros from other libraries get special filenames which we can
906
- // safely ignore
907
- Err ( ..) if filename. starts_with ( "<" ) &&
908
- filename. ends_with ( "macros>" ) => return Ok ( ( ) ) ,
909
- Err ( e) => return Err ( e)
910
- } ;
907
+ try!( File :: open ( & p) . and_then ( |mut f| f. read_to_end ( & mut contents) ) ) ;
908
+
911
909
let contents = str:: from_utf8 ( & contents) . unwrap ( ) ;
912
910
913
911
// Remove the utf-8 BOM if any
@@ -920,16 +918,20 @@ impl<'a> SourceCollector<'a> {
920
918
// Create the intermediate directories
921
919
let mut cur = self . dst . clone ( ) ;
922
920
let mut root_path = String :: from ( "../../" ) ;
921
+ let mut href = String :: new ( ) ;
923
922
clean_srcpath ( & self . cx . src_root , & p, false , |component| {
924
923
cur. push ( component) ;
925
924
mkdir ( & cur) . unwrap ( ) ;
926
925
root_path. push_str ( "../" ) ;
926
+ href. push_str ( component) ;
927
+ href. push ( '/' ) ;
927
928
} ) ;
928
-
929
929
let mut fname = p. file_name ( ) . expect ( "source has no filename" )
930
930
. to_os_string ( ) ;
931
931
fname. push ( ".html" ) ;
932
932
cur. push ( & fname[ ..] ) ;
933
+ href. push_str ( & fname. to_string_lossy ( ) ) ;
934
+
933
935
let mut w = BufWriter :: new ( try!( File :: create ( & cur) ) ) ;
934
936
let title = format ! ( "{} -- source" , cur. file_name( ) . unwrap( )
935
937
. to_string_lossy( ) ) ;
@@ -944,7 +946,8 @@ impl<'a> SourceCollector<'a> {
944
946
try!( layout:: render ( & mut w, & self . cx . layout ,
945
947
& page, & ( "" ) , & Source ( contents) ) ) ;
946
948
try!( w. flush ( ) ) ;
947
- return Ok ( ( ) ) ;
949
+ self . cx . local_sources . insert ( p, href) ;
950
+ Ok ( ( ) )
948
951
}
949
952
}
950
953
@@ -1459,7 +1462,7 @@ impl<'a> Item<'a> {
1459
1462
/// If `None` is returned, then a source link couldn't be generated. This
1460
1463
/// may happen, for example, with externally inlined items where the source
1461
1464
/// of their crate documentation isn't known.
1462
- fn href ( & self , cx : & Context ) -> Option < String > {
1465
+ fn href ( & self ) -> Option < String > {
1463
1466
let href = if self . item . source . loline == self . item . source . hiline {
1464
1467
format ! ( "{}" , self . item. source. loline)
1465
1468
} else {
@@ -1492,25 +1495,13 @@ impl<'a> Item<'a> {
1492
1495
// know the span, so we plow forward and generate a proper url. The url
1493
1496
// has anchors for the line numbers that we're linking to.
1494
1497
} else if self . item . def_id . is_local ( ) {
1495
- let mut path = Vec :: new ( ) ;
1496
- clean_srcpath ( & cx. src_root , Path :: new ( & self . item . source . filename ) ,
1497
- true , |component| {
1498
- path. push ( component. to_string ( ) ) ;
1499
- } ) ;
1500
-
1501
- // If the span points into an external macro the
1502
- // source-file will be bogus, i.e `<foo macros>`
1503
- let filename = & self . item . source . filename ;
1504
- if !( filename. starts_with ( "<" ) && filename. ends_with ( "macros>" ) ) {
1505
- Some ( format ! ( "{root}src/{krate}/{path}.html#{href}" ,
1506
- root = self . cx. root_path,
1507
- krate = self . cx. layout. krate,
1508
- path = path. join( "/" ) ,
1509
- href = href) )
1510
- } else {
1511
- None
1512
- }
1513
-
1498
+ self . cx . local_sources . get ( & PathBuf :: from ( & self . item . source . filename ) ) . map ( |path| {
1499
+ format ! ( "{root}src/{krate}/{path}.html#{href}" ,
1500
+ root = self . cx. root_path,
1501
+ krate = self . cx. layout. krate,
1502
+ path = path,
1503
+ href = href)
1504
+ } )
1514
1505
// If this item is not part of the local crate, then things get a little
1515
1506
// trickier. We don't actually know the span of the external item, but
1516
1507
// we know that the documentation on the other end knows the span!
@@ -1590,7 +1581,7 @@ impl<'a> fmt::Display for Item<'a> {
1590
1581
// this page, and this link will be auto-clicked. The `id` attribute is
1591
1582
// used to find the link to auto-click.
1592
1583
if self . cx . include_sources && !is_primitive {
1593
- match self . href ( self . cx ) {
1584
+ match self . href ( ) {
1594
1585
Some ( l) => {
1595
1586
try!( write ! ( fmt, "<a id='src-{}' class='srclink' \
1596
1587
href='{}' title='{}'>[src]</a>",
0 commit comments