All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jonathan Nieder <jrnieder@gmail.com>
To: Will Palmer <wmpalmer@gmail.com>
Cc: git@vger.kernel.org, gitster@pobox.com, peff@peff.net
Subject: Re: [PATCH v2 3/3] pretty: add aliases for pretty formats
Date: Mon, 26 Apr 2010 02:25:16 -0500	[thread overview]
Message-ID: <20100426072516.GA30416@progeny.tock> (raw)
In-Reply-To: <1272232579-18895-4-git-send-email-wmpalmer@gmail.com>

Will Palmer wrote:

> format.pretty.<name>::
>        Alias for a --pretty= format string, as specified in
>        linkgit:git-log[1]. Any aliases defined here can be used just
>        as the builtin pretty formats could. For example, defining
>        "format.pretty.hash = format:%H" would cause the invocation
>        "git log --pretty=hash" to be equivalent to running
>        "git log --pretty=format:%H".

Ah, so I could use 

	[format "pretty"]
		wrapped = "format:\
	%C(yellow)commit %H%n\
	Merge: %p%n\
	Author:	%aN <%aE>%n\
	Date:	%ad%n%n%w(80,4,4)%s%n\
	%+b"

and then by default I get the standard medium, but with --format=wrapped,
I get my imitation of it.  Sounds very useful, thanks.

> diff --git a/pretty.c b/pretty.c
> index f884f48..d49fec7 100644
> --- a/pretty.c
> +++ b/pretty.c
> @@ -11,6 +11,16 @@
>  #include "reflog-walk.h"
>  
>  static char *user_format;
> +static struct cmt_fmt_map {
> +	const char *name;
> +	enum cmit_fmt format;
> +	const char *user_format;
> +	int is_tformat;
> +	int is_alias;
> +} *commit_formats = NULL;
> +static size_t commit_formats_len = 0;
> +static size_t commit_formats_alloc = 0;
> +static struct cmt_fmt_map *find_commit_format(const char *sought);
>  
>  static void save_user_format(struct rev_info *rev, const char *cp, int is_tformat)
>  {
> @@ -21,22 +31,134 @@ static void save_user_format(struct rev_info *rev, const char *cp, int is_tforma
>  	rev->commit_format = CMIT_FMT_USERFORMAT;
>  }
>  
> -void get_commit_format(const char *arg, struct rev_info *rev)
> +static int git_pretty_formats_config(const char *var, const char *value, void *cb)
> +{
> +	if (!prefixcmp(var, "format.pretty.")) {

Simpler to use

	if (prefixcmp(var, "format.pretty."))
		return 0;

to avoid keeping the reader in suspense.

> +		struct cmt_fmt_map user_format = {0};
> +		const char *fmt;
> +
> +		user_format.name = xstrdup(&var[14]);
> +		user_format.format = CMIT_FMT_USERFORMAT;
> +		git_config_string(&fmt, var, value);

git_config_string() does a strdup(), but we were about to either
discard the value or do that ourselves anyway...

> +		if (!prefixcmp(fmt, "format:") || !prefixcmp(fmt, "tformat:")) {
> +			user_format.is_tformat = fmt[0] == 't';
> +			fmt = strchr(fmt, ':') + 1;
> +		} else if (strchr(fmt, '%'))
> +			user_format.is_tformat = 1;
> +		else
> +			user_format.is_alias = 1;
> +		user_format.user_format = fmt;

... or rather we would be, if this reused code from get_commit_format/
save_user_format.

> +
> +		ALLOC_GROW(commit_formats, commit_formats_len+1,
> +			   commit_formats_alloc);
> +		memcpy(&commit_formats[ commit_formats_len ], &user_format,
> +		       sizeof(user_format));
> +		commit_formats_len++;

Why not build it in place?  Not for performance reasons (that could go
either way); it is just that that would seem simpler to me.

> +	}
> +	return 0;
> +}

Regarding the next piece: I suspect the review would be easier if
it had been more than one patch.  Maybe three patches:

 1 restructure get_commit_format to read from a (dynamic) list of
   supported formats that is not its responsibility

 2 infrastructure for format aliases (this is not needed for
   --format=datelist where datelist = "tformat:%h %cd")

 3 new configuration for user-defined formats and format aliases

Maybe 3 could come before 2, since it seems like complicated.

The new call graph looks like this:

 setup_revisions() ->
   handle_revision_opt() ->
   get_commit_format() ->
   find_commit_format() ->
   setup_commit_formats() ->
   git_config() ->
   git_pretty_formats_config()

This means we have to have searched for a repository before parsing
these arguments; this constraint already exists for parsing the actual
revision arguments (maybe some day we will defer handling those
arguments for some reason).

I would have put the setup_commit_formats() call in setup_revisions()
to make this more obvious, but I suppose this way you save time if no
--format option is used.

> +
> +static void setup_commit_formats(void)
>  {
>  	int i;
> -	static struct cmt_fmt_map {
> -		const char *n;
> -		size_t cmp_len;
> -		enum cmit_fmt v;
> -	} cmt_fmts[] = {
> -		{ "raw",	1,	CMIT_FMT_RAW },
> -		{ "medium",	1,	CMIT_FMT_MEDIUM },
> -		{ "short",	1,	CMIT_FMT_SHORT },
> -		{ "email",	1,	CMIT_FMT_EMAIL },
> -		{ "full",	5,	CMIT_FMT_FULL },
> -		{ "fuller",	5,	CMIT_FMT_FULLER },
> -		{ "oneline",	1,	CMIT_FMT_ONELINE },
> +	const char **attempted_aliases = NULL;
> +	size_t attempted_aliases_alloc = 0;
> +	size_t attempted_aliases_len;
> +	struct cmt_fmt_map builtin_formats[] = {
> +		{ "raw",	CMIT_FMT_RAW,		NULL,	0 },
> +		{ "medium",	CMIT_FMT_MEDIUM,	NULL,	0 },
> +		{ "short",	CMIT_FMT_SHORT,		NULL,	0 },
> +		{ "email",	CMIT_FMT_EMAIL,		NULL,	0 },
> +		{ "full",	CMIT_FMT_FULL,		NULL,	0 },
> +		{ "fuller",	CMIT_FMT_FULLER,	NULL,	0 },
> +		{ "oneline",	CMIT_FMT_ONELINE,	NULL,	1 }

nitpick: Might be less noisy if the null format string field were the
last field.

>  	};
> +	commit_formats_len = ARRAY_SIZE(builtin_formats);
> +	ALLOC_GROW(commit_formats, commit_formats_len, commit_formats_alloc);
> +	memcpy(commit_formats, builtin_formats,
> +	       sizeof(*builtin_formats)*ARRAY_SIZE(builtin_formats));
> +
> +	git_config(git_pretty_formats_config, NULL);

I suspect the body of the next loop should be its own function to keep
the reader’s attention.

> +
> +	for (i = ARRAY_SIZE(builtin_formats); i < commit_formats_len; i++) {
> +		attempted_aliases_len = 0;
> +		struct cmt_fmt_map *aliased_format = &commit_formats[i];
> +		const char *fmt = commit_formats[i].user_format;
> +		int j;

declaration after statement

> +
> +		if (!commit_formats[i].is_alias)
> +			continue;
> +
> +		while ((aliased_format = find_commit_format(fmt))) {
[...]

Is this the right time to do this check?  Maybe we could check lazily
when the format is used.

> +			if (!aliased_format->is_alias)
> +				break;
> +
> +			fmt = aliased_format->user_format;
> +			for (j=0; j<attempted_aliases_len; j++) {
> +				if (!strcmp(fmt, attempted_aliases[j])) {
> +					aliased_format = NULL;
> +					break;
> +				}
> +			}

Example:

	[format "pretty"]
		foo = nonsense
		one = foo
		two = foo

one is treated as an alias, but two is not.  Why?

> +			if (!aliased_format)
> +				break;

Is to escape from the wider loop?  I think this is a valid use for goto.

> +
> +			ALLOC_GROW(attempted_aliases, attempted_aliases_len+1,
> +				   attempted_aliases_alloc);
> +			attempted_aliases[attempted_aliases_len] = fmt;
> +			attempted_aliases_len++;
> +		}

Example:

	[format "pretty"]
		foo = medium
		xyzzy = one
		one = foo
		two = foo
		frotz = two

At the end of this loop, attempted_aliases contains:

	one
	foo
	two

Every alias which is itself referred to by an alias is listed.

> +		if (aliased_format) {
> +			commit_formats[i].format = aliased_format->format;
> +			commit_formats[i].user_format = aliased_format->user_format;
> +			commit_formats[i].is_tformat = aliased_format->is_tformat;
> +			commit_formats[i].is_alias = 0;
> +		} else
> +			commit_formats[i].format = CMIT_FMT_UNSPECIFIED;
> +	}
> +}

Why go to the trouble to build attempted_aliases when it is never used?

I suspect I’ve completely misunderstood, so I’m stopping here.  Maybe
someone else can clear it up or take over.

Jonathan

  reply	other threads:[~2010-04-26  7:24 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-04-25 21:56 [PATCH v2 0/3] pretty: format aliases Will Palmer
2010-04-25 21:56 ` [PATCH v2 1/3] pretty: add conditional %C?colorname placeholders Will Palmer
2010-04-25 21:56   ` [PATCH v2 2/3] pretty: make %H/%h dependent on --abbrev[-commit] Will Palmer
2010-04-25 21:56     ` [PATCH v2 3/3] pretty: add aliases for pretty formats Will Palmer
2010-04-26  7:25       ` Jonathan Nieder [this message]
2010-04-26  8:15         ` Will Palmer
2010-04-26 22:11         ` Will Palmer
2010-04-26  3:11     ` [PATCH v2 2/3] pretty: make %H/%h dependent on --abbrev[-commit] Jonathan Nieder
2010-04-26  3:31       ` Jeff King
2010-04-26  3:38         ` Jonathan Nieder
2010-04-26  3:41           ` Jonathan Nieder
2010-04-26  3:45             ` Jeff King
2010-04-26  3:42           ` Jeff King
2010-04-26  7:47       ` Will Palmer
2010-04-26  9:53         ` Jonathan Nieder
2010-04-26  9:58           ` [PATCH 1/4] t4201 (shortlog): guard setup with test_expect_success Jonathan Nieder
2010-04-26  9:59           ` [PATCH 2/4] t4201 (shortlog): Test output format with multiple authors Jonathan Nieder
2010-04-26  9:59           ` [PATCH 3/4] shortlog: Document and test --format option Jonathan Nieder
2010-04-26 10:00           ` [PATCH 4/4] pretty: Respect --abbrev option Jonathan Nieder
2010-04-26 10:13           ` [PATCH v2 2/3] pretty: make %H/%h dependent on --abbrev[-commit] Will Palmer
2010-04-26 10:19             ` Jonathan Nieder
2010-04-26 10:23               ` Will Palmer
2010-04-26 10:28                 ` Jonathan Nieder
2010-04-26  2:13   ` [PATCH v2 1/3] pretty: add conditional %C?colorname placeholders Jonathan Nieder
2010-04-26  3:26     ` Jeff King
2010-04-26  4:14       ` Jonathan Nieder
2010-04-26 14:28         ` Jeff King

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20100426072516.GA30416@progeny.tock \
    --to=jrnieder@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=peff@peff.net \
    --cc=wmpalmer@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.