1
- use super :: { process_changes, Change , UnblamedHunk } ;
1
+ use super :: { process_changes, update_blame_with_changes, Change , UnblamedHunk } ;
2
+ use crate :: types:: BlameCacheObject ;
2
3
use crate :: { BlameEntry , Error , Outcome , Statistics } ;
3
4
use gix_diff:: blob:: intern:: TokenSource ;
4
5
use gix_diff:: tree:: Visit ;
5
6
use gix_hash:: ObjectId ;
6
7
use gix_object:: {
7
- bstr:: { BStr , BString } ,
8
+ bstr:: { BStr , BString , ByteSlice } ,
8
9
FindExt ,
9
10
} ;
10
11
use gix_traverse:: commit:: find as find_commit;
@@ -66,6 +67,7 @@ pub fn file(
66
67
suspect : ObjectId ,
67
68
cache : Option < gix_commitgraph:: Graph > ,
68
69
resource_cache : & mut gix_diff:: blob:: Platform ,
70
+ blame_cache : Option < BlameCacheObject > ,
69
71
file_path : & BStr ,
70
72
range : Option < Range < u32 > > ,
71
73
) -> Result < Outcome , Error > {
@@ -87,17 +89,56 @@ pub fn file(
87
89
}
88
90
89
91
let range_in_blamed_file = one_based_inclusive_to_zero_based_exclusive_range ( range, num_lines_in_blamed) ?;
90
- let mut hunks_to_blame = vec ! [ UnblamedHunk {
91
- range_in_blamed_file: range_in_blamed_file. clone( ) ,
92
- suspects: [ ( suspect, range_in_blamed_file) ] . into( ) ,
93
- } ] ;
92
+
93
+ let ( blame_entries, mut hunks_to_blame) = match blame_cache {
94
+ Some ( blame_cache) => {
95
+ // If there is a cache, we first get the diff between the current commit and the commit
96
+ // we passed as the cache.
97
+ let old_file_id = file_id ( & blame_cache. cache_id , & mut buf, & mut buf2) ?;
98
+ let changes = blob_changes (
99
+ & odb,
100
+ resource_cache,
101
+ blamed_file_entry_id,
102
+ old_file_id,
103
+ file_path. as_bstr ( ) ,
104
+ & mut stats,
105
+ ) ?;
106
+
107
+ // If there are no changes, we can return the cache as is immediately.
108
+ if changes. iter ( ) . all ( |change| matches ! ( change, Change :: Unchanged ( _) ) ) {
109
+ return Ok ( Outcome {
110
+ entries : blame_cache. entries . clone ( ) ,
111
+ blob : blamed_file_blob,
112
+ statistics : stats,
113
+ } ) ;
114
+ }
115
+ // Otherwise, we update the cache with the new changes.
116
+ let ( blame_entries, hunks_to_blame) = update_blame_with_changes ( blame_cache. entries , changes, suspect) ;
117
+ // If there are no more hunks to blame, we can return the result immediately.
118
+ if hunks_to_blame. is_empty ( ) {
119
+ return Ok ( Outcome {
120
+ entries : blame_entries,
121
+ blob : blamed_file_blob,
122
+ statistics : stats,
123
+ } ) ;
124
+ }
125
+ ( blame_entries, hunks_to_blame)
126
+ }
127
+ None => {
128
+ let hunks_to_blame = vec ! [ UnblamedHunk {
129
+ range_in_blamed_file: range_in_blamed_file. clone( ) ,
130
+ suspects: [ ( suspect, range_in_blamed_file) ] . into( ) ,
131
+ } ] ;
132
+ ( Vec :: new ( ) , hunks_to_blame)
133
+ }
134
+ } ;
94
135
95
136
let ( mut buf, mut buf2) = ( Vec :: new ( ) , Vec :: new ( ) ) ;
96
137
let commit = find_commit ( cache. as_ref ( ) , & odb, & suspect, & mut buf) ?;
97
138
let mut queue: gix_revwalk:: PriorityQueue < CommitTime , ObjectId > = gix_revwalk:: PriorityQueue :: new ( ) ;
98
139
queue. insert ( commit_time ( commit) ?, suspect) ;
99
140
100
- let mut out = Vec :: new ( ) ;
141
+ let mut out = blame_entries ;
101
142
let mut diff_state = gix_diff:: tree:: State :: default ( ) ;
102
143
let mut previous_entry: Option < ( ObjectId , ObjectId ) > = None ;
103
144
' outer: while let Some ( suspect) = queue. pop_value ( ) {
0 commit comments