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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.