Merge branch 'sg/overlong-progress-fix'
authorJunio C Hamano <gitster@pobox.com>
Thu, 25 Apr 2019 07:41:19 +0000 (16:41 +0900)
committerJunio C Hamano <gitster@pobox.com>
Thu, 25 Apr 2019 07:41:19 +0000 (16:41 +0900)
Updating the display with progress message has been cleaned up to
deal better with overlong messages.

* sg/overlong-progress-fix:
progress: break too long progress bar lines
progress: clear previous progress update dynamically
progress: assemble percentage and counters in a strbuf before printing
progress: make display_progress() return void

1  2 
progress.c
progress.h
diff --combined progress.c
index 212d00e524819aafe17b55f1b2f54a5bcf40dd7e,2d8022a6223e2e79ba087efaf0354fd16bdccd63..6cde5959fac75ab2640f11346dd124c962d98067
@@@ -8,11 -8,12 +8,12 @@@
   * published by the Free Software Foundation.
   */
  
- #include "git-compat-util.h"
+ #include "cache.h"
  #include "gettext.h"
  #include "progress.h"
  #include "strbuf.h"
  #include "trace.h"
+ #include "utf8.h"
  
  #define TP_IDX_MAX      8
  
@@@ -34,9 -35,11 +35,12 @@@ struct progress 
        uint64_t total;
        unsigned last_percent;
        unsigned delay;
 +      unsigned sparse;
        struct throughput *throughput;
        uint64_t start_ns;
+       struct strbuf counters_sb;
+       int title_len;
+       int split;
  };
  
  static volatile sig_atomic_t progress_update;
@@@ -79,41 -82,64 +83,64 @@@ static int is_foreground_fd(int fd
        return tpgrp < 0 || tpgrp == getpgid(0);
  }
  
- static int display(struct progress *progress, uint64_t n, const char *done)
+ static void display(struct progress *progress, uint64_t n, const char *done)
  {
-       const char *eol, *tp;
+       const char *tp;
+       struct strbuf *counters_sb = &progress->counters_sb;
+       int show_update = 0;
+       int last_count_len = counters_sb->len;
  
        if (progress->delay && (!progress_update || --progress->delay))
-               return 0;
+               return;
  
        progress->last_value = n;
        tp = (progress->throughput) ? progress->throughput->display.buf : "";
-       eol = done ? done : "   \r";
        if (progress->total) {
                unsigned percent = n * 100 / progress->total;
                if (percent != progress->last_percent || progress_update) {
                        progress->last_percent = percent;
-                       if (is_foreground_fd(fileno(stderr)) || done) {
-                               fprintf(stderr, "%s: %3u%% (%"PRIuMAX"/%"PRIuMAX")%s%s",
-                                       progress->title, percent,
-                                       (uintmax_t)n, (uintmax_t)progress->total,
-                                       tp, eol);
-                               fflush(stderr);
-                       }
-                       progress_update = 0;
-                       return 1;
+                       strbuf_reset(counters_sb);
+                       strbuf_addf(counters_sb,
+                                   "%3u%% (%"PRIuMAX"/%"PRIuMAX")%s", percent,
+                                   (uintmax_t)n, (uintmax_t)progress->total,
+                                   tp);
+                       show_update = 1;
                }
        } else if (progress_update) {
+               strbuf_reset(counters_sb);
+               strbuf_addf(counters_sb, "%"PRIuMAX"%s", (uintmax_t)n, tp);
+               show_update = 1;
+       }
+       if (show_update) {
                if (is_foreground_fd(fileno(stderr)) || done) {
-                       fprintf(stderr, "%s: %"PRIuMAX"%s%s",
-                               progress->title, (uintmax_t)n, tp, eol);
+                       const char *eol = done ? done : "\r";
+                       size_t clear_len = counters_sb->len < last_count_len ?
+                                       last_count_len - counters_sb->len + 1 :
+                                       0;
+                       size_t progress_line_len = progress->title_len +
+                                               counters_sb->len + 2;
+                       int cols = term_columns();
+                       if (progress->split) {
+                               fprintf(stderr, "  %s%*s", counters_sb->buf,
+                                       (int) clear_len, eol);
+                       } else if (!done && cols < progress_line_len) {
+                               clear_len = progress->title_len + 1 < cols ?
+                                           cols - progress->title_len : 0;
+                               fprintf(stderr, "%s:%*s\n  %s%s",
+                                       progress->title, (int) clear_len, "",
+                                       counters_sb->buf, eol);
+                               progress->split = 1;
+                       } else {
+                               fprintf(stderr, "%s: %s%*s", progress->title,
+                                       counters_sb->buf, (int) clear_len, eol);
+                       }
                        fflush(stderr);
                }
                progress_update = 0;
-               return 1;
        }
-       return 0;
  }
  
  static void throughput_string(struct strbuf *buf, uint64_t total,
@@@ -189,13 -215,14 +216,14 @@@ void display_throughput(struct progres
                display(progress, progress->last_value, NULL);
  }
  
int display_progress(struct progress *progress, uint64_t n)
void display_progress(struct progress *progress, uint64_t n)
  {
-       return progress ? display(progress, n, NULL) : 0;
+       if (progress)
+               display(progress, n, NULL);
  }
  
  static struct progress *start_progress_delay(const char *title, uint64_t total,
 -                                           unsigned delay)
 +                                           unsigned delay, unsigned sparse)
  {
        struct progress *progress = malloc(sizeof(*progress));
        if (!progress) {
        progress->last_value = -1;
        progress->last_percent = -1;
        progress->delay = delay;
 +      progress->sparse = sparse;
        progress->throughput = NULL;
        progress->start_ns = getnanotime();
+       strbuf_init(&progress->counters_sb, 0);
+       progress->title_len = utf8_strwidth(title);
+       progress->split = 0;
        set_progress_signal();
        return progress;
  }
  
  struct progress *start_delayed_progress(const char *title, uint64_t total)
  {
 -      return start_progress_delay(title, total, 2);
 +      return start_progress_delay(title, total, 2, 0);
  }
  
  struct progress *start_progress(const char *title, uint64_t total)
  {
 -      return start_progress_delay(title, total, 0);
 +      return start_progress_delay(title, total, 0, 0);
 +}
 +
 +/*
 + * Here "sparse" means that the caller might use some sampling criteria to
 + * decide when to call display_progress() rather than calling it for every
 + * integer value in[0 .. total).  In particular, the caller might not call
 + * display_progress() for the last value in the range.
 + *
 + * When "sparse" is set, stop_progress() will automatically force the done
 + * message to show 100%.
 + */
 +struct progress *start_sparse_progress(const char *title, uint64_t total)
 +{
 +      return start_progress_delay(title, total, 0, 1);
 +}
 +
 +struct progress *start_delayed_sparse_progress(const char *title,
 +                                             uint64_t total)
 +{
 +      return start_progress_delay(title, total, 2, 1);
 +}
 +
 +static void finish_if_sparse(struct progress *progress)
 +{
 +      if (progress &&
 +          progress->sparse &&
 +          progress->last_value != progress->total)
 +              display_progress(progress, progress->total);
  }
  
  void stop_progress(struct progress **p_progress)
  {
 +      finish_if_sparse(*p_progress);
 +
        stop_progress_msg(p_progress, _("done"));
  }
  
@@@ -285,6 -284,7 +316,7 @@@ void stop_progress_msg(struct progress 
                free(buf);
        }
        clear_progress_signal();
+       strbuf_release(&progress->counters_sb);
        if (progress->throughput)
                strbuf_release(&progress->throughput->display);
        free(progress->throughput);
diff --combined progress.h
index 7b725acc8d7b6cbaa5e36743b42b29d8c22d868d,59e40cc4fd003ec6037ef11e5f2270bfd28054f0..847338911fbb6cf359f39ea0cb7a406297b61812
@@@ -4,12 -4,9 +4,12 @@@
  struct progress;
  
  void display_throughput(struct progress *progress, uint64_t total);
int display_progress(struct progress *progress, uint64_t n);
void display_progress(struct progress *progress, uint64_t n);
  struct progress *start_progress(const char *title, uint64_t total);
 +struct progress *start_sparse_progress(const char *title, uint64_t total);
  struct progress *start_delayed_progress(const char *title, uint64_t total);
 +struct progress *start_delayed_sparse_progress(const char *title,
 +                                             uint64_t total);
  void stop_progress(struct progress **progress);
  void stop_progress_msg(struct progress **progress, const char *msg);