@@ -22,7 +22,7 @@ use super::format::{self, Buffer};
22
22
use super :: render:: LinkFromSrc ;
23
23
24
24
/// This type is needed in case we want to render links on items to allow to go to their definition.
25
- pub ( crate ) struct ContextInfo < ' a , ' b , ' c > {
25
+ pub ( crate ) struct HrefContext < ' a , ' b , ' c > {
26
26
pub ( crate ) context : & ' a Context < ' b > ,
27
27
/// This span contains the current file we're going through.
28
28
pub ( crate ) file_span : Span ,
@@ -44,7 +44,7 @@ pub(crate) fn render_with_highlighting(
44
44
tooltip : Option < ( Option < Edition > , & str ) > ,
45
45
edition : Edition ,
46
46
extra_content : Option < Buffer > ,
47
- context_info : Option < ContextInfo < ' _ , ' _ , ' _ > > ,
47
+ href_context : Option < HrefContext < ' _ , ' _ , ' _ > > ,
48
48
decoration_info : Option < DecorationInfo > ,
49
49
) {
50
50
debug ! ( "highlighting: ================\n {}\n ==============" , src) ;
@@ -62,7 +62,7 @@ pub(crate) fn render_with_highlighting(
62
62
}
63
63
64
64
write_header ( out, class, extra_content) ;
65
- write_code ( out, src, edition, context_info , decoration_info) ;
65
+ write_code ( out, src, edition, href_context , decoration_info) ;
66
66
write_footer ( out, playground_button) ;
67
67
}
68
68
@@ -85,31 +85,36 @@ fn write_header(out: &mut Buffer, class: Option<&str>, extra_content: Option<Buf
85
85
///
86
86
/// Some explanations on the last arguments:
87
87
///
88
- /// In case we are rendering a code block and not a source code file, `context_info ` will be `None`.
89
- /// To put it more simply: if `context_info ` is `None`, the code won't try to generate links to an
88
+ /// In case we are rendering a code block and not a source code file, `href_context ` will be `None`.
89
+ /// To put it more simply: if `href_context ` is `None`, the code won't try to generate links to an
90
90
/// item definition.
91
91
///
92
92
/// More explanations about spans and how we use them here are provided in the
93
93
fn write_code (
94
94
out : & mut Buffer ,
95
95
src : & str ,
96
96
edition : Edition ,
97
- context_info : Option < ContextInfo < ' _ , ' _ , ' _ > > ,
97
+ href_context : Option < HrefContext < ' _ , ' _ , ' _ > > ,
98
98
decoration_info : Option < DecorationInfo > ,
99
99
) {
100
100
// This replace allows to fix how the code source with DOS backline characters is displayed.
101
101
let src = src. replace ( "\r \n " , "\n " ) ;
102
+ let mut closing_tags: Vec < & ' static str > = Vec :: new ( ) ;
102
103
Classifier :: new (
103
104
& src,
104
105
edition,
105
- context_info . as_ref ( ) . map ( |c| c. file_span ) . unwrap_or ( DUMMY_SP ) ,
106
+ href_context . as_ref ( ) . map ( |c| c. file_span ) . unwrap_or ( DUMMY_SP ) ,
106
107
decoration_info,
107
108
)
108
109
. highlight ( & mut |highlight| {
109
110
match highlight {
110
- Highlight :: Token { text, class } => string ( out, Escape ( text) , class, & context_info) ,
111
- Highlight :: EnterSpan { class } => enter_span ( out, class) ,
112
- Highlight :: ExitSpan => exit_span ( out) ,
111
+ Highlight :: Token { text, class } => string ( out, Escape ( text) , class, & href_context) ,
112
+ Highlight :: EnterSpan { class } => {
113
+ closing_tags. push ( enter_span ( out, class, & href_context) )
114
+ }
115
+ Highlight :: ExitSpan => {
116
+ exit_span ( out, closing_tags. pop ( ) . expect ( "ExitSpan without EnterSpan" ) )
117
+ }
113
118
} ;
114
119
} ) ;
115
120
}
@@ -129,7 +134,7 @@ enum Class {
129
134
RefKeyWord ,
130
135
Self_ ( Span ) ,
131
136
Op ,
132
- Macro ,
137
+ Macro ( Span ) ,
133
138
MacroNonTerminal ,
134
139
String ,
135
140
Number ,
@@ -153,7 +158,7 @@ impl Class {
153
158
Class :: RefKeyWord => "kw-2" ,
154
159
Class :: Self_ ( _) => "self" ,
155
160
Class :: Op => "op" ,
156
- Class :: Macro => "macro" ,
161
+ Class :: Macro ( _ ) => "macro" ,
157
162
Class :: MacroNonTerminal => "macro-nonterminal" ,
158
163
Class :: String => "string" ,
159
164
Class :: Number => "number" ,
@@ -171,8 +176,22 @@ impl Class {
171
176
/// a "span" (a tuple representing `(lo, hi)` equivalent of `Span`).
172
177
fn get_span ( self ) -> Option < Span > {
173
178
match self {
174
- Self :: Ident ( sp) | Self :: Self_ ( sp) => Some ( sp) ,
175
- _ => None ,
179
+ Self :: Ident ( sp) | Self :: Self_ ( sp) | Self :: Macro ( sp) => Some ( sp) ,
180
+ Self :: Comment
181
+ | Self :: DocComment
182
+ | Self :: Attribute
183
+ | Self :: KeyWord
184
+ | Self :: RefKeyWord
185
+ | Self :: Op
186
+ | Self :: MacroNonTerminal
187
+ | Self :: String
188
+ | Self :: Number
189
+ | Self :: Bool
190
+ | Self :: Lifetime
191
+ | Self :: PreludeTy
192
+ | Self :: PreludeVal
193
+ | Self :: QuestionMark
194
+ | Self :: Decoration ( _) => None ,
176
195
}
177
196
}
178
197
}
@@ -611,7 +630,7 @@ impl<'a> Classifier<'a> {
611
630
} ,
612
631
TokenKind :: Ident | TokenKind :: RawIdent if lookahead == Some ( TokenKind :: Bang ) => {
613
632
self . in_macro = true ;
614
- sink ( Highlight :: EnterSpan { class : Class :: Macro } ) ;
633
+ sink ( Highlight :: EnterSpan { class : Class :: Macro ( self . new_span ( before , text ) ) } ) ;
615
634
sink ( Highlight :: Token { text, class : None } ) ;
616
635
return ;
617
636
}
@@ -658,13 +677,20 @@ impl<'a> Classifier<'a> {
658
677
659
678
/// Called when we start processing a span of text that should be highlighted.
660
679
/// The `Class` argument specifies how it should be highlighted.
661
- fn enter_span ( out : & mut Buffer , klass : Class ) {
662
- write ! ( out, "<span class=\" {}\" >" , klass. as_html( ) ) ;
680
+ fn enter_span (
681
+ out : & mut Buffer ,
682
+ klass : Class ,
683
+ href_context : & Option < HrefContext < ' _ , ' _ , ' _ > > ,
684
+ ) -> & ' static str {
685
+ string_without_closing_tag ( out, "" , Some ( klass) , href_context) . expect (
686
+ "internal error: enter_span was called with Some(klass) but did not return a \
687
+ closing HTML tag",
688
+ )
663
689
}
664
690
665
691
/// Called at the end of a span of highlighted text.
666
- fn exit_span ( out : & mut Buffer ) {
667
- out. write_str ( "</span>" ) ;
692
+ fn exit_span ( out : & mut Buffer , closing_tag : & str ) {
693
+ out. write_str ( closing_tag ) ;
668
694
}
669
695
670
696
/// Called for a span of text. If the text should be highlighted differently
@@ -687,15 +713,39 @@ fn string<T: Display>(
687
713
out : & mut Buffer ,
688
714
text : T ,
689
715
klass : Option < Class > ,
690
- context_info : & Option < ContextInfo < ' _ , ' _ , ' _ > > ,
716
+ href_context : & Option < HrefContext < ' _ , ' _ , ' _ > > ,
691
717
) {
718
+ if let Some ( closing_tag) = string_without_closing_tag ( out, text, klass, href_context) {
719
+ out. write_str ( closing_tag) ;
720
+ }
721
+ }
722
+
723
+ /// This function writes `text` into `out` with some modifications depending on `klass`:
724
+ ///
725
+ /// * If `klass` is `None`, `text` is written into `out` with no modification.
726
+ /// * If `klass` is `Some` but `klass.get_span()` is `None`, it writes the text wrapped in a
727
+ /// `<span>` with the provided `klass`.
728
+ /// * If `klass` is `Some` and has a [`rustc_span::Span`], it then tries to generate a link (`<a>`
729
+ /// element) by retrieving the link information from the `span_correspondance_map` that was filled
730
+ /// in `span_map.rs::collect_spans_and_sources`. If it cannot retrieve the information, then it's
731
+ /// the same as the second point (`klass` is `Some` but doesn't have a [`rustc_span::Span`]).
732
+ fn string_without_closing_tag < T : Display > (
733
+ out : & mut Buffer ,
734
+ text : T ,
735
+ klass : Option < Class > ,
736
+ href_context : & Option < HrefContext < ' _ , ' _ , ' _ > > ,
737
+ ) -> Option < & ' static str > {
692
738
let Some ( klass) = klass
693
- else { return write ! ( out, "{}" , text) } ;
739
+ else {
740
+ write ! ( out, "{}" , text) ;
741
+ return None ;
742
+ } ;
694
743
let Some ( def_span) = klass. get_span ( )
695
744
else {
696
- write ! ( out, "<span class=\" {}\" >{}</span> " , klass. as_html( ) , text) ;
697
- return ;
745
+ write ! ( out, "<span class=\" {}\" >{}" , klass. as_html( ) , text) ;
746
+ return Some ( "</span>" ) ;
698
747
} ;
748
+
699
749
let mut text_s = text. to_string ( ) ;
700
750
if text_s. contains ( "::" ) {
701
751
text_s = text_s. split ( "::" ) . intersperse ( "::" ) . fold ( String :: new ( ) , |mut path, t| {
@@ -715,10 +765,10 @@ fn string<T: Display>(
715
765
path
716
766
} ) ;
717
767
}
718
- if let Some ( context_info ) = context_info {
768
+ if let Some ( href_context ) = href_context {
719
769
if let Some ( href) =
720
- context_info . context . shared . span_correspondance_map . get ( & def_span) . and_then ( |href| {
721
- let context = context_info . context ;
770
+ href_context . context . shared . span_correspondance_map . get ( & def_span) . and_then ( |href| {
771
+ let context = href_context . context ;
722
772
// FIXME: later on, it'd be nice to provide two links (if possible) for all items:
723
773
// one to the documentation page and one to the source definition.
724
774
// FIXME: currently, external items only generate a link to their documentation,
@@ -727,27 +777,28 @@ fn string<T: Display>(
727
777
match href {
728
778
LinkFromSrc :: Local ( span) => context
729
779
. href_from_span ( * span, true )
730
- . map ( |s| format ! ( "{}{}" , context_info . root_path, s) ) ,
780
+ . map ( |s| format ! ( "{}{}" , href_context . root_path, s) ) ,
731
781
LinkFromSrc :: External ( def_id) => {
732
- format:: href_with_root_path ( * def_id, context, Some ( context_info . root_path ) )
782
+ format:: href_with_root_path ( * def_id, context, Some ( href_context . root_path ) )
733
783
. ok ( )
734
784
. map ( |( url, _, _) | url)
735
785
}
736
786
LinkFromSrc :: Primitive ( prim) => format:: href_with_root_path (
737
787
PrimitiveType :: primitive_locations ( context. tcx ( ) ) [ prim] ,
738
788
context,
739
- Some ( context_info . root_path ) ,
789
+ Some ( href_context . root_path ) ,
740
790
)
741
791
. ok ( )
742
792
. map ( |( url, _, _) | url) ,
743
793
}
744
794
} )
745
795
{
746
- write ! ( out, "<a class=\" {}\" href=\" {}\" >{}</a> " , klass. as_html( ) , href, text_s) ;
747
- return ;
796
+ write ! ( out, "<a class=\" {}\" href=\" {}\" >{}" , klass. as_html( ) , href, text_s) ;
797
+ return Some ( "</a>" ) ;
748
798
}
749
799
}
750
- write ! ( out, "<span class=\" {}\" >{}</span>" , klass. as_html( ) , text_s) ;
800
+ write ! ( out, "<span class=\" {}\" >{}" , klass. as_html( ) , text_s) ;
801
+ Some ( "</span>" )
751
802
}
752
803
753
804
#[ cfg( test) ]
0 commit comments