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:
Junio C Hamano 2011-10-19 10:49:13 -07:00
commit 9b55aa03da
6 changed files with 175 additions and 16 deletions

View File

@ -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
View File

@ -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
View File

@ -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)

View 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

View File

@ -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)

View File

@ -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;
/*