@@ -16,10 +16,10 @@ pub(super) mod function;
16
16
///
17
17
/// This is the core of the blame implementation as it matches regions in *Source File* to the *Blamed File*.
18
18
fn process_change (
19
- out : & mut Vec < BlameEntry > ,
20
19
new_hunks_to_blame : & mut Vec < UnblamedHunk > ,
21
20
offset : & mut Offset ,
22
21
suspect : ObjectId ,
22
+ parent : ObjectId ,
23
23
hunk : Option < UnblamedHunk > ,
24
24
change : Option < Change > ,
25
25
) -> ( Option < UnblamedHunk > , Option < Change > ) {
@@ -40,6 +40,8 @@ fn process_change(
40
40
match ( hunk, change) {
41
41
( Some ( hunk) , Some ( Change :: Unchanged ( unchanged) ) ) => {
42
42
let Some ( range_in_suspect) = hunk. suspects . get ( & suspect) else {
43
+ // We don’t clone blame to `parent` as `suspect` has nothing to do with this
44
+ // `hunk`.
43
45
new_hunks_to_blame. push ( hunk) ;
44
46
return ( None , Some ( Change :: Unchanged ( unchanged) ) ) ;
45
47
} ;
@@ -64,7 +66,7 @@ fn process_change(
64
66
65
67
// Nothing to do with `hunk` except shifting it,
66
68
// but `unchanged` needs to be checked against the next hunk to catch up.
67
- new_hunks_to_blame. push ( hunk. shift_by ( suspect, * offset) ) ;
69
+ new_hunks_to_blame. push ( hunk. clone_blame ( suspect, parent ) . shift_by ( parent , * offset) ) ;
68
70
( None , Some ( Change :: Unchanged ( unchanged) ) )
69
71
}
70
72
( false , false ) => {
@@ -93,7 +95,7 @@ fn process_change(
93
95
94
96
// Nothing to do with `hunk` except shifting it,
95
97
// but `unchanged` needs to be checked against the next hunk to catch up.
96
- new_hunks_to_blame. push ( hunk. shift_by ( suspect, * offset) ) ;
98
+ new_hunks_to_blame. push ( hunk. clone_blame ( suspect, parent ) . shift_by ( parent , * offset) ) ;
97
99
( None , Some ( Change :: Unchanged ( unchanged) ) )
98
100
}
99
101
}
@@ -123,7 +125,7 @@ fn process_change(
123
125
}
124
126
Either :: Right ( ( before, after) ) => {
125
127
// requeue the left side `before` after offsetting it…
126
- new_hunks_to_blame. push ( before. shift_by ( suspect, * offset) ) ;
128
+ new_hunks_to_blame. push ( before. clone_blame ( suspect, parent ) . shift_by ( parent , * offset) ) ;
127
129
// …and treat `after` as `new_hunk`, which contains the `added` range.
128
130
after
129
131
}
@@ -132,20 +134,18 @@ fn process_change(
132
134
* offset += added. end - added. start ;
133
135
* offset -= number_of_lines_deleted;
134
136
135
- // The overlapping `added` section was successfully located.
136
- out. push ( BlameEntry :: with_offset (
137
- added. clone ( ) ,
138
- suspect,
139
- hunk_starting_at_added. offset_for ( suspect) ,
140
- ) ) ;
141
-
137
+ // The overlapping `added` section was successfully located.
142
138
// Re-split at the end of `added` to continue with what's after.
143
139
match hunk_starting_at_added. split_at ( suspect, added. end ) {
144
- Either :: Left ( _) => {
140
+ Either :: Left ( hunk) => {
141
+ new_hunks_to_blame. push ( hunk) ;
142
+
145
143
// Nothing to split, so we are done with this hunk.
146
144
( None , None )
147
145
}
148
- Either :: Right ( ( _, after) ) => {
146
+ Either :: Right ( ( hunk, after) ) => {
147
+ new_hunks_to_blame. push ( hunk) ;
148
+
149
149
// Keep processing the unblamed range after `added`
150
150
( Some ( after) , None )
151
151
}
@@ -162,17 +162,13 @@ fn process_change(
162
162
Either :: Left ( hunk) => hunk,
163
163
Either :: Right ( ( before, after) ) => {
164
164
// Keep looking for the left side of the unblamed portion.
165
- new_hunks_to_blame. push ( before. shift_by ( suspect, * offset) ) ;
165
+ new_hunks_to_blame. push ( before. clone_blame ( suspect, parent ) . shift_by ( parent , * offset) ) ;
166
166
after
167
167
}
168
168
} ;
169
169
170
170
// We can 'blame' the overlapping area of `added` and `hunk`.
171
- out. push ( BlameEntry :: with_offset (
172
- added. start ..range_in_suspect. end ,
173
- suspect,
174
- hunk_starting_at_added. offset_for ( suspect) ,
175
- ) ) ;
171
+ new_hunks_to_blame. push ( hunk_starting_at_added) ;
176
172
// Keep processing `added`, it's portion past `hunk` may still contribute.
177
173
( None , Some ( Change :: AddedOrReplaced ( added, number_of_lines_deleted) ) )
178
174
}
@@ -183,18 +179,20 @@ fn process_change(
183
179
// <---> (blamed)
184
180
// <--> (new hunk)
185
181
186
- out. push ( BlameEntry :: with_offset (
187
- range_in_suspect. start ..added. end ,
188
- suspect,
189
- hunk. offset_for ( suspect) ,
190
- ) ) ;
191
-
192
182
* offset += added. end - added. start ;
193
183
* offset -= number_of_lines_deleted;
194
184
195
185
match hunk. split_at ( suspect, added. end ) {
196
- Either :: Left ( _) => ( None , None ) ,
197
- Either :: Right ( ( _, after) ) => ( Some ( after) , None ) ,
186
+ Either :: Left ( hunk) => {
187
+ new_hunks_to_blame. push ( hunk) ;
188
+
189
+ ( None , None )
190
+ }
191
+ Either :: Right ( ( before, after) ) => {
192
+ new_hunks_to_blame. push ( before) ;
193
+
194
+ ( Some ( after) , None )
195
+ }
198
196
}
199
197
}
200
198
( false , false ) => {
@@ -222,7 +220,7 @@ fn process_change(
222
220
// <----> (added)
223
221
224
222
// Retry `hunk` once there is overlapping changes to process.
225
- new_hunks_to_blame. push ( hunk. shift_by ( suspect, * offset) ) ;
223
+ new_hunks_to_blame. push ( hunk. clone_blame ( suspect, parent ) . shift_by ( parent , * offset) ) ;
226
224
227
225
// Let hunks catchup with this change.
228
226
(
@@ -237,11 +235,7 @@ fn process_change(
237
235
// <---> (blamed)
238
236
239
237
// Successfully blame the whole range.
240
- out. push ( BlameEntry :: with_offset (
241
- range_in_suspect. clone ( ) ,
242
- suspect,
243
- hunk. offset_for ( suspect) ,
244
- ) ) ;
238
+ new_hunks_to_blame. push ( hunk) ;
245
239
246
240
// And keep processing `added` with future `hunks` that might be affected by it.
247
241
(
@@ -279,7 +273,7 @@ fn process_change(
279
273
}
280
274
Either :: Right ( ( before, after) ) => {
281
275
// `before` isn't affected by deletion, so keep it for later.
282
- new_hunks_to_blame. push ( before. shift_by ( suspect, * offset) ) ;
276
+ new_hunks_to_blame. push ( before. clone_blame ( suspect, parent ) . shift_by ( parent , * offset) ) ;
283
277
// after will be affected by offset, and we will see if there are more changes affecting it.
284
278
after
285
279
}
@@ -291,7 +285,8 @@ fn process_change(
291
285
// | (line_number_in_destination)
292
286
293
287
// Catchup with changes.
294
- new_hunks_to_blame. push ( hunk. shift_by ( suspect, * offset) ) ;
288
+ new_hunks_to_blame. push ( hunk. clone_blame ( suspect, parent) . shift_by ( parent, * offset) ) ;
289
+
295
290
(
296
291
None ,
297
292
Some ( Change :: Deleted ( line_number_in_destination, number_of_lines_deleted) ) ,
@@ -300,7 +295,7 @@ fn process_change(
300
295
}
301
296
( Some ( hunk) , None ) => {
302
297
// nothing to do - changes are exhausted, re-evaluate `hunk`.
303
- new_hunks_to_blame. push ( hunk. shift_by ( suspect, * offset) ) ;
298
+ new_hunks_to_blame. push ( hunk. clone_blame ( suspect, parent ) . shift_by ( parent , * offset) ) ;
304
299
( None , None )
305
300
}
306
301
( None , Some ( Change :: Unchanged ( _) ) ) => {
@@ -328,10 +323,10 @@ fn process_change(
328
323
/// Consume `hunks_to_blame` and `changes` to pair up matches ranges (also overlapping) with each other.
329
324
/// Once a match is found, it's pushed onto `out`.
330
325
fn process_changes (
331
- out : & mut Vec < BlameEntry > ,
332
326
hunks_to_blame : Vec < UnblamedHunk > ,
333
327
changes : Vec < Change > ,
334
328
suspect : ObjectId ,
329
+ parent : ObjectId ,
335
330
) -> Vec < UnblamedHunk > {
336
331
let mut hunks_iter = hunks_to_blame. into_iter ( ) ;
337
332
let mut changes_iter = changes. into_iter ( ) ;
@@ -344,10 +339,10 @@ fn process_changes(
344
339
345
340
loop {
346
341
( hunk, change) = process_change (
347
- out,
348
342
& mut new_hunks_to_blame,
349
343
& mut offset_in_destination,
350
344
suspect,
345
+ parent,
351
346
hunk,
352
347
change,
353
348
) ;
@@ -407,30 +402,20 @@ impl UnblamedHunk {
407
402
}
408
403
}
409
404
410
- fn offset_for ( & self , suspect : ObjectId ) -> Offset {
411
- let range_in_suspect = self
412
- . suspects
413
- . get ( & suspect)
414
- . expect ( "Internal and we know suspect is present" ) ;
415
-
416
- if self . range_in_blamed_file . start > range_in_suspect. start {
417
- Offset :: Added ( self . range_in_blamed_file . start - range_in_suspect. start )
418
- } else {
419
- Offset :: Deleted ( range_in_suspect. start - self . range_in_blamed_file . start )
420
- }
421
- }
422
-
423
405
/// Transfer all ranges from the commit at `from` to the commit at `to`.
424
406
fn pass_blame ( & mut self , from : ObjectId , to : ObjectId ) {
425
407
if let Some ( range_in_suspect) = self . suspects . remove ( & from) {
426
408
self . suspects . insert ( to, range_in_suspect) ;
427
409
}
428
410
}
429
411
430
- fn clone_blame ( & mut self , from : ObjectId , to : ObjectId ) {
412
+ // TODO
413
+ // Should this also accept `&mut self` as the other functions do?
414
+ fn clone_blame ( mut self , from : ObjectId , to : ObjectId ) -> Self {
431
415
if let Some ( range_in_suspect) = self . suspects . get ( & from) {
432
416
self . suspects . insert ( to, range_in_suspect. clone ( ) ) ;
433
417
}
418
+ self
434
419
}
435
420
436
421
fn remove_blame ( & mut self , suspect : ObjectId ) {
@@ -439,36 +424,6 @@ impl UnblamedHunk {
439
424
}
440
425
441
426
impl BlameEntry {
442
- /// Create a new instance by creating `range_in_blamed_file` after applying `offset` to `range_in_source_file`.
443
- fn with_offset ( range_in_source_file : Range < u32 > , commit_id : ObjectId , offset : Offset ) -> Self {
444
- debug_assert ! (
445
- range_in_source_file. end > range_in_source_file. start,
446
- "{range_in_source_file:?}"
447
- ) ;
448
-
449
- match offset {
450
- Offset :: Added ( added) => Self {
451
- start_in_blamed_file : range_in_source_file. start + added,
452
- start_in_source_file : range_in_source_file. start ,
453
- len : force_non_zero ( range_in_source_file. len ( ) as u32 ) ,
454
- commit_id,
455
- } ,
456
- Offset :: Deleted ( deleted) => {
457
- debug_assert ! (
458
- range_in_source_file. start >= deleted,
459
- "{range_in_source_file:?} {offset:?}"
460
- ) ;
461
-
462
- Self {
463
- start_in_blamed_file : range_in_source_file. start - deleted,
464
- start_in_source_file : range_in_source_file. start ,
465
- len : force_non_zero ( range_in_source_file. len ( ) as u32 ) ,
466
- commit_id,
467
- }
468
- }
469
- }
470
- }
471
-
472
427
/// Create an offset from a portion of the *Blamed File*.
473
428
fn from_unblamed_hunk ( unblamed_hunk : & UnblamedHunk , commit_id : ObjectId ) -> Option < Self > {
474
429
let range_in_source_file = unblamed_hunk. suspects . get ( & commit_id) ?;
0 commit comments