@@ -76,26 +76,34 @@ pub struct CodeSuggestion {
76
76
///
77
77
/// ```
78
78
/// vec![
79
- /// (0..3, vec![ "a", "x"]) ,
80
- /// (4..7, vec!["b", "y"]) ,
79
+ /// Substitution { parts: vec![ (0..3, "a"), (4..7, "b")] } ,
80
+ /// Substitution { parts: vec![(0..3, "x"), (4..7, "y")] } ,
81
81
/// ]
82
82
/// ```
83
83
///
84
84
/// or by replacing the entire span:
85
85
///
86
86
/// ```
87
- /// vec![(0..7, vec!["a.b", "x.y"])]
87
+ /// vec![
88
+ /// Substitution { parts: vec![(0..7, "a.b")] },
89
+ /// Substitution { parts: vec![(0..7, "x.y")] },
90
+ /// ]
88
91
/// ```
89
- pub substitution_parts : Vec < Substitution > ,
92
+ pub substitutions : Vec < Substitution > ,
90
93
pub msg : String ,
91
94
pub show_code_when_inline : bool ,
92
95
}
93
96
94
97
#[ derive( Clone , Debug , PartialEq , Hash , RustcEncodable , RustcDecodable ) ]
95
98
/// See the docs on `CodeSuggestion::substitutions`
96
99
pub struct Substitution {
100
+ pub parts : Vec < SubstitutionPart > ,
101
+ }
102
+
103
+ #[ derive( Clone , Debug , PartialEq , Hash , RustcEncodable , RustcDecodable ) ]
104
+ pub struct SubstitutionPart {
97
105
pub span : Span ,
98
- pub substitutions : Vec < String > ,
106
+ pub snippet : String ,
99
107
}
100
108
101
109
pub trait CodeMapper {
@@ -109,18 +117,8 @@ pub trait CodeMapper {
109
117
}
110
118
111
119
impl CodeSuggestion {
112
- /// Returns the number of substitutions
113
- fn substitutions ( & self ) -> usize {
114
- self . substitution_parts [ 0 ] . substitutions . len ( )
115
- }
116
-
117
- /// Returns the number of substitutions
118
- fn substitution_spans < ' a > ( & ' a self ) -> impl Iterator < Item = Span > + ' a {
119
- self . substitution_parts . iter ( ) . map ( |sub| sub. span )
120
- }
121
-
122
- /// Returns the assembled code suggestions and wether they should be shown with an underline.
123
- pub fn splice_lines ( & self , cm : & CodeMapper ) -> Vec < ( String , bool ) > {
120
+ /// Returns the assembled code suggestions and whether they should be shown with an underline.
121
+ pub fn splice_lines ( & self , cm : & CodeMapper ) -> Vec < ( String , Vec < SubstitutionPart > ) > {
124
122
use syntax_pos:: { CharPos , Loc , Pos } ;
125
123
126
124
fn push_trailing ( buf : & mut String ,
@@ -142,60 +140,42 @@ impl CodeSuggestion {
142
140
}
143
141
}
144
142
145
- if self . substitution_parts . is_empty ( ) {
146
- return vec ! [ ( String :: new( ) , false ) ] ;
147
- }
148
-
149
- let mut primary_spans: Vec < _ > = self . substitution_parts
150
- . iter ( )
151
- . map ( |sub| ( sub. span , & sub. substitutions ) )
152
- . collect ( ) ;
153
-
154
- // Assumption: all spans are in the same file, and all spans
155
- // are disjoint. Sort in ascending order.
156
- primary_spans. sort_by_key ( |sp| sp. 0 . lo ( ) ) ;
157
-
158
- // Find the bounding span.
159
- let lo = primary_spans. iter ( ) . map ( |sp| sp. 0 . lo ( ) ) . min ( ) . unwrap ( ) ;
160
- let hi = primary_spans. iter ( ) . map ( |sp| sp. 0 . hi ( ) ) . min ( ) . unwrap ( ) ;
161
- let bounding_span = Span :: new ( lo, hi, NO_EXPANSION ) ;
162
- let lines = cm. span_to_lines ( bounding_span) . unwrap ( ) ;
163
- assert ! ( !lines. lines. is_empty( ) ) ;
164
-
165
- // To build up the result, we do this for each span:
166
- // - push the line segment trailing the previous span
167
- // (at the beginning a "phantom" span pointing at the start of the line)
168
- // - push lines between the previous and current span (if any)
169
- // - if the previous and current span are not on the same line
170
- // push the line segment leading up to the current span
171
- // - splice in the span substitution
172
- //
173
- // Finally push the trailing line segment of the last span
174
- let fm = & lines. file ;
175
- let mut prev_hi = cm. lookup_char_pos ( bounding_span. lo ( ) ) ;
176
- prev_hi. col = CharPos :: from_usize ( 0 ) ;
177
-
178
- let mut prev_line = fm. get_line ( lines. lines [ 0 ] . line_index ) ;
179
- let mut bufs = vec ! [ ( String :: new( ) , false ) ; self . substitutions( ) ] ;
180
-
181
- for ( sp, substitutes) in primary_spans {
182
- let cur_lo = cm. lookup_char_pos ( sp. lo ( ) ) ;
183
- for ( & mut ( ref mut buf, ref mut underline) , substitute) in bufs. iter_mut ( )
184
- . zip ( substitutes) {
143
+ assert ! ( !self . substitutions. is_empty( ) ) ;
144
+
145
+ self . substitutions . iter ( ) . cloned ( ) . map ( |mut substitution| {
146
+ // Assumption: all spans are in the same file, and all spans
147
+ // are disjoint. Sort in ascending order.
148
+ substitution. parts . sort_by_key ( |part| part. span . lo ( ) ) ;
149
+
150
+ // Find the bounding span.
151
+ let lo = substitution. parts . iter ( ) . map ( |part| part. span . lo ( ) ) . min ( ) . unwrap ( ) ;
152
+ let hi = substitution. parts . iter ( ) . map ( |part| part. span . hi ( ) ) . min ( ) . unwrap ( ) ;
153
+ let bounding_span = Span :: new ( lo, hi, NO_EXPANSION ) ;
154
+ let lines = cm. span_to_lines ( bounding_span) . unwrap ( ) ;
155
+ assert ! ( !lines. lines. is_empty( ) ) ;
156
+
157
+ // To build up the result, we do this for each span:
158
+ // - push the line segment trailing the previous span
159
+ // (at the beginning a "phantom" span pointing at the start of the line)
160
+ // - push lines between the previous and current span (if any)
161
+ // - if the previous and current span are not on the same line
162
+ // push the line segment leading up to the current span
163
+ // - splice in the span substitution
164
+ //
165
+ // Finally push the trailing line segment of the last span
166
+ let fm = & lines. file ;
167
+ let mut prev_hi = cm. lookup_char_pos ( bounding_span. lo ( ) ) ;
168
+ prev_hi. col = CharPos :: from_usize ( 0 ) ;
169
+
170
+ let mut prev_line = fm. get_line ( lines. lines [ 0 ] . line_index ) ;
171
+ let mut buf = String :: new ( ) ;
172
+
173
+ for part in & substitution. parts {
174
+ let cur_lo = cm. lookup_char_pos ( part. span . lo ( ) ) ;
185
175
if prev_hi. line == cur_lo. line {
186
- push_trailing ( buf, prev_line. as_ref ( ) , & prev_hi, Some ( & cur_lo) ) ;
187
-
188
- // Only show an underline in the suggestions if the suggestion is not the
189
- // entirety of the code being shown and the displayed code is not multiline.
190
- if prev_line. as_ref ( ) . unwrap ( ) . trim ( ) . len ( ) > 0
191
- && !substitute. ends_with ( '\n' )
192
- && substitute. lines ( ) . count ( ) == 1
193
- {
194
- * underline = true ;
195
- }
176
+ push_trailing ( & mut buf, prev_line. as_ref ( ) , & prev_hi, Some ( & cur_lo) ) ;
196
177
} else {
197
- * underline = false ;
198
- push_trailing ( buf, prev_line. as_ref ( ) , & prev_hi, None ) ;
178
+ push_trailing ( & mut buf, prev_line. as_ref ( ) , & prev_hi, None ) ;
199
179
// push lines between the previous and current span (if any)
200
180
for idx in prev_hi. line ..( cur_lo. line - 1 ) {
201
181
if let Some ( line) = fm. get_line ( idx) {
@@ -207,22 +187,20 @@ impl CodeSuggestion {
207
187
buf. push_str ( & cur_line[ ..cur_lo. col . to_usize ( ) ] ) ;
208
188
}
209
189
}
210
- buf. push_str ( substitute) ;
190
+ buf. push_str ( & part. snippet ) ;
191
+ prev_hi = cm. lookup_char_pos ( part. span . hi ( ) ) ;
192
+ prev_line = fm. get_line ( prev_hi. line - 1 ) ;
211
193
}
212
- prev_hi = cm. lookup_char_pos ( sp. hi ( ) ) ;
213
- prev_line = fm. get_line ( prev_hi. line - 1 ) ;
214
- }
215
- for & mut ( ref mut buf, _) in & mut bufs {
216
194
// if the replacement already ends with a newline, don't print the next line
217
195
if !buf. ends_with ( '\n' ) {
218
- push_trailing ( buf, prev_line. as_ref ( ) , & prev_hi, None ) ;
196
+ push_trailing ( & mut buf, prev_line. as_ref ( ) , & prev_hi, None ) ;
219
197
}
220
198
// remove trailing newlines
221
199
while buf. ends_with ( '\n' ) {
222
200
buf. pop ( ) ;
223
201
}
224
- }
225
- bufs
202
+ ( buf , substitution . parts )
203
+ } ) . collect ( )
226
204
}
227
205
}
228
206
0 commit comments