@@ -944,6 +944,65 @@ fn string<T: Display>(
944944 }
945945}
946946
947+ fn generate_link_to_def (
948+ out : & mut impl Write ,
949+ text_s : & str ,
950+ klass : Class ,
951+ href_context : & Option < HrefContext < ' _ , ' _ > > ,
952+ def_span : Span ,
953+ open_tag : bool ,
954+ ) -> bool {
955+ if let Some ( href_context) = href_context {
956+ if let Some ( href) =
957+ href_context. context . shared . span_correspondence_map . get ( & def_span) . and_then ( |href| {
958+ let context = href_context. context ;
959+ // FIXME: later on, it'd be nice to provide two links (if possible) for all items:
960+ // one to the documentation page and one to the source definition.
961+ // FIXME: currently, external items only generate a link to their documentation,
962+ // a link to their definition can be generated using this:
963+ // https://github.com/rust-lang/rust/blob/60f1a2fc4b535ead9c85ce085fdce49b1b097531/src/librustdoc/html/render/context.rs#L315-L338
964+ match href {
965+ LinkFromSrc :: Local ( span) => {
966+ context. href_from_span_relative ( * span, & href_context. current_href )
967+ }
968+ LinkFromSrc :: External ( def_id) => {
969+ format:: href_with_root_path ( * def_id, context, Some ( href_context. root_path ) )
970+ . ok ( )
971+ . map ( |( url, _, _) | url)
972+ }
973+ LinkFromSrc :: Primitive ( prim) => format:: href_with_root_path (
974+ PrimitiveType :: primitive_locations ( context. tcx ( ) ) [ prim] ,
975+ context,
976+ Some ( href_context. root_path ) ,
977+ )
978+ . ok ( )
979+ . map ( |( url, _, _) | url) ,
980+ LinkFromSrc :: Doc ( def_id) => {
981+ format:: href_with_root_path ( * def_id, context, Some ( href_context. root_path ) )
982+ . ok ( )
983+ . map ( |( doc_link, _, _) | doc_link)
984+ }
985+ }
986+ } )
987+ {
988+ if !open_tag {
989+ // We're already inside an element which has the same klass, no need to give it
990+ // again.
991+ write ! ( out, "<a href=\" {href}\" >{text_s}" ) . unwrap ( ) ;
992+ } else {
993+ let klass_s = klass. as_html ( ) ;
994+ if klass_s. is_empty ( ) {
995+ write ! ( out, "<a href=\" {href}\" >{text_s}" ) . unwrap ( ) ;
996+ } else {
997+ write ! ( out, "<a class=\" {klass_s}\" href=\" {href}\" >{text_s}" ) . unwrap ( ) ;
998+ }
999+ }
1000+ return true ;
1001+ }
1002+ }
1003+ false
1004+ }
1005+
9471006/// This function writes `text` into `out` with some modifications depending on `klass`:
9481007///
9491008/// * If `klass` is `None`, `text` is written into `out` with no modification.
@@ -973,10 +1032,14 @@ fn string_without_closing_tag<T: Display>(
9731032 return Some ( "</span>" ) ;
9741033 } ;
9751034
1035+ let mut added_links = false ;
9761036 let mut text_s = text. to_string ( ) ;
9771037 if text_s. contains ( "::" ) {
1038+ let mut span = def_span. with_hi ( def_span. lo ( ) ) ;
9781039 text_s = text_s. split ( "::" ) . intersperse ( "::" ) . fold ( String :: new ( ) , |mut path, t| {
1040+ span = span. with_hi ( span. hi ( ) + BytePos ( t. len ( ) as _ ) ) ;
9791041 match t {
1042+ "::" => write ! ( & mut path, "::" ) ,
9801043 "self" | "Self" => write ! (
9811044 & mut path,
9821045 "<span class=\" {klass}\" >{t}</span>" ,
@@ -989,60 +1052,25 @@ fn string_without_closing_tag<T: Display>(
9891052 klass = Class :: KeyWord . as_html( ) ,
9901053 )
9911054 }
992- t => write ! ( & mut path, "{t}" ) ,
1055+ t => {
1056+ if !t. is_empty ( )
1057+ && generate_link_to_def ( & mut path, t, klass, href_context, span, open_tag)
1058+ {
1059+ added_links = true ;
1060+ write ! ( & mut path, "</a>" )
1061+ } else {
1062+ write ! ( & mut path, "{t}" )
1063+ }
1064+ }
9931065 }
9941066 . expect ( "Failed to build source HTML path" ) ;
1067+ span = span. with_lo ( span. lo ( ) + BytePos ( t. len ( ) as _ ) ) ;
9951068 path
9961069 } ) ;
9971070 }
9981071
999- if let Some ( href_context) = href_context {
1000- if let Some ( href) =
1001- href_context. context . shared . span_correspondence_map . get ( & def_span) . and_then ( |href| {
1002- let context = href_context. context ;
1003- // FIXME: later on, it'd be nice to provide two links (if possible) for all items:
1004- // one to the documentation page and one to the source definition.
1005- // FIXME: currently, external items only generate a link to their documentation,
1006- // a link to their definition can be generated using this:
1007- // https://github.com/rust-lang/rust/blob/60f1a2fc4b535ead9c85ce085fdce49b1b097531/src/librustdoc/html/render/context.rs#L315-L338
1008- match href {
1009- LinkFromSrc :: Local ( span) => {
1010- context. href_from_span_relative ( * span, & href_context. current_href )
1011- }
1012- LinkFromSrc :: External ( def_id) => {
1013- format:: href_with_root_path ( * def_id, context, Some ( href_context. root_path ) )
1014- . ok ( )
1015- . map ( |( url, _, _) | url)
1016- }
1017- LinkFromSrc :: Primitive ( prim) => format:: href_with_root_path (
1018- PrimitiveType :: primitive_locations ( context. tcx ( ) ) [ prim] ,
1019- context,
1020- Some ( href_context. root_path ) ,
1021- )
1022- . ok ( )
1023- . map ( |( url, _, _) | url) ,
1024- LinkFromSrc :: Doc ( def_id) => {
1025- format:: href_with_root_path ( * def_id, context, Some ( href_context. root_path ) )
1026- . ok ( )
1027- . map ( |( doc_link, _, _) | doc_link)
1028- }
1029- }
1030- } )
1031- {
1032- if !open_tag {
1033- // We're already inside an element which has the same klass, no need to give it
1034- // again.
1035- write ! ( out, "<a href=\" {href}\" >{text_s}" ) . unwrap ( ) ;
1036- } else {
1037- let klass_s = klass. as_html ( ) ;
1038- if klass_s. is_empty ( ) {
1039- write ! ( out, "<a href=\" {href}\" >{text_s}" ) . unwrap ( ) ;
1040- } else {
1041- write ! ( out, "<a class=\" {klass_s}\" href=\" {href}\" >{text_s}" ) . unwrap ( ) ;
1042- }
1043- }
1044- return Some ( "</a>" ) ;
1045- }
1072+ if !added_links && generate_link_to_def ( out, & text_s, klass, href_context, def_span, open_tag) {
1073+ return Some ( "</a>" ) ;
10461074 }
10471075 if !open_tag {
10481076 write ! ( out, "{}" , text_s) . unwrap ( ) ;
0 commit comments