Skip to content

Commit d4461e7

Browse files
committed
refactor
- cargo fmt - apply some IDE suggestions - partition tests more - run doc-tests - use RangeInclusive for a less confusing representation
1 parent 36a6ffe commit d4461e7

File tree

6 files changed

+134
-131
lines changed

6 files changed

+134
-131
lines changed

gix-blame/Cargo.toml

-3
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@ authors = ["Christoph Rüßler <[email protected]>", "Sebastian Thi
1010
edition = "2021"
1111
rust-version = "1.70"
1212

13-
[lib]
14-
doctest = false
15-
1613
[dependencies]
1714
gix-commitgraph = { version = "^0.28.0", path = "../gix-commitgraph" }
1815
gix-revwalk = { version = "^0.20.1", path = "../gix-revwalk" }

gix-blame/src/types.rs

+36-35
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1+
use gix_hash::ObjectId;
2+
use gix_object::bstr::BString;
3+
use smallvec::SmallVec;
4+
use std::ops::RangeInclusive;
15
use std::{
26
num::NonZeroU32,
37
ops::{AddAssign, Range, SubAssign},
48
};
59

6-
use gix_hash::ObjectId;
7-
use gix_object::bstr::BString;
8-
use smallvec::SmallVec;
9-
1010
use crate::file::function::tokens_for_diffing;
1111
use crate::Error;
1212

1313
/// A type to represent one or more line ranges to blame in a file.
1414
///
15-
/// This type handles the conversion between git's 1-based inclusive ranges and the internal
15+
/// It handles the conversion between git's 1-based inclusive ranges and the internal
1616
/// 0-based exclusive ranges used by the blame algorithm.
1717
///
1818
/// # Examples
@@ -21,18 +21,18 @@ use crate::Error;
2121
/// use gix_blame::BlameRanges;
2222
///
2323
/// // Blame lines 20 through 40 (inclusive)
24-
/// let range = BlameRanges::from_range(20..41);
24+
/// let range = BlameRanges::from_range(20..=40);
2525
///
2626
/// // Blame multiple ranges
2727
/// let mut ranges = BlameRanges::new();
28-
/// ranges.add_range(1..5); // Lines 1-4
29-
/// ranges.add_range(10..15); // Lines 10-14
28+
/// ranges.add_range(1..=4); // Lines 1-4
29+
/// ranges.add_range(10..=14); // Lines 10-14
3030
/// ```
3131
///
3232
/// # Line Number Representation
3333
///
3434
/// This type uses 1-based inclusive ranges to mirror `git`'s behaviour:
35-
/// - A range of `20..41` represents 21 lines, spanning from line 20 up to and including line 40
35+
/// - A range of `20..=40` represents 21 lines, spanning from line 20 up to and including line 40
3636
/// - This will be converted to `19..40` internally as the algorithm uses 0-based ranges that are exclusive at the end
3737
///
3838
/// # Empty Ranges
@@ -43,59 +43,60 @@ use crate::Error;
4343
pub struct BlameRanges {
4444
/// The ranges to blame, stored as 1-based inclusive ranges
4545
/// An empty Vec means blame the entire file
46-
ranges: Vec<Range<u32>>,
46+
ranges: Vec<RangeInclusive<u32>>,
4747
}
4848

49+
/// Lifecycle
4950
impl BlameRanges {
5051
/// Create a new empty BlameRanges instance.
5152
///
5253
/// An empty instance means to blame the entire file.
5354
pub fn new() -> Self {
54-
Self { ranges: Vec::new() }
55-
}
56-
57-
/// Add a single range to blame.
58-
///
59-
/// The range should be 1-based inclusive.
60-
/// If the new range overlaps with or is adjacent to an existing range,
61-
/// they will be merged into a single range.
62-
pub fn add_range(&mut self, new_range: Range<u32>) {
63-
self.merge_range(new_range);
55+
Self::default()
6456
}
6557

6658
/// Create from a single range.
6759
///
68-
/// The range should be 1-based inclusive, similar to git's line number format.
69-
pub fn from_range(range: Range<u32>) -> Self {
60+
/// The range is 1-based, similar to git's line number format.
61+
pub fn from_range(range: RangeInclusive<u32>) -> Self {
7062
Self { ranges: vec![range] }
7163
}
7264

7365
/// Create from multiple ranges.
7466
///
75-
/// All ranges should be 1-based inclusive.
67+
/// All ranges are 1-based.
7668
/// Overlapping or adjacent ranges will be merged.
77-
pub fn from_ranges(ranges: Vec<Range<u32>>) -> Self {
69+
pub fn from_ranges(ranges: Vec<RangeInclusive<u32>>) -> Self {
7870
let mut result = Self::new();
7971
for range in ranges {
8072
result.merge_range(range);
8173
}
8274
result
8375
}
76+
}
77+
78+
impl BlameRanges {
79+
/// Add a single range to blame.
80+
///
81+
/// The range should be 1-based inclusive.
82+
/// If the new range overlaps with or is adjacent to an existing range,
83+
/// they will be merged into a single range.
84+
pub fn add_range(&mut self, new_range: RangeInclusive<u32>) {
85+
self.merge_range(new_range);
86+
}
8487

8588
/// Attempts to merge the new range with any existing ranges.
86-
/// If no merge is possible, adds it as a new range.
87-
fn merge_range(&mut self, new_range: Range<u32>) {
88-
// First check if this range can be merged with any existing range
89+
/// If no merge is possible, add it as a new range.
90+
fn merge_range(&mut self, new_range: RangeInclusive<u32>) {
91+
// Check if this range can be merged with any existing range
8992
for range in &mut self.ranges {
9093
// Check if ranges overlap or are adjacent
91-
if new_range.start <= range.end && range.start <= new_range.end {
92-
// Merge the ranges by taking the minimum start and maximum end
93-
range.start = range.start.min(new_range.start);
94-
range.end = range.end.max(new_range.end);
94+
if new_range.start() <= range.end() && range.start() <= new_range.end() {
95+
*range = *range.start().min(new_range.start())..=*range.end().max(new_range.end());
9596
return;
9697
}
9798
}
98-
// If no overlap found, add as new range
99+
// If no overlap found, add it as a new range
99100
self.ranges.push(new_range);
100101
}
101102

@@ -118,11 +119,11 @@ impl BlameRanges {
118119

119120
let mut result = Vec::with_capacity(self.ranges.len());
120121
for range in &self.ranges {
121-
if range.start == 0 {
122+
if *range.start() == 0 {
122123
return Err(Error::InvalidLineRange);
123124
}
124-
let start = range.start - 1;
125-
let end = range.end;
125+
let start = range.start() - 1;
126+
let end = *range.end();
126127
if start >= max_lines || end > max_lines || start == end {
127128
return Err(Error::InvalidLineRange);
128129
}

gix-blame/tests/blame.rs

+92-87
Original file line numberDiff line numberDiff line change
@@ -281,37 +281,6 @@ fn diff_disparity() {
281281
}
282282
}
283283

284-
#[test]
285-
fn line_range() {
286-
let Fixture {
287-
odb,
288-
mut resource_cache,
289-
suspect,
290-
} = Fixture::new().unwrap();
291-
292-
let lines_blamed = gix_blame::file(
293-
&odb,
294-
suspect,
295-
None,
296-
&mut resource_cache,
297-
"simple.txt".into(),
298-
gix_blame::Options {
299-
diff_algorithm: gix_diff::blob::Algorithm::Histogram,
300-
range: BlameRanges::from_range(1..2),
301-
since: None,
302-
},
303-
)
304-
.unwrap()
305-
.entries;
306-
307-
assert_eq!(lines_blamed.len(), 2);
308-
309-
let git_dir = fixture_path().join(".git");
310-
let baseline = Baseline::collect(git_dir.join("simple-lines-1-2.baseline")).unwrap();
311-
312-
assert_eq!(lines_blamed, baseline);
313-
}
314-
315284
#[test]
316285
fn since() {
317286
let Fixture {
@@ -343,73 +312,109 @@ fn since() {
343312
assert_eq!(lines_blamed, baseline);
344313
}
345314

346-
#[test]
347-
fn multiple_ranges_using_add_range() {
348-
let Fixture {
349-
odb,
350-
mut resource_cache,
351-
suspect,
352-
} = Fixture::new().unwrap();
315+
mod blame_ranges {
316+
use crate::{fixture_path, Baseline, Fixture};
317+
use gix_blame::BlameRanges;
353318

354-
let mut ranges = BlameRanges::new();
355-
ranges.add_range(1..2); // Lines 1-2
356-
ranges.add_range(1..1); // Duplicate range, should be ignored
357-
ranges.add_range(4..4); // Line 4
319+
#[test]
320+
fn line_range() {
321+
let Fixture {
322+
odb,
323+
mut resource_cache,
324+
suspect,
325+
} = Fixture::new().unwrap();
358326

359-
let lines_blamed = gix_blame::file(
360-
&odb,
361-
suspect,
362-
None,
363-
&mut resource_cache,
364-
"simple.txt".into(),
365-
gix_blame::Options {
366-
diff_algorithm: gix_diff::blob::Algorithm::Histogram,
367-
range: ranges,
368-
since: None,
369-
},
370-
)
371-
.unwrap()
372-
.entries;
327+
let lines_blamed = gix_blame::file(
328+
&odb,
329+
suspect,
330+
None,
331+
&mut resource_cache,
332+
"simple.txt".into(),
333+
gix_blame::Options {
334+
diff_algorithm: gix_diff::blob::Algorithm::Histogram,
335+
range: BlameRanges::from_range(1..=2),
336+
since: None,
337+
},
338+
)
339+
.unwrap()
340+
.entries;
373341

374-
assert_eq!(lines_blamed.len(), 3); // Should have 3 lines total (2 from first range + 1 from second range)
342+
assert_eq!(lines_blamed.len(), 2);
375343

376-
let git_dir = fixture_path().join(".git");
377-
let baseline = Baseline::collect(git_dir.join("simple-lines-multiple-1-2-and-4.baseline")).unwrap();
344+
let git_dir = fixture_path().join(".git");
345+
let baseline = Baseline::collect(git_dir.join("simple-lines-1-2.baseline")).unwrap();
378346

379-
assert_eq!(lines_blamed, baseline);
380-
}
347+
assert_eq!(lines_blamed, baseline);
348+
}
381349

382-
#[test]
383-
fn multiple_ranges_usingfrom_ranges() {
384-
let Fixture {
385-
odb,
386-
mut resource_cache,
387-
suspect,
388-
} = Fixture::new().unwrap();
350+
#[test]
351+
fn multiple_ranges_using_add_range() {
352+
let Fixture {
353+
odb,
354+
mut resource_cache,
355+
suspect,
356+
} = Fixture::new().unwrap();
389357

390-
let ranges = BlameRanges::from_ranges(vec![1..2, 1..1, 4..4]);
358+
let mut ranges = BlameRanges::new();
359+
ranges.add_range(1..=2); // Lines 1-2
360+
ranges.add_range(1..=1); // Duplicate range, should be ignored
361+
ranges.add_range(4..=4); // Line 4
391362

392-
let lines_blamed = gix_blame::file(
393-
&odb,
394-
suspect,
395-
None,
396-
&mut resource_cache,
397-
"simple.txt".into(),
398-
gix_blame::Options {
399-
diff_algorithm: gix_diff::blob::Algorithm::Histogram,
400-
range: ranges,
401-
since: None,
402-
},
403-
)
404-
.unwrap()
405-
.entries;
363+
let lines_blamed = gix_blame::file(
364+
&odb,
365+
suspect,
366+
None,
367+
&mut resource_cache,
368+
"simple.txt".into(),
369+
gix_blame::Options {
370+
diff_algorithm: gix_diff::blob::Algorithm::Histogram,
371+
range: ranges,
372+
since: None,
373+
},
374+
)
375+
.unwrap()
376+
.entries;
406377

407-
assert_eq!(lines_blamed.len(), 3); // Should have 3 lines total (2 from first range + 1 from second range)
378+
assert_eq!(lines_blamed.len(), 3); // Should have 3 lines total (2 from first range + 1 from second range)
408379

409-
let git_dir = fixture_path().join(".git");
410-
let baseline = Baseline::collect(git_dir.join("simple-lines-multiple-1-2-and-4.baseline")).unwrap();
380+
let git_dir = fixture_path().join(".git");
381+
let baseline = Baseline::collect(git_dir.join("simple-lines-multiple-1-2-and-4.baseline")).unwrap();
411382

412-
assert_eq!(lines_blamed, baseline);
383+
assert_eq!(lines_blamed, baseline);
384+
}
385+
386+
#[test]
387+
fn multiple_ranges_usingfrom_ranges() {
388+
let Fixture {
389+
odb,
390+
mut resource_cache,
391+
suspect,
392+
} = Fixture::new().unwrap();
393+
394+
let ranges = BlameRanges::from_ranges(vec![1..=2, 1..=1, 4..=4]);
395+
396+
let lines_blamed = gix_blame::file(
397+
&odb,
398+
suspect,
399+
None,
400+
&mut resource_cache,
401+
"simple.txt".into(),
402+
gix_blame::Options {
403+
diff_algorithm: gix_diff::blob::Algorithm::Histogram,
404+
range: ranges,
405+
since: None,
406+
},
407+
)
408+
.unwrap()
409+
.entries;
410+
411+
assert_eq!(lines_blamed.len(), 3); // Should have 3 lines total (2 from first range + 1 from second range)
412+
413+
let git_dir = fixture_path().join(".git");
414+
let baseline = Baseline::collect(git_dir.join("simple-lines-multiple-1-2-and-4.baseline")).unwrap();
415+
416+
assert_eq!(lines_blamed, baseline);
417+
}
413418
}
414419

415420
fn fixture_path() -> PathBuf {

src/plumbing/main.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use anyhow::{anyhow, Context, Result};
1111
use clap::{CommandFactory, Parser};
1212
use gitoxide_core as core;
1313
use gitoxide_core::{pack::verify, repository::PathsOrPatterns};
14-
use gix::{bstr::{io::BufReadExt, BString}};
14+
use gix::bstr::{io::BufReadExt, BString};
1515

1616
use crate::{
1717
plumbing::{

src/plumbing/options/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ pub enum Subcommands {
169169
file: std::ffi::OsString,
170170
/// Only blame lines in the given 1-based inclusive range '<start>,<end>', e.g. '20,40'.
171171
#[clap(short='L', value_parser=AsRange, action=clap::ArgAction::Append)]
172-
ranges: Vec<std::ops::Range<u32>>,
172+
ranges: Vec<std::ops::RangeInclusive<u32>>,
173173
/// Don't consider commits before the given date.
174174
#[clap(long, value_parser=AsTime, value_name = "DATE")]
175175
since: Option<gix::date::Time>,

0 commit comments

Comments
 (0)