Message ID | 4f9f34876413927d819313a70fcdefcad5b35689.1654263472.git.gitgitgadget@gmail.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | rebase: update branches in multi-part topic | expand |
"Derrick Stolee via GitGitGadget" <gitgitgadget@gmail.com> writes: > const struct name_decoration *decoration; > + struct format_decorations_context ctx = { > + .sb = sb, > + .use_color = use_color, > + .prefix = prefix, > + .separator = separator, > + .suffix = suffix, > + .color_commit = diff_get_color(use_color, DIFF_COMMIT), > + .color_reset = decorate_get_color(use_color, DECORATION_NONE), > + }; > > decoration = get_name_decoration(&commit->object); > if (!decoration) > return; > > + ctx.current_and_HEAD = current_pointed_by_HEAD(decoration); > > + for_each_decoration(commit, append_decoration, &ctx); The function for_each_decoration() that does not take decoration but a commit felt iffy, especially because we already have called get_name_decoration() to obtain one for commit, and the API forces us to do that again at the beginning of for_each_decoration(). > + strbuf_addstr(sb, ctx.color_commit); > + strbuf_addstr(sb, ctx.suffix); > + strbuf_addstr(sb, ctx.color_reset); > +} > + > +int for_each_decoration(const struct commit *c, decoration_fn fn, void *data) > +{ > + const struct name_decoration *decoration; > + > + decoration = get_name_decoration(&c->object); > + while (decoration) { > + int res; > + if ((res = fn(decoration, data))) > + return res; > decoration = decoration->next; > } > + > + return 0; > } We'll know if this small waste is worth it when we see the new caller(s), I guess, but even if they start from commit, allowing them the same early return trick would require this piece of code: decoration = get_name_decoration(&commit->object); if (!decoration) return; in them, and even if they do not need it, it would be trivial for them to say for_each_decoration(get_name_decoration(&commit->object), do_whatever_they_need_to_do, &ctx); so, we may want to revisit this after we finish reading the series through. Making the iterator take name_decoration does not look too bad. > void show_decorations(struct rev_info *opt, struct commit *commit) > diff --git a/log-tree.h b/log-tree.h > index e7e4641cf83..ea07da2625b 100644 > --- a/log-tree.h > +++ b/log-tree.h > @@ -35,4 +35,8 @@ void fmt_output_commit(struct strbuf *, struct commit *, struct rev_info *); > void fmt_output_subject(struct strbuf *, const char *subject, struct rev_info *); > void fmt_output_email_subject(struct strbuf *, struct rev_info *); > > +typedef int decoration_fn(const struct name_decoration *d, > + void *data); > +int for_each_decoration(const struct commit *c, decoration_fn fn, void *data); > + > #endif
On 6/3/2022 1:39 PM, Junio C Hamano wrote: > "Derrick Stolee via GitGitGadget" <gitgitgadget@gmail.com> writes: > >> const struct name_decoration *decoration; >> + struct format_decorations_context ctx = { >> + .sb = sb, >> + .use_color = use_color, >> + .prefix = prefix, >> + .separator = separator, >> + .suffix = suffix, >> + .color_commit = diff_get_color(use_color, DIFF_COMMIT), >> + .color_reset = decorate_get_color(use_color, DECORATION_NONE), >> + }; >> >> decoration = get_name_decoration(&commit->object); >> if (!decoration) >> return; >> >> + ctx.current_and_HEAD = current_pointed_by_HEAD(decoration); >> >> + for_each_decoration(commit, append_decoration, &ctx); > > The function for_each_decoration() that does not take decoration but > a commit felt iffy, especially because we already have called > get_name_decoration() to obtain one for commit, and the API forces > us to do that again at the beginning of for_each_decoration(). This is more an issue with this particular caller since it needs that current_pointed_by_HEAD() information. I had considered it as something to include in the prototype of decoration_fn so it could be incorporated into for_each_decoration(), but it ended up being overly clunky for this one consumer. I'm open to other ideas, though. >> + strbuf_addstr(sb, ctx.color_commit); >> + strbuf_addstr(sb, ctx.suffix); >> + strbuf_addstr(sb, ctx.color_reset); >> +} >> + >> +int for_each_decoration(const struct commit *c, decoration_fn fn, void *data) The goal of this method was to make it super simple to iterate without doing any prep work: just load the commit and go. >> +{ >> + const struct name_decoration *decoration; >> + >> + decoration = get_name_decoration(&c->object); >> + while (decoration) { >> + int res; >> + if ((res = fn(decoration, data))) >> + return res; >> decoration = decoration->next; >> } >> + >> + return 0; >> } > > We'll know if this small waste is worth it when we see the new > caller(s), I guess, but even if they start from commit, allowing > them the same early return trick would require this piece of code: > > decoration = get_name_decoration(&commit->object); > if (!decoration) > return; The iterator returns quickly because the while loop notices a NULL decoration. This use in format_decorations_extended() needs that check because of the current_pointed_by_HEAD(decoration) call based on the result being non-NULL. > in them, and even if they do not need it, it would be trivial for > them to say > > for_each_decoration(get_name_decoration(&commit->object), > do_whatever_they_need_to_do, &ctx); > > so, we may want to revisit this after we finish reading the series > through. Making the iterator take name_decoration does not look > too bad. You are right that this would work, but it's a bit messier. We could go this route to avoid the duplicate get_name_decoration() calls in format_decorations_extended(). Thanks, -Stolee
Derrick Stolee <derrickstolee@github.com> writes: >>> + for_each_decoration(commit, append_decoration, &ctx); >> >> The function for_each_decoration() that does not take decoration but >> a commit felt iffy,... >> ... >> for_each_decoration(get_name_decoration(&commit->object), >> do_whatever_they_need_to_do, &ctx); >> >> so, we may want to revisit this after we finish reading the series >> through. Making the iterator take name_decoration does not look >> too bad. > > You are right that this would work, but it's a bit messier. We > could go this route to avoid the duplicate get_name_decoration() > calls in format_decorations_extended(). Having a convenience function that takes a commit and let you walk over its decoration is OK, but calling it for_each_decoration() bothers me somewhat (which is where my comment started from after all). Hopefully it will stay unambiguous, and it will stay to be unnecessary to name it for_each_decoration_for_commit(), as I do not think we'd add "decoration" to things that are not commits (or if we added one, we probably will call it differently from "decoration"). So, OK.
diff --git a/log-tree.c b/log-tree.c index d0ac0a6327a..b15a7c9db22 100644 --- a/log-tree.c +++ b/log-tree.c @@ -282,6 +282,54 @@ static void show_name(struct strbuf *sb, const struct name_decoration *decoratio strbuf_addstr(sb, decoration->name); } +struct format_decorations_context { + struct strbuf *sb; + int use_color; + const char *prefix; + const char *separator; + const char *suffix; + const char *color_commit; + const char *color_reset; + const struct name_decoration *current_and_HEAD; +}; + +static int append_decoration(const struct name_decoration *d, + void *data) +{ + struct format_decorations_context *ctx = data; + /* + * When both current and HEAD are there, only + * show HEAD->current where HEAD would have + * appeared, skipping the entry for current. + */ + if (d != ctx->current_and_HEAD) { + strbuf_addstr(ctx->sb, ctx->color_commit); + strbuf_addstr(ctx->sb, ctx->prefix); + strbuf_addstr(ctx->sb, ctx->color_reset); + strbuf_addstr(ctx->sb, decorate_get_color(ctx->use_color, d->type)); + if (d->type == DECORATION_REF_TAG) + strbuf_addstr(ctx->sb, "tag: "); + + show_name(ctx->sb, d); + + if (ctx->current_and_HEAD && + d->type == DECORATION_REF_HEAD) { + strbuf_addstr(ctx->sb, " -> "); + strbuf_addstr(ctx->sb, ctx->color_reset); + strbuf_addstr(ctx->sb, + decorate_get_color( + ctx->use_color, + ctx->current_and_HEAD->type)); + show_name(ctx->sb, ctx->current_and_HEAD); + } + strbuf_addstr(ctx->sb, ctx->color_reset); + + ctx->prefix = ctx->separator; + } + + return 0; +} + /* * The caller makes sure there is no funny color before calling. * format_decorations_extended makes sure the same after return. @@ -294,49 +342,42 @@ void format_decorations_extended(struct strbuf *sb, const char *suffix) { const struct name_decoration *decoration; - const struct name_decoration *current_and_HEAD; - const char *color_commit = - diff_get_color(use_color, DIFF_COMMIT); - const char *color_reset = - decorate_get_color(use_color, DECORATION_NONE); + struct format_decorations_context ctx = { + .sb = sb, + .use_color = use_color, + .prefix = prefix, + .separator = separator, + .suffix = suffix, + .color_commit = diff_get_color(use_color, DIFF_COMMIT), + .color_reset = decorate_get_color(use_color, DECORATION_NONE), + }; decoration = get_name_decoration(&commit->object); if (!decoration) return; - current_and_HEAD = current_pointed_by_HEAD(decoration); - while (decoration) { - /* - * When both current and HEAD are there, only - * show HEAD->current where HEAD would have - * appeared, skipping the entry for current. - */ - if (decoration != current_and_HEAD) { - strbuf_addstr(sb, color_commit); - strbuf_addstr(sb, prefix); - strbuf_addstr(sb, color_reset); - strbuf_addstr(sb, decorate_get_color(use_color, decoration->type)); - if (decoration->type == DECORATION_REF_TAG) - strbuf_addstr(sb, "tag: "); - - show_name(sb, decoration); - - if (current_and_HEAD && - decoration->type == DECORATION_REF_HEAD) { - strbuf_addstr(sb, " -> "); - strbuf_addstr(sb, color_reset); - strbuf_addstr(sb, decorate_get_color(use_color, current_and_HEAD->type)); - show_name(sb, current_and_HEAD); - } - strbuf_addstr(sb, color_reset); + ctx.current_and_HEAD = current_pointed_by_HEAD(decoration); - prefix = separator; - } + for_each_decoration(commit, append_decoration, &ctx); + + strbuf_addstr(sb, ctx.color_commit); + strbuf_addstr(sb, ctx.suffix); + strbuf_addstr(sb, ctx.color_reset); +} + +int for_each_decoration(const struct commit *c, decoration_fn fn, void *data) +{ + const struct name_decoration *decoration; + + decoration = get_name_decoration(&c->object); + while (decoration) { + int res; + if ((res = fn(decoration, data))) + return res; decoration = decoration->next; } - strbuf_addstr(sb, color_commit); - strbuf_addstr(sb, suffix); - strbuf_addstr(sb, color_reset); + + return 0; } void show_decorations(struct rev_info *opt, struct commit *commit) diff --git a/log-tree.h b/log-tree.h index e7e4641cf83..ea07da2625b 100644 --- a/log-tree.h +++ b/log-tree.h @@ -35,4 +35,8 @@ void fmt_output_commit(struct strbuf *, struct commit *, struct rev_info *); void fmt_output_subject(struct strbuf *, const char *subject, struct rev_info *); void fmt_output_email_subject(struct strbuf *, struct rev_info *); +typedef int decoration_fn(const struct name_decoration *d, + void *data); +int for_each_decoration(const struct commit *c, decoration_fn fn, void *data); + #endif