@@ -76,26 +76,34 @@ pub struct CodeSuggestion {
7676 ///
7777 /// ```
7878 /// 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")] } ,
8181 /// ]
8282 /// ```
8383 ///
8484 /// or by replacing the entire span:
8585 ///
8686 /// ```
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+ /// ]
8891 /// ```
89- pub substitution_parts : Vec < Substitution > ,
92+ pub substitutions : Vec < Substitution > ,
9093 pub msg : String ,
9194 pub show_code_when_inline : bool ,
9295}
9396
9497#[ derive( Clone , Debug , PartialEq , Hash , RustcEncodable , RustcDecodable ) ]
9598/// See the docs on `CodeSuggestion::substitutions`
9699pub struct Substitution {
100+ pub parts : Vec < SubstitutionPart > ,
101+ }
102+
103+ #[ derive( Clone , Debug , PartialEq , Hash , RustcEncodable , RustcDecodable ) ]
104+ pub struct SubstitutionPart {
97105 pub span : Span ,
98- pub substitutions : Vec < String > ,
106+ pub snippet : String ,
99107}
100108
101109pub trait CodeMapper {
@@ -109,18 +117,8 @@ pub trait CodeMapper {
109117}
110118
111119impl 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 > ) > {
124122 use syntax_pos:: { CharPos , Loc , Pos } ;
125123
126124 fn push_trailing ( buf : & mut String ,
@@ -142,60 +140,42 @@ impl CodeSuggestion {
142140 }
143141 }
144142
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 ( ) ) ;
185175 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) ) ;
196177 } 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 ) ;
199179 // push lines between the previous and current span (if any)
200180 for idx in prev_hi. line ..( cur_lo. line - 1 ) {
201181 if let Some ( line) = fm. get_line ( idx) {
@@ -207,22 +187,20 @@ impl CodeSuggestion {
207187 buf. push_str ( & cur_line[ ..cur_lo. col . to_usize ( ) ] ) ;
208188 }
209189 }
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 ) ;
211193 }
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 {
216194 // if the replacement already ends with a newline, don't print the next line
217195 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 ) ;
219197 }
220198 // remove trailing newlines
221199 while buf. ends_with ( '\n' ) {
222200 buf. pop ( ) ;
223201 }
224- }
225- bufs
202+ ( buf , substitution . parts )
203+ } ) . collect ( )
226204 }
227205}
228206
0 commit comments