format_display_notes() outputs notes in a specific format which is suitable for displaying in a terminal with "git log"/"git show". Other users may want a different format. This patch adds a new function -- for_each_oid_note() -- which, given the oid for a commit, iterates over notes refs and calls the given callback function for each note ref that contains a corresponding note. The old functionality can easily be implemented using the new interface, so I'm doing that at the same time. Cc: Johan Herland <johan@xxxxxxxxxxx> Cc: Jason A. Donenfeld <Jason@xxxxxxxxx> Cc: Christian Hesse <mail@xxxxxxxx> Signed-off-by: Vegard Nossum <vegard.nossum@xxxxxxxxxx> --- notes.c | 108 ++++++++++++++++++++++++++++++++++---------------------- notes.h | 5 +++ 2 files changed, 70 insertions(+), 43 deletions(-) diff --git a/notes.c b/notes.c index 90ec625192..4c7e883758 100644 --- a/notes.c +++ b/notes.c @@ -1242,56 +1242,68 @@ void free_notes(struct notes_tree *t) memset(t, 0, sizeof(struct notes_tree)); } -/* - * Fill the given strbuf with the notes associated with the given object. - * - * If the given notes_tree structure is not initialized, it will be auto- - * initialized to the default value (see documentation for init_notes() above). - * If the given notes_tree is NULL, the internal/default notes_tree will be - * used instead. - * - * (raw != 0) gives the %N userformat; otherwise, the note message is given - * for human consumption. - */ -static void format_note(struct notes_tree *t, const struct object_id *object_oid, - struct strbuf *sb, const char *output_encoding, int raw) +void for_each_oid_note(const struct object_id *object_oid, + const char *output_encoding, int raw, + each_oid_note_fn fn, void *cb_data) { static const char utf8[] = "utf-8"; - const struct object_id *oid; - char *msg, *msg_p; - unsigned long linelen, msglen; - enum object_type type; - if (!t) - t = &default_notes_tree; - if (!t->initialized) - init_notes(t, NULL, NULL, 0); + int i; + assert(display_notes_trees); + for (i = 0; display_notes_trees[i]; i++) { + struct notes_tree *t = display_notes_trees[i]; + const struct object_id *oid; + char *msg; + unsigned long msglen; + enum object_type type; + + if (!t) + t = &default_notes_tree; + if (!t->initialized) + init_notes(t, NULL, NULL, 0); + + oid = get_note(t, object_oid); + if (!oid) + continue; - oid = get_note(t, object_oid); - if (!oid) - return; + if (!(msg = read_object_file(oid, &type, &msglen)) || type != OBJ_BLOB) { + free(msg); + continue; + } + + if (output_encoding && *output_encoding && + !is_encoding_utf8(output_encoding)) { + char *reencoded = reencode_string(msg, output_encoding, utf8); + if (reencoded) { + free(msg); + msg = reencoded; + msglen = strlen(msg); + } + } - if (!(msg = read_object_file(oid, &type, &msglen)) || type != OBJ_BLOB) { + fn(t->ref, msg, msglen, cb_data); free(msg); - return; } +} - if (output_encoding && *output_encoding && - !is_encoding_utf8(output_encoding)) { - char *reencoded = reencode_string(msg, output_encoding, utf8); - if (reencoded) { - free(msg); - msg = reencoded; - msglen = strlen(msg); - } - } +struct format_display_notes_cb { + int raw; + struct strbuf *output; +}; + +static void format_note(const char *ref, const char *msg, unsigned long msglen, void *cb_data) +{ + struct format_display_notes_cb *cb = cb_data; + int raw = cb->raw; + struct strbuf *sb = cb->output; + const char *msg_p; + unsigned long linelen; /* we will end the annotation by a newline anyway */ if (msglen && msg[msglen - 1] == '\n') msglen--; if (!raw) { - const char *ref = t->ref; if (!ref || !strcmp(ref, GIT_NOTES_DEFAULT_REF)) { strbuf_addstr(sb, "\nNotes:\n"); } else { @@ -1309,18 +1321,28 @@ static void format_note(struct notes_tree *t, const struct object_id *object_oid strbuf_add(sb, msg_p, linelen); strbuf_addch(sb, '\n'); } - - free(msg); } +/* + * Fill the given strbuf with the notes associated with the given object. + * + * If the given notes_tree structure is not initialized, it will be auto- + * initialized to the default value (see documentation for init_notes() above). + * If the given notes_tree is NULL, the internal/default notes_tree will be + * used instead. + * + * (raw != 0) gives the %N userformat; otherwise, the note message is given + * for human consumption. + */ void format_display_notes(const struct object_id *object_oid, struct strbuf *sb, const char *output_encoding, int raw) { - int i; - assert(display_notes_trees); - for (i = 0; display_notes_trees[i]; i++) - format_note(display_notes_trees[i], object_oid, sb, - output_encoding, raw); + struct format_display_notes_cb cb = { + .raw = raw, + .output = sb, + }; + + for_each_oid_note(object_oid, output_encoding, raw, format_note, &cb); } int copy_note(struct notes_tree *t, diff --git a/notes.h b/notes.h index c7aae85ea6..833af94fae 100644 --- a/notes.h +++ b/notes.h @@ -309,6 +309,11 @@ void load_display_notes(struct display_notes_opt *opt); void format_display_notes(const struct object_id *object_oid, struct strbuf *sb, const char *output_encoding, int raw); +typedef void (*each_oid_note_fn)(const char *ref, const char *msg, unsigned long msglen, void *cb_data); + +void for_each_oid_note(const struct object_id *object_oid, + const char *output_encoding, int raw, each_oid_note_fn fn, void *cb_data); + /* * Load the notes tree from each ref listed in 'refs'. The output is * an array of notes_tree*, terminated by a NULL. -- 2.35.1.46.g38062e73e0