diff.c: add a blocks mode for moved code detection

The new "blocks" mode provides a middle ground between plain and zebra.
It is as intuitive (few colors) as plain, but still has the requirement
for a minimum of lines/characters to count a block as moved.

Suggested-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
 (https://public-inbox.org/git/87o9j0uljo.fsf@evledraar.gmail.com/)
Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Stefan Beller 2018-07-16 16:05:39 -07:00 committed by Junio C Hamano
parent ee1df66f7c
commit 51da15eb23
4 changed files with 60 additions and 8 deletions

View File

@ -276,10 +276,14 @@ plain::
that are added somewhere else in the diff. This mode picks up any that are added somewhere else in the diff. This mode picks up any
moved line, but it is not very useful in a review to determine moved line, but it is not very useful in a review to determine
if a block of code was moved without permutation. if a block of code was moved without permutation.
zebra:: blocks::
Blocks of moved text of at least 20 alphanumeric characters Blocks of moved text of at least 20 alphanumeric characters
are detected greedily. The detected blocks are are detected greedily. The detected blocks are
painted using either the 'color.diff.{old,new}Moved' color or painted using either the 'color.diff.{old,new}Moved' color.
Adjacent blocks cannot be told apart.
zebra::
Blocks of moved text are detected as in 'blocks' mode. The blocks
are painted using either the 'color.diff.{old,new}Moved' color or
'color.diff.{old,new}MovedAlternative'. The change between 'color.diff.{old,new}MovedAlternative'. The change between
the two colors indicates that a new block was detected. the two colors indicates that a new block was detected.
dimmed_zebra:: dimmed_zebra::

6
diff.c
View File

@ -271,6 +271,8 @@ static int parse_color_moved(const char *arg)
return COLOR_MOVED_NO; return COLOR_MOVED_NO;
else if (!strcmp(arg, "plain")) else if (!strcmp(arg, "plain"))
return COLOR_MOVED_PLAIN; return COLOR_MOVED_PLAIN;
else if (!strcmp(arg, "blocks"))
return COLOR_MOVED_BLOCKS;
else if (!strcmp(arg, "zebra")) else if (!strcmp(arg, "zebra"))
return COLOR_MOVED_ZEBRA; return COLOR_MOVED_ZEBRA;
else if (!strcmp(arg, "default")) else if (!strcmp(arg, "default"))
@ -278,7 +280,7 @@ static int parse_color_moved(const char *arg)
else if (!strcmp(arg, "dimmed_zebra")) else if (!strcmp(arg, "dimmed_zebra"))
return COLOR_MOVED_ZEBRA_DIM; return COLOR_MOVED_ZEBRA_DIM;
else else
return error(_("color moved setting must be one of 'no', 'default', 'zebra', 'dimmed_zebra', 'plain'")); return error(_("color moved setting must be one of 'no', 'default', 'blocks', 'zebra', 'dimmed_zebra', 'plain'"));
} }
int git_diff_ui_config(const char *var, const char *value, void *cb) int git_diff_ui_config(const char *var, const char *value, void *cb)
@ -903,7 +905,7 @@ static void mark_color_as_moved(struct diff_options *o,
block_length++; block_length++;
if (flipped_block) if (flipped_block && o->color_moved != COLOR_MOVED_BLOCKS)
l->flags |= DIFF_SYMBOL_MOVED_LINE_ALT; l->flags |= DIFF_SYMBOL_MOVED_LINE_ALT;
} }
adjust_last_block(o, n, block_length); adjust_last_block(o, n, block_length);

5
diff.h
View File

@ -208,8 +208,9 @@ struct diff_options {
enum { enum {
COLOR_MOVED_NO = 0, COLOR_MOVED_NO = 0,
COLOR_MOVED_PLAIN = 1, COLOR_MOVED_PLAIN = 1,
COLOR_MOVED_ZEBRA = 2, COLOR_MOVED_BLOCKS = 2,
COLOR_MOVED_ZEBRA_DIM = 3, COLOR_MOVED_ZEBRA = 3,
COLOR_MOVED_ZEBRA_DIM = 4,
} color_moved; } color_moved;
#define COLOR_MOVED_DEFAULT COLOR_MOVED_ZEBRA #define COLOR_MOVED_DEFAULT COLOR_MOVED_ZEBRA
#define COLOR_MOVED_MIN_ALNUM_COUNT 20 #define COLOR_MOVED_MIN_ALNUM_COUNT 20

View File

@ -1223,7 +1223,7 @@ test_expect_success 'plain moved code, inside file' '
test_cmp expected actual test_cmp expected actual
' '
test_expect_success 'detect permutations inside moved code -- dimmed_zebra' ' test_expect_success 'detect blocks of moved code' '
git reset --hard && git reset --hard &&
cat <<-\EOF >lines.txt && cat <<-\EOF >lines.txt &&
long line 1 long line 1
@ -1271,6 +1271,50 @@ test_expect_success 'detect permutations inside moved code -- dimmed_zebra' '
test_config color.diff.newMovedDimmed "normal cyan" && test_config color.diff.newMovedDimmed "normal cyan" &&
test_config color.diff.oldMovedAlternativeDimmed "normal blue" && test_config color.diff.oldMovedAlternativeDimmed "normal blue" &&
test_config color.diff.newMovedAlternativeDimmed "normal yellow" && test_config color.diff.newMovedAlternativeDimmed "normal yellow" &&
git diff HEAD --no-renames --color-moved=blocks --color >actual.raw &&
grep -v "index" actual.raw | test_decode_color >actual &&
cat <<-\EOF >expected &&
<BOLD>diff --git a/lines.txt b/lines.txt<RESET>
<BOLD>--- a/lines.txt<RESET>
<BOLD>+++ b/lines.txt<RESET>
<CYAN>@@ -1,16 +1,16 @@<RESET>
<MAGENTA>-long line 1<RESET>
<MAGENTA>-long line 2<RESET>
<MAGENTA>-long line 3<RESET>
line 4<RESET>
line 5<RESET>
line 6<RESET>
line 7<RESET>
line 8<RESET>
line 9<RESET>
<CYAN>+<RESET><CYAN>long line 1<RESET>
<CYAN>+<RESET><CYAN>long line 2<RESET>
<CYAN>+<RESET><CYAN>long line 3<RESET>
<CYAN>+<RESET><CYAN>long line 14<RESET>
<CYAN>+<RESET><CYAN>long line 15<RESET>
<CYAN>+<RESET><CYAN>long line 16<RESET>
line 10<RESET>
line 11<RESET>
line 12<RESET>
line 13<RESET>
<MAGENTA>-long line 14<RESET>
<MAGENTA>-long line 15<RESET>
<MAGENTA>-long line 16<RESET>
EOF
test_cmp expected actual
'
test_expect_success 'detect permutations inside moved code -- dimmed_zebra' '
# reuse setup from test before!
test_config color.diff.oldMoved "magenta" &&
test_config color.diff.newMoved "cyan" &&
test_config color.diff.oldMovedAlternative "blue" &&
test_config color.diff.newMovedAlternative "yellow" &&
test_config color.diff.oldMovedDimmed "normal magenta" &&
test_config color.diff.newMovedDimmed "normal cyan" &&
test_config color.diff.oldMovedAlternativeDimmed "normal blue" &&
test_config color.diff.newMovedAlternativeDimmed "normal yellow" &&
git diff HEAD --no-renames --color-moved=dimmed_zebra --color >actual.raw && git diff HEAD --no-renames --color-moved=dimmed_zebra --color >actual.raw &&
grep -v "index" actual.raw | test_decode_color >actual && grep -v "index" actual.raw | test_decode_color >actual &&
cat <<-\EOF >expected && cat <<-\EOF >expected &&
@ -1669,7 +1713,8 @@ test_expect_success '--color-moved treats adjacent blocks as separate for MIN_AL
7charsA 7charsA
EOF EOF
git diff HEAD --color-moved=zebra --color --no-renames | grep -v "index" | test_decode_color >actual && git diff HEAD --color-moved=zebra --color --no-renames >actual.raw &&
grep -v "index" actual.raw | test_decode_color >actual &&
cat >expected <<-\EOF && cat >expected <<-\EOF &&
<BOLD>diff --git a/bar b/bar<RESET> <BOLD>diff --git a/bar b/bar<RESET>
<BOLD>--- a/bar<RESET> <BOLD>--- a/bar<RESET>