Merge branch 'rs/diff-whole-function'
* rs/diff-whole-function: diff: add option to show whole functions as context xdiff: factor out get_func_line()
This commit is contained in:
@ -408,6 +408,10 @@ endif::git-format-patch[]
|
|||||||
Show the context between diff hunks, up to the specified number
|
Show the context between diff hunks, up to the specified number
|
||||||
of lines, thereby fusing hunks that are close to each other.
|
of lines, thereby fusing hunks that are close to each other.
|
||||||
|
|
||||||
|
-W::
|
||||||
|
--function-context::
|
||||||
|
Show whole surrounding functions of changes.
|
||||||
|
|
||||||
ifndef::git-format-patch[]
|
ifndef::git-format-patch[]
|
||||||
--exit-code::
|
--exit-code::
|
||||||
Make the program exit with codes similar to diff(1).
|
Make the program exit with codes similar to diff(1).
|
||||||
|
8
diff.c
8
diff.c
@ -2169,6 +2169,8 @@ static void builtin_diff(const char *name_a,
|
|||||||
xecfg.ctxlen = o->context;
|
xecfg.ctxlen = o->context;
|
||||||
xecfg.interhunkctxlen = o->interhunkcontext;
|
xecfg.interhunkctxlen = o->interhunkcontext;
|
||||||
xecfg.flags = XDL_EMIT_FUNCNAMES;
|
xecfg.flags = XDL_EMIT_FUNCNAMES;
|
||||||
|
if (DIFF_OPT_TST(o, FUNCCONTEXT))
|
||||||
|
xecfg.flags |= XDL_EMIT_FUNCCONTEXT;
|
||||||
if (pe)
|
if (pe)
|
||||||
xdiff_set_find_func(&xecfg, pe->pattern, pe->cflags);
|
xdiff_set_find_func(&xecfg, pe->pattern, pe->cflags);
|
||||||
if (!diffopts)
|
if (!diffopts)
|
||||||
@ -3536,6 +3538,12 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
|
|||||||
else if (opt_arg(arg, '\0', "inter-hunk-context",
|
else if (opt_arg(arg, '\0', "inter-hunk-context",
|
||||||
&options->interhunkcontext))
|
&options->interhunkcontext))
|
||||||
;
|
;
|
||||||
|
else if (!strcmp(arg, "-W"))
|
||||||
|
DIFF_OPT_SET(options, FUNCCONTEXT);
|
||||||
|
else if (!strcmp(arg, "--function-context"))
|
||||||
|
DIFF_OPT_SET(options, FUNCCONTEXT);
|
||||||
|
else if (!strcmp(arg, "--no-function-context"))
|
||||||
|
DIFF_OPT_CLR(options, FUNCCONTEXT);
|
||||||
else if ((argcount = parse_long_opt("output", av, &optarg))) {
|
else if ((argcount = parse_long_opt("output", av, &optarg))) {
|
||||||
options->file = fopen(optarg, "w");
|
options->file = fopen(optarg, "w");
|
||||||
if (!options->file)
|
if (!options->file)
|
||||||
|
1
diff.h
1
diff.h
@ -79,6 +79,7 @@ typedef struct strbuf *(*diff_prefix_fn_t)(struct diff_options *opt, void *data)
|
|||||||
#define DIFF_OPT_IGNORE_DIRTY_SUBMODULES (1 << 26)
|
#define DIFF_OPT_IGNORE_DIRTY_SUBMODULES (1 << 26)
|
||||||
#define DIFF_OPT_OVERRIDE_SUBMODULE_CONFIG (1 << 27)
|
#define DIFF_OPT_OVERRIDE_SUBMODULE_CONFIG (1 << 27)
|
||||||
#define DIFF_OPT_DIRSTAT_BY_LINE (1 << 28)
|
#define DIFF_OPT_DIRSTAT_BY_LINE (1 << 28)
|
||||||
|
#define DIFF_OPT_FUNCCONTEXT (1 << 29)
|
||||||
|
|
||||||
#define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag)
|
#define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag)
|
||||||
#define DIFF_OPT_SET(opts, flag) ((opts)->flags |= DIFF_OPT_##flag)
|
#define DIFF_OPT_SET(opts, flag) ((opts)->flags |= DIFF_OPT_##flag)
|
||||||
|
92
t/t4051-diff-function-context.sh
Normal file
92
t/t4051-diff-function-context.sh
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
test_description='diff function context'
|
||||||
|
|
||||||
|
. ./test-lib.sh
|
||||||
|
. "$TEST_DIRECTORY"/diff-lib.sh
|
||||||
|
|
||||||
|
|
||||||
|
cat <<\EOF >hello.c
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
static int a(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Dummy.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hello_world(void)
|
||||||
|
{
|
||||||
|
/* Classic. */
|
||||||
|
printf("Hello world.\n");
|
||||||
|
|
||||||
|
/* Success! */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static int b(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Dummy, too.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
a();
|
||||||
|
b();
|
||||||
|
return hello_world();
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
test_expect_success 'setup' '
|
||||||
|
git add hello.c &&
|
||||||
|
test_tick &&
|
||||||
|
git commit -m initial &&
|
||||||
|
|
||||||
|
grep -v Classic <hello.c >hello.c.new &&
|
||||||
|
mv hello.c.new hello.c
|
||||||
|
'
|
||||||
|
|
||||||
|
cat <<\EOF >expected
|
||||||
|
diff --git a/hello.c b/hello.c
|
||||||
|
--- a/hello.c
|
||||||
|
+++ b/hello.c
|
||||||
|
@@ -10,8 +10,7 @@ static int a(void)
|
||||||
|
static int hello_world(void)
|
||||||
|
{
|
||||||
|
- /* Classic. */
|
||||||
|
printf("Hello world.\n");
|
||||||
|
|
||||||
|
/* Success! */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
test_expect_success 'diff -U0 -W' '
|
||||||
|
git diff -U0 -W >actual &&
|
||||||
|
compare_diff_patch actual expected
|
||||||
|
'
|
||||||
|
|
||||||
|
cat <<\EOF >expected
|
||||||
|
diff --git a/hello.c b/hello.c
|
||||||
|
--- a/hello.c
|
||||||
|
+++ b/hello.c
|
||||||
|
@@ -9,9 +9,8 @@ static int a(void)
|
||||||
|
|
||||||
|
static int hello_world(void)
|
||||||
|
{
|
||||||
|
- /* Classic. */
|
||||||
|
printf("Hello world.\n");
|
||||||
|
|
||||||
|
/* Success! */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
test_expect_success 'diff -W' '
|
||||||
|
git diff -W >actual &&
|
||||||
|
compare_diff_patch actual expected
|
||||||
|
'
|
||||||
|
|
||||||
|
test_done
|
@ -43,6 +43,7 @@ extern "C" {
|
|||||||
|
|
||||||
#define XDL_EMIT_FUNCNAMES (1 << 0)
|
#define XDL_EMIT_FUNCNAMES (1 << 0)
|
||||||
#define XDL_EMIT_COMMON (1 << 1)
|
#define XDL_EMIT_COMMON (1 << 1)
|
||||||
|
#define XDL_EMIT_FUNCCONTEXT (1 << 2)
|
||||||
|
|
||||||
#define XDL_MMB_READONLY (1 << 0)
|
#define XDL_MMB_READONLY (1 << 0)
|
||||||
|
|
||||||
|
@ -100,14 +100,40 @@ static int xdl_emit_common(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct func_line {
|
||||||
|
long len;
|
||||||
|
char buf[80];
|
||||||
|
};
|
||||||
|
|
||||||
|
static long get_func_line(xdfenv_t *xe, xdemitconf_t const *xecfg,
|
||||||
|
struct func_line *func_line, long start, long limit)
|
||||||
|
{
|
||||||
|
find_func_t ff = xecfg->find_func ? xecfg->find_func : def_ff;
|
||||||
|
long l, size, step = (start > limit) ? -1 : 1;
|
||||||
|
char *buf, dummy[1];
|
||||||
|
|
||||||
|
buf = func_line ? func_line->buf : dummy;
|
||||||
|
size = func_line ? sizeof(func_line->buf) : sizeof(dummy);
|
||||||
|
|
||||||
|
for (l = start; l != limit && 0 <= l && l < xe->xdf1.nrec; l += step) {
|
||||||
|
const char *rec;
|
||||||
|
long reclen = xdl_get_rec(&xe->xdf1, l, &rec);
|
||||||
|
long len = ff(rec, reclen, buf, size, xecfg->find_func_priv);
|
||||||
|
if (len >= 0) {
|
||||||
|
if (func_line)
|
||||||
|
func_line->len = len;
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
|
int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
|
||||||
xdemitconf_t const *xecfg) {
|
xdemitconf_t const *xecfg) {
|
||||||
long s1, s2, e1, e2, lctx;
|
long s1, s2, e1, e2, lctx;
|
||||||
xdchange_t *xch, *xche;
|
xdchange_t *xch, *xche;
|
||||||
char funcbuf[80];
|
|
||||||
long funclen = 0;
|
|
||||||
long funclineprev = -1;
|
long funclineprev = -1;
|
||||||
find_func_t ff = xecfg->find_func ? xecfg->find_func : def_ff;
|
struct func_line func_line = { 0 };
|
||||||
|
|
||||||
if (xecfg->flags & XDL_EMIT_COMMON)
|
if (xecfg->flags & XDL_EMIT_COMMON)
|
||||||
return xdl_emit_common(xe, xscr, ecb, xecfg);
|
return xdl_emit_common(xe, xscr, ecb, xecfg);
|
||||||
@ -118,6 +144,17 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
|
|||||||
s1 = XDL_MAX(xch->i1 - xecfg->ctxlen, 0);
|
s1 = XDL_MAX(xch->i1 - xecfg->ctxlen, 0);
|
||||||
s2 = XDL_MAX(xch->i2 - xecfg->ctxlen, 0);
|
s2 = XDL_MAX(xch->i2 - xecfg->ctxlen, 0);
|
||||||
|
|
||||||
|
if (xecfg->flags & XDL_EMIT_FUNCCONTEXT) {
|
||||||
|
long fs1 = get_func_line(xe, xecfg, NULL, xch->i1, -1);
|
||||||
|
if (fs1 < 0)
|
||||||
|
fs1 = 0;
|
||||||
|
if (fs1 < s1) {
|
||||||
|
s2 -= s1 - fs1;
|
||||||
|
s1 = fs1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
again:
|
||||||
lctx = xecfg->ctxlen;
|
lctx = xecfg->ctxlen;
|
||||||
lctx = XDL_MIN(lctx, xe->xdf1.nrec - (xche->i1 + xche->chg1));
|
lctx = XDL_MIN(lctx, xe->xdf1.nrec - (xche->i1 + xche->chg1));
|
||||||
lctx = XDL_MIN(lctx, xe->xdf2.nrec - (xche->i2 + xche->chg2));
|
lctx = XDL_MIN(lctx, xe->xdf2.nrec - (xche->i2 + xche->chg2));
|
||||||
@ -125,27 +162,43 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
|
|||||||
e1 = xche->i1 + xche->chg1 + lctx;
|
e1 = xche->i1 + xche->chg1 + lctx;
|
||||||
e2 = xche->i2 + xche->chg2 + lctx;
|
e2 = xche->i2 + xche->chg2 + lctx;
|
||||||
|
|
||||||
|
if (xecfg->flags & XDL_EMIT_FUNCCONTEXT) {
|
||||||
|
long fe1 = get_func_line(xe, xecfg, NULL,
|
||||||
|
xche->i1 + xche->chg1,
|
||||||
|
xe->xdf1.nrec);
|
||||||
|
if (fe1 < 0)
|
||||||
|
fe1 = xe->xdf1.nrec;
|
||||||
|
if (fe1 > e1) {
|
||||||
|
e2 += fe1 - e1;
|
||||||
|
e1 = fe1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Overlap with next change? Then include it
|
||||||
|
* in the current hunk and start over to find
|
||||||
|
* its new end.
|
||||||
|
*/
|
||||||
|
if (xche->next) {
|
||||||
|
long l = xche->next->i1;
|
||||||
|
if (l <= e1 ||
|
||||||
|
get_func_line(xe, xecfg, NULL, l, e1) < 0) {
|
||||||
|
xche = xche->next;
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Emit current hunk header.
|
* Emit current hunk header.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (xecfg->flags & XDL_EMIT_FUNCNAMES) {
|
if (xecfg->flags & XDL_EMIT_FUNCNAMES) {
|
||||||
long l;
|
get_func_line(xe, xecfg, &func_line,
|
||||||
for (l = s1 - 1; l >= 0 && l > funclineprev; l--) {
|
s1 - 1, funclineprev);
|
||||||
const char *rec;
|
|
||||||
long reclen = xdl_get_rec(&xe->xdf1, l, &rec);
|
|
||||||
long newfunclen = ff(rec, reclen, funcbuf,
|
|
||||||
sizeof(funcbuf),
|
|
||||||
xecfg->find_func_priv);
|
|
||||||
if (newfunclen >= 0) {
|
|
||||||
funclen = newfunclen;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
funclineprev = s1 - 1;
|
funclineprev = s1 - 1;
|
||||||
}
|
}
|
||||||
if (xdl_emit_hunk_hdr(s1 + 1, e1 - s1, s2 + 1, e2 - s2,
|
if (xdl_emit_hunk_hdr(s1 + 1, e1 - s1, s2 + 1, e2 - s2,
|
||||||
funcbuf, funclen, ecb) < 0)
|
func_line.buf, func_line.len, ecb) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Reference in New Issue
Block a user