From a3c158d4a58b17c1e4a8d3f793344beee21d3a4c Mon Sep 17 00:00:00 2001 From: Bo Yang Date: Wed, 26 May 2010 15:08:02 +0800 Subject: Add a prefix output callback to diff output The callback can be used to add some prefix string to each line of diff output. Signed-off-by: Bo Yang Signed-off-by: Junio C Hamano diff --git a/diff.c b/diff.c index 494f560..e2f910a 100644 --- a/diff.c +++ b/diff.c @@ -194,8 +194,8 @@ struct emit_callback { sane_truncate_fn truncate; const char **label_path; struct diff_words_data *diff_words; + struct diff_options *opt; int *found_changesp; - FILE *file; struct strbuf *header; }; @@ -282,11 +282,19 @@ static void check_blank_at_eof(mmfile_t *mf1, mmfile_t *mf2, ecbdata->blank_at_eof_in_postimage = (at - l2) + 1; } -static void emit_line_0(FILE *file, const char *set, const char *reset, +static void emit_line_0(struct diff_options *o, const char *set, const char *reset, int first, const char *line, int len) { int has_trailing_newline, has_trailing_carriage_return; int nofirst; + FILE *file = o->file; + + if (o->output_prefix) { + struct strbuf *msg = NULL; + msg = o->output_prefix(o, o->output_prefix_data); + assert(msg); + fwrite(msg->buf, msg->len, 1, file); + } if (len == 0) { has_trailing_newline = (first == '\n'); @@ -316,10 +324,10 @@ static void emit_line_0(FILE *file, const char *set, const char *reset, fputc('\n', file); } -static void emit_line(FILE *file, const char *set, const char *reset, +static void emit_line(struct diff_options *o, const char *set, const char *reset, const char *line, int len) { - emit_line_0(file, set, reset, line[0], line+1, len-1); + emit_line_0(o, set, reset, line[0], line+1, len-1); } static int new_blank_line_at_eof(struct emit_callback *ecbdata, const char *line, int len) @@ -341,15 +349,15 @@ static void emit_add_line(const char *reset, const char *set = diff_get_color(ecbdata->color_diff, DIFF_FILE_NEW); if (!*ws) - emit_line_0(ecbdata->file, set, reset, '+', line, len); + emit_line_0(ecbdata->opt, set, reset, '+', line, len); else if (new_blank_line_at_eof(ecbdata, line, len)) /* Blank line at EOF - paint '+' as well */ - emit_line_0(ecbdata->file, ws, reset, '+', line, len); + emit_line_0(ecbdata->opt, ws, reset, '+', line, len); else { /* Emit just the prefix, then the rest. */ - emit_line_0(ecbdata->file, set, reset, '+', "", 0); + emit_line_0(ecbdata->opt, set, reset, '+', "", 0); ws_check_emit(line, len, ecbdata->ws_rule, - ecbdata->file, set, reset, ws); + ecbdata->opt->file, set, reset, ws); } } @@ -370,23 +378,23 @@ static void emit_hunk_header(struct emit_callback *ecbdata, if (len < 10 || memcmp(line, atat, 2) || !(ep = memmem(line + 2, len - 2, atat, 2))) { - emit_line(ecbdata->file, plain, reset, line, len); + emit_line(ecbdata->opt, plain, reset, line, len); return; } ep += 2; /* skip over @@ */ /* The hunk header in fraginfo color */ - emit_line(ecbdata->file, frag, reset, line, ep - line); + emit_line(ecbdata->opt, frag, reset, line, ep - line); /* blank before the func header */ for (cp = ep; ep - line < len; ep++) if (*ep != ' ' && *ep != '\t') break; if (ep != cp) - emit_line(ecbdata->file, plain, reset, cp, ep - cp); + emit_line(ecbdata->opt, plain, reset, cp, ep - cp); if (ep < line + len) - emit_line(ecbdata->file, func, reset, ep, line + len - ep); + emit_line(ecbdata->opt, func, reset, ep, line + len - ep); } static struct diff_tempfile *claim_diff_tempfile(void) { @@ -446,7 +454,7 @@ static void emit_rewrite_lines(struct emit_callback *ecb, len = endp ? (endp - data + 1) : size; if (prefix != '+') { ecb->lno_in_preimage++; - emit_line_0(ecb->file, old, reset, '-', + emit_line_0(ecb->opt, old, reset, '-', data, len); } else { ecb->lno_in_postimage++; @@ -458,7 +466,7 @@ static void emit_rewrite_lines(struct emit_callback *ecb, if (!endp) { const char *plain = diff_get_color(ecb->color_diff, DIFF_PLAIN); - emit_line_0(ecb->file, plain, reset, '\\', + emit_line_0(ecb->opt, plain, reset, '\\', nneof, strlen(nneof)); } } @@ -508,7 +516,7 @@ static void emit_rewrite_diff(const char *name_a, ecbdata.color_diff = color_diff; ecbdata.found_changesp = &o->found_changes; ecbdata.ws_rule = whitespace_rule(name_b ? name_b : name_a); - ecbdata.file = o->file; + ecbdata.opt = o; if (ecbdata.ws_rule & WS_BLANK_AT_EOF) { mmfile_t mf1, mf2; mf1.ptr = (char *)data_one; @@ -840,7 +848,7 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) const char *reset = diff_get_color(ecbdata->color_diff, DIFF_RESET); if (ecbdata->header) { - fprintf(ecbdata->file, "%s", ecbdata->header->buf); + fprintf(ecbdata->opt->file, "%s", ecbdata->header->buf); strbuf_reset(ecbdata->header); ecbdata->header = NULL; } @@ -852,9 +860,9 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) name_a_tab = strchr(ecbdata->label_path[0], ' ') ? "\t" : ""; name_b_tab = strchr(ecbdata->label_path[1], ' ') ? "\t" : ""; - fprintf(ecbdata->file, "%s--- %s%s%s\n", + fprintf(ecbdata->opt->file, "%s--- %s%s%s\n", meta, ecbdata->label_path[0], reset, name_a_tab); - fprintf(ecbdata->file, "%s+++ %s%s%s\n", + fprintf(ecbdata->opt->file, "%s+++ %s%s%s\n", meta, ecbdata->label_path[1], reset, name_b_tab); ecbdata->label_path[0] = ecbdata->label_path[1] = NULL; } @@ -872,15 +880,15 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) find_lno(line, ecbdata); emit_hunk_header(ecbdata, line, len); if (line[len-1] != '\n') - putc('\n', ecbdata->file); + putc('\n', ecbdata->opt->file); return; } if (len < 1) { - emit_line(ecbdata->file, reset, reset, line, len); + emit_line(ecbdata->opt, reset, reset, line, len); if (ecbdata->diff_words && ecbdata->diff_words->type == DIFF_WORDS_PORCELAIN) - fputs("~\n", ecbdata->file); + fputs("~\n", ecbdata->opt->file); return; } @@ -896,11 +904,11 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) } diff_words_flush(ecbdata); if (ecbdata->diff_words->type == DIFF_WORDS_PORCELAIN) { - emit_line(ecbdata->file, plain, reset, line, len); - fputs("~\n", ecbdata->file); + emit_line(ecbdata->opt, plain, reset, line, len); + fputs("~\n", ecbdata->opt->file); } else { /* don't print the prefix character */ - emit_line(ecbdata->file, plain, reset, line+1, len-1); + emit_line(ecbdata->opt, plain, reset, line+1, len-1); } return; } @@ -912,7 +920,7 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) ecbdata->lno_in_preimage++; if (line[0] == ' ') ecbdata->lno_in_postimage++; - emit_line(ecbdata->file, color, reset, line, len); + emit_line(ecbdata->opt, color, reset, line, len); } else { ecbdata->lno_in_postimage++; emit_add_line(reset, ecbdata, line + 1, len - 1); @@ -1477,7 +1485,7 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len) fprintf(data->o->file, "%s:%d: %s.\n", data->filename, data->lineno, err); free(err); - emit_line(data->o->file, set, reset, line, 1); + emit_line(data->o, set, reset, line, 1); ws_check_emit(line + 1, len - 1, data->ws_rule, data->o->file, set, reset, ws); } else if (line[0] == ' ') { @@ -1787,7 +1795,7 @@ static void builtin_diff(const char *name_a, ecbdata.ws_rule = whitespace_rule(name_b ? name_b : name_a); if (ecbdata.ws_rule & WS_BLANK_AT_EOF) check_blank_at_eof(&mf1, &mf2, &ecbdata); - ecbdata.file = o->file; + ecbdata.opt = o; ecbdata.header = header.len ? &header : NULL; xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts; xecfg.ctxlen = o->context; diff --git a/diff.h b/diff.h index 9ace08c..b4eefa7 100644 --- a/diff.h +++ b/diff.h @@ -9,6 +9,7 @@ struct rev_info; struct diff_options; struct diff_queue_struct; +struct strbuf; typedef void (*change_fn_t)(struct diff_options *options, unsigned old_mode, unsigned new_mode, @@ -25,6 +26,8 @@ typedef void (*add_remove_fn_t)(struct diff_options *options, typedef void (*diff_format_fn_t)(struct diff_queue_struct *q, struct diff_options *options, void *data); +typedef struct strbuf *(*diff_prefix_fn_t)(struct diff_options *opt, void *data); + #define DIFF_FORMAT_RAW 0x0001 #define DIFF_FORMAT_DIFFSTAT 0x0002 #define DIFF_FORMAT_NUMSTAT 0x0004 @@ -130,6 +133,8 @@ struct diff_options { add_remove_fn_t add_remove; diff_format_fn_t format_callback; void *format_callback_data; + diff_prefix_fn_t output_prefix; + void *output_prefix_data; }; enum color_diff { -- cgit v0.10.2-6-g49f6 From 81bd1b2a96ecc12dcc72fc2b22aa5b7691186685 Mon Sep 17 00:00:00 2001 From: Bo Yang Date: Wed, 26 May 2010 15:08:03 +0800 Subject: Output the graph columns at the end of the commit message There is an empty line between the commit message and the diff output. Add the graph columns as prefix of this line. Signed-off-by: Bo Yang Signed-off-by: Junio C Hamano diff --git a/log-tree.c b/log-tree.c index d3ae969..2e2be7c 100644 --- a/log-tree.c +++ b/log-tree.c @@ -469,6 +469,12 @@ int log_tree_diff_flush(struct rev_info *opt) int pch = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_PATCH; if ((pch & opt->diffopt.output_format) == pch) printf("---"); + if (opt->diffopt.output_prefix) { + struct strbuf *msg = NULL; + msg = opt->diffopt.output_prefix(&opt->diffopt, + opt->diffopt.output_prefix_data); + fwrite(msg->buf, msg->len, 1, stdout); + } putchar('\n'); } } -- cgit v0.10.2-6-g49f6 From 7be5761073fde260d3aca10883e8688bd30cbccf Mon Sep 17 00:00:00 2001 From: Bo Yang Date: Wed, 26 May 2010 15:23:54 +0800 Subject: diff.c: Output the text graph padding before each diff line Change output from diff with -p/--dirstat/--binary/--numstat/--stat/ --shortstat/--check/--summary options to align with graph paddings. Thanks Jeff King for reporting the '--summary' bug and his initial patch. Signed-off-by: Bo Yang Signed-off-by: Junio C Hamano diff --git a/diff.c b/diff.c index e2f910a..7f2538d 100644 --- a/diff.c +++ b/diff.c @@ -490,6 +490,13 @@ static void emit_rewrite_diff(const char *name_a, char *data_one, *data_two; size_t size_one, size_two; struct emit_callback ecbdata; + char *line_prefix = ""; + struct strbuf *msgbuf; + + if (o && o->output_prefix) { + msgbuf = o->output_prefix(o, o->output_prefix_data); + line_prefix = msgbuf->buf; + } if (diff_mnemonic_prefix && DIFF_OPT_TST(o, REVERSE_DIFF)) { a_prefix = o->b_prefix; @@ -531,9 +538,10 @@ static void emit_rewrite_diff(const char *name_a, lc_a = count_lines(data_one, size_one); lc_b = count_lines(data_two, size_two); fprintf(o->file, - "%s--- %s%s%s\n%s+++ %s%s%s\n%s@@ -", - metainfo, a_name.buf, name_a_tab, reset, - metainfo, b_name.buf, name_b_tab, reset, fraginfo); + "%s%s--- %s%s%s\n%s%s+++ %s%s%s\n%s%s@@ -", + line_prefix, metainfo, a_name.buf, name_a_tab, reset, + line_prefix, metainfo, b_name.buf, name_b_tab, reset, + line_prefix, fraginfo); print_line_count(o->file, lc_a); fprintf(o->file, " +"); print_line_count(o->file, lc_b); @@ -846,6 +854,14 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) const char *meta = diff_get_color(ecbdata->color_diff, DIFF_METAINFO); const char *plain = diff_get_color(ecbdata->color_diff, DIFF_PLAIN); const char *reset = diff_get_color(ecbdata->color_diff, DIFF_RESET); + struct diff_options *o = ecbdata->opt; + char *line_prefix = ""; + struct strbuf *msgbuf; + + if (o && o->output_prefix) { + msgbuf = o->output_prefix(o, o->output_prefix_data); + line_prefix = msgbuf->buf; + } if (ecbdata->header) { fprintf(ecbdata->opt->file, "%s", ecbdata->header->buf); @@ -860,10 +876,10 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) name_a_tab = strchr(ecbdata->label_path[0], ' ') ? "\t" : ""; name_b_tab = strchr(ecbdata->label_path[1], ' ') ? "\t" : ""; - fprintf(ecbdata->opt->file, "%s--- %s%s%s\n", - meta, ecbdata->label_path[0], reset, name_a_tab); - fprintf(ecbdata->opt->file, "%s+++ %s%s%s\n", - meta, ecbdata->label_path[1], reset, name_b_tab); + fprintf(ecbdata->opt->file, "%s%s--- %s%s%s\n", + line_prefix, meta, ecbdata->label_path[0], reset, name_a_tab); + fprintf(ecbdata->opt->file, "%s%s+++ %s%s%s\n", + line_prefix, meta, ecbdata->label_path[1], reset, name_b_tab); ecbdata->label_path[0] = ecbdata->label_path[1] = NULL; } @@ -1100,10 +1116,17 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) int total_files = data->nr; int width, name_width; const char *reset, *set, *add_c, *del_c; + const char *line_prefix = ""; + struct strbuf *msg = NULL; if (data->nr == 0) return; + if (options->output_prefix) { + msg = options->output_prefix(options, options->output_prefix_data); + line_prefix = msg->buf; + } + width = options->stat_width ? options->stat_width : 80; name_width = options->stat_name_width ? options->stat_name_width : 50; @@ -1173,6 +1196,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) } if (data->files[i]->is_binary) { + fprintf(options->file, "%s", line_prefix); show_name(options->file, prefix, name, len); fprintf(options->file, " Bin "); fprintf(options->file, "%s%"PRIuMAX"%s", @@ -1185,6 +1209,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) continue; } else if (data->files[i]->is_unmerged) { + fprintf(options->file, "%s", line_prefix); show_name(options->file, prefix, name, len); fprintf(options->file, " Unmerged\n"); continue; @@ -1207,6 +1232,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) add = scale_linear(add, width, max_change); del = scale_linear(del, width, max_change); } + fprintf(options->file, "%s", line_prefix); show_name(options->file, prefix, name, len); fprintf(options->file, "%5"PRIuMAX"%s", added + deleted, added + deleted ? " " : ""); @@ -1214,6 +1240,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) show_graph(options->file, '-', del, del_c, reset); fprintf(options->file, "\n"); } + fprintf(options->file, "%s", line_prefix); fprintf(options->file, " %d files changed, %d insertions(+), %d deletions(-)\n", total_files, adds, dels); @@ -1240,6 +1267,12 @@ static void show_shortstats(struct diffstat_t *data, struct diff_options *option } } } + if (options->output_prefix) { + struct strbuf *msg = NULL; + msg = options->output_prefix(options, + options->output_prefix_data); + fprintf(options->file, "%s", msg->buf); + } fprintf(options->file, " %d files changed, %d insertions(+), %d deletions(-)\n", total_files, adds, dels); } @@ -1254,6 +1287,13 @@ static void show_numstat(struct diffstat_t *data, struct diff_options *options) for (i = 0; i < data->nr; i++) { struct diffstat_file *file = data->files[i]; + if (options->output_prefix) { + struct strbuf *msg = NULL; + msg = options->output_prefix(options, + options->output_prefix_data); + fprintf(options->file, "%s", msg->buf); + } + if (file->is_binary) fprintf(options->file, "-\t-\t"); else @@ -1289,10 +1329,18 @@ struct dirstat_dir { int alloc, nr, percent, cumulative; }; -static long gather_dirstat(FILE *file, struct dirstat_dir *dir, unsigned long changed, const char *base, int baselen) +static long gather_dirstat(struct diff_options *opt, struct dirstat_dir *dir, + unsigned long changed, const char *base, int baselen) { unsigned long this_dir = 0; unsigned int sources = 0; + const char *line_prefix = ""; + struct strbuf *msg = NULL; + + if (opt->output_prefix) { + msg = opt->output_prefix(opt, opt->output_prefix_data); + line_prefix = msg->buf; + } while (dir->nr) { struct dirstat_file *f = dir->files; @@ -1307,7 +1355,7 @@ static long gather_dirstat(FILE *file, struct dirstat_dir *dir, unsigned long ch slash = strchr(f->name + baselen, '/'); if (slash) { int newbaselen = slash + 1 - f->name; - this = gather_dirstat(file, dir, changed, f->name, newbaselen); + this = gather_dirstat(opt, dir, changed, f->name, newbaselen); sources++; } else { this = f->changed; @@ -1329,7 +1377,8 @@ static long gather_dirstat(FILE *file, struct dirstat_dir *dir, unsigned long ch if (permille) { int percent = permille / 10; if (percent >= dir->percent) { - fprintf(file, "%4d.%01d%% %.*s\n", percent, permille % 10, baselen, base); + fprintf(opt->file, "%s%4d.%01d%% %.*s\n", line_prefix, + percent, permille % 10, baselen, base); if (!dir->cumulative) return 0; } @@ -1409,7 +1458,7 @@ static void show_dirstat(struct diff_options *options) /* Show all directories with more than x% of the changes */ qsort(dir.files, dir.nr, sizeof(dir.files[0]), dirstat_compare); - gather_dirstat(options->file, &dir, changed, "", 0); + gather_dirstat(options, &dir, changed, "", 0); } static void free_diffstat_info(struct diffstat_t *diffstat) @@ -1467,6 +1516,15 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len) const char *reset = diff_get_color(color_diff, DIFF_RESET); const char *set = diff_get_color(color_diff, DIFF_FILE_NEW); char *err; + char *line_prefix = ""; + struct strbuf *msgbuf; + + assert(data->o); + if (data->o->output_prefix) { + msgbuf = data->o->output_prefix(data->o, + data->o->output_prefix_data); + line_prefix = msgbuf->buf; + } if (line[0] == '+') { unsigned bad; @@ -1474,16 +1532,16 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len) if (is_conflict_marker(line + 1, marker_size, len - 1)) { data->status |= 1; fprintf(data->o->file, - "%s:%d: leftover conflict marker\n", - data->filename, data->lineno); + "%s%s:%d: leftover conflict marker\n", + line_prefix, data->filename, data->lineno); } bad = ws_check(line + 1, len - 1, data->ws_rule); if (!bad) return; data->status |= bad; err = whitespace_error_string(bad); - fprintf(data->o->file, "%s:%d: %s.\n", - data->filename, data->lineno, err); + fprintf(data->o->file, "%s%s:%d: %s.\n", + line_prefix, data->filename, data->lineno, err); free(err); emit_line(data->o, set, reset, line, 1); ws_check_emit(line + 1, len - 1, data->ws_rule, @@ -1523,7 +1581,7 @@ static unsigned char *deflate_it(char *data, return deflated; } -static void emit_binary_diff_body(FILE *file, mmfile_t *one, mmfile_t *two) +static void emit_binary_diff_body(FILE *file, mmfile_t *one, mmfile_t *two, char *prefix) { void *cp; void *delta; @@ -1552,13 +1610,13 @@ static void emit_binary_diff_body(FILE *file, mmfile_t *one, mmfile_t *two) } if (delta && delta_size < deflate_size) { - fprintf(file, "delta %lu\n", orig_size); + fprintf(file, "%sdelta %lu\n", prefix, orig_size); free(deflated); data = delta; data_size = delta_size; } else { - fprintf(file, "literal %lu\n", two->size); + fprintf(file, "%sliteral %lu\n", prefix, two->size); free(delta); data = deflated; data_size = deflate_size; @@ -1576,18 +1634,19 @@ static void emit_binary_diff_body(FILE *file, mmfile_t *one, mmfile_t *two) line[0] = bytes - 26 + 'a' - 1; encode_85(line + 1, cp, bytes); cp = (char *) cp + bytes; + fprintf(file, "%s", prefix); fputs(line, file); fputc('\n', file); } - fprintf(file, "\n"); + fprintf(file, "%s\n", prefix); free(data); } -static void emit_binary_diff(FILE *file, mmfile_t *one, mmfile_t *two) +static void emit_binary_diff(FILE *file, mmfile_t *one, mmfile_t *two, char *prefix) { - fprintf(file, "GIT binary patch\n"); - emit_binary_diff_body(file, one, two); - emit_binary_diff_body(file, two, one); + fprintf(file, "%sGIT binary patch\n", prefix); + emit_binary_diff_body(file, one, two, prefix); + emit_binary_diff_body(file, two, one, prefix); } static void diff_filespec_load_driver(struct diff_filespec *one) @@ -1676,6 +1735,13 @@ static void builtin_diff(const char *name_a, struct userdiff_driver *textconv_one = NULL; struct userdiff_driver *textconv_two = NULL; struct strbuf header = STRBUF_INIT; + struct strbuf *msgbuf; + char *line_prefix = ""; + + if (o->output_prefix) { + msgbuf = o->output_prefix(o, o->output_prefix_data); + line_prefix = msgbuf->buf; + } if (DIFF_OPT_TST(o, SUBMODULE_LOG) && (!one->mode || S_ISGITLINK(one->mode)) && @@ -1710,22 +1776,22 @@ static void builtin_diff(const char *name_a, b_two = quote_two(b_prefix, name_b + (*name_b == '/')); lbl[0] = DIFF_FILE_VALID(one) ? a_one : "/dev/null"; lbl[1] = DIFF_FILE_VALID(two) ? b_two : "/dev/null"; - strbuf_addf(&header, "%sdiff --git %s %s%s\n", set, a_one, b_two, reset); + strbuf_addf(&header, "%s%sdiff --git %s %s%s\n", line_prefix, set, a_one, b_two, reset); if (lbl[0][0] == '/') { /* /dev/null */ - strbuf_addf(&header, "%snew file mode %06o%s\n", set, two->mode, reset); + strbuf_addf(&header, "%s%snew file mode %06o%s\n", line_prefix, set, two->mode, reset); if (xfrm_msg && xfrm_msg[0]) strbuf_addf(&header, "%s%s%s\n", set, xfrm_msg, reset); } else if (lbl[1][0] == '/') { - strbuf_addf(&header, "%sdeleted file mode %06o%s\n", set, one->mode, reset); + strbuf_addf(&header, "%s%sdeleted file mode %06o%s\n", line_prefix, set, one->mode, reset); if (xfrm_msg && xfrm_msg[0]) strbuf_addf(&header, "%s%s%s\n", set, xfrm_msg, reset); } else { if (one->mode != two->mode) { - strbuf_addf(&header, "%sold mode %06o%s\n", set, one->mode, reset); - strbuf_addf(&header, "%snew mode %06o%s\n", set, two->mode, reset); + strbuf_addf(&header, "%s%sold mode %06o%s\n", line_prefix, set, one->mode, reset); + strbuf_addf(&header, "%s%snew mode %06o%s\n", line_prefix, set, two->mode, reset); } if (xfrm_msg && xfrm_msg[0]) strbuf_addf(&header, "%s%s%s\n", set, xfrm_msg, reset); @@ -1760,10 +1826,10 @@ static void builtin_diff(const char *name_a, fprintf(o->file, "%s", header.buf); strbuf_reset(&header); if (DIFF_OPT_TST(o, BINARY)) - emit_binary_diff(o->file, &mf1, &mf2); + emit_binary_diff(o->file, &mf1, &mf2, line_prefix); else - fprintf(o->file, "Binary files %s and %s differ\n", - lbl[0], lbl[1]); + fprintf(o->file, "%sBinary files %s and %s differ\n", + line_prefix, lbl[0], lbl[1]); o->found_changes = 1; } else { @@ -2389,28 +2455,36 @@ static void fill_metainfo(struct strbuf *msg, struct diff_options *o, struct diff_filepair *p) { + struct strbuf *msgbuf; + char *line_prefix = ""; + + if (o->output_prefix) { + msgbuf = o->output_prefix(o, o->output_prefix_data); + line_prefix = msgbuf->buf; + } + strbuf_init(msg, PATH_MAX * 2 + 300); switch (p->status) { case DIFF_STATUS_COPIED: - strbuf_addf(msg, "similarity index %d%%", similarity_index(p)); - strbuf_addstr(msg, "\ncopy from "); + strbuf_addf(msg, "%ssimilarity index %d%%", line_prefix, similarity_index(p)); + strbuf_addf(msg, "\n%scopy from ", line_prefix); quote_c_style(name, msg, NULL, 0); - strbuf_addstr(msg, "\ncopy to "); + strbuf_addf(msg, "\n%scopy to ", line_prefix); quote_c_style(other, msg, NULL, 0); strbuf_addch(msg, '\n'); break; case DIFF_STATUS_RENAMED: - strbuf_addf(msg, "similarity index %d%%", similarity_index(p)); - strbuf_addstr(msg, "\nrename from "); + strbuf_addf(msg, "%ssimilarity index %d%%", line_prefix, similarity_index(p)); + strbuf_addf(msg, "\n%srename from ", line_prefix); quote_c_style(name, msg, NULL, 0); - strbuf_addstr(msg, "\nrename to "); + strbuf_addf(msg, "\n%srename to ", line_prefix); quote_c_style(other, msg, NULL, 0); strbuf_addch(msg, '\n'); break; case DIFF_STATUS_MODIFIED: if (p->score) { - strbuf_addf(msg, "dissimilarity index %d%%\n", - similarity_index(p)); + strbuf_addf(msg, "%sdissimilarity index %d%%\n", + line_prefix, similarity_index(p)); break; } /* fallthru */ @@ -2427,8 +2501,8 @@ static void fill_metainfo(struct strbuf *msg, (!fill_mmfile(&mf, two) && diff_filespec_is_binary(two))) abbrev = 40; } - strbuf_addf(msg, "index %.*s..%.*s", - abbrev, sha1_to_hex(one->sha1), + strbuf_addf(msg, "%sindex %.*s..%.*s", + line_prefix, abbrev, sha1_to_hex(one->sha1), abbrev, sha1_to_hex(two->sha1)); if (one->mode == two->mode) strbuf_addf(msg, " %06o", one->mode); @@ -3132,6 +3206,11 @@ static void diff_flush_raw(struct diff_filepair *p, struct diff_options *opt) { int line_termination = opt->line_termination; int inter_name_termination = line_termination ? '\t' : '\0'; + if (opt->output_prefix) { + struct strbuf *msg = NULL; + msg = opt->output_prefix(opt, opt->output_prefix_data); + fprintf(opt->file, "%s", msg->buf); + } if (!(opt->output_format & DIFF_FORMAT_NAME_STATUS)) { fprintf(opt->file, ":%06o %06o %s ", p->one->mode, p->two->mode, @@ -3377,48 +3456,62 @@ static void show_file_mode_name(FILE *file, const char *newdelete, struct diff_f } -static void show_mode_change(FILE *file, struct diff_filepair *p, int show_name) +static void show_mode_change(FILE *file, struct diff_filepair *p, int show_name, + const char *line_prefix) { if (p->one->mode && p->two->mode && p->one->mode != p->two->mode) { - fprintf(file, " mode change %06o => %06o%c", p->one->mode, p->two->mode, - show_name ? ' ' : '\n'); + fprintf(file, "%s mode change %06o => %06o%c", line_prefix, p->one->mode, + p->two->mode, show_name ? ' ' : '\n'); if (show_name) { write_name_quoted(p->two->path, file, '\n'); } } } -static void show_rename_copy(FILE *file, const char *renamecopy, struct diff_filepair *p) +static void show_rename_copy(FILE *file, const char *renamecopy, struct diff_filepair *p, + const char *line_prefix) { char *names = pprint_rename(p->one->path, p->two->path); fprintf(file, " %s %s (%d%%)\n", renamecopy, names, similarity_index(p)); free(names); - show_mode_change(file, p, 0); + show_mode_change(file, p, 0, line_prefix); } -static void diff_summary(FILE *file, struct diff_filepair *p) +static void diff_summary(struct diff_options *opt, struct diff_filepair *p) { + FILE *file = opt->file; + char *line_prefix = ""; + + if (opt->output_prefix) { + struct strbuf *buf = opt->output_prefix(opt, opt->output_prefix_data); + line_prefix = buf->buf; + } + switch(p->status) { case DIFF_STATUS_DELETED: + fputs(line_prefix, file); show_file_mode_name(file, "delete", p->one); break; case DIFF_STATUS_ADDED: + fputs(line_prefix, file); show_file_mode_name(file, "create", p->two); break; case DIFF_STATUS_COPIED: - show_rename_copy(file, "copy", p); + fputs(line_prefix, file); + show_rename_copy(file, "copy", p, line_prefix); break; case DIFF_STATUS_RENAMED: - show_rename_copy(file, "rename", p); + fputs(line_prefix, file); + show_rename_copy(file, "rename", p, line_prefix); break; default: if (p->score) { - fputs(" rewrite ", file); + fprintf(file, "%s rewrite ", line_prefix); write_name_quoted(p->two->path, file, ' '); fprintf(file, "(%d%%)\n", similarity_index(p)); } - show_mode_change(file, p, !p->score); + show_mode_change(file, p, !p->score, line_prefix); break; } } @@ -3627,8 +3720,9 @@ void diff_flush(struct diff_options *options) show_dirstat(options); if (output_format & DIFF_FORMAT_SUMMARY && !is_summary_empty(q)) { - for (i = 0; i < q->nr; i++) - diff_summary(options->file, q->queue[i]); + for (i = 0; i < q->nr; i++) { + diff_summary(options, q->queue[i]); + } separator++; } -- cgit v0.10.2-6-g49f6 From 2efcc977646320123c0d461664d25c4c93aaa9ee Mon Sep 17 00:00:00 2001 From: Bo Yang Date: Sat, 29 May 2010 23:32:05 +0800 Subject: Emit a whole line in one go Since the graph prefix will be printed when calling emit_line, so the functions should be used to emit a complete line out once a time. No one should call emit_line to just output some strings instead of a complete line. Use a strbuf to compose the whole line, and then call emit_line to output it once. Signed-off-by: Bo Yang Signed-off-by: Junio C Hamano diff --git a/diff.c b/diff.c index 7f2538d..2a1482a 100644 --- a/diff.c +++ b/diff.c @@ -370,6 +370,9 @@ static void emit_hunk_header(struct emit_callback *ecbdata, const char *reset = diff_get_color(ecbdata->color_diff, DIFF_RESET); static const char atat[2] = { '@', '@' }; const char *cp, *ep; + struct strbuf msgbuf = STRBUF_INIT; + int org_len = len; + int i = 1; /* * As a hunk header must begin with "@@ -, + @@", @@ -384,17 +387,36 @@ static void emit_hunk_header(struct emit_callback *ecbdata, ep += 2; /* skip over @@ */ /* The hunk header in fraginfo color */ - emit_line(ecbdata->opt, frag, reset, line, ep - line); + strbuf_add(&msgbuf, frag, strlen(frag)); + strbuf_add(&msgbuf, line, ep - line); + strbuf_add(&msgbuf, reset, strlen(reset)); + + /* + * trailing "\r\n" + */ + for ( ; i < 3; i++) + if (line[len - i] == '\r' || line[len - i] == '\n') + len--; /* blank before the func header */ for (cp = ep; ep - line < len; ep++) if (*ep != ' ' && *ep != '\t') break; - if (ep != cp) - emit_line(ecbdata->opt, plain, reset, cp, ep - cp); + if (ep != cp) { + strbuf_add(&msgbuf, plain, strlen(plain)); + strbuf_add(&msgbuf, cp, ep - cp); + strbuf_add(&msgbuf, reset, strlen(reset)); + } + + if (ep < line + len) { + strbuf_add(&msgbuf, func, strlen(func)); + strbuf_add(&msgbuf, ep, line + len - ep); + strbuf_add(&msgbuf, reset, strlen(reset)); + } - if (ep < line + len) - emit_line(ecbdata->opt, func, reset, ep, line + len - ep); + strbuf_add(&msgbuf, line + len, org_len - len); + emit_line(ecbdata->opt, "", "", msgbuf.buf, msgbuf.len); + strbuf_release(&msgbuf); } static struct diff_tempfile *claim_diff_tempfile(void) { -- cgit v0.10.2-6-g49f6 From b5a4de9d506030fce1b70a06dc49090a46877c3f Mon Sep 17 00:00:00 2001 From: Bo Yang Date: Wed, 26 May 2010 15:23:56 +0800 Subject: graph.c: register a callback for graph output It will look better if the 'git log --graph' print the graph pading lines before the diff output just like what it does for commit message. And this patch leverage the new diff prefix callback function to achieve this. Signed-off-by: Bo Yang Signed-off-by: Junio C Hamano diff --git a/graph.c b/graph.c index e6bbcaa..ac7c605 100644 --- a/graph.c +++ b/graph.c @@ -211,6 +211,18 @@ struct git_graph { unsigned short default_column_color; }; +static struct strbuf *diff_output_prefix_callback(struct diff_options *opt, void *data) +{ + struct git_graph *graph = data; + static struct strbuf msgbuf = STRBUF_INIT; + + assert(graph); + + strbuf_reset(&msgbuf); + graph_padding_line(graph, &msgbuf); + return &msgbuf; +} + struct git_graph *graph_init(struct rev_info *opt) { struct git_graph *graph = xmalloc(sizeof(struct git_graph)); @@ -244,6 +256,13 @@ struct git_graph *graph_init(struct rev_info *opt) graph->mapping = xmalloc(sizeof(int) * 2 * graph->column_capacity); graph->new_mapping = xmalloc(sizeof(int) * 2 * graph->column_capacity); + /* + * The diff output prefix callback, with this we can make + * all the diff output to align with the graph lines. + */ + opt->diffopt.output_prefix = diff_output_prefix_callback; + opt->diffopt.output_prefix_data = graph; + return graph; } -- cgit v0.10.2-6-g49f6 From 4297c0aeb5cc6b9c1c87d770c91e09ac2a837320 Mon Sep 17 00:00:00 2001 From: Bo Yang Date: Sat, 29 May 2010 23:32:06 +0800 Subject: Make --color-words work well with --graph '--color-words' algorithm can be described as: 1. collect a the minus/plus lines of a diff hunk, divided into minus-lines and plus-lines; 2. break both minus-lines and plus-lines into words and place them into two mmfile_t with one word for each line; 3. use xdiff to run diff on the two mmfile_t to get the words level diff; And for the common parts of the both file, we output the plus side text. diff_words->current_plus is used to trace the current position of the plus file which printed. diff_words->last_minus is used to trace the last minus word printed. For '--graph' to work with '--color-words', we need to output the graph prefix on each line of color words output. Generally, there are two conditions on which we should output the prefix. 1. diff_words->last_minus == 0 && diff_words->current_plus == diff_words->plus.text.ptr that is: the plus text must start as a new line, and if there is no minus word printed, a graph prefix must be printed. 2. diff_words->current_plus > diff_words->plus.text.ptr && *(diff_words->current_plus - 1) == '\n' that is: a graph prefix must be printed following a '\n' Signed-off-by: Bo Yang Signed-off-by: Junio C Hamano diff --git a/diff.c b/diff.c index 2a1482a..974b6a9 100644 --- a/diff.c +++ b/diff.c @@ -622,7 +622,8 @@ struct diff_words_style diff_words_styles[] = { struct diff_words_data { struct diff_words_buffer minus, plus; const char *current_plus; - FILE *file; + int last_minus; + struct diff_options *opt; regex_t *word_regex; enum diff_words_type type; struct diff_words_style *style; @@ -631,10 +632,15 @@ struct diff_words_data { static int fn_out_diff_words_write_helper(FILE *fp, struct diff_words_style_elem *st_el, const char *newline, - size_t count, const char *buf) + size_t count, const char *buf, + const char *line_prefix) { + int print = 0; + while (count) { char *p = memchr(buf, '\n', count); + if (print) + fputs(line_prefix, fp); if (p != buf) { if (st_el->color && fputs(st_el->color, fp) < 0) return -1; @@ -652,21 +658,74 @@ static int fn_out_diff_words_write_helper(FILE *fp, return -1; count -= p + 1 - buf; buf = p + 1; + print = 1; } return 0; } +/* + * '--color-words' algorithm can be described as: + * + * 1. collect a the minus/plus lines of a diff hunk, divided into + * minus-lines and plus-lines; + * + * 2. break both minus-lines and plus-lines into words and + * place them into two mmfile_t with one word for each line; + * + * 3. use xdiff to run diff on the two mmfile_t to get the words level diff; + * + * And for the common parts of the both file, we output the plus side text. + * diff_words->current_plus is used to trace the current position of the plus file + * which printed. diff_words->last_minus is used to trace the last minus word + * printed. + * + * For '--graph' to work with '--color-words', we need to output the graph prefix + * on each line of color words output. Generally, there are two conditions on + * which we should output the prefix. + * + * 1. diff_words->last_minus == 0 && + * diff_words->current_plus == diff_words->plus.text.ptr + * + * that is: the plus text must start as a new line, and if there is no minus + * word printed, a graph prefix must be printed. + * + * 2. diff_words->current_plus > diff_words->plus.text.ptr && + * *(diff_words->current_plus - 1) == '\n' + * + * that is: a graph prefix must be printed following a '\n' + */ +static int color_words_output_graph_prefix(struct diff_words_data *diff_words) +{ + if ((diff_words->last_minus == 0 && + diff_words->current_plus == diff_words->plus.text.ptr) || + (diff_words->current_plus > diff_words->plus.text.ptr && + *(diff_words->current_plus - 1) == '\n')) { + return 1; + } else { + return 0; + } +} + static void fn_out_diff_words_aux(void *priv, char *line, unsigned long len) { struct diff_words_data *diff_words = priv; struct diff_words_style *style = diff_words->style; int minus_first, minus_len, plus_first, plus_len; const char *minus_begin, *minus_end, *plus_begin, *plus_end; + struct diff_options *opt = diff_words->opt; + struct strbuf *msgbuf; + char *line_prefix = ""; if (line[0] != '@' || parse_hunk_header(line, len, &minus_first, &minus_len, &plus_first, &plus_len)) return; + assert(opt); + if (opt->output_prefix) { + msgbuf = opt->output_prefix(opt, opt->output_prefix_data); + line_prefix = msgbuf->buf; + } + /* POSIX requires that first be decremented by one if len == 0... */ if (minus_len) { minus_begin = diff_words->minus.orig[minus_first].begin; @@ -682,21 +741,32 @@ static void fn_out_diff_words_aux(void *priv, char *line, unsigned long len) } else plus_begin = plus_end = diff_words->plus.orig[plus_first].end; - if (diff_words->current_plus != plus_begin) - fn_out_diff_words_write_helper(diff_words->file, + if (color_words_output_graph_prefix(diff_words)) { + fputs(line_prefix, diff_words->opt->file); + } + if (diff_words->current_plus != plus_begin) { + fn_out_diff_words_write_helper(diff_words->opt->file, &style->ctx, style->newline, plus_begin - diff_words->current_plus, - diff_words->current_plus); - if (minus_begin != minus_end) - fn_out_diff_words_write_helper(diff_words->file, + diff_words->current_plus, line_prefix); + if (*(plus_begin - 1) == '\n') + fputs(line_prefix, diff_words->opt->file); + } + if (minus_begin != minus_end) { + fn_out_diff_words_write_helper(diff_words->opt->file, &style->old, style->newline, - minus_end - minus_begin, minus_begin); - if (plus_begin != plus_end) - fn_out_diff_words_write_helper(diff_words->file, + minus_end - minus_begin, minus_begin, + line_prefix); + } + if (plus_begin != plus_end) { + fn_out_diff_words_write_helper(diff_words->opt->file, &style->new, style->newline, - plus_end - plus_begin, plus_begin); + plus_end - plus_begin, plus_begin, + line_prefix); + } diff_words->current_plus = plus_end; + diff_words->last_minus = minus_first; } /* This function starts looking at *begin, and returns 0 iff a word was found. */ @@ -777,16 +847,29 @@ static void diff_words_show(struct diff_words_data *diff_words) mmfile_t minus, plus; struct diff_words_style *style = diff_words->style; + struct diff_options *opt = diff_words->opt; + struct strbuf *msgbuf; + char *line_prefix = ""; + + assert(opt); + if (opt->output_prefix) { + msgbuf = opt->output_prefix(opt, opt->output_prefix_data); + line_prefix = msgbuf->buf; + } + /* special case: only removal */ if (!diff_words->plus.text.size) { - fn_out_diff_words_write_helper(diff_words->file, + fputs(line_prefix, diff_words->opt->file); + fn_out_diff_words_write_helper(diff_words->opt->file, &style->old, style->newline, - diff_words->minus.text.size, diff_words->minus.text.ptr); + diff_words->minus.text.size, + diff_words->minus.text.ptr, line_prefix); diff_words->minus.text.size = 0; return; } diff_words->current_plus = diff_words->plus.text.ptr; + diff_words->last_minus = 0; memset(&xpp, 0, sizeof(xpp)); memset(&xecfg, 0, sizeof(xecfg)); @@ -800,11 +883,15 @@ static void diff_words_show(struct diff_words_data *diff_words) free(minus.ptr); free(plus.ptr); if (diff_words->current_plus != diff_words->plus.text.ptr + - diff_words->plus.text.size) - fn_out_diff_words_write_helper(diff_words->file, + diff_words->plus.text.size) { + if (color_words_output_graph_prefix(diff_words)) + fputs(line_prefix, diff_words->opt->file); + fn_out_diff_words_write_helper(diff_words->opt->file, &style->ctx, style->newline, diff_words->plus.text.ptr + diff_words->plus.text.size - - diff_words->current_plus, diff_words->current_plus); + - diff_words->current_plus, diff_words->current_plus, + line_prefix); + } diff_words->minus.text.size = diff_words->plus.text.size = 0; } @@ -1902,8 +1989,8 @@ static void builtin_diff(const char *name_a, ecbdata.diff_words = xcalloc(1, sizeof(struct diff_words_data)); - ecbdata.diff_words->file = o->file; ecbdata.diff_words->type = o->word_diff; + ecbdata.diff_words->opt = o; if (!o->word_regex) o->word_regex = userdiff_word_regex(one); if (!o->word_regex) -- cgit v0.10.2-6-g49f6