@@ -103,7 +103,7 @@ fn write_code(
103
103
) {
104
104
// This replace allows to fix how the code source with DOS backline characters is displayed.
105
105
let src = src. replace ( "\r \n " , "\n " ) ;
106
- let mut closing_tag = "" ;
106
+ let mut closing_tags : Vec < & ' static str > = Vec :: new ( ) ;
107
107
Classifier :: new (
108
108
& src,
109
109
edition,
@@ -113,8 +113,12 @@ fn write_code(
113
113
. highlight ( & mut |highlight| {
114
114
match highlight {
115
115
Highlight :: Token { text, class } => string ( out, Escape ( text) , class, & href_context) ,
116
- Highlight :: EnterSpan { class } => closing_tag = enter_span ( out, class, & href_context) ,
117
- Highlight :: ExitSpan => exit_span ( out, & closing_tag) ,
116
+ Highlight :: EnterSpan { class } => {
117
+ closing_tags. push ( enter_span ( out, class, & href_context) )
118
+ }
119
+ Highlight :: ExitSpan => {
120
+ exit_span ( out, closing_tags. pop ( ) . expect ( "ExitSpan without EnterSpan" ) )
121
+ }
118
122
} ;
119
123
} ) ;
120
124
}
@@ -682,8 +686,10 @@ fn enter_span(
682
686
klass : Class ,
683
687
href_context : & Option < HrefContext < ' _ , ' _ , ' _ > > ,
684
688
) -> & ' static str {
685
- string_without_closing_tag ( out, "" , Some ( klass) , href_context)
686
- . expect ( "no closing tag to close wrapper..." )
689
+ string_without_closing_tag ( out, "" , Some ( klass) , href_context) . expect (
690
+ "internal error: enter_span was called with Some(klass) but did not return a \
691
+ closing HTML tag",
692
+ )
687
693
}
688
694
689
695
/// Called at the end of a span of highlighted text.
@@ -718,6 +724,15 @@ fn string<T: Display>(
718
724
}
719
725
}
720
726
727
+ /// This function writes `text` into `out` with some modifications depending on `klass`:
728
+ ///
729
+ /// * If `klass` is `None`, `text` is written into `out` with no modification.
730
+ /// * If `klass` is `Some` but `klass.get_span()` is `None`, it writes the text wrapped in a
731
+ /// `<span>` with the provided `klass`.
732
+ /// * If `klass` is `Some` and has a [`rustc_span::Span`], it then tries to generate a link (`<a>`
733
+ /// element) by retrieving the link information from the `span_correspondance_map` that was filled
734
+ /// in `span_map.rs::collect_spans_and_sources`. If it cannot retrieve the information, then it's
735
+ /// the same as the second point (`klass` is `Some` but doesn't have a [`rustc_span::Span`]).
721
736
fn string_without_closing_tag < T : Display > (
722
737
out : & mut Buffer ,
723
738
text : T ,
@@ -799,42 +814,55 @@ fn string_without_closing_tag<T: Display>(
799
814
Some ( "</span>" )
800
815
}
801
816
802
- /// This function is to get the external macro path because they are not in the cache used n
817
+ /// This function is to get the external macro path because they are not in the cache used in
803
818
/// `href_with_root_path`.
804
819
fn generate_macro_def_id_path ( href_context : & HrefContext < ' _ , ' _ , ' _ > , def_id : DefId ) -> String {
805
820
let tcx = href_context. context . shared . tcx ;
806
821
let crate_name = tcx. crate_name ( def_id. krate ) . to_string ( ) ;
807
- let cache = & href_context. context . cache ( ) ;
822
+ let cache = href_context. context . cache ( ) ;
808
823
809
824
let relative = tcx. def_path ( def_id) . data . into_iter ( ) . filter_map ( |elem| {
810
825
// extern blocks have an empty name
811
826
let s = elem. data . to_string ( ) ;
812
827
if !s. is_empty ( ) { Some ( s) } else { None }
813
828
} ) ;
814
- // Check to see if it is a macro 2.0 or built-in macro
815
- let mut path = if matches ! (
816
- CStore :: from_tcx( tcx) . load_macro_untracked( def_id, tcx. sess) ,
817
- LoadedMacro :: MacroDef ( def, _)
818
- if matches!( & def. kind, ast:: ItemKind :: MacroDef ( ast_def)
819
- if !ast_def. macro_rules)
820
- ) {
829
+ // Check to see if it is a macro 2.0 or built-in macro.
830
+ // More information in <https://rust-lang.github.io/rfcs/1584-macros.html>.
831
+ let is_macro_2 = match CStore :: from_tcx ( tcx) . load_macro_untracked ( def_id, tcx. sess ) {
832
+ LoadedMacro :: MacroDef ( def, _) => {
833
+ // If `ast_def.macro_rules` is `true`, then it's not a macro 2.0.
834
+ matches ! ( & def. kind, ast:: ItemKind :: MacroDef ( ast_def) if !ast_def. macro_rules)
835
+ }
836
+ _ => false ,
837
+ } ;
838
+
839
+ let mut path = if is_macro_2 {
821
840
once ( crate_name. clone ( ) ) . chain ( relative) . collect ( )
822
841
} else {
823
- vec ! [ crate_name. clone( ) , relative. last( ) . expect ( "relative was empty" ) ]
842
+ vec ! [ crate_name. clone( ) , relative. last( ) . unwrap ( ) ]
824
843
} ;
844
+ if path. len ( ) < 2 {
845
+ // The minimum we can have is the crate name followed by the macro name. If shorter, then
846
+ // it means that that `relative` was empty, which is an error.
847
+ panic ! ( "macro path cannot be empty!" ) ;
848
+ }
825
849
826
- let url_parts = match cache. extern_locations [ & def_id. krate ] {
827
- ExternalLocation :: Remote ( ref s) => vec ! [ s. trim_end_matches( '/' ) ] ,
828
- ExternalLocation :: Local => vec ! [ href_context. root_path. trim_end_matches( '/' ) , & crate_name] ,
829
- ExternalLocation :: Unknown => panic ! ( "unknown crate" ) ,
830
- } ;
850
+ if let Some ( last) = path. last_mut ( ) {
851
+ * last = format ! ( "macro.{}.html" , last) ;
852
+ }
831
853
832
- let last = path. pop ( ) . unwrap ( ) ;
833
- let last = format ! ( "macro.{}.html" , last) ;
834
- if path. is_empty ( ) {
835
- format ! ( "{}/{}" , url_parts. join( "/" ) , last)
836
- } else {
837
- format ! ( "{}/{}/{}" , url_parts. join( "/" ) , path. join( "/" ) , last)
854
+ match cache. extern_locations [ & def_id. krate ] {
855
+ ExternalLocation :: Remote ( ref s) => {
856
+ // `ExternalLocation::Remote` always end with a `/`.
857
+ format ! ( "{}{}" , s, path. join( "/" ) )
858
+ }
859
+ ExternalLocation :: Local => {
860
+ // `href_context.root_path` always end with a `/`.
861
+ format ! ( "{}{}/{}" , href_context. root_path, crate_name, path. join( "/" ) )
862
+ }
863
+ ExternalLocation :: Unknown => {
864
+ panic ! ( "crate {} not in cache when linkifying macros" , crate_name)
865
+ }
838
866
}
839
867
}
840
868
0 commit comments