@@ -224,6 +224,13 @@ pub struct SubstitutionPart {
224224    pub  snippet :  String , 
225225} 
226226
227+ #[ derive( Clone ,  Debug ,  PartialEq ,  Hash ,  Encodable ,  Decodable ) ]  
228+ pub  struct  TrimmedSubstitutionPart  { 
229+     pub  original_span :  Span , 
230+     pub  span :  Span , 
231+     pub  snippet :  String , 
232+ } 
233+ 
227234/// Used to translate between `Span`s and byte positions within a single output line in highlighted 
228235/// code of structured suggestions. 
229236#[ derive( Debug ,  Clone ,  Copy ) ]  
@@ -233,6 +240,35 @@ pub(crate) struct SubstitutionHighlight {
233240} 
234241
235242impl  SubstitutionPart  { 
243+     /// Try to turn a replacement into an addition when the span that is being 
244+ /// overwritten matches either the prefix or suffix of the replacement. 
245+ fn  trim_trivial_replacements ( self ,  sm :  & SourceMap )  -> TrimmedSubstitutionPart  { 
246+         let  mut  trimmed_part = TrimmedSubstitutionPart  { 
247+             original_span :  self . span , 
248+             span :  self . span , 
249+             snippet :  self . snippet , 
250+         } ; 
251+         if  trimmed_part. snippet . is_empty ( )  { 
252+             return  trimmed_part; 
253+         } 
254+         let  Ok ( snippet)  = sm. span_to_snippet ( trimmed_part. span )  else  { 
255+             return  trimmed_part; 
256+         } ; 
257+ 
258+         if  let  Some ( ( prefix,  substr,  suffix) )  = as_substr ( & snippet,  & trimmed_part. snippet )  { 
259+             trimmed_part. span  = Span :: new ( 
260+                 trimmed_part. span . lo ( )  + BytePos ( prefix as  u32 ) , 
261+                 trimmed_part. span . hi ( )  - BytePos ( suffix as  u32 ) , 
262+                 trimmed_part. span . ctxt ( ) , 
263+                 trimmed_part. span . parent ( ) , 
264+             ) ; 
265+             trimmed_part. snippet  = substr. to_string ( ) ; 
266+         } 
267+         trimmed_part
268+     } 
269+ } 
270+ 
271+ impl  TrimmedSubstitutionPart  { 
236272    pub  fn  is_addition ( & self ,  sm :  & SourceMap )  -> bool  { 
237273        !self . snippet . is_empty ( )  && !self . replaces_meaningful_content ( sm) 
238274    } 
@@ -260,27 +296,6 @@ impl SubstitutionPart {
260296        sm. span_to_snippet ( self . span ) 
261297            . map_or ( !self . span . is_empty ( ) ,  |snippet| !snippet. trim ( ) . is_empty ( ) ) 
262298    } 
263- 
264-     /// Try to turn a replacement into an addition when the span that is being 
265- /// overwritten matches either the prefix or suffix of the replacement. 
266- fn  trim_trivial_replacements ( & mut  self ,  sm :  & SourceMap )  { 
267-         if  self . snippet . is_empty ( )  { 
268-             return ; 
269-         } 
270-         let  Ok ( snippet)  = sm. span_to_snippet ( self . span )  else  { 
271-             return ; 
272-         } ; 
273- 
274-         if  let  Some ( ( prefix,  substr,  suffix) )  = as_substr ( & snippet,  & self . snippet )  { 
275-             self . span  = Span :: new ( 
276-                 self . span . lo ( )  + BytePos ( prefix as  u32 ) , 
277-                 self . span . hi ( )  - BytePos ( suffix as  u32 ) , 
278-                 self . span . ctxt ( ) , 
279-                 self . span . parent ( ) , 
280-             ) ; 
281-             self . snippet  = substr. to_string ( ) ; 
282-         } 
283-     } 
284299} 
285300
286301/// Given an original string like `AACC`, and a suggestion like `AABBCC`, try to detect 
@@ -310,7 +325,8 @@ impl CodeSuggestion {
310325pub ( crate )  fn  splice_lines ( 
311326        & self , 
312327        sm :  & SourceMap , 
313-     )  -> Vec < ( String ,  Vec < SubstitutionPart > ,  Vec < Vec < SubstitutionHighlight > > ,  ConfusionType ) >  { 
328+     )  -> Vec < ( String ,  Vec < TrimmedSubstitutionPart > ,  Vec < Vec < SubstitutionHighlight > > ,  ConfusionType ) > 
329+     { 
314330        // For the `Vec<Vec<SubstitutionHighlight>>` value, the first level of the vector 
315331        // corresponds to the output snippet's lines, while the second level corresponds to the 
316332        // substrings within that line that should be highlighted. 
@@ -428,12 +444,17 @@ impl CodeSuggestion {
428444                // or deleted code in order to point at the correct column *after* substitution. 
429445                let  mut  acc = 0 ; 
430446                let  mut  confusion_type = ConfusionType :: None ; 
431-                 for  part in  & mut  substitution. parts  { 
447+ 
448+                 let  trimmed_parts = substitution
449+                     . parts 
450+                     . into_iter ( ) 
432451                    // If this is a replacement of, e.g. `"a"` into `"ab"`, adjust the 
433452                    // suggestion and snippet to look as if we just suggested to add 
434453                    // `"b"`, which is typically much easier for the user to understand. 
435-                     part. trim_trivial_replacements ( sm) ; 
454+                     . map ( |part| part. trim_trivial_replacements ( sm) ) 
455+                     . collect :: < Vec < _ > > ( ) ; 
436456
457+                 for  part in  & trimmed_parts { 
437458                    let  part_confusion = detect_confusion_type ( sm,  & part. snippet ,  part. span ) ; 
438459                    confusion_type = confusion_type. combine ( part_confusion) ; 
439460                    let  cur_lo = sm. lookup_char_pos ( part. span . lo ( ) ) ; 
@@ -521,7 +542,7 @@ impl CodeSuggestion {
521542                if  highlights. iter ( ) . all ( |parts| parts. is_empty ( ) )  { 
522543                    None 
523544                }  else  { 
524-                     Some ( ( buf,  substitution . parts ,  highlights,  confusion_type) ) 
545+                     Some ( ( buf,  trimmed_parts ,  highlights,  confusion_type) ) 
525546                } 
526547            } ) 
527548            . collect ( ) 
0 commit comments