xdiff: handle appended chunks better with -W

If lines are added at the end of a file, diff -W shows the whole file. That's because get_func_line() only considers the pre-image and gives up if it sees a record index beyond its end. Consider the post-image as well to see if the added lines already make up a full function. If it doesn't then search for the previous function line by starting from the bottom of the pre-image, thereby avoiding to confuse get_func_line(). Reuse the existing label called "again", as it's exactly where we need to jump to when we're done handling the pre-context, but rename it to "post_context_calculation" in order to document its new purpose better. Reported-by: Junio C Hamano <gitster@pobox.com> Initial-patch-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Rene Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

René Scharfe committed May 28, 2016 at 17:00 UTC 6d5badb2389d5d1d0752a230cd7ee74bb4043893
2 files changed +25 -4
t/t4051-diff-function-context.sh
+1 -1
@@ -131,7 +131,7 @@ test_expect_success ' context includes end' '
131 grep "^[+].*End of second part" extended.diff
132 '
133
134 -test_expect_failure ' context does not include other functions' '
134 +test_expect_success ' context does not include other functions' '
135 test $(grep -c "^[ +-].*Begin" extended.diff) -le 2
136 '
137
xdiff/xemit.c
+24 -3
@@ -171,7 +171,28 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
171 s2 = XDL_MAX(xch->i2 - xecfg->ctxlen, 0);
172
173 if (xecfg->flags & XDL_EMIT_FUNCCONTEXT) {
174 - long fs1 = get_func_line(xe, xecfg, NULL, xch->i1, -1);
174 + long fs1, i1 = xch->i1;
175 +
176 + /* Appended chunk? */
177 + if (i1 >= xe->xdf1.nrec) {
178 + char dummy[1];
179 +
180 + /*
181 + * We don't need additional context if
182 + * a whole function was added.
183 + */
184 + if (match_func_rec(&xe->xdf2, xecfg, xch->i2,
185 + dummy, sizeof(dummy)) >= 0)
186 + goto post_context_calculation;
187 +
188 + /*
189 + * Otherwise get more context from the
190 + * pre-image.
191 + */
192 + i1 = xe->xdf1.nrec - 1;
193 + }
194 +
195 + fs1 = get_func_line(xe, xecfg, NULL, i1, -1);
196 if (fs1 < 0)
197 fs1 = 0;
198 if (fs1 < s1) {
@@ -180,7 +201,7 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
201 }
202 }
203
183 - again:
204 + post_context_calculation:
205 lctx = xecfg->ctxlen;
206 lctx = XDL_MIN(lctx, xe->xdf1.nrec - (xche->i1 + xche->chg1));
207 lctx = XDL_MIN(lctx, xe->xdf2.nrec - (xche->i2 + xche->chg2));
@@ -209,7 +230,7 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
230 if (l <= e1 ||
231 get_func_line(xe, xecfg, NULL, l, e1) < 0) {
232 xche = xche->next;
212 - goto again;
233 + goto post_context_calculation;
234 }
235 }
236 }