752
const char *line;
753
int len;
754
int flags;
755
+ int indent_off; /* Offset to first non-whitespace character */
756
+ int indent_width; /* The visual width of the indentation */
757
enum diff_symbol s;
758
};
759
#define EMITTED_DIFF_SYMBOL_INIT {NULL}
784
struct moved_entry *next_line;
785
};
786
785
-/**
786
- * The struct ws_delta holds white space differences between moved lines, i.e.
787
- * between '+' and '-' lines that have been detected to be a move.
788
- * The string contains the difference in leading white spaces, before the
789
- * rest of the line is compared using the white space config for move
790
- * coloring. The current_longer indicates if the first string in the
791
- * comparision is longer than the second.
792
- */
793
-struct ws_delta {
794
- char *string;
795
- unsigned int current_longer : 1;
796
-};
797
-#define WS_DELTA_INIT { NULL, 0 }
798
-
787
struct moved_block {
788
struct moved_entry *match;
801
- struct ws_delta wsd;
789
+ int wsd; /* The whitespace delta of this block */
790
};
791
792
static void moved_block_clear(struct moved_block *b)
793
{
806
- FREE_AND_NULL(b->wsd.string);
807
- b->match = NULL;
794
+ memset(b, 0, sizeof(*b));
795
}
796
810
-static int compute_ws_delta(const struct emitted_diff_symbol *a,
811
- const struct emitted_diff_symbol *b,
812
- struct ws_delta *out)
797
+static void fill_es_indent_data(struct emitted_diff_symbol *es)
798
{
814
- const struct emitted_diff_symbol *longer = a->len > b->len ? a : b;
815
- const struct emitted_diff_symbol *shorter = a->len > b->len ? b : a;
816
- int d = longer->len - shorter->len;
799
+ unsigned int off = 0;
800
+ int width = 0, tab_width = es->flags & WS_TAB_WIDTH_MASK;
801
+ const char *s = es->line;
802
+ const int len = es->len;
803
+
804
+ /* skip any \v \f \r at start of indentation */
805
+ while (s[off] == '\f' || s[off] == '\v' ||
806
+ (s[off] == '\r' && off < len - 1))
807
+ off++;
808
+
809
+ /* calculate the visual width of indentation */
810
+ while(1) {
811
+ if (s[off] == ' ') {
812
+ width++;
813
+ off++;
814
+ } else if (s[off] == '\t') {
815
+ width += tab_width - (width % tab_width);
816
+ while (s[++off] == '\t')
817
+ width += tab_width;
818
+ } else {
819
+ break;
820
+ }
821
+ }
822
+
823
+ es->indent_off = off;
824
+ es->indent_width = width;
825
+}
826
+
827
+static int compute_ws_delta(const struct emitted_diff_symbol *a,
828
+ const struct emitted_diff_symbol *b,
829
+ int *out)
830
+{
831
+ int a_len = a->len,
832
+ b_len = b->len,
833
+ a_off = a->indent_off,
834
+ a_width = a->indent_width,
835
+ b_off = b->indent_off,
836
+ b_width = b->indent_width;
837
+ int delta;
838
+
839
+ if (a->s == DIFF_SYMBOL_PLUS)
840
+ delta = a_width - b_width;
841
+ else
842
+ delta = b_width - a_width;
843
818
- if (strncmp(longer->line + d, shorter->line, shorter->len))
844
+ if (a_len - a_off != b_len - b_off ||
845
+ memcmp(a->line + a_off, b->line + b_off, a_len - a_off))
846
return 0;
847
821
- out->string = xmemdupz(longer->line, d);
822
- out->current_longer = (a == longer);
848
+ *out = delta;
849
850
return 1;
851
}
861
const char *a = cur->es->line,
862
*b = match->es->line,
863
*c = l->line;
838
- const char *orig_a = a;
839
- int wslen;
864
+ int a_off = cur->es->indent_off,
865
+ a_width = cur->es->indent_width,
866
+ c_off = l->indent_off,
867
+ c_width = l->indent_width;
868
+ int delta;
869
870
/*
871
* We need to check if 'cur' is equal to 'match'. As those
879
if (al != bl)
880
return 1;
881
853
- if (!pmb->wsd.string)
854
- /*
855
- * The white space delta is not active? This can happen
856
- * when we exit early in this function.
857
- */
858
- return 1;
859
-
882
/*
861
- * The indent changes of the block are known and stored in
862
- * pmb->wsd; however we need to check if the indent changes of the
863
- * current line are still the same as before.
864
- *
865
- * To do so we need to compare 'l' to 'cur', adjusting the
866
- * one of them for the white spaces, depending which was longer.
883
+ * The indent changes of the block are known and stored in pmb->wsd;
884
+ * however we need to check if the indent changes of the current line
885
+ * match those of the current block and that the text of 'l' and 'cur'
886
+ * after the indentation match.
887
*/
888
+ if (cur->es->s == DIFF_SYMBOL_PLUS)
889
+ delta = a_width - c_width;
890
+ else
891
+ delta = c_width - a_width;
892
869
- wslen = strlen(pmb->wsd.string);
870
- if (pmb->wsd.current_longer) {
871
- c += wslen;
872
- cl -= wslen;
873
- } else {
874
- a += wslen;
875
- al -= wslen;
876
- }
877
-
878
- if (al != cl || memcmp(orig_a, b, bl) || memcmp(a, c, al))
879
- return 1;
880
-
881
- return 0;
893
+ return !(delta == pmb->wsd && al - a_off == cl - c_off &&
894
+ !memcmp(a, b, al) && !
895
+ memcmp(a + a_off, c + c_off, al - a_off));
896
}
897
898
static int moved_entry_cmp(const void *hashmap_cmp_fn_data,
958
continue;
959
}
960
961
+ if (o->color_moved_ws_handling &
962
+ COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE)
963
+ fill_es_indent_data(&o->emitted_symbols->buf[n]);
964
key = prepare_entry(o, n);
965
if (prev_line && prev_line->es->s == o->emitted_symbols->buf[n].s)
966
prev_line->next_line = key;
1039
1040
if (lp < pmb_nr && rp > -1 && lp < rp) {
1041
pmb[lp] = pmb[rp];
1025
- pmb[rp].match = NULL;
1026
- pmb[rp].wsd.string = NULL;
1042
+ memset(&pmb[rp], 0, sizeof(pmb[rp]));
1043
rp--;
1044
lp++;
1045
}
1159
&pmb[pmb_nr].wsd))
1160
pmb[pmb_nr++].match = match;
1161
} else {
1146
- pmb[pmb_nr].wsd.string = NULL;
1162
+ pmb[pmb_nr].wsd = 0;
1163
pmb[pmb_nr++].match = match;
1164
}
1165
}
1523
static void emit_diff_symbol(struct diff_options *o, enum diff_symbol s,
1524
const char *line, int len, unsigned flags)
1525
{
1510
- struct emitted_diff_symbol e = {line, len, flags, s};
1526
+ struct emitted_diff_symbol e = {line, len, flags, 0, 0, s};
1527
1528
if (o->emitted_symbols)
1529
append_emitted_diff_symbol(o, &e);