@@ -3,9 +3,9 @@ use crate::{BlameEntry, Error, Outcome, Statistics};
33use gix_diff:: blob:: intern:: TokenSource ;
44use gix_hash:: ObjectId ;
55use gix_object:: { bstr:: BStr , FindExt } ;
6+ use std:: num:: NonZeroU32 ;
67use std:: ops:: Range ;
78
8- // TODO: do not instantiate anything, get everything passed as argument.
99/// Produce a list of consecutive [`BlameEntry`] instances to indicate in which commits the ranges of the file
1010/// at `traverse[0]:<file_path>` originated in.
1111///
@@ -142,8 +142,8 @@ where
142142 ) ?;
143143 let Some ( modification) = changes_for_file_path else {
144144 if more_than_one_parent {
145- // None of the changes affected the file we’re currently blaming. Pass blame
146- // to parent.
145+ // None of the changes affected the file we’re currently blaming.
146+ // Copy blame to parent.
147147 for unblamed_hunk in & mut hunks_to_blame {
148148 unblamed_hunk. clone_blame ( suspect, parent_id) ;
149149 }
@@ -159,8 +159,6 @@ where
159159 // Do nothing under the assumption that this always (or almost always)
160160 // implies that the file comes from a different parent, compared to which
161161 // it was modified, not added.
162- //
163- // TODO: I still have to figure out whether this is correct in all cases.
164162 } else {
165163 unblamed_to_out ( & mut hunks_to_blame, & mut out, suspect) ;
166164 break ;
@@ -191,25 +189,26 @@ where
191189
192190 // I don’t know yet whether it would make sense to use a data structure instead that preserves
193191 // order on insertion.
194- out. sort_by ( |a, b| a. range_in_blamed_file . start . cmp ( & b. range_in_blamed_file . start ) ) ;
192+ out. sort_by ( |a, b| a. start_in_blamed_file . cmp ( & b. start_in_blamed_file ) ) ;
195193 Ok ( Outcome {
196194 entries : coalesce_blame_entries ( out) ,
197195 blob : blamed_file_blob,
198196 statistics : stats,
199197 } )
200198}
201199
202- /// The blobs storing the blamed file in `entry` and `parent_entry` are identical which is why
203- /// we can pass blame to the parent without further checks.
200+ /// Pass ownership of each unblamed hunk of `from` to `to`.
201+ ///
202+ /// This happens when `from` didn't actually change anything in the blamed file.
204203fn pass_blame_from_to ( from : ObjectId , to : ObjectId , hunks_to_blame : & mut Vec < UnblamedHunk > ) {
205204 for unblamed_hunk in hunks_to_blame {
206205 unblamed_hunk. pass_blame ( from, to) ;
207206 }
208207}
209208
209+ /// Convert each of the unblamed hunk in `hunks_to_blame` into a [`BlameEntry`], consuming them in the process.
210+ /// `suspect` is expected to be present in the suspect-map in each [`UnblamedHunk`].
210211fn unblamed_to_out ( hunks_to_blame : & mut Vec < UnblamedHunk > , out : & mut Vec < BlameEntry > , suspect : ObjectId ) {
211- // Every line that has not been blamed yet on a commit, is expected to have been
212- // added when the file was added to the repository.
213212 out. extend (
214213 hunks_to_blame
215214 . drain ( ..)
@@ -234,14 +233,21 @@ fn coalesce_blame_entries(lines_blamed: Vec<BlameEntry>) -> Vec<BlameEntry> {
234233 let previous_entry = acc. last ( ) ;
235234
236235 if let Some ( previous_entry) = previous_entry {
236+ let previous_blamed_range = previous_entry. range_in_blamed_file ( ) ;
237+ let current_blamed_range = entry. range_in_blamed_file ( ) ;
238+ let previous_source_range = previous_entry. range_in_source_file ( ) ;
239+ let current_source_range = entry. range_in_source_file ( ) ;
237240 if previous_entry. commit_id == entry. commit_id
238- && previous_entry . range_in_blamed_file . end == entry . range_in_blamed_file . start
241+ && previous_blamed_range . end == current_blamed_range . start
239242 // As of 2024-09-19, the check below only is in `git`, but not in `libgit2`.
240- && previous_entry . range_in_source_file . end == entry . range_in_source_file . start
243+ && previous_source_range . end == current_source_range . start
241244 {
245+ // let combined_range =
242246 let coalesced_entry = BlameEntry {
243- range_in_blamed_file : previous_entry. range_in_blamed_file . start ..entry. range_in_blamed_file . end ,
244- range_in_source_file : previous_entry. range_in_source_file . start ..entry. range_in_source_file . end ,
247+ start_in_blamed_file : previous_blamed_range. start as u32 ,
248+ start_in_source_file : previous_source_range. start as u32 ,
249+ len : NonZeroU32 :: new ( ( current_source_range. end - previous_source_range. start ) as u32 )
250+ . expect ( "BUG: hunks are never zero-sized" ) ,
245251 commit_id : previous_entry. commit_id ,
246252 } ;
247253
0 commit comments