Re: [Patch v2 10/17] cli: add support for batch tagging operations to notmuch tag
Hi David, overall looks good. The tag-util abstractions are paying off nicely here. First two high level bikesheds: 1) This could be split in two patches, first one adding the tag-util usage to normal operation and second one adding the batch tagging, and 2) I think it would be neater if the batch tagging was in a separate function instead of inline in the top level function. I'm not insisting though; we should probably just go with this, and the latter part can be refactored later if needed. Some minor nits inline. BR, Jani. On Sat, 24 Nov 2012, da...@tethera.net wrote: From: Jani Nikula j...@nikula.org Add support for batch tagging operations through stdin to notmuch tag. This can be enabled with the new --stdin command line option to --batch notmuch tag. The input must consist of lines of the format: +tag|-tag [...] [--] search-terms Each line is interpreted similarly to notmuch tag command line arguments. The delimiter is one or more spaces ' '. Any characters in tag and search-terms MAY be hex encoded with %NN where NN is the hexadecimal value of the character. Any ' ' and '%' characters in tag and search-terms MUST be hex encoded (using %20 and %25, respectively). Any characters that are not part of tag or search-terms MUST NOT be hex encoded. Leading and trailing space ' ' is ignored. Empty lines and lines beginning with '#' are ignored. Signed-off-by: Jani Nikula j...@nikula.org Hacked-like-crazy-by: David Bremner da...@tethera.net --- notmuch-tag.c | 194 +++-- 1 file changed, 118 insertions(+), 76 deletions(-) diff --git a/notmuch-tag.c b/notmuch-tag.c index 88d559b..8a8af0b 100644 --- a/notmuch-tag.c +++ b/notmuch-tag.c @@ -19,6 +19,7 @@ */ #include notmuch-client.h +#include tag-util.h static volatile sig_atomic_t interrupted; @@ -54,14 +55,9 @@ _escape_tag (char *buf, const char *tag) return buf; } -typedef struct { -const char *tag; -notmuch_bool_t remove; -} tag_operation_t; - static char * _optimize_tag_query (void *ctx, const char *orig_query_string, - const tag_operation_t *tag_ops) + const tag_op_list_t *list) { /* This is subtler than it looks. Xapian ignores the '-' operator * at the beginning both queries and parenthesized groups and, @@ -73,19 +69,20 @@ _optimize_tag_query (void *ctx, const char *orig_query_string, char *escaped, *query_string; const char *join = ; -int i; +size_t i; unsigned int max_tag_len = 0; /* Don't optimize if there are no tag changes. */ -if (tag_ops[0].tag == NULL) +if (tag_op_list_size (list) == 0) return talloc_strdup (ctx, orig_query_string); /* Allocate a buffer for escaping tags. This is large enough to * hold a fully escaped tag with every character doubled plus * enclosing quotes and a NUL. */ -for (i = 0; tag_ops[i].tag; i++) - if (strlen (tag_ops[i].tag) max_tag_len) - max_tag_len = strlen (tag_ops[i].tag); +for (i = 0; i tag_op_list_size (list); i++) + if (strlen (tag_op_list_tag (list, i)) max_tag_len) + max_tag_len = strlen (tag_op_list_tag (list, i)); + escaped = talloc_array (ctx, char, max_tag_len * 2 + 3); if (! escaped) return NULL; @@ -96,11 +93,11 @@ _optimize_tag_query (void *ctx, const char *orig_query_string, else query_string = talloc_asprintf (ctx, ( %s ) and (, orig_query_string); -for (i = 0; tag_ops[i].tag query_string; i++) { +for (i = 0; i tag_op_list_size (list) query_string; i++) { query_string = talloc_asprintf_append_buffer ( query_string, %s%stag:%s, join, - tag_ops[i].remove ? : not , - _escape_tag (escaped, tag_ops[i].tag)); + tag_op_list_isremove (list, i) ? : not , + _escape_tag (escaped, tag_op_list_tag (list, i))); join = or ; } @@ -116,12 +113,11 @@ _optimize_tag_query (void *ctx, const char *orig_query_string, * element. */ static int tag_query (void *ctx, notmuch_database_t *notmuch, const char *query_string, -tag_operation_t *tag_ops, notmuch_bool_t synchronize_flags) +tag_op_list_t *tag_ops, tag_op_flag_t flags) { notmuch_query_t *query; notmuch_messages_t *messages; notmuch_message_t *message; -int i; /* Optimize the query so it excludes messages that already have * the specified set of tags. */ @@ -144,21 +140,7 @@ tag_query (void *ctx, notmuch_database_t *notmuch, const char *query_string, notmuch_messages_valid (messages) ! interrupted; notmuch_messages_move_to_next (messages)) { message = notmuch_messages_get (messages); - - notmuch_message_freeze (message); - - for (i = 0; tag_ops[i].tag; i++) { - if (tag_ops[i].remove) -
[Patch v2 10/17] cli: add support for batch tagging operations to "notmuch tag"
From: Jani NikulaAdd support for batch tagging operations through stdin to "notmuch tag". This can be enabled with the new --stdin command line option to "notmuch tag". The input must consist of lines of the format: +|- [...] [--] Each line is interpreted similarly to "notmuch tag" command line arguments. The delimiter is one or more spaces ' '. Any characters in and MAY be hex encoded with %NN where NN is the hexadecimal value of the character. Any ' ' and '%' characters in and MUST be hex encoded (using %20 and %25, respectively). Any characters that are not part of or MUST NOT be hex encoded. Leading and trailing space ' ' is ignored. Empty lines and lines beginning with '#' are ignored. Signed-off-by: Jani Nikula Hacked-like-crazy-by: David Bremner --- notmuch-tag.c | 194 +++-- 1 file changed, 118 insertions(+), 76 deletions(-) diff --git a/notmuch-tag.c b/notmuch-tag.c index 88d559b..8a8af0b 100644 --- a/notmuch-tag.c +++ b/notmuch-tag.c @@ -19,6 +19,7 @@ */ #include "notmuch-client.h" +#include "tag-util.h" static volatile sig_atomic_t interrupted; @@ -54,14 +55,9 @@ _escape_tag (char *buf, const char *tag) return buf; } -typedef struct { -const char *tag; -notmuch_bool_t remove; -} tag_operation_t; - static char * _optimize_tag_query (void *ctx, const char *orig_query_string, -const tag_operation_t *tag_ops) +const tag_op_list_t *list) { /* This is subtler than it looks. Xapian ignores the '-' operator * at the beginning both queries and parenthesized groups and, @@ -73,19 +69,20 @@ _optimize_tag_query (void *ctx, const char *orig_query_string, char *escaped, *query_string; const char *join = ""; -int i; +size_t i; unsigned int max_tag_len = 0; /* Don't optimize if there are no tag changes. */ -if (tag_ops[0].tag == NULL) +if (tag_op_list_size (list) == 0) return talloc_strdup (ctx, orig_query_string); /* Allocate a buffer for escaping tags. This is large enough to * hold a fully escaped tag with every character doubled plus * enclosing quotes and a NUL. */ -for (i = 0; tag_ops[i].tag; i++) - if (strlen (tag_ops[i].tag) > max_tag_len) - max_tag_len = strlen (tag_ops[i].tag); +for (i = 0; i < tag_op_list_size (list); i++) + if (strlen (tag_op_list_tag (list, i)) > max_tag_len) + max_tag_len = strlen (tag_op_list_tag (list, i)); + escaped = talloc_array (ctx, char, max_tag_len * 2 + 3); if (! escaped) return NULL; @@ -96,11 +93,11 @@ _optimize_tag_query (void *ctx, const char *orig_query_string, else query_string = talloc_asprintf (ctx, "( %s ) and (", orig_query_string); -for (i = 0; tag_ops[i].tag && query_string; i++) { +for (i = 0; i < tag_op_list_size (list) && query_string; i++) { query_string = talloc_asprintf_append_buffer ( query_string, "%s%stag:%s", join, - tag_ops[i].remove ? "" : "not ", - _escape_tag (escaped, tag_ops[i].tag)); + tag_op_list_isremove (list, i) ? "" : "not ", + _escape_tag (escaped, tag_op_list_tag (list, i))); join = " or "; } @@ -116,12 +113,11 @@ _optimize_tag_query (void *ctx, const char *orig_query_string, * element. */ static int tag_query (void *ctx, notmuch_database_t *notmuch, const char *query_string, - tag_operation_t *tag_ops, notmuch_bool_t synchronize_flags) + tag_op_list_t *tag_ops, tag_op_flag_t flags) { notmuch_query_t *query; notmuch_messages_t *messages; notmuch_message_t *message; -int i; /* Optimize the query so it excludes messages that already have * the specified set of tags. */ @@ -144,21 +140,7 @@ tag_query (void *ctx, notmuch_database_t *notmuch, const char *query_string, notmuch_messages_valid (messages) && ! interrupted; notmuch_messages_move_to_next (messages)) { message = notmuch_messages_get (messages); - - notmuch_message_freeze (message); - - for (i = 0; tag_ops[i].tag; i++) { - if (tag_ops[i].remove) - notmuch_message_remove_tag (message, tag_ops[i].tag); - else - notmuch_message_add_tag (message, tag_ops[i].tag); - } - - notmuch_message_thaw (message); - - if (synchronize_flags) - notmuch_message_tags_to_maildir_flags (message); - + tag_op_list_apply (message, tag_ops, flags); notmuch_message_destroy (message); } @@ -170,15 +152,17 @@ tag_query (void *ctx, notmuch_database_t *notmuch, const char *query_string, int notmuch_tag_command (void *ctx, int argc, char *argv[]) { -tag_operation_t *tag_ops; -int tag_ops_count = 0; -char *query_string; +tag_op_list_t *tag_ops = NULL; +char *query_string = NULL; notmuch_config_t *config;
[Patch v2 10/17] cli: add support for batch tagging operations to notmuch tag
From: Jani Nikula j...@nikula.org Add support for batch tagging operations through stdin to notmuch tag. This can be enabled with the new --stdin command line option to notmuch tag. The input must consist of lines of the format: +tag|-tag [...] [--] search-terms Each line is interpreted similarly to notmuch tag command line arguments. The delimiter is one or more spaces ' '. Any characters in tag and search-terms MAY be hex encoded with %NN where NN is the hexadecimal value of the character. Any ' ' and '%' characters in tag and search-terms MUST be hex encoded (using %20 and %25, respectively). Any characters that are not part of tag or search-terms MUST NOT be hex encoded. Leading and trailing space ' ' is ignored. Empty lines and lines beginning with '#' are ignored. Signed-off-by: Jani Nikula j...@nikula.org Hacked-like-crazy-by: David Bremner da...@tethera.net --- notmuch-tag.c | 194 +++-- 1 file changed, 118 insertions(+), 76 deletions(-) diff --git a/notmuch-tag.c b/notmuch-tag.c index 88d559b..8a8af0b 100644 --- a/notmuch-tag.c +++ b/notmuch-tag.c @@ -19,6 +19,7 @@ */ #include notmuch-client.h +#include tag-util.h static volatile sig_atomic_t interrupted; @@ -54,14 +55,9 @@ _escape_tag (char *buf, const char *tag) return buf; } -typedef struct { -const char *tag; -notmuch_bool_t remove; -} tag_operation_t; - static char * _optimize_tag_query (void *ctx, const char *orig_query_string, -const tag_operation_t *tag_ops) +const tag_op_list_t *list) { /* This is subtler than it looks. Xapian ignores the '-' operator * at the beginning both queries and parenthesized groups and, @@ -73,19 +69,20 @@ _optimize_tag_query (void *ctx, const char *orig_query_string, char *escaped, *query_string; const char *join = ; -int i; +size_t i; unsigned int max_tag_len = 0; /* Don't optimize if there are no tag changes. */ -if (tag_ops[0].tag == NULL) +if (tag_op_list_size (list) == 0) return talloc_strdup (ctx, orig_query_string); /* Allocate a buffer for escaping tags. This is large enough to * hold a fully escaped tag with every character doubled plus * enclosing quotes and a NUL. */ -for (i = 0; tag_ops[i].tag; i++) - if (strlen (tag_ops[i].tag) max_tag_len) - max_tag_len = strlen (tag_ops[i].tag); +for (i = 0; i tag_op_list_size (list); i++) + if (strlen (tag_op_list_tag (list, i)) max_tag_len) + max_tag_len = strlen (tag_op_list_tag (list, i)); + escaped = talloc_array (ctx, char, max_tag_len * 2 + 3); if (! escaped) return NULL; @@ -96,11 +93,11 @@ _optimize_tag_query (void *ctx, const char *orig_query_string, else query_string = talloc_asprintf (ctx, ( %s ) and (, orig_query_string); -for (i = 0; tag_ops[i].tag query_string; i++) { +for (i = 0; i tag_op_list_size (list) query_string; i++) { query_string = talloc_asprintf_append_buffer ( query_string, %s%stag:%s, join, - tag_ops[i].remove ? : not , - _escape_tag (escaped, tag_ops[i].tag)); + tag_op_list_isremove (list, i) ? : not , + _escape_tag (escaped, tag_op_list_tag (list, i))); join = or ; } @@ -116,12 +113,11 @@ _optimize_tag_query (void *ctx, const char *orig_query_string, * element. */ static int tag_query (void *ctx, notmuch_database_t *notmuch, const char *query_string, - tag_operation_t *tag_ops, notmuch_bool_t synchronize_flags) + tag_op_list_t *tag_ops, tag_op_flag_t flags) { notmuch_query_t *query; notmuch_messages_t *messages; notmuch_message_t *message; -int i; /* Optimize the query so it excludes messages that already have * the specified set of tags. */ @@ -144,21 +140,7 @@ tag_query (void *ctx, notmuch_database_t *notmuch, const char *query_string, notmuch_messages_valid (messages) ! interrupted; notmuch_messages_move_to_next (messages)) { message = notmuch_messages_get (messages); - - notmuch_message_freeze (message); - - for (i = 0; tag_ops[i].tag; i++) { - if (tag_ops[i].remove) - notmuch_message_remove_tag (message, tag_ops[i].tag); - else - notmuch_message_add_tag (message, tag_ops[i].tag); - } - - notmuch_message_thaw (message); - - if (synchronize_flags) - notmuch_message_tags_to_maildir_flags (message); - + tag_op_list_apply (message, tag_ops, flags); notmuch_message_destroy (message); } @@ -170,15 +152,17 @@ tag_query (void *ctx, notmuch_database_t *notmuch, const char *query_string, int notmuch_tag_command (void *ctx, int argc, char *argv[]) { -tag_operation_t *tag_ops; -int tag_ops_count = 0; -char *query_string; +tag_op_list_t *tag_ops = NULL; +char