Merge branch 'lm/git-blame-el' into maint
[git.git] / diff.c
diff --git a/diff.c b/diff.c
index 7da16c9590805dc687d7dc67acac2cb104144036..62cbe141efb411e831484fc36c0cba95a2b8846b 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -1443,8 +1443,8 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
 {
        int i, len, add, del, adds = 0, dels = 0;
        uintmax_t max_change = 0, max_len = 0;
-       int total_files = data->nr;
-       int width, name_width, graph_width, number_width = 4, count;
+       int total_files = data->nr, count;
+       int width, name_width, graph_width, number_width = 0, bin_width = 0;
        const char *reset, *add_c, *del_c;
        const char *line_prefix = "";
        int extra_shown = 0;
@@ -1480,8 +1480,21 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
                if (max_len < len)
                        max_len = len;
 
-               if (file->is_binary || file->is_unmerged)
+               if (file->is_unmerged) {
+                       /* "Unmerged" is 8 characters */
+                       bin_width = bin_width < 8 ? 8 : bin_width;
                        continue;
+               }
+               if (file->is_binary) {
+                       /* "Bin XXX -> YYY bytes" */
+                       int w = 14 + decimal_width(file->added)
+                               + decimal_width(file->deleted);
+                       bin_width = bin_width < w ? w : bin_width;
+                       /* Display change counts aligned with "Bin" */
+                       number_width = 3;
+                       continue;
+               }
+
                if (max_change < change)
                        max_change = change;
        }
@@ -1506,12 +1519,22 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
         * stat_name_width fixes the maximum width of the filename,
         * and is also used to divide available columns if there
         * aren't enough.
+        *
+        * Binary files are displayed with "Bin XXX -> YYY bytes"
+        * instead of the change count and graph. This part is treated
+        * similarly to the graph part, except that it is not
+        * "scaled". If total width is too small to accomodate the
+        * guaranteed minimum width of the filename part and the
+        * separators and this message, this message will "overflow"
+        * making the line longer than the maximum width.
         */
 
        if (options->stat_width == -1)
                width = term_columns() - options->output_prefix_length;
        else
                width = options->stat_width ? options->stat_width : 80;
+       number_width = decimal_width(max_change) > number_width ?
+               decimal_width(max_change) : number_width;
 
        if (options->stat_graph_width == -1)
                options->stat_graph_width = diff_stat_graph_width;
@@ -1525,10 +1548,14 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
 
        /*
         * First assign sizes that are wanted, ignoring available width.
+        * strlen("Bin XXX -> YYY bytes") == bin_width, and the part
+        * starting from "XXX" should fit in graph_width.
         */
-       graph_width = (options->stat_graph_width &&
-                      options->stat_graph_width < max_change) ?
-               options->stat_graph_width : max_change;
+       graph_width = max_change + 4 > bin_width ? max_change : bin_width - 4;
+       if (options->stat_graph_width &&
+           options->stat_graph_width < graph_width)
+               graph_width = options->stat_graph_width;
+
        name_width = (options->stat_name_width > 0 &&
                      options->stat_name_width < max_len) ?
                options->stat_name_width : max_len;
@@ -1587,8 +1614,12 @@ 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",
+                       fprintf(options->file, " %*s", number_width, "Bin");
+                       if (!added && !deleted) {
+                               putc('\n', options->file);
+                               continue;
+                       }
+                       fprintf(options->file, " %s%"PRIuMAX"%s",
                                del_c, deleted, reset);
                        fprintf(options->file, " -> ");
                        fprintf(options->file, "%s%"PRIuMAX"%s",
@@ -1600,7 +1631,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
                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");
+                       fprintf(options->file, " Unmerged\n");
                        continue;
                }
 
@@ -1629,8 +1660,9 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
                }
                fprintf(options->file, "%s", line_prefix);
                show_name(options->file, prefix, name, len);
-               fprintf(options->file, "%5"PRIuMAX"%s", added + deleted,
-                               added + deleted ? " " : "");
+               fprintf(options->file, " %*"PRIuMAX"%s",
+                       number_width, added + deleted,
+                       added + deleted ? " " : "");
                show_graph(options->file, '+', add, add_c, reset);
                show_graph(options->file, '-', del, del_c, reset);
                fprintf(options->file, "\n");
@@ -1661,17 +1693,16 @@ static void show_shortstats(struct diffstat_t *data, struct diff_options *option
                return;
 
        for (i = 0; i < data->nr; i++) {
-               if (!data->files[i]->is_binary &&
-                   !data->files[i]->is_unmerged) {
-                       int added = data->files[i]->added;
-                       int deleted= data->files[i]->deleted;
-                       if (!data->files[i]->is_renamed &&
-                           (added + deleted == 0)) {
-                               total_files--;
-                       } else {
-                               adds += added;
-                               dels += deleted;
-                       }
+               int added = data->files[i]->added;
+               int deleted= data->files[i]->deleted;
+
+               if (data->files[i]->is_unmerged)
+                       continue;
+               if (!data->files[i]->is_renamed && (added + deleted == 0)) {
+                       total_files--;
+               } else if (!data->files[i]->is_binary) { /* don't count bytes */
+                       adds += added;
+                       dels += deleted;
                }
        }
        if (options->output_prefix) {
@@ -2371,6 +2402,7 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
 {
        mmfile_t mf1, mf2;
        struct diffstat_file *data;
+       int same_contents;
 
        data = diffstat_add(diffstat, name_a, name_b);
 
@@ -2379,10 +2411,17 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
                return;
        }
 
+       same_contents = !hashcmp(one->sha1, two->sha1);
+
        if (diff_filespec_is_binary(one) || diff_filespec_is_binary(two)) {
                data->is_binary = 1;
-               data->added = diff_filespec_size(two);
-               data->deleted = diff_filespec_size(one);
+               if (same_contents) {
+                       data->added = 0;
+                       data->deleted = 0;
+               } else {
+                       data->added = diff_filespec_size(two);
+                       data->deleted = diff_filespec_size(one);
+               }
        }
 
        else if (complete_rewrite) {
@@ -2392,7 +2431,7 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
                data->added = count_lines(two->data, two->size);
        }
 
-       else {
+       else if (!same_contents) {
                /* Crazy xdl interfaces.. */
                xpparam_t xpp;
                xdemitconf_t xecfg;
@@ -2580,22 +2619,6 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int
        return 0;
 }
 
-static int populate_from_stdin(struct diff_filespec *s)
-{
-       struct strbuf buf = STRBUF_INIT;
-       size_t size = 0;
-
-       if (strbuf_read(&buf, 0, 0) < 0)
-               return error("error while reading from stdin %s",
-                                    strerror(errno));
-
-       s->should_munmap = 0;
-       s->data = strbuf_detach(&buf, &size);
-       s->size = size;
-       s->should_free = 1;
-       return 0;
-}
-
 static int diff_populate_gitlink(struct diff_filespec *s, int size_only)
 {
        int len;
@@ -2645,9 +2668,6 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
                struct stat st;
                int fd;
 
-               if (!strcmp(s->path, "-"))
-                       return populate_from_stdin(s);
-
                if (lstat(s->path, &st) < 0) {
                        if (errno == ENOENT) {
                        err_empty:
@@ -2972,9 +2992,8 @@ static void run_diff_cmd(const char *pgm,
        int complete_rewrite = (p->status == DIFF_STATUS_MODIFIED) && p->score;
        int must_show_header = 0;
 
-       if (!DIFF_OPT_TST(o, ALLOW_EXTERNAL))
-               pgm = NULL;
-       else {
+
+       if (DIFF_OPT_TST(o, ALLOW_EXTERNAL)) {
                struct userdiff_driver *drv = userdiff_find_by_path(attr_path);
                if (drv && drv->external)
                        pgm = drv->external;
@@ -3009,7 +3028,7 @@ static void diff_fill_sha1_info(struct diff_filespec *one)
        if (DIFF_FILE_VALID(one)) {
                if (!one->sha1_valid) {
                        struct stat st;
-                       if (!strcmp(one->path, "-")) {
+                       if (one->is_stdin) {
                                hashcpy(one->sha1, null_sha1);
                                return;
                        }
@@ -3054,6 +3073,9 @@ static void run_diff(struct diff_filepair *p, struct diff_options *o)
        if (o->prefix_length)
                strip_prefix(o->prefix_length, &name, &other);
 
+       if (!DIFF_OPT_TST(o, ALLOW_EXTERNAL))
+               pgm = NULL;
+
        if (DIFF_PAIR_UNMERGED(p)) {
                run_diff_cmd(pgm, name, NULL, attr_path,
                             NULL, NULL, NULL, o, p);