Merge branch 'jk/diff-compact-heuristic'
authorJunio C Hamano <gitster@pobox.com>
Fri, 6 May 2016 21:45:46 +0000 (14:45 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 6 May 2016 21:45:46 +0000 (14:45 -0700)
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

diff.c
xdiff/xdiff.h
xdiff/xdiffi.c
diff --git a/diff.c b/diff.c
index 4dfe6609d059b56c5ab4dd31c8d2139c7fa90abb..d3734d3181b7eebedf80bf6f3d534c61961dca9f 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -26,6 +26,7 @@
 #endif
 
 static int diff_detect_rename_default;
+static int diff_compaction_heuristic = 1;
 static int diff_rename_limit_default = 400;
 static int diff_suppress_blank_empty;
 static int diff_use_color_default = -1;
@@ -189,6 +190,10 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
                diff_detect_rename_default = git_config_rename(var, value);
                return 0;
        }
+       if (!strcmp(var, "diff.compactionheuristic")) {
+               diff_compaction_heuristic = git_config_bool(var, value);
+               return 0;
+       }
        if (!strcmp(var, "diff.autorefreshindex")) {
                diff_auto_refresh_index = git_config_bool(var, value);
                return 0;
@@ -3278,6 +3283,8 @@ void diff_setup(struct diff_options *options)
        options->use_color = diff_use_color_default;
        options->detect_rename = diff_detect_rename_default;
        options->xdl_opts |= diff_algorithm;
+       if (diff_compaction_heuristic)
+               DIFF_XDL_SET(options, COMPACTION_HEURISTIC);
 
        options->orderfile = diff_order_file_cfg;
 
@@ -3798,6 +3805,10 @@ int diff_opt_parse(struct diff_options *options,
                DIFF_XDL_SET(options, IGNORE_WHITESPACE_AT_EOL);
        else if (!strcmp(arg, "--ignore-blank-lines"))
                DIFF_XDL_SET(options, IGNORE_BLANK_LINES);
+       else if (!strcmp(arg, "--compaction-heuristic"))
+               DIFF_XDL_SET(options, COMPACTION_HEURISTIC);
+       else if (!strcmp(arg, "--no-compaction-heuristic"))
+               DIFF_XDL_CLR(options, COMPACTION_HEURISTIC);
        else if (!strcmp(arg, "--patience"))
                options->xdl_opts = DIFF_WITH_ALG(options, PATIENCE_DIFF);
        else if (!strcmp(arg, "--histogram"))
index 4fb7e79410c22fba1fb390af2e09008e932f5ea8..7423f77fc8b2682c121e8d4adb855337e107b29e 100644 (file)
@@ -41,6 +41,8 @@ extern "C" {
 
 #define XDF_IGNORE_BLANK_LINES (1 << 7)
 
+#define XDF_COMPACTION_HEURISTIC (1 << 8)
+
 #define XDL_EMIT_FUNCNAMES (1 << 0)
 #define XDL_EMIT_FUNCCONTEXT (1 << 2)
 
index 2358a2d6326e54308413cb8a5e6b61eba06324e9..b3c684887502c3c473a614114e4acdfbc57ea094 100644 (file)
@@ -400,9 +400,23 @@ static xdchange_t *xdl_add_change(xdchange_t *xscr, long i1, long i2, long chg1,
 }
 
 
+static int is_blank_line(xrecord_t **recs, long ix, long flags)
+{
+       return xdl_blankline(recs[ix]->ptr, recs[ix]->size, flags);
+}
+
+static int recs_match(xrecord_t **recs, long ixs, long ix, long flags)
+{
+       return (recs[ixs]->ha == recs[ix]->ha &&
+               xdl_recmatch(recs[ixs]->ptr, recs[ixs]->size,
+                            recs[ix]->ptr, recs[ix]->size,
+                            flags));
+}
+
 int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {
        long ix, ixo, ixs, ixref, grpsiz, nrec = xdf->nrec;
        char *rchg = xdf->rchg, *rchgo = xdfo->rchg;
+       unsigned int blank_lines;
        xrecord_t **recs = xdf->recs;
 
        /*
@@ -436,14 +450,14 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {
 
                do {
                        grpsiz = ix - ixs;
+                       blank_lines = 0;
 
                        /*
                         * If the line before the current change group, is equal to
                         * the last line of the current change group, shift backward
                         * the group.
                         */
-                       while (ixs > 0 && recs[ixs - 1]->ha == recs[ix - 1]->ha &&
-                              xdl_recmatch(recs[ixs - 1]->ptr, recs[ixs - 1]->size, recs[ix - 1]->ptr, recs[ix - 1]->size, flags)) {
+                       while (ixs > 0 && recs_match(recs, ixs - 1, ix - 1, flags)) {
                                rchg[--ixs] = 1;
                                rchg[--ix] = 0;
 
@@ -470,8 +484,9 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {
                         * the line next of the current change group, shift forward
                         * the group.
                         */
-                       while (ix < nrec && recs[ixs]->ha == recs[ix]->ha &&
-                              xdl_recmatch(recs[ixs]->ptr, recs[ixs]->size, recs[ix]->ptr, recs[ix]->size, flags)) {
+                       while (ix < nrec && recs_match(recs, ixs, ix, flags)) {
+                               blank_lines += is_blank_line(recs, ix, flags);
+
                                rchg[ixs++] = 0;
                                rchg[ix++] = 1;
 
@@ -498,6 +513,23 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {
                        rchg[--ix] = 0;
                        while (rchgo[--ixo]);
                }
+
+               /*
+                * If a group can be moved back and forth, see if there is a
+                * blank line in the moving space. If there is a blank line,
+                * make sure the last blank line is the end of the group.
+                *
+                * As we already shifted the group forward as far as possible
+                * in the earlier loop, we need to shift it back only if at all.
+                */
+               if ((flags & XDF_COMPACTION_HEURISTIC) && blank_lines) {
+                       while (ixs > 0 &&
+                              !is_blank_line(recs, ix - 1, flags) &&
+                              recs_match(recs, ixs - 1, ix - 1, flags)) {
+                               rchg[--ixs] = 1;
+                               rchg[--ix] = 0;
+                       }
+               }
        }
 
        return 0;