{"thread":{"id":"23811","subject":"[PATCH 0/7] Make git log --graph looks better with -p and other diff options","startedAt":"2010-05-15T11:02:04Z","lastAt":"2010-05-17T06:59:27Z","messageCount":12,"participants":["Bo Yang","Thomas Rast"],"isPatch":true,"patchVersion":1,"patchTotal":7},"messages":[{"id":"141721","messageId":"1273921331-32702-1-git-send-email-struggleyb.nku@gmail.com","threadId":"23811","inReplyTo":null,"subject":"[PATCH 0/7] Make git log --graph looks better with -p and other diff options","fromName":"Bo Yang","fromEmail":"struggleyb.nku@gmail.com","sentAt":"2010-05-15T11:02:04Z","receivedAt":"2010-05-15T11:02:04Z","isPatch":true,"sender":{"key":"struggleyb.nku@gmail.com","avatar":"https://avatars.githubusercontent.com/u/233030?v=4"},"body":"When we run git log --graph with any other diff output function, such as '-p','--check','--numstat' or other diff optoins, the diff output area have no graph lines ahead of it. And this make the text graph looks strange.\nThe following 7 patches try to deal with this, and put the text graph columns before all the diff output lines.\n\nBo Yang (7):\n  Add a prefix output callback to diff output.\n  Change to call the new emit_line.\n  Output the graph columns at the end of the commit message.\n  diff.c: Output the text graph padding before each diff line.\n  Emit a whole line once a time.\n  Register a callback for graph output.\n  Make --color-words work well with --graph.\n\n color.c    |   21 +++-\n color.h    |    3 +-\n diff.c     |  315 ++++++++++++++++++++++++++++++++++++++++++++----------------\n diff.h     |    5 +\n graph.c    |   22 ++++\n log-tree.c |    4 +\n 6 files changed, 281 insertions(+), 89 deletions(-)\n"},{"id":"141723","messageId":"1273921331-32702-2-git-send-email-struggleyb.nku@gmail.com","threadId":"23811","inReplyTo":"1273921331-32702-1-git-send-email-struggleyb.nku@gmail.com","subject":"[PATCH 1/7] Add a prefix output callback to diff output.","fromName":"Bo Yang","fromEmail":"struggleyb.nku@gmail.com","sentAt":"2010-05-15T11:02:05Z","receivedAt":"2010-05-15T11:02:05Z","isPatch":true,"sender":{"key":"struggleyb.nku@gmail.com","avatar":"https://avatars.githubusercontent.com/u/233030?v=4"},"body":"The callback allow to output some prefix string for\neach line of diff output.\n\nSigned-off-by: Bo Yang <struggleyb.nku@gmail.com>\n---\n diff.c |   11 ++++++++---\n diff.h |    5 +++++\n 2 files changed, 13 insertions(+), 3 deletions(-)\n\ndiff --git a/diff.c b/diff.c\nindex e49f14a..2a38bef 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -282,11 +282,16 @@ static void check_blank_at_eof(mmfile_t *mf1, mmfile_t *mf2,\n \tecbdata->blank_at_eof_in_postimage = (at - l2) + 1;\n }\n \n-static void emit_line_0(FILE *file, const char *set, const char *reset,\n+static void emit_line_0(struct diff_options *o, const char *set, const char *reset,\n \t\t\tint first, const char *line, int len)\n {\n \tint has_trailing_newline, has_trailing_carriage_return;\n \tint nofirst;\n+\tFILE *file = o->file;\n+\n+\tif (o->output_prefix) {\n+\t\to->output_prefix(file, 1, o->output_prefix_data);\n+\t}\n \n \tif (len == 0) {\n \t\thas_trailing_newline = (first == '\\n');\n@@ -316,10 +321,10 @@ static void emit_line_0(FILE *file, const char *set, const char *reset,\n \t\tfputc('\\n', file);\n }\n \n-static void emit_line(FILE *file, const char *set, const char *reset,\n+static void emit_line(struct diff_options *o, const char *set, const char *reset,\n \t\t      const char *line, int len)\n {\n-\temit_line_0(file, set, reset, line[0], line+1, len-1);\n+\temit_line_0(o, set, reset, line[0], line+1, len-1);\n }\n \n static int new_blank_line_at_eof(struct emit_callback *ecbdata, const char *line, int len)\ndiff --git a/diff.h b/diff.h\nindex 6a71013..0031dd8 100644\n--- a/diff.h\n+++ b/diff.h\n@@ -9,6 +9,7 @@\n struct rev_info;\n struct diff_options;\n struct diff_queue_struct;\n+struct strbuf;\n \n typedef void (*change_fn_t)(struct diff_options *options,\n \t\t unsigned old_mode, unsigned new_mode,\n@@ -25,6 +26,8 @@ typedef void (*add_remove_fn_t)(struct diff_options *options,\n typedef void (*diff_format_fn_t)(struct diff_queue_struct *q,\n \t\tstruct diff_options *options, void *data);\n \n+typedef struct strbuf *(*diff_prefix_fn_t)(FILE *file, int print, void *data);\n+\n #define DIFF_FORMAT_RAW\t\t0x0001\n #define DIFF_FORMAT_DIFFSTAT\t0x0002\n #define DIFF_FORMAT_NUMSTAT\t0x0004\n@@ -122,6 +125,8 @@ struct diff_options {\n \tadd_remove_fn_t add_remove;\n \tdiff_format_fn_t format_callback;\n \tvoid *format_callback_data;\n+\tdiff_prefix_fn_t output_prefix;\n+\tvoid *output_prefix_data;\n };\n \n enum color_diff {\n-- \n1.7.1.94.gc3269\n"},{"id":"141722","messageId":"1273921331-32702-3-git-send-email-struggleyb.nku@gmail.com","threadId":"23811","inReplyTo":"1273921331-32702-2-git-send-email-struggleyb.nku@gmail.com","subject":"[PATCH 2/7] Change to call the new emit_line.","fromName":"Bo Yang","fromEmail":"struggleyb.nku@gmail.com","sentAt":"2010-05-15T11:02:06Z","receivedAt":"2010-05-15T11:02:06Z","isPatch":true,"sender":{"key":"struggleyb.nku@gmail.com","avatar":"https://avatars.githubusercontent.com/u/233030?v=4"},"body":"Call the new emit_line function.\n\nSigned-off-by: Bo Yang <struggleyb.nku@gmail.com>\n---\n diff.c |   34 +++++++++++++++++-----------------\n 1 files changed, 17 insertions(+), 17 deletions(-)\n\ndiff --git a/diff.c b/diff.c\nindex 2a38bef..9bd9063 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -194,8 +194,8 @@ struct emit_callback {\n \tsane_truncate_fn truncate;\n \tconst char **label_path;\n \tstruct diff_words_data *diff_words;\n+\tstruct diff_options *opt;\n \tint *found_changesp;\n-\tFILE *file;\n \tstruct strbuf *header;\n };\n \n@@ -346,15 +346,15 @@ static void emit_add_line(const char *reset,\n \tconst char *set = diff_get_color(ecbdata->color_diff, DIFF_FILE_NEW);\n \n \tif (!*ws)\n-\t\temit_line_0(ecbdata->file, set, reset, '+', line, len);\n+\t\temit_line_0(ecbdata->opt, set, reset, '+', line, len);\n \telse if (new_blank_line_at_eof(ecbdata, line, len))\n \t\t/* Blank line at EOF - paint '+' as well */\n-\t\temit_line_0(ecbdata->file, ws, reset, '+', line, len);\n+\t\temit_line_0(ecbdata->opt, ws, reset, '+', line, len);\n \telse {\n \t\t/* Emit just the prefix, then the rest. */\n-\t\temit_line_0(ecbdata->file, set, reset, '+', \"\", 0);\n+\t\temit_line_0(ecbdata->opt, set, reset, '+', \"\", 0);\n \t\tws_check_emit(line, len, ecbdata->ws_rule,\n-\t\t\t      ecbdata->file, set, reset, ws);\n+\t\t\t      ecbdata->opt->file, set, reset, ws);\n \t}\n }\n \n@@ -375,23 +375,23 @@ static void emit_hunk_header(struct emit_callback *ecbdata,\n \tif (len < 10 ||\n \t    memcmp(line, atat, 2) ||\n \t    !(ep = memmem(line + 2, len - 2, atat, 2))) {\n-\t\temit_line(ecbdata->file, plain, reset, line, len);\n+\t\temit_line(ecbdata->opt, plain, reset, line, len);\n \t\treturn;\n \t}\n \tep += 2; /* skip over @@ */\n \n \t/* The hunk header in fraginfo color */\n-\temit_line(ecbdata->file, frag, reset, line, ep - line);\n+\temit_line(ecbdata->opt, frag, reset, line, ep - line);\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->file, plain, reset, cp, ep - cp);\n+\t\temit_line(ecbdata->opt, plain, reset, cp, ep - cp);\n \n \tif (ep < line + len)\n-\t\temit_line(ecbdata->file, func, reset, ep, line + len - ep);\n+\t\temit_line(ecbdata->opt, func, reset, ep, line + len - ep);\n }\n \n static struct diff_tempfile *claim_diff_tempfile(void) {\n@@ -451,7 +451,7 @@ static void emit_rewrite_lines(struct emit_callback *ecb,\n \t\tlen = endp ? (endp - data + 1) : size;\n \t\tif (prefix != '+') {\n \t\t\tecb->lno_in_preimage++;\n-\t\t\temit_line_0(ecb->file, old, reset, '-',\n+\t\t\temit_line_0(ecb->opt, old, reset, '-',\n \t\t\t\t    data, len);\n \t\t} else {\n \t\t\tecb->lno_in_postimage++;\n@@ -463,7 +463,7 @@ static void emit_rewrite_lines(struct emit_callback *ecb,\n \tif (!endp) {\n \t\tconst char *plain = diff_get_color(ecb->color_diff,\n \t\t\t\t\t\t   DIFF_PLAIN);\n-\t\temit_line_0(ecb->file, plain, reset, '\\\\',\n+\t\temit_line_0(ecb->opt, plain, reset, '\\\\',\n \t\t\t    nneof, strlen(nneof));\n \t}\n }\n@@ -513,7 +513,7 @@ static void emit_rewrite_diff(const char *name_a,\n \tecbdata.color_diff = color_diff;\n \tecbdata.found_changesp = &o->found_changes;\n \tecbdata.ws_rule = whitespace_rule(name_b ? name_b : name_a);\n-\tecbdata.file = o->file;\n+\tecbdata.opt = o;\n \tif (ecbdata.ws_rule & WS_BLANK_AT_EOF) {\n \t\tmmfile_t mf1, mf2;\n \t\tmf1.ptr = (char *)data_one;\n@@ -828,7 +828,7 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)\n \t}\n \n \tif (len < 1) {\n-\t\temit_line(ecbdata->file, reset, reset, line, len);\n+\t\temit_line(ecbdata->opt, reset, reset, line, len);\n \t\treturn;\n \t}\n \n@@ -845,7 +845,7 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)\n \t\tdiff_words_flush(ecbdata);\n \t\tline++;\n \t\tlen--;\n-\t\temit_line(ecbdata->file, plain, reset, line, len);\n+\t\temit_line(ecbdata->opt, plain, reset, line, len);\n \t\treturn;\n \t}\n \n@@ -856,7 +856,7 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)\n \t\tecbdata->lno_in_preimage++;\n \t\tif (line[0] == ' ')\n \t\t\tecbdata->lno_in_postimage++;\n-\t\temit_line(ecbdata->file, color, reset, line, len);\n+\t\temit_line(ecbdata->opt, color, reset, line, len);\n \t} else {\n \t\tecbdata->lno_in_postimage++;\n \t\temit_add_line(reset, ecbdata, line + 1, len - 1);\n@@ -1421,7 +1421,7 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)\n \t\tfprintf(data->o->file, \"%s:%d: %s.\\n\",\n \t\t\tdata->filename, data->lineno, err);\n \t\tfree(err);\n-\t\temit_line(data->o->file, set, reset, line, 1);\n+\t\temit_line(data->o, set, reset, line, 1);\n \t\tws_check_emit(line + 1, len - 1, data->ws_rule,\n \t\t\t      data->o->file, set, reset, ws);\n \t} else if (line[0] == ' ') {\n@@ -1731,7 +1731,7 @@ static void builtin_diff(const char *name_a,\n \t\tecbdata.ws_rule = whitespace_rule(name_b ? name_b : name_a);\n \t\tif (ecbdata.ws_rule & WS_BLANK_AT_EOF)\n \t\t\tcheck_blank_at_eof(&mf1, &mf2, &ecbdata);\n-\t\tecbdata.file = o->file;\n+\t\tecbdata.opt = o;\n \t\tecbdata.header = header.len ? &header : NULL;\n \t\txpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;\n \t\txecfg.ctxlen = o->context;\n-- \n1.7.1.94.gc3269\n"},{"id":"141724","messageId":"1273921331-32702-4-git-send-email-struggleyb.nku@gmail.com","threadId":"23811","inReplyTo":"1273921331-32702-3-git-send-email-struggleyb.nku@gmail.com","subject":"[PATCH 3/7] Output the graph columns at the end of the commit message.","fromName":"Bo Yang","fromEmail":"struggleyb.nku@gmail.com","sentAt":"2010-05-15T11:02:07Z","receivedAt":"2010-05-15T11:02:07Z","isPatch":true,"sender":{"key":"struggleyb.nku@gmail.com","avatar":"https://avatars.githubusercontent.com/u/233030?v=4"},"body":"There is an empty line between the commit message and the\ndiff output. Add the graph columns as prefix of this line.\n\nSigned-off-by: Bo Yang <struggleyb.nku@gmail.com>\n---\n log-tree.c |    4 ++++\n 1 files changed, 4 insertions(+), 0 deletions(-)\n\ndiff --git a/log-tree.c b/log-tree.c\nindex d3ae969..1da4ea7 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -469,6 +469,10 @@ int log_tree_diff_flush(struct rev_info *opt)\n \t\t\tint pch = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_PATCH;\n \t\t\tif ((pch & opt->diffopt.output_format) == pch)\n \t\t\t\tprintf(\"---\");\n+\t\t\tif (opt->diffopt.output_prefix) {\n+\t\t\t\topt->diffopt.output_prefix(opt->diffopt.file,\n+\t\t\t\t\t1, opt->diffopt.output_prefix_data);\n+\t\t\t}\n \t\t\tputchar('\\n');\n \t\t}\n \t}\n-- \n1.7.1.94.gc3269\n"},{"id":"141726","messageId":"1273921331-32702-5-git-send-email-struggleyb.nku@gmail.com","threadId":"23811","inReplyTo":"1273921331-32702-4-git-send-email-struggleyb.nku@gmail.com","subject":"[PATCH 4/7] diff.c: Output the text graph padding before each diff line.","fromName":"Bo Yang","fromEmail":"struggleyb.nku@gmail.com","sentAt":"2010-05-15T11:02:08Z","receivedAt":"2010-05-15T11:02:08Z","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\nto align with graph paddings.\n\nSigned-off-by: Bo Yang <struggleyb.nku@gmail.com>\n---\n diff.c |  158 +++++++++++++++++++++++++++++++++++++++++++++++-----------------\n 1 files changed, 116 insertions(+), 42 deletions(-)\n\ndiff --git a/diff.c b/diff.c\nindex 9bd9063..4a10d16 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -487,6 +487,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->file, 0, 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@@ -528,9 +535,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@@ -789,9 +797,17 @@ 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->file, 0, o->output_prefix_data);\n+\t\tline_prefix = msgbuf->buf;\n+\t}\n \n \tif (ecbdata->header) {\n-\t\tfprintf(ecbdata->file, \"%s\", ecbdata->header->buf);\n+\t\tfprintf(ecbdata->opt->file, \"%s\", ecbdata->header->buf);\n \t\tstrbuf_reset(ecbdata->header);\n \t\tecbdata->header = NULL;\n \t}\n@@ -803,10 +819,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->file, \"%s--- %s%s%s\\n\",\n-\t\t\tmeta, ecbdata->label_path[0], reset, name_a_tab);\n-\t\tfprintf(ecbdata->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@@ -823,7 +839,7 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)\n \t\tfind_lno(line, ecbdata);\n \t\temit_hunk_header(ecbdata, line, len);\n \t\tif (line[len-1] != '\\n')\n-\t\t\tputc('\\n', ecbdata->file);\n+\t\t\tputc('\\n', ecbdata->opt->file);\n \t\treturn;\n \t}\n \n@@ -1109,6 +1125,10 @@ 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\tif (options->output_prefix) {\n+\t\t\t\toptions->output_prefix(options->file,\n+\t\t\t\t\t\t1, options->output_prefix_data);\n+\t\t\t}\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@@ -1121,6 +1141,10 @@ 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\tif (options->output_prefix) {\n+\t\t\t\toptions->output_prefix(options->file,\n+\t\t\t\t\t\t1, options->output_prefix_data);\n+\t\t\t}\n \t\t\tshow_name(options->file, prefix, name, len);\n \t\t\tfprintf(options->file, \"  Unmerged\\n\");\n \t\t\tcontinue;\n@@ -1143,6 +1167,10 @@ 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\tif (options->output_prefix) {\n+\t\t\toptions->output_prefix(options->file,\n+\t\t\t\t\t1, options->output_prefix_data);\n+\t\t}\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@@ -1150,6 +1178,10 @@ 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+\tif (options->output_prefix) {\n+\t\toptions->output_prefix(options->file,\n+\t\t\t\t1, options->output_prefix_data);\n+\t}\n \tfprintf(options->file,\n \t       \" %d files changed, %d insertions(+), %d deletions(-)\\n\",\n \t       total_files, adds, dels);\n@@ -1176,6 +1208,10 @@ 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\toptions->output_prefix(options->file,\n+\t\t\t\t1, options->output_prefix_data);\n+\t}\n \tfprintf(options->file, \" %d files changed, %d insertions(+), %d deletions(-)\\n\",\n \t       total_files, adds, dels);\n }\n@@ -1190,6 +1226,11 @@ 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\toptions->output_prefix(options->file,\n+\t\t\t\t\t1, options->output_prefix_data);\n+\t\t}\n+\n \t\tif (file->is_binary)\n \t\t\tfprintf(options->file, \"-\\t-\\t\");\n \t\telse\n@@ -1225,10 +1266,12 @@ 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, unsigned long changed, const char *base, int baselen)\n {\n \tunsigned long this_dir = 0;\n \tunsigned int sources = 0;\n+\tassert(opt);\n+\tFILE *file = opt->file;\n \n \twhile (dir->nr) {\n \t\tstruct dirstat_file *f = dir->files;\n@@ -1243,7 +1286,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@@ -1265,6 +1308,9 @@ 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\tif (opt->output_prefix) {\n+\t\t\t\t\topt->output_prefix(file, 1, opt->output_prefix_data);\n+\t\t\t\t}\n \t\t\t\tfprintf(file, \"%4d.%01d%% %.*s\\n\", percent, permille % 10, baselen, base);\n \t\t\t\tif (!dir->cumulative)\n \t\t\t\t\treturn 0;\n@@ -1345,7 +1391,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@@ -1403,6 +1449,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->file, 0,\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@@ -1410,16 +1465,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@@ -1459,7 +1514,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@@ -1488,13 +1543,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@@ -1512,18 +1567,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@@ -1612,6 +1668,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->file, 0, 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@@ -1646,22 +1709,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@@ -1696,10 +1759,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@@ -2309,28 +2372,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->file, 0, 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@@ -2347,8 +2418,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@@ -3027,6 +3098,9 @@ 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\topt->output_prefix(opt->file, 1, opt->output_prefix_data);\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-- \n1.7.1.94.gc3269\n"},{"id":"141725","messageId":"1273921331-32702-6-git-send-email-struggleyb.nku@gmail.com","threadId":"23811","inReplyTo":"1273921331-32702-5-git-send-email-struggleyb.nku@gmail.com","subject":"[PATCH 5/7] Emit a whole line once a time.","fromName":"Bo Yang","fromEmail":"struggleyb.nku@gmail.com","sentAt":"2010-05-15T11:02:09Z","receivedAt":"2010-05-15T11:02:09Z","isPatch":true,"sender":{"key":"struggleyb.nku@gmail.com","avatar":"https://avatars.githubusercontent.com/u/233030?v=4"},"body":"Use a strbuf to compose the whole line, and then\ncall emit_line to output it once. This make output_prefix\ncallback works well.\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 4a10d16..ed97115 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -367,6 +367,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@@ -381,17 +393,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.7.1.94.gc3269\n"},{"id":"141727","messageId":"1273921331-32702-7-git-send-email-struggleyb.nku@gmail.com","threadId":"23811","inReplyTo":"1273921331-32702-6-git-send-email-struggleyb.nku@gmail.com","subject":"[PATCH 6/7] Register a callback for graph output.","fromName":"Bo Yang","fromEmail":"struggleyb.nku@gmail.com","sentAt":"2010-05-15T11:02:10Z","receivedAt":"2010-05-15T11:02:10Z","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 |   22 ++++++++++++++++++++++\n 1 files changed, 22 insertions(+), 0 deletions(-)\n\ndiff --git a/graph.c b/graph.c\nindex e6bbcaa..d4d2719 100644\n--- a/graph.c\n+++ b/graph.c\n@@ -211,6 +211,21 @@ struct git_graph {\n \tunsigned short default_column_color;\n };\n \n+static struct strbuf *diff_output_prefix_callback(FILE *file, int print, 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+\tif (print) {\n+\t\tfwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);\n+\t}\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 +259,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.7.1.94.gc3269\n"},{"id":"141728","messageId":"1273921331-32702-8-git-send-email-struggleyb.nku@gmail.com","threadId":"23811","inReplyTo":"1273921331-32702-7-git-send-email-struggleyb.nku@gmail.com","subject":"[PATCH 7/7] Make --color-words work well with --graph.","fromName":"Bo Yang","fromEmail":"struggleyb.nku@gmail.com","sentAt":"2010-05-15T11:02:11Z","receivedAt":"2010-05-15T11:02:11Z","isPatch":true,"sender":{"key":"struggleyb.nku@gmail.com","avatar":"https://avatars.githubusercontent.com/u/233030?v=4"},"body":"Align color words output with text graph lines.\n\nSigned-off-by: Bo Yang <struggleyb.nku@gmail.com>\n---\n color.c |   21 +++++++++++----\n color.h |    3 +-\n diff.c  |   84 +++++++++++++++++++++++++++++++++++++++++++++++++-------------\n 3 files changed, 83 insertions(+), 25 deletions(-)\n\ndiff --git a/color.c b/color.c\nindex bcf4e2c..e034e3b 100644\n--- a/color.c\n+++ b/color.c\n@@ -218,22 +218,31 @@ int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...)\n  * Returns 0 on success.\n  */\n int color_fwrite_lines(FILE *fp, const char *color,\n-\t\tsize_t count, const char *buf)\n+\t\tsize_t count, const char *buf, const char *prefix)\n {\n-\tif (!*color)\n-\t\treturn fwrite(buf, count, 1, fp) != 1;\n+\tint printing = 0;\n+\tconst char *reset = GIT_COLOR_RESET;\n+\n+\tif (strlen(color) == 0)\n+\t\treset = \"\";\n+\n \twhile (count) {\n \t\tchar *p = memchr(buf, '\\n', count);\n-\t\tif (p != buf && (fputs(color, fp) < 0 ||\n+\t\tif (printing)\n+\t\t\tfputs(prefix, fp);\n+\t\tif (p != buf) {\n+\t\t\tif (fputs(color, fp) < 0 ||\n \t\t\t\tfwrite(buf, p ? p - buf : count, 1, fp) != 1 ||\n-\t\t\t\tfputs(GIT_COLOR_RESET, fp) < 0))\n-\t\t\treturn -1;\n+\t\t\t\tfputs(reset, fp) < 0)\n+\t\t\t\treturn -1;\n+\t\t}\n \t\tif (!p)\n \t\t\treturn 0;\n \t\tif (fputc('\\n', fp) < 0)\n \t\t\treturn -1;\n \t\tcount -= p + 1 - buf;\n \t\tbuf = p + 1;\n+\t\tprinting = 1;\n \t}\n \treturn 0;\n }\ndiff --git a/color.h b/color.h\nindex 5c264b0..55fea4f 100644\n--- a/color.h\n+++ b/color.h\n@@ -61,6 +61,7 @@ __attribute__((format (printf, 3, 4)))\n int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);\n __attribute__((format (printf, 3, 4)))\n int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);\n-int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf);\n+int color_fwrite_lines(FILE *fp, const char *color, size_t count,\n+\tconst char *buf, const char *prefix);\n \n #endif /* COLOR_H */\ndiff --git a/diff.c b/diff.c\nindex ed97115..216cd5b 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -600,7 +600,8 @@ static void diff_words_append(char *line, unsigned long len,\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 };\n \n@@ -609,11 +610,21 @@ static void fn_out_diff_words_aux(void *priv, char *line, unsigned long len)\n \tstruct diff_words_data *diff_words = priv;\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+\tint print = 0;\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->file, 0, 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@@ -629,20 +640,39 @@ 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\tfwrite(diff_words->current_plus,\n-\t\t\t\tplus_begin - diff_words->current_plus, 1,\n-\t\t\t\tdiff_words->file);\n-\tif (minus_begin != minus_end)\n-\t\tcolor_fwrite_lines(diff_words->file,\n+\tif (diff_words->current_plus != plus_begin) {\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\t\tprint = 1;\n+\t\t}\n+\t\tcolor_fwrite_lines(diff_words->opt->file, \"\",\n+\t\t\t\tplus_begin - diff_words->current_plus,\n+\t\t\t\tdiff_words->current_plus, line_prefix);\n+\t}\n+\tif (minus_begin != minus_end) {\n+\t\tif ((plus_begin > diff_words->plus.text.ptr &&\n+\t\t\t*(plus_begin - 1) == '\\n') || \n+\t\t\t(minus_first == 1 && print == 0))\n+\t\t\tfputs(line_prefix, diff_words->opt->file);\n+\t\tcolor_fwrite_lines(diff_words->opt->file,\n \t\t\t\tdiff_get_color(1, DIFF_FILE_OLD),\n-\t\t\t\tminus_end - minus_begin, minus_begin);\n-\tif (plus_begin != plus_end)\n-\t\tcolor_fwrite_lines(diff_words->file,\n+\t\t\t\tminus_end - minus_begin, minus_begin, line_prefix);\n+\t}\n+\tif (plus_begin != plus_end) {\n+\t\tif((minus_len == 0 && plus_first == 1 && print == 0) ||\n+\t\t\t(plus_begin > diff_words->plus.text.ptr &&\n+\t\t\t*(plus_begin - 1) == '\\n' && minus_len == 0))\n+\t\t\tfputs(line_prefix, diff_words->opt->file);\n+\t\tcolor_fwrite_lines(diff_words->opt->file,\n \t\t\t\tdiff_get_color(1, DIFF_FILE_NEW),\n-\t\t\t\tplus_end - plus_begin, plus_begin);\n+\t\t\t\tplus_end - plus_begin, plus_begin, line_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@@ -721,17 +751,29 @@ static void diff_words_show(struct diff_words_data *diff_words)\n \txpparam_t xpp;\n \txdemitconf_t xecfg;\n \tmmfile_t minus, plus;\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->file, 0, 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\tcolor_fwrite_lines(diff_words->file,\n+\t\tfputs(line_prefix, diff_words->opt->file);\n+\t\tcolor_fwrite_lines(diff_words->opt->file,\n \t\t\tdiff_get_color(1, DIFF_FILE_OLD),\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@@ -745,11 +787,17 @@ 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\tfwrite(diff_words->current_plus,\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\tcolor_fwrite_lines(diff_words->opt->file, \"\",\n \t\t\tdiff_words->plus.text.ptr + diff_words->plus.text.size\n-\t\t\t- diff_words->current_plus, 1,\n-\t\t\tdiff_words->file);\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@@ -1835,7 +1883,7 @@ static void builtin_diff(const char *name_a,\n \t\tif (DIFF_OPT_TST(o, COLOR_DIFF_WORDS)) {\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->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.1.94.gc3269\n"},{"id":"141790","messageId":"201005170845.59018.trast@student.ethz.ch","threadId":"23811","inReplyTo":"1273921331-32702-3-git-send-email-struggleyb.nku@gmail.com","subject":"Re: [PATCH 2/7] Change to call the new emit_line.","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2010-05-17T06:45:58Z","receivedAt":"2010-05-17T06:45:58Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Bo Yang wrote:\n> Call the new emit_line function.\n\nThis should be squashed into the last patch so as to keep the\nresulting code working.\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"141791","messageId":"201005170852.31546.trast@student.ethz.ch","threadId":"23811","inReplyTo":"1273921331-32702-5-git-send-email-struggleyb.nku@gmail.com","subject":"Re: [PATCH 4/7] diff.c: Output the text graph padding before each diff line.","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2010-05-17T06:52:31Z","receivedAt":"2010-05-17T06:52:31Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Bo Yang wrote:\n> diff --git a/diff.c b/diff.c\n> index 9bd9063..4a10d16 100644\n> --- a/diff.c\n> +++ b/diff.c\n> @@ -487,6 +487,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->file, 0, o->output_prefix_data);\n> +\t\tline_prefix = msgbuf->buf;\n> +\t}\n\nUmm.  This snippet of code means that the callback can't to much\nexcept return or print a string depending on the value of the second\nargument, doesn't it?\n\nSo why not either make it explicit and just put a char* field there,\nor make a more generic callback that replaces write() (or so) and\ngets a chance to mangle the output in any way it likes?\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"141793","messageId":"201005170857.47545.trast@student.ethz.ch","threadId":"23811","inReplyTo":"1273921331-32702-7-git-send-email-struggleyb.nku@gmail.com","subject":"Re: [PATCH 6/7] Register a callback for graph output.","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2010-05-17T06:57:47Z","receivedAt":"2010-05-17T06:57:47Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Bo Yang wrote:\n> +static struct strbuf *diff_output_prefix_callback(FILE *file, int print, 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> +\tif (print) {\n> +\t\tfwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);\n> +\t}\n> +\treturn &msgbuf;\n> +}\n> +\n\nOk, this partially answers my last mail and means that a simple string\nwould be too tedious, so a callback is needed.\n\nIt leaks the 'msgbuf' in the 'printing' case though.\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"141794","messageId":"201005170859.28022.trast@student.ethz.ch","threadId":"23811","inReplyTo":"1273921331-32702-8-git-send-email-struggleyb.nku@gmail.com","subject":"Re: [PATCH 7/7] Make --color-words work well with --graph.","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2010-05-17T06:59:27Z","receivedAt":"2010-05-17T06:59:27Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Bo Yang wrote:\n> @@ -629,20 +640,39 @@ 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\tfwrite(diff_words->current_plus,\n> -\t\t\t\tplus_begin - diff_words->current_plus, 1,\n> -\t\t\t\tdiff_words->file);\n> -\tif (minus_begin != minus_end)\n> -\t\tcolor_fwrite_lines(diff_words->file,\n> +\tif (diff_words->current_plus != plus_begin) {\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\t\tprint = 1;\n\nAre these border checks needed/the best solution?  If so, please can\nyou put an explanation in the commit message?\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"}]}