8
8
use crate :: emitter:: FileWithAnnotatedLines ;
9
9
use crate :: snippet:: Line ;
10
10
use crate :: { CodeSuggestion , Diagnostic , DiagnosticId , Emitter , Level , SubDiagnostic } ;
11
- use annotate_snippets:: display_list:: DisplayList ;
12
- use annotate_snippets:: formatter:: DisplayListFormatter ;
11
+ use annotate_snippets:: display_list:: { DisplayList , FormatOptions } ;
13
12
use annotate_snippets:: snippet:: * ;
14
13
use rustc_data_structures:: sync:: Lrc ;
15
14
use rustc_span:: source_map:: SourceMap ;
16
- use rustc_span:: { Loc , MultiSpan , SourceFile } ;
15
+ use rustc_span:: { MultiSpan , SourceFile } ;
17
16
18
17
/// Generates diagnostics using annotate-snippet
19
18
pub struct AnnotateSnippetEmitterWriter {
@@ -59,112 +58,20 @@ impl Emitter for AnnotateSnippetEmitterWriter {
59
58
}
60
59
}
61
60
62
- /// Collects all the data needed to generate the data structures needed for the
63
- /// `annotate-snippets` library.
64
- struct DiagnosticConverter < ' a > {
65
- source_map : Option < Lrc < SourceMap > > ,
66
- level : Level ,
67
- message : String ,
68
- code : Option < DiagnosticId > ,
69
- msp : MultiSpan ,
70
- #[ allow( dead_code) ]
71
- children : & ' a [ SubDiagnostic ] ,
72
- #[ allow( dead_code) ]
73
- suggestions : & ' a [ CodeSuggestion ] ,
61
+ /// Provides the source string for the given `line` of `file`
62
+ fn source_string ( file : Lrc < SourceFile > , line : & Line ) -> String {
63
+ file. get_line ( line. line_index - 1 ) . map ( |a| a. to_string ( ) ) . unwrap_or_default ( )
74
64
}
75
65
76
- impl < ' a > DiagnosticConverter < ' a > {
77
- /// Turns rustc Diagnostic information into a `annotate_snippets::snippet::Snippet`.
78
- fn to_annotation_snippet ( & self ) -> Option < Snippet > {
79
- if let Some ( source_map) = & self . source_map {
80
- // Make sure our primary file comes first
81
- let primary_lo = if let Some ( ref primary_span) = self . msp . primary_span ( ) . as_ref ( ) {
82
- source_map. lookup_char_pos ( primary_span. lo ( ) )
83
- } else {
84
- // FIXME(#59346): Not sure when this is the case and what
85
- // should be done if it happens
86
- return None ;
87
- } ;
88
- let annotated_files =
89
- FileWithAnnotatedLines :: collect_annotations ( & self . msp , & self . source_map ) ;
90
- let slices = self . slices_for_files ( annotated_files, primary_lo) ;
91
-
92
- Some ( Snippet {
93
- title : Some ( Annotation {
94
- label : Some ( self . message . to_string ( ) ) ,
95
- id : self . code . clone ( ) . map ( |c| match c {
96
- DiagnosticId :: Error ( val) | DiagnosticId :: Lint ( val) => val,
97
- } ) ,
98
- annotation_type : Self :: annotation_type_for_level ( self . level ) ,
99
- } ) ,
100
- footer : vec ! [ ] ,
101
- slices,
102
- } )
103
- } else {
104
- // FIXME(#59346): Is it ok to return None if there's no source_map?
105
- None
106
- }
107
- }
108
-
109
- fn slices_for_files (
110
- & self ,
111
- annotated_files : Vec < FileWithAnnotatedLines > ,
112
- primary_lo : Loc ,
113
- ) -> Vec < Slice > {
114
- // FIXME(#64205): Provide a test case where `annotated_files` is > 1
115
- annotated_files
116
- . iter ( )
117
- . flat_map ( |annotated_file| {
118
- annotated_file
119
- . lines
120
- . iter ( )
121
- . map ( |line| {
122
- let line_source = Self :: source_string ( annotated_file. file . clone ( ) , & line) ;
123
- Slice {
124
- source : line_source,
125
- line_start : line. line_index ,
126
- origin : Some ( primary_lo. file . name . to_string ( ) ) ,
127
- // FIXME(#59346): Not really sure when `fold` should be true or false
128
- fold : false ,
129
- annotations : line
130
- . annotations
131
- . iter ( )
132
- . map ( |a| self . annotation_to_source_annotation ( a. clone ( ) ) )
133
- . collect ( ) ,
134
- }
135
- } )
136
- . collect :: < Vec < Slice > > ( )
137
- } )
138
- . collect :: < Vec < Slice > > ( )
139
- }
140
-
141
- /// Turns a `crate::snippet::Annotation` into a `SourceAnnotation`
142
- fn annotation_to_source_annotation (
143
- & self ,
144
- annotation : crate :: snippet:: Annotation ,
145
- ) -> SourceAnnotation {
146
- SourceAnnotation {
147
- range : ( annotation. start_col , annotation. end_col ) ,
148
- label : annotation. label . unwrap_or ( "" . to_string ( ) ) ,
149
- annotation_type : Self :: annotation_type_for_level ( self . level ) ,
150
- }
151
- }
152
-
153
- /// Provides the source string for the given `line` of `file`
154
- fn source_string ( file : Lrc < SourceFile > , line : & Line ) -> String {
155
- file. get_line ( line. line_index - 1 ) . map ( |a| a. to_string ( ) ) . unwrap_or ( String :: new ( ) )
156
- }
157
-
158
- /// Maps `Diagnostic::Level` to `snippet::AnnotationType`
159
- fn annotation_type_for_level ( level : Level ) -> AnnotationType {
160
- match level {
161
- Level :: Bug | Level :: Fatal | Level :: Error => AnnotationType :: Error ,
162
- Level :: Warning => AnnotationType :: Warning ,
163
- Level :: Note => AnnotationType :: Note ,
164
- Level :: Help => AnnotationType :: Help ,
165
- // FIXME(#59346): Not sure how to map these two levels
166
- Level :: Cancelled | Level :: FailureNote => AnnotationType :: Error ,
167
- }
66
+ /// Maps `Diagnostic::Level` to `snippet::AnnotationType`
67
+ fn annotation_type_for_level ( level : Level ) -> AnnotationType {
68
+ match level {
69
+ Level :: Bug | Level :: Fatal | Level :: Error => AnnotationType :: Error ,
70
+ Level :: Warning => AnnotationType :: Warning ,
71
+ Level :: Note => AnnotationType :: Note ,
72
+ Level :: Help => AnnotationType :: Help ,
73
+ // FIXME(#59346): Not sure how to map these two levels
74
+ Level :: Cancelled | Level :: FailureNote => AnnotationType :: Error ,
168
75
}
169
76
}
170
77
@@ -191,25 +98,87 @@ impl AnnotateSnippetEmitterWriter {
191
98
message : String ,
192
99
code : & Option < DiagnosticId > ,
193
100
msp : & MultiSpan ,
194
- children : & [ SubDiagnostic ] ,
195
- suggestions : & [ CodeSuggestion ] ,
101
+ _children : & [ SubDiagnostic ] ,
102
+ _suggestions : & [ CodeSuggestion ] ,
196
103
) {
197
- let converter = DiagnosticConverter {
198
- source_map : self . source_map . clone ( ) ,
199
- level : * level,
200
- message,
201
- code : code. clone ( ) ,
202
- msp : msp. clone ( ) ,
203
- children,
204
- suggestions,
205
- } ;
206
- if let Some ( snippet) = converter. to_annotation_snippet ( ) {
207
- let dl = DisplayList :: from ( snippet) ;
208
- let dlf = DisplayListFormatter :: new ( true , self . ui_testing ) ;
104
+ if let Some ( source_map) = & self . source_map {
105
+ // Make sure our primary file comes first
106
+ let primary_lo = if let Some ( ref primary_span) = msp. primary_span ( ) . as_ref ( ) {
107
+ if primary_span. is_dummy ( ) {
108
+ // FIXME(#59346): Not sure when this is the case and what
109
+ // should be done if it happens
110
+ return ;
111
+ } else {
112
+ source_map. lookup_char_pos ( primary_span. lo ( ) )
113
+ }
114
+ } else {
115
+ // FIXME(#59346): Not sure when this is the case and what
116
+ // should be done if it happens
117
+ return ;
118
+ } ;
119
+ let mut annotated_files =
120
+ FileWithAnnotatedLines :: collect_annotations ( msp, & self . source_map ) ;
121
+ if let Ok ( pos) =
122
+ annotated_files. binary_search_by ( |x| x. file . name . cmp ( & primary_lo. file . name ) )
123
+ {
124
+ annotated_files. swap ( 0 , pos) ;
125
+ }
126
+ // owned: line source, line index, annotations
127
+ type Owned = ( String , usize , Vec < crate :: snippet:: Annotation > ) ;
128
+ let origin = primary_lo. file . name . to_string ( ) ;
129
+ let annotated_files: Vec < Owned > = annotated_files
130
+ . into_iter ( )
131
+ . flat_map ( |annotated_file| {
132
+ let file = annotated_file. file ;
133
+ annotated_file
134
+ . lines
135
+ . into_iter ( )
136
+ . map ( |line| {
137
+ ( source_string ( file. clone ( ) , & line) , line. line_index , line. annotations )
138
+ } )
139
+ . collect :: < Vec < Owned > > ( )
140
+ } )
141
+ . collect ( ) ;
142
+ let snippet = Snippet {
143
+ title : Some ( Annotation {
144
+ label : Some ( & message) ,
145
+ id : code. as_ref ( ) . map ( |c| match c {
146
+ DiagnosticId :: Error ( val) | DiagnosticId :: Lint ( val) => val. as_str ( ) ,
147
+ } ) ,
148
+ annotation_type : annotation_type_for_level ( * level) ,
149
+ } ) ,
150
+ footer : vec ! [ ] ,
151
+ opt : FormatOptions { color : true , anonymized_line_numbers : self . ui_testing } ,
152
+ slices : annotated_files
153
+ . iter ( )
154
+ . map ( |( source, line_index, annotations) | {
155
+ Slice {
156
+ source,
157
+ line_start : * line_index,
158
+ origin : Some ( & origin) ,
159
+ // FIXME(#59346): Not really sure when `fold` should be true or false
160
+ fold : false ,
161
+ annotations : annotations
162
+ . into_iter ( )
163
+ . map ( |annotation| SourceAnnotation {
164
+ range : ( annotation. start_col , annotation. end_col ) ,
165
+ label : annotation
166
+ . label
167
+ . as_ref ( )
168
+ . map ( |s| s. as_str ( ) )
169
+ . unwrap_or_default ( ) ,
170
+ annotation_type : annotation_type_for_level ( * level) ,
171
+ } )
172
+ . collect ( ) ,
173
+ }
174
+ } )
175
+ . collect ( ) ,
176
+ } ;
209
177
// FIXME(#59346): Figure out if we can _always_ print to stderr or not.
210
178
// `emitter.rs` has the `Destination` enum that lists various possible output
211
179
// destinations.
212
- eprintln ! ( "{}" , dlf. format( & dl) ) ;
213
- } ;
180
+ eprintln ! ( "{}" , DisplayList :: from( snippet) )
181
+ }
182
+ // FIXME(#59346): Is it ok to return None if there's no source_map?
214
183
}
215
184
}
0 commit comments