From f99f4b3667a83f870565bb140711f0e585999108 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= Date: Sun, 9 Oct 2011 13:34:49 +0200 Subject: xdiff: factor out get_func_line() Move the code to search for a function line to be shown in the hunk header into its own function and to make returning the length-limited result string easier, introduce struct func_line. Signed-off-by: Rene Scharfe Signed-off-by: Junio C Hamano --- xdiff/xemit.c | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) (limited to 'xdiff') diff --git a/xdiff/xemit.c b/xdiff/xemit.c index 277e2eec5b..64eb17a463 100644 --- a/xdiff/xemit.c +++ b/xdiff/xemit.c @@ -100,14 +100,35 @@ 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 void 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 = sizeof(func_line->buf); + char *buf = func_line->buf; + + for (l = start; l > limit && 0 <= l; l--) { + 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) { + func_line->len = len; + break; + } + } +} + 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); @@ -130,22 +151,12 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, */ 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; /* -- cgit v1.2.3 From 14937c2c06e63f93f65e1bc6693b95d4e54053d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= Date: Sun, 9 Oct 2011 13:36:57 +0200 Subject: diff: add option to show whole functions as context Add the option -W/--function-context to git diff. It is similar to the same option of git grep and expands the context of change hunks so that the whole surrounding function is shown. This "natural" context can allow changes to be understood better. Note: GNU patch doesn't like diffs generated with the new option; it seems to expect context lines to be the same before and after changes. git apply doesn't complain. This implementation has the same shortcoming as the one in grep, namely that there is no way to explicitly find the end of a function. That means that a few lines of extra context are shown, right up to the next recognized function begins. It's already useful in its current form, though. The function get_func_line() in xdiff/xemit.c is extended to work forward as well as backward to find post-context as well as pre-context. It returns the position of the first found matching line. The func_line parameter is made optional, as we don't need it for -W. The enhanced function is then used in xdl_emit_diff() to extend the context as needed. If the added context overlaps with the next change, it is merged into the current hunk. Signed-off-by: Rene Scharfe Signed-off-by: Junio C Hamano --- xdiff/xdiff.h | 1 + xdiff/xemit.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 49 insertions(+), 6 deletions(-) (limited to 'xdiff') diff --git a/xdiff/xdiff.h b/xdiff/xdiff.h index 4beb10c678..00d36c3ac7 100644 --- a/xdiff/xdiff.h +++ b/xdiff/xdiff.h @@ -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) diff --git a/xdiff/xemit.c b/xdiff/xemit.c index 64eb17a463..2e669c3e25 100644 --- a/xdiff/xemit.c +++ b/xdiff/xemit.c @@ -105,22 +105,27 @@ struct func_line { char buf[80]; }; -static void get_func_line(xdfenv_t *xe, xdemitconf_t const *xecfg, +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 = sizeof(func_line->buf); - char *buf = func_line->buf; + long l, size, step = (start > limit) ? -1 : 1; + char *buf, dummy[1]; - for (l = start; l > limit && 0 <= l; l--) { + 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) { - func_line->len = len; - break; + if (func_line) + func_line->len = len; + return l; } } + return -1; } int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, @@ -139,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)); @@ -146,6 +162,32 @@ 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. */ -- cgit v1.2.3