From 2c88262a255d3afa14a49bfe73363aae2f4be60d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20R=C3=BC=C3=9Fler?= Date: Sun, 7 Dec 2025 18:40:03 +0100 Subject: [PATCH] Update `gix-blame` to `imara-diff` 0.2 --- gix-blame/Cargo.toml | 2 +- gix-blame/src/file/function.rs | 105 ++++++++++++++------------------- gix-blame/tests/blame.rs | 5 +- 3 files changed, 48 insertions(+), 64 deletions(-) diff --git a/gix-blame/Cargo.toml b/gix-blame/Cargo.toml index 4417277cfe6..4fc8f775d32 100644 --- a/gix-blame/Cargo.toml +++ b/gix-blame/Cargo.toml @@ -15,7 +15,7 @@ gix-commitgraph = { version = "^0.30.0", path = "../gix-commitgraph" } gix-revwalk = { version = "^0.23.0", path = "../gix-revwalk" } gix-trace = { version = "^0.1.14", path = "../gix-trace" } gix-date = { version = "^0.11.0", path = "../gix-date" } -gix-diff = { version = "^0.55.0", path = "../gix-diff", default-features = false, features = ["blob"] } +gix-diff = { version = "^0.55.0", path = "../gix-diff", default-features = false, features = ["blob", "blob-experimental"] } gix-object = { version = "^0.52.0", path = "../gix-object" } gix-hash = { version = "^0.20.0", path = "../gix-hash" } gix-worktree = { version = "^0.44.0", path = "../gix-worktree", default-features = false, features = ["attributes"] } diff --git a/gix-blame/src/file/function.rs b/gix-blame/src/file/function.rs index 773ac1425cb..649b27db84f 100644 --- a/gix-blame/src/file/function.rs +++ b/gix-blame/src/file/function.rs @@ -1,6 +1,9 @@ -use std::{num::NonZeroU32, ops::Range}; +use std::num::NonZeroU32; -use gix_diff::{blob::intern::TokenSource, tree::Visit}; +use gix_diff::{ + blob::{intern::TokenSource, v2::Hunk}, + tree::Visit, +}; use gix_hash::ObjectId; use gix_object::{ bstr::{BStr, BString}, @@ -758,85 +761,65 @@ fn blob_changes( diff_algorithm: gix_diff::blob::Algorithm, stats: &mut Statistics, ) -> Result, Error> { - /// Record all [`Change`]s to learn about additions, deletions and unchanged portions of a *Source File*. - struct ChangeRecorder { - last_seen_after_end: u32, - hunks: Vec, - total_number_of_lines: u32, - } + resource_cache.set_resource( + previous_oid, + gix_object::tree::EntryKind::Blob, + previous_file_path, + gix_diff::blob::ResourceKind::OldOrSource, + &odb, + )?; + resource_cache.set_resource( + oid, + gix_object::tree::EntryKind::Blob, + file_path, + gix_diff::blob::ResourceKind::NewOrDestination, + &odb, + )?; - impl ChangeRecorder { - /// `total_number_of_lines` is used to fill in the last unchanged hunk if needed - /// so that the entire file is represented by [`Change`]. - fn new(total_number_of_lines: u32) -> Self { - ChangeRecorder { - last_seen_after_end: 0, - hunks: Vec::new(), - total_number_of_lines, - } - } - } + let outcome = resource_cache.prepare_diff()?; + let input = gix_diff::blob::v2::InternedInput::new( + outcome.old.data.as_slice().unwrap_or_default(), + outcome.new.data.as_slice().unwrap_or_default(), + ); + + let diff_algorithm: gix_diff::blob::v2::Algorithm = match diff_algorithm { + gix_diff::blob::Algorithm::Histogram => gix_diff::blob::v2::Algorithm::Histogram, + gix_diff::blob::Algorithm::Myers => gix_diff::blob::v2::Algorithm::Myers, + gix_diff::blob::Algorithm::MyersMinimal => gix_diff::blob::v2::Algorithm::MyersMinimal, + }; + let mut diff = gix_diff::blob::v2::Diff::compute(diff_algorithm, &input); + diff.postprocess_lines(&input); - impl gix_diff::blob::Sink for ChangeRecorder { - type Out = Vec; + let changes = diff + .hunks() + .fold((Vec::new(), 0), |(mut hunks, mut last_seen_after_end), hunk| { + let Hunk { before, after } = hunk; - fn process_change(&mut self, before: Range, after: Range) { // This checks for unchanged hunks. - if after.start > self.last_seen_after_end { - self.hunks - .push(Change::Unchanged(self.last_seen_after_end..after.start)); + if after.start > last_seen_after_end { + hunks.push(Change::Unchanged(last_seen_after_end..after.start)); } match (!before.is_empty(), !after.is_empty()) { (_, true) => { - self.hunks.push(Change::AddedOrReplaced( + hunks.push(Change::AddedOrReplaced( after.start..after.end, before.end - before.start, )); } (true, false) => { - self.hunks.push(Change::Deleted(after.start, before.end - before.start)); + hunks.push(Change::Deleted(after.start, before.end - before.start)); } (false, false) => unreachable!("BUG: imara-diff provided a non-change"), } - self.last_seen_after_end = after.end; - } - - fn finish(mut self) -> Self::Out { - if self.total_number_of_lines > self.last_seen_after_end { - self.hunks - .push(Change::Unchanged(self.last_seen_after_end..self.total_number_of_lines)); - } - self.hunks - } - } - resource_cache.set_resource( - previous_oid, - gix_object::tree::EntryKind::Blob, - previous_file_path, - gix_diff::blob::ResourceKind::OldOrSource, - &odb, - )?; - resource_cache.set_resource( - oid, - gix_object::tree::EntryKind::Blob, - file_path, - gix_diff::blob::ResourceKind::NewOrDestination, - &odb, - )?; + last_seen_after_end = after.end; - let outcome = resource_cache.prepare_diff()?; - let input = gix_diff::blob::intern::InternedInput::new( - tokens_for_diffing(outcome.old.data.as_slice().unwrap_or_default()), - tokens_for_diffing(outcome.new.data.as_slice().unwrap_or_default()), - ); - let number_of_lines_in_destination = input.after.len(); - let change_recorder = ChangeRecorder::new(number_of_lines_in_destination as u32); + (hunks, last_seen_after_end) + }); - let res = gix_diff::blob::diff(diff_algorithm, &input, change_recorder); stats.blobs_diffed += 1; - Ok(res) + Ok(changes.0) } fn find_path_entry_in_commit( diff --git a/gix-blame/tests/blame.rs b/gix-blame/tests/blame.rs index bd9e1f50c35..0a6b851d91d 100644 --- a/gix-blame/tests/blame.rs +++ b/gix-blame/tests/blame.rs @@ -292,11 +292,12 @@ mktest!( 3 ); -/// As of 2024-09-24, these tests are expected to fail. +/// As of 2024-09-24, the Myers-related test was expected to fail. Both tests were initially +/// written when diffing was done by `imara-diff` 0.1. After updating to `imara-diff` 0.2 on +/// 2025-12-07, the Myers-related test started passing. /// /// Context: https://github.com/Byron/gitoxide/pull/1453#issuecomment-2371013904 #[test] -#[should_panic = "empty-lines-myers"] fn diff_disparity() { for case in ["empty-lines-myers", "empty-lines-histogram"] { let Fixture {