@@ -12,15 +12,17 @@ use std::io;
12
12
use std:: io:: prelude:: * ;
13
13
14
14
use rustc_ast:: token:: { self , Token } ;
15
+ use rustc_data_structures:: sync:: Lrc ;
15
16
use rustc_parse:: lexer;
16
17
use rustc_session:: parse:: ParseSess ;
18
+ use rustc_span:: hygiene:: SyntaxContext ;
17
19
use rustc_span:: source_map:: SourceMap ;
18
20
use rustc_span:: symbol:: { kw, sym} ;
19
- use rustc_span:: { FileName , Span } ;
21
+ use rustc_span:: { BytePos , FileName , SourceFile , Span } ;
20
22
21
23
/// Highlights `src`, returning the HTML output.
22
24
pub fn render_with_highlighting (
23
- src : & str ,
25
+ src : String ,
24
26
class : Option < & str > ,
25
27
playground_button : Option < & str > ,
26
28
tooltip : Option < ( & str , & str ) > ,
@@ -38,12 +40,13 @@ pub fn render_with_highlighting(
38
40
}
39
41
40
42
let sess = ParseSess :: with_silent_emitter ( ) ;
41
- let sf = sess
43
+ let source_file = sess
42
44
. source_map ( )
43
- . new_source_file ( FileName :: Custom ( String :: from ( "rustdoc-highlighting" ) ) , src. to_owned ( ) ) ;
45
+ . new_source_file ( FileName :: Custom ( String :: from ( "rustdoc-highlighting" ) ) , src) ;
46
+
47
+ let classifier_source_file = Lrc :: clone ( & source_file) ;
44
48
let highlight_result = rustc_driver:: catch_fatal_errors ( || {
45
- let lexer = lexer:: StringReader :: new ( & sess, sf, None ) ;
46
- let mut classifier = Classifier :: new ( lexer, sess. source_map ( ) ) ;
49
+ let mut classifier = Classifier :: new ( & sess, classifier_source_file) ;
47
50
48
51
let mut highlighted_source = vec ! [ ] ;
49
52
if classifier. write_source ( & mut highlighted_source) . is_err ( ) {
@@ -61,9 +64,17 @@ pub fn render_with_highlighting(
61
64
write_footer ( & mut out, playground_button) . unwrap ( ) ;
62
65
}
63
66
Err ( ( ) ) => {
67
+ // Get the source back out of the source map to avoid a copy in the happy path.
68
+ let span =
69
+ Span :: new ( BytePos ( 0 ) , BytePos ( source_file. byte_length ( ) ) , SyntaxContext :: root ( ) ) ;
70
+ let src = sess
71
+ . source_map ( )
72
+ . span_to_snippet ( span)
73
+ . expect ( "could not retrieve snippet from artificial source file" ) ;
74
+
64
75
// If errors are encountered while trying to highlight, just emit
65
76
// the unhighlighted source.
66
- write ! ( out, "<pre><code>{}</code></pre>" , Escape ( src) ) . unwrap ( ) ;
77
+ write ! ( out, "<pre><code>{}</code></pre>" , Escape ( & src) ) . unwrap ( ) ;
67
78
}
68
79
}
69
80
@@ -73,10 +84,10 @@ pub fn render_with_highlighting(
73
84
/// Processes a program (nested in the internal `lexer`), classifying strings of
74
85
/// text by highlighting category (`Class`). Calls out to a `Writer` to write
75
86
/// each span of text in sequence.
76
- struct Classifier < ' a > {
77
- lexer : lexer:: StringReader < ' a > ,
87
+ struct Classifier < ' sess > {
88
+ lexer : lexer:: StringReader < ' sess > ,
78
89
peek_token : Option < Token > ,
79
- source_map : & ' a SourceMap ,
90
+ source_map : & ' sess SourceMap ,
80
91
81
92
// State of the classifier.
82
93
in_attribute : bool ,
@@ -154,6 +165,7 @@ impl<U: Write> Writer for U {
154
165
}
155
166
}
156
167
168
+ #[ derive( Debug ) ]
157
169
enum HighlightError {
158
170
LexError ,
159
171
IoError ( io:: Error ) ,
@@ -165,12 +177,14 @@ impl From<io::Error> for HighlightError {
165
177
}
166
178
}
167
179
168
- impl < ' a > Classifier < ' a > {
169
- fn new ( lexer : lexer:: StringReader < ' a > , source_map : & ' a SourceMap ) -> Classifier < ' a > {
180
+ impl < ' sess > Classifier < ' sess > {
181
+ fn new ( sess : & ParseSess , source_file : Lrc < SourceFile > ) -> Classifier < ' _ > {
182
+ let lexer = lexer:: StringReader :: new ( sess, source_file, None ) ;
183
+
170
184
Classifier {
171
185
lexer,
172
186
peek_token : None ,
173
- source_map,
187
+ source_map : sess . source_map ( ) ,
174
188
in_attribute : false ,
175
189
in_macro : false ,
176
190
in_macro_nonterminal : false ,
@@ -209,11 +223,17 @@ impl<'a> Classifier<'a> {
209
223
/// source.
210
224
fn write_source < W : Writer > ( & mut self , out : & mut W ) -> Result < ( ) , HighlightError > {
211
225
loop {
212
- let next = self . try_next_token ( ) ?;
226
+ let mut next = self . try_next_token ( ) ?;
213
227
if next == token:: Eof {
214
228
break ;
215
229
}
216
230
231
+ // Glue any tokens that need to be glued.
232
+ if let Some ( joint) = next. glue ( self . peek ( ) ?) {
233
+ next = joint;
234
+ let _ = self . try_next_token ( ) ?;
235
+ }
236
+
217
237
self . write_token ( out, next) ?;
218
238
}
219
239
@@ -429,3 +449,6 @@ fn write_header(class: Option<&str>, out: &mut dyn Write) -> io::Result<()> {
429
449
fn write_footer ( out : & mut dyn Write , playground_button : Option < & str > ) -> io:: Result < ( ) > {
430
450
write ! ( out, "</pre>{}</div>\n " , if let Some ( button) = playground_button { button } else { "" } )
431
451
}
452
+
453
+ #[ cfg( test) ]
454
+ mod tests;
0 commit comments