]> git.ipfire.org Git - thirdparty/git.git/commitdiff
config: allow tweaking whitespace between value and comment
authorJunio C Hamano <gitster@pobox.com>
Fri, 15 Mar 2024 22:26:40 +0000 (15:26 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 15 Mar 2024 23:07:39 +0000 (16:07 -0700)
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>
Documentation/git-config.txt
builtin/config.c
config.c
config.h
t/t1300-config.sh

index af374ee2e0fce42b01bcac880bbf0d3b7b62b139..e4f2e0792683afddc7c26d3a7110722c08882d7b 100644 (file)
@@ -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
index e859a659f44eae50ae6433957d5046f67bd9c5de..0015620ddeb2ab31a1bbb41a85eac70c7c548bfb 100644 (file)
@@ -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);
index 15019cb9a5ccf5d221a34f5c87a34e09f4b5d6a4..f1d4263a68bb6b5a92c340234c65b9fbd18a97b6 100644 (file)
--- 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);
index a85a827169668c2190ae9f96b8fc91cf563586a0..f4966e374948a59cbe95af6f999f0e70d44aa1e9 100644 (file)
--- a/config.h
+++ b/config.h
@@ -338,6 +338,8 @@ void git_config_set_multivar(const char *, const char *, const char *, unsigned)
 int repo_config_set_multivar_gently(struct repository *, const char *, const char *, const char *, unsigned);
 int git_config_set_multivar_in_file_gently(const char *, const char *, const char *, const char *, const char *, unsigned);
 
+const char *git_config_prepare_comment_string(const char *);
+
 /**
  * takes four parameters:
  *
index d5dfb45877f52961b572f4f385ab0f69347464dc..cc050b3c201590abfdd6c5226793cfdbbecd881c 100755 (executable)
@@ -74,6 +74,8 @@ cat > expect << EOF
        penguin = gentoo # Pygoscelis papua
        disposition = peckish # find fish
        foo = bar #abc
+       spsp = value # and comment
+       htsp = value    # and comment
 [Sections]
        WhatEver = Second
 EOF
@@ -82,6 +84,10 @@ test_expect_success 'append comments' '
        git config --replace-all --comment="Pygoscelis papua" section.penguin gentoo &&
        git config --comment="find fish" section.disposition peckish &&
        git config --comment="#abc" section.foo bar &&
+
+       git config --comment="and comment" section.spsp value &&
+       git config --comment="  # and comment" section.htsp value &&
+
        test_cmp expect .git/config
 '