{"thread":{"id":"23939","subject":"Re: [PATCH v4 6/6] Make --color-words work well with --graph","startedAt":"2010-05-29T15:32:05Z","lastAt":"2010-05-29T15:32:06Z","messageCount":2,"participants":["Bo Yang"],"isPatch":true,"patchVersion":4,"patchTotal":6},"messages":[{"id":"142538","messageId":"1275147126-16784-1-git-send-email-struggleyb.nku@gmail.com","threadId":"23939","inReplyTo":null,"subject":"Re: [PATCH v4 4/6] Emit a whole line in one go","fromName":"Bo Yang","fromEmail":"struggleyb.nku@gmail.com","sentAt":"2010-05-29T15:32:05Z","receivedAt":"2010-05-29T15:32:05Z","isPatch":true,"sender":{"key":"struggleyb.nku@gmail.com","avatar":"https://avatars.githubusercontent.com/u/233030?v=4"},"body":"Since the graph prefix will be printed when calling\nemit_line, so the functions should be used to emit a\ncomplete line out once a time. No one should call\nemit_line to just output some strings instead of a\ncomplete line.\nUse a strbuf to compose the whole line, and then\ncall emit_line to output it once.\n\nSigned-off-by: Bo Yang <struggleyb.nku@gmail.com>\n---\n diff.c |   34 +++++++++++++++++++++++++++++-----\n 1 files changed, 29 insertions(+), 5 deletions(-)\n\ndiff --git a/diff.c b/diff.c\nindex 7f2538d..8b738f0 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -370,6 +370,9 @@ static void emit_hunk_header(struct emit_callback *ecbdata,\n \tconst char *reset = diff_get_color(ecbdata->color_diff, DIFF_RESET);\n \tstatic const char atat[2] = { '@', '@' };\n \tconst char *cp, *ep;\n+\tstruct strbuf msgbuf = STRBUF_INIT;\n+\tint org_len = len;\n+\tint i = 1;\n \n \t/*\n \t * As a hunk header must begin with \"@@ -<old>, +<new> @@\",\n@@ -384,17 +387,38 @@ static void emit_hunk_header(struct emit_callback *ecbdata,\n \tep += 2; /* skip over @@ */\n \n \t/* The hunk header in fraginfo color */\n-\temit_line(ecbdata->opt, frag, reset, line, ep - line);\n+\tstrbuf_add(&msgbuf, frag, strlen(frag));\n+\tstrbuf_add(&msgbuf, line, ep - line);\n+\tstrbuf_add(&msgbuf, reset, strlen(reset));\n+\n+\t/*\n+\t * trailing \\r\\n\n+\t */\n+\tfor (; i < 3; i++) {\n+\t\tif (line[len - i] == '\\r' || line[len - i] == '\\n') {\n+\t\t\tlen --;\n+\t\t}\n+\t}\n \n \t/* blank before the func header */\n \tfor (cp = ep; ep - line < len; ep++)\n \t\tif (*ep != ' ' && *ep != '\\t')\n \t\t\tbreak;\n-\tif (ep != cp)\n-\t\temit_line(ecbdata->opt, plain, reset, cp, ep - cp);\n+\tif (ep != cp) {\n+\t\tstrbuf_add(&msgbuf, plain, strlen(plain));\n+\t\tstrbuf_add(&msgbuf, cp, ep - cp);\n+\t\tstrbuf_add(&msgbuf, reset, strlen(reset));\n+\t}\n+\n+\tif (ep < line + len) {\n+\t\tstrbuf_add(&msgbuf, func, strlen(func));\n+\t\tstrbuf_add(&msgbuf, ep, line + len - ep);\n+\t\tstrbuf_add(&msgbuf, reset, strlen(reset));\n+\t}\n \n-\tif (ep < line + len)\n-\t\temit_line(ecbdata->opt, func, reset, ep, line + len - ep);\n+\tstrbuf_add(&msgbuf, line + len, org_len - len);\n+\temit_line(ecbdata->opt, \"\", \"\", msgbuf.buf, msgbuf.len);\n+\tstrbuf_release(&msgbuf);\n }\n \n static struct diff_tempfile *claim_diff_tempfile(void) {\n-- \n1.7.0.2.273.gc2413.dirty\n"},{"id":"142537","messageId":"1275147126-16784-2-git-send-email-struggleyb.nku@gmail.com","threadId":"23939","inReplyTo":"1275147126-16784-1-git-send-email-struggleyb.nku@gmail.com","subject":"Re: [PATCH v4 6/6] Make --color-words work well with --graph","fromName":"Bo Yang","fromEmail":"struggleyb.nku@gmail.com","sentAt":"2010-05-29T15:32:06Z","receivedAt":"2010-05-29T15:32:06Z","isPatch":true,"sender":{"key":"struggleyb.nku@gmail.com","avatar":"https://avatars.githubusercontent.com/u/233030?v=4"},"body":"'--color-words' algorithm can be described as:\n\n  1. collect a the minus/plus lines of a diff hunk, divided into\n     minus-lines and plus-lines;\n\n  2. break both minus-lines and plus-lines into words and\n     place them into two mmfile_t with one word for each line;\n\n  3. use xdiff to run diff on the two mmfile_t to get the words level diff;\n\nAnd for the common parts of the both file, we output the plus side text.\ndiff_words->current_plus is used to trace the current position of the plus file\nwhich printed. diff_words->last_minus is used to trace the last minus word\nprinted.\n\nFor '--graph' to work with '--color-words', we need to output the graph prefix\non each line of color words output. Generally, there are two conditions on\nwhich we should output the prefix.\n\n  1. diff_words->last_minus == 0 &&\n     diff_words->current_plus == diff_words->plus.text.ptr\n\n     that is: the plus text must start as a new line, and if there is no minus\n     word printed, a graph prefix must be printed.\n\n  2. diff_words->current_plus > diff_words->plus.text.ptr &&\n     *(diff_words->current_plus - 1) == '\\n'\n\n     that is: a graph prefix must be printed following a '\\n'\n\nSigned-off-by: Bo Yang <struggleyb.nku@gmail.com>\n---\n diff.c |  121 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---------\n 1 files changed, 104 insertions(+), 17 deletions(-)\n\ndiff --git a/diff.c b/diff.c\nindex 8b738f0..030fceb 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -624,7 +624,8 @@ struct diff_words_style diff_words_styles[] = {\n struct diff_words_data {\n \tstruct diff_words_buffer minus, plus;\n \tconst char *current_plus;\n-\tFILE *file;\n+\tint last_minus;\n+\tstruct diff_options *opt;\n \tregex_t *word_regex;\n \tenum diff_words_type type;\n \tstruct diff_words_style *style;\n@@ -633,10 +634,15 @@ struct diff_words_data {\n static int fn_out_diff_words_write_helper(FILE *fp,\n \t\t\t\t\t  struct diff_words_style_elem *st_el,\n \t\t\t\t\t  const char *newline,\n-\t\t\t\t\t  size_t count, const char *buf)\n+\t\t\t\t\t  size_t count, const char *buf,\n+\t\t\t\t\t  const char *line_prefix)\n {\n+\tint print = 0;\n+\n \twhile (count) {\n \t\tchar *p = memchr(buf, '\\n', count);\n+\t\tif (print)\n+\t\t\tfputs(line_prefix, fp);\n \t\tif (p != buf) {\n \t\t\tif (st_el->color && fputs(st_el->color, fp) < 0)\n \t\t\t\treturn -1;\n@@ -654,21 +660,74 @@ static int fn_out_diff_words_write_helper(FILE *fp,\n \t\t\treturn -1;\n \t\tcount -= p + 1 - buf;\n \t\tbuf = p + 1;\n+\t\tprint = 1;\n \t}\n \treturn 0;\n }\n \n+/*\n+ * '--color-words' algorithm can be described as:\n+ *\n+ *   1. collect a the minus/plus lines of a diff hunk, divided into\n+ *      minus-lines and plus-lines;\n+ *\n+ *   2. break both minus-lines and plus-lines into words and\n+ *      place them into two mmfile_t with one word for each line;\n+ *\n+ *   3. use xdiff to run diff on the two mmfile_t to get the words level diff;\n+ *\n+ * And for the common parts of the both file, we output the plus side text.\n+ * diff_words->current_plus is used to trace the current position of the plus file\n+ * which printed. diff_words->last_minus is used to trace the last minus word\n+ * printed.\n+ *\n+ * For '--graph' to work with '--color-words', we need to output the graph prefix\n+ * on each line of color words output. Generally, there are two conditions on\n+ * which we should output the prefix.\n+ *\n+ *   1. diff_words->last_minus == 0 &&\n+ *      diff_words->current_plus == diff_words->plus.text.ptr\n+ *\n+ *      that is: the plus text must start as a new line, and if there is no minus\n+ *      word printed, a graph prefix must be printed.\n+ *\n+ *   2. diff_words->current_plus > diff_words->plus.text.ptr &&\n+ *      *(diff_words->current_plus - 1) == '\\n'\n+ *\n+ *      that is: a graph prefix must be printed following a '\\n'\n+ */\n+static int color_words_output_graph_prefix(struct diff_words_data *diff_words)\n+{\n+\tif ((diff_words->last_minus == 0 &&\n+\t\tdiff_words->current_plus == diff_words->plus.text.ptr) ||\n+\t\t(diff_words->current_plus > diff_words->plus.text.ptr &&\n+\t\t*(diff_words->current_plus - 1) == '\\n')) {\n+\t\treturn 1;\n+\t} else {\n+\t\treturn 0;\n+\t}\n+}\n+\n static void fn_out_diff_words_aux(void *priv, char *line, unsigned long len)\n {\n \tstruct diff_words_data *diff_words = priv;\n \tstruct diff_words_style *style = diff_words->style;\n \tint minus_first, minus_len, plus_first, plus_len;\n \tconst char *minus_begin, *minus_end, *plus_begin, *plus_end;\n+\tstruct diff_options *opt = diff_words->opt;\n+\tstruct strbuf *msgbuf;\n+\tchar *line_prefix = \"\";\n \n \tif (line[0] != '@' || parse_hunk_header(line, len,\n \t\t\t&minus_first, &minus_len, &plus_first, &plus_len))\n \t\treturn;\n \n+\tassert(opt);\n+\tif (opt->output_prefix) {\n+\t\tmsgbuf = opt->output_prefix(opt, opt->output_prefix_data);\n+\t\tline_prefix = msgbuf->buf;\n+\t}\n+\n \t/* POSIX requires that first be decremented by one if len == 0... */\n \tif (minus_len) {\n \t\tminus_begin = diff_words->minus.orig[minus_first].begin;\n@@ -684,21 +743,32 @@ static void fn_out_diff_words_aux(void *priv, char *line, unsigned long len)\n \t} else\n \t\tplus_begin = plus_end = diff_words->plus.orig[plus_first].end;\n \n-\tif (diff_words->current_plus != plus_begin)\n-\t\tfn_out_diff_words_write_helper(diff_words->file,\n+\tif (color_words_output_graph_prefix(diff_words)) {\n+\t\tfputs(line_prefix, diff_words->opt->file);\n+\t}\n+\tif (diff_words->current_plus != plus_begin) {\n+\t\tfn_out_diff_words_write_helper(diff_words->opt->file,\n \t\t\t\t&style->ctx, style->newline,\n \t\t\t\tplus_begin - diff_words->current_plus,\n-\t\t\t\tdiff_words->current_plus);\n-\tif (minus_begin != minus_end)\n-\t\tfn_out_diff_words_write_helper(diff_words->file,\n+\t\t\t\tdiff_words->current_plus, line_prefix);\n+\t\tif (*(plus_begin - 1) == '\\n')\n+\t\t\tfputs(line_prefix, diff_words->opt->file);\n+\t}\n+\tif (minus_begin != minus_end) {\n+\t\tfn_out_diff_words_write_helper(diff_words->opt->file,\n \t\t\t\t&style->old, style->newline,\n-\t\t\t\tminus_end - minus_begin, minus_begin);\n-\tif (plus_begin != plus_end)\n-\t\tfn_out_diff_words_write_helper(diff_words->file,\n+\t\t\t\tminus_end - minus_begin, minus_begin,\n+\t\t\t\tline_prefix);\n+\t}\n+\tif (plus_begin != plus_end) {\n+\t\tfn_out_diff_words_write_helper(diff_words->opt->file,\n \t\t\t\t&style->new, style->newline,\n-\t\t\t\tplus_end - plus_begin, plus_begin);\n+\t\t\t\tplus_end - plus_begin, plus_begin,\n+\t\t\t\tline_prefix);\n+\t}\n \n \tdiff_words->current_plus = plus_end;\n+\tdiff_words->last_minus = minus_first;\n }\n \n /* This function starts looking at *begin, and returns 0 iff a word was found. */\n@@ -779,16 +849,29 @@ static void diff_words_show(struct diff_words_data *diff_words)\n \tmmfile_t minus, plus;\n \tstruct diff_words_style *style = diff_words->style;\n \n+\tstruct diff_options *opt = diff_words->opt;\n+\tstruct strbuf *msgbuf;\n+\tchar *line_prefix = \"\";\n+\n+\tassert(opt);\n+\tif (opt->output_prefix) {\n+\t\tmsgbuf = opt->output_prefix(opt, opt->output_prefix_data);\n+\t\tline_prefix = msgbuf->buf;\n+\t}\n+\n \t/* special case: only removal */\n \tif (!diff_words->plus.text.size) {\n-\t\tfn_out_diff_words_write_helper(diff_words->file,\n+\t\tfputs(line_prefix, diff_words->opt->file);\n+\t\tfn_out_diff_words_write_helper(diff_words->opt->file,\n \t\t\t&style->old, style->newline,\n-\t\t\tdiff_words->minus.text.size, diff_words->minus.text.ptr);\n+\t\t\tdiff_words->minus.text.size,\n+\t\t\tdiff_words->minus.text.ptr, line_prefix);\n \t\tdiff_words->minus.text.size = 0;\n \t\treturn;\n \t}\n \n \tdiff_words->current_plus = diff_words->plus.text.ptr;\n+\tdiff_words->last_minus = 0;\n \n \tmemset(&xpp, 0, sizeof(xpp));\n \tmemset(&xecfg, 0, sizeof(xecfg));\n@@ -802,11 +885,15 @@ static void diff_words_show(struct diff_words_data *diff_words)\n \tfree(minus.ptr);\n \tfree(plus.ptr);\n \tif (diff_words->current_plus != diff_words->plus.text.ptr +\n-\t\t\tdiff_words->plus.text.size)\n-\t\tfn_out_diff_words_write_helper(diff_words->file,\n+\t\t\tdiff_words->plus.text.size) {\n+\t\tif (color_words_output_graph_prefix(diff_words))\n+\t\t\tfputs(line_prefix, diff_words->opt->file);\n+\t\tfn_out_diff_words_write_helper(diff_words->opt->file,\n \t\t\t&style->ctx, style->newline,\n \t\t\tdiff_words->plus.text.ptr + diff_words->plus.text.size\n-\t\t\t- diff_words->current_plus, diff_words->current_plus);\n+\t\t\t- diff_words->current_plus, diff_words->current_plus,\n+\t\t\tline_prefix);\n+\t}\n \tdiff_words->minus.text.size = diff_words->plus.text.size = 0;\n }\n \n@@ -1904,8 +1991,8 @@ static void builtin_diff(const char *name_a,\n \n \t\t\tecbdata.diff_words =\n \t\t\t\txcalloc(1, sizeof(struct diff_words_data));\n-\t\t\tecbdata.diff_words->file = o->file;\n \t\t\tecbdata.diff_words->type = o->word_diff;\n+\t\t\tecbdata.diff_words->opt = o;\n \t\t\tif (!o->word_regex)\n \t\t\t\to->word_regex = userdiff_word_regex(one);\n \t\t\tif (!o->word_regex)\n-- \n1.7.0.2.273.gc2413.dirty\n"}]}