Code

diff --stat: show bars of same length for paths with same amount of changes
[git.git] / diff.c
diff --git a/diff.c b/diff.c
index d922b77aef2da84824a8e14fc21961e36e6d2e36..74db18846f3149822bb1cd9b988feb953cc309dd 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -1267,13 +1267,15 @@ const char mime_boundary_leader[] = "------------";
 
 static int scale_linear(int it, int width, int max_change)
 {
+       if (!it)
+               return 0;
        /*
-        * make sure that at least one '-' is printed if there were deletions,
-        * and likewise for '+'.
+        * make sure that at least one '-' or '+' is printed if
+        * there is any change to this path. The easiest way is to
+        * scale linearly as if the alloted width is one column shorter
+        * than it is, and then add 1 to the result.
         */
-       if (max_change < 2)
-               return it;
-       return ((it - 1) * (width - 1) + max_change - 1) / (max_change - 1);
+       return 1 + (it * (width - 1) / max_change);
 }
 
 static void show_name(FILE *file,
@@ -1440,8 +1442,19 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
                dels += del;
 
                if (width <= max_change) {
-                       add = scale_linear(add, width, max_change);
-                       del = scale_linear(del, width, max_change);
+                       int total = add + del;
+
+                       total = scale_linear(add + del, width, max_change);
+                       if (total < 2 && add && del)
+                               /* width >= 2 due to the sanity check */
+                               total = 2;
+                       if (add < del) {
+                               add = scale_linear(add, width, max_change);
+                               del = total - add;
+                       } else {
+                               del = scale_linear(del, width, max_change);
+                               add = total - del;
+                       }
                }
                fprintf(options->file, "%s", line_prefix);
                show_name(options->file, prefix, name, len);
@@ -2169,6 +2182,8 @@ static void builtin_diff(const char *name_a,
                xecfg.ctxlen = o->context;
                xecfg.interhunkctxlen = o->interhunkcontext;
                xecfg.flags = XDL_EMIT_FUNCNAMES;
+               if (DIFF_OPT_TST(o, FUNCCONTEXT))
+                       xecfg.flags |= XDL_EMIT_FUNCCONTEXT;
                if (pe)
                        xdiff_set_find_func(&xecfg, pe->pattern, pe->cflags);
                if (!diffopts)
@@ -3536,6 +3551,12 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
        else if (opt_arg(arg, '\0', "inter-hunk-context",
                         &options->interhunkcontext))
                ;
+       else if (!strcmp(arg, "-W"))
+               DIFF_OPT_SET(options, FUNCCONTEXT);
+       else if (!strcmp(arg, "--function-context"))
+               DIFF_OPT_SET(options, FUNCCONTEXT);
+       else if (!strcmp(arg, "--no-function-context"))
+               DIFF_OPT_CLR(options, FUNCCONTEXT);
        else if ((argcount = parse_long_opt("output", av, &optarg))) {
                options->file = fopen(optarg, "w");
                if (!options->file)