diff options
author | Teng Long <dyroneteng@gmail.com> | 2023-05-27 10:57:51 +0300 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2023-06-21 18:51:00 +0300 |
commit | 90bc19b3aede4ebe8b1044541373ac970804cde4 (patch) | |
tree | c85e4aa55e1c37a009d81fcd28ce3784cd2ddecc /builtin/notes.c | |
parent | 59587049e2724d762c52f8c475e7ecd79dc96b18 (diff) |
notes.c: introduce '--separator=<paragraph-break>' option
When adding new notes or appending to an existing notes, we will
insert a blank line between the paragraphs, like:
$ git notes add -m foo -m bar
$ git notes show HEAD
foo
bar
The default behavour sometimes is not enough, the user may want
to use a custom delimiter between paragraphs, like when
specifying '-m', '-F', '-C', '-c' options. So this commit
introduce a new '--separator' option for 'git notes add' and
'git notes append', for example when executing:
$ git notes add -m foo -m bar --separator="-"
$ git notes show HEAD
foo
-
bar
a newline is added to the value given to --separator if it
does not end with one already. So when executing:
$ git notes add -m foo -m bar --separator="-"
and
$ export LF="
"
$ git notes add -m foo -m bar --separator="-$LF"
Both the two exections produce the same result.
The reason we use a "strbuf" array to concat but not "string_list", is
that the binary file content may contain '\0' in the middle, this will
cause the corrupt result if using a string to save.
Signed-off-by: Teng Long <dyroneteng@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'builtin/notes.c')
-rw-r--r-- | builtin/notes.c | 109 |
1 files changed, 85 insertions, 24 deletions
diff --git a/builtin/notes.c b/builtin/notes.c index 9d8ca79582..d8a39fe2d0 100644 --- a/builtin/notes.c +++ b/builtin/notes.c @@ -8,6 +8,7 @@ */ #include "cache.h" +#include "alloc.h" #include "config.h" #include "builtin.h" #include "gettext.h" @@ -27,11 +28,12 @@ #include "worktree.h" #include "write-or-die.h" +static char *separator = "\n"; static const char * const git_notes_usage[] = { N_("git notes [--ref <notes-ref>] [list [<object>]]"), - N_("git notes [--ref <notes-ref>] add [-f] [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"), + N_("git notes [--ref <notes-ref>] add [-f] [--allow-empty] [--separator=<paragraph-break>] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"), N_("git notes [--ref <notes-ref>] copy [-f] <from-object> <to-object>"), - N_("git notes [--ref <notes-ref>] append [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"), + N_("git notes [--ref <notes-ref>] append [--allow-empty] [--separator=<paragraph-break>] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"), N_("git notes [--ref <notes-ref>] edit [--allow-empty] [<object>]"), N_("git notes [--ref <notes-ref>] show [<object>]"), N_("git notes [--ref <notes-ref>] merge [-v | -q] [-s <strategy>] <notes-ref>"), @@ -99,11 +101,19 @@ static const char * const git_notes_get_ref_usage[] = { static const char note_template[] = N_("Write/edit the notes for the following object:"); +struct note_msg { + int stripspace; + struct strbuf buf; +}; + struct note_data { int given; int use_editor; char *edit_path; struct strbuf buf; + struct note_msg **messages; + size_t msg_nr; + size_t msg_alloc; }; static void free_note_data(struct note_data *d) @@ -113,6 +123,12 @@ static void free_note_data(struct note_data *d) free(d->edit_path); } strbuf_release(&d->buf); + + while (d->msg_nr--) { + strbuf_release(&d->messages[d->msg_nr]->buf); + free(d->messages[d->msg_nr]); + } + free(d->messages); } static int list_each_note(const struct object_id *object_oid, @@ -213,65 +229,97 @@ static void write_note_data(struct note_data *d, struct object_id *oid) } } +static void insert_separator(struct strbuf *message, size_t pos) +{ + size_t sep_len = strlen(separator); + if (sep_len && separator[sep_len - 1] == '\n') + strbuf_insertstr(message, pos, separator); + else + strbuf_insertf(message, pos, "%s%s", separator, "\n"); +} + +static void concat_messages(struct note_data *d) +{ + struct strbuf msg = STRBUF_INIT; + + size_t i; + for (i = 0; i < d->msg_nr ; i++) { + if (d->buf.len) + insert_separator(&d->buf, d->buf.len); + strbuf_add(&msg, d->messages[i]->buf.buf, d->messages[i]->buf.len); + strbuf_addbuf(&d->buf, &msg); + if (d->messages[i]->stripspace) + strbuf_stripspace(&d->buf, 0); + strbuf_reset(&msg); + } + strbuf_release(&msg); +} + static int parse_msg_arg(const struct option *opt, const char *arg, int unset) { struct note_data *d = opt->value; + struct note_msg *msg = xmalloc(sizeof(*msg)); BUG_ON_OPT_NEG(unset); - if (d->buf.len) - strbuf_addch(&d->buf, '\n'); - strbuf_addstr(&d->buf, arg); - strbuf_stripspace(&d->buf, 0); - - d->given = 1; + strbuf_init(&msg->buf, strlen(arg)); + strbuf_addstr(&msg->buf, arg); + ALLOC_GROW_BY(d->messages, d->msg_nr, 1, d->msg_alloc); + d->messages[d->msg_nr - 1] = msg; + msg->stripspace = 1; return 0; } static int parse_file_arg(const struct option *opt, const char *arg, int unset) { struct note_data *d = opt->value; + struct note_msg *msg = xmalloc(sizeof(*msg)); BUG_ON_OPT_NEG(unset); - if (d->buf.len) - strbuf_addch(&d->buf, '\n'); + strbuf_init(&msg->buf , 0); if (!strcmp(arg, "-")) { - if (strbuf_read(&d->buf, 0, 1024) < 0) + if (strbuf_read(&msg->buf, 0, 1024) < 0) die_errno(_("cannot read '%s'"), arg); - } else if (strbuf_read_file(&d->buf, arg, 1024) < 0) + } else if (strbuf_read_file(&msg->buf, arg, 1024) < 0) die_errno(_("could not open or read '%s'"), arg); - strbuf_stripspace(&d->buf, 0); - d->given = 1; + ALLOC_GROW_BY(d->messages, d->msg_nr, 1, d->msg_alloc); + d->messages[d->msg_nr - 1] = msg; + msg->stripspace = 1; return 0; } static int parse_reuse_arg(const struct option *opt, const char *arg, int unset) { struct note_data *d = opt->value; - char *buf; + struct note_msg *msg = xmalloc(sizeof(*msg)); + char *value; struct object_id object; enum object_type type; unsigned long len; BUG_ON_OPT_NEG(unset); - if (d->buf.len) - strbuf_addch(&d->buf, '\n'); - + strbuf_init(&msg->buf, 0); if (repo_get_oid(the_repository, arg, &object)) die(_("failed to resolve '%s' as a valid ref."), arg); - if (!(buf = repo_read_object_file(the_repository, &object, &type, &len))) + if (!(value = repo_read_object_file(the_repository, &object, &type, &len))) die(_("failed to read object '%s'."), arg); if (type != OBJ_BLOB) { - free(buf); + strbuf_release(&msg->buf); + free(value); + free(msg); die(_("cannot read note data from non-blob object '%s'."), arg); } - strbuf_add(&d->buf, buf, len); - free(buf); - d->given = 1; + strbuf_add(&msg->buf, value, len); + free(value); + + msg->buf.len = len; + ALLOC_GROW_BY(d->messages, d->msg_nr, 1, d->msg_alloc); + d->messages[d->msg_nr - 1] = msg; + msg->stripspace = 0; return 0; } @@ -406,6 +454,7 @@ static int add(int argc, const char **argv, const char *prefix) struct object_id object, new_note; const struct object_id *note; struct note_data d = { .buf = STRBUF_INIT }; + struct option options[] = { OPT_CALLBACK_F('m', "message", &d, N_("message"), N_("note contents as a string"), PARSE_OPT_NONEG, @@ -422,6 +471,8 @@ static int add(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "allow-empty", &allow_empty, N_("allow storing empty note")), OPT__FORCE(&force, N_("replace existing notes"), PARSE_OPT_NOCOMPLETE), + OPT_STRING(0, "separator", &separator, N_("separator"), + N_("insert <paragraph-break> between paragraphs")), OPT_END() }; @@ -433,6 +484,10 @@ static int add(int argc, const char **argv, const char *prefix) usage_with_options(git_notes_add_usage, options); } + if (d.msg_nr) + concat_messages(&d); + d.given = !!d.buf.len; + object_ref = argc > 1 ? argv[1] : "HEAD"; if (repo_get_oid(the_repository, object_ref, &object)) @@ -587,6 +642,8 @@ static int append_edit(int argc, const char **argv, const char *prefix) parse_reuse_arg), OPT_BOOL(0, "allow-empty", &allow_empty, N_("allow storing empty note")), + OPT_STRING(0, "separator", &separator, N_("separator"), + N_("insert <paragraph-break> between paragraphs")), OPT_END() }; int edit = !strcmp(argv[0], "edit"); @@ -600,6 +657,10 @@ static int append_edit(int argc, const char **argv, const char *prefix) usage_with_options(usage, options); } + if (d.msg_nr) + concat_messages(&d); + d.given = !!d.buf.len; + if (d.given && edit) fprintf(stderr, _("The -m/-F/-c/-C options have been deprecated " "for the 'edit' subcommand.\n" @@ -623,7 +684,7 @@ static int append_edit(int argc, const char **argv, const char *prefix) &type, &size); if (d.buf.len && prev_buf && size) - strbuf_insertstr(&d.buf, 0, "\n"); + insert_separator(&d.buf, 0); if (prev_buf && size) strbuf_insert(&d.buf, 0, prev_buf, size); free(prev_buf); |