@@ -119,10 +119,13 @@ pub fn run_clang_format(
119119 replacements : diff
120120 . hunks ( )
121121 . filter_map ( |hunk| {
122+ let altered_start = hunk. after . start . saturating_add ( 1 ) ; // convert to 1-based line numbers
123+ let og_start = hunk. before . start . saturating_add ( 1 ) ; // convert to 1-based line numbers
124+ let og_end = hunk. before . end ; // exclusive end is inclusive for 1-based line numbers
122125 let replacement = if hunk. is_pure_insertion ( ) {
123- RangeInclusive :: new ( hunk . after . start , hunk . after . start )
126+ RangeInclusive :: new ( altered_start , altered_start )
124127 } else {
125- RangeInclusive :: new ( hunk . before . start , hunk . before . end . saturating_sub ( 1 ) )
128+ RangeInclusive :: new ( og_start , og_end )
126129 } ;
127130 if ranges. is_empty ( ) {
128131 Some ( replacement)
@@ -241,14 +244,14 @@ fn three_way_diff(ranges: &[RangeInclusive<u32>], tidy_diff: Diff) -> Vec<RangeI
241244
242245 while let Some ( tidy_hunk) = tidy_iter. peek ( ) {
243246 // alias for readability and prevent some repeated calculations
244- let before_start = tidy_hunk. before . start ;
245- let before_end = tidy_hunk. before . end . saturating_sub ( 1 ) ;
246- let after_start = tidy_hunk. after . start ;
247- let after_end = tidy_hunk. after . end . saturating_sub ( 1 ) ;
247+ let before_start = tidy_hunk. before . start . saturating_add ( 1 ) ; // convert to 1-based line numbers
248+ let before_end = tidy_hunk. before . end ; // exclusive end is inclusive for 1-based line numbers
249+ let after_start = tidy_hunk. after . start . saturating_add ( 1 ) ; // convert to 1-based line numbers
250+ let after_end = tidy_hunk. after . end ; // exclusive end is inclusive for 1-based line numbers
248251 let delta = tidy_hunk. after . len ( ) as i32 - tidy_hunk. before . len ( ) as i32 ;
249252
250- // The tidy hunk is a pure removal that exactly matches the og range.
251- if tidy_hunk. is_pure_removal ( ) && before_start == og_start && before_end = = og_end {
253+ // The tidy hunk is a pure removal that encompasses the og range.
254+ if tidy_hunk. is_pure_removal ( ) && before_start <= og_start && before_end > = og_end {
252255 // Skip the og range and tidy hunk entirely.
253256 // The line shift must still be adjusted for the pure removal though
254257 line_shift += delta;
@@ -272,15 +275,15 @@ fn three_way_diff(ranges: &[RangeInclusive<u32>], tidy_diff: Diff) -> Vec<RangeI
272275 }
273276
274277 // tidy hunk overlaps with the og range in some way (case 4).
275- if tidy_hunk . before . contains ( & og_start) {
278+ if ( before_start..=before_end ) . contains ( & og_start) {
276279 merged_start = after_start;
277280 }
278281
279282 // commit the line shift now that the tidy hunk start is checked.
280283 line_shift += delta;
281284
282285 // tidy hunk suffixes the og range.
283- if tidy_hunk . before . contains ( & og_end) {
286+ if ( before_start..=before_end ) . contains ( & og_end) {
284287 merged_end = after_end;
285288 tidy_iter. next ( ) ; // this tidy hunk is handled.
286289 break ; // break from loop to push the merged range into joint_ranges.
@@ -299,8 +302,8 @@ fn three_way_diff(ranges: &[RangeInclusive<u32>], tidy_diff: Diff) -> Vec<RangeI
299302 for tidy_hunk in tidy_iter {
300303 maybe_push_range (
301304 & mut joint_ranges,
302- tidy_hunk. after . start ,
303- tidy_hunk. after . end . saturating_sub ( 1 ) ,
305+ tidy_hunk. after . start . saturating_add ( 1 ) , // convert to 1-based line numbers
306+ tidy_hunk. after . end , // exclusive end is inclusive for 1-based line numbers
304307 ) ;
305308 }
306309
@@ -313,9 +316,8 @@ mod tests {
313316
314317 use std:: ops:: RangeInclusive ;
315318
316- use gix_imara_diff:: { Diff , InternedInput } ;
317-
318319 use super :: { summarize_style, three_way_diff} ;
320+ use crate :: clang_tools:: make_patch;
319321
320322 fn formalize_style ( style : & str , expected : & str ) {
321323 assert_eq ! ( summarize_style( style) , expected) ;
@@ -339,38 +341,70 @@ mod tests {
339341 #[ test]
340342 fn three_way_diff_mixed ( ) {
341343 const OG_SRC : & str =
342- "line1\n line2\n line3\n line4\n line5\n line6\n line7\n line8\n line9\n line10\n line11" ;
343- // TIDY_SRC replaces line3->StringA (hunk before=2..3) and
344- // line8+line9+line10->StringB+StringC (hunk before=7..10), then appends StringE.
345- // The second hunk's before=7..10 contains og_end=9 but not og_start=6,
346- // which exercises the "tidy hunk suffixes og range" branch.
344+ "line1\n line2\n line3\n line4\n line5\n line6\n line7\n line8\n line9\n line10\n line11\n line12" ;
345+ // The first hunk line2-3->StringA-B (hunk 2..4 prefixes og range[3..=5]).
346+ // The second hunk line8-11->StringC-D\nline11\n (hunk 8..12 suffixes og range[7..=9]).
347347 const TIDY_SRC : & str =
348- "line1\n line2 \ n StringA\n line4\n line5\n line6\n line7\n StringB \n StringC\n line11 \n StringE " ;
349- let input = InternedInput :: new ( OG_SRC , TIDY_SRC ) ;
350- let mut tidy_diff = Diff :: compute ( gix_imara_diff :: Algorithm :: Histogram , & input ) ;
351- tidy_diff . postprocess_lines ( & input ) ;
352- let ranges = vec ! [ RangeInclusive :: new( 2 , 4 ) , RangeInclusive :: new( 6 , 9 ) ] ;
348+ "line1\n StringA\n StringB \ n line4\n line5\n line6\n line7\n line8 \n StringC\n StringD \n line11 " ;
349+ let ( tidy_diff , _input ) = make_patch ( TIDY_SRC , OG_SRC ) ;
350+ # [ cfg ( feature = "bin" ) ]
351+ print_diff ( OG_SRC , TIDY_SRC , & tidy_diff , & _input ) ;
352+ let ranges = vec ! [ RangeInclusive :: new( 3 , 5 ) , RangeInclusive :: new( 7 , 9 ) ] ;
353353 println ! ( "tidy diff: {tidy_diff:#?}\n compared to og ranges: {ranges:?}" ) ;
354354 let joint_ranges = three_way_diff ( & ranges, tidy_diff) ;
355355 println ! ( "joint ranges: {joint_ranges:#?}" ) ;
356- assert_eq ! ( joint_ranges, vec![ 2 ..=4 , 6 ..=10 ] ) ;
356+ assert_eq ! ( joint_ranges, vec![ 2 ..=5 , 7 ..=11 ] ) ;
357357 }
358358
359359 #[ test]
360360 fn three_way_diff_separated ( ) {
361361 const OG_SRC : & str =
362362 "line1\n line2\n line3\n line4\n line5\n line6\n line7\n line8\n line9\n line10\n line11" ;
363- // TIDY_SRC removes "line3" (index 2) which decrements offsets in ranges[5,8] and removes ranges[2,2 ].
363+ // TIDY_SRC removes "line3" which decrements offsets in ranges[5,8] and removes ranges[3,3 ].
364364 // TIDY_SRC appends StringE, which handles remaining tidy hunks after done iterating ranges
365365 const TIDY_SRC : & str =
366366 "line1\n line2\n line4\n line5\n line6\n line7\n line8\n line9\n line10\n line11\n StringE" ;
367- let input = InternedInput :: new ( OG_SRC , TIDY_SRC ) ;
368- let mut tidy_diff = Diff :: compute ( gix_imara_diff :: Algorithm :: Histogram , & input ) ;
369- tidy_diff . postprocess_lines ( & input ) ;
370- let ranges = vec ! [ 2 ..=2 , 5 ..=8 ] ;
367+ let ( tidy_diff , _input ) = make_patch ( TIDY_SRC , OG_SRC ) ;
368+ # [ cfg ( feature = "bin" ) ]
369+ print_diff ( OG_SRC , TIDY_SRC , & tidy_diff , & _input ) ;
370+ let ranges = vec ! [ 3 ..=3 , 5 ..=8 ] ;
371371 println ! ( "tidy diff: {tidy_diff:#?}\n compared to og ranges: {ranges:?}" ) ;
372372 let joint_ranges = three_way_diff ( & ranges, tidy_diff) ;
373373 println ! ( "joint ranges: {joint_ranges:#?}" ) ;
374- assert_eq ! ( joint_ranges, vec![ 4 ..=7 , 9 ..=10 ] ) ;
374+ assert_eq ! ( joint_ranges, vec![ 4 ..=7 , 10 ..=11 ] ) ;
375+ }
376+
377+ #[ cfg( feature = "bin" ) ]
378+ fn print_diff (
379+ og : & str ,
380+ altered : & str ,
381+ diff : & gix_imara_diff:: Diff ,
382+ input : & gix_imara_diff:: InternedInput < & str > ,
383+ ) {
384+ use clap:: builder:: styling:: { AnsiColor , Color , Style } ;
385+ use gix_imara_diff:: { BasicLineDiffPrinter , UnifiedDiffConfig } ;
386+
387+ println ! ( "---\n OG SRC:" ) ;
388+ for ( i, l) in og. lines ( ) . enumerate ( ) {
389+ println ! ( "{i:>2}|{l}" ) ;
390+ }
391+ println ! ( "---\n ALTERED SRC:" ) ;
392+ for ( i, l) in altered. lines ( ) . enumerate ( ) {
393+ println ! ( "{i:>2}|{l}" ) ;
394+ }
395+ let printer = BasicLineDiffPrinter ( & input. interner ) ;
396+ let mut config = UnifiedDiffConfig :: default ( ) ;
397+ config. context_len ( 0 ) ;
398+ let unified = diff. unified_diff ( & printer, config, input) . to_string ( ) ;
399+ for l in unified. lines ( ) {
400+ let style = if l. starts_with ( '+' ) {
401+ Style :: new ( ) . fg_color ( Some ( Color :: Ansi ( AnsiColor :: Green ) ) )
402+ } else if l. starts_with ( '-' ) {
403+ Style :: new ( ) . fg_color ( Some ( Color :: Ansi ( AnsiColor :: Red ) ) )
404+ } else {
405+ Style :: new ( )
406+ } ;
407+ println ! ( "{style}{l}{style:#}" ) ;
408+ }
375409 }
376410}
0 commit comments