Hi,
This iteration contains some minor fixups (courtesy reviews by Eric
Sunshine and Junio), and some tests from Duy squashed in. Also,
missing signoffs from Duy filled in.
Let's get this merged and work on stuff to do on top.
Thanks.
Nguyễn Thái Ngọc Duy (8):
for-each-ref, quote: convert *_quote_print -> *_quote_buf
for-each-ref: don't print out elements directly
pretty: extend pretty_print_context with callback
pretty: allow passing NULL commit to format_commit_message()
for-each-ref: get --pretty using format_commit_message()
for-each-ref: teach verify_format() about pretty's syntax
for-each-ref: introduce format specifier %>(*) and %<(*)
for-each-ref: improve responsiveness of %(upstream:track)
Ramkumar Ramachandra (7):
tar-tree: remove dependency on sq_quote_print()
quote: remove sq_quote_print()
pretty: limit recursion in format_commit_one()
for-each-ref: introduce %(HEAD) marker
for-each-ref: introduce %(upstream:track[short])
pretty: introduce get_pretty_userformat
for-each-ref: use get_pretty_userformat in --pretty
Documentation/git-for-each-ref.txt | 43 +++++-
builtin/for-each-ref.c | 279 ++++++++++++++++++++++++++++++-------
builtin/tar-tree.c | 11 +-
commit.h | 9 ++
pretty.c | 77 +++++++++-
quote.c | 61 +++-----
quote.h | 8 +-
t/t6300-for-each-ref.sh | 143 +++++++++++++++++++
8 files changed, 521 insertions(+), 110 deletions(-)
--
1.8.3.247.g485169c
From: Nguyễn Thái Ngọc Duy <redacted>
for-each-ref.c:print_value() currently prints values to stdout
immediately using {sq|perl|python|tcl}_quote_print, giving us no
opportunity to do any further processing. In preparation for getting
print_value() to accept an additional strbuf argument to write to,
convert the *_quote_print functions and callers to *_quote_buf.
[rr: commit message, minor modifications]
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
Signed-off-by: Ramkumar Ramachandra <redacted>
---
builtin/for-each-ref.c | 13 +++++++++----
quote.c | 44 ++++++++++++++++++++++----------------------
quote.h | 6 +++---
3 files changed, 34 insertions(+), 29 deletions(-)
@@ -463,72 +463,72 @@ int unquote_c_style(struct strbuf *sb, const char *quoted, const char **endp)/* quoting as a string literal for other languages */-voidperl_quote_print(FILE*stream,constchar*src)+voidperl_quote_buf(structstrbuf*sb,constchar*src){constcharsq='\'';constcharbq='\\';charc;-fputc(sq,stream);+strbuf_addch(sb,sq);while((c=*src++)){if(c==sq||c==bq)-fputc(bq,stream);-fputc(c,stream);+strbuf_addch(sb,bq);+strbuf_addch(sb,c);}-fputc(sq,stream);+strbuf_addch(sb,sq);}-voidpython_quote_print(FILE*stream,constchar*src)+voidpython_quote_buf(structstrbuf*sb,constchar*src){constcharsq='\'';constcharbq='\\';constcharnl='\n';charc;-fputc(sq,stream);+strbuf_addch(sb,sq);while((c=*src++)){if(c==nl){-fputc(bq,stream);-fputc('n',stream);+strbuf_addch(sb,bq);+strbuf_addch(sb,'n');continue;}if(c==sq||c==bq)-fputc(bq,stream);-fputc(c,stream);+strbuf_addch(sb,bq);+strbuf_addch(sb,c);}-fputc(sq,stream);+strbuf_addch(sb,sq);}-voidtcl_quote_print(FILE*stream,constchar*src)+voidtcl_quote_buf(structstrbuf*sb,constchar*src){charc;-fputc('"',stream);+strbuf_addch(sb,'"');while((c=*src++)){switch(c){case'[':case']':case'{':case'}':case'$':case'\\':case'"':-fputc('\\',stream);+strbuf_addch(sb,'\\');default:-fputc(c,stream);+strbuf_addch(sb,c);break;case'\f':-fputs("\\f",stream);+strbuf_addstr(sb,"\\f");break;case'\r':-fputs("\\r",stream);+strbuf_addstr(sb,"\\r");break;case'\n':-fputs("\\n",stream);+strbuf_addstr(sb,"\\n");break;case'\t':-fputs("\\t",stream);+strbuf_addstr(sb,"\\t");break;case'\v':-fputs("\\v",stream);+strbuf_addstr(sb,"\\v");break;}}-fputc('"',stream);+strbuf_addch(sb,'"');}
@@ -69,8 +69,8 @@ extern char *quote_path_relative(const char *in, int len,structstrbuf*out,constchar*prefix);/* quoting as a string literal for other languages */-externvoidperl_quote_print(FILE*stream,constchar*src);-externvoidpython_quote_print(FILE*stream,constchar*src);-externvoidtcl_quote_print(FILE*stream,constchar*src);+externvoidperl_quote_buf(structstrbuf*sb,constchar*src);+externvoidpython_quote_buf(structstrbuf*sb,constchar*src);+externvoidtcl_quote_buf(structstrbuf*sb,constchar*src);#endif
Remove sq_quote_print() since it has no callers. A nicer alternative
sq_quote_buf() exists: its callers aren't forced to print immediately.
For historical context, sq_quote_print() was first introduced in
575ba9d6 (GIT_TRACE: show which built-in/external commands are executed,
2006-06-25) for the purpose of printing argv for $GIT_TRACE. Today, we
achieve this using trace_argv_printf() -> sq_quote_argv() ->
sq_quote_buf(), which ultimately fills in a strbuf.
Signed-off-by: Ramkumar Ramachandra <redacted>
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
---
quote.c | 17 -----------------
quote.h | 2 --
2 files changed, 19 deletions(-)
From: Nguyễn Thái Ngọc Duy <redacted>
Currently, the entire callchain starting from show_ref() parses and
prints immediately. This inflexibility limits our ability to extend the
parser. So, convert the entire callchain to accept a strbuf argument to
write to. Also introduce a show_refs() helper that calls show_ref() in
a loop to avoid cluttering up cmd_for_each_ref() with the task of
initializing/freeing the strbuf.
[rr: commit message]
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
Signed-off-by: Ramkumar Ramachandra <redacted>
---
builtin/for-each-ref.c | 55 ++++++++++++++++++++++++++++++++------------------
1 file changed, 35 insertions(+), 20 deletions(-)
To make sure that a pretty_ctx->format substitution doesn't result in an
infinite recursion, change the prototype of format_commit_one() to
accept one last argument: no_recurse. So, a single substitution by
format() must yield a result that can be parsed by format_commit_one()
without the help of format().
Signed-off-by: Ramkumar Ramachandra <redacted>
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
---
pretty.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
From: Nguyễn Thái Ngọc Duy <redacted>
The struct pretty_print_context contains the context in which the
placeholders in format_commit_one() should be parsed. Although
format_commit_one() primarily acts as a parser, there is no way for a
caller to plug in custom callbacks. Now, callers can:
1. Parse a custom placeholder that is not supported by
format_commit_one(), and act on it independently of the pretty
machinery.
2. Parse a custom placeholder to substitute the custom placeholder with
a placeholder that format_commit_one() understands. This is
especially useful for supporting %>(*), where * is substituted with a
length computed by the caller.
To support these two usecases, the interface for the function looks
like:
typedef size_t (*format_message_fn)(struct strbuf *sb,
const char *placeholder,
void *format_context,
void *user_data,
struct strbuf *placeholder_subst)
It is exactly like format_commit_one(), except that there are two
additional fields: user_data (to pass custom data to the callback), and
placeholder_subst (to set the substitution). The callback should return
the length of the original string parsed, and optionally set
placeholder_subst.
[rr: commit message, minor modifications]
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
Signed-off-by: Ramkumar Ramachandra <redacted>
---
commit.h | 8 ++++++++
pretty.c | 25 +++++++++++++++++++++++++
2 files changed, 33 insertions(+)
@@ -1069,6 +1069,31 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */structcommit_list*p;inth1,h2;+if(c->pretty_ctx->format){+structstrbufsubst=STRBUF_INIT;+intret=c->pretty_ctx->format(sb,placeholder,context,+c->pretty_ctx->user_data,+&subst);+if(ret&&subst.len){+/*+*Somethingwasparsedbyformat(),anda+*placeholder-substitutionwasset.+*Recursionisrequiredtooverridethe+*returnvalueofformat_commit_one()with+*ret:thelengthoftheoriginalstring+*beforesubstitution.+*/+ret=format_commit_one(sb,subst.buf,context)?ret:0;+strbuf_release(&subst);+returnret;+}elseif(ret)+/*+*Somethingwasparsedbyformat(),but+*noplaceholder-substitutionwasset.+*/+returnret;+}+/* these are independent of the commit */switch(placeholder[0]){case'C':
From: Nguyễn Thái Ngọc Duy <redacted>
The new formatter, for-each-ref, may use non-commit placeholders only.
While it could audit the format line and warn/exclude commit
placeholders, that's a lot more work than simply ignore them.
Unrecognized placeholders are displayed as-is, pretty obvious that they
are not handled.
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
Signed-off-by: Ramkumar Ramachandra <redacted>
---
pretty.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
@@ -1156,6 +1156,9 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */}/* these depend on the commit */+if(!commit)+return0;+if(!commit->object.parsed)parse_object(commit->object.sha1);
@@ -1276,6 +1279,9 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */}+if(!c->message)+return0;+/* For the rest we have to parse the commit header. */if(!c->commit_header_parsed)parse_commit_header(c);
From: Nguyễn Thái Ngọc Duy <redacted>
--format is very limited in its capabilities. Introduce --pretty, which
extends the existing --format with pretty-formats. In --pretty:
- Existing --format %(atom) is available. They also accept some pretty
magic. For example, you can use "% (atom)" to only display a leading
space if the atom produces something.
- %ab to display a hex character 0xab is not available as it may
conflict with other pretty's placeholders. Use %xab instead.
- Many pretty placeholders are designed to work on commits. While some
of them should work on tags too, they don't (yet).
- Unsupported atoms cause for-each-ref to exit early and report.
Unsupported pretty placeholders are displayed as-is.
- Pretty placeholders can not be used as a sorting criteria.
--format is considered deprecated. If the user hits a bug specific in
--format code, they are advised to migrate to --pretty.
[rr: documentation]
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
Signed-off-by: Ramkumar Ramachandra <redacted>
---
Documentation/git-for-each-ref.txt | 23 ++++++-
builtin/for-each-ref.c | 72 +++++++++++++++++++++-
t/t6300-for-each-ref.sh | 123 +++++++++++++++++++++++++++++++++++++
3 files changed, 214 insertions(+), 4 deletions(-)
@@ -47,6 +48,26 @@ OPTIONS `xx`; for example `%00` interpolates to `\0` (NUL), `%09` to `\t` (TAB) and `%0a` to `\n` (LF).+<pretty>::+ A format string with supporting placeholders described in the+ "PRETTY FORMATS" section in linkgit:git-log[1]. Additionally+ supports placeholders from `<format>`+ (i.e. `%[*](fieldname)`).+++Caveats:++1. Many of the placeholders in "PRETTY FORMATS" are designed to work+ specifically on commit objects: when non-commit objects are+ supplied, those placeholders won't work (i.e. they will be emitted+ literally).++2. Does not interpolate `%ab` (where `ab` are hex digits) with the+ corresponding hex code. To print a byte from a hex code, use+ `%xab` (from pretty-formats) instead.++3. Only the placeholders inherited from `<format>` will respect+ quoting settings.+ <pattern>...:: If one or more patterns are given, only refs are shown that match against at least one pattern, either using fnmatch(3) or
@@ -1022,6 +1081,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)OPT_GROUP(""),OPT_INTEGER(0,"count",&maxcount,N_("show only <n> matched refs")),OPT_STRING(0,"format",&format,N_("format"),N_("format to use for the output")),+OPT_STRING(0,"pretty",&pretty,N_("format"),N_("alternative format to use for the output")),OPT_CALLBACK(0,"sort",sort_tail,N_("key"),N_("field name to sort on"),&opt_parse_sort),OPT_END(),
@@ -1036,7 +1096,10 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)error("more than one quoting style?");usage_with_options(for_each_ref_usage,opts);}-if(verify_format(format))+if(format!=default_format&&pretty)+die("--format and --pretty cannot be used together");+if((pretty&&verify_format(pretty))||+(!pretty&&verify_format(format)))usage_with_options(for_each_ref_usage,opts);if(!sort)
@@ -114,6 +128,115 @@ test_atom tag contents:signature '' test_atomtagcontents'Taggingat1151939927'+echo"Mailmap'd <map@example.com> <author@example.com>">$HOME/.mailmap++test_prettyhead'%(refname)'refs/heads/master+test_prettyhead'%(upstream)'refs/remotes/origin/master+test_prettyhead'%(objecttype)'commit+test_prettyhead'%(objectsize)'171+test_prettyhead'%(objectname)'67a36f10722846e891fbada1ba48ed035de75581+test_prettyhead'%H'67a36f10722846e891fbada1ba48ed035de75581+test_prettyhead'%h'67a36f1+test_prettyhead'%(tree)'0e51c00fcb93dffc755546f27593d511e1bdb46f+test_prettyhead'%T'0e51c00fcb93dffc755546f27593d511e1bdb46f+test_prettyhead'%t'0e51c00+test_prettyhead'%(parent)'''+test_prettyhead'%P'''+test_prettyhead'%(numparent)'0+test_prettyhead'%(object)'''+test_prettyhead'%(type)'''+test_prettyhead'%(author)''A U Thor <author@example.com> 1151939924 +0200'+test_prettyhead'%(authorname)''A U Thor'+test_prettyhead'%an''A U Thor'+test_prettyhead'%aN'"Mailmap'd"+test_prettyhead'%(authoremail)''<author@example.com>'+test_prettyhead'%ae''author@example.com'+test_prettyhead'%aE''map@example.com'+test_prettyhead'%(authordate)''Mon Jul 3 17:18:44 2006 +0200'+test_prettyhead'%aD''Mon, 3 Jul 2006 17:18:44 +0200'+test_prettyhead'%(committer)''C O Mitter <committer@example.com> 1151939923 +0200'+test_prettyhead'%(committername)''C O Mitter'+test_prettyhead'%cn''C O Mitter'+test_prettyhead'%(committeremail)''<committer@example.com>'+test_prettyhead'%ce''committer@example.com'+test_prettyhead'%(committerdate)''Mon Jul 3 17:18:43 2006 +0200'+test_prettyhead'%cD''Mon, 3 Jul 2006 17:18:43 +0200'+test_prettyhead'%(tag)'''+test_prettyhead'%(tagger)'''+test_prettyhead'%(taggername)'''+test_prettyhead'%(taggeremail)'''+test_prettyhead'%(taggerdate)'''+test_prettyhead'%(creator)''C O Mitter <committer@example.com> 1151939923 +0200'+test_prettyhead'%(creatordate)''Mon Jul 3 17:18:43 2006 +0200'+test_prettyhead'%(subject)''Initial'+test_prettyhead'%(contents:subject)''Initial'+test_prettyhead'%(body)'''+test_prettyhead'%(contents:body)'''+test_prettyhead'%(contents:signature)'''+test_prettyhead'%(contents)''Initial+'++test_prettyhead'%d'' (HEAD, tag: testtag, origin/master, master)'+test_prettyhead'%x20'' '+test_prettyhead'%g''%g'+test_prettyhead'%unknown''%unknown'+test_prettyhead'% (parent)'''+test_prettyhead'% P'''+test_prettyhead'% (tree)'' 0e51c00fcb93dffc755546f27593d511e1bdb46f'+test_prettyhead'% T'' 0e51c00fcb93dffc755546f27593d511e1bdb46f'++test_expect_success'% (unknown)''+test_must_failgitfor-each-ref--pretty="% (unknown)"refs/heads/master+'++test_prettyhead'%<(20)%cn end''C O Mitter end'+test_prettyhead'%>(20)%cn end'' C O Mitter end'+test_prettyhead'%><(20)%cn end'' C O Mitter end'+test_prettyhead'%<(20)%(committername) end''C O Mitter end'+test_prettyhead'%>(20)%(committername) end'' C O Mitter end'+test_prettyhead'%><(20)%(committername) end'' C O Mitter end'++test_prettytag'%(refname)'refs/tags/testtag+test_prettytag'%(upstream)'''+test_prettytag'%(objecttype)'tag+test_prettytag'%(objectsize)'154+test_prettytag'%(objectname)'98b46b1d36e5b07909de1b3886224e3e81e87322+test_prettytag'%(tree)'''+test_prettytag'%(parent)'''+test_prettytag'%(numparent)'''+test_prettytag'%(object)''67a36f10722846e891fbada1ba48ed035de75581'+test_prettytag'%(type)''commit'+test_prettytag'%(author)'''+test_prettytag'%(authorname)'''+test_prettytag'%(authoremail)'''+test_prettytag'%(authordate)'''+test_prettytag'%(committer)'''+test_prettytag'%(committername)'''+test_prettytag'%(committeremail)'''+test_prettytag'%(committerdate)'''+test_prettytag'%(tag)''testtag'+test_prettytag'%(tagger)''C O Mitter <committer@example.com> 1151939925 +0200'+test_prettytag'%(taggername)''C O Mitter'+test_prettytag'%(taggeremail)''<committer@example.com>'+test_prettytag'%(taggerdate)''Mon Jul 3 17:18:45 2006 +0200'+test_prettytag'%(creator)''C O Mitter <committer@example.com> 1151939925 +0200'+test_prettytag'%(creatordate)''Mon Jul 3 17:18:45 2006 +0200'+test_prettytag'%(subject)''Tagging at 1151939927'+test_prettytag'%(contents:subject)''Tagging at 1151939927'+test_prettytag'%(body)'''+test_prettytag'%(contents:body)'''+test_prettytag'%(contents:signature)'''+test_prettytag'%(contents)''Taggingat1151939927+'++# make sure we don't segfault when non-commits are passed in+# format_commit_message. Should be fixed so that some of these+# placeholders produce something useful for non-commits.+test_prettytag'%H''%H'+test_prettytag'%h''%h'+test_prettytag'%T''%T'+test_prettytag'%t''%t'+ test_expect_success'Check invalid atoms names are errors''test_must_failgitfor-each-ref--format="%(INVALID)"refs/heads'
From: Nguyễn Thái Ngọc Duy <redacted>
Pretty format accepts either ' ', '+' or '-' after '%' and before the
placeholder name to modify certain behaviors. Teach verify_format()
about this so that it finds atom "upstream" in, for example,
'% (upstream)'. This is important because verify_format populates
used_atom, which get_value() and populate_value() later rely on.
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
Signed-off-by: Ramkumar Ramachandra <redacted>
---
builtin/for-each-ref.c | 15 +++++++++------
pretty.c | 4 ++++
2 files changed, 13 insertions(+), 6 deletions(-)
@@ -160,6 +160,9 @@ static const char *find_next(const char *cp)*/if(cp[1]=='(')returncp;+elseif(pretty&&cp[1]&&cp[2]=='('&&+strchr(" +-",cp[1]))/* see format_commit_item() */+returncp+1;elseif(cp[1]=='%')cp++;/* skip over two % *//* otherwise this is a singleton, literal % */
@@ -1098,8 +1101,8 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)}if(format!=default_format&&pretty)die("--format and --pretty cannot be used together");-if((pretty&&verify_format(pretty))||-(!pretty&&verify_format(format)))+if((pretty&&verify_format(pretty,1))||+(!pretty&&verify_format(format,0)))usage_with_options(for_each_ref_usage,opts);if(!sort)
Use get_pretty_userformat() to interpret the --pretty string. This
means that you can now reference a format specified in a pretty.*
configuration variable as an argument to 'git for-each-ref --pretty='.
There are two caveats:
1. A leading "format:" or "tformat:" is automatically stripped and
ignored. Separator semantics are not configurable (yet).
2. No built-in formats are available. The ones specified in
pretty-formats (oneline, short etc) don't make sense when displaying
refs anyway.
Signed-off-by: Ramkumar Ramachandra <redacted>
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
---
Documentation/git-for-each-ref.txt | 3 +++
builtin/for-each-ref.c | 16 +++++++++-------
2 files changed, 12 insertions(+), 7 deletions(-)
@@ -60,6 +60,9 @@ calculated. + Caveats:+0. No built-in formats from PRETTY FORMATS (like oneline, short) are+ available.+ 1. Many of the placeholders in "PRETTY FORMATS" are designed to work specifically on commit objects: when non-commit objects are supplied, those placeholders won't work (i.e. they will be emitted
@@ -1170,13 +1170,15 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)OPT_GROUP(""),OPT_INTEGER(0,"count",&maxcount,N_("show only <n> matched refs")),OPT_STRING(0,"format",&format,N_("format"),N_("format to use for the output")),-OPT_STRING(0,"pretty",&pretty,N_("format"),N_("alternative format to use for the output")),+OPT_STRING(0,"pretty",&pretty_raw,N_("format"),N_("alternative format to use for the output")),OPT_CALLBACK(0,"sort",sort_tail,N_("key"),N_("field name to sort on"),&opt_parse_sort),OPT_END(),};parse_options(argc,argv,prefix,opts,for_each_ref_usage,0);+if(pretty_raw)+pretty_userformat=get_pretty_userformat(pretty_raw);if(maxcount<0){error("invalid --count argument: `%d'",maxcount);usage_with_options(for_each_ref_usage,opts);
@@ -1185,10 +1187,10 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)error("more than one quoting style?");usage_with_options(for_each_ref_usage,opts);}-if(format!=default_format&&pretty)+if(format!=default_format&&pretty_userformat)die("--format and --pretty cannot be used together");-if((pretty&&verify_format(pretty,1))||-(!pretty&&verify_format(format,0)))+if((pretty_userformat&&verify_format(pretty_userformat,1))||+(!pretty_userformat&&verify_format(format,0)))usage_with_options(for_each_ref_usage,opts);if(!sort)
'git branch' shows which branch you are currently on with an '*', but
'git for-each-ref' misses this feature. So, extend the format with
%(HEAD) to do exactly the same thing.
Now you can use the following format in for-each-ref:
%C(red)%(HEAD)%C(reset) %C(green)%(refname:short)%C(reset)
to display a red asterisk next to the current ref.
Signed-off-by: Ramkumar Ramachandra <redacted>
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
---
Documentation/git-for-each-ref.txt | 4 ++++
builtin/for-each-ref.c | 13 +++++++++++--
2 files changed, 15 insertions(+), 2 deletions(-)
@@ -121,6 +121,10 @@ upstream:: from the displayed ref. Respects `:short` in the same way as `refname` above.+HEAD::+ Useful to indicate the currently checked out branch. Is '*'+ if HEAD points to the current ref, and ' ' otherwise.+ In addition to the above, for commit and tag objects, the header field names (`tree`, `parent`, `object`, `type`, and `tag`) can be used to specify the value in the header field.
From: Nguyễn Thái Ngọc Duy <redacted>
Before anything is printed, for-each-ref sorts all refs first. As
part of the sorting, populate_value() is called to fill the values in
for all atoms/placeholders per entry. By the time sort_refs() is done,
pretty much all data is already retrieved.
This works fine when data can be cheaply retrieved before
%(upstream:track) comes into the picture. It may take a noticeable
amount of time to process %(upstream:track) for each entry. All
entries add up and make --format='%(refname)%(upstream:track)' seem
hung for a few seconds, then display everything at once.
Improve the responsiveness by only processing the one atom (*) at a
time so that processing one atom for all entries (e.g. sorting) won't
cause much delay (unless you choose a "heavy" atom to process).
(*) This is not entirely correct. If you sort by an atom that needs
object database access, then it will fill all atoms that need odb.
Which is not a bad thing. We don't want to access odb once at sorting
phase and again at display phase.
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
Signed-off-by: Ramkumar Ramachandra <redacted>
---
builtin/for-each-ref.c | 49 +++++++++++++++++++++++++------------------------
1 file changed, 25 insertions(+), 24 deletions(-)
@@ -630,13 +616,15 @@ static void populate_value(struct refinfo *ref)constunsignedchar*tagged;intupstream_present=0;-ref->value=xcalloc(sizeof(structatom_value),used_atom_cnt);+if(!ref->value){+ref->value=xcalloc(sizeof(structatom_value),used_atom_cnt);-if(need_symref&&(ref->flag&REF_ISSYMREF)&&!ref->symref){-unsignedcharunused1[20];-ref->symref=resolve_refdup(ref->refname,unused1,1,NULL);-if(!ref->symref)-ref->symref="";+if(need_symref&&(ref->flag&REF_ISSYMREF)&&!ref->symref){+unsignedcharunused1[20];+ref->symref=resolve_refdup(ref->refname,unused1,1,NULL);+if(!ref->symref)+ref->symref="";+}}/* Fill in specials first */
From: Nguyễn Thái Ngọc Duy <redacted>
Pretty placeholders %>(N) and %<(N) require a user provided width N,
which makes sense because the commit chain could be really long and the
user only needs to look at a few at the top, going to the end just to
calculate the best width wastes CPU cycles.
for-each-ref is different; the display set is small, and we display them
all at once. We even support sorting, which goes through all display
items anyway. This patch introduces new %>(*) and %<(*), which are
supposed to be followed immediately by %(fieldname) (i.e. original
for-each-ref specifiers, not ones coming from pretty.c). They calculate
the best width for the %(fieldname), ignoring ansi escape sequences if
any.
[rr: documentation]
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
Signed-off-by: Ramkumar Ramachandra <redacted>
---
Documentation/git-for-each-ref.txt | 7 +++++++
builtin/for-each-ref.c | 38 ++++++++++++++++++++++++++++++++++++++
t/t6300-for-each-ref.sh | 20 ++++++++++++++++++++
3 files changed, 65 insertions(+)
@@ -47,6 +47,10 @@ OPTIONS are hex digits interpolates to character with hex code `xx`; for example `%00` interpolates to `\0` (NUL), `%09` to `\t` (TAB) and `%0a` to `\n` (LF).+++Placeholders `%<(*)` and `%>(*)` work like `%<(<N>)` and `%>(<N>)`+respectively, except that the width of the next placeholder is+calculated. <pretty>:: A format string with supporting placeholders described in the
@@ -68,6 +72,9 @@ Caveats: 3. Only the placeholders inherited from `<format>` will respect quoting settings.+3. Only the placeholders inherited from `<format>` will work with the+ alignment placeholders `%<(*)` and '%>(*)`.+ <pattern>...:: If one or more patterns are given, only refs are shown that match against at least one pattern, either using fnmatch(3) or
Introduce %(upstream:track) to display "[ahead M, behind N]" and
%(upstream:trackshort) to display "=", ">", "<", or "<>"
appropriately (inspired by the contrib/completion/git-prompt.sh).
Now you can use the following format in for-each-ref:
%C(green)%(refname:short)%C(reset)%(upstream:trackshort)
to display refs with terse tracking information.
Note that :track and :trackshort only work with upstream, and error out
when used with anything else.
Signed-off-by: Ramkumar Ramachandra <redacted>
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
---
Documentation/git-for-each-ref.txt | 6 +++++-
builtin/for-each-ref.c | 42 ++++++++++++++++++++++++++++++++++++--
2 files changed, 45 insertions(+), 3 deletions(-)
@@ -119,7 +119,11 @@ objectname:: upstream:: The name of a local ref which can be considered ``upstream'' from the displayed ref. Respects `:short` in the same way as- `refname` above.+ `refname` above. Additionally respects `:track` to show+ "[ahead N, behind M]" and `:trackshort` to show the terse+ version (like the prompt) ">", "<", "<>", or "=". Has no+ effect if the ref does not have tracking information+ associated with it. HEAD:: Useful to indicate the currently checked out branch. Is '*'
@@ -656,7 +658,6 @@ static void populate_value(struct refinfo *ref)elseif(!prefixcmp(name,"symref"))refname=ref->symref?ref->symref:"";elseif(!prefixcmp(name,"upstream")){-structbranch*branch;/* only local branches may have an upstream */if(prefixcmp(ref->refname,"refs/heads/"))continue;
This helper function is intended to be used by callers implementing
--pretty themselves; it parses pretty.* configuration variables
recursively and hands the user-defined format back to the caller. No
builtins are supported, as CMT_FMT_* are really only useful when
displaying commits. Callers might like to define their own builtins in
the future.
Signed-off-by: Ramkumar Ramachandra <redacted>
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
---
commit.h | 1 +
pretty.c | 25 +++++++++++++++++++++++++
2 files changed, 26 insertions(+)
Currently, there is exactly one caller of sq_quote_print(), namely
cmd_tar_tree(). In the interest of removing sq_quote_print() and
simplification, replace it with an equivalent call to sq_quote_argv().
No functional changes intended.
Signed-off-by: Ramkumar Ramachandra <redacted>
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
---
builtin/tar-tree.c | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
On Mon, Jun 10, 2013 at 12:54 AM, Ramkumar Ramachandra
[off-list ref] wrote:
Hi,
This iteration contains some minor fixups (courtesy reviews by Eric
Sunshine and Junio), and some tests from Duy squashed in.
I'm starting to think this is a half-baked solution. It hides
problems, for example commit placeholders should produce empty string,
not the literal placeholders. Doing that from a callback is really
ugly. There's also the problem with sorting and quoting (both only
work with for-each-ref atoms only). A better solution may be improving
pretty.c to the point where it can more or less replace f-e-r's
--format. Even more, I think pretty engine should be easily added to
cat-file (especially --batch), as a generic way to extract
information. But for the reason I will send shortly, I will not work
not work on this series or any others.
--
Duy
[-CC: Duy, since he has left the community]
Junio: since Duy is no longer around to guide us, I will rely on your guidance.
Duy Nguyen wrote:
I'm starting to think this is a half-baked solution. It hides
problems, for example commit placeholders should produce empty string,
not the literal placeholders.
Why should they produce empty strings? Aren't they equivalent to
invalid placeholders?
Doing that from a callback is really
ugly.
Why is the callback ugly? I thought it was a great way to extend
pretty-formats, without teaching pretty.c about every possible format
that callers could ever want.
There's also the problem with sorting and quoting (both only
work with for-each-ref atoms only).
Why would I want to sort by reflog-identity-name (or something) in
for-each-ref? The sensible fields for sorting in for-each-ref are all
for-each-ref atoms.
On quoting, I agree. We must move the quoting to pretty.c eventually,
but I don't think it is urgent.
A better solution may be improving
pretty.c to the point where it can more or less replace f-e-r's
--format.
Why would you want to stuff everything into pretty.c? If any callers
wants to implement one specialized format, the only way to do it is to
stuff it into the One True pretty-formats?
Even more, I think pretty engine should be easily added to
cat-file (especially --batch), as a generic way to extract
information.
Cute theoretical exercise. As usual, I'm not interested: this topic
is about making git-branch more awesome, not playing with
pretty-formats.