{"thread":{"id":"31874","subject":"[PATCH] New \"git status\" format with --alternate","startedAt":"2012-10-20T09:36:31Z","lastAt":"2012-10-20T09:36:31Z","messageCount":1,"participants":["Nguyễn Thái Ngọc Duy"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"201590","messageId":"1350725791-10396-1-git-send-email-pclouds@gmail.com","threadId":"31874","inReplyTo":null,"subject":"[PATCH] New \"git status\" format with --alternate","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2012-10-20T09:36:31Z","receivedAt":"2012-10-20T09:36:31Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Another UI experiment, thrown at git@vger to see if it sticks. I've\nbeen using this for a week and it feels good in general. But it may be\ntoo specific to my taste to be useful for more people.\n\nThis format utilizes the screen estate as much as possible. It relies\non colors, so monochrome users are stuck with default format. In\nshort, it's a \"GNU ls\"-like output with footnotes:\n\n - entries of all kinds (untracked, modified, cached...) are sorted in\n   a single list, laid out in columns\n - different kinds of files have different colors, more on this later\n - square brackets around a tracked file means differences between\n   index and HEAD (aka \"git diff --cached\").\n - square brackets on untracked file means ignored file\n - more information such as renames, unmerged tyes... is added in form\n   of footnotes\n\nOn a clean repository, \"git status\" prints nothing. Branch state\n(rebasing/am-ing/....) is also printed.\n\nThis format is denser than the default format and easier to read (to\nme) as there is only one table. Colors and brackets are the visual\nclues. All the use of colors and brackets are explained in footnotes,\nso new users should have no problems with it (provided that they know\nbasic concepts).\n\nAbout colors, untracked files have no colors. Tracked files always do\n(to catch your eyes). Added/Removed/Modified/Unmerged have different\ncolors. Text color reflects the changes between worktree and index\n(aka \"git diff\"). Bracket color reflects changes between index and\nHEAD (aka \"git diff --cached\").\n\nIf you see all magenta (modified) text without brackets, \"git commit -a\"\nis your friend. If you see all yellow text (unmodified worktree)\nand magenta brackets, \"git commit\" to go. A mix of magenta text and\nbrackets mean you need to do \"git diff --cached\" and \"git diff\" to\nknow what changes you are going to commit.\n\nThe merge of untracked/tracked files could be annoying if you don't\nkeep your repository clean, though. Not sure if mering is a good idea,\nor just split them into two tables.\n\nFinal note: messy and incomplete implementation.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/commit.c |  11 ++\n wt-status.c      | 339 ++++++++++++++++++++++++++++++++++++++++++++++++++++---\n wt-status.h      |   1 +\n 3 files changed, 338 insertions(+), 13 deletions(-)\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex a17a5df..758cf11 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -114,6 +114,7 @@ static struct strbuf message = STRBUF_INIT;\n static enum {\n \tSTATUS_FORMAT_LONG,\n \tSTATUS_FORMAT_SHORT,\n+\tSTATUS_FORMAT_ALTERNATE,\n \tSTATUS_FORMAT_PORCELAIN\n } status_format = STATUS_FORMAT_LONG;\n \n@@ -451,6 +452,9 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int\n \tcase STATUS_FORMAT_SHORT:\n \t\twt_shortstatus_print(s);\n \t\tbreak;\n+\tcase STATUS_FORMAT_ALTERNATE:\n+\t\twt_altstatus_print(s);\n+\t\tbreak;\n \tcase STATUS_FORMAT_PORCELAIN:\n \t\twt_porcelain_print(s);\n \t\tbreak;\n@@ -1154,6 +1158,8 @@ int cmd_status(int argc, const char **argv, const char *prefix)\n \t\tOPT__VERBOSE(&verbose, N_(\"be verbose\")),\n \t\tOPT_SET_INT('s', \"short\", &status_format,\n \t\t\t    N_(\"show status concisely\"), STATUS_FORMAT_SHORT),\n+\t\tOPT_SET_INT(0, \"alternate\", &status_format,\n+\t\t\t    N_(\"show status concisely\"), STATUS_FORMAT_ALTERNATE),\n \t\tOPT_BOOLEAN('b', \"branch\", &s.show_branch,\n \t\t\t    N_(\"show branch information\")),\n \t\tOPT_SET_INT(0, \"porcelain\", &status_format,\n@@ -1188,6 +1194,8 @@ int cmd_status(int argc, const char **argv, const char *prefix)\n \n \tif (s.null_termination && status_format == STATUS_FORMAT_LONG)\n \t\tstatus_format = STATUS_FORMAT_PORCELAIN;\n+\tif (s.null_termination && status_format == STATUS_FORMAT_ALTERNATE)\n+\t\tdie(_(\"--alternate does not work with -z\"));\n \n \thandle_untracked_files_arg(&s);\n \tif (show_ignored_in_status)\n@@ -1213,6 +1221,9 @@ int cmd_status(int argc, const char **argv, const char *prefix)\n \tcase STATUS_FORMAT_SHORT:\n \t\twt_shortstatus_print(&s);\n \t\tbreak;\n+\tcase STATUS_FORMAT_ALTERNATE:\n+\t\twt_altstatus_print(&s);\n+\t\tbreak;\n \tcase STATUS_FORMAT_PORCELAIN:\n \t\twt_porcelain_print(&s);\n \t\tbreak;\ndiff --git a/wt-status.c b/wt-status.c\nindex 2a9658b..7502591 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -928,34 +928,40 @@ static void show_bisect_in_progress(struct wt_status *s,\n \twt_status_print_trailer(s);\n }\n \n-static void wt_status_print_state(struct wt_status *s)\n+static void wt_status_get_state(struct wt_status *s,\n+\t\t\t\tstruct wt_status_state *state)\n {\n-\tconst char *state_color = color(WT_STATUS_HEADER, s);\n-\tstruct wt_status_state state;\n \tstruct stat st;\n-\n-\tmemset(&state, 0, sizeof(state));\n+\tmemset(state, 0, sizeof(*state));\n \n \tif (!stat(git_path(\"MERGE_HEAD\"), &st)) {\n-\t\tstate.merge_in_progress = 1;\n+\t\tstate->merge_in_progress = 1;\n \t} else if (!stat(git_path(\"rebase-apply\"), &st)) {\n \t\tif (!stat(git_path(\"rebase-apply/applying\"), &st)) {\n-\t\t\tstate.am_in_progress = 1;\n+\t\t\tstate->am_in_progress = 1;\n \t\t\tif (!stat(git_path(\"rebase-apply/patch\"), &st) && !st.st_size)\n-\t\t\t\tstate.am_empty_patch = 1;\n+\t\t\t\tstate->am_empty_patch = 1;\n \t\t} else {\n-\t\t\tstate.rebase_in_progress = 1;\n+\t\t\tstate->rebase_in_progress = 1;\n \t\t}\n \t} else if (!stat(git_path(\"rebase-merge\"), &st)) {\n \t\tif (!stat(git_path(\"rebase-merge/interactive\"), &st))\n-\t\t\tstate.rebase_interactive_in_progress = 1;\n+\t\t\tstate->rebase_interactive_in_progress = 1;\n \t\telse\n-\t\t\tstate.rebase_in_progress = 1;\n+\t\t\tstate->rebase_in_progress = 1;\n \t} else if (!stat(git_path(\"CHERRY_PICK_HEAD\"), &st)) {\n-\t\tstate.cherry_pick_in_progress = 1;\n+\t\tstate->cherry_pick_in_progress = 1;\n \t}\n \tif (!stat(git_path(\"BISECT_LOG\"), &st))\n-\t\tstate.bisect_in_progress = 1;\n+\t\tstate->bisect_in_progress = 1;\n+}\n+\n+static void wt_status_print_state(struct wt_status *s)\n+{\n+\tconst char *state_color = color(WT_STATUS_HEADER, s);\n+\tstruct wt_status_state state;\n+\n+\twt_status_get_state(s, &state);\n \n \tif (state.merge_in_progress)\n \t\tshow_merge_in_progress(s, &state, state_color);\n@@ -1224,6 +1230,313 @@ void wt_shortstatus_print(struct wt_status *s)\n \t}\n }\n \n+static int cmp_items(const void *a, const void *b)\n+{\n+\tconst struct string_list_item *const *one = a;\n+\tconst struct string_list_item *const *two = b;\n+\treturn strcmp((*one)->string, (*two)->string);\n+}\n+\n+static const char *col_unmerged = GIT_COLOR_CYAN;\n+static const char *col_added = GIT_COLOR_GREEN;\n+static const char *col_deleted = GIT_COLOR_RED;\n+static const char *col_updated = GIT_COLOR_MAGENTA;\n+static const char *col_tracked = GIT_COLOR_YELLOW;\n+static const char *col_reset = GIT_COLOR_RESET;\n+\n+#define SHOW_TRACKED\t\t8\n+#define SHOW_UNMERGED\t\t9\n+#define SHOW_ADDED\t\t10\n+#define SHOW_DELETED\t\t11\n+#define SHOW_UPDATED\t\t12\n+#define SHOW_WORKTREE_DELETED\t13\n+#define SHOW_WORKTREE_UPDATED\t14\n+#define SHOW_UNTRACKED\t\t15\n+#define SHOW_IGNORED\t\t16\n+\n+static void wt_altstatus_unmerged(struct wt_status *s,\n+\t\t\t\t  const char *name,\n+\t\t\t\t  struct wt_status_change_data *d,\n+\t\t\t\t  struct strbuf *out,\n+\t\t\t\t  struct string_list *footnotes,\n+\t\t\t\t  int *shown_how)\n+{\n+\tstruct strbuf onebuf = STRBUF_INIT;\n+\tconst char *one;\n+\tconst char *how = \"\";\n+\n+\tswitch (d->stagemask) {\n+\tcase 1: how = \"DD\"; break; /* both deleted */\n+\tcase 2: how = \"AU\"; break; /* added by us */\n+\tcase 3: how = \"UD\"; break; /* deleted by them */\n+\tcase 4: how = \"UA\"; break; /* added by them */\n+\tcase 5: how = \"DU\"; break; /* deleted by us */\n+\tcase 6: how = \"AA\"; break; /* both added */\n+\tcase 7: how = \"UU\"; break; /* both modified */\n+\t}\n+\n+\tif (!shown_how[d->stagemask]) {\n+\t\tconst char *legend = NULL;\n+\t\tshown_how[d->stagemask] = 1;\n+\t\tswitch (d->stagemask) {\n+\t\tcase 1: legend = \"[DD] deleted by both\"; break;\n+\t\tcase 2: legend = \"[AU] added by us\"; break;\n+\t\tcase 3: legend = \"[UD] deleted by them\"; break;\n+\t\tcase 4: legend = \"[UA] added by them\"; break;\n+\t\tcase 5: legend = \"[DU] deleted by us\"; break;\n+\t\tcase 6: legend = \"[AA] added by both\"; break;\n+\t\tcase 7: legend = \"[UU] modified by both\"; break;\n+\t\t}\n+\t\tif (legend)\n+\t\t\tstring_list_append(footnotes, xstrdup(legend));\n+\t}\n+\n+\tif (!shown_how[SHOW_UNMERGED]) {\n+\t\tstruct strbuf legend = STRBUF_INIT;\n+\t\tstrbuf_addf(&legend, \"%sfile%s -> unmerged entry\",\n+\t\t\t    col_unmerged, col_reset);\n+\t\tstring_list_append(footnotes, strbuf_detach(&legend, NULL));\n+\t\tshown_how[SHOW_UNMERGED] = 1;\n+\t}\n+\n+\tone = quote_path(name, -1, &onebuf, s->prefix);\n+\tif (*one != '\"' && strchr(one, ' ') != NULL) {\n+\t\tputchar('\"');\n+\t\tstrbuf_addch(&onebuf, '\"');\n+\t\tone = onebuf.buf;\n+\t}\n+\tstrbuf_addf(out,\" %s%s%s [%s]\", col_unmerged, one, col_reset, how);\n+\tstrbuf_release(&onebuf);\n+}\n+\n+static void wt_altstatus_tracked(struct wt_status *s,\n+\t\t\t\t const char *name,\n+\t\t\t\t struct wt_status_change_data *d,\n+\t\t\t\t struct strbuf *out,\n+\t\t\t\t struct string_list *footnotes,\n+\t\t\t\t int *shown_how)\n+{\n+\tstruct strbuf onebuf = STRBUF_INIT;\n+\tconst char *one;\n+\tconst char *color;\n+\n+\tone = quote_path(name, -1, &onebuf, s->prefix);\n+\tif (*one != '\"' && strchr(one, ' ') != NULL) {\n+\t\tputchar('\"');\n+\t\tstrbuf_addch(&onebuf, '\"');\n+\t\tone = onebuf.buf;\n+\t}\n+\n+\tswitch (d->worktree_status) {\n+\tcase DIFF_STATUS_DELETED:\n+\t\tcolor = col_deleted;\n+\t\tif (!shown_how[SHOW_WORKTREE_DELETED]) {\n+\t\t\tstruct strbuf legend = STRBUF_INIT;\n+\t\t\tstrbuf_addf(&legend, \"%s[  ]%s -> removed from worktree\",\n+\t\t\t\t    col_deleted, col_reset);\n+\t\t\tstring_list_append(footnotes, strbuf_detach(&legend, NULL));\n+\t\t\tshown_how[SHOW_WORKTREE_DELETED] = 1;\n+\t\t}\n+\t\tbreak;\n+\tcase 0:\n+\t\tcolor = col_tracked;\n+\t\tif (!shown_how[SHOW_TRACKED]) {\n+\t\t\tstruct strbuf legend = STRBUF_INIT;\n+\t\t\tstrbuf_addf(&legend, \"%sfile%s -> worktree same as in index\",\n+\t\t\t\t    col_tracked, col_reset);\n+\t\t\tstring_list_append(footnotes, strbuf_detach(&legend, NULL));\n+\t\t\tshown_how[SHOW_TRACKED] = 1;\n+\t\t}\n+\t\tbreak;\n+\tdefault:\n+\t\tcolor = col_updated;\n+\t\tif (!shown_how[SHOW_WORKTREE_UPDATED]) {\n+\t\t\tstruct strbuf legend = STRBUF_INIT;\n+\t\t\tstrbuf_addf(&legend, \"%sfile%s -> modified in worktree\",\n+\t\t\t\t    col_updated, col_reset);\n+\t\t\tstring_list_append(footnotes, strbuf_detach(&legend, NULL));\n+\t\t\tshown_how[SHOW_WORKTREE_UPDATED] = 1;\n+\t\t}\n+\t}\n+\n+\tswitch (d->index_status) {\n+\tcase DIFF_STATUS_ADDED:\n+\t\tstrbuf_addf(out, \"%s[ %s%s%s ]%s\",\n+\t\t\t    col_added, color, one,\n+\t\t\t    col_added, col_reset);\n+\t\tif (!shown_how[SHOW_ADDED]) {\n+\t\t\tstruct strbuf legend = STRBUF_INIT;\n+\t\t\tstrbuf_addf(&legend, \"%sfile%s -> added to index\",\n+\t\t\t\t    col_added, col_reset);\n+\t\t\tstring_list_append(footnotes, strbuf_detach(&legend, NULL));\n+\t\t\tshown_how[SHOW_ADDED] = 1;\n+\t\t}\n+\t\tbreak;\n+\tcase DIFF_STATUS_DELETED:\n+\t\tstrbuf_addf(out, \"%s[ %s%s%s ]%s\",\n+\t\t\t    col_deleted, color, one,\n+\t\t\t    col_deleted, col_reset);\n+\t\tif (!shown_how[SHOW_DELETED]) {\n+\t\t\tstruct strbuf legend = STRBUF_INIT;\n+\t\t\tstrbuf_addf(&legend, \"%sfile%s -> removed from index\",\n+\t\t\t\t    col_deleted, col_reset);\n+\t\t\tstring_list_append(footnotes, strbuf_detach(&legend, NULL));\n+\t\t\tshown_how[SHOW_DELETED] = 1;\n+\t\t}\n+\t\tbreak;\n+\tcase 0:\n+\t\tstrbuf_addf(out, \"  %s%s%s\", color, one, col_reset);\n+\t\tbreak;\n+\tdefault:\n+\t\tstrbuf_addf(out, \"%s[ %s%s%s ]%s\",\n+\t\t\t    col_updated, color, one,\n+\t\t\t    col_updated, col_reset);\n+\t\tif (!shown_how[SHOW_UPDATED]) {\n+\t\t\tstruct strbuf legend = STRBUF_INIT;\n+\t\t\tstrbuf_addf(&legend, \"%s[  ]%s -> changes in index\",\n+\t\t\t\t    col_updated, col_reset);\n+\t\t\tstring_list_append(footnotes, strbuf_detach(&legend, NULL));\n+\t\t\tshown_how[SHOW_UPDATED] = 1;\n+\t\t}\n+\t}\n+\n+\tstrbuf_release(&onebuf);\n+\n+\t/* extra things at the end */\n+\tswitch (d->worktree_status) {\n+\tcase DIFF_STATUS_ADDED:\n+\tcase DIFF_STATUS_DELETED:\n+\t\tbreak;\n+\tcase DIFF_STATUS_TYPE_CHANGED:\n+\t\t/* FIXME */\n+\t\tstrbuf_addf(out, \"%s+x%s\", GIT_COLOR_YELLOW,\n+\t\t\t    GIT_COLOR_RESET);\n+\t\tbreak;\n+\tcase 0:\n+\t\tbreak;\n+\t}\n+\n+\tif (d->head_path) {\n+\t\tstruct strbuf tmp = STRBUF_INIT;\n+\t\tint id = footnotes->nr + 1;\n+\t\tstrbuf_addf(out, \" [%d]\", id);\n+\t\tone = quote_path(d->head_path, -1, &onebuf, s->prefix);\n+\t\tif (*one != '\"' && strchr(one, ' ') != NULL) {\n+\t\t\tputchar('\"');\n+\t\t\tstrbuf_addch(&onebuf, '\"');\n+\t\t\tone = onebuf.buf;\n+\t\t}\n+\t\tstrbuf_addf(&tmp, \"[%d] renamed from %s\", id, onebuf.buf);\n+\t\tstrbuf_release(&onebuf);\n+\t\tstring_list_append(footnotes, strbuf_detach(&tmp, NULL));\n+\t}\n+}\n+\n+void wt_altstatus_print(struct wt_status *s)\n+{\n+\tint i, n;\n+\tstruct string_list_item **all, **p;\n+\tstruct string_list footnotes = STRING_LIST_INIT_NODUP;\n+\tstruct string_list output = STRING_LIST_INIT_NODUP;\n+\tstruct column_options copts;\n+\tstruct wt_status_state state;\n+\tint shown_how[17];\n+\n+\tn = s->untracked.nr + s->ignored.nr + s->change.nr;\n+\tp = all = xmalloc(sizeof(*all) * n);\n+\n+\tfor (i = 0; i < s->change.nr; i++)\n+\t\t*p++ = s->change.items + i;\n+\tfor (i = 0; i < s->untracked.nr; i++)\n+\t\t*p++ = s->untracked.items + i;\n+\tfor (i = 0; i < s->ignored.nr; i++)\n+\t\t*p++ = s->ignored.items + i;\n+\tqsort(all, n, sizeof(*all), cmp_items);\n+\n+\twt_status_get_state(s, &state);\n+\tif (state.merge_in_progress)\n+\t\tprintf(\"%s(Merge in progress)%s\\n\",\n+\t\t       GIT_COLOR_YELLOW,\n+\t\t       GIT_COLOR_RESET);\n+\telse if (state.am_in_progress)\n+\t\tprintf(\"%s(git-am in progress)%s\\n\",\n+\t\t       GIT_COLOR_YELLOW,\n+\t\t       GIT_COLOR_RESET);\n+\telse if (state.rebase_in_progress || state.rebase_interactive_in_progress)\n+\t\tprintf(\"%s(Rebase in progress)%s\\n\",\n+\t\t       GIT_COLOR_YELLOW,\n+\t\t       GIT_COLOR_RESET);\n+\telse if (state.cherry_pick_in_progress)\n+\t\tprintf(\"%s(Cherry-pick in progress)%s\\n\",\n+\t\t       GIT_COLOR_YELLOW,\n+\t\t       GIT_COLOR_RESET);\n+\tif (state.bisect_in_progress)\n+\t\tprintf(\"%s(Bisect in progress)%s\\n\",\n+\t\t       GIT_COLOR_YELLOW,\n+\t\t       GIT_COLOR_RESET);\n+\n+\tmemset(shown_how, 0, sizeof(shown_how));\n+\n+\tmemset(&copts, 0, sizeof(copts));\n+\tcopts.padding = 1;\n+\n+\tfor (i = 0; i < n; i++) {\n+\t\tstruct string_list_item *it = all[i];\n+\t\tstruct strbuf out = STRBUF_INIT;\n+\n+\t\tif (it >= s->change.items &&\n+\t\t    it < s->change.items + s->change.nr) {\n+\t\t\tstruct wt_status_change_data *d;\n+\n+\t\t\td = it->util;\n+\t\t\tif (d->stagemask)\n+\t\t\t\twt_altstatus_unmerged(s, it->string, d, &out, &footnotes, shown_how);\n+\t\t\telse\n+\t\t\t\twt_altstatus_tracked(s, it->string, d, &out, &footnotes, shown_how);\n+\t\t} else {\n+\t\t\tstruct strbuf onebuf = STRBUF_INIT;\n+\t\t\tconst char *one;\n+\n+\t\t\tone = quote_path(it->string, -1, &onebuf, s->prefix);\n+\t\t\tif (*one != '\"' && strchr(one, ' ') != NULL) {\n+\t\t\t\tputchar('\"');\n+\t\t\t\tstrbuf_addch(&onebuf, '\"');\n+\t\t\t\tone = onebuf.buf;\n+\t\t\t}\n+\n+\t\t\tif (it >= s->untracked.items &&\n+\t\t\t\t it < s->untracked.items + s->untracked.nr) {\n+\t\t\t\tstrbuf_addf(&out, \"  %s\", one);\n+\t\t\t\tif (!shown_how[SHOW_UNTRACKED]) {\n+\t\t\t\t\tstring_list_append(&footnotes, xstrdup(\"file -> untracked file\"));\n+\t\t\t\t\tshown_how[SHOW_UNTRACKED] = 1;\n+\t\t\t\t}\n+\t\t\t} else if (it >= s->ignored.items &&\n+\t\t\t\t it < s->ignored.items + s->ignored.nr) {\n+\t\t\t\tstrbuf_addf(&out, \"[ %s ]\", one);\n+\t\t\t\tif (!shown_how[SHOW_IGNORED]) {\n+\t\t\t\t\tstring_list_append(&footnotes, xstrdup(\"[file] -> ignored file\"));\n+\t\t\t\t\tshown_how[SHOW_IGNORED] = 1;\n+\t\t\t\t}\n+\t\t\t} else\n+\t\t\t\tdie(\"Where does this item come from?\");\n+\n+\t\t\tstrbuf_release(&onebuf);\n+\t\t}\n+\t\tstring_list_append(&output, strbuf_detach(&out, NULL));\n+\t}\n+\tprint_columns(&output, s->colopts, &copts);\n+\tstring_list_clear(&output, 0);\n+\n+\tif (footnotes.nr) {\n+\t\tprintf(\"\\n\");\n+\t\tmemset(&copts, 0, sizeof(copts));\n+\t\tcopts.padding = 3;\n+\t\tprint_columns(&footnotes, s->colopts, &copts);\n+\t}\n+\tstring_list_clear(&footnotes, 0);\n+}\n+\n void wt_porcelain_print(struct wt_status *s)\n {\n \ts->use_color = 0;\ndiff --git a/wt-status.h b/wt-status.h\nindex 236b41f..8804400 100644\n--- a/wt-status.h\n+++ b/wt-status.h\n@@ -86,6 +86,7 @@ void wt_status_print(struct wt_status *s);\n void wt_status_collect(struct wt_status *s);\n \n void wt_shortstatus_print(struct wt_status *s);\n+void wt_altstatus_print(struct wt_status *s);\n void wt_porcelain_print(struct wt_status *s);\n \n void status_printf_ln(struct wt_status *s, const char *color, const char *fmt, ...)\n-- \n1.8.0.rc2.25.gf0e8e5d\n"}]}