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(-)
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(-)
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(-)
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':
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 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)
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;
'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.
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(+)
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 */
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)
On Tue, Jul 09, 2013 at 04:02:11PM +0530, Ramkumar Ramachandra wrote:
Hi,
I'm sending this out in the hope of attracting some reviews. It's an
unedited resend, and there were zero conflicts from the rebase.
I still don't like my callback idea. How about this? It's refactoring
a bit so that you can now extract the color parsing and alignment code
from pretty.c and add them to for-each-ref as new atoms in --format.
As this is simply extending --format, the syntax unification idea is
put back on the shelf and won't hinder your work.
parse_color() can be used to generate color escape sequences. For
alignment, you can do something like this:
pad_an_item();
process_following_atom_after_the_alignment_atom();
align_an_item();
I'm afraid it needs a bit more work on the for-each-ref side and may
even need some fixups (I tested t4205 only and it passed, but I may
have left some bugs)
-- 8< --
@@ -766,19 +766,23 @@ enum trunc_type {trunc_right};+structalignment{+enumflush_typeflush_type;+enumtrunc_typetruncate;+intpadding;+};+structformat_commit_context{conststructcommit*commit;conststructpretty_print_context*pretty_ctx;unsignedcommit_header_parsed:1;unsignedcommit_message_parsed:1;structsignature_checksignature_check;-enumflush_typeflush_type;-enumtrunc_typetruncate;char*message;char*commit_encoding;size_twidth,indent1,indent2;intauto_color;-intpadding;+structalignmentalignment;/* These offsets are relative to the start of the commit message. */structchunkauthor;
@@ -957,7 +961,7 @@ static int format_reflog_person(struct strbuf *sb,staticsize_tparse_color(structstrbuf*sb,/* in UTF-8 */constchar*placeholder,-structformat_commit_context*c)+intcolor_setting){if(placeholder[1]=='('){constchar*begin=placeholder+2;
@@ -1126,7 +1131,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */case'<':case'>':-returnparse_padding_placeholder(sb,placeholder,c);+returnparse_padding_placeholder(sb,placeholder,&c->alignment);}/* these depend on the commit */
@@ -1291,12 +1296,8 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */return0;/* unknown placeholder */}-staticsize_tformat_and_pad_commit(structstrbuf*sb,/* in UTF-8 */-constchar*placeholder,-structformat_commit_context*c)+staticintpad_an_item(structstrbuf*sb,intpadding){-structstrbuflocal_sb=STRBUF_INIT;-inttotal_consumed=0,len,padding=c->padding;if(padding<0){constchar*start=strrchr(sb->buf,'\n');intoccupied;