@@ -4,6 +4,7 @@ use std::fmt;
4
4
use std:: hash:: { Hash , Hasher } ;
5
5
use std:: iter:: FromIterator ;
6
6
use std:: lazy:: SyncOnceCell as OnceCell ;
7
+ use std:: path:: PathBuf ;
7
8
use std:: rc:: Rc ;
8
9
use std:: sync:: Arc ;
9
10
use std:: { slice, vec} ;
@@ -90,6 +91,58 @@ impl ExternalCrate {
90
91
tcx. crate_name ( self . crate_num )
91
92
}
92
93
94
+ crate fn src_root ( & self , tcx : TyCtxt < ' _ > ) -> PathBuf {
95
+ match self . src ( tcx) {
96
+ FileName :: Real ( ref p) => match p. local_path ( ) . parent ( ) {
97
+ Some ( p) => p. to_path_buf ( ) ,
98
+ None => PathBuf :: new ( ) ,
99
+ } ,
100
+ _ => PathBuf :: new ( ) ,
101
+ }
102
+ }
103
+
104
+ /// Attempts to find where an external crate is located, given that we're
105
+ /// rendering in to the specified source destination.
106
+ crate fn location (
107
+ & self ,
108
+ extern_url : Option < & str > ,
109
+ dst : & std:: path:: Path ,
110
+ tcx : TyCtxt < ' _ > ,
111
+ ) -> ExternalLocation {
112
+ use ExternalLocation :: * ;
113
+
114
+ fn to_remote ( url : impl ToString ) -> ExternalLocation {
115
+ let mut url = url. to_string ( ) ;
116
+ if !url. ends_with ( '/' ) {
117
+ url. push ( '/' ) ;
118
+ }
119
+ Remote ( url)
120
+ }
121
+
122
+ // See if there's documentation generated into the local directory
123
+ // WARNING: since rustdoc creates these directories as it generates documentation, this check is only accurate before rendering starts.
124
+ // Make sure to call `location()` by that time.
125
+ let local_location = dst. join ( & * self . name ( tcx) . as_str ( ) ) ;
126
+ if local_location. is_dir ( ) {
127
+ return Local ;
128
+ }
129
+
130
+ if let Some ( url) = extern_url {
131
+ return to_remote ( url) ;
132
+ }
133
+
134
+ // Failing that, see if there's an attribute specifying where to find this
135
+ // external crate
136
+ let did = DefId { krate : self . crate_num , index : CRATE_DEF_INDEX } ;
137
+ tcx. get_attrs ( did)
138
+ . lists ( sym:: doc)
139
+ . filter ( |a| a. has_name ( sym:: html_root_url) )
140
+ . filter_map ( |a| a. value_str ( ) )
141
+ . map ( to_remote)
142
+ . next ( )
143
+ . unwrap_or ( Unknown ) // Well, at least we tried.
144
+ }
145
+
93
146
crate fn keywords ( & self , tcx : TyCtxt < ' _ > ) -> ThinVec < ( DefId , Symbol ) > {
94
147
let root = self . def_id ( ) ;
95
148
@@ -381,7 +434,7 @@ impl Item {
381
434
let relative_to = & cx. current ;
382
435
if let Some ( ref fragment) = * fragment {
383
436
let url = match cx. cache ( ) . extern_locations . get ( & self . def_id . krate ) {
384
- Some ( & ( _ , _ , ExternalLocation :: Local ) ) => {
437
+ Some ( ExternalLocation :: Local ) => {
385
438
if relative_to[ 0 ] == "std" {
386
439
let depth = relative_to. len ( ) - 1 ;
387
440
"../" . repeat ( depth)
@@ -390,10 +443,10 @@ impl Item {
390
443
format ! ( "{}std/" , "../" . repeat( depth) )
391
444
}
392
445
}
393
- Some ( & ( _ , _ , ExternalLocation :: Remote ( ref s) ) ) => {
446
+ Some ( ExternalLocation :: Remote ( ref s) ) => {
394
447
format ! ( "{}/std/" , s. trim_end_matches( '/' ) )
395
448
}
396
- Some ( & ( _ , _ , ExternalLocation :: Unknown ) ) | None => format ! (
449
+ Some ( ExternalLocation :: Unknown ) | None => format ! (
397
450
"https://doc.rust-lang.org/{}/std/" ,
398
451
crate :: doc_rust_lang_org_channel( ) ,
399
452
) ,
0 commit comments