fetch: align all "remote -> local" output
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>
Fri, 1 Jul 2016 16:03:30 +0000 (18:03 +0200)
committerJunio C Hamano <gitster@pobox.com>
Wed, 6 Jul 2016 18:48:25 +0000 (11:48 -0700)
We do align "remote -> local" output by allocating 10 columns to
"remote". That produces aligned output only for short refs. An extra
pass is performed to find the longest remote ref name (that does not
produce a line longer than terminal width) to produce better aligned
output.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/fetch.c
t/t5510-fetch.sh
index 8177f90d418f5b3d27ececad4e74fb529faff1de..2bc609b7f7152af97c5adea0172ba90f807ac7b0 100644 (file)
@@ -15,6 +15,7 @@
 #include "submodule.h"
 #include "connected.h"
 #include "argv-array.h"
+#include "utf8.h"
 
 static const char * const builtin_fetch_usage[] = {
        N_("git fetch [<options>] [<repository> [<refspec>...]]"),
@@ -449,14 +450,54 @@ static int s_update_ref(const char *action,
                           : STORE_REF_ERROR_OTHER;
 }
 
-#define REFCOL_WIDTH  10
+static int refcol_width = 10;
+
+static void adjust_refcol_width(const struct ref *ref)
+{
+       int max, rlen, llen, len;
+
+       /* uptodate lines are only shown on high verbosity level */
+       if (!verbosity && !oidcmp(&ref->peer_ref->old_oid, &ref->old_oid))
+               return;
+
+       max    = term_columns();
+       rlen   = utf8_strwidth(prettify_refname(ref->name));
+       llen   = utf8_strwidth(prettify_refname(ref->peer_ref->name));
+
+       /*
+        * rough estimation to see if the output line is too long and
+        * should not be counted (we can't do precise calculation
+        * anyway because we don't know if the error explanation part
+        * will be printed in update_local_ref)
+        */
+       len = 21 /* flag and summary */ + rlen + 4 /* -> */ + llen;
+       if (len >= max)
+               return;
+
+       if (refcol_width < rlen)
+               refcol_width = rlen;
+}
+
+static void prepare_format_display(struct ref *ref_map)
+{
+       struct ref *rm;
+
+       for (rm = ref_map; rm; rm = rm->next) {
+               if (rm->status == REF_STATUS_REJECT_SHALLOW ||
+                   !rm->peer_ref ||
+                   !strcmp(rm->name, "HEAD"))
+                       continue;
+
+               adjust_refcol_width(rm);
+       }
+}
 
 static void format_display(struct strbuf *display, char code,
                           const char *summary, const char *error,
                           const char *remote, const char *local)
 {
        strbuf_addf(display, "%c %-*s ", code, TRANSPORT_SUMMARY(summary));
-       strbuf_addf(display, "%-*s -> %s", REFCOL_WIDTH, remote, local);
+       strbuf_addf(display, "%-*s -> %s", refcol_width, remote, local);
        if (error)
                strbuf_addf(display, "  (%s)", error);
 }
@@ -618,6 +659,8 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
                goto abort;
        }
 
+       prepare_format_display(ref_map);
+
        /*
         * We do a pass for each fetch_head_status type in their enum order, so
         * merged entries are written before not-for-merge. That lets readers
index 454d896390c03667442ce12925066b14593b3cd1..f50497eaa14c799680821eff4de61f47a63ab48b 100755 (executable)
@@ -688,4 +688,19 @@ test_expect_success 'fetching with auto-gc does not lock up' '
        )
 '
 
+test_expect_success 'fetch aligned output' '
+       git clone . full-output &&
+       test_commit looooooooooooong-tag &&
+       (
+               cd full-output &&
+               git fetch origin 2>&1 | \
+                       grep -e "->" | cut -c 22- >../actual
+       ) &&
+       cat >expect <<-\EOF &&
+       master               -> origin/master
+       looooooooooooong-tag -> looooooooooooong-tag
+       EOF
+       test_cmp expect actual
+'
+
 test_done