diff --git a/include/git2/diff.h b/include/git2/diff.h index 0c9f620c1..d8dc91c80 100644 --- a/include/git2/diff.h +++ b/include/git2/diff.h @@ -154,19 +154,22 @@ typedef int (*git_diff_hunk_fn)( * Line origin constants. * * These values describe where a line came from and will be passed to - * the git_diff_line_fn when iterating over a diff. There are some + * the git_diff_data_fn when iterating over a diff. There are some * special origin contants at the end that are used for the text * output callbacks to demarcate lines that are actually part of * the file or hunk headers. */ enum { - /* these values will be sent to `git_diff_line_fn` along with the line */ + /* these values will be sent to `git_diff_data_fn` along with the line */ GIT_DIFF_LINE_CONTEXT = ' ', GIT_DIFF_LINE_ADDITION = '+', GIT_DIFF_LINE_DELETION = '-', GIT_DIFF_LINE_ADD_EOFNL = '\n', /**< LF was added at end of file */ GIT_DIFF_LINE_DEL_EOFNL = '\0', /**< LF was removed at end of file */ - /* these values will only be sent to a `git_diff_output_fn` */ + /* these values will only be sent to a `git_diff_data_fn` when the content + * of a diff is being formatted (eg. through git_diff_print_patch() or + * git_diff_print_compact(), for instance). + */ GIT_DIFF_LINE_FILE_HDR = 'F', GIT_DIFF_LINE_HUNK_HDR = 'H', GIT_DIFF_LINE_BINARY = 'B' @@ -174,25 +177,19 @@ enum { /** * When iterating over a diff, callback that will be made per text diff - * line. - */ -typedef int (*git_diff_line_fn)( - void *cb_data, - git_diff_delta *delta, - char line_origin, /**< GIT_DIFF_LINE_... value from above */ - const char *content, - size_t content_len); - -/** + * line. In this context, the provided range will be NULL. + * * When printing a diff, callback that will be made to output each line * of text. This uses some extra GIT_DIFF_LINE_... constants for output * of lines of file and hunk headers. */ -typedef int (*git_diff_output_fn)( +typedef int (*git_diff_data_fn)( void *cb_data, + git_diff_delta *delta, + git_diff_range *range, char line_origin, /**< GIT_DIFF_LINE_... value from above */ - const char *formatted_output); - + const char *content, + size_t content_len); /** @name Diff List Generator Functions * @@ -311,7 +308,7 @@ GIT_EXTERN(int) git_diff_foreach( void *cb_data, git_diff_file_fn file_cb, git_diff_hunk_fn hunk_cb, - git_diff_line_fn line_cb); + git_diff_data_fn line_cb); /** * Iterate over a diff generating text output like "git diff --name-status". @@ -319,7 +316,7 @@ GIT_EXTERN(int) git_diff_foreach( GIT_EXTERN(int) git_diff_print_compact( git_diff_list *diff, void *cb_data, - git_diff_output_fn print_cb); + git_diff_data_fn print_cb); /** * Iterate over a diff generating text output like "git diff". @@ -329,7 +326,7 @@ GIT_EXTERN(int) git_diff_print_compact( GIT_EXTERN(int) git_diff_print_patch( git_diff_list *diff, void *cb_data, - git_diff_output_fn print_cb); + git_diff_data_fn print_cb); /**@}*/ @@ -348,7 +345,7 @@ GIT_EXTERN(int) git_diff_blobs( git_diff_options *options, void *cb_data, git_diff_hunk_fn hunk_cb, - git_diff_line_fn line_cb); + git_diff_data_fn line_cb); GIT_END_DECL diff --git a/src/diff_output.c b/src/diff_output.c index 7c5b6f276..a5a11395f 100644 --- a/src/diff_output.c +++ b/src/diff_output.c @@ -18,9 +18,10 @@ typedef struct { git_diff_list *diff; void *cb_data; git_diff_hunk_fn hunk_cb; - git_diff_line_fn line_cb; + git_diff_data_fn line_cb; unsigned int index; git_diff_delta *delta; + git_diff_range range; } diff_output_info; static int read_next_int(const char **str, int *value) @@ -62,6 +63,8 @@ static int diff_output_cb(void *priv, mmbuffer_t *bufs, int len) if (range.old_start < 0 || range.new_start < 0) return -1; + memcpy(&info->range, &range, sizeof(git_diff_range)); + return info->hunk_cb( info->cb_data, info->delta, &range, bufs[0].ptr, bufs[0].size); } @@ -76,7 +79,7 @@ static int diff_output_cb(void *priv, mmbuffer_t *bufs, int len) GIT_DIFF_LINE_CONTEXT; if (info->line_cb( - info->cb_data, info->delta, origin, bufs[1].ptr, bufs[1].size) < 0) + info->cb_data, info->delta, &info->range, origin, bufs[1].ptr, bufs[1].size) < 0) return -1; /* deal with adding and removing newline at EOF */ @@ -87,7 +90,7 @@ static int diff_output_cb(void *priv, mmbuffer_t *bufs, int len) origin = GIT_DIFF_LINE_DEL_EOFNL; return info->line_cb( - info->cb_data, info->delta, origin, bufs[2].ptr, bufs[2].size); + info->cb_data, info->delta, &info->range, origin, bufs[2].ptr, bufs[2].size); } } @@ -291,7 +294,7 @@ int git_diff_foreach( void *data, git_diff_file_fn file_cb, git_diff_hunk_fn hunk_cb, - git_diff_line_fn line_cb) + git_diff_data_fn line_cb) { int error = 0; diff_output_info info; @@ -433,7 +436,7 @@ cleanup: typedef struct { git_diff_list *diff; - git_diff_output_fn print_cb; + git_diff_data_fn print_cb; void *cb_data; git_buf *buf; } diff_print_info; @@ -491,13 +494,13 @@ static int print_compact(void *data, git_diff_delta *delta, float progress) if (git_buf_oom(pi->buf)) return -1; - return pi->print_cb(pi->cb_data, GIT_DIFF_LINE_FILE_HDR, pi->buf->ptr); + return pi->print_cb(pi->cb_data, delta, NULL, GIT_DIFF_LINE_FILE_HDR, git_buf_cstr(pi->buf), git_buf_len(pi->buf)); } int git_diff_print_compact( git_diff_list *diff, void *cb_data, - git_diff_output_fn print_cb) + git_diff_data_fn print_cb) { int error; git_buf buf = GIT_BUF_INIT; @@ -586,7 +589,7 @@ static int print_patch_file(void *data, git_diff_delta *delta, float progress) if (git_buf_oom(pi->buf)) return -1; - result = pi->print_cb(pi->cb_data, GIT_DIFF_LINE_FILE_HDR, pi->buf->ptr); + result = pi->print_cb(pi->cb_data, delta, NULL, GIT_DIFF_LINE_FILE_HDR, git_buf_cstr(pi->buf), git_buf_len(pi->buf)); if (result < 0) return result; @@ -600,7 +603,7 @@ static int print_patch_file(void *data, git_diff_delta *delta, float progress) if (git_buf_oom(pi->buf)) return -1; - return pi->print_cb(pi->cb_data, GIT_DIFF_LINE_BINARY, pi->buf->ptr); + return pi->print_cb(pi->cb_data, delta, NULL, GIT_DIFF_LINE_BINARY, git_buf_cstr(pi->buf), git_buf_len(pi->buf)); } static int print_patch_hunk( @@ -612,27 +615,23 @@ static int print_patch_hunk( { diff_print_info *pi = data; - GIT_UNUSED(d); - GIT_UNUSED(r); - git_buf_clear(pi->buf); if (git_buf_printf(pi->buf, "%.*s", (int)header_len, header) < 0) return -1; - return pi->print_cb(pi->cb_data, GIT_DIFF_LINE_HUNK_HDR, pi->buf->ptr); + return pi->print_cb(pi->cb_data, d, r, GIT_DIFF_LINE_HUNK_HDR, git_buf_cstr(pi->buf), git_buf_len(pi->buf)); } static int print_patch_line( void *data, git_diff_delta *delta, + git_diff_range *range, char line_origin, /* GIT_DIFF_LINE value from above */ const char *content, size_t content_len) { diff_print_info *pi = data; - GIT_UNUSED(delta); - git_buf_clear(pi->buf); if (line_origin == GIT_DIFF_LINE_ADDITION || @@ -645,13 +644,13 @@ static int print_patch_line( if (git_buf_oom(pi->buf)) return -1; - return pi->print_cb(pi->cb_data, line_origin, pi->buf->ptr); + return pi->print_cb(pi->cb_data, delta, range, line_origin, git_buf_cstr(pi->buf), git_buf_len(pi->buf)); } int git_diff_print_patch( git_diff_list *diff, void *cb_data, - git_diff_output_fn print_cb) + git_diff_data_fn print_cb) { int error; git_buf buf = GIT_BUF_INIT; @@ -678,7 +677,7 @@ int git_diff_blobs( git_diff_options *options, void *cb_data, git_diff_hunk_fn hunk_cb, - git_diff_line_fn line_cb) + git_diff_data_fn line_cb) { diff_output_info info; git_diff_delta delta; diff --git a/tests-clar/diff/diff_helpers.c b/tests-clar/diff/diff_helpers.c index c9a633cd0..85dd52601 100644 --- a/tests-clar/diff/diff_helpers.c +++ b/tests-clar/diff/diff_helpers.c @@ -60,12 +60,14 @@ int diff_hunk_fn( int diff_line_fn( void *cb_data, git_diff_delta *delta, + git_diff_range *range, char line_origin, const char *content, size_t content_len) { diff_expects *e = cb_data; (void)delta; + (void)range; (void)content; (void)content_len; e->lines++; diff --git a/tests-clar/diff/diff_helpers.h b/tests-clar/diff/diff_helpers.h index 010d156fa..ca8c40177 100644 --- a/tests-clar/diff/diff_helpers.h +++ b/tests-clar/diff/diff_helpers.h @@ -37,6 +37,7 @@ extern int diff_hunk_fn( extern int diff_line_fn( void *cb_data, git_diff_delta *delta, + git_diff_range *range, char line_origin, const char *content, size_t content_len); diff --git a/tests-clar/diff/patch.c b/tests-clar/diff/patch.c index e2576277f..3da9ce82b 100644 --- a/tests-clar/diff/patch.c +++ b/tests-clar/diff/patch.c @@ -13,26 +13,56 @@ void test_diff_patch__cleanup(void) cl_git_sandbox_cleanup(); } -#define EXPECTED_OUTPUT "diff --git a/subdir.txt b/subdir.txt\n" \ +#define EXPECTED_HEADER "diff --git a/subdir.txt b/subdir.txt\n" \ "deleted file mode 100644\n" \ "index e8ee89e..0000000\n" \ "--- a/subdir.txt\n" \ "+++ /dev/null\n" +#define EXPECTED_HUNK "@@ -1,2 +0,0 @@\n" + static int check_removal_cb( void *cb_data, + git_diff_delta *delta, + git_diff_range *range, char line_origin, - const char *formatted_output) + const char *formatted_output, + size_t output_len) { GIT_UNUSED(cb_data); - if (line_origin != 'F') - return 0; + switch (line_origin) { + case GIT_DIFF_LINE_FILE_HDR: + cl_assert_equal_s(EXPECTED_HEADER, formatted_output); + cl_assert(range == NULL); + goto check_delta; - if (strcmp(EXPECTED_OUTPUT, formatted_output) == 0) - return 0; + case GIT_DIFF_LINE_HUNK_HDR: + cl_assert_equal_s(EXPECTED_HUNK, formatted_output); + /* Fall through */ - return -1; + case GIT_DIFF_LINE_CONTEXT: + case GIT_DIFF_LINE_DELETION: + goto check_range; + + default: + /* unexpected code path */ + return -1; + } + +check_range: + cl_assert(range != NULL); + cl_assert_equal_i(1, range->old_start); + cl_assert_equal_i(2, range->old_lines); + cl_assert_equal_i(0, range->new_start); + cl_assert_equal_i(0, range->new_lines); + +check_delta: + cl_assert_equal_s("subdir.txt", delta->old.path); + cl_assert_equal_s("subdir.txt", delta->new.path); + cl_assert_equal_i(GIT_DELTA_DELETED, delta->status); + + return 0; } void test_diff_patch__can_properly_display_the_removal_of_a_file(void)