@@ -22,7 +22,7 @@ use super::format::{self, Buffer};
2222use super :: render:: LinkFromSrc ;
2323
2424/// 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 > {
2626 pub ( crate ) context : & ' a Context < ' b > ,
2727 /// This span contains the current file we're going through.
2828 pub ( crate ) file_span : Span ,
@@ -44,7 +44,7 @@ pub(crate) fn render_with_highlighting(
4444 tooltip : Option < ( Option < Edition > , & str ) > ,
4545 edition : Edition ,
4646 extra_content : Option < Buffer > ,
47- context_info : Option < ContextInfo < ' _ , ' _ , ' _ > > ,
47+ href_context : Option < HrefContext < ' _ , ' _ , ' _ > > ,
4848 decoration_info : Option < DecorationInfo > ,
4949) {
5050 debug ! ( "highlighting: ================\n {}\n ==============" , src) ;
@@ -62,7 +62,7 @@ pub(crate) fn render_with_highlighting(
6262 }
6363
6464 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) ;
6666 write_footer ( out, playground_button) ;
6767}
6868
@@ -85,31 +85,36 @@ fn write_header(out: &mut Buffer, class: Option<&str>, extra_content: Option<Buf
8585///
8686/// Some explanations on the last arguments:
8787///
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
9090/// item definition.
9191///
9292/// More explanations about spans and how we use them here are provided in the
9393fn write_code (
9494 out : & mut Buffer ,
9595 src : & str ,
9696 edition : Edition ,
97- context_info : Option < ContextInfo < ' _ , ' _ , ' _ > > ,
97+ href_context : Option < HrefContext < ' _ , ' _ , ' _ > > ,
9898 decoration_info : Option < DecorationInfo > ,
9999) {
100100 // This replace allows to fix how the code source with DOS backline characters is displayed.
101101 let src = src. replace ( "\r \n " , "\n " ) ;
102+ let mut closing_tags: Vec < & ' static str > = Vec :: new ( ) ;
102103 Classifier :: new (
103104 & src,
104105 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 ) ,
106107 decoration_info,
107108 )
108109 . highlight ( & mut |highlight| {
109110 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+ }
113118 } ;
114119 } ) ;
115120}
@@ -129,7 +134,7 @@ enum Class {
129134 RefKeyWord ,
130135 Self_ ( Span ) ,
131136 Op ,
132- Macro ,
137+ Macro ( Span ) ,
133138 MacroNonTerminal ,
134139 String ,
135140 Number ,
@@ -153,7 +158,7 @@ impl Class {
153158 Class :: RefKeyWord => "kw-2" ,
154159 Class :: Self_ ( _) => "self" ,
155160 Class :: Op => "op" ,
156- Class :: Macro => "macro" ,
161+ Class :: Macro ( _ ) => "macro" ,
157162 Class :: MacroNonTerminal => "macro-nonterminal" ,
158163 Class :: String => "string" ,
159164 Class :: Number => "number" ,
@@ -171,8 +176,22 @@ impl Class {
171176 /// a "span" (a tuple representing `(lo, hi)` equivalent of `Span`).
172177 fn get_span ( self ) -> Option < Span > {
173178 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 ,
176195 }
177196 }
178197}
@@ -611,7 +630,7 @@ impl<'a> Classifier<'a> {
611630 } ,
612631 TokenKind :: Ident | TokenKind :: RawIdent if lookahead == Some ( TokenKind :: Bang ) => {
613632 self . in_macro = true ;
614- sink ( Highlight :: EnterSpan { class : Class :: Macro } ) ;
633+ sink ( Highlight :: EnterSpan { class : Class :: Macro ( self . new_span ( before , text ) ) } ) ;
615634 sink ( Highlight :: Token { text, class : None } ) ;
616635 return ;
617636 }
@@ -658,13 +677,20 @@ impl<'a> Classifier<'a> {
658677
659678/// Called when we start processing a span of text that should be highlighted.
660679/// 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+ )
663689}
664690
665691/// 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 ) ;
668694}
669695
670696/// Called for a span of text. If the text should be highlighted differently
@@ -687,15 +713,39 @@ fn string<T: Display>(
687713 out : & mut Buffer ,
688714 text : T ,
689715 klass : Option < Class > ,
690- context_info : & Option < ContextInfo < ' _ , ' _ , ' _ > > ,
716+ href_context : & Option < HrefContext < ' _ , ' _ , ' _ > > ,
691717) {
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 > {
692738 let Some ( klass) = klass
693- else { return write ! ( out, "{}" , text) } ;
739+ else {
740+ write ! ( out, "{}" , text) ;
741+ return None ;
742+ } ;
694743 let Some ( def_span) = klass. get_span ( )
695744 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>" ) ;
698747 } ;
748+
699749 let mut text_s = text. to_string ( ) ;
700750 if text_s. contains ( "::" ) {
701751 text_s = text_s. split ( "::" ) . intersperse ( "::" ) . fold ( String :: new ( ) , |mut path, t| {
@@ -715,10 +765,10 @@ fn string<T: Display>(
715765 path
716766 } ) ;
717767 }
718- if let Some ( context_info ) = context_info {
768+ if let Some ( href_context ) = href_context {
719769 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 ;
722772 // FIXME: later on, it'd be nice to provide two links (if possible) for all items:
723773 // one to the documentation page and one to the source definition.
724774 // FIXME: currently, external items only generate a link to their documentation,
@@ -727,27 +777,28 @@ fn string<T: Display>(
727777 match href {
728778 LinkFromSrc :: Local ( span) => context
729779 . href_from_span ( * span, true )
730- . map ( |s| format ! ( "{}{}" , context_info . root_path, s) ) ,
780+ . map ( |s| format ! ( "{}{}" , href_context . root_path, s) ) ,
731781 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 ) )
733783 . ok ( )
734784 . map ( |( url, _, _) | url)
735785 }
736786 LinkFromSrc :: Primitive ( prim) => format:: href_with_root_path (
737787 PrimitiveType :: primitive_locations ( context. tcx ( ) ) [ prim] ,
738788 context,
739- Some ( context_info . root_path ) ,
789+ Some ( href_context . root_path ) ,
740790 )
741791 . ok ( )
742792 . map ( |( url, _, _) | url) ,
743793 }
744794 } )
745795 {
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>" ) ;
748798 }
749799 }
750- write ! ( out, "<span class=\" {}\" >{}</span>" , klass. as_html( ) , text_s) ;
800+ write ! ( out, "<span class=\" {}\" >{}" , klass. as_html( ) , text_s) ;
801+ Some ( "</span>" )
751802}
752803
753804#[ cfg( test) ]
0 commit comments