{"thread":{"id":"48456","subject":"[PATCH 0/9] completion: avoid hard coding config var list","startedAt":"2018-05-10T14:19:36Z","lastAt":"2018-05-29T17:41:34Z","messageCount":36,"participants":["Nguyễn Thái Ngọc Duy","Duy Nguyen","Stefan Beller","Junio C Hamano","Eric Sunshine","SZEDER Gábor"],"isPatch":true,"patchVersion":1,"patchTotal":9},"messages":[{"id":"347231","messageId":"20180510141927.23590-1-pclouds@gmail.com","threadId":"48456","inReplyTo":null,"subject":"[PATCH 0/9] completion: avoid hard coding config var list","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-10T14:19:18Z","receivedAt":"2018-05-10T14:19:36Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This is part of the attempt to automate more in git-completion.bash.\nThis series is about making 'git' binary provide the list of\nrecognized configuration variables and feeding it to git-completion.bash.\n\nThe approach is less than ideal. Unlike parse-options, we don't have a\nreliable source for configuration variables. Instead, we go grep\nconfig.txt for variable names.\n\nThis should work most of the time even if it might miss some variables\nif we start to write funny things in config.txt. But compared to the\ncurrent approach \"every now and then, manually go through config.txt\n(or something) and update _git_config() function\", this is still\ndefinitely better.\n\nThe result is about 200 more completable options (from current 324).\nGranted most of this is fsck message ids, but I'm sure it has picked\nup a few good config variables and will continue so in the future.\n\nWhile at there, this config list is also available to the user via\n`git help --config` if you can't remember the exact config name you\nwant and don't want to go through that big git-config man page.\n\nPS. Yes too many complete options (524 now) is not that helpful. I\nhave a plan to deal with this but probably after I'm done with the\n--no-xxx completion topic. Stay tuned.\n\n(on top of nd/command-list)\n\nNguyễn Thái Ngọc Duy (9):\n  Add and use generic name->id mapping code for color slot parsing\n  grep: keep all colors in an array\n  fsck: factor out msg_id_info[] lazy initialization code\n  help: add --config to list all available config\n  advice: keep config name in camelCase in advice_config[]\n  am: move advice.amWorkDir parsing back to advice.c\n  completion: drop the hard coded list of config vars\n  completion: support case-insensitive config vars just a bit\n  log-tree: allow to customize 'grafted' color\n\n Documentation/config.txt               |   3 +-\n Documentation/git-help.txt             |   5 +\n advice.c                               |  51 ++--\n advice.h                               |   1 +\n builtin/am.c                           |   5 +-\n builtin/branch.c                       |  28 +-\n builtin/clean.c                        |  28 +-\n builtin/commit.c                       |  40 +--\n builtin/help.c                         |  14 +\n config.c                               |  13 +\n config.h                               |   4 +\n contrib/completion/git-completion.bash | 340 +------------------------\n diff.c                                 |  60 ++---\n fsck.c                                 |  49 ++--\n generate-cmdlist.sh                    |  20 ++\n grep.c                                 | 113 ++++----\n grep.h                                 |  21 +-\n help.c                                 |  74 ++++++\n help.h                                 |  18 ++\n log-tree.c                             |  36 +--\n t/t4254-am-corrupt.sh                  |   2 +-\n 21 files changed, 387 insertions(+), 538 deletions(-)\n\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"347232","messageId":"20180510141927.23590-2-pclouds@gmail.com","threadId":"48456","inReplyTo":"20180510141927.23590-1-pclouds@gmail.com","subject":"[PATCH 1/9] Add and use generic name->id mapping code for color slot parsing","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-10T14:19:19Z","receivedAt":"2018-05-10T14:19:40Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Instead of hard coding the name-to-id mapping in C code, keep it in an\narray and use a common function to do the parsing. This reduces code\nand also allows us to list all possible color slots later.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/branch.c | 28 +++++++++----------------\n builtin/clean.c  | 28 +++++++++----------------\n builtin/commit.c | 33 ++++++++++++++----------------\n config.c         | 13 ++++++++++++\n config.h         |  4 ++++\n diff.c           | 53 +++++++++++++++++++-----------------------------\n log-tree.c       | 35 ++++++++------------------------\n 7 files changed, 82 insertions(+), 112 deletions(-)\n\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 5bd2a0dd48..b41f332589 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -55,26 +55,18 @@ enum color_branch {\n \tBRANCH_COLOR_UPSTREAM = 5\n };\n \n+static const char *color_branch_slots[] = {\n+\t[BRANCH_COLOR_RESET]\t= \"reset\",\n+\t[BRANCH_COLOR_PLAIN]\t= \"plain\",\n+\t[BRANCH_COLOR_REMOTE]\t= \"remote\",\n+\t[BRANCH_COLOR_LOCAL]\t= \"local\",\n+\t[BRANCH_COLOR_CURRENT]\t= \"current\",\n+\t[BRANCH_COLOR_UPSTREAM] = \"upstream\",\n+};\n+\n static struct string_list output = STRING_LIST_INIT_DUP;\n static unsigned int colopts;\n \n-static int parse_branch_color_slot(const char *slot)\n-{\n-\tif (!strcasecmp(slot, \"plain\"))\n-\t\treturn BRANCH_COLOR_PLAIN;\n-\tif (!strcasecmp(slot, \"reset\"))\n-\t\treturn BRANCH_COLOR_RESET;\n-\tif (!strcasecmp(slot, \"remote\"))\n-\t\treturn BRANCH_COLOR_REMOTE;\n-\tif (!strcasecmp(slot, \"local\"))\n-\t\treturn BRANCH_COLOR_LOCAL;\n-\tif (!strcasecmp(slot, \"current\"))\n-\t\treturn BRANCH_COLOR_CURRENT;\n-\tif (!strcasecmp(slot, \"upstream\"))\n-\t\treturn BRANCH_COLOR_UPSTREAM;\n-\treturn -1;\n-}\n-\n static int git_branch_config(const char *var, const char *value, void *cb)\n {\n \tconst char *slot_name;\n@@ -86,7 +78,7 @@ static int git_branch_config(const char *var, const char *value, void *cb)\n \t\treturn 0;\n \t}\n \tif (skip_prefix(var, \"color.branch.\", &slot_name)) {\n-\t\tint slot = parse_branch_color_slot(slot_name);\n+\t\tint slot = LOOKUP_CONFIG(color_branch_slots, slot_name);\n \t\tif (slot < 0)\n \t\t\treturn 0;\n \t\tif (!value)\ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex fad533a0a7..0ccd95e693 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -42,6 +42,15 @@ enum color_clean {\n \tCLEAN_COLOR_ERROR = 5\n };\n \n+static const char *color_interactive_slots[] = {\n+\t[CLEAN_COLOR_ERROR]  = \"error\",\n+\t[CLEAN_COLOR_HEADER] = \"header\",\n+\t[CLEAN_COLOR_HELP]   = \"help\",\n+\t[CLEAN_COLOR_PLAIN]  = \"plain\",\n+\t[CLEAN_COLOR_PROMPT] = \"prompt\",\n+\t[CLEAN_COLOR_RESET]  = \"reset\",\n+};\n+\n static int clean_use_color = -1;\n static char clean_colors[][COLOR_MAXLEN] = {\n \t[CLEAN_COLOR_ERROR] = GIT_COLOR_BOLD_RED,\n@@ -82,23 +91,6 @@ struct menu_stuff {\n \tvoid *stuff;\n };\n \n-static int parse_clean_color_slot(const char *var)\n-{\n-\tif (!strcasecmp(var, \"reset\"))\n-\t\treturn CLEAN_COLOR_RESET;\n-\tif (!strcasecmp(var, \"plain\"))\n-\t\treturn CLEAN_COLOR_PLAIN;\n-\tif (!strcasecmp(var, \"prompt\"))\n-\t\treturn CLEAN_COLOR_PROMPT;\n-\tif (!strcasecmp(var, \"header\"))\n-\t\treturn CLEAN_COLOR_HEADER;\n-\tif (!strcasecmp(var, \"help\"))\n-\t\treturn CLEAN_COLOR_HELP;\n-\tif (!strcasecmp(var, \"error\"))\n-\t\treturn CLEAN_COLOR_ERROR;\n-\treturn -1;\n-}\n-\n static int git_clean_config(const char *var, const char *value, void *cb)\n {\n \tconst char *slot_name;\n@@ -113,7 +105,7 @@ static int git_clean_config(const char *var, const char *value, void *cb)\n \t\treturn 0;\n \t}\n \tif (skip_prefix(var, \"color.interactive.\", &slot_name)) {\n-\t\tint slot = parse_clean_color_slot(slot_name);\n+\t\tint slot = LOOKUP_CONFIG(color_interactive_slots, slot_name);\n \t\tif (slot < 0)\n \t\t\treturn 0;\n \t\tif (!value)\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 37fcb55ab0..bee5825bd2 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -66,6 +66,18 @@ N_(\"If you wish to skip this commit, use:\\n\"\n \"Then \\\"git cherry-pick --continue\\\" will resume cherry-picking\\n\"\n \"the remaining commits.\\n\");\n \n+static const char *color_status_slots[] = {\n+\t[WT_STATUS_HEADER]\t  = \"header\",\n+\t[WT_STATUS_UPDATED]\t  = \"updated\",\n+\t[WT_STATUS_CHANGED]\t  = \"changed\",\n+\t[WT_STATUS_UNTRACKED]\t  = \"untracked\",\n+\t[WT_STATUS_NOBRANCH]\t  = \"noBranch\",\n+\t[WT_STATUS_UNMERGED]\t  = \"unmerged\",\n+\t[WT_STATUS_LOCAL_BRANCH]  = \"localBranch\",\n+\t[WT_STATUS_REMOTE_BRANCH] = \"remoteBranch\",\n+\t[WT_STATUS_ONBRANCH]\t  = \"branch\",\n+};\n+\n static const char *use_message_buffer;\n static struct lock_file index_lock; /* real index */\n static struct lock_file false_lock; /* used only for partial commits */\n@@ -1176,25 +1188,10 @@ static int dry_run_commit(int argc, const char **argv, const char *prefix,\n \n static int parse_status_slot(const char *slot)\n {\n-\tif (!strcasecmp(slot, \"header\"))\n-\t\treturn WT_STATUS_HEADER;\n-\tif (!strcasecmp(slot, \"branch\"))\n-\t\treturn WT_STATUS_ONBRANCH;\n-\tif (!strcasecmp(slot, \"updated\") || !strcasecmp(slot, \"added\"))\n+\tif (!strcasecmp(slot, \"added\"))\n \t\treturn WT_STATUS_UPDATED;\n-\tif (!strcasecmp(slot, \"changed\"))\n-\t\treturn WT_STATUS_CHANGED;\n-\tif (!strcasecmp(slot, \"untracked\"))\n-\t\treturn WT_STATUS_UNTRACKED;\n-\tif (!strcasecmp(slot, \"nobranch\"))\n-\t\treturn WT_STATUS_NOBRANCH;\n-\tif (!strcasecmp(slot, \"unmerged\"))\n-\t\treturn WT_STATUS_UNMERGED;\n-\tif (!strcasecmp(slot, \"localBranch\"))\n-\t\treturn WT_STATUS_LOCAL_BRANCH;\n-\tif (!strcasecmp(slot, \"remoteBranch\"))\n-\t\treturn WT_STATUS_REMOTE_BRANCH;\n-\treturn -1;\n+\n+\treturn LOOKUP_CONFIG(color_status_slots, slot);\n }\n \n static int git_status_config(const char *k, const char *v, void *cb)\ndiff --git a/config.c b/config.c\nindex c698988f5e..69ea707f36 100644\n--- a/config.c\n+++ b/config.c\n@@ -3041,3 +3041,16 @@ enum config_scope current_config_scope(void)\n \telse\n \t\treturn current_parsing_scope;\n }\n+\n+int lookup_config(const char **mapping, int nr_mapping, const char *var)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < nr_mapping; i++) {\n+\t\tconst char *name = mapping[i];\n+\n+\t\tif (name && !strcasecmp(var, name))\n+\t\t\treturn i;\n+\t}\n+\treturn -1;\n+}\ndiff --git a/config.h b/config.h\nindex ef70a9cac1..cf35ab74db 100644\n--- a/config.h\n+++ b/config.h\n@@ -231,4 +231,8 @@ struct key_value_info {\n extern NORETURN void git_die_config(const char *key, const char *err, ...) __attribute__((format(printf, 2, 3)));\n extern NORETURN void git_die_config_linenr(const char *key, const char *filename, int linenr);\n \n+#define LOOKUP_CONFIG(mapping, var) \\\n+\tlookup_config(mapping, ARRAY_SIZE(mapping), var)\n+int lookup_config(const char **mapping, int nr_mapping, const char *var);\n+\n #endif /* CONFIG_H */\ndiff --git a/diff.c b/diff.c\nindex 1289df4b1f..6f781a2c57 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -69,6 +69,25 @@ static char diff_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_FAINT_ITALIC,\t/* NEW_MOVED_ALTERNATIVE_DIM */\n };\n \n+static const char *color_diff_slots[] = {\n+\t[DIFF_CONTEXT]\t\t      = \"context\",\n+\t[DIFF_METAINFO]\t\t      = \"meta\",\n+\t[DIFF_FRAGINFO]\t\t      = \"frag\",\n+\t[DIFF_FILE_OLD]\t\t      = \"old\",\n+\t[DIFF_FILE_NEW]\t\t      = \"new\",\n+\t[DIFF_COMMIT]\t\t      = \"commit\",\n+\t[DIFF_WHITESPACE]\t      = \"whitespace\",\n+\t[DIFF_FUNCINFO]\t\t      = \"func\",\n+\t[DIFF_FILE_OLD_MOVED]\t      = \"oldMoved\",\n+\t[DIFF_FILE_OLD_MOVED_ALT]     = \"oldMovedAlternative\",\n+\t[DIFF_FILE_OLD_MOVED_DIM]     = \"oldMovedDimmed\",\n+\t[DIFF_FILE_OLD_MOVED_ALT_DIM] = \"oldMovedAlternativeDimmed\",\n+\t[DIFF_FILE_NEW_MOVED]\t      = \"newMoved\",\n+\t[DIFF_FILE_NEW_MOVED_ALT]     = \"newMovedAlternative\",\n+\t[DIFF_FILE_NEW_MOVED_DIM]     = \"newMovedDimmed\",\n+\t[DIFF_FILE_NEW_MOVED_ALT_DIM] = \"newMovedAlternativeDimmed\",\n+};\n+\n static NORETURN void die_want_option(const char *option_name)\n {\n \tdie(_(\"option '%s' requires a value\"), option_name);\n@@ -76,39 +95,9 @@ static NORETURN void die_want_option(const char *option_name)\n \n static int parse_diff_color_slot(const char *var)\n {\n-\tif (!strcasecmp(var, \"context\") || !strcasecmp(var, \"plain\"))\n+\tif (!strcasecmp(var, \"plain\"))\n \t\treturn DIFF_CONTEXT;\n-\tif (!strcasecmp(var, \"meta\"))\n-\t\treturn DIFF_METAINFO;\n-\tif (!strcasecmp(var, \"frag\"))\n-\t\treturn DIFF_FRAGINFO;\n-\tif (!strcasecmp(var, \"old\"))\n-\t\treturn DIFF_FILE_OLD;\n-\tif (!strcasecmp(var, \"new\"))\n-\t\treturn DIFF_FILE_NEW;\n-\tif (!strcasecmp(var, \"commit\"))\n-\t\treturn DIFF_COMMIT;\n-\tif (!strcasecmp(var, \"whitespace\"))\n-\t\treturn DIFF_WHITESPACE;\n-\tif (!strcasecmp(var, \"func\"))\n-\t\treturn DIFF_FUNCINFO;\n-\tif (!strcasecmp(var, \"oldmoved\"))\n-\t\treturn DIFF_FILE_OLD_MOVED;\n-\tif (!strcasecmp(var, \"oldmovedalternative\"))\n-\t\treturn DIFF_FILE_OLD_MOVED_ALT;\n-\tif (!strcasecmp(var, \"oldmoveddimmed\"))\n-\t\treturn DIFF_FILE_OLD_MOVED_DIM;\n-\tif (!strcasecmp(var, \"oldmovedalternativedimmed\"))\n-\t\treturn DIFF_FILE_OLD_MOVED_ALT_DIM;\n-\tif (!strcasecmp(var, \"newmoved\"))\n-\t\treturn DIFF_FILE_NEW_MOVED;\n-\tif (!strcasecmp(var, \"newmovedalternative\"))\n-\t\treturn DIFF_FILE_NEW_MOVED_ALT;\n-\tif (!strcasecmp(var, \"newmoveddimmed\"))\n-\t\treturn DIFF_FILE_NEW_MOVED_DIM;\n-\tif (!strcasecmp(var, \"newmovedalternativedimmed\"))\n-\t\treturn DIFF_FILE_NEW_MOVED_ALT_DIM;\n-\treturn -1;\n+\treturn LOOKUP_CONFIG(color_diff_slots, var);\n }\n \n static int parse_dirstat_params(struct diff_options *options, const char *params_string,\ndiff --git a/log-tree.c b/log-tree.c\nindex d1c0bedf24..093efb477e 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -27,6 +27,14 @@ static char decoration_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_BOLD_BLUE,\t/* GRAFTED */\n };\n \n+static const char *color_decorate_slots[] = {\n+\t[DECORATION_REF_LOCAL]\t= \"branch\",\n+\t[DECORATION_REF_REMOTE] = \"remoteBranch\",\n+\t[DECORATION_REF_TAG]\t= \"tag\",\n+\t[DECORATION_REF_STASH]\t= \"stash\",\n+\t[DECORATION_REF_HEAD]\t= \"HEAD\",\n+};\n+\n static const char *decorate_get_color(int decorate_use_color, enum decoration_type ix)\n {\n \tif (want_color(decorate_use_color))\n@@ -34,34 +42,9 @@ static const char *decorate_get_color(int decorate_use_color, enum decoration_ty\n \treturn \"\";\n }\n \n-static int parse_decorate_color_slot(const char *slot)\n-{\n-\t/*\n-\t * We're comparing with 'ignore-case' on\n-\t * (because config.c sets them all tolower),\n-\t * but let's match the letters in the literal\n-\t * string values here with how they are\n-\t * documented in Documentation/config.txt, for\n-\t * consistency.\n-\t *\n-\t * We love being consistent, don't we?\n-\t */\n-\tif (!strcasecmp(slot, \"branch\"))\n-\t\treturn DECORATION_REF_LOCAL;\n-\tif (!strcasecmp(slot, \"remoteBranch\"))\n-\t\treturn DECORATION_REF_REMOTE;\n-\tif (!strcasecmp(slot, \"tag\"))\n-\t\treturn DECORATION_REF_TAG;\n-\tif (!strcasecmp(slot, \"stash\"))\n-\t\treturn DECORATION_REF_STASH;\n-\tif (!strcasecmp(slot, \"HEAD\"))\n-\t\treturn DECORATION_REF_HEAD;\n-\treturn -1;\n-}\n-\n int parse_decorate_color_config(const char *var, const char *slot_name, const char *value)\n {\n-\tint slot = parse_decorate_color_slot(slot_name);\n+\tint slot = LOOKUP_CONFIG(color_decorate_slots, slot_name);\n \tif (slot < 0)\n \t\treturn 0;\n \tif (!value)\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"347233","messageId":"20180510141927.23590-4-pclouds@gmail.com","threadId":"48456","inReplyTo":"20180510141927.23590-1-pclouds@gmail.com","subject":"[PATCH 3/9] fsck: factor out msg_id_info[] lazy initialization code","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-10T14:19:21Z","receivedAt":"2018-05-10T14:19:41Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This array will be used by some other function than parse_msg_id() in\nthe following commit. Factor out this prep code so it could be called\nfrom that one.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n fsck.c | 38 ++++++++++++++++++++++----------------\n 1 file changed, 22 insertions(+), 16 deletions(-)\n\ndiff --git a/fsck.c b/fsck.c\nindex 9218c2a643..f2534abd44 100644\n--- a/fsck.c\n+++ b/fsck.c\n@@ -84,26 +84,32 @@ static struct {\n };\n #undef MSG_ID\n \n-static int parse_msg_id(const char *text)\n+static void prepare_msg_ids(void)\n {\n \tint i;\n \n-\tif (!msg_id_info[0].downcased) {\n-\t\t/* convert id_string to lower case, without underscores. */\n-\t\tfor (i = 0; i < FSCK_MSG_MAX; i++) {\n-\t\t\tconst char *p = msg_id_info[i].id_string;\n-\t\t\tint len = strlen(p);\n-\t\t\tchar *q = xmalloc(len);\n-\n-\t\t\tmsg_id_info[i].downcased = q;\n-\t\t\twhile (*p)\n-\t\t\t\tif (*p == '_')\n-\t\t\t\t\tp++;\n-\t\t\t\telse\n-\t\t\t\t\t*(q)++ = tolower(*(p)++);\n-\t\t\t*q = '\\0';\n-\t\t}\n+\t/* convert id_string to lower case, without underscores. */\n+\tfor (i = 0; i < FSCK_MSG_MAX; i++) {\n+\t\tconst char *p = msg_id_info[i].id_string;\n+\t\tint len = strlen(p);\n+\t\tchar *q = xmalloc(len);\n+\n+\t\tmsg_id_info[i].downcased = q;\n+\t\twhile (*p)\n+\t\t\tif (*p == '_')\n+\t\t\t\tp++;\n+\t\t\telse\n+\t\t\t\t*(q)++ = tolower(*(p)++);\n+\t\t*q = '\\0';\n \t}\n+}\n+\n+static int parse_msg_id(const char *text)\n+{\n+\tint i;\n+\n+\tif (!msg_id_info[0].downcased)\n+\t\tprepare_msg_ids();\n \n \tfor (i = 0; i < FSCK_MSG_MAX; i++)\n \t\tif (!strcmp(text, msg_id_info[i].downcased))\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"347234","messageId":"20180510141927.23590-3-pclouds@gmail.com","threadId":"48456","inReplyTo":"20180510141927.23590-1-pclouds@gmail.com","subject":"[PATCH 2/9] grep: keep all colors in an array","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-10T14:19:20Z","receivedAt":"2018-05-10T14:19:43Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This is more inline with how we handle color slots in other code. It\nalso allows us to get the list of configurable color slots later.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n grep.c | 106 ++++++++++++++++++++++++++-------------------------------\n grep.h |  21 +++++++-----\n 2 files changed, 62 insertions(+), 65 deletions(-)\n\ndiff --git a/grep.c b/grep.c\nindex 65b90c10a3..2f7ebe60f6 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -13,6 +13,17 @@ static int grep_source_is_binary(struct grep_source *gs);\n \n static struct grep_opt grep_defaults;\n \n+static const char *color_grep_slots[] = {\n+\t[GREP_COLOR_CONTEXT] = \"context\",\n+\t[GREP_COLOR_FILENAME] = \"filename\",\n+\t[GREP_COLOR_FUNCTION] = \"function\",\n+\t[GREP_COLOR_LINENO] = \"lineNumber\",\n+\t[GREP_COLOR_MATCH_CONTEXT] = \"matchContext\",\n+\t[GREP_COLOR_MATCH_SELECTED] = \"matchSelected\",\n+\t[GREP_COLOR_SELECTED] = \"selected\",\n+\t[GREP_COLOR_SEP] = \"separator\",\n+};\n+\n static void std_output(struct grep_opt *opt, const void *buf, size_t size)\n {\n \tfwrite(buf, size, 1, stdout);\n@@ -42,14 +53,14 @@ void init_grep_defaults(void)\n \topt->pathname = 1;\n \topt->max_depth = -1;\n \topt->pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED;\n-\tcolor_set(opt->color_context, \"\");\n-\tcolor_set(opt->color_filename, \"\");\n-\tcolor_set(opt->color_function, \"\");\n-\tcolor_set(opt->color_lineno, \"\");\n-\tcolor_set(opt->color_match_context, GIT_COLOR_BOLD_RED);\n-\tcolor_set(opt->color_match_selected, GIT_COLOR_BOLD_RED);\n-\tcolor_set(opt->color_selected, \"\");\n-\tcolor_set(opt->color_sep, GIT_COLOR_CYAN);\n+\tcolor_set(opt->colors[GREP_COLOR_CONTEXT], \"\");\n+\tcolor_set(opt->colors[GREP_COLOR_FILENAME], \"\");\n+\tcolor_set(opt->colors[GREP_COLOR_FUNCTION], \"\");\n+\tcolor_set(opt->colors[GREP_COLOR_LINENO], \"\");\n+\tcolor_set(opt->colors[GREP_COLOR_MATCH_CONTEXT], GIT_COLOR_BOLD_RED);\n+\tcolor_set(opt->colors[GREP_COLOR_MATCH_SELECTED], GIT_COLOR_BOLD_RED);\n+\tcolor_set(opt->colors[GREP_COLOR_SELECTED], \"\");\n+\tcolor_set(opt->colors[GREP_COLOR_SEP], GIT_COLOR_CYAN);\n \topt->color = -1;\n \topt->output = std_output;\n }\n@@ -76,7 +87,7 @@ static int parse_pattern_type_arg(const char *opt, const char *arg)\n int grep_config(const char *var, const char *value, void *cb)\n {\n \tstruct grep_opt *opt = &grep_defaults;\n-\tchar *color = NULL;\n+\tconst char *slot;\n \n \tif (userdiff_config(var, value) < 0)\n \t\treturn -1;\n@@ -103,32 +114,18 @@ int grep_config(const char *var, const char *value, void *cb)\n \n \tif (!strcmp(var, \"color.grep\"))\n \t\topt->color = git_config_colorbool(var, value);\n-\telse if (!strcmp(var, \"color.grep.context\"))\n-\t\tcolor = opt->color_context;\n-\telse if (!strcmp(var, \"color.grep.filename\"))\n-\t\tcolor = opt->color_filename;\n-\telse if (!strcmp(var, \"color.grep.function\"))\n-\t\tcolor = opt->color_function;\n-\telse if (!strcmp(var, \"color.grep.linenumber\"))\n-\t\tcolor = opt->color_lineno;\n-\telse if (!strcmp(var, \"color.grep.matchcontext\"))\n-\t\tcolor = opt->color_match_context;\n-\telse if (!strcmp(var, \"color.grep.matchselected\"))\n-\t\tcolor = opt->color_match_selected;\n-\telse if (!strcmp(var, \"color.grep.selected\"))\n-\t\tcolor = opt->color_selected;\n-\telse if (!strcmp(var, \"color.grep.separator\"))\n-\t\tcolor = opt->color_sep;\n-\telse if (!strcmp(var, \"color.grep.match\")) {\n-\t\tint rc = 0;\n-\t\tif (!value)\n-\t\t\treturn config_error_nonbool(var);\n-\t\trc |= color_parse(value, opt->color_match_context);\n-\t\trc |= color_parse(value, opt->color_match_selected);\n-\t\treturn rc;\n-\t}\n-\n-\tif (color) {\n+\tif (!strcmp(var, \"color.grep.match\")) {\n+\t\tif (grep_config(\"color.grep.matchcontext\", value, cb) < 0)\n+\t\t\treturn -1;\n+\t\tif (grep_config(\"color.grep.matchselected\", value, cb) < 0)\n+\t\t\treturn -1;\n+\t} else if (skip_prefix(var, \"color.grep.\", &slot)) {\n+\t\tint i = LOOKUP_CONFIG(color_grep_slots, slot);\n+\t\tchar *color;\n+\n+\t\tif (i < 0)\n+\t\t\treturn -1;\n+\t\tcolor = opt->colors[i];\n \t\tif (!value)\n \t\t\treturn config_error_nonbool(var);\n \t\treturn color_parse(value, color);\n@@ -144,6 +141,7 @@ int grep_config(const char *var, const char *value, void *cb)\n void grep_init(struct grep_opt *opt, const char *prefix)\n {\n \tstruct grep_opt *def = &grep_defaults;\n+\tint i;\n \n \tmemset(opt, 0, sizeof(*opt));\n \topt->prefix = prefix;\n@@ -160,14 +158,8 @@ void grep_init(struct grep_opt *opt, const char *prefix)\n \topt->relative = def->relative;\n \topt->output = def->output;\n \n-\tcolor_set(opt->color_context, def->color_context);\n-\tcolor_set(opt->color_filename, def->color_filename);\n-\tcolor_set(opt->color_function, def->color_function);\n-\tcolor_set(opt->color_lineno, def->color_lineno);\n-\tcolor_set(opt->color_match_context, def->color_match_context);\n-\tcolor_set(opt->color_match_selected, def->color_match_selected);\n-\tcolor_set(opt->color_selected, def->color_selected);\n-\tcolor_set(opt->color_sep, def->color_sep);\n+\tfor (i = 0; i < NR_GREP_COLORS; i++)\n+\t\tcolor_set(opt->colors[i], def->colors[i]);\n }\n \n static void grep_set_pattern_type_option(enum grep_pattern_type pattern_type, struct grep_opt *opt)\n@@ -1100,12 +1092,12 @@ static void output_sep(struct grep_opt *opt, char sign)\n \tif (opt->null_following_name)\n \t\topt->output(opt, \"\\0\", 1);\n \telse\n-\t\toutput_color(opt, &sign, 1, opt->color_sep);\n+\t\toutput_color(opt, &sign, 1, opt->colors[GREP_COLOR_SEP]);\n }\n \n static void show_name(struct grep_opt *opt, const char *name)\n {\n-\toutput_color(opt, name, strlen(name), opt->color_filename);\n+\toutput_color(opt, name, strlen(name), opt->colors[GREP_COLOR_FILENAME]);\n \topt->output(opt, opt->null_following_name ? \"\\0\" : \"\\n\", 1);\n }\n \n@@ -1372,28 +1364,28 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,\n \t} else if (opt->pre_context || opt->post_context || opt->funcbody) {\n \t\tif (opt->last_shown == 0) {\n \t\t\tif (opt->show_hunk_mark) {\n-\t\t\t\toutput_color(opt, \"--\", 2, opt->color_sep);\n+\t\t\t\toutput_color(opt, \"--\", 2, opt->colors[GREP_COLOR_SEP]);\n \t\t\t\topt->output(opt, \"\\n\", 1);\n \t\t\t}\n \t\t} else if (lno > opt->last_shown + 1) {\n-\t\t\toutput_color(opt, \"--\", 2, opt->color_sep);\n+\t\t\toutput_color(opt, \"--\", 2, opt->colors[GREP_COLOR_SEP]);\n \t\t\topt->output(opt, \"\\n\", 1);\n \t\t}\n \t}\n \tif (opt->heading && opt->last_shown == 0) {\n-\t\toutput_color(opt, name, strlen(name), opt->color_filename);\n+\t\toutput_color(opt, name, strlen(name), opt->colors[GREP_COLOR_FILENAME]);\n \t\topt->output(opt, \"\\n\", 1);\n \t}\n \topt->last_shown = lno;\n \n \tif (!opt->heading && opt->pathname) {\n-\t\toutput_color(opt, name, strlen(name), opt->color_filename);\n+\t\toutput_color(opt, name, strlen(name), opt->colors[GREP_COLOR_FILENAME]);\n \t\toutput_sep(opt, sign);\n \t}\n \tif (opt->linenum) {\n \t\tchar buf[32];\n \t\txsnprintf(buf, sizeof(buf), \"%d\", lno);\n-\t\toutput_color(opt, buf, strlen(buf), opt->color_lineno);\n+\t\toutput_color(opt, buf, strlen(buf), opt->colors[GREP_COLOR_LINENO]);\n \t\toutput_sep(opt, sign);\n \t}\n \tif (opt->color) {\n@@ -1403,15 +1395,15 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,\n \t\tint eflags = 0;\n \n \t\tif (sign == ':')\n-\t\t\tmatch_color = opt->color_match_selected;\n+\t\t\tmatch_color = opt->colors[GREP_COLOR_MATCH_SELECTED];\n \t\telse\n-\t\t\tmatch_color = opt->color_match_context;\n+\t\t\tmatch_color = opt->colors[GREP_COLOR_MATCH_CONTEXT];\n \t\tif (sign == ':')\n-\t\t\tline_color = opt->color_selected;\n+\t\t\tline_color = opt->colors[GREP_COLOR_SELECTED];\n \t\telse if (sign == '-')\n-\t\t\tline_color = opt->color_context;\n+\t\t\tline_color = opt->colors[GREP_COLOR_CONTEXT];\n \t\telse if (sign == '=')\n-\t\t\tline_color = opt->color_function;\n+\t\t\tline_color = opt->colors[GREP_COLOR_FUNCTION];\n \t\t*eol = '\\0';\n \t\twhile (next_match(opt, bol, eol, ctx, &match, eflags)) {\n \t\t\tif (match.rm_so == match.rm_eo)\n@@ -1818,7 +1810,7 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle\n \t\t\tif (binary_match_only) {\n \t\t\t\topt->output(opt, \"Binary file \", 12);\n \t\t\t\toutput_color(opt, gs->name, strlen(gs->name),\n-\t\t\t\t\t     opt->color_filename);\n+\t\t\t\t\t     opt->colors[GREP_COLOR_FILENAME]);\n \t\t\t\topt->output(opt, \" matches\\n\", 9);\n \t\t\t\treturn 1;\n \t\t\t}\n@@ -1892,7 +1884,7 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle\n \t\tchar buf[32];\n \t\tif (opt->pathname) {\n \t\t\toutput_color(opt, gs->name, strlen(gs->name),\n-\t\t\t\t     opt->color_filename);\n+\t\t\t\t     opt->colors[GREP_COLOR_FILENAME]);\n \t\t\toutput_sep(opt, ':');\n \t\t}\n \t\txsnprintf(buf, sizeof(buf), \"%u\\n\", count);\ndiff --git a/grep.h b/grep.h\nindex 399381c908..ed25be271b 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -62,6 +62,18 @@ enum grep_header_field {\n \tGREP_HEADER_FIELD_MAX\n };\n \n+enum grep_color {\n+\tGREP_COLOR_CONTEXT,\n+\tGREP_COLOR_FILENAME,\n+\tGREP_COLOR_FUNCTION,\n+\tGREP_COLOR_LINENO,\n+\tGREP_COLOR_MATCH_CONTEXT,\n+\tGREP_COLOR_MATCH_SELECTED,\n+\tGREP_COLOR_SELECTED,\n+\tGREP_COLOR_SEP,\n+\tNR_GREP_COLORS\n+};\n+\n struct grep_pat {\n \tstruct grep_pat *next;\n \tconst char *origin;\n@@ -155,14 +167,7 @@ struct grep_opt {\n \tint funcbody;\n \tint extended_regexp_option;\n \tint pattern_type_option;\n-\tchar color_context[COLOR_MAXLEN];\n-\tchar color_filename[COLOR_MAXLEN];\n-\tchar color_function[COLOR_MAXLEN];\n-\tchar color_lineno[COLOR_MAXLEN];\n-\tchar color_match_context[COLOR_MAXLEN];\n-\tchar color_match_selected[COLOR_MAXLEN];\n-\tchar color_selected[COLOR_MAXLEN];\n-\tchar color_sep[COLOR_MAXLEN];\n+\tchar colors[NR_GREP_COLORS][COLOR_MAXLEN];\n \tunsigned pre_context;\n \tunsigned post_context;\n \tunsigned last_shown;\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"347235","messageId":"20180510141927.23590-9-pclouds@gmail.com","threadId":"48456","inReplyTo":"20180510141927.23590-1-pclouds@gmail.com","subject":"[PATCH 8/9] completion: support case-insensitive config vars just a bit","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-10T14:19:26Z","receivedAt":"2018-05-10T14:19:48Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"config variable names are technically case-insensitive while this case\nconstruct is by default case-sensitive. Moving it to case-insensitive\ncould be a lot more work. Instead let's just accept the form that is\nmore likely to show up in practice.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n contrib/completion/git-completion.bash | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 8d3257c4de..e7829b5b24 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -2084,7 +2084,7 @@ __git_compute_config_vars ()\n _git_config ()\n {\n \tcase \"$prev\" in\n-\tbranch.*.remote|branch.*.pushremote)\n+\tbranch.*.remote|branch.*.push[Rr]emote)\n \t\t__gitcomp_nl \"$(__git_remotes)\"\n \t\treturn\n \t\t;;\n@@ -2096,7 +2096,7 @@ _git_config ()\n \t\t__gitcomp \"false true preserve interactive\"\n \t\treturn\n \t\t;;\n-\tremote.pushdefault)\n+\tremote.push[Dd]efault)\n \t\t__gitcomp_nl \"$(__git_remotes)\"\n \t\treturn\n \t\t;;\n@@ -2162,7 +2162,7 @@ _git_config ()\n \t\t__gitcomp \"$__git_send_email_suppresscc_options\"\n \t\treturn\n \t\t;;\n-\tsendemail.transferencoding)\n+\tsendemail.transfer[Ee]ncoding)\n \t\t__gitcomp \"7bit 8bit quoted-printable base64\"\n \t\treturn\n \t\t;;\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"347236","messageId":"20180510141927.23590-8-pclouds@gmail.com","threadId":"48456","inReplyTo":"20180510141927.23590-1-pclouds@gmail.com","subject":"[PATCH 7/9] completion: drop the hard coded list of config vars","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-10T14:19:25Z","receivedAt":"2018-05-10T14:19:49Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The new help option --config-for-completion is a machine friendlier\nversion of --config where all the placeholders and wildcards are\ndropped, leaving only the good, completable prefixes for\ngit-completion.bash to consume.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/help.c                         |  13 +-\n contrib/completion/git-completion.bash | 334 +------------------------\n help.c                                 |  30 ++-\n help.h                                 |   2 +-\n 4 files changed, 47 insertions(+), 332 deletions(-)\n\ndiff --git a/builtin/help.c b/builtin/help.c\nindex a1153cf473..fbd2b0238a 100644\n--- a/builtin/help.c\n+++ b/builtin/help.c\n@@ -45,7 +45,8 @@ static struct option builtin_help_options[] = {\n \tOPT_BOOL('a', \"all\", &show_all, N_(\"print all available commands\")),\n \tOPT_HIDDEN_BOOL(0, \"exclude-guides\", &exclude_guides, N_(\"exclude guides\")),\n \tOPT_BOOL('g', \"guides\", &show_guides, N_(\"print list of useful guides\")),\n-\tOPT_BOOL('c', \"config\", &show_config, N_(\"print list recognized config variables\")),\n+\tOPT_SET_INT('c', \"config\", &show_config, N_(\"print list recognized config variables\"), 1),\n+\tOPT_SET_INT_F(0, \"config-for-completion\", &show_config, \"\", 2, PARSE_OPT_HIDDEN),\n \tOPT_SET_INT('m', \"man\", &help_format, N_(\"show man page\"), HELP_FORMAT_MAN),\n \tOPT_SET_INT('w', \"web\", &help_format, N_(\"show manual in web browser\"),\n \t\t\tHELP_FORMAT_WEB),\n@@ -446,9 +447,13 @@ int cmd_help(int argc, const char **argv, const char *prefix)\n \t}\n \n \tif (show_config) {\n-\t\tsetup_pager();\n-\t\tlist_config_help();\n-\t\tprintf(\"\\n%s\\n\", _(\"'git help config' for more information\"));\n+\t\tint for_human = show_config == 1;\n+\n+\t\tif (for_human)\n+\t\t\tsetup_pager();\n+\t\tlist_config_help(for_human);\n+\t\tif (for_human)\n+\t\t\tprintf(\"\\n%s\\n\", _(\"'git help config' for more information\"));\n \t\treturn 0;\n \t}\n \ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex f7ca9a4d4f..8d3257c4de 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -2074,6 +2074,13 @@ __git_config_get_set_variables ()\n \t__git config $config_file --name-only --list\n }\n \n+__git_config_vars=\n+__git_compute_config_vars ()\n+{\n+\ttest -n \"$__git_config_vars\" ||\n+\t__git_config_vars=\"$(git help --config-for-completion | sort | uniq)\"\n+}\n+\n _git_config ()\n {\n \tcase \"$prev\" in\n@@ -2232,331 +2239,8 @@ _git_config ()\n \t\treturn\n \t\t;;\n \tesac\n-\t__gitcomp \"\n-\t\tadd.ignoreErrors\n-\t\tadvice.amWorkDir\n-\t\tadvice.commitBeforeMerge\n-\t\tadvice.detachedHead\n-\t\tadvice.implicitIdentity\n-\t\tadvice.pushAlreadyExists\n-\t\tadvice.pushFetchFirst\n-\t\tadvice.pushNeedsForce\n-\t\tadvice.pushNonFFCurrent\n-\t\tadvice.pushNonFFMatching\n-\t\tadvice.pushUpdateRejected\n-\t\tadvice.resolveConflict\n-\t\tadvice.rmHints\n-\t\tadvice.statusHints\n-\t\tadvice.statusUoption\n-\t\tadvice.ignoredHook\n-\t\talias.\n-\t\tam.keepcr\n-\t\tam.threeWay\n-\t\tapply.ignorewhitespace\n-\t\tapply.whitespace\n-\t\tbranch.autosetupmerge\n-\t\tbranch.autosetuprebase\n-\t\tbrowser.\n-\t\tclean.requireForce\n-\t\tcolor.branch\n-\t\tcolor.branch.current\n-\t\tcolor.branch.local\n-\t\tcolor.branch.plain\n-\t\tcolor.branch.remote\n-\t\tcolor.decorate.HEAD\n-\t\tcolor.decorate.branch\n-\t\tcolor.decorate.remoteBranch\n-\t\tcolor.decorate.stash\n-\t\tcolor.decorate.tag\n-\t\tcolor.diff\n-\t\tcolor.diff.commit\n-\t\tcolor.diff.frag\n-\t\tcolor.diff.func\n-\t\tcolor.diff.meta\n-\t\tcolor.diff.new\n-\t\tcolor.diff.old\n-\t\tcolor.diff.plain\n-\t\tcolor.diff.whitespace\n-\t\tcolor.grep\n-\t\tcolor.grep.context\n-\t\tcolor.grep.filename\n-\t\tcolor.grep.function\n-\t\tcolor.grep.linenumber\n-\t\tcolor.grep.match\n-\t\tcolor.grep.selected\n-\t\tcolor.grep.separator\n-\t\tcolor.interactive\n-\t\tcolor.interactive.error\n-\t\tcolor.interactive.header\n-\t\tcolor.interactive.help\n-\t\tcolor.interactive.prompt\n-\t\tcolor.pager\n-\t\tcolor.showbranch\n-\t\tcolor.status\n-\t\tcolor.status.added\n-\t\tcolor.status.changed\n-\t\tcolor.status.header\n-\t\tcolor.status.localBranch\n-\t\tcolor.status.nobranch\n-\t\tcolor.status.remoteBranch\n-\t\tcolor.status.unmerged\n-\t\tcolor.status.untracked\n-\t\tcolor.status.updated\n-\t\tcolor.ui\n-\t\tcommit.cleanup\n-\t\tcommit.gpgSign\n-\t\tcommit.status\n-\t\tcommit.template\n-\t\tcommit.verbose\n-\t\tcore.abbrev\n-\t\tcore.askpass\n-\t\tcore.attributesfile\n-\t\tcore.autocrlf\n-\t\tcore.bare\n-\t\tcore.bigFileThreshold\n-\t\tcore.checkStat\n-\t\tcore.commentChar\n-\t\tcore.compression\n-\t\tcore.createObject\n-\t\tcore.deltaBaseCacheLimit\n-\t\tcore.editor\n-\t\tcore.eol\n-\t\tcore.excludesfile\n-\t\tcore.fileMode\n-\t\tcore.fsyncobjectfiles\n-\t\tcore.gitProxy\n-\t\tcore.hideDotFiles\n-\t\tcore.hooksPath\n-\t\tcore.ignoreStat\n-\t\tcore.ignorecase\n-\t\tcore.logAllRefUpdates\n-\t\tcore.loosecompression\n-\t\tcore.notesRef\n-\t\tcore.packedGitLimit\n-\t\tcore.packedGitWindowSize\n-\t\tcore.packedRefsTimeout\n-\t\tcore.pager\n-\t\tcore.precomposeUnicode\n-\t\tcore.preferSymlinkRefs\n-\t\tcore.preloadindex\n-\t\tcore.protectHFS\n-\t\tcore.protectNTFS\n-\t\tcore.quotepath\n-\t\tcore.repositoryFormatVersion\n-\t\tcore.safecrlf\n-\t\tcore.sharedRepository\n-\t\tcore.sparseCheckout\n-\t\tcore.splitIndex\n-\t\tcore.sshCommand\n-\t\tcore.symlinks\n-\t\tcore.trustctime\n-\t\tcore.untrackedCache\n-\t\tcore.warnAmbiguousRefs\n-\t\tcore.whitespace\n-\t\tcore.worktree\n-\t\tcredential.helper\n-\t\tcredential.useHttpPath\n-\t\tcredential.username\n-\t\tcredentialCache.ignoreSIGHUP\n-\t\tdiff.autorefreshindex\n-\t\tdiff.external\n-\t\tdiff.ignoreSubmodules\n-\t\tdiff.mnemonicprefix\n-\t\tdiff.noprefix\n-\t\tdiff.renameLimit\n-\t\tdiff.renames\n-\t\tdiff.statGraphWidth\n-\t\tdiff.submodule\n-\t\tdiff.suppressBlankEmpty\n-\t\tdiff.tool\n-\t\tdiff.wordRegex\n-\t\tdiff.algorithm\n-\t\tdifftool.\n-\t\tdifftool.prompt\n-\t\tfetch.recurseSubmodules\n-\t\tfetch.unpackLimit\n-\t\tformat.attach\n-\t\tformat.cc\n-\t\tformat.coverLetter\n-\t\tformat.from\n-\t\tformat.headers\n-\t\tformat.numbered\n-\t\tformat.pretty\n-\t\tformat.signature\n-\t\tformat.signoff\n-\t\tformat.subjectprefix\n-\t\tformat.suffix\n-\t\tformat.thread\n-\t\tformat.to\n-\t\tgc.\n-\t\tgc.aggressiveDepth\n-\t\tgc.aggressiveWindow\n-\t\tgc.auto\n-\t\tgc.autoDetach\n-\t\tgc.autopacklimit\n-\t\tgc.logExpiry\n-\t\tgc.packrefs\n-\t\tgc.pruneexpire\n-\t\tgc.reflogexpire\n-\t\tgc.reflogexpireunreachable\n-\t\tgc.rerereresolved\n-\t\tgc.rerereunresolved\n-\t\tgc.worktreePruneExpire\n-\t\tgitcvs.allbinary\n-\t\tgitcvs.commitmsgannotation\n-\t\tgitcvs.dbTableNamePrefix\n-\t\tgitcvs.dbdriver\n-\t\tgitcvs.dbname\n-\t\tgitcvs.dbpass\n-\t\tgitcvs.dbuser\n-\t\tgitcvs.enabled\n-\t\tgitcvs.logfile\n-\t\tgitcvs.usecrlfattr\n-\t\tguitool.\n-\t\tgui.blamehistoryctx\n-\t\tgui.commitmsgwidth\n-\t\tgui.copyblamethreshold\n-\t\tgui.diffcontext\n-\t\tgui.encoding\n-\t\tgui.fastcopyblame\n-\t\tgui.matchtrackingbranch\n-\t\tgui.newbranchtemplate\n-\t\tgui.pruneduringfetch\n-\t\tgui.spellingdictionary\n-\t\tgui.trustmtime\n-\t\thelp.autocorrect\n-\t\thelp.browser\n-\t\thelp.format\n-\t\thttp.lowSpeedLimit\n-\t\thttp.lowSpeedTime\n-\t\thttp.maxRequests\n-\t\thttp.minSessions\n-\t\thttp.noEPSV\n-\t\thttp.postBuffer\n-\t\thttp.proxy\n-\t\thttp.sslCipherList\n-\t\thttp.sslVersion\n-\t\thttp.sslCAInfo\n-\t\thttp.sslCAPath\n-\t\thttp.sslCert\n-\t\thttp.sslCertPasswordProtected\n-\t\thttp.sslKey\n-\t\thttp.sslVerify\n-\t\thttp.useragent\n-\t\ti18n.commitEncoding\n-\t\ti18n.logOutputEncoding\n-\t\timap.authMethod\n-\t\timap.folder\n-\t\timap.host\n-\t\timap.pass\n-\t\timap.port\n-\t\timap.preformattedHTML\n-\t\timap.sslverify\n-\t\timap.tunnel\n-\t\timap.user\n-\t\tinit.templatedir\n-\t\tinstaweb.browser\n-\t\tinstaweb.httpd\n-\t\tinstaweb.local\n-\t\tinstaweb.modulepath\n-\t\tinstaweb.port\n-\t\tinteractive.singlekey\n-\t\tlog.date\n-\t\tlog.decorate\n-\t\tlog.showroot\n-\t\tmailmap.file\n-\t\tman.\n-\t\tman.viewer\n-\t\tmerge.\n-\t\tmerge.conflictstyle\n-\t\tmerge.log\n-\t\tmerge.renameLimit\n-\t\tmerge.renormalize\n-\t\tmerge.stat\n-\t\tmerge.tool\n-\t\tmerge.verbosity\n-\t\tmergetool.\n-\t\tmergetool.keepBackup\n-\t\tmergetool.keepTemporaries\n-\t\tmergetool.prompt\n-\t\tnotes.displayRef\n-\t\tnotes.rewrite.\n-\t\tnotes.rewrite.amend\n-\t\tnotes.rewrite.rebase\n-\t\tnotes.rewriteMode\n-\t\tnotes.rewriteRef\n-\t\tpack.compression\n-\t\tpack.deltaCacheLimit\n-\t\tpack.deltaCacheSize\n-\t\tpack.depth\n-\t\tpack.indexVersion\n-\t\tpack.packSizeLimit\n-\t\tpack.threads\n-\t\tpack.window\n-\t\tpack.windowMemory\n-\t\tpager.\n-\t\tpretty.\n-\t\tpull.octopus\n-\t\tpull.twohead\n-\t\tpush.default\n-\t\tpush.followTags\n-\t\trebase.autosquash\n-\t\trebase.stat\n-\t\treceive.autogc\n-\t\treceive.denyCurrentBranch\n-\t\treceive.denyDeleteCurrent\n-\t\treceive.denyDeletes\n-\t\treceive.denyNonFastForwards\n-\t\treceive.fsckObjects\n-\t\treceive.unpackLimit\n-\t\treceive.updateserverinfo\n-\t\tremote.pushdefault\n-\t\tremotes.\n-\t\trepack.usedeltabaseoffset\n-\t\trerere.autoupdate\n-\t\trerere.enabled\n-\t\tsendemail.\n-\t\tsendemail.aliasesfile\n-\t\tsendemail.aliasfiletype\n-\t\tsendemail.bcc\n-\t\tsendemail.cc\n-\t\tsendemail.cccmd\n-\t\tsendemail.chainreplyto\n-\t\tsendemail.confirm\n-\t\tsendemail.envelopesender\n-\t\tsendemail.from\n-\t\tsendemail.identity\n-\t\tsendemail.multiedit\n-\t\tsendemail.signedoffbycc\n-\t\tsendemail.smtpdomain\n-\t\tsendemail.smtpencryption\n-\t\tsendemail.smtppass\n-\t\tsendemail.smtpserver\n-\t\tsendemail.smtpserveroption\n-\t\tsendemail.smtpserverport\n-\t\tsendemail.smtpuser\n-\t\tsendemail.suppresscc\n-\t\tsendemail.suppressfrom\n-\t\tsendemail.thread\n-\t\tsendemail.to\n-\t\tsendemail.tocmd\n-\t\tsendemail.validate\n-\t\tsendemail.smtpbatchsize\n-\t\tsendemail.smtprelogindelay\n-\t\tshowbranch.default\n-\t\tstatus.relativePaths\n-\t\tstatus.showUntrackedFiles\n-\t\tstatus.submodulesummary\n-\t\tsubmodule.\n-\t\ttar.umask\n-\t\ttransfer.unpackLimit\n-\t\turl.\n-\t\tuser.email\n-\t\tuser.name\n-\t\tuser.signingkey\n-\t\tweb.browser\n-\t\tbranch. remote.\n-\t\"\n+\t__git_compute_config_vars\n+\t__gitcomp \"$__git_config_vars\"\n }\n \n _git_remote ()\ndiff --git a/help.c b/help.c\nindex b10c8b0230..a4157a3512 100644\n--- a/help.c\n+++ b/help.c\n@@ -416,7 +416,7 @@ struct slot_expansion {\n \tint found;\n };\n \n-void list_config_help(void)\n+void list_config_help(int for_human)\n {\n \tstruct slot_expansion slot_expansions[] = {\n \t\t{ \"advice\", \"*\", list_advices },\n@@ -435,6 +435,7 @@ void list_config_help(void)\n \n \tfor (p = config_name_list; *p; p++) {\n \t\tconst char *var = *p;\n+\t\tconst char *wildcard, *tag, *cut;\n \n \t\tfor (e = slot_expansions; e->prefix; e++) {\n \t\t\tstruct strbuf sb = STRBUF_INIT;\n@@ -447,8 +448,33 @@ void list_config_help(void)\n \t\t\te->found++;\n \t\t\tbreak;\n \t\t}\n-\t\tif (!e->prefix)\n+\t\tif (e->prefix)\n+\t\t\tcontinue;\n+\t\tif (for_human) {\n \t\t\tputs(var);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\twildcard = strchr(var, '*');\n+\t\ttag = strchr(var, '<');\n+\n+\t\tif (!wildcard && !tag) {\n+\t\t\tputs(var);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (wildcard && !tag)\n+\t\t\tcut = wildcard;\n+\t\telse if (!wildcard && tag)\n+\t\t\tcut = tag;\n+\t\telse\n+\t\t\tcut = wildcard < tag ? wildcard : tag;\n+\n+\t\t/*\n+\t\t * We may produce duplicates, but that's up to\n+\t\t * git-completion.bash to handle\n+\t\t */\n+\t\tprintf(\"%.*s\\n\", (int)(cut - var), var);\n \t}\n \n \tfor (e = slot_expansions; e->prefix; e++)\ndiff --git a/help.h b/help.h\nindex d7d1409718..04df559c64 100644\n--- a/help.h\n+++ b/help.h\n@@ -21,7 +21,7 @@ static inline void mput_char(char c, unsigned int num)\n extern void list_common_cmds_help(void);\n extern void list_all_cmds_help(void);\n extern void list_common_guides_help(void);\n-extern void list_config_help(void);\n+extern void list_config_help(int for_human);\n \n extern void list_all_main_cmds(struct string_list *list);\n extern void list_all_other_cmds(struct string_list *list);\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"347237","messageId":"20180510141927.23590-7-pclouds@gmail.com","threadId":"48456","inReplyTo":"20180510141927.23590-1-pclouds@gmail.com","subject":"[PATCH 6/9] am: move advice.amWorkDir parsing back to advice.c","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-10T14:19:24Z","receivedAt":"2018-05-10T14:19:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The only benefit from this move (apart from cleaner code) is that\nadvice.amWorkDir should now show up in `git help --config`. There\nshould be no regression since advice config is always read by the\ngit_default_config().\n\nWhile at there, use advise() like other code. We now get \"hint: \"\nprefix and the output is stderr instead of stdout (which is also the\nreason for the test update because stderr is checked in a following\ntest and the extra advice can fail it).\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n advice.c              | 2 ++\n advice.h              | 1 +\n builtin/am.c          | 5 +----\n t/t4254-am-corrupt.sh | 2 +-\n 4 files changed, 5 insertions(+), 5 deletions(-)\n\ndiff --git a/advice.c b/advice.c\nindex d8ea93637a..d300491a6f 100644\n--- a/advice.c\n+++ b/advice.c\n@@ -16,6 +16,7 @@ int advice_implicit_identity = 1;\n int advice_detached_head = 1;\n int advice_set_upstream_failure = 1;\n int advice_object_name_warning = 1;\n+int advice_amworkdir = 1;\n int advice_rm_hints = 1;\n int advice_add_embedded_repo = 1;\n int advice_ignored_hook = 1;\n@@ -39,6 +40,7 @@ static struct {\n \t{ \"detachedHead\", &advice_detached_head },\n \t{ \"setupStreamFailure\", &advice_set_upstream_failure },\n \t{ \"objectNameWarning\", &advice_object_name_warning },\n+\t{ \"amWorkDir\", &advice_amworkdir },\n \t{ \"rmHints\", &advice_rm_hints },\n \t{ \"addEmbeddedRepo\", &advice_add_embedded_repo },\n \t{ \"ignoredHook\", &advice_ignored_hook },\ndiff --git a/advice.h b/advice.h\nindex 70568fa792..7555385aa5 100644\n--- a/advice.h\n+++ b/advice.h\n@@ -17,6 +17,7 @@ extern int advice_implicit_identity;\n extern int advice_detached_head;\n extern int advice_set_upstream_failure;\n extern int advice_object_name_warning;\n+extern int advice_amworkdir;\n extern int advice_rm_hints;\n extern int advice_add_embedded_repo;\n extern int advice_ignored_hook;\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 9c82603f70..03e5870c62 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -1827,15 +1827,12 @@ static void am_run(struct am_state *state, int resume)\n \t\t}\n \n \t\tif (apply_status) {\n-\t\t\tint advice_amworkdir = 1;\n \n \t\t\tprintf_ln(_(\"Patch failed at %s %.*s\"), msgnum(state),\n \t\t\t\tlinelen(state->msg), state->msg);\n \n-\t\t\tgit_config_get_bool(\"advice.amworkdir\", &advice_amworkdir);\n-\n \t\t\tif (advice_amworkdir)\n-\t\t\t\tprintf_ln(_(\"Use 'git am --show-current-patch' to see the failed patch\"));\n+\t\t\t\tadvise(_(\"Use 'git am --show-current-patch' to see the failed patch\"));\n \n \t\t\tdie_user_resolve(state);\n \t\t}\ndiff --git a/t/t4254-am-corrupt.sh b/t/t4254-am-corrupt.sh\nindex 168739c721..fd3bdbfe2c 100755\n--- a/t/t4254-am-corrupt.sh\n+++ b/t/t4254-am-corrupt.sh\n@@ -25,7 +25,7 @@ test_expect_success setup '\n #   fatal: unable to write file '(null)' mode 100644: Bad address\n # Also, it had the unwanted side-effect of deleting f.\n test_expect_success 'try to apply corrupted patch' '\n-\ttest_must_fail git am bad-patch.diff 2>actual\n+\ttest_must_fail git -c advice.amWorkDir=false am bad-patch.diff 2>actual\n '\n \n test_expect_success 'compare diagnostic; ensure file is still here' '\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"347238","messageId":"20180510141927.23590-10-pclouds@gmail.com","threadId":"48456","inReplyTo":"20180510141927.23590-1-pclouds@gmail.com","subject":"[PATCH 9/9] log-tree: allow to customize 'grafted' color","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-10T14:19:27Z","receivedAt":"2018-05-10T14:19:53Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Commit 76f5df305b (log: decorate grafted commits with \"grafted\" -\n2011-08-18) lets us decorate grafted commits but I forgot about the\ncolor.decorate.* config.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/config.txt | 3 ++-\n log-tree.c               | 1 +\n 2 files changed, 3 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 91f7eaed7b..c63d66906d 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -1138,7 +1138,8 @@ color.diff.<slot>::\n color.decorate.<slot>::\n \tUse customized color for 'git log --decorate' output.  `<slot>` is one\n \tof `branch`, `remoteBranch`, `tag`, `stash` or `HEAD` for local\n-\tbranches, remote-tracking branches, tags, stash and HEAD, respectively.\n+\tbranches, remote-tracking branches, tags, stash and HEAD, respectively\n+\tand `grafted` for grafted commits.\n \n color.grep::\n \tWhen set to `always`, always highlight matches.  When `false` (or\ndiff --git a/log-tree.c b/log-tree.c\nindex 19cfebd231..414dbce0dd 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -34,6 +34,7 @@ static const char *color_decorate_slots[] = {\n \t[DECORATION_REF_TAG]\t= \"tag\",\n \t[DECORATION_REF_STASH]\t= \"stash\",\n \t[DECORATION_REF_HEAD]\t= \"HEAD\",\n+\t[DECORATION_GRAFTED]\t= \"grafted\",\n };\n \n static const char *decorate_get_color(int decorate_use_color, enum decoration_type ix)\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"347239","messageId":"20180510141927.23590-5-pclouds@gmail.com","threadId":"48456","inReplyTo":"20180510141927.23590-1-pclouds@gmail.com","subject":"[PATCH 4/9] help: add --config to list all available config","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-10T14:19:22Z","receivedAt":"2018-05-10T14:20:01Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Sometimes it helps to list all available config vars so the user can\nsearch for something they want. The config man page can also be used\nbut it's harder to search if you want to focus on the variable name,\nfor example.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/git-help.txt |  5 ++++\n advice.c                   |  9 +++++++\n builtin/branch.c           |  6 +++++\n builtin/clean.c            |  6 +++++\n builtin/commit.c           |  7 ++++++\n builtin/help.c             |  9 +++++++\n diff.c                     |  7 ++++++\n fsck.c                     | 11 +++++++++\n generate-cmdlist.sh        | 20 ++++++++++++++++\n grep.c                     |  7 ++++++\n help.c                     | 48 ++++++++++++++++++++++++++++++++++++++\n help.h                     | 18 ++++++++++++++\n log-tree.c                 |  6 +++++\n 13 files changed, 159 insertions(+)\n\ndiff --git a/Documentation/git-help.txt b/Documentation/git-help.txt\nindex a40fc38d8b..83d25d825a 100644\n--- a/Documentation/git-help.txt\n+++ b/Documentation/git-help.txt\n@@ -45,6 +45,11 @@ OPTIONS\n \tWhen used with `--verbose` print description for all recognized\n \tcommands.\n \n+-c::\n+--config::\n+\tList all available configuration variables. This is a short\n+\tsummary of the list in linkgit:git-config[1].\n+\n -g::\n --guides::\n \tPrints a list of useful guides on the standard output. This\ndiff --git a/advice.c b/advice.c\nindex 406efc183b..b211ebc588 100644\n--- a/advice.c\n+++ b/advice.c\n@@ -1,5 +1,6 @@\n #include \"cache.h\"\n #include \"config.h\"\n+#include \"help.h\"\n \n int advice_push_update_rejected = 1;\n int advice_push_non_ff_current = 1;\n@@ -84,6 +85,14 @@ int git_default_advice_config(const char *var, const char *value)\n \treturn 0;\n }\n \n+void list_advices(const char *prefix)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < ARRAY_SIZE(advice_config); i++)\n+\t\tprintf(\"%s.%s\\n\", prefix, advice_config[i].name);\n+}\n+\n int error_resolve_conflict(const char *me)\n {\n \tif (!strcmp(me, \"cherry-pick\"))\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex b41f332589..23bbdcb301 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -22,6 +22,7 @@\n #include \"wt-status.h\"\n #include \"ref-filter.h\"\n #include \"worktree.h\"\n+#include \"help.h\"\n \n static const char * const builtin_branch_usage[] = {\n \tN_(\"git branch [<options>] [-r | -a] [--merged | --no-merged]\"),\n@@ -67,6 +68,11 @@ static const char *color_branch_slots[] = {\n static struct string_list output = STRING_LIST_INIT_DUP;\n static unsigned int colopts;\n \n+void list_color_branch_slots(const char *prefix)\n+{\n+\tPRINT_ARRAY(prefix, color_branch_slots);\n+}\n+\n static int git_branch_config(const char *var, const char *value, void *cb)\n {\n \tconst char *slot_name;\ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex 0ccd95e693..72cea1537e 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -16,6 +16,7 @@\n #include \"column.h\"\n #include \"color.h\"\n #include \"pathspec.h\"\n+#include \"help.h\"\n \n static int force = -1; /* unset */\n static int interactive;\n@@ -91,6 +92,11 @@ struct menu_stuff {\n \tvoid *stuff;\n };\n \n+void list_color_interactive_slots(const char *prefix)\n+{\n+\tPRINT_ARRAY(prefix, color_interactive_slots);\n+}\n+\n static int git_clean_config(const char *var, const char *value, void *cb)\n {\n \tconst char *slot_name;\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex bee5825bd2..41c3c4f5cd 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -32,6 +32,7 @@\n #include \"column.h\"\n #include \"sequencer.h\"\n #include \"mailmap.h\"\n+#include \"help.h\"\n \n static const char * const builtin_commit_usage[] = {\n \tN_(\"git commit [<options>] [--] <pathspec>...\"),\n@@ -1194,6 +1195,12 @@ static int parse_status_slot(const char *slot)\n \treturn LOOKUP_CONFIG(color_status_slots, slot);\n }\n \n+void list_color_status_slots(const char *prefix)\n+{\n+\tprintf(\"%s.%s\\n\", prefix, \"added\");\n+\tPRINT_ARRAY(prefix, color_status_slots);\n+}\n+\n static int git_status_config(const char *k, const char *v, void *cb)\n {\n \tstruct wt_status *s = cb;\ndiff --git a/builtin/help.c b/builtin/help.c\nindex 5727fb5e51..a1153cf473 100644\n--- a/builtin/help.c\n+++ b/builtin/help.c\n@@ -36,6 +36,7 @@ static const char *html_path;\n \n static int show_all = 0;\n static int show_guides = 0;\n+static int show_config;\n static int verbose;\n static unsigned int colopts;\n static enum help_format help_format = HELP_FORMAT_NONE;\n@@ -44,6 +45,7 @@ static struct option builtin_help_options[] = {\n \tOPT_BOOL('a', \"all\", &show_all, N_(\"print all available commands\")),\n \tOPT_HIDDEN_BOOL(0, \"exclude-guides\", &exclude_guides, N_(\"exclude guides\")),\n \tOPT_BOOL('g', \"guides\", &show_guides, N_(\"print list of useful guides\")),\n+\tOPT_BOOL('c', \"config\", &show_config, N_(\"print list recognized config variables\")),\n \tOPT_SET_INT('m', \"man\", &help_format, N_(\"show man page\"), HELP_FORMAT_MAN),\n \tOPT_SET_INT('w', \"web\", &help_format, N_(\"show manual in web browser\"),\n \t\t\tHELP_FORMAT_WEB),\n@@ -443,6 +445,13 @@ int cmd_help(int argc, const char **argv, const char *prefix)\n \t\tlist_commands(colopts, &main_cmds, &other_cmds);\n \t}\n \n+\tif (show_config) {\n+\t\tsetup_pager();\n+\t\tlist_config_help();\n+\t\tprintf(\"\\n%s\\n\", _(\"'git help config' for more information\"));\n+\t\treturn 0;\n+\t}\n+\n \tif (show_guides)\n \t\tlist_common_guides_help();\n \ndiff --git a/diff.c b/diff.c\nindex 6f781a2c57..5cae59ec1a 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -22,6 +22,7 @@\n #include \"argv-array.h\"\n #include \"graph.h\"\n #include \"packfile.h\"\n+#include \"help.h\"\n \n #ifdef NO_FAST_WORKING_DIRECTORY\n #define FAST_WORKING_DIRECTORY 0\n@@ -100,6 +101,12 @@ static int parse_diff_color_slot(const char *var)\n \treturn LOOKUP_CONFIG(color_diff_slots, var);\n }\n \n+void list_color_diff_slots(const char *prefix)\n+{\n+\tprintf(\"%s.%s\\n\", prefix, \"plain\");\n+\tPRINT_ARRAY(prefix, color_diff_slots);\n+}\n+\n static int parse_dirstat_params(struct diff_options *options, const char *params_string,\n \t\t\t\tstruct strbuf *errmsg)\n {\ndiff --git a/fsck.c b/fsck.c\nindex f2534abd44..b9f5e7b3f1 100644\n--- a/fsck.c\n+++ b/fsck.c\n@@ -10,6 +10,7 @@\n #include \"utf8.h\"\n #include \"sha1-array.h\"\n #include \"decorate.h\"\n+#include \"help.h\"\n \n #define FSCK_FATAL -1\n #define FSCK_INFO -2\n@@ -118,6 +119,16 @@ static int parse_msg_id(const char *text)\n \treturn -1;\n }\n \n+void list_fsck_msg_ids(const char *prefix)\n+{\n+\tint i;\n+\n+\tprepare_msg_ids();\n+\t/* TODO: we can do better by producing camelCase names */\n+\tfor (i = 0; i < FSCK_MSG_MAX; i++)\n+\t\tprintf(\"%s.%s\\n\", prefix, msg_id_info[i].downcased);\n+}\n+\n static int fsck_msg_type(enum fsck_msg_id msg_id,\n \tstruct fsck_options *options)\n {\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex 8d6d8b45ce..25d4516f1f 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -76,6 +76,24 @@ print_command_list () {\n \techo \"};\"\n }\n \n+print_config_list() {\n+\tcat <<EOF\n+static const char *config_name_list[] = {\n+EOF\n+\tgrep '^[a-zA-Z].*\\..*::$' Documentation/config.txt |\n+\tgrep -v deprecated |\n+\tsed 's/::$//; s/,  */\\n/g' |\n+\tsort |\n+\twhile read line\n+\tdo\n+\t\techo \"\t\\\"$line\\\",\"\n+\tdone\n+\tcat <<EOF\n+\tNULL,\n+};\n+EOF\n+}\n+\n echo \"/* Automatically generated by generate-cmdlist.sh */\n struct cmdname_help {\n \tconst char *name;\n@@ -88,3 +106,5 @@ echo\n define_category_names \"$1\"\n echo\n print_command_list \"$1\"\n+echo\n+print_config_list\ndiff --git a/grep.c b/grep.c\nindex 2f7ebe60f6..da6dc9af4f 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -7,6 +7,7 @@\n #include \"diffcore.h\"\n #include \"commit.h\"\n #include \"quote.h\"\n+#include \"help.h\"\n \n static int grep_source_load(struct grep_source *gs);\n static int grep_source_is_binary(struct grep_source *gs);\n@@ -133,6 +134,12 @@ int grep_config(const char *var, const char *value, void *cb)\n \treturn 0;\n }\n \n+void list_color_grep_slots(const char *prefix)\n+{\n+\tprintf(\"%s.%s\\n\", prefix, \"match\");\n+\tPRINT_ARRAY(prefix, color_grep_slots);\n+}\n+\n /*\n  * Initialize one instance of grep_opt and copy the\n  * default values from the template we read the configuration\ndiff --git a/help.c b/help.c\nindex abf87205b2..b10c8b0230 100644\n--- a/help.c\n+++ b/help.c\n@@ -409,6 +409,54 @@ void list_common_guides_help(void)\n \tputchar('\\n');\n }\n \n+struct slot_expansion {\n+\tconst char *prefix;\n+\tconst char *placeholder;\n+\tvoid (*fn)(const char *prefix);\n+\tint found;\n+};\n+\n+void list_config_help(void)\n+{\n+\tstruct slot_expansion slot_expansions[] = {\n+\t\t{ \"advice\", \"*\", list_advices },\n+\t\t{ \"color.branch\", \"<slot>\", list_color_branch_slots },\n+\t\t{ \"color.decorate\", \"<slot>\", list_color_decorate_slots },\n+\t\t{ \"color.diff\", \"<slot>\", list_color_diff_slots },\n+\t\t{ \"color.grep\", \"<slot>\", list_color_grep_slots },\n+\t\t{ \"color.interactive\", \"<slot>\", list_color_interactive_slots },\n+\t\t{ \"color.status\", \"<slot>\", list_color_status_slots },\n+\t\t{ \"fsck\", \"<msg-id>\", list_fsck_msg_ids },\n+\t\t{ \"receive.fsck\", \"<msg-id>\", list_fsck_msg_ids },\n+\t\t{ NULL, NULL, NULL }\n+\t};\n+\tconst char **p;\n+\tstruct slot_expansion *e;\n+\n+\tfor (p = config_name_list; *p; p++) {\n+\t\tconst char *var = *p;\n+\n+\t\tfor (e = slot_expansions; e->prefix; e++) {\n+\t\t\tstruct strbuf sb = STRBUF_INIT;\n+\n+\t\t\tstrbuf_addf(&sb, \"%s.%s\", e->prefix, e->placeholder);\n+\t\t\tif (strcasecmp(var, sb.buf))\n+\t\t\t\tcontinue;\n+\t\t\te->fn(e->prefix);\n+\t\t\tstrbuf_release(&sb);\n+\t\t\te->found++;\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (!e->prefix)\n+\t\t\tputs(var);\n+\t}\n+\n+\tfor (e = slot_expansions; e->prefix; e++)\n+\t\tif (!e->found)\n+\t\t\tBUG(\"slot_expansion %s.%s is not used\",\n+\t\t\t    e->prefix, e->placeholder);\n+}\n+\n void list_all_cmds_help(void)\n {\n \tprint_cmd_by_category(main_categories);\ndiff --git a/help.h b/help.h\nindex 3b38292a1b..d7d1409718 100644\n--- a/help.h\n+++ b/help.h\n@@ -21,6 +21,7 @@ static inline void mput_char(char c, unsigned int num)\n extern void list_common_cmds_help(void);\n extern void list_all_cmds_help(void);\n extern void list_common_guides_help(void);\n+extern void list_config_help(void);\n \n extern void list_all_main_cmds(struct string_list *list);\n extern void list_all_other_cmds(struct string_list *list);\n@@ -42,4 +43,21 @@ extern void list_commands(unsigned int colopts, struct cmdnames *main_cmds, stru\n  * ref to the command, to give suggested \"correct\" refs.\n  */\n extern void help_unknown_ref(const char *ref, const char *cmd, const char *error);\n+\n+/* These are actually scattered over many C files */\n+#define PRINT_ARRAY(prefix, array)  {\t\t\t\t\t\\\n+\t\tint i;\t\t\t\t\t\t\t\\\n+\t\tfor (i = 0; i < ARRAY_SIZE(array); i++)\t\t\t\\\n+\t\t\tif (array[i])\t\t\t\t\t\\\n+\t\t\t\tprintf(\"%s.%s\\n\", prefix, array[i]);\t\\\n+\t}\n+void list_advices(const char *prefix);\n+void list_color_branch_slots(const char *prefix);\n+void list_color_decorate_slots(const char *prefix);\n+void list_color_diff_slots(const char *prefix);\n+void list_color_grep_slots(const char *prefix);\n+void list_color_interactive_slots(const char *prefix);\n+void list_color_status_slots(const char *prefix);\n+void list_fsck_msg_ids(const char *prefix);\n+\n #endif /* HELP_H */\ndiff --git a/log-tree.c b/log-tree.c\nindex 093efb477e..19cfebd231 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -12,6 +12,7 @@\n #include \"gpg-interface.h\"\n #include \"sequencer.h\"\n #include \"line-log.h\"\n+#include \"help.h\"\n \n static struct decoration name_decoration = { \"object names\" };\n static int decoration_loaded;\n@@ -42,6 +43,11 @@ static const char *decorate_get_color(int decorate_use_color, enum decoration_ty\n \treturn \"\";\n }\n \n+void list_color_decorate_slots(const char *prefix)\n+{\n+\tPRINT_ARRAY(prefix, color_decorate_slots);\n+}\n+\n int parse_decorate_color_config(const char *var, const char *slot_name, const char *value)\n {\n \tint slot = LOOKUP_CONFIG(color_decorate_slots, slot_name);\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"347240","messageId":"20180510141927.23590-6-pclouds@gmail.com","threadId":"48456","inReplyTo":"20180510141927.23590-1-pclouds@gmail.com","subject":"[PATCH 5/9] advice: keep config name in camelCase in advice_config[]","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-10T14:19:23Z","receivedAt":"2018-05-10T14:20:03Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"For parsing, we don't really need this because the main config parser\nwill lowercase everything so we can do exact matching. But this array\nnow is also used for printing in `git help --config`. Keep camelCase\nso we have a nice printout.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n advice.c | 40 ++++++++++++++++++++--------------------\n 1 file changed, 20 insertions(+), 20 deletions(-)\n\ndiff --git a/advice.c b/advice.c\nindex b211ebc588..d8ea93637a 100644\n--- a/advice.c\n+++ b/advice.c\n@@ -25,27 +25,27 @@ static struct {\n \tconst char *name;\n \tint *preference;\n } advice_config[] = {\n-\t{ \"pushupdaterejected\", &advice_push_update_rejected },\n-\t{ \"pushnonffcurrent\", &advice_push_non_ff_current },\n-\t{ \"pushnonffmatching\", &advice_push_non_ff_matching },\n-\t{ \"pushalreadyexists\", &advice_push_already_exists },\n-\t{ \"pushfetchfirst\", &advice_push_fetch_first },\n-\t{ \"pushneedsforce\", &advice_push_needs_force },\n-\t{ \"statushints\", &advice_status_hints },\n-\t{ \"statusuoption\", &advice_status_u_option },\n-\t{ \"commitbeforemerge\", &advice_commit_before_merge },\n-\t{ \"resolveconflict\", &advice_resolve_conflict },\n-\t{ \"implicitidentity\", &advice_implicit_identity },\n-\t{ \"detachedhead\", &advice_detached_head },\n-\t{ \"setupstreamfailure\", &advice_set_upstream_failure },\n-\t{ \"objectnamewarning\", &advice_object_name_warning },\n-\t{ \"rmhints\", &advice_rm_hints },\n-\t{ \"addembeddedrepo\", &advice_add_embedded_repo },\n-\t{ \"ignoredhook\", &advice_ignored_hook },\n-\t{ \"waitingforeditor\", &advice_waiting_for_editor },\n+\t{ \"pushUpdateRejected\", &advice_push_update_rejected },\n+\t{ \"pushNonFFCurrent\", &advice_push_non_ff_current },\n+\t{ \"pushNonFFMatching\", &advice_push_non_ff_matching },\n+\t{ \"pushAlreadyExists\", &advice_push_already_exists },\n+\t{ \"pushFetchFirst\", &advice_push_fetch_first },\n+\t{ \"pushNeedsForce\", &advice_push_needs_force },\n+\t{ \"statusHints\", &advice_status_hints },\n+\t{ \"statusUoption\", &advice_status_u_option },\n+\t{ \"commitBeforeMerge\", &advice_commit_before_merge },\n+\t{ \"resolveConflict\", &advice_resolve_conflict },\n+\t{ \"implicitIdentity\", &advice_implicit_identity },\n+\t{ \"detachedHead\", &advice_detached_head },\n+\t{ \"setupStreamFailure\", &advice_set_upstream_failure },\n+\t{ \"objectNameWarning\", &advice_object_name_warning },\n+\t{ \"rmHints\", &advice_rm_hints },\n+\t{ \"addEmbeddedRepo\", &advice_add_embedded_repo },\n+\t{ \"ignoredHook\", &advice_ignored_hook },\n+\t{ \"waitingForEditor\", &advice_waiting_for_editor },\n \n \t/* make this an alias for backward compatibility */\n-\t{ \"pushnonfastforward\", &advice_push_update_rejected }\n+\t{ \"pushNonFastForward\", &advice_push_update_rejected }\n };\n \n void advise(const char *advice, ...)\n@@ -76,7 +76,7 @@ int git_default_advice_config(const char *var, const char *value)\n \t\treturn 0;\n \n \tfor (i = 0; i < ARRAY_SIZE(advice_config); i++) {\n-\t\tif (strcmp(k, advice_config[i].name))\n+\t\tif (strcasecmp(k, advice_config[i].name))\n \t\t\tcontinue;\n \t\t*advice_config[i].preference = git_config_bool(var, value);\n \t\treturn 0;\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"347242","messageId":"CACsJy8CvbZfVK6TdQAGMGfBWiHuRcVgxQ-MEPNQ_Rcmf1EnFtw@mail.gmail.com","threadId":"48456","inReplyTo":"20180510141927.23590-1-pclouds@gmail.com","subject":"Re: [PATCH 0/9] completion: avoid hard coding config var list","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-10T14:22:43Z","receivedAt":"2018-05-10T14:23:17Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, May 10, 2018 at 4:19 PM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> (on top of nd/command-list)\n\nOh.. and it does make use of C99 designated initializer feature. I\ncould go with out it, but since git-clean has used it for some time\nwithout anybody complaining, I figure I should take advantage of it.\n-- \nDuy\n"},{"id":"347260","messageId":"CAGZ79kYnzQM-mcAm7Q3C=q+uhvt8MYvWrhkUrsyu1FbM2=1Z8g@mail.gmail.com","threadId":"48456","inReplyTo":"20180510141927.23590-2-pclouds@gmail.com","subject":"Re: [PATCH 1/9] Add and use generic name->id mapping code for color slot parsing","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2018-05-10T17:16:58Z","receivedAt":"2018-05-10T17:17:03Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Thu, May 10, 2018 at 7:19 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n\n>  7 files changed, 82 insertions(+), 112 deletions(-)\n\nNice!\n\n\n>\n> +static const char *color_branch_slots[] = {\n> +       [BRANCH_COLOR_RESET]    = \"reset\",\n\nIn 512f41cfac5 (clean.c: use designated initializer, 2017-07-14)\nwe thought we'll do it once and see if anyone complains\n(and it shipped v2.15.0, 2017-10-29), and so far\nnobody complained half a year later. So designated initializers\nare all good now? Do we want to mention this decision in the\ncommit message?\n\nIf so, the patch looks good!\nThanks,\nStefan\n"},{"id":"347335","messageId":"xmqqvabug298.fsf@gitster-ct.c.googlers.com","threadId":"48456","inReplyTo":"20180510141927.23590-1-pclouds@gmail.com","subject":"Re: [PATCH 0/9] completion: avoid hard coding config var list","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-05-11T06:00:51Z","receivedAt":"2018-05-11T06:00:58Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> While at there, this config list is also available to the user via\n> `git help --config` if you can't remember the exact config name you\n> want and don't want to go through that big git-config man page.\n\nMakes a reader anticipate a new user of levenshtein code, perhaps\n;-)\n\n\n"},{"id":"347337","messageId":"CACsJy8C5=+7cVV3nQ5qkgz4pT1QqpEoXE15MkW99vyrwHUnMXA@mail.gmail.com","threadId":"48456","inReplyTo":"xmqqvabug298.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH 0/9] completion: avoid hard coding config var list","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-11T06:24:39Z","receivedAt":"2018-05-11T06:25:13Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Fri, May 11, 2018 at 8:00 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n>\n>> While at there, this config list is also available to the user via\n>> `git help --config` if you can't remember the exact config name you\n>> want and don't want to go through that big git-config man page.\n>\n> Makes a reader anticipate a new user of levenshtein code, perhaps\n> ;-)\n\nWhy would you go and write that for? Now I want to do it :-) Yeah I\nthink config name typo has been a common complaint (including from\nme).\n-- \nDuy\n"},{"id":"347341","messageId":"CACsJy8AYEbV6niTqaJ4XtVjHpXZ65-=9-vpGtxUHbuXVmc8paw@mail.gmail.com","threadId":"48456","inReplyTo":"CAGZ79kYnzQM-mcAm7Q3C=q+uhvt8MYvWrhkUrsyu1FbM2=1Z8g@mail.gmail.com","subject":"Re: [PATCH 1/9] Add and use generic name->id mapping code for color slot parsing","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-11T07:22:55Z","receivedAt":"2018-05-11T07:23:29Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, May 10, 2018 at 7:16 PM, Stefan Beller <sbeller@google.com> wrote:\n> On Thu, May 10, 2018 at 7:19 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n>\n>>  7 files changed, 82 insertions(+), 112 deletions(-)\n>\n> Nice!\n>\n>\n>>\n>> +static const char *color_branch_slots[] = {\n>> +       [BRANCH_COLOR_RESET]    = \"reset\",\n>\n> In 512f41cfac5 (clean.c: use designated initializer, 2017-07-14)\n> we thought we'll do it once and see if anyone complains\n> (and it shipped v2.15.0, 2017-10-29), and so far\n> nobody complained half a year later. So designated initializers\n> are all good now?\n\nI don't know :) but it's worth pushing. I don't think this series\nwould land on the next release, which gives people a couple more\nmonths to complain about C99. It does save me time and if it causes\nproblem, removing designated initializers is trivial\n\n> Do we want to mention this decision in the commit message?\n>\n> If so, the patch looks good!\n> Thanks,\n> Stefan\n-- \nDuy\n"},{"id":"347396","messageId":"CAPig+cQYaabk+XibOMUGa5b4y2D8AhjNBjujgNE7ctLCdFpdCQ@mail.gmail.com","threadId":"48456","inReplyTo":"20180510141927.23590-4-pclouds@gmail.com","subject":"Re: [PATCH 3/9] fsck: factor out msg_id_info[] lazy initialization code","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-05-11T22:23:27Z","receivedAt":"2018-05-11T22:23:42Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, May 10, 2018 at 10:19 AM Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nwrote:\n> This array will be used by some other function than parse_msg_id() in\n> the following commit. Factor out this prep code so it could be called\n> from that one.\n\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n> diff --git a/fsck.c b/fsck.c\n> @@ -84,26 +84,32 @@ static struct {\n> -static int parse_msg_id(const char *text)\n> +static void prepare_msg_ids(void)\n>   {\n> -       if (!msg_id_info[0].downcased) {\n> -               /* convert id_string to lower case, without underscores.\n*/\n> -               for (i = 0; i < FSCK_MSG_MAX; i++) {\n> -                       [...]\n> -               }\n> +       /* convert id_string to lower case, without underscores. */\n> +       for (i = 0; i < FSCK_MSG_MAX; i++) {\n> +               [...]\n>          }\n> +}\n> +\n> +static int parse_msg_id(const char *text)\n> +{\n> +       if (!msg_id_info[0].downcased)\n> +               prepare_msg_ids();\n\nIf you move the \"if (!msg_id_info...)\" conditional into the new\nparpare_msg_ids() function, then it becomes self-contained; it takes care\nof avoiding double-initialization so callers don't have to worry or know\nabout it. (Doing so would also make the diff less noisy.)\n\nNot at all worth a re-roll.\n"},{"id":"347397","messageId":"CAPig+cR63S-cpihwHYOadK_SbNRoCVjOOQH87Ry7fdCwxdbOxg@mail.gmail.com","threadId":"48456","inReplyTo":"20180510141927.23590-5-pclouds@gmail.com","subject":"Re: [PATCH 4/9] help: add --config to list all available config","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-05-11T22:39:20Z","receivedAt":"2018-05-11T22:41:44Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, May 10, 2018 at 10:20 AM Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nwrote:\n> Sometimes it helps to list all available config vars so the user can\n> search for something they want. The config man page can also be used\n> but it's harder to search if you want to focus on the variable name,\n> for example.\n\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n> diff --git a/builtin/help.c b/builtin/help.c\n> @@ -44,6 +45,7 @@ static struct option builtin_help_options[] = {\n>          OPT_BOOL('g', \"guides\", &show_guides, N_(\"print list of useful\nguides\")),\n> +       OPT_BOOL('c', \"config\", &show_config, N_(\"print list recognized\nconfig variables\")),\n\ns/list/& of/\n\nThough, simpler might be better: \"print all configuration variable names\"\n\n> diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\n> @@ -76,6 +76,24 @@ print_command_list () {\n> +print_config_list() {\n> +       cat <<EOF\n> +static const char *config_name_list[] = {\n> +EOF\n> +       grep '^[a-zA-Z].*\\..*::$' Documentation/config.txt |\n> +       grep -v deprecated |\n> +       sed 's/::$//; s/,  */\\n/g' |\n\nNit: \"grep -v\" and \"sed\" could be combined:\n\n     sed '/deprecated/d; s/::$//; s/,  */\\n/g' |\n\n> +       sort |\n> +       while read line\n> +       do\n> +               echo \"  \\\"$line\\\",\"\n> +       done\n> +       cat <<EOF\n> +       NULL,\n> +};\n> +EOF\n> diff --git a/help.c b/help.c\n> @@ -409,6 +409,54 @@ void list_common_guides_help(void)\n> +void list_config_help(void)\n> +{\n> +       [...]\n> +       for (p = config_name_list; *p; p++) {\n> +               const char *var = *p;\n> +\n> +               for (e = slot_expansions; e->prefix; e++) {\n> +                       struct strbuf sb = STRBUF_INIT;\n> +\n> +                       strbuf_addf(&sb, \"%s.%s\", e->prefix,\ne->placeholder);\n> +                       if (strcasecmp(var, sb.buf))\n> +                               continue;\n\nIsn't this \"continue\" leaking the strbuf? It seems that it would be easier\nto declare the strbuf once outside the loop, strbuf_reset() it at the top\nof the loop, and finally strbuf_release() it after the loop exits.\n\n> +                       e->fn(e->prefix);\n> +                       strbuf_release(&sb);\n> +                       e->found++;\n> +                       break;\n> +               }\n> +               if (!e->prefix)\n> +                       puts(var);\n> +       }\n"},{"id":"347398","messageId":"CAPig+cSE_efq71V5ZskORgX5teP5FmUBYB49EdVrveSU8qxnVg@mail.gmail.com","threadId":"48456","inReplyTo":"20180510141927.23590-7-pclouds@gmail.com","subject":"Re: [PATCH 6/9] am: move advice.amWorkDir parsing back to advice.c","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-05-11T22:42:46Z","receivedAt":"2018-05-11T22:43:00Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, May 10, 2018 at 10:19 AM Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nwrote:\n> The only benefit from this move (apart from cleaner code) is that\n> advice.amWorkDir should now show up in `git help --config`. There\n> should be no regression since advice config is always read by the\n> git_default_config().\n\n> While at there, use advise() like other code. We now get \"hint: \"\n> prefix and the output is stderr instead of stdout (which is also the\n> reason for the test update because stderr is checked in a following\n> test and the extra advice can fail it).\n\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n> diff --git a/builtin/am.c b/builtin/am.c\n> @@ -1827,15 +1827,12 @@ static void am_run(struct am_state *state, int\nresume)\n>                  if (apply_status) {\n> -                       int advice_amworkdir = 1;\n\n\nNit: Maybe also delete the blank line following the removed declaration...\n\n>                          printf_ln(_(\"Patch failed at %s %.*s\"),\nmsgnum(state),\n>                                  linelen(state->msg), state->msg);\n"},{"id":"347399","messageId":"CAPig+cSndzXM+FD4bD5axn-QxOjowycDtD_JOoa4ra3sdnWXFQ@mail.gmail.com","threadId":"48456","inReplyTo":"20180510141927.23590-8-pclouds@gmail.com","subject":"Re: [PATCH 7/9] completion: drop the hard coded list of config vars","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-05-11T22:47:52Z","receivedAt":"2018-05-11T22:48:07Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, May 10, 2018 at 10:19 AM Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nwrote:\n> The new help option --config-for-completion is a machine friendlier\n> version of --config where all the placeholders and wildcards are\n> dropped, leaving only the good, completable prefixes for\n> git-completion.bash to consume.\n\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n> diff --git a/builtin/help.c b/builtin/help.c\n> @@ -446,9 +447,13 @@ int cmd_help(int argc, const char **argv, const char\n*prefix)\n> +               int for_human = show_config == 1;\n> +\n> +               if (for_human)\n> +                       setup_pager();\n> +               list_config_help(for_human);\n> +               if (for_human)\n> +                       printf(\"\\n%s\\n\", _(\"'git help config' for more\ninformation\"));\n\nSimpler to read, perhaps:\n\n     if (!for_human)\n         list_config_help(0);\n     else {\n         setup_pager();\n         list_config_help(1);\n         printf(...);\n     }\n"},{"id":"348105","messageId":"20180520160139.11299-1-szeder.dev@gmail.com","threadId":"48456","inReplyTo":"20180510141927.23590-8-pclouds@gmail.com","subject":"Re: [PATCH 7/9] completion: drop the hard coded list of config vars","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2018-05-20T16:01:39Z","receivedAt":"2018-05-20T16:01:50Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"> The new help option --config-for-completion is a machine friendlier\n> version of --config where all the placeholders and wildcards are\n> dropped, leaving only the good, completable prefixes for\n> git-completion.bash to consume.\n> \n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n>  builtin/help.c                         |  13 +-\n>  contrib/completion/git-completion.bash | 334 +------------------------\n>  help.c                                 |  30 ++-\n>  help.h                                 |   2 +-\n>  4 files changed, 47 insertions(+), 332 deletions(-)\n\nOh, this diffstat is fantastic! :)\n\nI'm glad to see that enormous hardcoded list go.\n\n\n"},{"id":"348106","messageId":"20180520163329.12202-1-szeder.dev@gmail.com","threadId":"48456","inReplyTo":"20180510141927.23590-9-pclouds@gmail.com","subject":"Re: [PATCH 8/9] completion: support case-insensitive config vars just a bit","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2018-05-20T16:33:29Z","receivedAt":"2018-05-20T16:33:46Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"> config variable names are technically case-insensitive while this case\n> construct is by default case-sensitive. Moving it to case-insensitive\n> could be a lot more work.\n\nBash v4 supports the case modification expansion in the form of\n${prev,,}.  Alas OSX (or older LTS/Enterprise Linux releases) ships\nBash v3.2, which doesn't yet support this syntax, and there is ZSH,\nwhich doesn't understand it either (though I suspect it has its own\nweird syntax for case modification).  Supporting them could look\nsomething like this:\n\n  local varname\n  \n  if [ \"${BASH_VERSINFO[0]:-0}\" -ge 4 ]; then\n          varname=\"${prev,,}\"\n  else\n          varname=\"$(echo \"$prev\" |tr A-Z a-z)\"\n  fi\n  \n  case \"$varname\" in\n  <....>\n\nNot pretty, but I think the additional complexity and overhead is\nacceptable.  Yeah, on some platforms/shells we would run an extra\ncommand substitution and an external command, but I suppose on those\nplatforms the overhead of the extra processes is not that critical.\nAnd where this additional overhead matters the most is Windows, but\nluckily Git for Windows ships with Bash v4.\n\n\n> Instead let's just accept the form that is\n> more likely to show up in practice.\n> \n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n>  contrib/completion/git-completion.bash | 6 +++---\n>  1 file changed, 3 insertions(+), 3 deletions(-)\n> \n> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\n> index 8d3257c4de..e7829b5b24 100644\n> --- a/contrib/completion/git-completion.bash\n> +++ b/contrib/completion/git-completion.bash\n> @@ -2084,7 +2084,7 @@ __git_compute_config_vars ()\n>  _git_config ()\n>  {\n>  \tcase \"$prev\" in\n> -\tbranch.*.remote|branch.*.pushremote)\n> +\tbranch.*.remote|branch.*.push[Rr]emote)\n>  \t\t__gitcomp_nl \"$(__git_remotes)\"\n>  \t\treturn\n>  \t\t;;\n> @@ -2096,7 +2096,7 @@ _git_config ()\n>  \t\t__gitcomp \"false true preserve interactive\"\n>  \t\treturn\n>  \t\t;;\n> -\tremote.pushdefault)\n> +\tremote.push[Dd]efault)\n>  \t\t__gitcomp_nl \"$(__git_remotes)\"\n>  \t\treturn\n>  \t\t;;\n> @@ -2162,7 +2162,7 @@ _git_config ()\n>  \t\t__gitcomp \"$__git_send_email_suppresscc_options\"\n>  \t\treturn\n>  \t\t;;\n> -\tsendemail.transferencoding)\n> +\tsendemail.transfer[Ee]ncoding)\n>  \t\t__gitcomp \"7bit 8bit quoted-printable base64\"\n>  \t\treturn\n>  \t\t;;\n\n'git help config' shows 'color.showBranch' and\n'sendemail.aliasesfiletype' in camelCase as well.\n\n"},{"id":"348590","messageId":"20180526135531.4516-1-pclouds@gmail.com","threadId":"48456","inReplyTo":"20180510141927.23590-1-pclouds@gmail.com","subject":"[PATCH v2 00/11] completion: avoid hard coding config var list","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-26T13:55:20Z","receivedAt":"2018-05-26T13:55:44Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"v2 changes:\n\n- based on 'next'\n- C99 is now mentioned in the commit message\n- fixed Eric's comments\n- the old 8/9 partial case-insensitive support patch is replaced\n  with Szeder's version.\n  \n  Szeder I claimed authorship because I wrote the commit message which\n  may not be what you like. If you want to claim it instead, I'll be\n  glad to resend.\n\n- There is no levenshtein support yet. But the code is updated to keep\n  this config list in memory instead of printf'ing directly to make it\n  easier in the future to do that.\n\nNguyễn Thái Ngọc Duy (11):\n  Add and use generic name->id mapping code for color slot parsing\n  grep: keep all colors in an array\n  fsck: factor out msg_id_info[] lazy initialization code\n  help: add --config to list all available config\n  fsck: produce camelCase config key names\n  advice: keep config name in camelCase in advice_config[]\n  am: move advice.amWorkDir parsing back to advice.c\n  completion: drop the hard coded list of config vars\n  completion: keep other config var completion in camelCase\n  completion: support case-insensitive config vars\n  log-tree: allow to customize 'grafted' color\n\n Documentation/config.txt               |   3 +-\n Documentation/git-help.txt             |   5 +\n advice.c                               |  53 ++--\n advice.h                               |   1 +\n builtin/am.c                           |   6 +-\n builtin/branch.c                       |  29 +-\n builtin/clean.c                        |  29 +-\n builtin/commit.c                       |  36 +--\n builtin/help.c                         |  16 ++\n config.c                               |  13 +\n config.h                               |   4 +\n contrib/completion/git-completion.bash | 357 ++-----------------------\n diff.c                                 |  56 ++--\n fsck.c                                 |  68 +++--\n generate-cmdlist.sh                    |  19 ++\n grep.c                                 | 109 ++++----\n grep.h                                 |  21 +-\n help.c                                 |  84 ++++++\n help.h                                 |  45 +++-\n log-tree.c                             |  37 +--\n t/t4254-am-corrupt.sh                  |   2 +-\n 21 files changed, 440 insertions(+), 553 deletions(-)\n\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"348591","messageId":"20180526135531.4516-2-pclouds@gmail.com","threadId":"48456","inReplyTo":"20180526135531.4516-1-pclouds@gmail.com","subject":"[PATCH v2 01/11] Add and use generic name->id mapping code for color slot parsing","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-26T13:55:21Z","receivedAt":"2018-05-26T13:55:44Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Instead of hard coding the name-to-id mapping in C code, keep it in an\narray and use a common function to do the parsing. This reduces code\nand also allows us to list all possible color slots later.\n\nThis starts using C99 designated initializers more for convenience\n(the first designated initializers have been introduced in builtin/clean.c\nfor some time without complaints)\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/branch.c | 28 +++++++++----------------\n builtin/clean.c  | 28 +++++++++----------------\n builtin/commit.c | 33 ++++++++++++++----------------\n config.c         | 13 ++++++++++++\n config.h         |  4 ++++\n diff.c           | 53 +++++++++++++++++++-----------------------------\n log-tree.c       | 35 ++++++++------------------------\n 7 files changed, 82 insertions(+), 112 deletions(-)\n\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex f85d3de531..09232576b6 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -55,26 +55,18 @@ enum color_branch {\n \tBRANCH_COLOR_UPSTREAM = 5\n };\n \n+static const char *color_branch_slots[] = {\n+\t[BRANCH_COLOR_RESET]\t= \"reset\",\n+\t[BRANCH_COLOR_PLAIN]\t= \"plain\",\n+\t[BRANCH_COLOR_REMOTE]\t= \"remote\",\n+\t[BRANCH_COLOR_LOCAL]\t= \"local\",\n+\t[BRANCH_COLOR_CURRENT]\t= \"current\",\n+\t[BRANCH_COLOR_UPSTREAM] = \"upstream\",\n+};\n+\n static struct string_list output = STRING_LIST_INIT_DUP;\n static unsigned int colopts;\n \n-static int parse_branch_color_slot(const char *slot)\n-{\n-\tif (!strcasecmp(slot, \"plain\"))\n-\t\treturn BRANCH_COLOR_PLAIN;\n-\tif (!strcasecmp(slot, \"reset\"))\n-\t\treturn BRANCH_COLOR_RESET;\n-\tif (!strcasecmp(slot, \"remote\"))\n-\t\treturn BRANCH_COLOR_REMOTE;\n-\tif (!strcasecmp(slot, \"local\"))\n-\t\treturn BRANCH_COLOR_LOCAL;\n-\tif (!strcasecmp(slot, \"current\"))\n-\t\treturn BRANCH_COLOR_CURRENT;\n-\tif (!strcasecmp(slot, \"upstream\"))\n-\t\treturn BRANCH_COLOR_UPSTREAM;\n-\treturn -1;\n-}\n-\n static int git_branch_config(const char *var, const char *value, void *cb)\n {\n \tconst char *slot_name;\n@@ -86,7 +78,7 @@ static int git_branch_config(const char *var, const char *value, void *cb)\n \t\treturn 0;\n \t}\n \tif (skip_prefix(var, \"color.branch.\", &slot_name)) {\n-\t\tint slot = parse_branch_color_slot(slot_name);\n+\t\tint slot = LOOKUP_CONFIG(color_branch_slots, slot_name);\n \t\tif (slot < 0)\n \t\t\treturn 0;\n \t\tif (!value)\ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex fad533a0a7..0ccd95e693 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -42,6 +42,15 @@ enum color_clean {\n \tCLEAN_COLOR_ERROR = 5\n };\n \n+static const char *color_interactive_slots[] = {\n+\t[CLEAN_COLOR_ERROR]  = \"error\",\n+\t[CLEAN_COLOR_HEADER] = \"header\",\n+\t[CLEAN_COLOR_HELP]   = \"help\",\n+\t[CLEAN_COLOR_PLAIN]  = \"plain\",\n+\t[CLEAN_COLOR_PROMPT] = \"prompt\",\n+\t[CLEAN_COLOR_RESET]  = \"reset\",\n+};\n+\n static int clean_use_color = -1;\n static char clean_colors[][COLOR_MAXLEN] = {\n \t[CLEAN_COLOR_ERROR] = GIT_COLOR_BOLD_RED,\n@@ -82,23 +91,6 @@ struct menu_stuff {\n \tvoid *stuff;\n };\n \n-static int parse_clean_color_slot(const char *var)\n-{\n-\tif (!strcasecmp(var, \"reset\"))\n-\t\treturn CLEAN_COLOR_RESET;\n-\tif (!strcasecmp(var, \"plain\"))\n-\t\treturn CLEAN_COLOR_PLAIN;\n-\tif (!strcasecmp(var, \"prompt\"))\n-\t\treturn CLEAN_COLOR_PROMPT;\n-\tif (!strcasecmp(var, \"header\"))\n-\t\treturn CLEAN_COLOR_HEADER;\n-\tif (!strcasecmp(var, \"help\"))\n-\t\treturn CLEAN_COLOR_HELP;\n-\tif (!strcasecmp(var, \"error\"))\n-\t\treturn CLEAN_COLOR_ERROR;\n-\treturn -1;\n-}\n-\n static int git_clean_config(const char *var, const char *value, void *cb)\n {\n \tconst char *slot_name;\n@@ -113,7 +105,7 @@ static int git_clean_config(const char *var, const char *value, void *cb)\n \t\treturn 0;\n \t}\n \tif (skip_prefix(var, \"color.interactive.\", &slot_name)) {\n-\t\tint slot = parse_clean_color_slot(slot_name);\n+\t\tint slot = LOOKUP_CONFIG(color_interactive_slots, slot_name);\n \t\tif (slot < 0)\n \t\t\treturn 0;\n \t\tif (!value)\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex a842fea666..2b43a6c48a 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -66,6 +66,18 @@ N_(\"If you wish to skip this commit, use:\\n\"\n \"Then \\\"git cherry-pick --continue\\\" will resume cherry-picking\\n\"\n \"the remaining commits.\\n\");\n \n+static const char *color_status_slots[] = {\n+\t[WT_STATUS_HEADER]\t  = \"header\",\n+\t[WT_STATUS_UPDATED]\t  = \"updated\",\n+\t[WT_STATUS_CHANGED]\t  = \"changed\",\n+\t[WT_STATUS_UNTRACKED]\t  = \"untracked\",\n+\t[WT_STATUS_NOBRANCH]\t  = \"noBranch\",\n+\t[WT_STATUS_UNMERGED]\t  = \"unmerged\",\n+\t[WT_STATUS_LOCAL_BRANCH]  = \"localBranch\",\n+\t[WT_STATUS_REMOTE_BRANCH] = \"remoteBranch\",\n+\t[WT_STATUS_ONBRANCH]\t  = \"branch\",\n+};\n+\n static const char *use_message_buffer;\n static struct lock_file index_lock; /* real index */\n static struct lock_file false_lock; /* used only for partial commits */\n@@ -1185,25 +1197,10 @@ static int dry_run_commit(int argc, const char **argv, const char *prefix,\n \n static int parse_status_slot(const char *slot)\n {\n-\tif (!strcasecmp(slot, \"header\"))\n-\t\treturn WT_STATUS_HEADER;\n-\tif (!strcasecmp(slot, \"branch\"))\n-\t\treturn WT_STATUS_ONBRANCH;\n-\tif (!strcasecmp(slot, \"updated\") || !strcasecmp(slot, \"added\"))\n+\tif (!strcasecmp(slot, \"added\"))\n \t\treturn WT_STATUS_UPDATED;\n-\tif (!strcasecmp(slot, \"changed\"))\n-\t\treturn WT_STATUS_CHANGED;\n-\tif (!strcasecmp(slot, \"untracked\"))\n-\t\treturn WT_STATUS_UNTRACKED;\n-\tif (!strcasecmp(slot, \"nobranch\"))\n-\t\treturn WT_STATUS_NOBRANCH;\n-\tif (!strcasecmp(slot, \"unmerged\"))\n-\t\treturn WT_STATUS_UNMERGED;\n-\tif (!strcasecmp(slot, \"localBranch\"))\n-\t\treturn WT_STATUS_LOCAL_BRANCH;\n-\tif (!strcasecmp(slot, \"remoteBranch\"))\n-\t\treturn WT_STATUS_REMOTE_BRANCH;\n-\treturn -1;\n+\n+\treturn LOOKUP_CONFIG(color_status_slots, slot);\n }\n \n static int git_status_config(const char *k, const char *v, void *cb)\ndiff --git a/config.c b/config.c\nindex fbbf0f8e9f..a0a6ae1980 100644\n--- a/config.c\n+++ b/config.c\n@@ -3245,3 +3245,16 @@ enum config_scope current_config_scope(void)\n \telse\n \t\treturn current_parsing_scope;\n }\n+\n+int lookup_config(const char **mapping, int nr_mapping, const char *var)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < nr_mapping; i++) {\n+\t\tconst char *name = mapping[i];\n+\n+\t\tif (name && !strcasecmp(var, name))\n+\t\t\treturn i;\n+\t}\n+\treturn -1;\n+}\ndiff --git a/config.h b/config.h\nindex cdac2fc73e..626d4654bd 100644\n--- a/config.h\n+++ b/config.h\n@@ -257,4 +257,8 @@ struct key_value_info {\n extern NORETURN void git_die_config(const char *key, const char *err, ...) __attribute__((format(printf, 2, 3)));\n extern NORETURN void git_die_config_linenr(const char *key, const char *filename, int linenr);\n \n+#define LOOKUP_CONFIG(mapping, var) \\\n+\tlookup_config(mapping, ARRAY_SIZE(mapping), var)\n+int lookup_config(const char **mapping, int nr_mapping, const char *var);\n+\n #endif /* CONFIG_H */\ndiff --git a/diff.c b/diff.c\nindex efa6c1b82f..2e5e1404a5 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -69,6 +69,25 @@ static char diff_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_FAINT_ITALIC,\t/* NEW_MOVED_ALTERNATIVE_DIM */\n };\n \n+static const char *color_diff_slots[] = {\n+\t[DIFF_CONTEXT]\t\t      = \"context\",\n+\t[DIFF_METAINFO]\t\t      = \"meta\",\n+\t[DIFF_FRAGINFO]\t\t      = \"frag\",\n+\t[DIFF_FILE_OLD]\t\t      = \"old\",\n+\t[DIFF_FILE_NEW]\t\t      = \"new\",\n+\t[DIFF_COMMIT]\t\t      = \"commit\",\n+\t[DIFF_WHITESPACE]\t      = \"whitespace\",\n+\t[DIFF_FUNCINFO]\t\t      = \"func\",\n+\t[DIFF_FILE_OLD_MOVED]\t      = \"oldMoved\",\n+\t[DIFF_FILE_OLD_MOVED_ALT]     = \"oldMovedAlternative\",\n+\t[DIFF_FILE_OLD_MOVED_DIM]     = \"oldMovedDimmed\",\n+\t[DIFF_FILE_OLD_MOVED_ALT_DIM] = \"oldMovedAlternativeDimmed\",\n+\t[DIFF_FILE_NEW_MOVED]\t      = \"newMoved\",\n+\t[DIFF_FILE_NEW_MOVED_ALT]     = \"newMovedAlternative\",\n+\t[DIFF_FILE_NEW_MOVED_DIM]     = \"newMovedDimmed\",\n+\t[DIFF_FILE_NEW_MOVED_ALT_DIM] = \"newMovedAlternativeDimmed\",\n+};\n+\n static NORETURN void die_want_option(const char *option_name)\n {\n \tdie(_(\"option '%s' requires a value\"), option_name);\n@@ -76,39 +95,9 @@ static NORETURN void die_want_option(const char *option_name)\n \n static int parse_diff_color_slot(const char *var)\n {\n-\tif (!strcasecmp(var, \"context\") || !strcasecmp(var, \"plain\"))\n+\tif (!strcasecmp(var, \"plain\"))\n \t\treturn DIFF_CONTEXT;\n-\tif (!strcasecmp(var, \"meta\"))\n-\t\treturn DIFF_METAINFO;\n-\tif (!strcasecmp(var, \"frag\"))\n-\t\treturn DIFF_FRAGINFO;\n-\tif (!strcasecmp(var, \"old\"))\n-\t\treturn DIFF_FILE_OLD;\n-\tif (!strcasecmp(var, \"new\"))\n-\t\treturn DIFF_FILE_NEW;\n-\tif (!strcasecmp(var, \"commit\"))\n-\t\treturn DIFF_COMMIT;\n-\tif (!strcasecmp(var, \"whitespace\"))\n-\t\treturn DIFF_WHITESPACE;\n-\tif (!strcasecmp(var, \"func\"))\n-\t\treturn DIFF_FUNCINFO;\n-\tif (!strcasecmp(var, \"oldmoved\"))\n-\t\treturn DIFF_FILE_OLD_MOVED;\n-\tif (!strcasecmp(var, \"oldmovedalternative\"))\n-\t\treturn DIFF_FILE_OLD_MOVED_ALT;\n-\tif (!strcasecmp(var, \"oldmoveddimmed\"))\n-\t\treturn DIFF_FILE_OLD_MOVED_DIM;\n-\tif (!strcasecmp(var, \"oldmovedalternativedimmed\"))\n-\t\treturn DIFF_FILE_OLD_MOVED_ALT_DIM;\n-\tif (!strcasecmp(var, \"newmoved\"))\n-\t\treturn DIFF_FILE_NEW_MOVED;\n-\tif (!strcasecmp(var, \"newmovedalternative\"))\n-\t\treturn DIFF_FILE_NEW_MOVED_ALT;\n-\tif (!strcasecmp(var, \"newmoveddimmed\"))\n-\t\treturn DIFF_FILE_NEW_MOVED_DIM;\n-\tif (!strcasecmp(var, \"newmovedalternativedimmed\"))\n-\t\treturn DIFF_FILE_NEW_MOVED_ALT_DIM;\n-\treturn -1;\n+\treturn LOOKUP_CONFIG(color_diff_slots, var);\n }\n \n static int parse_dirstat_params(struct diff_options *options, const char *params_string,\ndiff --git a/log-tree.c b/log-tree.c\nindex 0b97de5e87..33be7f7a3d 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -27,6 +27,14 @@ static char decoration_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_BOLD_BLUE,\t/* GRAFTED */\n };\n \n+static const char *color_decorate_slots[] = {\n+\t[DECORATION_REF_LOCAL]\t= \"branch\",\n+\t[DECORATION_REF_REMOTE] = \"remoteBranch\",\n+\t[DECORATION_REF_TAG]\t= \"tag\",\n+\t[DECORATION_REF_STASH]\t= \"stash\",\n+\t[DECORATION_REF_HEAD]\t= \"HEAD\",\n+};\n+\n static const char *decorate_get_color(int decorate_use_color, enum decoration_type ix)\n {\n \tif (want_color(decorate_use_color))\n@@ -34,34 +42,9 @@ static const char *decorate_get_color(int decorate_use_color, enum decoration_ty\n \treturn \"\";\n }\n \n-static int parse_decorate_color_slot(const char *slot)\n-{\n-\t/*\n-\t * We're comparing with 'ignore-case' on\n-\t * (because config.c sets them all tolower),\n-\t * but let's match the letters in the literal\n-\t * string values here with how they are\n-\t * documented in Documentation/config.txt, for\n-\t * consistency.\n-\t *\n-\t * We love being consistent, don't we?\n-\t */\n-\tif (!strcasecmp(slot, \"branch\"))\n-\t\treturn DECORATION_REF_LOCAL;\n-\tif (!strcasecmp(slot, \"remoteBranch\"))\n-\t\treturn DECORATION_REF_REMOTE;\n-\tif (!strcasecmp(slot, \"tag\"))\n-\t\treturn DECORATION_REF_TAG;\n-\tif (!strcasecmp(slot, \"stash\"))\n-\t\treturn DECORATION_REF_STASH;\n-\tif (!strcasecmp(slot, \"HEAD\"))\n-\t\treturn DECORATION_REF_HEAD;\n-\treturn -1;\n-}\n-\n int parse_decorate_color_config(const char *var, const char *slot_name, const char *value)\n {\n-\tint slot = parse_decorate_color_slot(slot_name);\n+\tint slot = LOOKUP_CONFIG(color_decorate_slots, slot_name);\n \tif (slot < 0)\n \t\treturn 0;\n \tif (!value)\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"348592","messageId":"20180526135531.4516-5-pclouds@gmail.com","threadId":"48456","inReplyTo":"20180526135531.4516-1-pclouds@gmail.com","subject":"[PATCH v2 04/11] help: add --config to list all available config","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-26T13:55:24Z","receivedAt":"2018-05-26T13:55:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Sometimes it helps to list all available config vars so the user can\nsearch for something they want. The config man page can also be used\nbut it's harder to search if you want to focus on the variable name,\nfor example.\n\nThis is not the best way to collect the available config since it's\nnot precise. Ideally we should have a centralized list of config in C\ncode (pretty much like 'struct option'), but that's a lot more work.\nThis will do for now.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/git-help.txt |  5 ++++\n advice.c                   |  9 ++++++\n builtin/branch.c           |  3 ++\n builtin/clean.c            |  3 ++\n builtin/commit.c           |  3 ++\n builtin/help.c             |  9 ++++++\n diff.c                     |  3 ++\n fsck.c                     | 12 ++++++++\n generate-cmdlist.sh        | 19 +++++++++++++\n grep.c                     |  3 ++\n help.c                     | 56 ++++++++++++++++++++++++++++++++++++++\n help.h                     | 45 +++++++++++++++++++++++++++++-\n log-tree.c                 |  3 ++\n 13 files changed, 172 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-help.txt b/Documentation/git-help.txt\nindex a40fc38d8b..83d25d825a 100644\n--- a/Documentation/git-help.txt\n+++ b/Documentation/git-help.txt\n@@ -45,6 +45,11 @@ OPTIONS\n \tWhen used with `--verbose` print description for all recognized\n \tcommands.\n \n+-c::\n+--config::\n+\tList all available configuration variables. This is a short\n+\tsummary of the list in linkgit:git-config[1].\n+\n -g::\n --guides::\n \tPrints a list of useful guides on the standard output. This\ndiff --git a/advice.c b/advice.c\nindex 370a56d054..cf6c673ed7 100644\n--- a/advice.c\n+++ b/advice.c\n@@ -1,6 +1,7 @@\n #include \"cache.h\"\n #include \"config.h\"\n #include \"color.h\"\n+#include \"help.h\"\n \n int advice_push_update_rejected = 1;\n int advice_push_non_ff_current = 1;\n@@ -131,6 +132,14 @@ int git_default_advice_config(const char *var, const char *value)\n \treturn 0;\n }\n \n+void list_config_advices(struct string_list *list, const char *prefix)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < ARRAY_SIZE(advice_config); i++)\n+\t\tlist_config_item(list, prefix, advice_config[i].name);\n+}\n+\n int error_resolve_conflict(const char *me)\n {\n \tif (!strcmp(me, \"cherry-pick\"))\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 09232576b6..ddc48ca931 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -22,6 +22,7 @@\n #include \"wt-status.h\"\n #include \"ref-filter.h\"\n #include \"worktree.h\"\n+#include \"help.h\"\n \n static const char * const builtin_branch_usage[] = {\n \tN_(\"git branch [<options>] [-r | -a] [--merged | --no-merged]\"),\n@@ -67,6 +68,8 @@ static const char *color_branch_slots[] = {\n static struct string_list output = STRING_LIST_INIT_DUP;\n static unsigned int colopts;\n \n+define_list_config_array(color_branch_slots);\n+\n static int git_branch_config(const char *var, const char *value, void *cb)\n {\n \tconst char *slot_name;\ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex 0ccd95e693..ab402c204c 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -16,6 +16,7 @@\n #include \"column.h\"\n #include \"color.h\"\n #include \"pathspec.h\"\n+#include \"help.h\"\n \n static int force = -1; /* unset */\n static int interactive;\n@@ -91,6 +92,8 @@ struct menu_stuff {\n \tvoid *stuff;\n };\n \n+define_list_config_array(color_interactive_slots);\n+\n static int git_clean_config(const char *var, const char *value, void *cb)\n {\n \tconst char *slot_name;\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 2b43a6c48a..9bcbb0c25c 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -32,6 +32,7 @@\n #include \"column.h\"\n #include \"sequencer.h\"\n #include \"mailmap.h\"\n+#include \"help.h\"\n \n static const char * const builtin_commit_usage[] = {\n \tN_(\"git commit [<options>] [--] <pathspec>...\"),\n@@ -1195,6 +1196,8 @@ static int dry_run_commit(int argc, const char **argv, const char *prefix,\n \treturn commitable ? 0 : 1;\n }\n \n+define_list_config_array_extra(color_status_slots, {\"added\"});\n+\n static int parse_status_slot(const char *slot)\n {\n \tif (!strcasecmp(slot, \"added\"))\ndiff --git a/builtin/help.c b/builtin/help.c\nindex 58e0a5507f..ccb206e1d4 100644\n--- a/builtin/help.c\n+++ b/builtin/help.c\n@@ -37,6 +37,7 @@ static const char *html_path;\n \n static int show_all = 0;\n static int show_guides = 0;\n+static int show_config;\n static int verbose;\n static unsigned int colopts;\n static enum help_format help_format = HELP_FORMAT_NONE;\n@@ -45,6 +46,7 @@ static struct option builtin_help_options[] = {\n \tOPT_BOOL('a', \"all\", &show_all, N_(\"print all available commands\")),\n \tOPT_HIDDEN_BOOL(0, \"exclude-guides\", &exclude_guides, N_(\"exclude guides\")),\n \tOPT_BOOL('g', \"guides\", &show_guides, N_(\"print list of useful guides\")),\n+\tOPT_BOOL('c', \"config\", &show_config, N_(\"print all configuration variable names\")),\n \tOPT_SET_INT('m', \"man\", &help_format, N_(\"show man page\"), HELP_FORMAT_MAN),\n \tOPT_SET_INT('w', \"web\", &help_format, N_(\"show manual in web browser\"),\n \t\t\tHELP_FORMAT_WEB),\n@@ -444,6 +446,13 @@ int cmd_help(int argc, const char **argv, const char *prefix)\n \t\tlist_commands(colopts, &main_cmds, &other_cmds);\n \t}\n \n+\tif (show_config) {\n+\t\tsetup_pager();\n+\t\tlist_config_help();\n+\t\tprintf(\"\\n%s\\n\", _(\"'git help config' for more information\"));\n+\t\treturn 0;\n+\t}\n+\n \tif (show_guides)\n \t\tlist_common_guides_help();\n \ndiff --git a/diff.c b/diff.c\nindex 2e5e1404a5..c79f18869a 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -22,6 +22,7 @@\n #include \"argv-array.h\"\n #include \"graph.h\"\n #include \"packfile.h\"\n+#include \"help.h\"\n \n #ifdef NO_FAST_WORKING_DIRECTORY\n #define FAST_WORKING_DIRECTORY 0\n@@ -93,6 +94,8 @@ static NORETURN void die_want_option(const char *option_name)\n \tdie(_(\"option '%s' requires a value\"), option_name);\n }\n \n+define_list_config_array_extra(color_diff_slots, {\"plain\"});\n+\n static int parse_diff_color_slot(const char *var)\n {\n \tif (!strcasecmp(var, \"plain\"))\ndiff --git a/fsck.c b/fsck.c\nindex e2a6f33891..b65ff2d856 100644\n--- a/fsck.c\n+++ b/fsck.c\n@@ -10,6 +10,7 @@\n #include \"utf8.h\"\n #include \"sha1-array.h\"\n #include \"decorate.h\"\n+#include \"help.h\"\n \n #define FSCK_FATAL -1\n #define FSCK_INFO -2\n@@ -120,6 +121,17 @@ static int parse_msg_id(const char *text)\n \treturn -1;\n }\n \n+void list_config_fsck_msg_ids(struct string_list *list, const char *prefix)\n+{\n+\tint i;\n+\n+\tprepare_msg_ids();\n+\n+\t/* TODO: we can do better by producing camelCase names */\n+\tfor (i = 0; i < FSCK_MSG_MAX; i++)\n+\t\tlist_config_item(list, prefix, msg_id_info[i].downcased);\n+}\n+\n static int fsck_msg_type(enum fsck_msg_id msg_id,\n \tstruct fsck_options *options)\n {\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex 8d6d8b45ce..c4124acbe7 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -76,6 +76,23 @@ print_command_list () {\n \techo \"};\"\n }\n \n+print_config_list () {\n+\tcat <<EOF\n+static const char *config_name_list[] = {\n+EOF\n+\tgrep '^[a-zA-Z].*\\..*::$' Documentation/config.txt |\n+\tsed '/deprecated/d; s/::$//; s/,  */\\n/g' |\n+\tsort |\n+\twhile read line\n+\tdo\n+\t\techo \"\t\\\"$line\\\",\"\n+\tdone\n+\tcat <<EOF\n+\tNULL,\n+};\n+EOF\n+}\n+\n echo \"/* Automatically generated by generate-cmdlist.sh */\n struct cmdname_help {\n \tconst char *name;\n@@ -88,3 +105,5 @@ echo\n define_category_names \"$1\"\n echo\n print_command_list \"$1\"\n+echo\n+print_config_list\ndiff --git a/grep.c b/grep.c\nindex d94e2c4aeb..7c1b8e2e8b 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -7,6 +7,7 @@\n #include \"diffcore.h\"\n #include \"commit.h\"\n #include \"quote.h\"\n+#include \"help.h\"\n \n static int grep_source_load(struct grep_source *gs);\n static int grep_source_is_binary(struct grep_source *gs);\n@@ -80,6 +81,8 @@ static int parse_pattern_type_arg(const char *opt, const char *arg)\n \tdie(\"bad %s argument: %s\", opt, arg);\n }\n \n+define_list_config_array_extra(color_grep_slots, {\"match\"});\n+\n /*\n  * Read the configuration file once and store it in\n  * the grep_defaults template.\ndiff --git a/help.c b/help.c\nindex dd35fcc133..f078dfebad 100644\n--- a/help.c\n+++ b/help.c\n@@ -409,6 +409,62 @@ void list_common_guides_help(void)\n \tputchar('\\n');\n }\n \n+struct slot_expansion {\n+\tconst char *prefix;\n+\tconst char *placeholder;\n+\tvoid (*fn)(struct string_list *list, const char *prefix);\n+\tint found;\n+};\n+\n+void list_config_help(void)\n+{\n+\tstruct slot_expansion slot_expansions[] = {\n+\t\t{ \"advice\", \"*\", list_config_advices },\n+\t\t{ \"color.branch\", \"<slot>\", list_config_color_branch_slots },\n+\t\t{ \"color.decorate\", \"<slot>\", list_config_color_decorate_slots },\n+\t\t{ \"color.diff\", \"<slot>\", list_config_color_diff_slots },\n+\t\t{ \"color.grep\", \"<slot>\", list_config_color_grep_slots },\n+\t\t{ \"color.interactive\", \"<slot>\", list_config_color_interactive_slots },\n+\t\t{ \"color.status\", \"<slot>\", list_config_color_status_slots },\n+\t\t{ \"fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n+\t\t{ \"receive.fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n+\t\t{ NULL, NULL, NULL }\n+\t};\n+\tconst char **p;\n+\tstruct slot_expansion *e;\n+\tstruct string_list keys = STRING_LIST_INIT_DUP;\n+\tint i;\n+\n+\tfor (p = config_name_list; *p; p++) {\n+\t\tconst char *var = *p;\n+\t\tstruct strbuf sb = STRBUF_INIT;\n+\n+\t\tfor (e = slot_expansions; e->prefix; e++) {\n+\n+\t\t\tstrbuf_reset(&sb);\n+\t\t\tstrbuf_addf(&sb, \"%s.%s\", e->prefix, e->placeholder);\n+\t\t\tif (!strcasecmp(var, sb.buf)) {\n+\t\t\t\te->fn(&keys, e->prefix);\n+\t\t\t\te->found++;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t\tstrbuf_release(&sb);\n+\t\tif (!e->prefix)\n+\t\t\tstring_list_append(&keys, var);\n+\t}\n+\n+\tfor (e = slot_expansions; e->prefix; e++)\n+\t\tif (!e->found)\n+\t\t\tBUG(\"slot_expansion %s.%s is not used\",\n+\t\t\t    e->prefix, e->placeholder);\n+\n+\tstring_list_sort(&keys);\n+\tfor (i = 0; i < keys.nr; i++)\n+\t\tputs(keys.items[i].string);\n+\tstring_list_clear(&keys, 0);\n+}\n+\n void list_all_cmds_help(void)\n {\n \tprint_cmd_by_category(main_categories);\ndiff --git a/help.h b/help.h\nindex 3b38292a1b..b46fe6ee73 100644\n--- a/help.h\n+++ b/help.h\n@@ -1,7 +1,8 @@\n #ifndef HELP_H\n #define HELP_H\n \n-struct string_list;\n+#include \"string-list.h\"\n+#include \"strbuf.h\"\n \n struct cmdnames {\n \tint alloc;\n@@ -21,6 +22,7 @@ static inline void mput_char(char c, unsigned int num)\n extern void list_common_cmds_help(void);\n extern void list_all_cmds_help(void);\n extern void list_common_guides_help(void);\n+extern void list_config_help(void);\n \n extern void list_all_main_cmds(struct string_list *list);\n extern void list_all_other_cmds(struct string_list *list);\n@@ -42,4 +44,45 @@ extern void list_commands(unsigned int colopts, struct cmdnames *main_cmds, stru\n  * ref to the command, to give suggested \"correct\" refs.\n  */\n extern void help_unknown_ref(const char *ref, const char *cmd, const char *error);\n+\n+static inline void list_config_item(struct string_list *list,\n+\t\t\t\t    const char *prefix,\n+\t\t\t\t    const char *str)\n+{\n+\tstring_list_append_nodup(list, xstrfmt(\"%s.%s\", prefix, str));\n+}\n+\n+#define define_list_config_array(array)\t\t\t\t\t\\\n+void list_config_##array(struct string_list *list, const char *prefix)\t\\\n+{\t\t\t\t\t\t\t\t\t\\\n+\tint i;\t\t\t\t\t\t\t\t\\\n+\tfor (i = 0; i < ARRAY_SIZE(array); i++)\t\t\t\t\\\n+\t\tif (array[i])\t\t\t\t\t\t\\\n+\t\t\tlist_config_item(list, prefix, array[i]);\t\\\n+}\t\t\t\t\t\t\t\t\t\\\n+struct string_list\n+\n+#define define_list_config_array_extra(array, values)\t\t\t\\\n+void list_config_##array(struct string_list *list, const char *prefix)\t\\\n+{\t\t\t\t\t\t\t\t\t\\\n+\tint i;\t\t\t\t\t\t\t\t\\\n+\tstatic const char *extra[] = values;\t\t\t\t\\\n+\tfor (i = 0; i < ARRAY_SIZE(extra); i++)\t\t\t\t\\\n+\t\tlist_config_item(list, prefix, extra[i]);\t\t\\\n+\tfor (i = 0; i < ARRAY_SIZE(array); i++)\t\t\t\t\\\n+\t\tif (array[i])\t\t\t\t\t\t\\\n+\t\t\tlist_config_item(list, prefix, array[i]);\t\\\n+}\t\t\t\t\t\t\t\t\t\\\n+struct string_list\n+\n+/* These are actually scattered over many C files */\n+void list_config_advices(struct string_list *list, const char *prefix);\n+void list_config_color_branch_slots(struct string_list *list, const char *prefix);\n+void list_config_color_decorate_slots(struct string_list *list, const char *prefix);\n+void list_config_color_diff_slots(struct string_list *list, const char *prefix);\n+void list_config_color_grep_slots(struct string_list *list, const char *prefix);\n+void list_config_color_interactive_slots(struct string_list *list, const char *prefix);\n+void list_config_color_status_slots(struct string_list *list, const char *prefix);\n+void list_config_fsck_msg_ids(struct string_list *list, const char *prefix);\n+\n #endif /* HELP_H */\ndiff --git a/log-tree.c b/log-tree.c\nindex 33be7f7a3d..284ce0e3c5 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -12,6 +12,7 @@\n #include \"gpg-interface.h\"\n #include \"sequencer.h\"\n #include \"line-log.h\"\n+#include \"help.h\"\n \n static struct decoration name_decoration = { \"object names\" };\n static int decoration_loaded;\n@@ -42,6 +43,8 @@ static const char *decorate_get_color(int decorate_use_color, enum decoration_ty\n \treturn \"\";\n }\n \n+define_list_config_array(color_decorate_slots);\n+\n int parse_decorate_color_config(const char *var, const char *slot_name, const char *value)\n {\n \tint slot = LOOKUP_CONFIG(color_decorate_slots, slot_name);\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"348593","messageId":"20180526135531.4516-10-pclouds@gmail.com","threadId":"48456","inReplyTo":"20180526135531.4516-1-pclouds@gmail.com","subject":"[PATCH v2 09/11] completion: keep other config var completion in camelCase","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-26T13:55:29Z","receivedAt":"2018-05-26T13:55:55Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The last patch makes \"git config <tab>\" shows camelCase names because\nthat's what's in the source: config.txt. There are still a couple\nmanual var completion in this code. Let's make them follow the naming\nconvention as well.\n\nIn theory we could automate this part too because we have the\ninformation. But let's stick to one step at a time and leave this for\nlater.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n contrib/completion/git-completion.bash | 12 ++++++------\n 1 file changed, 6 insertions(+), 6 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 1b0c30ed9a..efc930c9d1 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -2249,20 +2249,20 @@ _git_config ()\n \t\t;;\n \tbranch.*.*)\n \t\tlocal pfx=\"${cur%.*}.\" cur_=\"${cur##*.}\"\n-\t\t__gitcomp \"remote pushremote merge mergeoptions rebase\" \"$pfx\" \"$cur_\"\n+\t\t__gitcomp \"remote pushRemote merge mergeOptions rebase\" \"$pfx\" \"$cur_\"\n \t\treturn\n \t\t;;\n \tbranch.*)\n \t\tlocal pfx=\"${cur%.*}.\" cur_=\"${cur#*.}\"\n \t\t__gitcomp_direct \"$(__git_heads \"$pfx\" \"$cur_\" \".\")\"\n-\t\t__gitcomp_nl_append $'autosetupmerge\\nautosetuprebase\\n' \"$pfx\" \"$cur_\"\n+\t\t__gitcomp_nl_append $'autoSetupMerge\\nautoSetupRebase\\n' \"$pfx\" \"$cur_\"\n \t\treturn\n \t\t;;\n \tguitool.*.*)\n \t\tlocal pfx=\"${cur%.*}.\" cur_=\"${cur##*.}\"\n \t\t__gitcomp \"\n-\t\t\targprompt cmd confirm needsfile noconsole norescan\n-\t\t\tprompt revprompt revunmerged title\n+\t\t\targPrompt cmd confirm needsFile noConsole noRescan\n+\t\t\tprompt revPrompt revUnmerged title\n \t\t\t\" \"$pfx\" \"$cur_\"\n \t\treturn\n \t\t;;\n@@ -2291,14 +2291,14 @@ _git_config ()\n \t\tlocal pfx=\"${cur%.*}.\" cur_=\"${cur##*.}\"\n \t\t__gitcomp \"\n \t\t\turl proxy fetch push mirror skipDefaultUpdate\n-\t\t\treceivepack uploadpack tagopt pushurl\n+\t\t\treceivepack uploadpack tagOpt pushurl\n \t\t\t\" \"$pfx\" \"$cur_\"\n \t\treturn\n \t\t;;\n \tremote.*)\n \t\tlocal pfx=\"${cur%.*}.\" cur_=\"${cur#*.}\"\n \t\t__gitcomp_nl \"$(__git_remotes)\" \"$pfx\" \"$cur_\" \".\"\n-\t\t__gitcomp_nl_append \"pushdefault\" \"$pfx\" \"$cur_\"\n+\t\t__gitcomp_nl_append \"pushDefault\" \"$pfx\" \"$cur_\"\n \t\treturn\n \t\t;;\n \turl.*.*)\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"348594","messageId":"20180526135531.4516-8-pclouds@gmail.com","threadId":"48456","inReplyTo":"20180526135531.4516-1-pclouds@gmail.com","subject":"[PATCH v2 07/11] am: move advice.amWorkDir parsing back to advice.c","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-26T13:55:27Z","receivedAt":"2018-05-26T13:55:57Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The only benefit from this move (apart from cleaner code) is that\nadvice.amWorkDir should now show up in `git help --config`. There\nshould be no regression since advice config is always read by the\ngit_default_config().\n\nWhile at there, use advise() like other code. We now get \"hint: \"\nprefix and the output is stderr instead of stdout (which is also the\nreason for the test update because stderr is checked in a following\ntest and the extra advice can fail it).\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n advice.c              | 2 ++\n advice.h              | 1 +\n builtin/am.c          | 6 +-----\n t/t4254-am-corrupt.sh | 2 +-\n 4 files changed, 5 insertions(+), 6 deletions(-)\n\ndiff --git a/advice.c b/advice.c\nindex 2aca11f45e..52aa85bdfd 100644\n--- a/advice.c\n+++ b/advice.c\n@@ -17,6 +17,7 @@ int advice_implicit_identity = 1;\n int advice_detached_head = 1;\n int advice_set_upstream_failure = 1;\n int advice_object_name_warning = 1;\n+int advice_amworkdir = 1;\n int advice_rm_hints = 1;\n int advice_add_embedded_repo = 1;\n int advice_ignored_hook = 1;\n@@ -68,6 +69,7 @@ static struct {\n \t{ \"detachedHead\", &advice_detached_head },\n \t{ \"setupStreamFailure\", &advice_set_upstream_failure },\n \t{ \"objectNameWarning\", &advice_object_name_warning },\n+\t{ \"amWorkDir\", &advice_amworkdir },\n \t{ \"rmHints\", &advice_rm_hints },\n \t{ \"addEmbeddedRepo\", &advice_add_embedded_repo },\n \t{ \"ignoredHook\", &advice_ignored_hook },\ndiff --git a/advice.h b/advice.h\nindex 9f5064e82a..7e9377864f 100644\n--- a/advice.h\n+++ b/advice.h\n@@ -17,6 +17,7 @@ extern int advice_implicit_identity;\n extern int advice_detached_head;\n extern int advice_set_upstream_failure;\n extern int advice_object_name_warning;\n+extern int advice_amworkdir;\n extern int advice_rm_hints;\n extern int advice_add_embedded_repo;\n extern int advice_ignored_hook;\ndiff --git a/builtin/am.c b/builtin/am.c\nindex aa989e7390..735d016525 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -1827,15 +1827,11 @@ static void am_run(struct am_state *state, int resume)\n \t\t}\n \n \t\tif (apply_status) {\n-\t\t\tint advice_amworkdir = 1;\n-\n \t\t\tprintf_ln(_(\"Patch failed at %s %.*s\"), msgnum(state),\n \t\t\t\tlinelen(state->msg), state->msg);\n \n-\t\t\tgit_config_get_bool(\"advice.amworkdir\", &advice_amworkdir);\n-\n \t\t\tif (advice_amworkdir)\n-\t\t\t\tprintf_ln(_(\"Use 'git am --show-current-patch' to see the failed patch\"));\n+\t\t\t\tadvise(_(\"Use 'git am --show-current-patch' to see the failed patch\"));\n \n \t\t\tdie_user_resolve(state);\n \t\t}\ndiff --git a/t/t4254-am-corrupt.sh b/t/t4254-am-corrupt.sh\nindex 168739c721..fd3bdbfe2c 100755\n--- a/t/t4254-am-corrupt.sh\n+++ b/t/t4254-am-corrupt.sh\n@@ -25,7 +25,7 @@ test_expect_success setup '\n #   fatal: unable to write file '(null)' mode 100644: Bad address\n # Also, it had the unwanted side-effect of deleting f.\n test_expect_success 'try to apply corrupted patch' '\n-\ttest_must_fail git am bad-patch.diff 2>actual\n+\ttest_must_fail git -c advice.amWorkDir=false am bad-patch.diff 2>actual\n '\n \n test_expect_success 'compare diagnostic; ensure file is still here' '\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"348595","messageId":"20180526135531.4516-12-pclouds@gmail.com","threadId":"48456","inReplyTo":"20180526135531.4516-1-pclouds@gmail.com","subject":"[PATCH v2 11/11] log-tree: allow to customize 'grafted' color","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-26T13:55:31Z","receivedAt":"2018-05-26T13:56:00Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Commit 76f5df305b (log: decorate grafted commits with \"grafted\" -\n2011-08-18) lets us decorate grafted commits but I forgot about the\ncolor.decorate.* config.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/config.txt | 3 ++-\n log-tree.c               | 1 +\n 2 files changed, 3 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex ab641bf5a9..1cc18a828c 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -1162,7 +1162,8 @@ color.diff.<slot>::\n color.decorate.<slot>::\n \tUse customized color for 'git log --decorate' output.  `<slot>` is one\n \tof `branch`, `remoteBranch`, `tag`, `stash` or `HEAD` for local\n-\tbranches, remote-tracking branches, tags, stash and HEAD, respectively.\n+\tbranches, remote-tracking branches, tags, stash and HEAD, respectively\n+\tand `grafted` for grafted commits.\n \n color.grep::\n \tWhen set to `always`, always highlight matches.  When `false` (or\ndiff --git a/log-tree.c b/log-tree.c\nindex 284ce0e3c5..d3a43e29cd 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -34,6 +34,7 @@ static const char *color_decorate_slots[] = {\n \t[DECORATION_REF_TAG]\t= \"tag\",\n \t[DECORATION_REF_STASH]\t= \"stash\",\n \t[DECORATION_REF_HEAD]\t= \"HEAD\",\n+\t[DECORATION_GRAFTED]\t= \"grafted\",\n };\n \n static const char *decorate_get_color(int decorate_use_color, enum decoration_type ix)\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"348596","messageId":"20180526135531.4516-11-pclouds@gmail.com","threadId":"48456","inReplyTo":"20180526135531.4516-1-pclouds@gmail.com","subject":"[PATCH v2 10/11] completion: support case-insensitive config vars","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-26T13:55:30Z","receivedAt":"2018-05-26T13:56:02Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Config variables are case-insensitive but this case/esac construct is\ncase-sensitive by default. For bash v4, it'll be easy. For platforms\nthat are stuck with older versions, we need an external command, but\nthat is not that critical. And where this additional overhead matters\nthe most is Windows, but luckily Git for Windows ships with Bash v4.\n\nHelped-by: SZEDER Gábor <szeder.dev@gmail.com>\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n contrib/completion/git-completion.bash | 10 +++++++++-\n 1 file changed, 9 insertions(+), 1 deletion(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex efc930c9d1..2cbd14b346 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -2151,7 +2151,15 @@ __git_compute_config_vars ()\n \n _git_config ()\n {\n-\tcase \"$prev\" in\n+\tlocal varname\n+\n+\tif [ \"${BASH_VERSINFO[0]:-0}\" -ge 4 ]; then\n+\t\tvarname=\"${prev,,}\"\n+\telse\n+\t\tvarname=\"$(echo \"$prev\" |tr A-Z a-z)\"\n+\tfi\n+\n+\tcase \"$varname\" in\n \tbranch.*.remote|branch.*.pushremote)\n \t\t__gitcomp_nl \"$(__git_remotes)\"\n \t\treturn\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"348597","messageId":"20180526135531.4516-4-pclouds@gmail.com","threadId":"48456","inReplyTo":"20180526135531.4516-1-pclouds@gmail.com","subject":"[PATCH v2 03/11] fsck: factor out msg_id_info[] lazy initialization code","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-26T13:55:23Z","receivedAt":"2018-05-26T13:56:03Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This array will be used by some other function than parse_msg_id() in\nthe following commit. Factor out this prep code so it could be called\nfrom that one.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n fsck.c | 40 ++++++++++++++++++++++++----------------\n 1 file changed, 24 insertions(+), 16 deletions(-)\n\ndiff --git a/fsck.c b/fsck.c\nindex 1722f6cab0..e2a6f33891 100644\n--- a/fsck.c\n+++ b/fsck.c\n@@ -84,26 +84,34 @@ static struct {\n };\n #undef MSG_ID\n \n-static int parse_msg_id(const char *text)\n+static void prepare_msg_ids(void)\n {\n \tint i;\n \n-\tif (!msg_id_info[0].downcased) {\n-\t\t/* convert id_string to lower case, without underscores. */\n-\t\tfor (i = 0; i < FSCK_MSG_MAX; i++) {\n-\t\t\tconst char *p = msg_id_info[i].id_string;\n-\t\t\tint len = strlen(p);\n-\t\t\tchar *q = xmalloc(len);\n-\n-\t\t\tmsg_id_info[i].downcased = q;\n-\t\t\twhile (*p)\n-\t\t\t\tif (*p == '_')\n-\t\t\t\t\tp++;\n-\t\t\t\telse\n-\t\t\t\t\t*(q)++ = tolower(*(p)++);\n-\t\t\t*q = '\\0';\n-\t\t}\n+\tif (msg_id_info[0].downcased)\n+\t\treturn;\n+\n+\t/* convert id_string to lower case, without underscores. */\n+\tfor (i = 0; i < FSCK_MSG_MAX; i++) {\n+\t\tconst char *p = msg_id_info[i].id_string;\n+\t\tint len = strlen(p);\n+\t\tchar *q = xmalloc(len);\n+\n+\t\tmsg_id_info[i].downcased = q;\n+\t\twhile (*p)\n+\t\t\tif (*p == '_')\n+\t\t\t\tp++;\n+\t\t\telse\n+\t\t\t\t*(q)++ = tolower(*(p)++);\n+\t\t*q = '\\0';\n \t}\n+}\n+\n+static int parse_msg_id(const char *text)\n+{\n+\tint i;\n+\n+\tprepare_msg_ids();\n \n \tfor (i = 0; i < FSCK_MSG_MAX; i++)\n \t\tif (!strcmp(text, msg_id_info[i].downcased))\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"348598","messageId":"20180526135531.4516-9-pclouds@gmail.com","threadId":"48456","inReplyTo":"20180526135531.4516-1-pclouds@gmail.com","subject":"[PATCH v2 08/11] completion: drop the hard coded list of config vars","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-26T13:55:28Z","receivedAt":"2018-05-26T13:56:06Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The new help option --config-for-completion is a machine friendlier\nversion of --config where all the placeholders and wildcards are\ndropped, leaving only the good, completable prefixes for\ngit-completion.bash to consume.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/help.c                         |   9 +-\n contrib/completion/git-completion.bash | 335 +------------------------\n help.c                                 |  34 ++-\n help.h                                 |   2 +-\n 4 files changed, 49 insertions(+), 331 deletions(-)\n\ndiff --git a/builtin/help.c b/builtin/help.c\nindex ccb206e1d4..8d4f6dd301 100644\n--- a/builtin/help.c\n+++ b/builtin/help.c\n@@ -47,6 +47,7 @@ static struct option builtin_help_options[] = {\n \tOPT_HIDDEN_BOOL(0, \"exclude-guides\", &exclude_guides, N_(\"exclude guides\")),\n \tOPT_BOOL('g', \"guides\", &show_guides, N_(\"print list of useful guides\")),\n \tOPT_BOOL('c', \"config\", &show_config, N_(\"print all configuration variable names\")),\n+\tOPT_SET_INT_F(0, \"config-for-completion\", &show_config, \"\", 2, PARSE_OPT_HIDDEN),\n \tOPT_SET_INT('m', \"man\", &help_format, N_(\"show man page\"), HELP_FORMAT_MAN),\n \tOPT_SET_INT('w', \"web\", &help_format, N_(\"show manual in web browser\"),\n \t\t\tHELP_FORMAT_WEB),\n@@ -447,8 +448,14 @@ int cmd_help(int argc, const char **argv, const char *prefix)\n \t}\n \n \tif (show_config) {\n+\t\tint for_human = show_config == 1;\n+\n+\t\tif (!for_human) {\n+\t\t\tlist_config_help(for_human);\n+\t\t\treturn 0;\n+\t\t}\n \t\tsetup_pager();\n-\t\tlist_config_help();\n+\t\tlist_config_help(for_human);\n \t\tprintf(\"\\n%s\\n\", _(\"'git help config' for more information\"));\n \t\treturn 0;\n \t}\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 12814e9bbf..1b0c30ed9a 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -2142,6 +2142,13 @@ __git_config_get_set_variables ()\n \t__git config $config_file --name-only --list\n }\n \n+__git_config_vars=\n+__git_compute_config_vars ()\n+{\n+\ttest -n \"$__git_config_vars\" ||\n+\t__git_config_vars=\"$(git help --config-for-completion | sort | uniq)\"\n+}\n+\n _git_config ()\n {\n \tcase \"$prev\" in\n@@ -2300,332 +2307,8 @@ _git_config ()\n \t\treturn\n \t\t;;\n \tesac\n-\t__gitcomp \"\n-\t\tadd.ignoreErrors\n-\t\tadvice.amWorkDir\n-\t\tadvice.commitBeforeMerge\n-\t\tadvice.detachedHead\n-\t\tadvice.implicitIdentity\n-\t\tadvice.pushAlreadyExists\n-\t\tadvice.pushFetchFirst\n-\t\tadvice.pushNeedsForce\n-\t\tadvice.pushNonFFCurrent\n-\t\tadvice.pushNonFFMatching\n-\t\tadvice.pushUpdateRejected\n-\t\tadvice.resolveConflict\n-\t\tadvice.rmHints\n-\t\tadvice.statusHints\n-\t\tadvice.statusUoption\n-\t\tadvice.ignoredHook\n-\t\talias.\n-\t\tam.keepcr\n-\t\tam.threeWay\n-\t\tapply.ignorewhitespace\n-\t\tapply.whitespace\n-\t\tbranch.autosetupmerge\n-\t\tbranch.autosetuprebase\n-\t\tbrowser.\n-\t\tclean.requireForce\n-\t\tcolor.branch\n-\t\tcolor.branch.current\n-\t\tcolor.branch.local\n-\t\tcolor.branch.plain\n-\t\tcolor.branch.remote\n-\t\tcolor.decorate.HEAD\n-\t\tcolor.decorate.branch\n-\t\tcolor.decorate.remoteBranch\n-\t\tcolor.decorate.stash\n-\t\tcolor.decorate.tag\n-\t\tcolor.diff\n-\t\tcolor.diff.commit\n-\t\tcolor.diff.frag\n-\t\tcolor.diff.func\n-\t\tcolor.diff.meta\n-\t\tcolor.diff.new\n-\t\tcolor.diff.old\n-\t\tcolor.diff.plain\n-\t\tcolor.diff.whitespace\n-\t\tcolor.grep\n-\t\tcolor.grep.context\n-\t\tcolor.grep.filename\n-\t\tcolor.grep.function\n-\t\tcolor.grep.linenumber\n-\t\tcolor.grep.match\n-\t\tcolor.grep.selected\n-\t\tcolor.grep.separator\n-\t\tcolor.interactive\n-\t\tcolor.interactive.error\n-\t\tcolor.interactive.header\n-\t\tcolor.interactive.help\n-\t\tcolor.interactive.prompt\n-\t\tcolor.pager\n-\t\tcolor.showbranch\n-\t\tcolor.status\n-\t\tcolor.status.added\n-\t\tcolor.status.changed\n-\t\tcolor.status.header\n-\t\tcolor.status.localBranch\n-\t\tcolor.status.nobranch\n-\t\tcolor.status.remoteBranch\n-\t\tcolor.status.unmerged\n-\t\tcolor.status.untracked\n-\t\tcolor.status.updated\n-\t\tcolor.ui\n-\t\tcommit.cleanup\n-\t\tcommit.gpgSign\n-\t\tcommit.status\n-\t\tcommit.template\n-\t\tcommit.verbose\n-\t\tcore.abbrev\n-\t\tcore.askpass\n-\t\tcore.attributesfile\n-\t\tcore.autocrlf\n-\t\tcore.bare\n-\t\tcore.bigFileThreshold\n-\t\tcore.checkStat\n-\t\tcore.commentChar\n-\t\tcore.commitGraph\n-\t\tcore.compression\n-\t\tcore.createObject\n-\t\tcore.deltaBaseCacheLimit\n-\t\tcore.editor\n-\t\tcore.eol\n-\t\tcore.excludesfile\n-\t\tcore.fileMode\n-\t\tcore.fsyncobjectfiles\n-\t\tcore.gitProxy\n-\t\tcore.hideDotFiles\n-\t\tcore.hooksPath\n-\t\tcore.ignoreStat\n-\t\tcore.ignorecase\n-\t\tcore.logAllRefUpdates\n-\t\tcore.loosecompression\n-\t\tcore.notesRef\n-\t\tcore.packedGitLimit\n-\t\tcore.packedGitWindowSize\n-\t\tcore.packedRefsTimeout\n-\t\tcore.pager\n-\t\tcore.precomposeUnicode\n-\t\tcore.preferSymlinkRefs\n-\t\tcore.preloadindex\n-\t\tcore.protectHFS\n-\t\tcore.protectNTFS\n-\t\tcore.quotepath\n-\t\tcore.repositoryFormatVersion\n-\t\tcore.safecrlf\n-\t\tcore.sharedRepository\n-\t\tcore.sparseCheckout\n-\t\tcore.splitIndex\n-\t\tcore.sshCommand\n-\t\tcore.symlinks\n-\t\tcore.trustctime\n-\t\tcore.untrackedCache\n-\t\tcore.warnAmbiguousRefs\n-\t\tcore.whitespace\n-\t\tcore.worktree\n-\t\tcredential.helper\n-\t\tcredential.useHttpPath\n-\t\tcredential.username\n-\t\tcredentialCache.ignoreSIGHUP\n-\t\tdiff.autorefreshindex\n-\t\tdiff.external\n-\t\tdiff.ignoreSubmodules\n-\t\tdiff.mnemonicprefix\n-\t\tdiff.noprefix\n-\t\tdiff.renameLimit\n-\t\tdiff.renames\n-\t\tdiff.statGraphWidth\n-\t\tdiff.submodule\n-\t\tdiff.suppressBlankEmpty\n-\t\tdiff.tool\n-\t\tdiff.wordRegex\n-\t\tdiff.algorithm\n-\t\tdifftool.\n-\t\tdifftool.prompt\n-\t\tfetch.recurseSubmodules\n-\t\tfetch.unpackLimit\n-\t\tformat.attach\n-\t\tformat.cc\n-\t\tformat.coverLetter\n-\t\tformat.from\n-\t\tformat.headers\n-\t\tformat.numbered\n-\t\tformat.pretty\n-\t\tformat.signature\n-\t\tformat.signoff\n-\t\tformat.subjectprefix\n-\t\tformat.suffix\n-\t\tformat.thread\n-\t\tformat.to\n-\t\tgc.\n-\t\tgc.aggressiveDepth\n-\t\tgc.aggressiveWindow\n-\t\tgc.auto\n-\t\tgc.autoDetach\n-\t\tgc.autopacklimit\n-\t\tgc.logExpiry\n-\t\tgc.packrefs\n-\t\tgc.pruneexpire\n-\t\tgc.reflogexpire\n-\t\tgc.reflogexpireunreachable\n-\t\tgc.rerereresolved\n-\t\tgc.rerereunresolved\n-\t\tgc.worktreePruneExpire\n-\t\tgitcvs.allbinary\n-\t\tgitcvs.commitmsgannotation\n-\t\tgitcvs.dbTableNamePrefix\n-\t\tgitcvs.dbdriver\n-\t\tgitcvs.dbname\n-\t\tgitcvs.dbpass\n-\t\tgitcvs.dbuser\n-\t\tgitcvs.enabled\n-\t\tgitcvs.logfile\n-\t\tgitcvs.usecrlfattr\n-\t\tguitool.\n-\t\tgui.blamehistoryctx\n-\t\tgui.commitmsgwidth\n-\t\tgui.copyblamethreshold\n-\t\tgui.diffcontext\n-\t\tgui.encoding\n-\t\tgui.fastcopyblame\n-\t\tgui.matchtrackingbranch\n-\t\tgui.newbranchtemplate\n-\t\tgui.pruneduringfetch\n-\t\tgui.spellingdictionary\n-\t\tgui.trustmtime\n-\t\thelp.autocorrect\n-\t\thelp.browser\n-\t\thelp.format\n-\t\thttp.lowSpeedLimit\n-\t\thttp.lowSpeedTime\n-\t\thttp.maxRequests\n-\t\thttp.minSessions\n-\t\thttp.noEPSV\n-\t\thttp.postBuffer\n-\t\thttp.proxy\n-\t\thttp.sslCipherList\n-\t\thttp.sslVersion\n-\t\thttp.sslCAInfo\n-\t\thttp.sslCAPath\n-\t\thttp.sslCert\n-\t\thttp.sslCertPasswordProtected\n-\t\thttp.sslKey\n-\t\thttp.sslVerify\n-\t\thttp.useragent\n-\t\ti18n.commitEncoding\n-\t\ti18n.logOutputEncoding\n-\t\timap.authMethod\n-\t\timap.folder\n-\t\timap.host\n-\t\timap.pass\n-\t\timap.port\n-\t\timap.preformattedHTML\n-\t\timap.sslverify\n-\t\timap.tunnel\n-\t\timap.user\n-\t\tinit.templatedir\n-\t\tinstaweb.browser\n-\t\tinstaweb.httpd\n-\t\tinstaweb.local\n-\t\tinstaweb.modulepath\n-\t\tinstaweb.port\n-\t\tinteractive.singlekey\n-\t\tlog.date\n-\t\tlog.decorate\n-\t\tlog.showroot\n-\t\tmailmap.file\n-\t\tman.\n-\t\tman.viewer\n-\t\tmerge.\n-\t\tmerge.conflictstyle\n-\t\tmerge.log\n-\t\tmerge.renameLimit\n-\t\tmerge.renormalize\n-\t\tmerge.stat\n-\t\tmerge.tool\n-\t\tmerge.verbosity\n-\t\tmergetool.\n-\t\tmergetool.keepBackup\n-\t\tmergetool.keepTemporaries\n-\t\tmergetool.prompt\n-\t\tnotes.displayRef\n-\t\tnotes.rewrite.\n-\t\tnotes.rewrite.amend\n-\t\tnotes.rewrite.rebase\n-\t\tnotes.rewriteMode\n-\t\tnotes.rewriteRef\n-\t\tpack.compression\n-\t\tpack.deltaCacheLimit\n-\t\tpack.deltaCacheSize\n-\t\tpack.depth\n-\t\tpack.indexVersion\n-\t\tpack.packSizeLimit\n-\t\tpack.threads\n-\t\tpack.window\n-\t\tpack.windowMemory\n-\t\tpager.\n-\t\tpretty.\n-\t\tpull.octopus\n-\t\tpull.twohead\n-\t\tpush.default\n-\t\tpush.followTags\n-\t\trebase.autosquash\n-\t\trebase.stat\n-\t\treceive.autogc\n-\t\treceive.denyCurrentBranch\n-\t\treceive.denyDeleteCurrent\n-\t\treceive.denyDeletes\n-\t\treceive.denyNonFastForwards\n-\t\treceive.fsckObjects\n-\t\treceive.unpackLimit\n-\t\treceive.updateserverinfo\n-\t\tremote.pushdefault\n-\t\tremotes.\n-\t\trepack.usedeltabaseoffset\n-\t\trerere.autoupdate\n-\t\trerere.enabled\n-\t\tsendemail.\n-\t\tsendemail.aliasesfile\n-\t\tsendemail.aliasfiletype\n-\t\tsendemail.bcc\n-\t\tsendemail.cc\n-\t\tsendemail.cccmd\n-\t\tsendemail.chainreplyto\n-\t\tsendemail.confirm\n-\t\tsendemail.envelopesender\n-\t\tsendemail.from\n-\t\tsendemail.identity\n-\t\tsendemail.multiedit\n-\t\tsendemail.signedoffbycc\n-\t\tsendemail.smtpdomain\n-\t\tsendemail.smtpencryption\n-\t\tsendemail.smtppass\n-\t\tsendemail.smtpserver\n-\t\tsendemail.smtpserveroption\n-\t\tsendemail.smtpserverport\n-\t\tsendemail.smtpuser\n-\t\tsendemail.suppresscc\n-\t\tsendemail.suppressfrom\n-\t\tsendemail.thread\n-\t\tsendemail.to\n-\t\tsendemail.tocmd\n-\t\tsendemail.validate\n-\t\tsendemail.smtpbatchsize\n-\t\tsendemail.smtprelogindelay\n-\t\tshowbranch.default\n-\t\tstatus.relativePaths\n-\t\tstatus.showUntrackedFiles\n-\t\tstatus.submodulesummary\n-\t\tsubmodule.\n-\t\ttar.umask\n-\t\ttransfer.unpackLimit\n-\t\turl.\n-\t\tuser.email\n-\t\tuser.name\n-\t\tuser.signingkey\n-\t\tweb.browser\n-\t\tbranch. remote.\n-\t\"\n+\t__git_compute_config_vars\n+\t__gitcomp \"$__git_config_vars\"\n }\n \n _git_remote ()\ndiff --git a/help.c b/help.c\nindex f078dfebad..3ebf0568db 100644\n--- a/help.c\n+++ b/help.c\n@@ -416,7 +416,7 @@ struct slot_expansion {\n \tint found;\n };\n \n-void list_config_help(void)\n+void list_config_help(int for_human)\n {\n \tstruct slot_expansion slot_expansions[] = {\n \t\t{ \"advice\", \"*\", list_config_advices },\n@@ -460,8 +460,36 @@ void list_config_help(void)\n \t\t\t    e->prefix, e->placeholder);\n \n \tstring_list_sort(&keys);\n-\tfor (i = 0; i < keys.nr; i++)\n-\t\tputs(keys.items[i].string);\n+\tfor (i = 0; i < keys.nr; i++) {\n+\t\tconst char *var = keys.items[i].string;\n+\t\tconst char *wildcard, *tag, *cut;\n+\n+\t\tif (for_human) {\n+\t\t\tputs(var);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\twildcard = strchr(var, '*');\n+\t\ttag = strchr(var, '<');\n+\n+\t\tif (!wildcard && !tag) {\n+\t\t\tputs(var);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (wildcard && !tag)\n+\t\t\tcut = wildcard;\n+\t\telse if (!wildcard && tag)\n+\t\t\tcut = tag;\n+\t\telse\n+\t\t\tcut = wildcard < tag ? wildcard : tag;\n+\n+\t\t/*\n+\t\t * We may produce duplicates, but that's up to\n+\t\t * git-completion.bash to handle\n+\t\t */\n+\t\tprintf(\"%.*s\\n\", (int)(cut - var), var);\n+\t}\n \tstring_list_clear(&keys, 0);\n }\n \ndiff --git a/help.h b/help.h\nindex b46fe6ee73..f8b15323a6 100644\n--- a/help.h\n+++ b/help.h\n@@ -22,7 +22,7 @@ static inline void mput_char(char c, unsigned int num)\n extern void list_common_cmds_help(void);\n extern void list_all_cmds_help(void);\n extern void list_common_guides_help(void);\n-extern void list_config_help(void);\n+extern void list_config_help(int for_human);\n \n extern void list_all_main_cmds(struct string_list *list);\n extern void list_all_other_cmds(struct string_list *list);\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"348599","messageId":"20180526135531.4516-3-pclouds@gmail.com","threadId":"48456","inReplyTo":"20180526135531.4516-1-pclouds@gmail.com","subject":"[PATCH v2 02/11] grep: keep all colors in an array","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-26T13:55:22Z","receivedAt":"2018-05-26T13:56:08Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This is more inline with how we handle color slots in other code. It\nalso allows us to get the list of configurable color slots later.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n grep.c | 106 ++++++++++++++++++++++++++-------------------------------\n grep.h |  21 +++++++-----\n 2 files changed, 62 insertions(+), 65 deletions(-)\n\ndiff --git a/grep.c b/grep.c\nindex 45ec7e636c..d94e2c4aeb 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -13,6 +13,17 @@ static int grep_source_is_binary(struct grep_source *gs);\n \n static struct grep_opt grep_defaults;\n \n+static const char *color_grep_slots[] = {\n+\t[GREP_COLOR_CONTEXT]\t    = \"context\",\n+\t[GREP_COLOR_FILENAME]\t    = \"filename\",\n+\t[GREP_COLOR_FUNCTION]\t    = \"function\",\n+\t[GREP_COLOR_LINENO]\t    = \"lineNumber\",\n+\t[GREP_COLOR_MATCH_CONTEXT]  = \"matchContext\",\n+\t[GREP_COLOR_MATCH_SELECTED] = \"matchSelected\",\n+\t[GREP_COLOR_SELECTED]\t    = \"selected\",\n+\t[GREP_COLOR_SEP]\t    = \"separator\",\n+};\n+\n static void std_output(struct grep_opt *opt, const void *buf, size_t size)\n {\n \tfwrite(buf, size, 1, stdout);\n@@ -42,14 +53,14 @@ void init_grep_defaults(void)\n \topt->pathname = 1;\n \topt->max_depth = -1;\n \topt->pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED;\n-\tcolor_set(opt->color_context, \"\");\n-\tcolor_set(opt->color_filename, \"\");\n-\tcolor_set(opt->color_function, \"\");\n-\tcolor_set(opt->color_lineno, \"\");\n-\tcolor_set(opt->color_match_context, GIT_COLOR_BOLD_RED);\n-\tcolor_set(opt->color_match_selected, GIT_COLOR_BOLD_RED);\n-\tcolor_set(opt->color_selected, \"\");\n-\tcolor_set(opt->color_sep, GIT_COLOR_CYAN);\n+\tcolor_set(opt->colors[GREP_COLOR_CONTEXT], \"\");\n+\tcolor_set(opt->colors[GREP_COLOR_FILENAME], \"\");\n+\tcolor_set(opt->colors[GREP_COLOR_FUNCTION], \"\");\n+\tcolor_set(opt->colors[GREP_COLOR_LINENO], \"\");\n+\tcolor_set(opt->colors[GREP_COLOR_MATCH_CONTEXT], GIT_COLOR_BOLD_RED);\n+\tcolor_set(opt->colors[GREP_COLOR_MATCH_SELECTED], GIT_COLOR_BOLD_RED);\n+\tcolor_set(opt->colors[GREP_COLOR_SELECTED], \"\");\n+\tcolor_set(opt->colors[GREP_COLOR_SEP], GIT_COLOR_CYAN);\n \topt->color = -1;\n \topt->output = std_output;\n }\n@@ -76,7 +87,7 @@ static int parse_pattern_type_arg(const char *opt, const char *arg)\n int grep_config(const char *var, const char *value, void *cb)\n {\n \tstruct grep_opt *opt = &grep_defaults;\n-\tchar *color = NULL;\n+\tconst char *slot;\n \n \tif (userdiff_config(var, value) < 0)\n \t\treturn -1;\n@@ -103,32 +114,18 @@ int grep_config(const char *var, const char *value, void *cb)\n \n \tif (!strcmp(var, \"color.grep\"))\n \t\topt->color = git_config_colorbool(var, value);\n-\telse if (!strcmp(var, \"color.grep.context\"))\n-\t\tcolor = opt->color_context;\n-\telse if (!strcmp(var, \"color.grep.filename\"))\n-\t\tcolor = opt->color_filename;\n-\telse if (!strcmp(var, \"color.grep.function\"))\n-\t\tcolor = opt->color_function;\n-\telse if (!strcmp(var, \"color.grep.linenumber\"))\n-\t\tcolor = opt->color_lineno;\n-\telse if (!strcmp(var, \"color.grep.matchcontext\"))\n-\t\tcolor = opt->color_match_context;\n-\telse if (!strcmp(var, \"color.grep.matchselected\"))\n-\t\tcolor = opt->color_match_selected;\n-\telse if (!strcmp(var, \"color.grep.selected\"))\n-\t\tcolor = opt->color_selected;\n-\telse if (!strcmp(var, \"color.grep.separator\"))\n-\t\tcolor = opt->color_sep;\n-\telse if (!strcmp(var, \"color.grep.match\")) {\n-\t\tint rc = 0;\n-\t\tif (!value)\n-\t\t\treturn config_error_nonbool(var);\n-\t\trc |= color_parse(value, opt->color_match_context);\n-\t\trc |= color_parse(value, opt->color_match_selected);\n-\t\treturn rc;\n-\t}\n-\n-\tif (color) {\n+\tif (!strcmp(var, \"color.grep.match\")) {\n+\t\tif (grep_config(\"color.grep.matchcontext\", value, cb) < 0)\n+\t\t\treturn -1;\n+\t\tif (grep_config(\"color.grep.matchselected\", value, cb) < 0)\n+\t\t\treturn -1;\n+\t} else if (skip_prefix(var, \"color.grep.\", &slot)) {\n+\t\tint i = LOOKUP_CONFIG(color_grep_slots, slot);\n+\t\tchar *color;\n+\n+\t\tif (i < 0)\n+\t\t\treturn -1;\n+\t\tcolor = opt->colors[i];\n \t\tif (!value)\n \t\t\treturn config_error_nonbool(var);\n \t\treturn color_parse(value, color);\n@@ -144,6 +141,7 @@ int grep_config(const char *var, const char *value, void *cb)\n void grep_init(struct grep_opt *opt, const char *prefix)\n {\n \tstruct grep_opt *def = &grep_defaults;\n+\tint i;\n \n \tmemset(opt, 0, sizeof(*opt));\n \topt->prefix = prefix;\n@@ -160,14 +158,8 @@ void grep_init(struct grep_opt *opt, const char *prefix)\n \topt->relative = def->relative;\n \topt->output = def->output;\n \n-\tcolor_set(opt->color_context, def->color_context);\n-\tcolor_set(opt->color_filename, def->color_filename);\n-\tcolor_set(opt->color_function, def->color_function);\n-\tcolor_set(opt->color_lineno, def->color_lineno);\n-\tcolor_set(opt->color_match_context, def->color_match_context);\n-\tcolor_set(opt->color_match_selected, def->color_match_selected);\n-\tcolor_set(opt->color_selected, def->color_selected);\n-\tcolor_set(opt->color_sep, def->color_sep);\n+\tfor (i = 0; i < NR_GREP_COLORS; i++)\n+\t\tcolor_set(opt->colors[i], def->colors[i]);\n }\n \n static void grep_set_pattern_type_option(enum grep_pattern_type pattern_type, struct grep_opt *opt)\n@@ -1098,12 +1090,12 @@ static void output_sep(struct grep_opt *opt, char sign)\n \tif (opt->null_following_name)\n \t\topt->output(opt, \"\\0\", 1);\n \telse\n-\t\toutput_color(opt, &sign, 1, opt->color_sep);\n+\t\toutput_color(opt, &sign, 1, opt->colors[GREP_COLOR_SEP]);\n }\n \n static void show_name(struct grep_opt *opt, const char *name)\n {\n-\toutput_color(opt, name, strlen(name), opt->color_filename);\n+\toutput_color(opt, name, strlen(name), opt->colors[GREP_COLOR_FILENAME]);\n \topt->output(opt, opt->null_following_name ? \"\\0\" : \"\\n\", 1);\n }\n \n@@ -1370,28 +1362,28 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,\n \t} else if (opt->pre_context || opt->post_context || opt->funcbody) {\n \t\tif (opt->last_shown == 0) {\n \t\t\tif (opt->show_hunk_mark) {\n-\t\t\t\toutput_color(opt, \"--\", 2, opt->color_sep);\n+\t\t\t\toutput_color(opt, \"--\", 2, opt->colors[GREP_COLOR_SEP]);\n \t\t\t\topt->output(opt, \"\\n\", 1);\n \t\t\t}\n \t\t} else if (lno > opt->last_shown + 1) {\n-\t\t\toutput_color(opt, \"--\", 2, opt->color_sep);\n+\t\t\toutput_color(opt, \"--\", 2, opt->colors[GREP_COLOR_SEP]);\n \t\t\topt->output(opt, \"\\n\", 1);\n \t\t}\n \t}\n \tif (opt->heading && opt->last_shown == 0) {\n-\t\toutput_color(opt, name, strlen(name), opt->color_filename);\n+\t\toutput_color(opt, name, strlen(name), opt->colors[GREP_COLOR_FILENAME]);\n \t\topt->output(opt, \"\\n\", 1);\n \t}\n \topt->last_shown = lno;\n \n \tif (!opt->heading && opt->pathname) {\n-\t\toutput_color(opt, name, strlen(name), opt->color_filename);\n+\t\toutput_color(opt, name, strlen(name), opt->colors[GREP_COLOR_FILENAME]);\n \t\toutput_sep(opt, sign);\n \t}\n \tif (opt->linenum) {\n \t\tchar buf[32];\n \t\txsnprintf(buf, sizeof(buf), \"%d\", lno);\n-\t\toutput_color(opt, buf, strlen(buf), opt->color_lineno);\n+\t\toutput_color(opt, buf, strlen(buf), opt->colors[GREP_COLOR_LINENO]);\n \t\toutput_sep(opt, sign);\n \t}\n \tif (opt->color) {\n@@ -1401,15 +1393,15 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,\n \t\tint eflags = 0;\n \n \t\tif (sign == ':')\n-\t\t\tmatch_color = opt->color_match_selected;\n+\t\t\tmatch_color = opt->colors[GREP_COLOR_MATCH_SELECTED];\n \t\telse\n-\t\t\tmatch_color = opt->color_match_context;\n+\t\t\tmatch_color = opt->colors[GREP_COLOR_MATCH_CONTEXT];\n \t\tif (sign == ':')\n-\t\t\tline_color = opt->color_selected;\n+\t\t\tline_color = opt->colors[GREP_COLOR_SELECTED];\n \t\telse if (sign == '-')\n-\t\t\tline_color = opt->color_context;\n+\t\t\tline_color = opt->colors[GREP_COLOR_CONTEXT];\n \t\telse if (sign == '=')\n-\t\t\tline_color = opt->color_function;\n+\t\t\tline_color = opt->colors[GREP_COLOR_FUNCTION];\n \t\t*eol = '\\0';\n \t\twhile (next_match(opt, bol, eol, ctx, &match, eflags)) {\n \t\t\tif (match.rm_so == match.rm_eo)\n@@ -1816,7 +1808,7 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle\n \t\t\tif (binary_match_only) {\n \t\t\t\topt->output(opt, \"Binary file \", 12);\n \t\t\t\toutput_color(opt, gs->name, strlen(gs->name),\n-\t\t\t\t\t     opt->color_filename);\n+\t\t\t\t\t     opt->colors[GREP_COLOR_FILENAME]);\n \t\t\t\topt->output(opt, \" matches\\n\", 9);\n \t\t\t\treturn 1;\n \t\t\t}\n@@ -1890,7 +1882,7 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle\n \t\tchar buf[32];\n \t\tif (opt->pathname) {\n \t\t\toutput_color(opt, gs->name, strlen(gs->name),\n-\t\t\t\t     opt->color_filename);\n+\t\t\t\t     opt->colors[GREP_COLOR_FILENAME]);\n \t\t\toutput_sep(opt, ':');\n \t\t}\n \t\txsnprintf(buf, sizeof(buf), \"%u\\n\", count);\ndiff --git a/grep.h b/grep.h\nindex 399381c908..ed25be271b 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -62,6 +62,18 @@ enum grep_header_field {\n \tGREP_HEADER_FIELD_MAX\n };\n \n+enum grep_color {\n+\tGREP_COLOR_CONTEXT,\n+\tGREP_COLOR_FILENAME,\n+\tGREP_COLOR_FUNCTION,\n+\tGREP_COLOR_LINENO,\n+\tGREP_COLOR_MATCH_CONTEXT,\n+\tGREP_COLOR_MATCH_SELECTED,\n+\tGREP_COLOR_SELECTED,\n+\tGREP_COLOR_SEP,\n+\tNR_GREP_COLORS\n+};\n+\n struct grep_pat {\n \tstruct grep_pat *next;\n \tconst char *origin;\n@@ -155,14 +167,7 @@ struct grep_opt {\n \tint funcbody;\n \tint extended_regexp_option;\n \tint pattern_type_option;\n-\tchar color_context[COLOR_MAXLEN];\n-\tchar color_filename[COLOR_MAXLEN];\n-\tchar color_function[COLOR_MAXLEN];\n-\tchar color_lineno[COLOR_MAXLEN];\n-\tchar color_match_context[COLOR_MAXLEN];\n-\tchar color_match_selected[COLOR_MAXLEN];\n-\tchar color_selected[COLOR_MAXLEN];\n-\tchar color_sep[COLOR_MAXLEN];\n+\tchar colors[NR_GREP_COLORS][COLOR_MAXLEN];\n \tunsigned pre_context;\n \tunsigned post_context;\n \tunsigned last_shown;\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"348600","messageId":"20180526135531.4516-7-pclouds@gmail.com","threadId":"48456","inReplyTo":"20180526135531.4516-1-pclouds@gmail.com","subject":"[PATCH v2 06/11] advice: keep config name in camelCase in advice_config[]","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-26T13:55:26Z","receivedAt":"2018-05-26T13:56:11Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"For parsing, we don't really need this because the main config parser\nwill lowercase everything so we can do exact matching. But this array\nnow is also used for printing in `git help --config`. Keep camelCase\nso we have a nice printout.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n advice.c | 42 +++++++++++++++++++++---------------------\n 1 file changed, 21 insertions(+), 21 deletions(-)\n\ndiff --git a/advice.c b/advice.c\nindex cf6c673ed7..2aca11f45e 100644\n--- a/advice.c\n+++ b/advice.c\n@@ -54,28 +54,28 @@ static struct {\n \tconst char *name;\n \tint *preference;\n } advice_config[] = {\n-\t{ \"pushupdaterejected\", &advice_push_update_rejected },\n-\t{ \"pushnonffcurrent\", &advice_push_non_ff_current },\n-\t{ \"pushnonffmatching\", &advice_push_non_ff_matching },\n-\t{ \"pushalreadyexists\", &advice_push_already_exists },\n-\t{ \"pushfetchfirst\", &advice_push_fetch_first },\n-\t{ \"pushneedsforce\", &advice_push_needs_force },\n-\t{ \"statushints\", &advice_status_hints },\n-\t{ \"statusuoption\", &advice_status_u_option },\n-\t{ \"commitbeforemerge\", &advice_commit_before_merge },\n-\t{ \"resolveconflict\", &advice_resolve_conflict },\n-\t{ \"implicitidentity\", &advice_implicit_identity },\n-\t{ \"detachedhead\", &advice_detached_head },\n-\t{ \"setupstreamfailure\", &advice_set_upstream_failure },\n-\t{ \"objectnamewarning\", &advice_object_name_warning },\n-\t{ \"rmhints\", &advice_rm_hints },\n-\t{ \"addembeddedrepo\", &advice_add_embedded_repo },\n-\t{ \"ignoredhook\", &advice_ignored_hook },\n-\t{ \"waitingforeditor\", &advice_waiting_for_editor },\n-\t{ \"graftfiledeprecated\", &advice_graft_file_deprecated },\n+\t{ \"pushUpdateRejected\", &advice_push_update_rejected },\n+\t{ \"pushNonFFCurrent\", &advice_push_non_ff_current },\n+\t{ \"pushNonFFMatching\", &advice_push_non_ff_matching },\n+\t{ \"pushAlreadyExists\", &advice_push_already_exists },\n+\t{ \"pushFetchFirst\", &advice_push_fetch_first },\n+\t{ \"pushNeedsForce\", &advice_push_needs_force },\n+\t{ \"statusHints\", &advice_status_hints },\n+\t{ \"statusUoption\", &advice_status_u_option },\n+\t{ \"commitBeforeMerge\", &advice_commit_before_merge },\n+\t{ \"resolveConflict\", &advice_resolve_conflict },\n+\t{ \"implicitIdentity\", &advice_implicit_identity },\n+\t{ \"detachedHead\", &advice_detached_head },\n+\t{ \"setupStreamFailure\", &advice_set_upstream_failure },\n+\t{ \"objectNameWarning\", &advice_object_name_warning },\n+\t{ \"rmHints\", &advice_rm_hints },\n+\t{ \"addEmbeddedRepo\", &advice_add_embedded_repo },\n+\t{ \"ignoredHook\", &advice_ignored_hook },\n+\t{ \"waitingForEditor\", &advice_waiting_for_editor },\n+\t{ \"graftFileDeprecated\", &advice_graft_file_deprecated },\n \n \t/* make this an alias for backward compatibility */\n-\t{ \"pushnonfastforward\", &advice_push_update_rejected }\n+\t{ \"pushNonFastForward\", &advice_push_update_rejected }\n };\n \n void advise(const char *advice, ...)\n@@ -123,7 +123,7 @@ int git_default_advice_config(const char *var, const char *value)\n \t\treturn 0;\n \n \tfor (i = 0; i < ARRAY_SIZE(advice_config); i++) {\n-\t\tif (strcmp(k, advice_config[i].name))\n+\t\tif (strcasecmp(k, advice_config[i].name))\n \t\t\tcontinue;\n \t\t*advice_config[i].preference = git_config_bool(var, value);\n \t\treturn 0;\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"348601","messageId":"20180526135531.4516-6-pclouds@gmail.com","threadId":"48456","inReplyTo":"20180526135531.4516-1-pclouds@gmail.com","subject":"[PATCH v2 05/11] fsck: produce camelCase config key names","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-26T13:55:25Z","receivedAt":"2018-05-26T13:56:28Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n fsck.c | 22 ++++++++++++++++++----\n 1 file changed, 18 insertions(+), 4 deletions(-)\n\ndiff --git a/fsck.c b/fsck.c\nindex b65ff2d856..ff1547d3c7 100644\n--- a/fsck.c\n+++ b/fsck.c\n@@ -74,14 +74,15 @@ enum fsck_msg_id {\n #undef MSG_ID\n \n #define STR(x) #x\n-#define MSG_ID(id, msg_type) { STR(id), NULL, FSCK_##msg_type },\n+#define MSG_ID(id, msg_type) { STR(id), NULL, NULL, FSCK_##msg_type },\n static struct {\n \tconst char *id_string;\n \tconst char *downcased;\n+\tconst char *camelcased;\n \tint msg_type;\n } msg_id_info[FSCK_MSG_MAX + 1] = {\n \tFOREACH_MSG_ID(MSG_ID)\n-\t{ NULL, NULL, -1 }\n+\t{ NULL, NULL, NULL, -1 }\n };\n #undef MSG_ID\n \n@@ -105,6 +106,20 @@ static void prepare_msg_ids(void)\n \t\t\telse\n \t\t\t\t*(q)++ = tolower(*(p)++);\n \t\t*q = '\\0';\n+\n+\t\tp = msg_id_info[i].id_string;\n+\t\tq = xmalloc(len);\n+\t\tmsg_id_info[i].camelcased = q;\n+\t\twhile (*p) {\n+\t\t\tif (*p == '_') {\n+\t\t\t\tp++;\n+\t\t\t\tif (*p)\n+\t\t\t\t\t*q++ = *p++;\n+\t\t\t} else {\n+\t\t\t\t*q++ = tolower(*p++);\n+\t\t\t}\n+\t\t}\n+\t\t*q = '\\0';\n \t}\n }\n \n@@ -127,9 +142,8 @@ void list_config_fsck_msg_ids(struct string_list *list, const char *prefix)\n \n \tprepare_msg_ids();\n \n-\t/* TODO: we can do better by producing camelCase names */\n \tfor (i = 0; i < FSCK_MSG_MAX; i++)\n-\t\tlist_config_item(list, prefix, msg_id_info[i].downcased);\n+\t\tlist_config_item(list, prefix, msg_id_info[i].camelcased);\n }\n \n static int fsck_msg_type(enum fsck_msg_id msg_id,\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"348620","messageId":"CAPig+cRbp1Kb2Nu-JihsxTaiWy5t=tNfVjTxGWVunyDuLu-71Q@mail.gmail.com","threadId":"48456","inReplyTo":"20180526135531.4516-5-pclouds@gmail.com","subject":"Re: [PATCH v2 04/11] help: add --config to list all available config","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-05-27T07:33:48Z","receivedAt":"2018-05-27T07:33:53Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sat, May 26, 2018 at 9:55 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> Sometimes it helps to list all available config vars so the user can\n> search for something they want. The config man page can also be used\n> but it's harder to search if you want to focus on the variable name,\n> for example.\n>\n> This is not the best way to collect the available config since it's\n> not precise. Ideally we should have a centralized list of config in C\n> code (pretty much like 'struct option'), but that's a lot more work.\n> This will do for now.\n>\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n> diff --git a/help.c b/help.c\n> @@ -409,6 +409,62 @@ void list_common_guides_help(void)\n> +void list_config_help(void)\n> +{\n> +       for (p = config_name_list; *p; p++) {\n> +               const char *var = *p;\n> +               struct strbuf sb = STRBUF_INIT;\n> +\n> +               for (e = slot_expansions; e->prefix; e++) {\n> +\n> +                       strbuf_reset(&sb);\n\nStyle nit: unwanted blank line\n\n> +                       strbuf_addf(&sb, \"%s.%s\", e->prefix, e->placeholder);\n> +                       if (!strcasecmp(var, sb.buf)) {\n> +                               e->fn(&keys, e->prefix);\n> +                               e->found++;\n> +                               break;\n> +                       }\n> +               }\n> +               strbuf_release(&sb);\n> +               if (!e->prefix)\n> +                       string_list_append(&keys, var);\n> +       }\n"},{"id":"348638","messageId":"20180527182800.25109-1-pclouds@gmail.com","threadId":"48456","inReplyTo":"20180526135531.4516-12-pclouds@gmail.com","subject":"[PATCH v2 12/11] completion: complete general config vars in two steps","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-27T18:28:00Z","receivedAt":"2018-05-27T18:28:12Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"There are 581 config variables as of now when you do \"git config\n<tab>\" which can fill up a few screens and is not very helpful when\nyou have to look through columns of text to find what you want.\n\nThis patch instead shows you only first level when you do\n\n    git config <tab>\n\nThere are 78 items, which use up 8 rows in my screen. Compared to\nscreens of text, it's pretty good. Once you have chosen you first\nlevel, e.g. color:\n\n    git config color.<tab>\n\nwill show you all color.*\n\nThis is not a new idea. branch.* and remote.* completion already does\nthis for second and third levels. For those variables, you'll need to\n<tab> three times to get full variable name.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n I mentioned about this a while back in the --no-... completion RFC.\n It turns out not that hard to do, especially when branch.* and\n remote.* already kinda set a precedence.\n\n contrib/completion/git-completion.bash | 9 +++++++--\n 1 file changed, 7 insertions(+), 2 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 2cbd14b346..ab026776df 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -2314,9 +2314,14 @@ _git_config ()\n \t\t__gitcomp \"insteadOf pushInsteadOf\" \"$pfx\" \"$cur_\"\n \t\treturn\n \t\t;;\n+\t*.*)\n+\t\t__git_compute_config_vars\n+\t\t__gitcomp \"$__git_config_vars\"\n+\t\t;;\n+\t*)\n+\t\t__git_compute_config_vars\n+\t\t__gitcomp \"$(echo \"$__git_config_vars\" | sed 's/\\.[^ ]*/./g')\"\n \tesac\n-\t__git_compute_config_vars\n-\t__gitcomp \"$__git_config_vars\"\n }\n \n _git_remote ()\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"348708","messageId":"CAGZ79kb7K_uZfUdjsnm065h3EYn=GE3Rma5+yACERFhBBcOL+Q@mail.gmail.com","threadId":"48456","inReplyTo":"20180526135531.4516-2-pclouds@gmail.com","subject":"Re: [PATCH v2 01/11] Add and use generic name->id mapping code for color slot parsing","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2018-05-29T17:41:28Z","receivedAt":"2018-05-29T17:41:34Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Sat, May 26, 2018 at 6:55 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> Instead of hard coding the name-to-id mapping in C code, keep it in an\n> array and use a common function to do the parsing. This reduces code\n> and also allows us to list all possible color slots later.\n>\n> This starts using C99 designated initializers more for convenience\n> (the first designated initializers have been introduced in builtin/clean.c\n> for some time without complaints)\n\ns/for some time without complaints/\nin 512f41cfac5 (clean.c: use designated initializer, 2017-07-14) which\nis almost a year without complaint/ maybe?\n\n(just in case a resend is needed; please be precise and mention that\nother commit so it's easy to see the reasoning there)\n\n> +\n> +int lookup_config(const char **mapping, int nr_mapping, const char *var)\n> +{\n> +       int i;\n> +\n> +       for (i = 0; i < nr_mapping; i++) {\n> +               const char *name = mapping[i];\n> +\n\n    if (!name)\n        break;\n\nmaybe? We do we need to check for 'name' in the next\ncondition? What input do we expect/allow?\n\n> +               if (name && !strcasecmp(var, name))\n> +                       return i;\n\n\n> +#define LOOKUP_CONFIG(mapping, var) \\\n> +       lookup_config(mapping, ARRAY_SIZE(mapping), var)\n> +int lookup_config(const char **mapping, int nr_mapping, const char *var);\n\nCan you add a comment here saying what mapping is or should look like?\n"}]}