From: Junio C Hamano <hidden> Date: 2016-06-15 22:47:34
I mentioned an idea to enhance the pretty=format language with a string
function syntax that people can extend by adding new functions in one of
the "What's cooking" messages earlier. The general syntax would be like
%[function(args...)any string here%]
where "any string here" part would have the usual pretty=format strings.
E.g. git show -s --format='%{w(72,8,4)%s%+b%]' should give you a line
wrapped commit log message if w(width,in1,in2) is such a function.
This series is a proof of concept, as I didn't actually plug the
"wrapping" code into it; it would be fairly straightforward to integrate
the logic Dscho made strbuf capable in js/log-wrap series (queued in 'pu')
to finish this.
Junio C Hamano (3):
format_commit_message(): fix function signature
strbuf_nested_expand(): allow expansion to interrupt in the middle
Add proof-of-concept %[w(width,in1,in2)<<any-string>>%]
implementation
commit.h | 2 +-
pretty.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
strbuf.c | 23 +++++++++++++---
strbuf.h | 3 +-
4 files changed, 107 insertions(+), 7 deletions(-)
From: Junio C Hamano <hidden> Date: 2016-06-15 22:47:34
This uses the strbuf_nested_expand() mechanism introduced earlier
to demonstrate how to implement a nested string function. It does
not "wrap" using the line-wrap code, but lifting the change by Dscho
and plugging it in should be a trivial exercise.
The overall idea is to parse something like "%[w(72,4,8)%an %ae %s%]" in
these steps:
#1 "%[" introduces the nested string function.
#2 After that, a name identifies what function to call.
#3 The function parses its parameters ("(72,4,8)" in the above example),
and makes a nested expansion on the remainder of the format string.
#4 The nested expansion is terminated at "%]" and returned to the
function.
#5 The function massages the string returned from #4, and the result
becomes the expansion of the whole thing.
Signed-off-by: Junio C Hamano <redacted>
---
pretty.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 84 insertions(+), 0 deletions(-)
@@ -603,9 +677,19 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,constchar*msg=commit->buffer;structcommit_list*p;inth1,h2;+size_tnested;/* these are independent of the commit */switch(placeholder[0]){+case']':+return-1;+case'[':+/*+*%[func(arg...)string%]:weconsumedtheopening'['+*andthecalleeconsumeduptotheclosing'%]'.+*/+nested=format_fn(sb,placeholder+1,context);+returnnested?1+nested:0;case'C':if(placeholder[1]=='('){constchar*end=strchr(placeholder+2,')');
From: Junio C Hamano <hidden> Date: 2016-06-15 22:47:34
The format template string was declared as "const void *" for some unknown
reason, even though it obviously is meant to be passed a string. Make it
"const char *".
Signed-off-by: Junio C Hamano <redacted>
---
commit.h | 2 +-
pretty.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
From: Junio C Hamano <hidden> Date: 2016-06-15 22:47:34
This itself does not do a "nested" expansion, but it paves a way for
supporting an extended syntax to express a function that works on an
expanded substring, e.g. %[function(param...)expanded-string%], by
allowing the callback function to tell where the argument to the function
ends.
Signed-off-by: Junio C Hamano <redacted>
---
strbuf.c | 23 +++++++++++++++++++----
strbuf.h | 3 ++-
2 files changed, 21 insertions(+), 5 deletions(-)
From: Johannes Schindelin <hidden> Date: 2016-06-15 22:47:34
Hi,
maybe "rewrap" would be a better name than "w"?
On Fri, 16 Oct 2009, Junio C Hamano wrote:
#1 "%[" introduces the nested string function.
#2 After that, a name identifies what function to call.
#3 The function parses its parameters ("(72,4,8)" in the above example),
and makes a nested expansion on the remainder of the format string.
Can't we parse it once, i.e. the first time?
Ciao,
Dscho
From: Junio C Hamano <hidden> Date: 2016-06-15 22:47:34
Johannes Schindelin [off-list ref] writes:
On Fri, 16 Oct 2009, Junio C Hamano wrote:
quoted
consumed = fn(sb, format, context);
- if (consumed)
+ if ((ssize_t) consumed < 0)
+ break;
Would it not be much better to fix the signature of fn in a separate
commit before this one?
Yes, I considered it and it is a reasonable thing to do if this were to
become a real series for includion, but I thought it would add unnecessary
noise to the patch when the main purpose of posting the series is still to
be a proof-of-concept for discussing the design and future directions
(including "it should not have any future---it is useless code churn for
supporting only one example user 'rewrap'").
Please remind and yell at me if (1) this turns out to be going in the
right direction and (2) I forget to fix it when I redo the series after
discussion to apply them for real.
Thanks.
From: Junio C Hamano <hidden> Date: 2016-06-15 22:47:34
Johannes Schindelin [off-list ref] writes:
maybe "rewrap" would be a better name than "w"?
Perhaps, but I do not know if wrap() is even better. The only reason I
said w() here is because I saw you used w() and this is meant to be a
superset replacement for it, as this can re-wrap anything, not just one
particular field from the commit object.
On Fri, 16 Oct 2009, Junio C Hamano wrote:
quoted
#1 "%[" introduces the nested string function.
#2 After that, a name identifies what function to call.
#3 The function parses its parameters ("(72,4,8)" in the above example),
and makes a nested expansion on the remainder of the format string.
Can't we parse it once, i.e. the first time?
I may be missing the issue you are raising here, but it parses the string
only once; it stuffs the expansion of the enclosed string into a separate
buffer (while noting where it ends), applies the function to the result
obtained in the separate buffer and appends the result of the function
application to the main buffer, and the main expansion resumes where the
nested one finished.
From: Jakub Narebski <hidden> Date: 2016-06-15 22:47:34
Junio C Hamano [off-list ref] writes:
Johannes Schindelin [off-list ref] writes:
quoted
maybe "rewrap" would be a better name than "w"?
Perhaps, but I do not know if wrap() is even better. The only reason I
said w() here is because I saw you used w() and this is meant to be a
superset replacement for it, as this can re-wrap anything, not just one
particular field from the commit object.
wrap(initial_prefix, subsequent_prefix, columns) would for example
follow somewhat Text::Wrap syntax, together with 'fill'. With columns
being 0, not set, or negative it could simply indent result; this way
we finally would be able to get default git-log / git-rev-list format
using --pretty format.
I don't remember what were original parameters to w(72,4,8) means...
quoted
On Fri, 16 Oct 2009, Junio C Hamano wrote:
quoted
#1 "%[" introduces the nested string function.
#2 After that, a name identifies what function to call.
#3 The function parses its parameters ("(72,4,8)" in the above example),
and makes a nested expansion on the remainder of the format string.
Can't we parse it once, i.e. the first time?
I may be missing the issue you are raising here, but it parses the string
only once; it stuffs the expansion of the enclosed string into a separate
buffer (while noting where it ends), applies the function to the result
obtained in the separate buffer and appends the result of the function
application to the main buffer, and the main expansion resumes where the
nested one finished.
Do I understand it correctly that generic syntax is the following:
%[function(params) format specifiers]
which would run given function, with given extra parameters, on the
result of expansion of the rest of the group? That is a very
powerfull syntax... I wonder how other tools solved such problem...
BTW. can we have this also for git-for-each-ref format parameter?
Note that for single parameter we have different syntax (for
git-for-each-ref), namely
%(field:modifier)
which could be expanded to allow for parametrized modifiers with one
of the following:
%(field:modifier=param)
%(field:modifier[param])
%(field:modifier(param))
--
Jakub Narebski
Poland
ShadeHawk on #git
From: René Scharfe <hidden> Date: 2016-06-15 22:47:34
Junio C Hamano schrieb:
I mentioned an idea to enhance the pretty=format language with a
string function syntax that people can extend by adding new functions
in one of the "What's cooking" messages earlier. The general syntax
would be like
%[function(args...)any string here%]
where "any string here" part would have the usual pretty=format
strings. E.g. git show -s --format='%{w(72,8,4)%s%+b%]' should give
you a line wrapped commit log message if w(width,in1,in2) is such a
function.
I pondered line wrapping with format strings briefly a long time ago, and
I always considered it to be more similar to a colour, i.e. a state that
one can change and that is applied to all following text until the next
state change. (Except that it's always reset at the end of the format
string.) The example above would then turn into '%w(72,8,4)%s%+b'.
Here's a patch to implement this behaviour. It leaves the implementation
of the actual wrap function as an exercise to the reader, too. ;-)
pretty.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 66 insertions(+), 0 deletions(-)
@@ -445,6 +445,7 @@ struct format_commit_context {enumdate_modedmode;unsignedcommit_header_parsed:1;unsignedcommit_message_parsed:1;+size_twidth,indent1,indent2;/* These offsets are relative to the start of the commit message. */structchunkauthor;
From: René Scharfe <hidden> Date: 2016-06-15 22:47:34
Junio C Hamano schrieb:
The format template string was declared as "const void *" for some unknown
reason, even though it obviously is meant to be passed a string. Make it
"const char *".
Yes. I seem to have introduced that type in commit 7b95089c, but I
can't see (even less remember) why. Also note that commit message and
header file call the parameter "template", while it's called "format" in
commit.c (where the function used to live back then). What was I thinking?
Thanks for cleaning up after me.
René
From: Junio C Hamano <hidden> Date: 2016-06-15 22:47:34
René Scharfe [off-list ref] writes:
Junio C Hamano schrieb:
quoted
I mentioned an idea to enhance the pretty=format language with a
string function syntax that people can extend by adding new functions
in one of the "What's cooking" messages earlier. The general syntax
would be like
%[function(args...)any string here%]
where "any string here" part would have the usual pretty=format
strings. E.g. git show -s --format='%{w(72,8,4)%s%+b%]' should give
you a line wrapped commit log message if w(width,in1,in2) is such a
function.
I pondered line wrapping with format strings briefly a long time ago, and
I always considered it to be more similar to a colour, i.e. a state that
one can change and that is applied to all following text until the next
state change. (Except that it's always reset at the end of the format
string.) The example above would then turn into '%w(72,8,4)%s%+b'.
As a syntax to express "wrapping" behaviour alone, I think this is much
simpler and more superiour. I guess with this if you want to wrap
something to 72 columns and then wrap something else to 66 columns, you
would write '%w(72,8,4)something%w(66,8,4)something else', right?
I used %] only for two reasons.
- Without an explicit "here it ends", I couldn't come up with a good way
to express '%[w(72,8,4)something%]something else'. IOW, how I can say
"wrap something to 72 columns and then place something else without any
wrapping"?
- When we need to support more than one string function like this, it is
unclear what '%f()one string%g()another one' in your syntax means.
Does it mean '%[f()one string%]%[g()another one%]' (i.e. concatenate
the result of applying string function f to 'one string' and the result
of applying string function g to 'another one')? Or does it mean
'%[f()one string%[g()another one%]%]' (apply 'f' to concatenation of
'one string' and the result of applying 'g' to 'another one')?
From: René Scharfe <hidden> Date: 2016-06-15 22:47:34
Junio C Hamano schrieb:
René Scharfe [off-list ref] writes:
quoted
Junio C Hamano schrieb:
quoted
I mentioned an idea to enhance the pretty=format language with a
string function syntax that people can extend by adding new functions
in one of the "What's cooking" messages earlier. The general syntax
would be like
%[function(args...)any string here%]
where "any string here" part would have the usual pretty=format
strings. E.g. git show -s --format='%{w(72,8,4)%s%+b%]' should give
you a line wrapped commit log message if w(width,in1,in2) is such a
function.
I pondered line wrapping with format strings briefly a long time ago, and
I always considered it to be more similar to a colour, i.e. a state that
one can change and that is applied to all following text until the next
state change. (Except that it's always reset at the end of the format
string.) The example above would then turn into '%w(72,8,4)%s%+b'.
As a syntax to express "wrapping" behaviour alone, I think this is much
simpler and more superiour. I guess with this if you want to wrap
something to 72 columns and then wrap something else to 66 columns, you
would write '%w(72,8,4)something%w(66,8,4)something else', right?
That's right.
I used %] only for two reasons.
- Without an explicit "here it ends", I couldn't come up with a good way
to express '%[w(72,8,4)something%]something else'. IOW, how I can say
"wrap something to 72 columns and then place something else without any
wrapping"?
My patch makes '%w()' reset the wrapping parameters to their defaults.
- When we need to support more than one string function like this, it is
unclear what '%f()one string%g()another one' in your syntax means.
Does it mean '%[f()one string%]%[g()another one%]' (i.e. concatenate
the result of applying string function f to 'one string' and the result
of applying string function g to 'another one')? Or does it mean
'%[f()one string%[g()another one%]%]' (apply 'f' to concatenation of
'one string' and the result of applying 'g' to 'another one')?
I was going to say that we already have something like that with %C, and
that the natural way (to me) is to apply them both, independently. Case
modification functions (upper, lower, capitalized) could be treated the
same way -- as state changes (like pressing caps lock when typing text).
Which other text functions are we going to add which would break this
model? The only thing I can think of right now is nesting such
functions themselves, e.g. when indenting a list in an indented
sub-paragraph in an indented paragraph. Useful?
But then something else hit me: the line wrap function needs to consider
colour codes as having a length of zero. Ugh.
René
From: Junio C Hamano <hidden> Date: 2016-06-15 22:47:34
René Scharfe [off-list ref] writes:
Which other text functions are we going to add which would break this
model? The only thing I can think of right now is nesting such
functions themselves, e.g. when indenting a list in an indented
sub-paragraph in an indented paragraph. Useful?
I was more worried about painting ourselves now in a corner we cannot get
out of easily later. Even if my answer to question "what are we going to
add" may be "nothing I can think of right now", it does not make me happy.
Something off the top of my head are combinations like these.
%[toupper()%cD%] => 'SUN, 18 OCT 2009 12:34:56 -0700'
%[substr(7,3)%[toupper()%cD%]] => 'OCT'
%[sanitize()%s%] === %f (i.e. format-patch filename)
%[sanitize()%[substr(0,7)%[toupper()%aN%]%]%s] (with upcased author name)
By the way, I think that date formatting can be helped by introducing a
strftime() function that takes %ct/%at as input, e.g. %aD would become
%[strftime(%a, %d %b %Y %H:%M:%S %z)%at]
and we do not have to worry about keep adding random %[ac]X formats and
running out of X. Right now we use d/D/r/i and there were talks of adding
a shortened 8601 format without time or something we did not implement.
Also, if we had this %[func() any string%] mechanism, we probably wouldn't
have had to add distinction between n/N and e/E after %a and %c.
From: René Scharfe <hidden> Date: 2016-06-15 22:47:35
Junio C Hamano schrieb:
René Scharfe [off-list ref] writes:
quoted
Which other text functions are we going to add which would break this
model? The only thing I can think of right now is nesting such
functions themselves, e.g. when indenting a list in an indented
sub-paragraph in an indented paragraph. Useful?
I was more worried about painting ourselves now in a corner we cannot get
out of easily later. Even if my answer to question "what are we going to
add" may be "nothing I can think of right now", it does not make me happy.
If wrapping wasn't implemented as a nested function, nesting could still
be introduced independently and used for other things -- once these
other things arrive.
Something off the top of my head are combinations like these.
%[toupper()%cD%] => 'SUN, 18 OCT 2009 12:34:56 -0700'
%[substr(7,3)%[toupper()%cD%]] => 'OCT'
%[sanitize()%s%] === %f (i.e. format-patch filename)
%[sanitize()%[substr(0,7)%[toupper()%aN%]%]%s] (with upcased author name)
Interesting examples, I particular like sanitize().
By the way, I think that date formatting can be helped by introducing a
strftime() function that takes %ct/%at as input, e.g. %aD would become
%[strftime(%a, %d %b %Y %H:%M:%S %z)%at]
and we do not have to worry about keep adding random %[ac]X formats and
running out of X. Right now we use d/D/r/i and there were talks of adding
a shortened 8601 format without time or something we did not implement.
The number of date formats is scary, but this could be solved e.g. by
introducing "%aT(<date format specifiers etc.>)", without nesting.
Also, if we had this %[func() any string%] mechanism, we probably wouldn't
have had to add distinction between n/N and e/E after %a and %c.
Yeah, the place holders multiplied, and some of that growth could have
been avoided by providing ways to change the change the output instead
of providing the processed results.
However, I think that nesting is such a big addition that it warrants
further planning. It turns the simple "see place holder, fill in value"
interpolator into more of a programming language. Is that really
needed? And if yes, do we want to keep all these percent signs around
or is it better to invent a nicer syntax? Or borrow it from somewhere
else? Or perhaps I'm just afraid of change and complexity.
Anyway, all of the functions that accept strings need to be able to skip
over escape codes, which includes all of those mentioned above except
perhaps strftime. This is ugly. Or one could forbid colour codes in
function arguments.
I'm more in favour of adding ways to customize the shape of the elements
rather than adding string functions. %S(width=76,indent=4) over
%[wrap(76,4)%s%].
I feel I need to think a bit more about this; currently I'm a bit scared
by %[...%]. But first to catch some sleep..
René