@@ -122,17 +122,15 @@ pub fn file(
122122 }
123123
124124 let first_hunk_for_suspect = hunks_to_blame. iter ( ) . find ( |hunk| hunk. has_suspect ( & suspect) ) ;
125- let is_still_suspect = first_hunk_for_suspect. is_some ( ) ;
126- if !is_still_suspect {
125+ let Some ( first_hunk_for_suspect) = first_hunk_for_suspect else {
127126 // There are no `UnblamedHunk`s associated with this `suspect`, so we can continue with
128127 // the next one.
129128 continue ' outer;
130- }
129+ } ;
131130
132131 // We know `first_hunk_for_suspect` can’t be `None` here because we check `is_some()`
133132 // above.
134- let current_file_path: BString = first_hunk_for_suspect
135- . unwrap ( )
133+ let current_file_path = first_hunk_for_suspect
136134 . source_file_name
137135 . clone ( )
138136 . unwrap_or_else ( || file_path. to_owned ( ) ) ;
@@ -259,6 +257,7 @@ pub fn file(
259257 & mut buf,
260258 & mut buf2,
261259 & mut buf3,
260+ options. rewrites ,
262261 ) ?;
263262 let Some ( modification) = changes_for_file_path else {
264263 if more_than_one_parent {
@@ -293,6 +292,7 @@ pub fn file(
293292 id,
294293 previous_id,
295294 file_path,
295+ file_path,
296296 options. diff_algorithm ,
297297 & mut stats,
298298 ) ?;
@@ -309,6 +309,7 @@ pub fn file(
309309 id,
310310 source_id,
311311 file_path,
312+ source_location. as_ref ( ) ,
312313 options. diff_algorithm ,
313314 & mut stats,
314315 ) ?;
@@ -433,6 +434,8 @@ fn coalesce_blame_entries(lines_blamed: Vec<BlameEntry>) -> Vec<BlameEntry> {
433434 } )
434435}
435436
437+ /// The union of [`gix_diff::tree::recorder::Change`] and [`gix_diff::tree_with_rewrites::Change`],
438+ /// keeping only the blame-relevant information.
436439enum TreeDiffChange {
437440 Addition ,
438441 Deletion ,
@@ -497,6 +500,7 @@ fn tree_diff_at_file_path(
497500 commit_buf : & mut Vec < u8 > ,
498501 lhs_tree_buf : & mut Vec < u8 > ,
499502 rhs_tree_buf : & mut Vec < u8 > ,
503+ rewrites : Option < gix_diff:: Rewrites > ,
500504) -> Result < Option < TreeDiffChange > , Error > {
501505 let parent_tree_id = find_commit ( cache, & odb, & parent_id, commit_buf) ?. tree_id ( ) ?;
502506
@@ -513,9 +517,15 @@ fn tree_diff_at_file_path(
513517 // Here, we follow git’s behaviour. We return when we’ve found a `Modification`. We try a
514518 // second time with rename tracking when the change is either an `Addition` or a `Deletion`
515519 // because those can turn out to have been a `Rewrite`.
520+ // TODO(perf): renames are usually rare enough to not care about the work duplication done here.
521+ // But in theory, a rename tracker could be used by us, on demand, and we could stuff the
522+ // changes in there and have it find renames, without repeating the diff.
516523 if matches ! ( result, Some ( TreeDiffChange :: Modification { .. } ) ) {
517524 return Ok ( result) ;
518525 }
526+ let Some ( rewrites) = rewrites else {
527+ return Ok ( result) ;
528+ } ;
519529
520530 let result = tree_diff_with_rewrites_at_file_path (
521531 & odb,
@@ -525,6 +535,7 @@ fn tree_diff_at_file_path(
525535 resource_cache,
526536 parent_tree_iter,
527537 tree_iter,
538+ rewrites,
528539 ) ?;
529540
530541 Ok ( result)
@@ -626,7 +637,7 @@ fn tree_diff_without_rewrites_at_file_path(
626637 stats. trees_diffed += 1 ;
627638
628639 match result {
629- Ok ( _) | Err ( gix_diff:: tree:: Error :: Cancelled ) => Ok ( recorder. change . map ( std :: convert :: Into :: into) ) ,
640+ Ok ( _) | Err ( gix_diff:: tree:: Error :: Cancelled ) => Ok ( recorder. change . map ( Into :: into) ) ,
630641 Err ( error) => Err ( Error :: DiffTree ( error) ) ,
631642 }
632643}
@@ -640,12 +651,13 @@ fn tree_diff_with_rewrites_at_file_path(
640651 resource_cache : & mut gix_diff:: blob:: Platform ,
641652 parent_tree_iter : gix_object:: TreeRefIter < ' _ > ,
642653 tree_iter : gix_object:: TreeRefIter < ' _ > ,
654+ rewrites : gix_diff:: Rewrites ,
643655) -> Result < Option < TreeDiffChange > , Error > {
644656 let mut change: Option < gix_diff:: tree_with_rewrites:: Change > = None ;
645657
646658 let options: gix_diff:: tree_with_rewrites:: Options = gix_diff:: tree_with_rewrites:: Options {
647659 location : Some ( gix_diff:: tree:: recorder:: Location :: Path ) ,
648- rewrites : Some ( gix_diff :: Rewrites :: default ( ) ) ,
660+ rewrites : Some ( rewrites ) ,
649661 } ;
650662 let result = gix_diff:: tree_with_rewrites (
651663 parent_tree_iter,
@@ -667,18 +679,20 @@ fn tree_diff_with_rewrites_at_file_path(
667679
668680 match result {
669681 Ok ( _) | Err ( gix_diff:: tree_with_rewrites:: Error :: Diff ( gix_diff:: tree:: Error :: Cancelled ) ) => {
670- Ok ( change. map ( std :: convert :: Into :: into) )
682+ Ok ( change. map ( Into :: into) )
671683 }
672684 Err ( error) => Err ( Error :: DiffTreeWithRewrites ( error) ) ,
673685 }
674686}
675687
688+ #[ allow( clippy:: too_many_arguments) ]
676689fn blob_changes (
677690 odb : impl gix_object:: Find + gix_object:: FindHeader ,
678691 resource_cache : & mut gix_diff:: blob:: Platform ,
679692 oid : ObjectId ,
680693 previous_oid : ObjectId ,
681694 file_path : & BStr ,
695+ previous_file_path : & BStr ,
682696 diff_algorithm : gix_diff:: blob:: Algorithm ,
683697 stats : & mut Statistics ,
684698) -> Result < Vec < Change > , Error > {
@@ -738,7 +752,7 @@ fn blob_changes(
738752 resource_cache. set_resource (
739753 previous_oid,
740754 gix_object:: tree:: EntryKind :: Blob ,
741- file_path ,
755+ previous_file_path ,
742756 gix_diff:: blob:: ResourceKind :: OldOrSource ,
743757 & odb,
744758 ) ?;
0 commit comments