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:
commit
9b55aa03da
@ -408,6 +408,10 @@ endif::git-format-patch[]
|
||||
Show the context between diff hunks, up to the specified number
|
||||
of lines, thereby fusing hunks that are close to each other.
|
||||
|
||||
-W::
|
||||
--function-context::
|
||||
Show whole surrounding functions of changes.
|
||||
|
||||
ifndef::git-format-patch[]
|
||||
--exit-code::
|
||||
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.interhunkctxlen = o->interhunkcontext;
|
||||
xecfg.flags = XDL_EMIT_FUNCNAMES;
|
||||
if (DIFF_OPT_TST(o, FUNCCONTEXT))
|
||||
xecfg.flags |= XDL_EMIT_FUNCCONTEXT;
|
||||
if (pe)
|
||||
xdiff_set_find_func(&xecfg, pe->pattern, pe->cflags);
|
||||
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",
|
||||
&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))) {
|
||||
options->file = fopen(optarg, "w");
|
||||
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_OVERRIDE_SUBMODULE_CONFIG (1 << 27)
|
||||
#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_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_COMMON (1 << 1)
|
||||
#define XDL_EMIT_FUNCCONTEXT (1 << 2)
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
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,
|
||||
xdemitconf_t const *xecfg) {
|
||||
long s1, s2, e1, e2, lctx;
|
||||
xdchange_t *xch, *xche;
|
||||
char funcbuf[80];
|
||||
long funclen = 0;
|
||||
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)
|
||||
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);
|
||||
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 = XDL_MIN(lctx, xe->xdf1.nrec - (xche->i1 + xche->chg1));
|
||||
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;
|
||||
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.
|
||||
*/
|
||||
|
||||
if (xecfg->flags & XDL_EMIT_FUNCNAMES) {
|
||||
long l;
|
||||
for (l = s1 - 1; l >= 0 && l > funclineprev; l--) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
get_func_line(xe, xecfg, &func_line,
|
||||
s1 - 1, funclineprev);
|
||||
funclineprev = s1 - 1;
|
||||
}
|
||||
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;
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user