config: allow tweaking whitespace between value and comment
Extending the previous step, this allows the whitespace placed after
the value before the "# comment message" to be tweaked by tweaking
the preprocessing rule to:
* If the given comment string begins with one or more whitespace
characters followed by '#', it is passed intact.
* If the given comment string begins with '#', a Space is
prepended.
* Otherwise, " # " (Space, '#', Space) is prefixed.
* A string with LF in it cannot be used as a comment string.
Unlike the previous step, which unconditionally added a space after
the value before writing the "# comment string", because the above
preprocessing already gives a whitespace before the '#', the
resulting string is written immediately after copying the value.
And the sanity checking rule becomes
* comment string after the above massaging that comes into
git_config_set_multivar_in_file_gently() must
- begin with zero or more whitespace characters followed by '#'.
- not have a LF in it.
I personally think this is over-engineered, but since I thought
things through anyway, here it is in the patch form. The logic to
tweak end-user supplied comment string is encapsulated in a new
helper function, git_config_prepare_comment_string(), so if new
front-end callers would want to use the same massaging rules, it is
easily reused.
Unfortunately I do not think of a way to tweak the preprocessing
rules further to optionally allow having no blank after the value,
i.e. to produce
[section]
variable = value#comment
(which is a valid way to say section.variable=value, by the way)
without sacrificing the ergonomics for the more usual case, so this
time I really stop here.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Junio C Hamano committedMar 15, 2024 at 15:26 UTC31399a6b6166cf76cc533bc9915878211607ed80
5 files changed+76-20
Documentation/git-config.txt
+9-3
index af374ee2e0..e4f2e07926 100644--- a/Documentation/git-config.txt+++ b/Documentation/git-config.txt@@ -89,9 +89,15 @@ OPTIONS --comment <message>:: Append a comment at the end of new or modified lines.- Unless _<message>_ begins with "#", a string "# " (hash- followed by a space) is prepended to it. The _<message>_ must not- contain linefeed characters (no multi-line comments are permitted).++ If _<message>_ begins with one or more whitespaces followed+ by "#", it is used as-is. If it begins with "#", a space is+ prepended before it is used. Otherwise, a string " # " (a+ space followed by a hash followed by a space) is prepended+ to it. And the resulting string is placed immediately after+ the value defined for the variable. The _<message>_ must+ not contain linefeed characters (no multi-line comments are+ permitted). --get:: Get the value for a given key (optionally filtered by a regex
builtin/config.c
+1-6
index e859a659f4..0015620dde 100644--- a/builtin/config.c+++ b/builtin/config.c@@ -841,12 +841,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) flags |= CONFIG_FLAGS_FIXED_VALUE; }- if (comment) {- if (strchr(comment, '\n'))- die(_("no multi-line comment allowed: '%s'"), comment);- if (comment[0] != '#')- comment = xstrfmt("# %s", comment);- }+ comment = git_config_prepare_comment_string(comment); if (actions & PAGING_ACTIONS) setup_auto_pager("config", 1);
config.c
+58-11
index 15019cb9a5..f1d4263a68 100644--- a/config.c+++ b/config.c@@ -3044,7 +3044,7 @@ static ssize_t write_pair(int fd, const char *key, const char *value, } if (comment)- strbuf_addf(&sb, "%s %s\n", quote, comment);+ strbuf_addf(&sb, "%s%s\n", quote, comment); else strbuf_addf(&sb, "%s\n", quote);@@ -3172,6 +3172,62 @@ void git_config_set(const char *key, const char *value) trace2_cmd_set_config(key, value); }+/*+ * The ownership rule is that the caller will own the string+ * if it receives a piece of memory different from what it passed+ * as the parameter.+ */+const char *git_config_prepare_comment_string(const char *comment)+{+ size_t leading_blanks;++ if (!comment)+ return NULL;++ if (strchr(comment, '\n'))+ die(_("no multi-line comment allowed: '%s'"), comment);++ /*+ * If it begins with one or more leading whitespace characters+ * followed by '#", the comment string is used as-is.+ *+ * If it begins with '#', a SP is inserted between the comment+ * and the value the comment is about.+ *+ * Otherwise, the value is followed by a SP followed by '#'+ * followed by SP and then the comment string comes.+ */++ leading_blanks = strspn(comment, " \t");+ if (leading_blanks && comment[leading_blanks] == '#')+ ; /* use it as-is */+ else if (comment[0] == '#')+ comment = xstrfmt(" %s", comment);+ else+ comment = xstrfmt(" # %s", comment);++ return comment;+}++static void validate_comment_string(const char *comment)+{+ size_t leading_blanks;++ if (!comment)+ return;+ /*+ * The front-end must have massaged the comment string+ * properly before calling us.+ */+ if (strchr(comment, '\n'))+ BUG("multi-line comments are not permitted: '%s'", comment);++ leading_blanks = strspn(comment, " \t");+ if (!leading_blanks || comment[leading_blanks] != '#')+ BUG("comment must begin with one or more SP followed by '#': '%s'",+ comment);+}+ /* * If value==NULL, unset in (remove from) config, * if value_pattern!=NULL, disregard key/value pairs where value does not match.@@ -3211,16 +3267,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename, size_t contents_sz; struct config_store_data store = CONFIG_STORE_INIT;- if (comment) {- /*- * The front-end must have massaged the comment string- * properly before calling us.- */- if (strchr(comment, '\n'))- BUG("multi-line comments are not permitted: '%s'", comment);- if (comment[0] != '#')- BUG("comment should begin with '#': '%s'", comment);- }+ validate_comment_string(comment); /* parse-key returns negative; flip the sign to feed exit(3) */ ret = 0 - git_config_parse_key(key, &store.key, &store.baselen);