Skip to content

Commit b1ebf6a

Browse files
committed
Expose the git_diff_blobs API.
Fixes #547
1 parent a073509 commit b1ebf6a

File tree

2 files changed

+84
-9
lines changed

2 files changed

+84
-9
lines changed

src/diff.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -109,11 +109,11 @@ pub type BinaryCb<'a> = dyn FnMut(DiffDelta<'_>, DiffBinary<'_>) -> bool + 'a;
109109
pub type HunkCb<'a> = dyn FnMut(DiffDelta<'_>, DiffHunk<'_>) -> bool + 'a;
110110
pub type LineCb<'a> = dyn FnMut(DiffDelta<'_>, Option<DiffHunk<'_>>, DiffLine<'_>) -> bool + 'a;
111111

112-
struct DiffCallbacks<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h> {
113-
file: Option<&'a mut FileCb<'b>>,
114-
binary: Option<&'c mut BinaryCb<'d>>,
115-
hunk: Option<&'e mut HunkCb<'f>>,
116-
line: Option<&'g mut LineCb<'h>>,
112+
pub struct DiffCallbacks<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h> {
113+
pub file: Option<&'a mut FileCb<'b>>,
114+
pub binary: Option<&'c mut BinaryCb<'d>>,
115+
pub hunk: Option<&'e mut HunkCb<'f>>,
116+
pub line: Option<&'g mut LineCb<'h>>,
117117
}
118118

119119
impl<'repo> Diff<'repo> {
@@ -267,7 +267,7 @@ pub extern "C" fn print_cb(
267267
}
268268
}
269269

270-
extern "C" fn file_cb_c(
270+
pub extern "C" fn file_cb_c(
271271
delta: *const raw::git_diff_delta,
272272
progress: f32,
273273
data: *mut c_void,
@@ -290,7 +290,7 @@ extern "C" fn file_cb_c(
290290
}
291291
}
292292

293-
extern "C" fn binary_cb_c(
293+
pub extern "C" fn binary_cb_c(
294294
delta: *const raw::git_diff_delta,
295295
binary: *const raw::git_diff_binary,
296296
data: *mut c_void,
@@ -314,7 +314,7 @@ extern "C" fn binary_cb_c(
314314
}
315315
}
316316

317-
extern "C" fn hunk_cb_c(
317+
pub extern "C" fn hunk_cb_c(
318318
delta: *const raw::git_diff_delta,
319319
hunk: *const raw::git_diff_hunk,
320320
data: *mut c_void,
@@ -338,7 +338,7 @@ extern "C" fn hunk_cb_c(
338338
}
339339
}
340340

341-
extern "C" fn line_cb_c(
341+
pub extern "C" fn line_cb_c(
342342
delta: *const raw::git_diff_delta,
343343
hunk: *const raw::git_diff_hunk,
344344
line: *const raw::git_diff_line,

src/repo.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ use std::ptr;
88
use std::str;
99

1010
use crate::build::{CheckoutBuilder, RepoBuilder};
11+
use crate::diff::{
12+
binary_cb_c, file_cb_c, hunk_cb_c, line_cb_c, BinaryCb, DiffCallbacks, FileCb, HunkCb, LineCb,
13+
};
1114
use crate::oid_array::OidArray;
1215
use crate::stash::{stash_cb, StashApplyOptions, StashCbData};
1316
use crate::string_array::StringArray;
@@ -2249,6 +2252,78 @@ impl Repository {
22492252
}
22502253
}
22512254

2255+
/// Directly run a diff on two blobs.
2256+
///
2257+
/// Compared to a file, a blob lacks some contextual information. As such, the
2258+
/// `DiffFile` given to the callback will have some fake data; i.e. mode will be
2259+
/// 0 and path will be `None`.
2260+
///
2261+
/// `None` is allowed for either `old_blob` or `new_blob` and will be treated
2262+
/// as an empty blob, with the oid set to zero in the `DiffFile`. Passing `None`
2263+
/// for both blobs is a noop; no callbacks will be made at all.
2264+
///
2265+
/// We do run a binary content check on the blob content and if either blob looks
2266+
/// like binary data, the `DiffFile` binary attribute will be set to 1 and no call to
2267+
/// the `hunk_cb` nor `line_cb` will be made (unless you set the `force_text`
2268+
/// option).
2269+
pub fn diff_blobs(
2270+
&self,
2271+
old_blob: Option<&Blob<'_>>,
2272+
old_as_path: Option<&str>,
2273+
new_blob: Option<&Blob<'_>>,
2274+
new_as_path: Option<&str>,
2275+
opts: Option<&mut DiffOptions>,
2276+
file_cb: Option<&mut FileCb<'_>>,
2277+
binary_cb: Option<&mut BinaryCb<'_>>,
2278+
hunk_cb: Option<&mut HunkCb<'_>>,
2279+
line_cb: Option<&mut LineCb<'_>>,
2280+
) -> Result<(), Error> {
2281+
let old_as_path = crate::opt_cstr(old_as_path)?;
2282+
let new_as_path = crate::opt_cstr(new_as_path)?;
2283+
let mut cbs = DiffCallbacks {
2284+
file: file_cb,
2285+
binary: binary_cb,
2286+
hunk: hunk_cb,
2287+
line: line_cb,
2288+
};
2289+
let ptr = &mut cbs as *mut _;
2290+
unsafe {
2291+
let file_cb_c: raw::git_diff_file_cb = if cbs.file.is_some() {
2292+
Some(file_cb_c)
2293+
} else {
2294+
None
2295+
};
2296+
let binary_cb_c: raw::git_diff_binary_cb = if cbs.binary.is_some() {
2297+
Some(binary_cb_c)
2298+
} else {
2299+
None
2300+
};
2301+
let hunk_cb_c: raw::git_diff_hunk_cb = if cbs.hunk.is_some() {
2302+
Some(hunk_cb_c)
2303+
} else {
2304+
None
2305+
};
2306+
let line_cb_c: raw::git_diff_line_cb = if cbs.line.is_some() {
2307+
Some(line_cb_c)
2308+
} else {
2309+
None
2310+
};
2311+
try_call!(raw::git_diff_blobs(
2312+
old_blob.map(|s| s.raw()),
2313+
old_as_path,
2314+
new_blob.map(|s| s.raw()),
2315+
new_as_path,
2316+
opts.map(|s| s.raw()),
2317+
file_cb_c,
2318+
binary_cb_c,
2319+
hunk_cb_c,
2320+
line_cb_c,
2321+
ptr as *mut _
2322+
));
2323+
Ok(())
2324+
}
2325+
}
2326+
22522327
/// Create a diff with the difference between two tree objects.
22532328
///
22542329
/// This is equivalent to `git diff <old-tree> <new-tree>`

0 commit comments

Comments
 (0)