diff --color-moved-ws: handle blank lines

When using --color-moved-ws=allow-indentation-change allow lines with the same indentation change to be grouped across blank lines. For now this only works if the blank lines have been moved as well, not for blocks that have just had their indentation changed. This completes the changes to the implementation of --color-moved=allow-indentation-change. Running git diff --color-moved=allow-indentation-change v2.18.0 v2.19.0 now takes 5.0s. This is a saving of 41% from 8.5s for the optimized version of the previous implementation and 66% from the original which took 14.6s. Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Reviewed-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Phillip Wood committed Nov 23, 2018 at 11:16 UTC 0cd51e9d05e65608126c30fbb65a0cdd197cd570
2 files changed +68 -7
diff.c
+31 -3
@@ -794,9 +794,11 @@ static void moved_block_clear(struct moved_block *b)
794 memset(b, 0, sizeof(*b));
795 }
796
797 +#define INDENT_BLANKLINE INT_MIN
798 +
799 static void fill_es_indent_data(struct emitted_diff_symbol *es)
800 {
799 - unsigned int off = 0;
801 + unsigned int off = 0, i;
802 int width = 0, tab_width = es->flags & WS_TAB_WIDTH_MASK;
803 const char *s = es->line;
804 const int len = es->len;
@@ -820,8 +822,18 @@ static void fill_es_indent_data(struct emitted_diff_symbol *es)
822 }
823 }
824
823 - es->indent_off = off;
824 - es->indent_width = width;
825 + /* check if this line is blank */
826 + for (i = off; i < len; i++)
827 + if (!isspace(s[i]))
828 + break;
829 +
830 + if (i == len) {
831 + es->indent_width = INDENT_BLANKLINE;
832 + es->indent_off = len;
833 + } else {
834 + es->indent_off = off;
835 + es->indent_width = width;
836 + }
837 }
838
839 static int compute_ws_delta(const struct emitted_diff_symbol *a,
@@ -836,6 +848,11 @@ static int compute_ws_delta(const struct emitted_diff_symbol *a,
848 b_width = b->indent_width;
849 int delta;
850
851 + if (a_width == INDENT_BLANKLINE && b_width == INDENT_BLANKLINE) {
852 + *out = INDENT_BLANKLINE;
853 + return 1;
854 + }
855 +
856 if (a->s == DIFF_SYMBOL_PLUS)
857 delta = a_width - b_width;
858 else
@@ -879,6 +896,10 @@ static int cmp_in_block_with_wsd(const struct diff_options *o,
896 if (al != bl)
897 return 1;
898
899 + /* If 'l' and 'cur' are both blank then they match. */
900 + if (a_width == INDENT_BLANKLINE && c_width == INDENT_BLANKLINE)
901 + return 0;
902 +
903 /*
904 * The indent changes of the block are known and stored in pmb->wsd;
905 * however we need to check if the indent changes of the current line
@@ -890,6 +911,13 @@ static int cmp_in_block_with_wsd(const struct diff_options *o,
911 else
912 delta = c_width - a_width;
913
914 + /*
915 + * If the previous lines of this block were all blank then set its
916 + * whitespace delta.
917 + */
918 + if (pmb->wsd == INDENT_BLANKLINE)
919 + pmb->wsd = delta;
920 +
921 return !(delta == pmb->wsd && al - a_off == cl - c_off &&
922 !memcmp(a, b, al) && !
923 memcmp(a + a_off, c + c_off, al - a_off));
t/t4015-diff-whitespace.sh
+37 -4
@@ -1901,10 +1901,20 @@ test_expect_success 'compare whitespace delta incompatible with other space opti
1901 test_i18ngrep allow-indentation-change err
1902 '
1903
1904 +EMPTY=''
1905 test_expect_success 'compare mixed whitespace delta across moved blocks' '
1906
1907 git reset --hard &&
1908 tr Q_ "\t " <<-EOF >text.txt &&
1909 + ${EMPTY}
1910 + ____too short without
1911 + ${EMPTY}
1912 + ___being grouped across blank line
1913 + ${EMPTY}
1914 + context
1915 + lines
1916 + to
1917 + anchor
1918 ____Indented text to
1919 _Q____be further indented by four spaces across
1920 ____Qseveral lines
@@ -1918,9 +1928,18 @@ test_expect_success 'compare mixed whitespace delta across moved blocks' '
1928 git commit -m "add text.txt" &&
1929
1930 tr Q_ "\t " <<-EOF >text.txt &&
1931 + context
1932 + lines
1933 + to
1934 + anchor
1935 QIndented text to
1936 QQbe further indented by four spaces across
1937 Q____several lines
1938 + ${EMPTY}
1939 + QQtoo short without
1940 + ${EMPTY}
1941 + Q_______being grouped across blank line
1942 + ${EMPTY}
1943 Q_QThese two lines have had their
1944 indentation reduced by four spaces
1945 QQdifferent indentation change
@@ -1937,7 +1956,16 @@ test_expect_success 'compare mixed whitespace delta across moved blocks' '
1956 <BOLD>diff --git a/text.txt b/text.txt<RESET>
1957 <BOLD>--- a/text.txt<RESET>
1958 <BOLD>+++ b/text.txt<RESET>
1940 - <CYAN>@@ -1,7 +1,7 @@<RESET>
1959 + <CYAN>@@ -1,16 +1,16 @@<RESET>
1960 + <BOLD;MAGENTA>-<RESET>
1961 + <BOLD;MAGENTA>-<RESET><BOLD;MAGENTA> too short without<RESET>
1962 + <BOLD;MAGENTA>-<RESET>
1963 + <BOLD;MAGENTA>-<RESET><BOLD;MAGENTA> being grouped across blank line<RESET>
1964 + <BOLD;MAGENTA>-<RESET>
1965 + <RESET>context<RESET>
1966 + <RESET>lines<RESET>
1967 + <RESET>to<RESET>
1968 + <RESET>anchor<RESET>
1969 <BOLD;MAGENTA>-<RESET><BOLD;MAGENTA> Indented text to<RESET>
1970 <BOLD;MAGENTA>-<RESET><BRED> <RESET> <BOLD;MAGENTA> be further indented by four spaces across<RESET>
1971 <BOLD;MAGENTA>-<RESET><BRED> <RESET> <BOLD;MAGENTA>several lines<RESET>
@@ -1948,9 +1976,14 @@ test_expect_success 'compare mixed whitespace delta across moved blocks' '
1976 <BOLD;CYAN>+<RESET> <BOLD;CYAN>Indented text to<RESET>
1977 <BOLD;CYAN>+<RESET> <BOLD;CYAN>be further indented by four spaces across<RESET>
1978 <BOLD;CYAN>+<RESET> <BOLD;CYAN> several lines<RESET>
1951 - <BOLD;YELLOW>+<RESET> <BRED> <RESET> <BOLD;YELLOW>These two lines have had their<RESET>
1952 - <BOLD;YELLOW>+<RESET><BOLD;YELLOW>indentation reduced by four spaces<RESET>
1953 - <BOLD;CYAN>+<RESET> <BOLD;CYAN>different indentation change<RESET>
1979 + <BOLD;YELLOW>+<RESET>
1980 + <BOLD;YELLOW>+<RESET> <BOLD;YELLOW>too short without<RESET>
1981 + <BOLD;YELLOW>+<RESET>
1982 + <BOLD;YELLOW>+<RESET> <BOLD;YELLOW> being grouped across blank line<RESET>
1983 + <BOLD;YELLOW>+<RESET>
1984 + <BOLD;CYAN>+<RESET> <BRED> <RESET> <BOLD;CYAN>These two lines have had their<RESET>
1985 + <BOLD;CYAN>+<RESET><BOLD;CYAN>indentation reduced by four spaces<RESET>
1986 + <BOLD;YELLOW>+<RESET> <BOLD;YELLOW>different indentation change<RESET>
1987 <GREEN>+<RESET><BRED> <RESET> <GREEN>too short<RESET>
1988 EOF
1989