From: Karthik Nayak <karthik.188@gmail.com>
To: git@vger.kernel.org
Cc: christian.couder@gmail.com, Matthieu.Moy@grenoble-inp.fr,
gitster@pobox.com, Karthik Nayak <Karthik.188@gmail.com>
Subject: [PATCH v16 00/14] port tag.c to use ref-filter APIs
Date: Sun, 6 Sep 2015 00:22:01 +0530 [thread overview]
Message-ID: <1441479135-5285-1-git-send-email-Karthik.188@gmail.com> (raw)
Version 15 can be found here:
http://thread.gmane.org/gmane.comp.version-control.git/277012
Changes in this version:
* Grammatical changes.
* rename cb_data to at_end_data.
* rename align_handler() to end_align_handler() and move it
next to align_atom_handler().
* introduce match_atom_name() for checking atom names.
Karthik Nayak (14):
ref-filter: move `struct atom_value` to ref-filter.c
ref-filter: introduce ref_formatting_state and ref_formatting_stack
utf8: add function to align a string into given strbuf
ref-filter: introduce handler function for each atom
ref-filter: introduce match_atom_name()
ref-filter: implement an `align` atom
ref-filter: add option to filter out tags, branches and remotes
ref-filter: add support for %(contents:lines=X)
ref-filter: add support to sort by version
ref-filter: add option to match literal pattern
tag.c: use 'ref-filter' data structures
tag.c: use 'ref-filter' APIs
tag.c: implement '--format' option
tag.c: implement '--merged' and '--no-merged' options
Documentation/git-for-each-ref.txt | 16 +-
Documentation/git-tag.txt | 27 ++-
builtin/for-each-ref.c | 1 +
builtin/tag.c | 368 ++++++--------------------------
ref-filter.c | 415 ++++++++++++++++++++++++++++++++-----
ref-filter.h | 25 ++-
refs.c | 9 +
refs.h | 1 +
t/t6302-for-each-ref-filter.sh | 174 ++++++++++++++++
t/t7004-tag.sh | 47 ++++-
utf8.c | 21 ++
utf8.h | 15 ++
12 files changed, 743 insertions(+), 376 deletions(-)
Interdiff:
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index d039f40..c5154bb 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -128,13 +128,14 @@ color::
are described in `color.branch.*`.
align::
- Left-, middle-, or right-align the content between %(align:..)
+ Left-, middle-, or right-align the content between %(align:...)
and %(end). Followed by `:<width>,<position>`, where the
`<position>` is either left, right or middle and `<width>` is
the total length of the content with alignment. If the
contents length is more than the width then no alignment is
performed. If used with '--quote' everything in between
- %(align:..) and %(end) is quoted.
+ %(align:...) and %(end) is quoted, but if nested then only the
+ topmost level performs quoting.
In addition to the above, for commit and tag objects, the header
field names (`tree`, `parent`, `object`, `type`, and `tag`) can
diff --git a/builtin/tag.c b/builtin/tag.c
index 9fa1400..f55dfda 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -43,8 +43,8 @@ static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting, con
if (!format) {
if (filter->lines)
- format = to_free = xstrfmt("%%(align:15,left)%%(refname:short)%%(end) %%(contents:lines=%d)",
- filter->lines);
+ format = to_free = xstrfmt("%%(align:15,left)%%(refname:short)%%(end) "
+ "%%(contents:lines=%d)", filter->lines);
else
format = "%(refname:short)";
}
diff --git a/ref-filter.c b/ref-filter.c
index b37d57a..e3024d3 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -77,7 +77,7 @@ struct ref_formatting_stack {
struct ref_formatting_stack *prev;
struct strbuf output;
void (*at_end)(struct ref_formatting_stack *stack);
- void *cb_data;
+ void *at_end_data;
};
struct ref_formatting_state {
@@ -185,16 +185,6 @@ static void quote_formatting(struct strbuf *s, const char *str, int quote_style)
}
}
-static void align_handler(struct ref_formatting_stack *stack)
-{
- struct align *align = (struct align *)stack->cb_data;
- struct strbuf s = STRBUF_INIT;
-
- strbuf_utf8_align(&s, align->position, align->width, stack->output.buf);
- strbuf_swap(&stack->output, &s);
- strbuf_release(&s);
-}
-
static void append_atom(struct atom_value *v, struct ref_formatting_state *state)
{
/*
@@ -230,14 +220,24 @@ static void pop_stack_element(struct ref_formatting_stack **stack)
*stack = prev;
}
+static void end_align_handler(struct ref_formatting_stack *stack)
+{
+ struct align *align = (struct align *)stack->at_end_data;
+ struct strbuf s = STRBUF_INIT;
+
+ strbuf_utf8_align(&s, align->position, align->width, stack->output.buf);
+ strbuf_swap(&stack->output, &s);
+ strbuf_release(&s);
+}
+
static void align_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state)
{
struct ref_formatting_stack *new;
push_stack_element(&state->stack);
new = state->stack;
- new->at_end = align_handler;
- new->cb_data = &atomv->u.align;
+ new->at_end = end_align_handler;
+ new->at_end_data = &atomv->u.align;
}
static void end_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state)
@@ -246,12 +246,13 @@ static void end_atom_handler(struct atom_value *atomv, struct ref_formatting_sta
struct strbuf s = STRBUF_INIT;
if (!current->at_end)
- die(_("format: `end` atom used without a supporting atom"));
+ die(_("format: %%(end) atom used without corresponding atom"));
current->at_end(current);
/*
* Perform quote formatting when the stack element is that of
- * a modifier atom and right above the first stack element.
+ * a supporting atom. If nested then perform quote formatting
+ * only on the topmost supporting atom.
*/
if (!state->stack->prev->prev) {
quote_formatting(&s, current->output.buf, state->quote_style);
@@ -261,6 +262,22 @@ static void end_atom_handler(struct atom_value *atomv, struct ref_formatting_sta
pop_stack_element(&state->stack);
}
+static int match_atom_name(const char *name, const char *atom_name, const char **val)
+{
+ const char *body;
+
+ if (!skip_prefix(name, atom_name, &body))
+ return 0; /* doesn't even begin with "atom_name" */
+ if (!body[0] || !body[1]) {
+ *val = NULL; /* %(atom_name) and no customization */
+ return 1;
+ }
+ if (body[0] != ':')
+ return 0; /* "atom_namefoo" is not "atom_name" or "atom_name:..." */
+ *val = body + 1; /* "atomname:val" */
+ return 1;
+}
+
/*
* In a format string, find the next occurrence of %(atom).
*/
@@ -645,9 +662,6 @@ static void append_lines(struct strbuf *out, const char *buf, unsigned long size
const char *sp, *eol;
size_t len;
- if ((sp = strstr(buf, "\n\n")) && (sp <= buf + size))
- size += 2;
-
sp = buf;
for (i = 0; i < lines && sp < buf + size; i++) {
@@ -705,9 +719,12 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, struct obj
v->s = xstrdup(subpos);
else if (skip_prefix(name, "contents:lines=", &valp)) {
struct strbuf s = STRBUF_INIT;
+ const char *contents_end = bodylen + bodypos - siglen;
+
if (strtoul_ui(valp, 10, &v->u.contents.lines))
- die(_("positive width expected contents:lines=%s"), valp);
- append_lines(&s, subpos, sublen + bodylen - siglen, v->u.contents.lines);
+ die(_("positive value expected contents:lines=%s"), valp);
+ /* Size is the length of the message after removing the signature */
+ append_lines(&s, subpos, contents_end - subpos, v->u.contents.lines);
v->s = strbuf_detach(&s, NULL);
}
}
@@ -830,10 +847,12 @@ static void populate_value(struct ref_array_item *ref)
refname = branch_get_push(branch, NULL);
if (!refname)
continue;
- } else if (starts_with(name, "color:")) {
+ } else if (match_atom_name(name, "color", &valp)) {
char color[COLOR_MAXLEN] = "";
- if (color_parse(name + 6, color) < 0)
+ if (!valp)
+ die(_("expected format: %%(color:<color>)"));
+ if (color_parse(valp, color) < 0)
die(_("unable to parse format"));
v->s = xstrdup(color);
continue;
@@ -863,24 +882,32 @@ static void populate_value(struct ref_array_item *ref)
else
v->s = " ";
continue;
- } else if (skip_prefix(name, "align", &valp)) {
+ } else if (match_atom_name(name, "align", &valp)) {
struct align *align = &v->u.align;
struct strbuf **s;
- if (valp[0] != ':')
- die(_("format: usage %%(align:<width>,<position>)"));
- else
- valp++;
+ if (!valp)
+ die(_("expected format: %%(align:<width>, <position>)"));
+ /*
+ * TODO: Implement a function similar to strbuf_split_str()
+ * which would strip the terminator at the end.
+ */
s = strbuf_split_str(valp, ',', 0);
/* If the position is given trim the ',' from the first strbuf */
if (s[1])
strbuf_setlen(s[0], s[0]->len - 1);
+ if (s[2])
+ die(_("align:<width>,<position> followed by garbage: %s"), s[2]->buf);
if (strtoul_ui(s[0]->buf, 10, &align->width))
die(_("positive width expected align:%s"), s[0]->buf);
+ /*
+ * TODO: Implement a more general check, so that the values
+ * do not always have to be in a specific order.
+ */
if (!s[1])
align->position = ALIGN_LEFT;
else if (!strcmp(s[1]->buf, "left"))
@@ -1294,11 +1321,7 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,
return 0;
}
- /*
- * Get the current ref kind. If we're filtering tags, remotes or local branches
- * only then the current ref-kind is nothing but filter->kind and filter_ref_kind()
- * will only return that value.
- */
+ /* Obtain the current ref kind from filter_ref_kind() and ignore unwanted refs. */
kind = filter_ref_kind(filter, refname);
if (!(kind & filter->kind))
return 0;
@@ -1424,6 +1447,12 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int
if (!filter->kind)
die("filter_refs: invalid type");
else {
+ /*
+ * For common cases where we need only branches or remotes or tags,
+ * we only iterate through those refs. If a mix of refs is needed,
+ * we iterate over all refs and filter out required refs with the help
+ * of filter_ref_kind().
+ */
if (filter->kind == FILTER_REFS_BRANCHES)
ret = for_each_fullref_in("refs/heads/", ref_filter_handler, &ref_cbdata, broken);
else if (filter->kind == FILTER_REFS_REMOTES)
@@ -1561,7 +1590,7 @@ void show_ref_array_item(struct ref_array_item *info, const char *format, int qu
append_atom(&resetv, &state);
}
if (state.stack->prev)
- die(_("format: `end` atom missing"));
+ die(_("format: %%(end) atom missing"));
final_buf = &state.stack->output;
fwrite(final_buf->buf, 1, final_buf->len, stdout);
pop_stack_element(&state.stack);
diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
index d95b781..4bc1055 100755
--- a/t/t6302-for-each-ref-filter.sh
+++ b/t/t6302-for-each-ref-filter.sh
@@ -81,6 +81,10 @@ test_expect_success 'filtering with --contains' '
test_cmp expect actual
'
+test_expect_success '%(color) must fail' '
+ test_must_fail git for-each-ref --format="%(color)%(refname)"
+'
+
test_expect_success 'left alignment' '
cat >expect <<-\EOF &&
refname is refs/heads/master |refs/heads/master
@@ -129,42 +133,39 @@ test_expect_success 'right alignment' '
test_cmp expect actual
'
-# Everything in between the %(align)...%(end) atom must be quoted, hence we test this by
-# introducing single quote's in %(align)...%(end), which must not be escaped.
-
-sq="'"
+# Individual atoms inside %(align:...) and %(end) must not be quoted.
-test_expect_success 'alignment with format quote' '
- cat >expect <<-EOF &&
- refname is ${sq} ${sq}\\${sq}${sq}master${sq}\\${sq}${sq} ${sq}|
- refname is ${sq} ${sq}\\${sq}${sq}side${sq}\\${sq}${sq} ${sq}|
- refname is ${sq} ${sq}\\${sq}${sq}odd/spot${sq}\\${sq}${sq} ${sq}|
- refname is ${sq} ${sq}\\${sq}${sq}double-tag${sq}\\${sq}${sq} ${sq}|
- refname is ${sq} ${sq}\\${sq}${sq}four${sq}\\${sq}${sq} ${sq}|
- refname is ${sq} ${sq}\\${sq}${sq}one${sq}\\${sq}${sq} ${sq}|
- refname is ${sq} ${sq}\\${sq}${sq}signed-tag${sq}\\${sq}${sq} ${sq}|
- refname is ${sq} ${sq}\\${sq}${sq}three${sq}\\${sq}${sq} ${sq}|
- refname is ${sq} ${sq}\\${sq}${sq}two${sq}\\${sq}${sq} ${sq}|
+test_expect_success 'alignment with format quote' "
+ cat >expect <<-\EOF &&
+ |' master| A U Thor '|
+ |' side| A U Thor '|
+ |' odd/spot| A U Thor '|
+ |' double-tag| '|
+ |' four| A U Thor '|
+ |' one| A U Thor '|
+ |' signed-tag| '|
+ |' three| A U Thor '|
+ |' two| A U Thor '|
EOF
- git for-each-ref --shell --format="refname is %(align:30,middle)${sq}%(refname:short)${sq}%(end)|" >actual &&
+ git for-each-ref --shell --format='|%(align:30,middle)%(refname:short)| %(authorname)%(end)|' >actual &&
test_cmp expect actual
-'
+"
-test_expect_success 'nested alignment' '
+test_expect_success 'nested alignment with quote formatting' "
cat >expect <<-\EOF &&
- | master |
- | side |
- | odd/spot |
- | double-tag |
- | four |
- | one |
- | signed-tag |
- | three |
- | two |
+ |' master '|
+ |' side '|
+ |' odd/spot '|
+ |' double-tag '|
+ |' four '|
+ |' one '|
+ |' signed-tag '|
+ |' three '|
+ |' two '|
EOF
- git for-each-ref --format="|%(align:30,left)%(align:15,right)%(refname:short)%(end)%(end)|" >actual &&
+ git for-each-ref --shell --format='|%(align:30,left)%(align:15,right)%(refname:short)%(end)%(end)|' >actual &&
test_cmp expect actual
-'
+"
test_expect_success 'check `%(contents:lines=1)`' '
cat >expect <<-\EOF &&
--
2.5.1
next reply other threads:[~2015-09-05 18:52 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-09-05 18:52 Karthik Nayak [this message]
2015-09-05 18:52 ` [PATCH v16 01/14] ref-filter: move `struct atom_value` to ref-filter.c Karthik Nayak
2015-09-05 18:52 ` [PATCH v16 02/14] ref-filter: introduce ref_formatting_state and ref_formatting_stack Karthik Nayak
2015-09-05 18:52 ` [PATCH v16 03/14] utf8: add function to align a string into given strbuf Karthik Nayak
2015-09-05 18:52 ` [PATCH v16 04/14] ref-filter: introduce handler function for each atom Karthik Nayak
2015-09-05 18:52 ` [PATCH v16 05/14] ref-filter: introduce match_atom_name() Karthik Nayak
2015-09-06 19:52 ` Eric Sunshine
2015-09-07 18:07 ` Karthik Nayak
2015-09-05 18:52 ` [PATCH v16 06/14] ref-filter: implement an `align` atom Karthik Nayak
2015-09-06 20:10 ` Eric Sunshine
2015-09-07 18:26 ` Karthik Nayak
2015-09-05 18:52 ` [PATCH v16 07/14] ref-filter: add option to filter out tags, branches and remotes Karthik Nayak
2015-09-05 18:52 ` [PATCH v16 08/14] ref-filter: add support for %(contents:lines=X) Karthik Nayak
2015-09-05 18:52 ` [PATCH v16 09/14] ref-filter: add support to sort by version Karthik Nayak
2015-09-05 18:52 ` [PATCH v16 10/14] ref-filter: add option to match literal pattern Karthik Nayak
2015-09-05 18:52 ` [PATCH v16 11/14] tag.c: use 'ref-filter' data structures Karthik Nayak
2015-09-05 18:52 ` [PATCH v16 12/14] tag.c: use 'ref-filter' APIs Karthik Nayak
2015-09-05 18:52 ` [PATCH v16 13/14] tag.c: implement '--format' option Karthik Nayak
2015-09-05 18:52 ` [PATCH v16 14/14] tag.c: implement '--merged' and '--no-merged' options Karthik Nayak
2015-09-06 18:49 ` [PATCH v16 00/14] port tag.c to use ref-filter APIs Matthieu Moy
2015-09-06 19:16 ` Karthik Nayak
2015-09-07 6:33 ` Junio C Hamano
2015-09-07 6:42 ` Matthieu Moy
2015-09-07 13:56 ` Karthik Nayak
2015-09-07 14:05 ` Matthieu Moy
2015-09-08 5:43 ` Karthik Nayak
2015-09-08 18:20 ` Junio C Hamano
2015-09-09 17:37 ` Karthik Nayak
2015-09-09 19:18 ` Junio C Hamano
2015-09-08 18:20 ` Junio C Hamano
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=1441479135-5285-1-git-send-email-Karthik.188@gmail.com \
--to=karthik.188@gmail.com \
--cc=Matthieu.Moy@grenoble-inp.fr \
--cc=christian.couder@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).