@@ -25,6 +25,10 @@ use std::ops::Range;
25
25
/// - The first commit returned here is the first eligible commit to be responsible for parts of `file_path`.
26
26
/// * `file_path`
27
27
/// - A *slash-separated* worktree-relative path to the file to blame.
28
+ /// * `range`
29
+ /// - A 1-based inclusive range, in order to mirror `git`’s behaviour. `Some(20..40)` represents
30
+ /// 21 lines, spanning from line 20 up to and including line 40. This will be converted to
31
+ /// `19..40` internally as the algorithm uses 0-based ranges that are exclusive at the end.
28
32
/// * `resource_cache`
29
33
/// - Used for diffing trees.
30
34
///
@@ -61,6 +65,7 @@ pub fn file<E>(
61
65
traverse : impl IntoIterator < Item = Result < gix_traverse:: commit:: Info , E > > ,
62
66
resource_cache : & mut gix_diff:: blob:: Platform ,
63
67
file_path : & BStr ,
68
+ range : Option < Range < u32 > > ,
64
69
) -> Result < Outcome , Error >
65
70
where
66
71
E : Into < Box < dyn std:: error:: Error + Send + Sync + ' static > > ,
@@ -85,19 +90,37 @@ where
85
90
. tokenize ( )
86
91
. map ( |token| interner. intern ( token) )
87
92
. count ( )
88
- } ;
93
+ } as u32 ;
89
94
90
95
// Binary or otherwise empty?
91
96
if num_lines_in_blamed == 0 {
92
97
return Ok ( Outcome :: default ( ) ) ;
93
98
}
94
99
95
- let mut hunks_to_blame = vec ! [ {
96
- let range_in_blamed_file = 0 ..num_lines_in_blamed as u32 ;
97
- UnblamedHunk {
98
- range_in_blamed_file: range_in_blamed_file. clone( ) ,
99
- suspects: [ ( suspect, range_in_blamed_file) ] . into( ) ,
100
+ // This function assumes that `range` has 1-based inclusive line numbers and converts it to the
101
+ // format internally used: 0-based line numbers stored in ranges that are exclusive at the
102
+ // end.
103
+ let one_based_inclusive_to_zero_based_exclusive_range = || -> Result < Range < u32 > , Error > {
104
+ if let Some ( range) = range {
105
+ if range. start == 0 {
106
+ return Err ( Error :: InvalidLineRange ) ;
107
+ }
108
+ let start = range. start - 1 ;
109
+ let end = range. end ;
110
+ if start >= num_lines_in_blamed || end > num_lines_in_blamed || start == end {
111
+ return Err ( Error :: InvalidLineRange ) ;
112
+ }
113
+ Ok ( start..end)
114
+ } else {
115
+ Ok ( 0 ..num_lines_in_blamed)
100
116
}
117
+ } ;
118
+
119
+ let range_in_blamed_file = one_based_inclusive_to_zero_based_exclusive_range ( ) ?;
120
+
121
+ let mut hunks_to_blame = vec ! [ UnblamedHunk {
122
+ range_in_blamed_file: range_in_blamed_file. clone( ) ,
123
+ suspects: [ ( suspect, range_in_blamed_file) ] . into( ) ,
101
124
} ] ;
102
125
103
126
let mut out = Vec :: new ( ) ;
0 commit comments