Skip to content

Commit 3ec1909

Browse files
author
Junio C Hamano
committed
combine-diff: better hunk splitting.
It considered an otherwise unchanged line that had line removals in front of it an interesting line, which caused hunks to have one extra the trailing context line. Signed-off-by: Junio C Hamano <junkio@cox.net>
1 parent 8828cdc commit 3ec1909

File tree

1 file changed

+116
-27
lines changed

1 file changed

+116
-27
lines changed

combine-diff.c

Lines changed: 116 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -323,52 +323,141 @@ static unsigned long line_all_diff(struct sline *sline, unsigned long all_mask)
323323
return different;
324324
}
325325

326-
static int make_hunks(struct sline *sline, unsigned long cnt,
327-
int num_parent, int dense)
326+
static unsigned long adjust_hunk_tail(struct sline *sline,
327+
unsigned long all_mask,
328+
unsigned long hunk_begin,
329+
unsigned long i)
330+
{
331+
/* i points at the first uninteresting line.
332+
* If the last line of the hunk was interesting
333+
* only because it has some deletion, then
334+
* it is not all that interesting for the
335+
* purpose of giving trailing context lines.
336+
*/
337+
if ((hunk_begin + 1 <= i) &&
338+
((sline[i-1].flag & all_mask) == all_mask))
339+
i--;
340+
return i;
341+
}
342+
343+
static unsigned long next_interesting(struct sline *sline,
344+
unsigned long mark,
345+
unsigned long i,
346+
unsigned long cnt,
347+
int uninteresting)
348+
{
349+
while (i < cnt)
350+
if (uninteresting ?
351+
!(sline[i].flag & mark) :
352+
(sline[i].flag & mark))
353+
return i;
354+
else
355+
i++;
356+
return cnt;
357+
}
358+
359+
static int give_context(struct sline *sline, unsigned long cnt, int num_parent)
328360
{
329361
unsigned long all_mask = (1UL<<num_parent) - 1;
330362
unsigned long mark = (1UL<<num_parent);
331363
unsigned long i;
332-
int has_interesting = 0;
333364

334-
i = 0;
365+
i = next_interesting(sline, mark, 0, cnt, 0);
366+
if (cnt <= i)
367+
return 0;
368+
335369
while (i < cnt) {
336-
if (interesting(&sline[i], all_mask)) {
337-
unsigned long j = (context < i) ? i - context : 0;
338-
while (j <= i)
370+
unsigned long j = (context < i) ? (i - context) : 0;
371+
unsigned long k;
372+
while (j < i)
373+
sline[j++].flag |= mark;
374+
375+
again:
376+
j = next_interesting(sline, mark, i, cnt, 1);
377+
if (cnt <= j)
378+
break; /* the rest are all interesting */
379+
380+
/* lookahead context lines */
381+
k = next_interesting(sline, mark, j, cnt, 0);
382+
j = adjust_hunk_tail(sline, all_mask, i, j);
383+
384+
if (k < j + context) {
385+
/* k is interesting and [j,k) are not, but
386+
* paint them interesting because the gap is small.
387+
*/
388+
while (j < k)
339389
sline[j++].flag |= mark;
340-
while (++i < cnt) {
341-
if (!interesting(&sline[i], all_mask))
342-
break;
343-
sline[i].flag |= mark;
344-
}
345-
j = (i + context < cnt) ? i + context : cnt;
346-
while (i < j)
347-
sline[i++].flag |= mark;
348-
has_interesting = 1;
349-
continue;
390+
i = k;
391+
goto again;
350392
}
351-
i++;
393+
394+
/* j is the first uninteresting line and there is
395+
* no overlap beyond it within context lines.
396+
*/
397+
i = k;
398+
k = (j + context < cnt) ? j + context : cnt;
399+
while (j < k)
400+
sline[j++].flag |= mark;
401+
}
402+
return 1;
403+
}
404+
405+
static int make_hunks(struct sline *sline, unsigned long cnt,
406+
int num_parent, int dense)
407+
{
408+
unsigned long all_mask = (1UL<<num_parent) - 1;
409+
unsigned long mark = (1UL<<num_parent);
410+
unsigned long i;
411+
int has_interesting = 0;
412+
413+
for (i = 0; i < cnt; i++) {
414+
if (interesting(&sline[i], all_mask))
415+
sline[i].flag |= mark;
416+
else
417+
sline[i].flag &= ~mark;
352418
}
353419
if (!dense)
354-
return has_interesting;
420+
return give_context(sline, cnt, num_parent);
355421

356422
/* Look at each hunk, and if we have changes from only one
357423
* parent, or the changes are the same from all but one
358424
* parent, mark that uninteresting.
359425
*/
360-
has_interesting = 0;
361426
i = 0;
362427
while (i < cnt) {
363-
int j, hunk_end, same, diff;
428+
unsigned long j, hunk_begin, hunk_end;
429+
int same, diff;
364430
unsigned long same_diff, all_diff;
365431
while (i < cnt && !(sline[i].flag & mark))
366432
i++;
367433
if (cnt <= i)
368434
break; /* No more interesting hunks */
369-
for (hunk_end = i + 1; hunk_end < cnt; hunk_end++)
370-
if (!(sline[hunk_end].flag & mark))
371-
break;
435+
hunk_begin = i;
436+
for (j = i + 1; j < cnt; j++) {
437+
if (!(sline[j].flag & mark)) {
438+
/* Look beyond the end to see if there
439+
* is an interesting line after this
440+
* hunk within context span.
441+
*/
442+
unsigned long la; /* lookahead */
443+
int contin = 0;
444+
la = adjust_hunk_tail(sline, all_mask,
445+
hunk_begin, j);
446+
la = (la + context < cnt) ?
447+
(la + context) : cnt;
448+
while (j <= --la) {
449+
if (sline[la].flag & mark) {
450+
contin = 1;
451+
break;
452+
}
453+
}
454+
if (!contin)
455+
break;
456+
j = la;
457+
}
458+
}
459+
hunk_end = j;
460+
372461
/* [i..hunk_end) are interesting. Now does it have
373462
* the same change with all but one parent?
374463
*/
@@ -387,13 +476,13 @@ static int make_hunks(struct sline *sline, unsigned long cnt,
387476
}
388477
if ((num_parent - 1 <= same) || (diff == 1)) {
389478
/* This hunk is not that interesting after all */
390-
for (j = i; j < hunk_end; j++)
479+
for (j = hunk_begin; j < hunk_end; j++)
391480
sline[j].flag &= ~mark;
392481
}
393-
else
394-
has_interesting = 1;
395482
i = hunk_end;
396483
}
484+
485+
has_interesting = give_context(sline, cnt, num_parent);
397486
return has_interesting;
398487
}
399488

0 commit comments

Comments
 (0)