@matheusbsbs / matheus-bagliano / commits / 4297c0aeb5
Fork 0

Make --color-words work well with --graph

'--color-words' algorithm can be described as: 1. collect a the minus/plus lines of a diff hunk, divided into minus-lines and plus-lines; 2. break both minus-lines and plus-lines into words and place them into two mmfile_t with one word for each line; 3. use xdiff to run diff on the two mmfile_t to get the words level diff; And for the common parts of the both file, we output the plus side text. diff_words->current_plus is used to trace the current position of the plus file which printed. diff_words->last_minus is used to trace the last minus word printed. For '--graph' to work with '--color-words', we need to output the graph prefix on each line of color words output. Generally, there are two conditions on which we should output the prefix. 1. diff_words->last_minus == 0 && diff_words->current_plus == diff_words->plus.text.ptr that is: the plus text must start as a new line, and if there is no minus word printed, a graph prefix must be printed. 2. diff_words->current_plus > diff_words->plus.text.ptr && *(diff_words->current_plus - 1) == '\n' that is: a graph prefix must be printed following a '\n' Signed-off-by: Bo Yang <struggleyb.nku@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Bo Yang committed May 29, 2010 at 23:32 UTC 4297c0aeb5cc6b9c1c87d770c91e09ac2a837320
1 file changed +104 -17
diff.c
+104 -17
@@ -622,7 +622,8 @@ struct diff_words_style diff_words_styles[] = {
622 struct diff_words_data {
623 struct diff_words_buffer minus, plus;
624 const char *current_plus;
625 - FILE *file;
625 + int last_minus;
626 + struct diff_options *opt;
627 regex_t *word_regex;
628 enum diff_words_type type;
629 struct diff_words_style *style;
@@ -631,10 +632,15 @@ struct diff_words_data {
632 static int fn_out_diff_words_write_helper(FILE *fp,
633 struct diff_words_style_elem *st_el,
634 const char *newline,
634 - size_t count, const char *buf)
635 + size_t count, const char *buf,
636 + const char *line_prefix)
637 {
638 + int print = 0;
639 +
640 while (count) {
641 char *p = memchr(buf, '\n', count);
642 + if (print)
643 + fputs(line_prefix, fp);
644 if (p != buf) {
645 if (st_el->color && fputs(st_el->color, fp) < 0)
646 return -1;
@@ -652,21 +658,74 @@ static int fn_out_diff_words_write_helper(FILE *fp,
658 return -1;
659 count -= p + 1 - buf;
660 buf = p + 1;
661 + print = 1;
662 }
663 return 0;
664 }
665
666 +/*
667 + * '--color-words' algorithm can be described as:
668 + *
669 + * 1. collect a the minus/plus lines of a diff hunk, divided into
670 + * minus-lines and plus-lines;
671 + *
672 + * 2. break both minus-lines and plus-lines into words and
673 + * place them into two mmfile_t with one word for each line;
674 + *
675 + * 3. use xdiff to run diff on the two mmfile_t to get the words level diff;
676 + *
677 + * And for the common parts of the both file, we output the plus side text.
678 + * diff_words->current_plus is used to trace the current position of the plus file
679 + * which printed. diff_words->last_minus is used to trace the last minus word
680 + * printed.
681 + *
682 + * For '--graph' to work with '--color-words', we need to output the graph prefix
683 + * on each line of color words output. Generally, there are two conditions on
684 + * which we should output the prefix.
685 + *
686 + * 1. diff_words->last_minus == 0 &&
687 + * diff_words->current_plus == diff_words->plus.text.ptr
688 + *
689 + * that is: the plus text must start as a new line, and if there is no minus
690 + * word printed, a graph prefix must be printed.
691 + *
692 + * 2. diff_words->current_plus > diff_words->plus.text.ptr &&
693 + * *(diff_words->current_plus - 1) == '\n'
694 + *
695 + * that is: a graph prefix must be printed following a '\n'
696 + */
697 +static int color_words_output_graph_prefix(struct diff_words_data *diff_words)
698 +{
699 + if ((diff_words->last_minus == 0 &&
700 + diff_words->current_plus == diff_words->plus.text.ptr) ||
701 + (diff_words->current_plus > diff_words->plus.text.ptr &&
702 + *(diff_words->current_plus - 1) == '\n')) {
703 + return 1;
704 + } else {
705 + return 0;
706 + }
707 +}
708 +
709 static void fn_out_diff_words_aux(void *priv, char *line, unsigned long len)
710 {
711 struct diff_words_data *diff_words = priv;
712 struct diff_words_style *style = diff_words->style;
713 int minus_first, minus_len, plus_first, plus_len;
714 const char *minus_begin, *minus_end, *plus_begin, *plus_end;
715 + struct diff_options *opt = diff_words->opt;
716 + struct strbuf *msgbuf;
717 + char *line_prefix = "";
718
719 if (line[0] != '@' || parse_hunk_header(line, len,
720 &minus_first, &minus_len, &plus_first, &plus_len))
721 return;
722
723 + assert(opt);
724 + if (opt->output_prefix) {
725 + msgbuf = opt->output_prefix(opt, opt->output_prefix_data);
726 + line_prefix = msgbuf->buf;
727 + }
728 +
729 /* POSIX requires that first be decremented by one if len == 0... */
730 if (minus_len) {
731 minus_begin = diff_words->minus.orig[minus_first].begin;
@@ -682,21 +741,32 @@ static void fn_out_diff_words_aux(void *priv, char *line, unsigned long len)
741 } else
742 plus_begin = plus_end = diff_words->plus.orig[plus_first].end;
743
685 - if (diff_words->current_plus != plus_begin)
686 - fn_out_diff_words_write_helper(diff_words->file,
744 + if (color_words_output_graph_prefix(diff_words)) {
745 + fputs(line_prefix, diff_words->opt->file);
746 + }
747 + if (diff_words->current_plus != plus_begin) {
748 + fn_out_diff_words_write_helper(diff_words->opt->file,
749 &style->ctx, style->newline,
750 plus_begin - diff_words->current_plus,
689 - diff_words->current_plus);
690 - if (minus_begin != minus_end)
691 - fn_out_diff_words_write_helper(diff_words->file,
751 + diff_words->current_plus, line_prefix);
752 + if (*(plus_begin - 1) == '\n')
753 + fputs(line_prefix, diff_words->opt->file);
754 + }
755 + if (minus_begin != minus_end) {
756 + fn_out_diff_words_write_helper(diff_words->opt->file,
757 &style->old, style->newline,
693 - minus_end - minus_begin, minus_begin);
694 - if (plus_begin != plus_end)
695 - fn_out_diff_words_write_helper(diff_words->file,
758 + minus_end - minus_begin, minus_begin,
759 + line_prefix);
760 + }
761 + if (plus_begin != plus_end) {
762 + fn_out_diff_words_write_helper(diff_words->opt->file,
763 &style->new, style->newline,
697 - plus_end - plus_begin, plus_begin);
764 + plus_end - plus_begin, plus_begin,
765 + line_prefix);
766 + }
767
768 diff_words->current_plus = plus_end;
769 + diff_words->last_minus = minus_first;
770 }
771
772 /* This function starts looking at *begin, and returns 0 iff a word was found. */
@@ -777,16 +847,29 @@ static void diff_words_show(struct diff_words_data *diff_words)
847 mmfile_t minus, plus;
848 struct diff_words_style *style = diff_words->style;
849
850 + struct diff_options *opt = diff_words->opt;
851 + struct strbuf *msgbuf;
852 + char *line_prefix = "";
853 +
854 + assert(opt);
855 + if (opt->output_prefix) {
856 + msgbuf = opt->output_prefix(opt, opt->output_prefix_data);
857 + line_prefix = msgbuf->buf;
858 + }
859 +
860 /* special case: only removal */
861 if (!diff_words->plus.text.size) {
782 - fn_out_diff_words_write_helper(diff_words->file,
862 + fputs(line_prefix, diff_words->opt->file);
863 + fn_out_diff_words_write_helper(diff_words->opt->file,
864 &style->old, style->newline,
784 - diff_words->minus.text.size, diff_words->minus.text.ptr);
865 + diff_words->minus.text.size,
866 + diff_words->minus.text.ptr, line_prefix);
867 diff_words->minus.text.size = 0;
868 return;
869 }
870
871 diff_words->current_plus = diff_words->plus.text.ptr;
872 + diff_words->last_minus = 0;
873
874 memset(&xpp, 0, sizeof(xpp));
875 memset(&xecfg, 0, sizeof(xecfg));
@@ -800,11 +883,15 @@ static void diff_words_show(struct diff_words_data *diff_words)
883 free(minus.ptr);
884 free(plus.ptr);
885 if (diff_words->current_plus != diff_words->plus.text.ptr +
803 - diff_words->plus.text.size)
804 - fn_out_diff_words_write_helper(diff_words->file,
886 + diff_words->plus.text.size) {
887 + if (color_words_output_graph_prefix(diff_words))
888 + fputs(line_prefix, diff_words->opt->file);
889 + fn_out_diff_words_write_helper(diff_words->opt->file,
890 &style->ctx, style->newline,
891 diff_words->plus.text.ptr + diff_words->plus.text.size
807 - - diff_words->current_plus, diff_words->current_plus);
892 + - diff_words->current_plus, diff_words->current_plus,
893 + line_prefix);
894 + }
895 diff_words->minus.text.size = diff_words->plus.text.size = 0;
896 }
897
@@ -1902,8 +1989,8 @@ static void builtin_diff(const char *name_a,
1989
1990 ecbdata.diff_words =
1991 xcalloc(1, sizeof(struct diff_words_data));
1905 - ecbdata.diff_words->file = o->file;
1992 ecbdata.diff_words->type = o->word_diff;
1993 + ecbdata.diff_words->opt = o;
1994 if (!o->word_regex)
1995 o->word_regex = userdiff_word_regex(one);
1996 if (!o->word_regex)