{"thread":{"id":"23911","subject":"[PATCH v4 3/6] diff.c: Output the text graph padding before each diff line","startedAt":"2010-05-26T07:23:54Z","lastAt":"2010-05-29T14:19:14Z","messageCount":7,"participants":["Bo Yang","Junio C Hamano"],"isPatch":true,"patchVersion":4,"patchTotal":6},"messages":[{"id":"142345","messageId":"1274858637-13243-1-git-send-email-struggleyb.nku@gmail.com","threadId":"23911","inReplyTo":null,"subject":"[PATCH v4 3/6] diff.c: Output the text graph padding before each diff line","fromName":"Bo Yang","fromEmail":"struggleyb.nku@gmail.com","sentAt":"2010-05-26T07:23:54Z","receivedAt":"2010-05-26T07:23:54Z","isPatch":true,"sender":{"key":"struggleyb.nku@gmail.com","avatar":"https://avatars.githubusercontent.com/u/233030?v=4"},"body":"Change -p/--dirstat/--binary/--numstat/--stat/--shortstat/\n--check/--summary to align with graph paddings.\nThanks Jeff King <peff@peff.net> for reporting the '--summary' bug and his\ninitial patch.\n\nSigned-off-by: Bo Yang <struggleyb.nku@gmail.com>\n---\n diff.c |  200 +++++++++++++++++++++++++++++++++++++++++++++++-----------------\n 1 files changed, 147 insertions(+), 53 deletions(-)\n\ndiff --git a/diff.c b/diff.c\nindex e2f910a..7f2538d 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -490,6 +490,13 @@ static void emit_rewrite_diff(const char *name_a,\n \tchar *data_one, *data_two;\n \tsize_t size_one, size_two;\n \tstruct emit_callback ecbdata;\n+\tchar *line_prefix = \"\";\n+\tstruct strbuf *msgbuf;\n+\n+\tif (o && o->output_prefix) {\n+\t\tmsgbuf = o->output_prefix(o, o->output_prefix_data);\n+\t\tline_prefix = msgbuf->buf;\n+\t}\n \n \tif (diff_mnemonic_prefix && DIFF_OPT_TST(o, REVERSE_DIFF)) {\n \t\ta_prefix = o->b_prefix;\n@@ -531,9 +538,10 @@ static void emit_rewrite_diff(const char *name_a,\n \tlc_a = count_lines(data_one, size_one);\n \tlc_b = count_lines(data_two, size_two);\n \tfprintf(o->file,\n-\t\t\"%s--- %s%s%s\\n%s+++ %s%s%s\\n%s@@ -\",\n-\t\tmetainfo, a_name.buf, name_a_tab, reset,\n-\t\tmetainfo, b_name.buf, name_b_tab, reset, fraginfo);\n+\t\t\"%s%s--- %s%s%s\\n%s%s+++ %s%s%s\\n%s%s@@ -\",\n+\t\tline_prefix, metainfo, a_name.buf, name_a_tab, reset,\n+\t\tline_prefix, metainfo, b_name.buf, name_b_tab, reset,\n+\t\tline_prefix, fraginfo);\n \tprint_line_count(o->file, lc_a);\n \tfprintf(o->file, \" +\");\n \tprint_line_count(o->file, lc_b);\n@@ -846,6 +854,14 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)\n \tconst char *meta = diff_get_color(ecbdata->color_diff, DIFF_METAINFO);\n \tconst char *plain = diff_get_color(ecbdata->color_diff, DIFF_PLAIN);\n \tconst char *reset = diff_get_color(ecbdata->color_diff, DIFF_RESET);\n+\tstruct diff_options *o = ecbdata->opt;\n+\tchar *line_prefix = \"\";\n+\tstruct strbuf *msgbuf;\n+\n+\tif (o && o->output_prefix) {\n+\t\tmsgbuf = o->output_prefix(o, o->output_prefix_data);\n+\t\tline_prefix = msgbuf->buf;\n+\t}\n \n \tif (ecbdata->header) {\n \t\tfprintf(ecbdata->opt->file, \"%s\", ecbdata->header->buf);\n@@ -860,10 +876,10 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)\n \t\tname_a_tab = strchr(ecbdata->label_path[0], ' ') ? \"\\t\" : \"\";\n \t\tname_b_tab = strchr(ecbdata->label_path[1], ' ') ? \"\\t\" : \"\";\n \n-\t\tfprintf(ecbdata->opt->file, \"%s--- %s%s%s\\n\",\n-\t\t\tmeta, ecbdata->label_path[0], reset, name_a_tab);\n-\t\tfprintf(ecbdata->opt->file, \"%s+++ %s%s%s\\n\",\n-\t\t\tmeta, ecbdata->label_path[1], reset, name_b_tab);\n+\t\tfprintf(ecbdata->opt->file, \"%s%s--- %s%s%s\\n\",\n+\t\t\tline_prefix, meta, ecbdata->label_path[0], reset, name_a_tab);\n+\t\tfprintf(ecbdata->opt->file, \"%s%s+++ %s%s%s\\n\",\n+\t\t\tline_prefix, meta, ecbdata->label_path[1], reset, name_b_tab);\n \t\tecbdata->label_path[0] = ecbdata->label_path[1] = NULL;\n \t}\n \n@@ -1100,10 +1116,17 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)\n \tint total_files = data->nr;\n \tint width, name_width;\n \tconst char *reset, *set, *add_c, *del_c;\n+\tconst char *line_prefix = \"\";\n+\tstruct strbuf *msg = NULL;\n \n \tif (data->nr == 0)\n \t\treturn;\n \n+\tif (options->output_prefix) {\n+\t\tmsg = options->output_prefix(options, options->output_prefix_data);\n+\t\tline_prefix = msg->buf;\n+\t}\n+\n \twidth = options->stat_width ? options->stat_width : 80;\n \tname_width = options->stat_name_width ? options->stat_name_width : 50;\n \n@@ -1173,6 +1196,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)\n \t\t}\n \n \t\tif (data->files[i]->is_binary) {\n+\t\t\tfprintf(options->file, \"%s\", line_prefix);\n \t\t\tshow_name(options->file, prefix, name, len);\n \t\t\tfprintf(options->file, \"  Bin \");\n \t\t\tfprintf(options->file, \"%s%\"PRIuMAX\"%s\",\n@@ -1185,6 +1209,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)\n \t\t\tcontinue;\n \t\t}\n \t\telse if (data->files[i]->is_unmerged) {\n+\t\t\tfprintf(options->file, \"%s\", line_prefix);\n \t\t\tshow_name(options->file, prefix, name, len);\n \t\t\tfprintf(options->file, \"  Unmerged\\n\");\n \t\t\tcontinue;\n@@ -1207,6 +1232,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)\n \t\t\tadd = scale_linear(add, width, max_change);\n \t\t\tdel = scale_linear(del, width, max_change);\n \t\t}\n+\t\tfprintf(options->file, \"%s\", line_prefix);\n \t\tshow_name(options->file, prefix, name, len);\n \t\tfprintf(options->file, \"%5\"PRIuMAX\"%s\", added + deleted,\n \t\t\t\tadded + deleted ? \" \" : \"\");\n@@ -1214,6 +1240,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)\n \t\tshow_graph(options->file, '-', del, del_c, reset);\n \t\tfprintf(options->file, \"\\n\");\n \t}\n+\tfprintf(options->file, \"%s\", line_prefix);\n \tfprintf(options->file,\n \t       \" %d files changed, %d insertions(+), %d deletions(-)\\n\",\n \t       total_files, adds, dels);\n@@ -1240,6 +1267,12 @@ static void show_shortstats(struct diffstat_t *data, struct diff_options *option\n \t\t\t}\n \t\t}\n \t}\n+\tif (options->output_prefix) {\n+\t\tstruct strbuf *msg = NULL;\n+\t\tmsg = options->output_prefix(options,\n+\t\t\t\toptions->output_prefix_data);\n+\t\tfprintf(options->file, \"%s\", msg->buf);\n+\t}\n \tfprintf(options->file, \" %d files changed, %d insertions(+), %d deletions(-)\\n\",\n \t       total_files, adds, dels);\n }\n@@ -1254,6 +1287,13 @@ static void show_numstat(struct diffstat_t *data, struct diff_options *options)\n \tfor (i = 0; i < data->nr; i++) {\n \t\tstruct diffstat_file *file = data->files[i];\n \n+\t\tif (options->output_prefix) {\n+\t\t\tstruct strbuf *msg = NULL;\n+\t\t\tmsg = options->output_prefix(options,\n+\t\t\t\t\toptions->output_prefix_data);\n+\t\t\tfprintf(options->file, \"%s\", msg->buf);\n+\t\t}\n+\n \t\tif (file->is_binary)\n \t\t\tfprintf(options->file, \"-\\t-\\t\");\n \t\telse\n@@ -1289,10 +1329,18 @@ struct dirstat_dir {\n \tint alloc, nr, percent, cumulative;\n };\n \n-static long gather_dirstat(FILE *file, struct dirstat_dir *dir, unsigned long changed, const char *base, int baselen)\n+static long gather_dirstat(struct diff_options *opt, struct dirstat_dir *dir,\n+\t\tunsigned long changed, const char *base, int baselen)\n {\n \tunsigned long this_dir = 0;\n \tunsigned int sources = 0;\n+\tconst char *line_prefix = \"\";\n+\tstruct strbuf *msg = NULL;\n+\n+\tif (opt->output_prefix) {\n+\t\tmsg = opt->output_prefix(opt, opt->output_prefix_data);\n+\t\tline_prefix = msg->buf;\n+\t}\n \n \twhile (dir->nr) {\n \t\tstruct dirstat_file *f = dir->files;\n@@ -1307,7 +1355,7 @@ static long gather_dirstat(FILE *file, struct dirstat_dir *dir, unsigned long ch\n \t\tslash = strchr(f->name + baselen, '/');\n \t\tif (slash) {\n \t\t\tint newbaselen = slash + 1 - f->name;\n-\t\t\tthis = gather_dirstat(file, dir, changed, f->name, newbaselen);\n+\t\t\tthis = gather_dirstat(opt, dir, changed, f->name, newbaselen);\n \t\t\tsources++;\n \t\t} else {\n \t\t\tthis = f->changed;\n@@ -1329,7 +1377,8 @@ static long gather_dirstat(FILE *file, struct dirstat_dir *dir, unsigned long ch\n \t\tif (permille) {\n \t\t\tint percent = permille / 10;\n \t\t\tif (percent >= dir->percent) {\n-\t\t\t\tfprintf(file, \"%4d.%01d%% %.*s\\n\", percent, permille % 10, baselen, base);\n+\t\t\t\tfprintf(opt->file, \"%s%4d.%01d%% %.*s\\n\", line_prefix,\n+\t\t\t\t\tpercent, permille % 10, baselen, base);\n \t\t\t\tif (!dir->cumulative)\n \t\t\t\t\treturn 0;\n \t\t\t}\n@@ -1409,7 +1458,7 @@ static void show_dirstat(struct diff_options *options)\n \n \t/* Show all directories with more than x% of the changes */\n \tqsort(dir.files, dir.nr, sizeof(dir.files[0]), dirstat_compare);\n-\tgather_dirstat(options->file, &dir, changed, \"\", 0);\n+\tgather_dirstat(options, &dir, changed, \"\", 0);\n }\n \n static void free_diffstat_info(struct diffstat_t *diffstat)\n@@ -1467,6 +1516,15 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)\n \tconst char *reset = diff_get_color(color_diff, DIFF_RESET);\n \tconst char *set = diff_get_color(color_diff, DIFF_FILE_NEW);\n \tchar *err;\n+\tchar *line_prefix = \"\";\n+\tstruct strbuf *msgbuf;\n+\n+\tassert(data->o);\n+\tif (data->o->output_prefix) {\n+\t\tmsgbuf = data->o->output_prefix(data->o,\n+\t\t\tdata->o->output_prefix_data);\n+\t\tline_prefix = msgbuf->buf;\n+\t}\n \n \tif (line[0] == '+') {\n \t\tunsigned bad;\n@@ -1474,16 +1532,16 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)\n \t\tif (is_conflict_marker(line + 1, marker_size, len - 1)) {\n \t\t\tdata->status |= 1;\n \t\t\tfprintf(data->o->file,\n-\t\t\t\t\"%s:%d: leftover conflict marker\\n\",\n-\t\t\t\tdata->filename, data->lineno);\n+\t\t\t\t\"%s%s:%d: leftover conflict marker\\n\",\n+\t\t\t\tline_prefix, data->filename, data->lineno);\n \t\t}\n \t\tbad = ws_check(line + 1, len - 1, data->ws_rule);\n \t\tif (!bad)\n \t\t\treturn;\n \t\tdata->status |= bad;\n \t\terr = whitespace_error_string(bad);\n-\t\tfprintf(data->o->file, \"%s:%d: %s.\\n\",\n-\t\t\tdata->filename, data->lineno, err);\n+\t\tfprintf(data->o->file, \"%s%s:%d: %s.\\n\",\n+\t\t\tline_prefix, data->filename, data->lineno, err);\n \t\tfree(err);\n \t\temit_line(data->o, set, reset, line, 1);\n \t\tws_check_emit(line + 1, len - 1, data->ws_rule,\n@@ -1523,7 +1581,7 @@ static unsigned char *deflate_it(char *data,\n \treturn deflated;\n }\n \n-static void emit_binary_diff_body(FILE *file, mmfile_t *one, mmfile_t *two)\n+static void emit_binary_diff_body(FILE *file, mmfile_t *one, mmfile_t *two, char *prefix)\n {\n \tvoid *cp;\n \tvoid *delta;\n@@ -1552,13 +1610,13 @@ static void emit_binary_diff_body(FILE *file, mmfile_t *one, mmfile_t *two)\n \t}\n \n \tif (delta && delta_size < deflate_size) {\n-\t\tfprintf(file, \"delta %lu\\n\", orig_size);\n+\t\tfprintf(file, \"%sdelta %lu\\n\", prefix, orig_size);\n \t\tfree(deflated);\n \t\tdata = delta;\n \t\tdata_size = delta_size;\n \t}\n \telse {\n-\t\tfprintf(file, \"literal %lu\\n\", two->size);\n+\t\tfprintf(file, \"%sliteral %lu\\n\", prefix, two->size);\n \t\tfree(delta);\n \t\tdata = deflated;\n \t\tdata_size = deflate_size;\n@@ -1576,18 +1634,19 @@ static void emit_binary_diff_body(FILE *file, mmfile_t *one, mmfile_t *two)\n \t\t\tline[0] = bytes - 26 + 'a' - 1;\n \t\tencode_85(line + 1, cp, bytes);\n \t\tcp = (char *) cp + bytes;\n+\t\tfprintf(file, \"%s\", prefix);\n \t\tfputs(line, file);\n \t\tfputc('\\n', file);\n \t}\n-\tfprintf(file, \"\\n\");\n+\tfprintf(file, \"%s\\n\", prefix);\n \tfree(data);\n }\n \n-static void emit_binary_diff(FILE *file, mmfile_t *one, mmfile_t *two)\n+static void emit_binary_diff(FILE *file, mmfile_t *one, mmfile_t *two, char *prefix)\n {\n-\tfprintf(file, \"GIT binary patch\\n\");\n-\temit_binary_diff_body(file, one, two);\n-\temit_binary_diff_body(file, two, one);\n+\tfprintf(file, \"%sGIT binary patch\\n\", prefix);\n+\temit_binary_diff_body(file, one, two, prefix);\n+\temit_binary_diff_body(file, two, one, prefix);\n }\n \n static void diff_filespec_load_driver(struct diff_filespec *one)\n@@ -1676,6 +1735,13 @@ static void builtin_diff(const char *name_a,\n \tstruct userdiff_driver *textconv_one = NULL;\n \tstruct userdiff_driver *textconv_two = NULL;\n \tstruct strbuf header = STRBUF_INIT;\n+\tstruct strbuf *msgbuf;\n+\tchar *line_prefix = \"\";\n+\n+\tif (o->output_prefix) {\n+\t\tmsgbuf = o->output_prefix(o, o->output_prefix_data);\n+\t\tline_prefix = msgbuf->buf;\n+\t}\n \n \tif (DIFF_OPT_TST(o, SUBMODULE_LOG) &&\n \t\t\t(!one->mode || S_ISGITLINK(one->mode)) &&\n@@ -1710,22 +1776,22 @@ static void builtin_diff(const char *name_a,\n \tb_two = quote_two(b_prefix, name_b + (*name_b == '/'));\n \tlbl[0] = DIFF_FILE_VALID(one) ? a_one : \"/dev/null\";\n \tlbl[1] = DIFF_FILE_VALID(two) ? b_two : \"/dev/null\";\n-\tstrbuf_addf(&header, \"%sdiff --git %s %s%s\\n\", set, a_one, b_two, reset);\n+\tstrbuf_addf(&header, \"%s%sdiff --git %s %s%s\\n\", line_prefix, set, a_one, b_two, reset);\n \tif (lbl[0][0] == '/') {\n \t\t/* /dev/null */\n-\t\tstrbuf_addf(&header, \"%snew file mode %06o%s\\n\", set, two->mode, reset);\n+\t\tstrbuf_addf(&header, \"%s%snew file mode %06o%s\\n\", line_prefix, set, two->mode, reset);\n \t\tif (xfrm_msg && xfrm_msg[0])\n \t\t\tstrbuf_addf(&header, \"%s%s%s\\n\", set, xfrm_msg, reset);\n \t}\n \telse if (lbl[1][0] == '/') {\n-\t\tstrbuf_addf(&header, \"%sdeleted file mode %06o%s\\n\", set, one->mode, reset);\n+\t\tstrbuf_addf(&header, \"%s%sdeleted file mode %06o%s\\n\", line_prefix, set, one->mode, reset);\n \t\tif (xfrm_msg && xfrm_msg[0])\n \t\t\tstrbuf_addf(&header, \"%s%s%s\\n\", set, xfrm_msg, reset);\n \t}\n \telse {\n \t\tif (one->mode != two->mode) {\n-\t\t\tstrbuf_addf(&header, \"%sold mode %06o%s\\n\", set, one->mode, reset);\n-\t\t\tstrbuf_addf(&header, \"%snew mode %06o%s\\n\", set, two->mode, reset);\n+\t\t\tstrbuf_addf(&header, \"%s%sold mode %06o%s\\n\", line_prefix, set, one->mode, reset);\n+\t\t\tstrbuf_addf(&header, \"%s%snew mode %06o%s\\n\", line_prefix, set, two->mode, reset);\n \t\t}\n \t\tif (xfrm_msg && xfrm_msg[0])\n \t\t\tstrbuf_addf(&header, \"%s%s%s\\n\", set, xfrm_msg, reset);\n@@ -1760,10 +1826,10 @@ static void builtin_diff(const char *name_a,\n \t\tfprintf(o->file, \"%s\", header.buf);\n \t\tstrbuf_reset(&header);\n \t\tif (DIFF_OPT_TST(o, BINARY))\n-\t\t\temit_binary_diff(o->file, &mf1, &mf2);\n+\t\t\temit_binary_diff(o->file, &mf1, &mf2, line_prefix);\n \t\telse\n-\t\t\tfprintf(o->file, \"Binary files %s and %s differ\\n\",\n-\t\t\t\tlbl[0], lbl[1]);\n+\t\t\tfprintf(o->file, \"%sBinary files %s and %s differ\\n\",\n+\t\t\t\tline_prefix, lbl[0], lbl[1]);\n \t\to->found_changes = 1;\n \t}\n \telse {\n@@ -2389,28 +2455,36 @@ static void fill_metainfo(struct strbuf *msg,\n \t\t\t  struct diff_options *o,\n \t\t\t  struct diff_filepair *p)\n {\n+\tstruct strbuf *msgbuf;\n+\tchar *line_prefix = \"\";\n+\n+\tif (o->output_prefix) {\n+\t\tmsgbuf = o->output_prefix(o, o->output_prefix_data);\n+\t\tline_prefix = msgbuf->buf;\n+\t}\n+\n \tstrbuf_init(msg, PATH_MAX * 2 + 300);\n \tswitch (p->status) {\n \tcase DIFF_STATUS_COPIED:\n-\t\tstrbuf_addf(msg, \"similarity index %d%%\", similarity_index(p));\n-\t\tstrbuf_addstr(msg, \"\\ncopy from \");\n+\t\tstrbuf_addf(msg, \"%ssimilarity index %d%%\", line_prefix, similarity_index(p));\n+\t\tstrbuf_addf(msg, \"\\n%scopy from \", line_prefix);\n \t\tquote_c_style(name, msg, NULL, 0);\n-\t\tstrbuf_addstr(msg, \"\\ncopy to \");\n+\t\tstrbuf_addf(msg, \"\\n%scopy to \", line_prefix);\n \t\tquote_c_style(other, msg, NULL, 0);\n \t\tstrbuf_addch(msg, '\\n');\n \t\tbreak;\n \tcase DIFF_STATUS_RENAMED:\n-\t\tstrbuf_addf(msg, \"similarity index %d%%\", similarity_index(p));\n-\t\tstrbuf_addstr(msg, \"\\nrename from \");\n+\t\tstrbuf_addf(msg, \"%ssimilarity index %d%%\", line_prefix, similarity_index(p));\n+\t\tstrbuf_addf(msg, \"\\n%srename from \", line_prefix);\n \t\tquote_c_style(name, msg, NULL, 0);\n-\t\tstrbuf_addstr(msg, \"\\nrename to \");\n+\t\tstrbuf_addf(msg, \"\\n%srename to \", line_prefix);\n \t\tquote_c_style(other, msg, NULL, 0);\n \t\tstrbuf_addch(msg, '\\n');\n \t\tbreak;\n \tcase DIFF_STATUS_MODIFIED:\n \t\tif (p->score) {\n-\t\t\tstrbuf_addf(msg, \"dissimilarity index %d%%\\n\",\n-\t\t\t\t    similarity_index(p));\n+\t\t\tstrbuf_addf(msg, \"%sdissimilarity index %d%%\\n\",\n+\t\t\t\t    line_prefix, similarity_index(p));\n \t\t\tbreak;\n \t\t}\n \t\t/* fallthru */\n@@ -2427,8 +2501,8 @@ static void fill_metainfo(struct strbuf *msg,\n \t\t\t    (!fill_mmfile(&mf, two) && diff_filespec_is_binary(two)))\n \t\t\t\tabbrev = 40;\n \t\t}\n-\t\tstrbuf_addf(msg, \"index %.*s..%.*s\",\n-\t\t\t    abbrev, sha1_to_hex(one->sha1),\n+\t\tstrbuf_addf(msg, \"%sindex %.*s..%.*s\",\n+\t\t\t    line_prefix, abbrev, sha1_to_hex(one->sha1),\n \t\t\t    abbrev, sha1_to_hex(two->sha1));\n \t\tif (one->mode == two->mode)\n \t\t\tstrbuf_addf(msg, \" %06o\", one->mode);\n@@ -3132,6 +3206,11 @@ static void diff_flush_raw(struct diff_filepair *p, struct diff_options *opt)\n {\n \tint line_termination = opt->line_termination;\n \tint inter_name_termination = line_termination ? '\\t' : '\\0';\n+\tif (opt->output_prefix) {\n+\t\tstruct strbuf *msg = NULL;\n+\t\tmsg = opt->output_prefix(opt, opt->output_prefix_data);\n+\t\tfprintf(opt->file, \"%s\", msg->buf);\n+\t}\n \n \tif (!(opt->output_format & DIFF_FORMAT_NAME_STATUS)) {\n \t\tfprintf(opt->file, \":%06o %06o %s \", p->one->mode, p->two->mode,\n@@ -3377,48 +3456,62 @@ static void show_file_mode_name(FILE *file, const char *newdelete, struct diff_f\n }\n \n \n-static void show_mode_change(FILE *file, struct diff_filepair *p, int show_name)\n+static void show_mode_change(FILE *file, struct diff_filepair *p, int show_name,\n+\t\tconst char *line_prefix)\n {\n \tif (p->one->mode && p->two->mode && p->one->mode != p->two->mode) {\n-\t\tfprintf(file, \" mode change %06o => %06o%c\", p->one->mode, p->two->mode,\n-\t\t\tshow_name ? ' ' : '\\n');\n+\t\tfprintf(file, \"%s mode change %06o => %06o%c\", line_prefix, p->one->mode,\n+\t\t\tp->two->mode, show_name ? ' ' : '\\n');\n \t\tif (show_name) {\n \t\t\twrite_name_quoted(p->two->path, file, '\\n');\n \t\t}\n \t}\n }\n \n-static void show_rename_copy(FILE *file, const char *renamecopy, struct diff_filepair *p)\n+static void show_rename_copy(FILE *file, const char *renamecopy, struct diff_filepair *p,\n+\t\t\tconst char *line_prefix)\n {\n \tchar *names = pprint_rename(p->one->path, p->two->path);\n \n \tfprintf(file, \" %s %s (%d%%)\\n\", renamecopy, names, similarity_index(p));\n \tfree(names);\n-\tshow_mode_change(file, p, 0);\n+\tshow_mode_change(file, p, 0, line_prefix);\n }\n \n-static void diff_summary(FILE *file, struct diff_filepair *p)\n+static void diff_summary(struct diff_options *opt, struct diff_filepair *p)\n {\n+\tFILE *file = opt->file;\n+\tchar *line_prefix = \"\";\n+\n+\tif (opt->output_prefix) {\n+\t\tstruct strbuf *buf = opt->output_prefix(opt, opt->output_prefix_data);\n+\t\tline_prefix = buf->buf;\n+\t}\n+\n \tswitch(p->status) {\n \tcase DIFF_STATUS_DELETED:\n+\t\tfputs(line_prefix, file);\n \t\tshow_file_mode_name(file, \"delete\", p->one);\n \t\tbreak;\n \tcase DIFF_STATUS_ADDED:\n+\t\tfputs(line_prefix, file);\n \t\tshow_file_mode_name(file, \"create\", p->two);\n \t\tbreak;\n \tcase DIFF_STATUS_COPIED:\n-\t\tshow_rename_copy(file, \"copy\", p);\n+\t\tfputs(line_prefix, file);\n+\t\tshow_rename_copy(file, \"copy\", p, line_prefix);\n \t\tbreak;\n \tcase DIFF_STATUS_RENAMED:\n-\t\tshow_rename_copy(file, \"rename\", p);\n+\t\tfputs(line_prefix, file);\n+\t\tshow_rename_copy(file, \"rename\", p, line_prefix);\n \t\tbreak;\n \tdefault:\n \t\tif (p->score) {\n-\t\t\tfputs(\" rewrite \", file);\n+\t\t\tfprintf(file, \"%s rewrite \", line_prefix);\n \t\t\twrite_name_quoted(p->two->path, file, ' ');\n \t\t\tfprintf(file, \"(%d%%)\\n\", similarity_index(p));\n \t\t}\n-\t\tshow_mode_change(file, p, !p->score);\n+\t\tshow_mode_change(file, p, !p->score, line_prefix);\n \t\tbreak;\n \t}\n }\n@@ -3627,8 +3720,9 @@ void diff_flush(struct diff_options *options)\n \t\tshow_dirstat(options);\n \n \tif (output_format & DIFF_FORMAT_SUMMARY && !is_summary_empty(q)) {\n-\t\tfor (i = 0; i < q->nr; i++)\n-\t\t\tdiff_summary(options->file, q->queue[i]);\n+\t\tfor (i = 0; i < q->nr; i++) {\n+\t\t\tdiff_summary(options, q->queue[i]);\n+\t\t}\n \t\tseparator++;\n \t}\n \n-- \n1.6.0.4\n"},{"id":"142346","messageId":"1274858637-13243-2-git-send-email-struggleyb.nku@gmail.com","threadId":"23911","inReplyTo":"1274858637-13243-1-git-send-email-struggleyb.nku@gmail.com","subject":"[PATCH v4 4/6] Emit a whole line once a time","fromName":"Bo Yang","fromEmail":"struggleyb.nku@gmail.com","sentAt":"2010-05-26T07:23:55Z","receivedAt":"2010-05-26T07:23:55Z","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..bffaedc 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -370,6 +370,18 @@ 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+\n+\t/*\n+\t * trailing \\r\\n\n+\t */\n+\tint i = 1;\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/*\n \t * As a hunk header must begin with \"@@ -<old>, +<new> @@\",\n@@ -384,17 +396,29 @@ 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/* 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.6.0.4\n"},{"id":"142347","messageId":"1274858637-13243-3-git-send-email-struggleyb.nku@gmail.com","threadId":"23911","inReplyTo":"1274858637-13243-2-git-send-email-struggleyb.nku@gmail.com","subject":"[PATCH v4 5/6] Register a callback for graph output","fromName":"Bo Yang","fromEmail":"struggleyb.nku@gmail.com","sentAt":"2010-05-26T07:23:56Z","receivedAt":"2010-05-26T07:23:56Z","isPatch":true,"sender":{"key":"struggleyb.nku@gmail.com","avatar":"https://avatars.githubusercontent.com/u/233030?v=4"},"body":"It will look better if the 'git log --graph' print\nthe graph pading lines before the diff output just\nlike what it does for commit message.\nAnd this patch leverage the new diff prefix callback\nfunction to achieve this.\n\nSigned-off-by: Bo Yang <struggleyb.nku@gmail.com>\n---\n graph.c |   19 +++++++++++++++++++\n 1 files changed, 19 insertions(+), 0 deletions(-)\n\ndiff --git a/graph.c b/graph.c\nindex e6bbcaa..ac7c605 100644\n--- a/graph.c\n+++ b/graph.c\n@@ -211,6 +211,18 @@ struct git_graph {\n \tunsigned short default_column_color;\n };\n \n+static struct strbuf *diff_output_prefix_callback(struct diff_options *opt, void *data)\n+{\n+\tstruct git_graph *graph = data;\n+\tstatic struct strbuf msgbuf = STRBUF_INIT;\n+\n+\tassert(graph);\n+\n+\tstrbuf_reset(&msgbuf);\n+\tgraph_padding_line(graph, &msgbuf);\n+\treturn &msgbuf;\n+}\n+\n struct git_graph *graph_init(struct rev_info *opt)\n {\n \tstruct git_graph *graph = xmalloc(sizeof(struct git_graph));\n@@ -244,6 +256,13 @@ struct git_graph *graph_init(struct rev_info *opt)\n \tgraph->mapping = xmalloc(sizeof(int) * 2 * graph->column_capacity);\n \tgraph->new_mapping = xmalloc(sizeof(int) * 2 * graph->column_capacity);\n \n+\t/*\n+\t * The diff output prefix callback, with this we can make\n+\t * all the diff output to align with the graph lines.\n+\t */\n+\topt->diffopt.output_prefix = diff_output_prefix_callback;\n+\topt->diffopt.output_prefix_data = graph;\n+\n \treturn graph;\n }\n \n-- \n1.6.0.4\n"},{"id":"142348","messageId":"1274858637-13243-4-git-send-email-struggleyb.nku@gmail.com","threadId":"23911","inReplyTo":"1274858637-13243-3-git-send-email-struggleyb.nku@gmail.com","subject":"[PATCH v4 6/6] Make --color-words work well with --graph","fromName":"Bo Yang","fromEmail":"struggleyb.nku@gmail.com","sentAt":"2010-05-26T07:23:57Z","receivedAt":"2010-05-26T07:23:57Z","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\n1. collect a the minus/plus lines of a diff hunk, divided into minus-lines and plus-lines;\n2. break both minus-lines and plus-lines into words and place them into two\n   mmfile_t with one word for each line;\n3. 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.\n1. diff_words->last_minus == 0 && diff_words->current_plus == diff_words->plus.text.ptr\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.\n2. diff_words->current_plus > diff_words->plus.text.ptr && *(diff_words->current_plus - 1) == '\\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 |  106 +++++++++++++++++++++++++++++++++++++++++++++++++++++----------\n 1 files changed, 89 insertions(+), 17 deletions(-)\n\ndiff --git a/diff.c b/diff.c\nindex bffaedc..0e16651 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,6 +660,7 @@ 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@@ -664,11 +671,20 @@ static void fn_out_diff_words_aux(void *priv, char *line, unsigned long len)\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 +700,57 @@ 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+\t/*\n+\t * '--color-words' algorithm can be described as:\n+\t *\n+\t * 1. collect a the minus/plus lines of a diff hunk, divided into minus-lines and plus-lines;\n+\t * 2. break both minus-lines and plus-lines into words and place them into two\n+\t *    mmfile_t with one word for each line;\n+\t * 3. use xdiff to run diff on the two mmfile_t to get the words level diff;\n+\t *\n+\t * And for the common parts of the both file, we output the plus side text.\n+\t * diff_words->current_plus is used to trace the current position of the plus file\n+\t * which printed. diff_words->last_minus is used to trace the last minus word\n+\t * printed.\n+\t *\n+\t * For '--graph' to work with '--color-words', we need to output the graph prefix\n+\t * on each line of color words output. Generally, there are two conditions on\n+\t * which we should output the prefix.\n+\t * 1. diff_words->last_minus == 0 && diff_words->current_plus == diff_words->plus.text.ptr\n+\t *    that is: the plus text must start as a new line, and if there is no minus\n+\t *    word printed, a graph prefix must be printed.\n+\t * 2. diff_words->current_plus > diff_words->plus.text.ptr && *(diff_words->current_plus - 1) == '\\n'\n+\t *    that is: a graph prefix must be printed following a '\\n'\n+\t */\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\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 +831,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 +867,18 @@ 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 ((diff_words->current_plus == diff_words->plus.text.ptr &&\n+\t\t\tdiff_words->last_minus == 0) ||\n+\t\t\t(diff_words->current_plus > diff_words->plus.text.ptr &&\n+\t\t\t*(diff_words->current_plus - 1) == '\\n'))\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 +1976,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.6.0.4\n"},{"id":"142511","messageId":"7vocfz5x80.fsf@alter.siamese.dyndns.org","threadId":"23911","inReplyTo":"1274858637-13243-2-git-send-email-struggleyb.nku@gmail.com","subject":"Re: [PATCH v4 4/6] Emit a whole line once a time","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-05-29T01:10:39Z","receivedAt":"2010-05-29T01:10:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Bo Yang <struggleyb.nku@gmail.com> writes:\n\n> Since the graph prefix will be printed when calling\n> emit_line, so the functions should be used to emit a\n> complete line out once a time. No one should call\n> emit_line to just output some strings instead of a\n> complete line.\n> Use a strbuf to compose the whole line, and then\n> call emit_line to output it once.\n\n\"once a time\" in your title doesn't sound quite right.  I would say \"in\none go\" instead.\n\n> Signed-off-by: Bo Yang <struggleyb.nku@gmail.com>\n> ---\n>  diff.c |   34 +++++++++++++++++++++++++++++-----\n>  1 files changed, 29 insertions(+), 5 deletions(-)\n>\n> diff --git a/diff.c b/diff.c\n> index 7f2538d..bffaedc 100644\n> --- a/diff.c\n> +++ b/diff.c\n> @@ -370,6 +370,18 @@ 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> +\n> +\t/*\n> +\t * trailing \\r\\n\n> +\t */\n> +\tint i = 1;\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\nI am not very happy with this logic.  The existing code (just outside the\npost-context of this hunk) is being defensive and returns early when len\nis shorter than what we expect, but this new code blindly assumes that len\nis at least 2 bytes long, and also it would eat a line that ends with \\r\\r.\n\nCan the partial line at the end be on this line?  IOW, can line[len-1] be\ndifferent from '\\n' in some cases?\n\nWhat's the reason to strip trailing \"\\r\" at the end of the line to begin\nwith?\n\n>  \t/*\n>  \t * As a hunk header must begin with \"@@ -<old>, +<new> @@\",\n"},{"id":"142512","messageId":"7viq675x7t.fsf@alter.siamese.dyndns.org","threadId":"23911","inReplyTo":"1274858637-13243-4-git-send-email-struggleyb.nku@gmail.com","subject":"Re: [PATCH v4 6/6] Make --color-words work well with --graph","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-05-29T01:10:46Z","receivedAt":"2010-05-29T01:10:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Bo Yang <struggleyb.nku@gmail.com> writes:\n\n> '--color-words' algorithm can be described as:\n>\n> 1. collect a the minus/plus lines of a diff hunk, divided into minus-lines and plus-lines;\n> 2. break both minus-lines and plus-lines into words and place them into two\n>    mmfile_t with one word for each line;\n> 3. use xdiff to run diff on the two mmfile_t to get the words level diff;\n\nPlease wrap lines at reasonable length, and indent bulleted lists like\nthis a bit from the left, with a blank line between each item, like this:\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 place them\n|     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\n|     diff;\n|\n|And for the common parts of the both file, we output the plus side...\n| ...\n|For '--graph' to work with '--color-words', we need to output the\n|graph prefix on each line of color words output. Generally, there are\n|two conditions on 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\n|     no minus 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\nSame thing for the in-code comments; it would probably be easier to read\nif you made a small helper function (that a compiler would inline for you)\nthat decides if you would want to show the line_prefix, and make that big\ncomment a comment to that helper function.\n"},{"id":"142535","messageId":"AANLkTin5KJs-3rEbPgLWRnEsTtlkmq7QTb-t0qEKAg78@mail.gmail.com","threadId":"23911","inReplyTo":"7vocfz5x80.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v4 4/6] Emit a whole line once a time","fromName":"Bo Yang","fromEmail":"struggleyb.nku@gmail.com","sentAt":"2010-05-29T14:19:14Z","receivedAt":"2010-05-29T14:19:14Z","isPatch":true,"sender":{"key":"struggleyb.nku@gmail.com","avatar":"https://avatars.githubusercontent.com/u/233030?v=4"},"body":"On Sat, May 29, 2010 at 9:10 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Bo Yang <struggleyb.nku@gmail.com> writes:\n>\n>> Since the graph prefix will be printed when calling\n>> emit_line, so the functions should be used to emit a\n>> complete line out once a time. No one should call\n>> emit_line to just output some strings instead of a\n>> complete line.\n>> Use a strbuf to compose the whole line, and then\n>> call emit_line to output it once.\n>\n> \"once a time\" in your title doesn't sound quite right.  I would say \"in\n> one go\" instead.\n>\n>> Signed-off-by: Bo Yang <struggleyb.nku@gmail.com>\n>> ---\n>>  diff.c |   34 +++++++++++++++++++++++++++++-----\n>>  1 files changed, 29 insertions(+), 5 deletions(-)\n>>\n>> diff --git a/diff.c b/diff.c\n>> index 7f2538d..bffaedc 100644\n>> --- a/diff.c\n>> +++ b/diff.c\n>> @@ -370,6 +370,18 @@ static void emit_hunk_header(struct emit_callback *ecbdata,\n>>       const char *reset = diff_get_color(ecbdata->color_diff, DIFF_RESET);\n>>       static const char atat[2] = { '@', '@' };\n>>       const char *cp, *ep;\n>> +     struct strbuf msgbuf = STRBUF_INIT;\n>> +     int org_len = len;\n>> +\n>> +     /*\n>> +      * trailing \\r\\n\n>> +      */\n>> +     int i = 1;\n>> +     for (; i < 3; i++) {\n>> +             if (line[len - i] == '\\r' || line[len - i] == '\\n') {\n>> +                     len --;\n>> +             }\n>> +     }\n>\n> I am not very happy with this logic.  The existing code (just outside the\n> post-context of this hunk) is being defensive and returns early when len\n> is shorter than what we expect, but this new code blindly assumes that len\n> is at least 2 bytes long, and also it would eat a line that ends with \\r\\r.\n\nHmm, yes, I will move the defensive code upper this check.\n\n> Can the partial line at the end be on this line?  IOW, can line[len-1] be\n> different from '\\n' in some cases?\n\nI think a line in Macintosh will end with '\\r'.\n\n> What's the reason to strip trailing \"\\r\" at the end of the line to begin\n> with?\n\nBoth '\\r' and '\\n' will be added back to the strbuf, what I do is\nfinding the len and make sure the '\\r' and \\n will not be surround by\nthe color escape sequence.\n\n-- \nRegards!\nBo\n----------------------------\nMy blog: http://blog.morebits.org\nWhy Git: http://www.whygitisbetterthanx.com/\n"}]}