Skip to content

Commit 0018da1

Browse files
committed
Merge branch 'jk/diff-compact-heuristic'
Patch output from "git diff" and friends has been tweaked to be more readable by using a blank line as a strong hint that the contents before and after it belong to a logically separate unit. * jk/diff-compact-heuristic: diff: undocument the compaction heuristic knobs for experimentation xdiff: implement empty line chunk heuristic xdiff: add recs_match helper function
2 parents 21b4ae7 + 77085a6 commit 0018da1

File tree

3 files changed

+49
-4
lines changed

3 files changed

+49
-4
lines changed

diff.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#endif
2727

2828
static int diff_detect_rename_default;
29+
static int diff_compaction_heuristic = 1;
2930
static int diff_rename_limit_default = 400;
3031
static int diff_suppress_blank_empty;
3132
static int diff_use_color_default = -1;
@@ -189,6 +190,10 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
189190
diff_detect_rename_default = git_config_rename(var, value);
190191
return 0;
191192
}
193+
if (!strcmp(var, "diff.compactionheuristic")) {
194+
diff_compaction_heuristic = git_config_bool(var, value);
195+
return 0;
196+
}
192197
if (!strcmp(var, "diff.autorefreshindex")) {
193198
diff_auto_refresh_index = git_config_bool(var, value);
194199
return 0;
@@ -3278,6 +3283,8 @@ void diff_setup(struct diff_options *options)
32783283
options->use_color = diff_use_color_default;
32793284
options->detect_rename = diff_detect_rename_default;
32803285
options->xdl_opts |= diff_algorithm;
3286+
if (diff_compaction_heuristic)
3287+
DIFF_XDL_SET(options, COMPACTION_HEURISTIC);
32813288

32823289
options->orderfile = diff_order_file_cfg;
32833290

@@ -3798,6 +3805,10 @@ int diff_opt_parse(struct diff_options *options,
37983805
DIFF_XDL_SET(options, IGNORE_WHITESPACE_AT_EOL);
37993806
else if (!strcmp(arg, "--ignore-blank-lines"))
38003807
DIFF_XDL_SET(options, IGNORE_BLANK_LINES);
3808+
else if (!strcmp(arg, "--compaction-heuristic"))
3809+
DIFF_XDL_SET(options, COMPACTION_HEURISTIC);
3810+
else if (!strcmp(arg, "--no-compaction-heuristic"))
3811+
DIFF_XDL_CLR(options, COMPACTION_HEURISTIC);
38013812
else if (!strcmp(arg, "--patience"))
38023813
options->xdl_opts = DIFF_WITH_ALG(options, PATIENCE_DIFF);
38033814
else if (!strcmp(arg, "--histogram"))

xdiff/xdiff.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ extern "C" {
4141

4242
#define XDF_IGNORE_BLANK_LINES (1 << 7)
4343

44+
#define XDF_COMPACTION_HEURISTIC (1 << 8)
45+
4446
#define XDL_EMIT_FUNCNAMES (1 << 0)
4547
#define XDL_EMIT_FUNCCONTEXT (1 << 2)
4648

xdiff/xdiffi.c

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -400,9 +400,23 @@ static xdchange_t *xdl_add_change(xdchange_t *xscr, long i1, long i2, long chg1,
400400
}
401401

402402

403+
static int is_blank_line(xrecord_t **recs, long ix, long flags)
404+
{
405+
return xdl_blankline(recs[ix]->ptr, recs[ix]->size, flags);
406+
}
407+
408+
static int recs_match(xrecord_t **recs, long ixs, long ix, long flags)
409+
{
410+
return (recs[ixs]->ha == recs[ix]->ha &&
411+
xdl_recmatch(recs[ixs]->ptr, recs[ixs]->size,
412+
recs[ix]->ptr, recs[ix]->size,
413+
flags));
414+
}
415+
403416
int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {
404417
long ix, ixo, ixs, ixref, grpsiz, nrec = xdf->nrec;
405418
char *rchg = xdf->rchg, *rchgo = xdfo->rchg;
419+
unsigned int blank_lines;
406420
xrecord_t **recs = xdf->recs;
407421

408422
/*
@@ -436,14 +450,14 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {
436450

437451
do {
438452
grpsiz = ix - ixs;
453+
blank_lines = 0;
439454

440455
/*
441456
* If the line before the current change group, is equal to
442457
* the last line of the current change group, shift backward
443458
* the group.
444459
*/
445-
while (ixs > 0 && recs[ixs - 1]->ha == recs[ix - 1]->ha &&
446-
xdl_recmatch(recs[ixs - 1]->ptr, recs[ixs - 1]->size, recs[ix - 1]->ptr, recs[ix - 1]->size, flags)) {
460+
while (ixs > 0 && recs_match(recs, ixs - 1, ix - 1, flags)) {
447461
rchg[--ixs] = 1;
448462
rchg[--ix] = 0;
449463

@@ -470,8 +484,9 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {
470484
* the line next of the current change group, shift forward
471485
* the group.
472486
*/
473-
while (ix < nrec && recs[ixs]->ha == recs[ix]->ha &&
474-
xdl_recmatch(recs[ixs]->ptr, recs[ixs]->size, recs[ix]->ptr, recs[ix]->size, flags)) {
487+
while (ix < nrec && recs_match(recs, ixs, ix, flags)) {
488+
blank_lines += is_blank_line(recs, ix, flags);
489+
475490
rchg[ixs++] = 0;
476491
rchg[ix++] = 1;
477492

@@ -498,6 +513,23 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {
498513
rchg[--ix] = 0;
499514
while (rchgo[--ixo]);
500515
}
516+
517+
/*
518+
* If a group can be moved back and forth, see if there is a
519+
* blank line in the moving space. If there is a blank line,
520+
* make sure the last blank line is the end of the group.
521+
*
522+
* As we already shifted the group forward as far as possible
523+
* in the earlier loop, we need to shift it back only if at all.
524+
*/
525+
if ((flags & XDF_COMPACTION_HEURISTIC) && blank_lines) {
526+
while (ixs > 0 &&
527+
!is_blank_line(recs, ix - 1, flags) &&
528+
recs_match(recs, ixs - 1, ix - 1, flags)) {
529+
rchg[--ixs] = 1;
530+
rchg[--ix] = 0;
531+
}
532+
}
501533
}
502534

503535
return 0;

0 commit comments

Comments
 (0)