[PATCH v4 0/6] Move --no-exclude to --exclude=(true|false|flag)

2012-04-07 Thread Mark Walters
This is version 4 of the exclude= patch set. Version 3 was at [1].

The only changes relative to version 3 are in the tests. As suggested
by jrollins [2] I have added some systematic count and show tests and
moved all the exclude tests to the file test/excludes.

Best wishes

Mark

[1] id:"1333716551-29153-1-git-send-email-markwalters1...@gmail.com"
[2] id:"877gxs7ryv@servo.finestructure.net"

Mark Walters (6):
  lib: change default for notmuch_query_set_omit_excluded
  cli: move count to the new --exclude=(true|false|flag) naming scheme.
  cli: move search to the new --exclude= naming scheme.
  cli: move show to the new --exclude= option naming scheme.
  test: add some exclude tests
  emacs: make show set --exclude=false

 emacs/notmuch-show.el |6 +-
 lib/notmuch.h |   23 ++-
 lib/query.cc  |   10 +-
 man/man1/notmuch-count.1  |5 +-
 man/man1/notmuch-search.1 |   12 +-
 man/man1/notmuch-show.1   |   16 ++-
 notmuch-client.h  |1 +
 notmuch-count.c   |   17 ++-
 notmuch-search.c  |   32 +++-
 notmuch-show.c|   50 --
 test/count|   21 ---
 test/excludes |  423 +
 test/notmuch-test |1 +
 test/search   |   48 -
 14 files changed, 544 insertions(+), 121 deletions(-)
 create mode 100755 test/excludes

-- 
1.7.9.1

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH v4 1/6] lib: change default for notmuch_query_set_omit_excluded

2012-04-07 Thread Mark Walters
---
 lib/notmuch.h |   23 ++-
 lib/query.cc  |   10 +-
 2 files changed, 23 insertions(+), 10 deletions(-)

diff --git a/lib/notmuch.h b/lib/notmuch.h
index babd208..673c423 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -449,12 +449,25 @@ typedef enum {
 const char *
 notmuch_query_get_query_string (notmuch_query_t *query);
 
-/* Specify whether to results should omit the excluded results rather
- * than just marking them excluded. This is useful for passing a
- * notmuch_messages_t not containing the excluded messages to other
- * functions. */
+/* Specify whether to omit excluded results or simply flag them.  By
+ * default, this is set to TRUE.
+ *
+ * If this is TRUE, notmuch_query_search_messages will omit excluded
+ * messages from the results.  notmuch_query_search_threads will omit
+ * threads that match only in excluded messages, but will include all
+ * messages in threads that match in at least one non-excluded
+ * message.
+ *
+ * The performance difference when calling
+ * notmuch_query_search_messages should be relatively small (and both
+ * should be very fast).  However, in some cases,
+ * notmuch_query_search_threads is very much faster when omitting
+ * excluded messages as it does not need to construct the threads that
+ * only match in excluded messages.
+ */
+
 void
-notmuch_query_set_omit_excluded_messages (notmuch_query_t *query, 
notmuch_bool_t omit);
+notmuch_query_set_omit_excluded (notmuch_query_t *query, notmuch_bool_t 
omit_excluded);
 
 /* Specify the sorting desired for this query. */
 void
diff --git a/lib/query.cc b/lib/query.cc
index 68ac1e4..e9c1a2d 100644
--- a/lib/query.cc
+++ b/lib/query.cc
@@ -28,7 +28,7 @@ struct _notmuch_query {
 const char *query_string;
 notmuch_sort_t sort;
 notmuch_string_list_t *exclude_terms;
-notmuch_bool_t omit_excluded_messages;
+notmuch_bool_t omit_excluded;
 };
 
 typedef struct _notmuch_mset_messages {
@@ -92,7 +92,7 @@ notmuch_query_create (notmuch_database_t *notmuch,
 
 query->exclude_terms = _notmuch_string_list_create (query);
 
-query->omit_excluded_messages = FALSE;
+query->omit_excluded = TRUE;
 
 return query;
 }
@@ -104,9 +104,9 @@ notmuch_query_get_query_string (notmuch_query_t *query)
 }
 
 void
-notmuch_query_set_omit_excluded_messages (notmuch_query_t *query, 
notmuch_bool_t omit)
+notmuch_query_set_omit_excluded (notmuch_query_t *query, notmuch_bool_t 
omit_excluded)
 {
-query->omit_excluded_messages = omit;
+query->omit_excluded = omit_excluded;
 }
 
 void
@@ -220,7 +220,7 @@ notmuch_query_search_messages (notmuch_query_t *query)
if (query->exclude_terms) {
exclude_query = _notmuch_exclude_tags (query, final_query);
 
-   if (query->omit_excluded_messages)
+   if (query->omit_excluded)
final_query = Xapian::Query (Xapian::Query::OP_AND_NOT,
 final_query, exclude_query);
else {
-- 
1.7.9.1

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH v4 2/6] cli: move count to the new --exclude=(true|false|flag) naming scheme.

2012-04-07 Thread Mark Walters
Move the option --no-exclude to the --exclude= scheme. Since there is
no way to flag messages only true and false are implemented. Note
that, for consistency with other commands, this is implemented as a
keyword option rather than a boolean option.
---
 man/man1/notmuch-count.1 |5 +++--
 notmuch-count.c  |   17 -
 test/count   |4 ++--
 3 files changed, 17 insertions(+), 9 deletions(-)

diff --git a/man/man1/notmuch-count.1 b/man/man1/notmuch-count.1
index 35ecc53..d6cbf07 100644
--- a/man/man1/notmuch-count.1
+++ b/man/man1/notmuch-count.1
@@ -41,9 +41,10 @@ Output the number of matching threads.
 
 .RS 4
 .TP 4
-.BR \-\-no\-exclude
+.BR \-\-exclude=(true|false)
 
-Do not exclude the messages matching search.exclude_tags in the config file.
+Specify whether to omit messages matching search.tag_exclude from the
+count (the default) or not.
 .RE
 .RE
 .RE
diff --git a/notmuch-count.c b/notmuch-count.c
index 46b76ae..b76690c 100644
--- a/notmuch-count.c
+++ b/notmuch-count.c
@@ -26,6 +26,12 @@ enum {
 OUTPUT_MESSAGES,
 };
 
+/* The following is to allow future options to be added more easily */
+enum {
+EXCLUDE_TRUE,
+EXCLUDE_FALSE,
+};
+
 int
 notmuch_count_command (void *ctx, int argc, char *argv[])
 {
@@ -35,7 +41,7 @@ notmuch_count_command (void *ctx, int argc, char *argv[])
 char *query_str;
 int opt_index;
 int output = OUTPUT_MESSAGES;
-notmuch_bool_t no_exclude = FALSE;
+int exclude = EXCLUDE_TRUE;
 unsigned int i;
 
 notmuch_opt_desc_t options[] = {
@@ -43,7 +49,10 @@ notmuch_count_command (void *ctx, int argc, char *argv[])
  (notmuch_keyword_t []){ { "threads", OUTPUT_THREADS },
  { "messages", OUTPUT_MESSAGES },
  { 0, 0 } } },
-   { NOTMUCH_OPT_BOOLEAN, &no_exclude, "no-exclude", 'd', 0 },
+   { NOTMUCH_OPT_KEYWORD, &exclude, "exclude", 'x',
+ (notmuch_keyword_t []){ { "true", EXCLUDE_TRUE },
+ { "false", EXCLUDE_FALSE },
+ { 0, 0 } } },
{ 0, 0, 0, 0, 0 }
 };
 
@@ -78,7 +87,7 @@ notmuch_count_command (void *ctx, int argc, char *argv[])
return 1;
 }
 
-if (!no_exclude) {
+if (exclude == EXCLUDE_TRUE) {
const char **search_exclude_tags;
size_t search_exclude_tags_length;
 
@@ -88,8 +97,6 @@ notmuch_count_command (void *ctx, int argc, char *argv[])
notmuch_query_add_tag_exclude (query, search_exclude_tags[i]);
 }
 
-notmuch_query_set_omit_excluded_messages (query, TRUE);
-
 switch (output) {
 case OUTPUT_MESSAGES:
printf ("%u\n", notmuch_query_count_messages (query));
diff --git a/test/count b/test/count
index b97fc06..fd387e5 100755
--- a/test/count
+++ b/test/count
@@ -53,9 +53,9 @@ test_expect_equal \
 "1" \
 "`notmuch count subject:deleted and tag:deleted`"
 
-test_begin_subtest "count \"deleted\" messages, with --no-exclude"
+test_begin_subtest "count \"deleted\" messages, --exclude=false"
 test_expect_equal \
 "3" \
-"`notmuch count --no-exclude subject:deleted`"
+"`notmuch count --exclude=false subject:deleted`"
 
 test_done
-- 
1.7.9.1

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH v4 3/6] cli: move search to the new --exclude= naming scheme.

2012-04-07 Thread Mark Walters
This commit replaces the --no-exclude option with a
--exclude=(true|false|flag) option. The default is to omit the
excluded messages.

The flag option only makes sense if output=summary (as otherwise there
is nowhere to print the flag). In summary output exclude=false and
exclude=flag give almost identical output:
they differ in that with the exclude=flag option the match count
(i.e., the x in [x/n] in the output) is the number of matching
non-excluded messages rather than the number of matching messages.

Note this changes the default for output=summary when no --exclude=
option is given: it used to default to flag and now defaults to true
(i.e. omit excluded messages). This is neccesary to keep the cli
output uncluttered and for speed reasons.
---
 man/man1/notmuch-search.1 |   12 +---
 notmuch-search.c  |   32 +++-
 2 files changed, 32 insertions(+), 12 deletions(-)

diff --git a/man/man1/notmuch-search.1 b/man/man1/notmuch-search.1
index 06d81a6..ebb61fc 100644
--- a/man/man1/notmuch-search.1
+++ b/man/man1/notmuch-search.1
@@ -114,9 +114,15 @@ Limit the number of displayed results to N.
 
 .RS 4
 .TP 4
-.BR \-\-no\-exclude
-
-Do not exclude the messages matching search.exclude_tags in the config file.
+.BR \-\-exclude=(true|false|flag)
+
+Specify whether to omit messages matching search.tag_exclude from the
+search results (the default) or not. The extra option
+.B flag
+only has an effect when
+.B --output=summary
+In this case all matching threads are returned but the "match count"
+is the number of matching non-excluded messages in the thread.
 .RE
 
 .SH SEE ALSO
diff --git a/notmuch-search.c b/notmuch-search.c
index f6061e4..1cc8430 100644
--- a/notmuch-search.c
+++ b/notmuch-search.c
@@ -210,9 +210,6 @@ do_search_threads (const search_format_t *format,
 int first_thread = 1;
 int i;
 
-if (output == OUTPUT_THREADS)
-   notmuch_query_set_omit_excluded_messages (query, TRUE);
-
 if (offset < 0) {
offset += notmuch_query_count_threads (query);
if (offset < 0)
@@ -303,8 +300,6 @@ do_search_messages (const search_format_t *format,
 int first_message = 1;
 int i;
 
-notmuch_query_set_omit_excluded_messages (query, TRUE);
-
 if (offset < 0) {
offset += notmuch_query_count_messages (query);
if (offset < 0)
@@ -376,7 +371,6 @@ do_search_tags (notmuch_database_t *notmuch,
 const char *tag;
 int first_tag = 1;
 
-notmuch_query_set_omit_excluded_messages (query, TRUE);
 /* should the following only special case if no excluded terms
  * specified? */
 
@@ -422,6 +416,12 @@ do_search_tags (notmuch_database_t *notmuch,
 return 0;
 }
 
+enum {
+EXCLUDE_TRUE,
+EXCLUDE_FALSE,
+EXCLUDE_FLAG,
+};
+
 int
 notmuch_search_command (void *ctx, int argc, char *argv[])
 {
@@ -435,7 +435,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
 output_t output = OUTPUT_SUMMARY;
 int offset = 0;
 int limit = -1; /* unlimited */
-notmuch_bool_t no_exclude = FALSE;
+int exclude = EXCLUDE_TRUE;
 unsigned int i;
 
 enum { NOTMUCH_FORMAT_JSON, NOTMUCH_FORMAT_TEXT }
@@ -457,7 +457,11 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
  { "files", OUTPUT_FILES },
  { "tags", OUTPUT_TAGS },
  { 0, 0 } } },
-   { NOTMUCH_OPT_BOOLEAN, &no_exclude, "no-exclude", 'd', 0 },
+{ NOTMUCH_OPT_KEYWORD, &exclude, "exclude", 'x',
+  (notmuch_keyword_t []){ { "true", EXCLUDE_TRUE },
+  { "false", EXCLUDE_FALSE },
+  { "flag", EXCLUDE_FLAG },
+  { 0, 0 } } },
{ NOTMUCH_OPT_INT, &offset, "offset", 'O', 0 },
{ NOTMUCH_OPT_INT, &limit, "limit", 'L', 0  },
{ 0, 0, 0, 0, 0 }
@@ -505,7 +509,15 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
 
 notmuch_query_set_sort (query, sort);
 
-if (!no_exclude) {
+if (exclude == EXCLUDE_FLAG && output != OUTPUT_SUMMARY) {
+   /* If we are not doing summary output there is nowhere to
+* print the excluded flag so fall back on including the
+* excluded messages. */
+   fprintf (stderr, "Warning: this output format cannot flag excluded 
messages.\n");
+   exclude = EXCLUDE_FALSE;
+}
+
+if (exclude == EXCLUDE_TRUE || exclude == EXCLUDE_FLAG) {
const char **search_exclude_tags;
size_t search_exclude_tags_length;
 
@@ -513,6 +525,8 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
(config, &search_exclude_tags_length);
for (i = 0; i < search_exclude_tags_length; i++)
notmuch_query_add_tag_exclude (query, search_exclude_tags[i]);
+   if (exclude == EXCLUDE_FLAG)
+   notmuch_query_set_omit_excluded (query, FALSE);
 }
 
 switch (output) {
-- 
1.7.9.1


[PATCH v4 4/6] cli: move show to the new --exclude= option naming scheme.

2012-04-07 Thread Mark Walters
This moves notmuch show to the --exclude=(true|false) naming
scheme. When exclude=false show returns all threads that match
including those that only match in an excluded message. The excluded
messages are flagged.

When exclude=true the behaviour depends on whether --entire-thread is
set. If it is not set then show only returns the messages which match
and are not excluded. If it is set then show returns all messages in
the threads that match in a non-excluded message, flagging the excluded
messages in these threads. The rationale is that it is awkward to use
a thread with some missing messages.
---
 man/man1/notmuch-show.1 |   16 +-
 notmuch-client.h|1 +
 notmuch-show.c  |   50 +-
 3 files changed, 46 insertions(+), 21 deletions(-)

diff --git a/man/man1/notmuch-show.1 b/man/man1/notmuch-show.1
index b81cce6..83cc575 100644
--- a/man/man1/notmuch-show.1
+++ b/man/man1/notmuch-show.1
@@ -135,9 +135,21 @@ content.
 
 .RS 4
 .TP 4
-.B \-\-no-exclude
+.BR \-\-exclude=(true|false)
+
+Specify whether to omit threads only matching search.tag_exclude from
+the search results (the default) or not. In either case the excluded
+message will be marked with the exclude flag (except when output=mbox
+when there is nowhere to put the flag).
+
+If --entire-thread is specified then complete threads are returned
+regardless (with the excluded flag being set when appropriate) but
+threads that only match in an excluded message are not returned when
+.B --exclude=true.
+
+The default is
+.B --exclude=true.
 
-Do not exclude the messages matching search.exclude_tags in the config file.
 .RE
 
 A common use of
diff --git a/notmuch-client.h b/notmuch-client.h
index 203ac49..880b153 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -99,6 +99,7 @@ typedef struct notmuch_show_format {
 
 typedef struct notmuch_show_params {
 notmuch_bool_t entire_thread;
+notmuch_bool_t omit_excluded;
 notmuch_bool_t raw;
 int part;
 #ifdef GMIME_ATLEAST_26
diff --git a/notmuch-show.c b/notmuch-show.c
index 0bf5e21..7af8e64 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -866,6 +866,7 @@ show_messages (void *ctx,
 {
 notmuch_message_t *message;
 notmuch_bool_t match;
+notmuch_bool_t excluded;
 int first_set = 1;
 int next_indent;
 notmuch_status_t status, res = NOTMUCH_STATUS_SUCCESS;
@@ -885,10 +886,11 @@ show_messages (void *ctx,
message = notmuch_messages_get (messages);
 
match = notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_MATCH);
+   excluded = notmuch_message_get_flag (message, 
NOTMUCH_MESSAGE_FLAG_EXCLUDED);
 
next_indent = indent;
 
-   if (match || params->entire_thread) {
+   if ((match && (!excluded || !params->omit_excluded)) || 
params->entire_thread) {
status = show_message (ctx, format, message, indent, params);
if (status && !res)
res = status;
@@ -996,6 +998,12 @@ enum {
 NOTMUCH_FORMAT_RAW
 };
 
+/* The following is to allow future options to be added more easily */
+enum {
+EXCLUDE_TRUE,
+EXCLUDE_FALSE,
+};
+
 int
 notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[]))
 {
@@ -1005,10 +1013,10 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
 char *query_string;
 int opt_index, ret;
 const notmuch_show_format_t *format = &format_text;
-notmuch_show_params_t params = { .part = -1 };
+notmuch_show_params_t params = { .part = -1, .omit_excluded = TRUE };
 int format_sel = NOTMUCH_FORMAT_NOT_SPECIFIED;
 notmuch_bool_t verify = FALSE;
-notmuch_bool_t no_exclude = FALSE;
+int exclude = EXCLUDE_TRUE;
 
 notmuch_opt_desc_t options[] = {
{ NOTMUCH_OPT_KEYWORD, &format_sel, "format", 'f',
@@ -1017,11 +1025,14 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
  { "mbox", NOTMUCH_FORMAT_MBOX },
  { "raw", NOTMUCH_FORMAT_RAW },
  { 0, 0 } } },
+{ NOTMUCH_OPT_KEYWORD, &exclude, "exclude", 'x',
+  (notmuch_keyword_t []){ { "true", EXCLUDE_TRUE },
+  { "false", EXCLUDE_FALSE },
+  { 0, 0 } } },
{ NOTMUCH_OPT_INT, ¶ms.part, "part", 'p', 0 },
{ NOTMUCH_OPT_BOOLEAN, ¶ms.entire_thread, "entire-thread", 't', 0 },
{ NOTMUCH_OPT_BOOLEAN, ¶ms.decrypt, "decrypt", 'd', 0 },
{ NOTMUCH_OPT_BOOLEAN, &verify, "verify", 'v', 0 },
-   { NOTMUCH_OPT_BOOLEAN, &no_exclude, "no-exclude", 'n', 0 },
{ 0, 0, 0, 0, 0 }
 };
 
@@ -1110,29 +1121,30 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
return 1;
 }
 
-/* if format=mbox then we can not output excluded messages as
- * there is no way to make the exclude flag available */
-if (format_sel == NO

[PATCH v4 5/6] test: add some exclude tests

2012-04-07 Thread Mark Walters
Systematically test the exclude options for search. Also move the
search existing exclude tests into the new test. There is some overlap
between the two sets of tests but many of the existing ones are there
because they triggered bugs in the past so I have kept them to ensure
coverage.
---
 test/count|   21 ---
 test/excludes |  423 +
 test/notmuch-test |1 +
 test/search   |   48 --
 4 files changed, 424 insertions(+), 69 deletions(-)
 create mode 100755 test/excludes

diff --git a/test/count b/test/count
index fd387e5..300b171 100755
--- a/test/count
+++ b/test/count
@@ -37,25 +37,4 @@ test_expect_equal \
 "0" \
 "`notmuch count --output=threads ${SEARCH}`"
 
-test_begin_subtest "count excluding \"deleted\" messages"
-notmuch config set search.exclude_tags deleted
-generate_message '[subject]="Not deleted"'
-generate_message '[subject]="Another not deleted"'
-generate_message '[subject]="Deleted"'
-notmuch new > /dev/null
-notmuch tag +deleted id:$gen_msg_id
-test_expect_equal \
-"2" \
-"`notmuch count subject:deleted`"
-
-test_begin_subtest "count \"deleted\" messages, exclude overridden"
-test_expect_equal \
-"1" \
-"`notmuch count subject:deleted and tag:deleted`"
-
-test_begin_subtest "count \"deleted\" messages, --exclude=false"
-test_expect_equal \
-"3" \
-"`notmuch count --exclude=false subject:deleted`"
-
 test_done
diff --git a/test/excludes b/test/excludes
new file mode 100755
index 000..24d653e
--- /dev/null
+++ b/test/excludes
@@ -0,0 +1,423 @@
+#!/usr/bin/env bash
+test_description='"notmuch search, count and show" with excludes in several 
variations'
+. ./test-lib.sh
+
+# Generates a thread consisting of a top level message and 'length'
+# replies. The subject of the top message 'subject: top message"
+# and the subject of the nth reply in the thread is "subject: reply n"
+generate_thread ()
+{
+local subject="$1"
+local length="$2"
+generate_message '[subject]="'"${subject}: top message"'"' '[body]="'"body 
of top message"'"'
+parent_id=$gen_msg_id
+gen_thread_msg_id[0]=$gen_msg_id
+for i in `seq 1 $length`
+do
+   generate_message '[subject]="'"${subject}: reply $i"'"' \
+"[in-reply-to]=\<$parent_id\>" \
+'[body]="'"body of reply $i"'"'
+   gen_thread_msg_id[$i]=$gen_msg_id
+   parent_id=$gen_msg_id
+done
+notmuch new > /dev/null
+# We cannot retrieve the thread_id until after we have run notmuch new.
+gen_thread_id=`notmuch search --output=threads id:${gen_thread_msg_id[0]}`
+}
+
+#
+# These are the original search exclude tests.
+
+test_begin_subtest "Search, exclude \"deleted\" messages from search"
+notmuch config set search.exclude_tags deleted
+generate_message '[subject]="Not deleted"'
+not_deleted_id=$gen_msg_id
+generate_message '[subject]="Deleted"'
+notmuch new > /dev/null
+notmuch tag +deleted id:$gen_msg_id
+deleted_id=$gen_msg_id
+output=$(notmuch search subject:deleted | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; 
Not deleted (inbox unread)"
+
+test_begin_subtest "Search, exclude \"deleted\" messages from message search"
+output=$(notmuch search --output=messages subject:deleted | 
notmuch_search_sanitize)
+test_expect_equal "$output" "id:$not_deleted_id"
+
+test_begin_subtest "Search, exclude \"deleted\" messages from message search 
--exclude=false"
+output=$(notmuch search --exclude=false --output=messages subject:deleted | 
notmuch_search_sanitize)
+test_expect_equal "$output" "id:$not_deleted_id
+id:$deleted_id"
+
+test_begin_subtest "Search, exclude \"deleted\" messages from message search 
(non-existent exclude-tag)"
+notmuch config set search.exclude_tags deleted non_existent_tag
+output=$(notmuch search --output=messages subject:deleted | 
notmuch_search_sanitize)
+test_expect_equal "$output" "id:$not_deleted_id"
+notmuch config set search.exclude_tags deleted
+
+test_begin_subtest "Search, exclude \"deleted\" messages from search, 
overridden"
+output=$(notmuch search subject:deleted and tag:deleted | 
notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; 
Deleted (deleted inbox unread)"
+
+test_begin_subtest "Search, exclude \"deleted\" messages from threads"
+add_message '[subject]="Not deleted reply"' '[in-reply-to]="<$gen_msg_id>"'
+output=$(notmuch search subject:deleted | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; 
Not deleted (inbox unread)
+thread:XXX   2001-01-05 [1/2] Notmuch Test Suite; Not deleted reply (deleted 
inbox unread)"
+
+test_begin_subtest "Search, don't exclude \"deleted\" messages when 
--exclude=flag specified"
+output=$(notmuch search --exclude=flag subject:deleted | 
notmuch_search_sanitize)
+test_expect_equal 

[PATCH v4 6/6] emacs: make show set --exclude=false

2012-04-07 Thread Mark Walters
Show has to set --exclude=false to deal with cases where it is asked
to show a single excluded message. It uses JSON so it can easily pass
the exclude information to the user.
---
 emacs/notmuch-show.el |6 --
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 6d3fe62..30b26d1 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -1060,13 +1060,15 @@ function is used."
   (append (list "\'") basic-args
   (list "and (" notmuch-show-query-context ")\'"))
 (append (list "\'") basic-args (list "\'")
-   (notmuch-show-insert-forest (notmuch-query-get-threads args))
+   (notmuch-show-insert-forest (notmuch-query-get-threads
+(cons "--exclude=false" args)))
;; If the query context reduced the results to nothing, run
;; the basic query.
(when (and (eq (buffer-size) 0)
   notmuch-show-query-context)
  (notmuch-show-insert-forest
-  (notmuch-query-get-threads basic-args
+  (notmuch-query-get-threads
+   (cons "--exclude=false" basic-args)
 
   (jit-lock-register #'notmuch-show-buttonise-links)
 
-- 
1.7.9.1

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Why not tags inside messages?

2012-04-07 Thread David Belohrad
Dear all,

I'd love to use notmuch with offline imap  to work rather on local copy of 
messages, than using remote notmuch, which is slightly slower due to bandwidth 
limitation of my vdsl line. There is however fundamental problem of syncing 
flags between two instances of notmuch. So my question is, whether it would be 
possible, when tagging message, to store the tag as well in the message itself. 
Might this help to sync across multiple instances?

Another thing is, that I'd love to have native android app working over remote 
notmuch to work as my email agent. Is there anything like this? I guess not...

Thanks

D.




Odesláno z tabletu Samsung___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: Why not tags inside messages?

2012-04-07 Thread James Vasile
On Sat, 07 Apr 2012 18:46:03 +0200, David Belohrad  wrote:
> Dear all,
> 
> I'd love to use notmuch with offline imap  to work rather on local
> copy of messages, than using remote notmuch, which is slightly slower
> due to bandwidth limitation of my vdsl line. There is however
> fundamental problem of syncing flags between two instances of
> notmuch. So my question is, whether it would be possible, when tagging
> message, to store the tag as well in the message itself. Might this
> help to sync across multiple instances?

From my POV, there are two problems here.  

First is that storing tags in multiple places (one in db and once in
each message copy) leads to the question of which set of tags is
authoritative.  Syncing those tags is additional complexity.  And as a
mail moves to another system with a different notmuch db, what happens
to the tags?

Second is that your tags might then be public because
forwarding/replying to a message will, depending on your mail client,
also get included.

> 
> Another thing is, that I'd love to have native android app working
> over remote notmuch to work as my email agent. Is there anything like
> this? I guess not...

Not that I'm aware of, but if anybody is working on this, I'd love to
know and see if I can help.


pgpXBC6fzABie.pgp
Description: PGP signature
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: Why not tags inside messages?

2012-04-07 Thread Adam Wolfe Gordon
Hi David,

On Sat, Apr 7, 2012 at 10:46, David Belohrad  wrote:
> I'd love to use notmuch with offline imap  to work rather on local copy of
> messages, than using remote notmuch, which is slightly slower due to
> bandwidth limitation of my vdsl line. There is however fundamental problem
> of syncing flags between two instances of notmuch. So my question is,
> whether it would be possible, when tagging message, to store the tag as well
> in the message itself. Might this help to sync across multiple instances?

One solution that various people have used (I've used it for backup)
is to make the .notmuch directory in the maildir into a git
repository, and sync it to various machines using git push/git pull.
You can do the push/pull manually or in a notmuch hook to keep things
synced. I'm not sure if this is any better for your purposes than
using remote notmuch, but it would keep things local most of the time.

> Another thing is, that I'd love to have native android app working over
> remote notmuch to work as my email agent. Is there anything like this? I
> guess not...

I started working on one once, using python to write a little notmuch
server that produced JSON for various things, and an Android app that
contacted the server and displayed things nicely. It only got as far
as being able to list tags and count messages. It's probably something
I'll pick up again at some point, and of course I'd be happy to share
code if people are willing to help.

I know another Android client has been mentioned on IRC, but I'm not
sure if it got any further than mine.
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH v4 0/6] Move --no-exclude to --exclude=(true|false|flag)

2012-04-07 Thread Austin Clements
LGTM.

If for some reason you roll another version, you should update the
commit message on the test patch, but that's obviously not enough to
hold this series up.

Quoth Mark Walters on Apr 07 at  5:10 pm:
> This is version 4 of the exclude= patch set. Version 3 was at [1].
> 
> The only changes relative to version 3 are in the tests. As suggested
> by jrollins [2] I have added some systematic count and show tests and
> moved all the exclude tests to the file test/excludes.
> 
> Best wishes
> 
> Mark
> 
> [1] id:"1333716551-29153-1-git-send-email-markwalters1...@gmail.com"
> [2] id:"877gxs7ryv@servo.finestructure.net"
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 8/8] emacs: eliminate show-tag-message in favor of just show-tag

2012-04-07 Thread Jameson Graef Rollins
notmuch-show-tag-message is now completely redundant with
notmuch-show-tag so we eliminate it to simplify the interface.
---
 emacs/notmuch-show.el |   14 ++
 1 files changed, 2 insertions(+), 12 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 69bca02..f174910 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -1396,7 +1396,7 @@ current thread."
 
 (defun notmuch-show-mark-read ()
   "Mark the current message as read."
-  (notmuch-show-tag-message "-unread"))
+  (notmuch-show-tag "-unread"))
 
 ;; Functions for getting attributes of several messages in the current
 ;; thread.
@@ -1634,16 +1634,6 @@ than only the current message."
(message (format "Command '%s' exited abnormally with code %d"
 shell-command exit-code
 
-(defun notmuch-show-tag-message (&rest tag-changes)
-  "Change tags for the current message.
-
-TAG-CHANGES is a list of tag operations for `notmuch-tag'."
-  (let* ((current-tags (notmuch-show-get-tags))
-(new-tags (notmuch-update-tags current-tags tag-changes)))
-(unless (equal current-tags new-tags)
-  (funcall 'notmuch-tag (notmuch-show-get-message-id) tag-changes)
-  (notmuch-show-set-tags new-tags
-
 (defun notmuch-show-tag (&optional tag-changes)
   "Change tags for the current message.
 
@@ -1768,7 +1758,7 @@ If a prefix argument is given, the message will be
 removed)."
   (interactive "P")
   (let ((op (if unarchive "+" "-")))
-(notmuch-show-tag-message (concat op "inbox"
+(notmuch-show-tag (concat op "inbox"
 
 (defun notmuch-show-archive-message-then-next-or-exit ()
   "Archive the current message, then show the next open message in the current 
thread.
-- 
1.7.9.1

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 4/8] emacs: allow notmuch-tag to accept string inputs and prompt for tags

2012-04-07 Thread Jameson Graef Rollins
notmuch-tag is extended to accept various formats of the tag changes.
In particular, user prompting for tag changes is now incorporated
here, so it is common for modes.
---
 emacs/notmuch-tag.el |   20 +++-
 1 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/emacs/notmuch-tag.el b/emacs/notmuch-tag.el
index b1848b4..ed59c2d 100644
--- a/emacs/notmuch-tag.el
+++ b/emacs/notmuch-tag.el
@@ -108,18 +108,26 @@ from TAGS if present."
   (error "Changed tag must be of the form `+this_tag' or 
`-that_tag'")
 (sort result-tags 'string<)))
 
-(defun notmuch-tag (query &rest tag-changes)
+(defun notmuch-tag (query &optional tag-changes)
   "Add/remove tags in TAG-CHANGES to messages matching QUERY.
 
-TAG-CHANGES should be a list of strings of the form \"+tag\" or
-\"-tag\" and QUERY should be a string containing the
-search-query.
+QUERY should be a string containing the search-terms.
+TAG-CHANGES can take multiple forms.  If TAG-CHANGES is a list of
+strings of the form \"+tag\" or \"-tag\" then those are the tag
+changes applied.  If TAG-CHANGES is a string then it is
+interpreted as a single tag change.  If TAG-CHANGES is the string
+\"-\" or \"+\", or null, then the user is prompted to enter the
+tag changes.
 
 Note: Other code should always use this function alter tags of
 messages instead of running (notmuch-call-notmuch-process \"tag\" ..)
 directly, so that hooks specified in notmuch-before-tag-hook and
 notmuch-after-tag-hook will be run."
   ;; Perform some validation
+  (if (string-or-null-p tag-changes)
+  (if (or (string= tag-changes "-") (string= tag-changes "+") (null 
tag-changes))
+ (setq tag-changes (notmuch-read-tag-changes tag-changes query))
+   (setq tag-changes (list tag-changes
   (mapc (lambda (tag-change)
  (unless (string-match-p "^[-+]\\S-+$" tag-change)
(error "Tag must be of the form `+this_tag' or `-that_tag'")))
@@ -128,7 +136,9 @@ notmuch-after-tag-hook will be run."
 (run-hooks 'notmuch-before-tag-hook)
 (apply 'notmuch-call-notmuch-process "tag"
   (append tag-changes (list "--" query)))
-(run-hooks 'notmuch-after-tag-hook)))
+(run-hooks 'notmuch-after-tag-hook))
+  ;; return the list of actual changed tags
+  tag-changes)
 
 ;;
 
-- 
1.7.9.1

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 2/8] emacs: update tag-completion function

2012-04-07 Thread Jameson Graef Rollins
"search-tags" is deprecated, so we move to the more modern and
supported "search --output=tags".
---
 emacs/notmuch-tag.el |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/emacs/notmuch-tag.el b/emacs/notmuch-tag.el
index 81b4b00..5240d13 100644
--- a/emacs/notmuch-tag.el
+++ b/emacs/notmuch-tag.el
@@ -59,7 +59,7 @@ the messages that were tagged"
(with-output-to-string
  (with-current-buffer standard-output
(apply 'call-process notmuch-command nil t
- nil "search-tags" search-terms)))
+ nil "search" "--output=tags" search-terms)))
"\n+" t))
 
 (defun notmuch-select-tag-with-completion (prompt &rest search-terms)
-- 
1.7.9.1

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 5/8] emacs: modify search tag functions to use new notmuch-tag interface

2012-04-07 Thread Jameson Graef Rollins
The main change here is to modify argument parsing so as to not force
tag-changes to be a list, and to let notmuch-tag handle prompting the
user when required.  doc strings are also updated and cleaned up.
---
 emacs/notmuch.el |   36 +---
 1 files changed, 13 insertions(+), 23 deletions(-)

diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index 9aec96d..a03a526 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -523,13 +523,10 @@ and will also appear in a buffer named \"*Notmuch 
errors*\"."
 See `notmuch-search-tag-region' for details."
   (apply 'notmuch-search-tag-region (point) (point) tag-changes))
 
-(defun notmuch-search-tag-region (beg end &rest tag-changes)
-  "Change tags for threads in the given region.
-
-TAGS is a list of tag operations for `notmuch-tag'.  The tags are
-added or removed for all threads in the region from BEG to END."
+(defun notmuch-search-tag-region (beg end &optional tag-changes)
+  "Change tags for threads in the given region."
   (let ((search-string (notmuch-search-find-thread-id-region-search beg end)))
-(apply 'notmuch-tag search-string tag-changes)
+(setq tag-changes (funcall 'notmuch-tag search-string tag-changes))
 (save-excursion
   (let ((last-line (line-number-at-pos end))
(max-line (- (line-number-at-pos (point-max)) 2)))
@@ -539,14 +536,14 @@ added or removed for all threads in the region from BEG 
to END."
   (notmuch-update-tags (notmuch-search-get-tags) tag-changes))
  (forward-line))
 
-(defun notmuch-search-tag (&optional initial-input)
-  "Change tags for the currently selected thread or region."
+(defun notmuch-search-tag (&optional tag-changes)
+  "Change tags for the currently selected thread or region.
+
+See `notmuch-tag' for information on the format of TAG-CHANGES."
   (interactive)
   (let* ((beg (if (region-active-p) (region-beginning) (point)))
-(end (if (region-active-p) (region-end) (point)))
-(search-string (notmuch-search-find-thread-id-region-search beg end))
-(tags (notmuch-read-tag-changes initial-input search-string)))
-(apply 'notmuch-search-tag-region beg end tags)))
+(end (if (region-active-p) (region-end) (point
+(funcall 'notmuch-search-tag-region beg end tag-changes)))
 
 (defun notmuch-search-add-tag ()
   "Same as `notmuch-search-tag' but sets initial input to '+'."
@@ -790,18 +787,11 @@ non-authors is found, assume that all of the authors 
match."
  (goto-char found-target)))
   (delete-process proc
 
-(defun notmuch-search-tag-all (&rest tag-changes)
-  "Add/remove tags from all matching messages.
+(defun notmuch-search-tag-all (&optional tag-changes)
+  "Add/remove tags from all messages in current search buffer.
 
-This command adds or removes tags from all messages matching the
-current search terms. When called interactively, this command
-will prompt for tags to be added or removed. Tags prefixed with
-'+' will be added and tags prefixed with '-' will be removed.
-
-Each character of the tag name may consist of alphanumeric
-characters as well as `_.+-'.
-"
-  (interactive (notmuch-read-tag-changes))
+See `notmuch-tag' for information on the format of TAG-CHANGES."
+  (interactive)
   (apply 'notmuch-tag notmuch-search-query-string tag-changes))
 
 (defun notmuch-search-buffer-title (query)
-- 
1.7.9.1

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


emacs tagging cleanup

2012-04-07 Thread Jameson Graef Rollins
This is a rework of the series [0].  It addresses some of the comments
from Dmitry, and extends the scope to clean up the tagging interface
in both search and show mode.

[0] id:"154853-25729-1-git-send-email-jroll...@finestructure.net"

The goal here is to present a cleaner tagging interface to the user.
We want things to be simple, not confusing or redundant.  To that end
I have extended the notmuch-tag function to handle prompting if
needed.  The main user-facing functions are now:

  notmuch-search-tag  tag thread or region
  notmuch-search-tag-all  tag all thread in search buffer
  notmuch-show-tagtag message
  notmuch-show-tag-alltag all message in show buffer

I think this provides a much cleaner interface that is more useful to
users.  In particular, this improves the ability to tag regions in
search mode.

I have eliminated two user-facing functions (notmuch-search-tag-thread
and notmuch-show-tag-message) since they are now redundant.  This
might cause a slight hiccup for those using those functions, but I
think it's better in the long run.

Unfortunately something in the last patch (last two patches, I guess)
is now causing a two of our more esoteric tests to fail.  After
spending half the day trying to figure out why I'm at a loss.  And I
don't want all this work to be wasted so I'm submitting it anyway.
Hopefully someone (maybe the creator of those tests?) can figure out
what's going on.

jamie.

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 7/8] emacs: modify show tag functions to use new notmuch-tag interface

2012-04-07 Thread Jameson Graef Rollins
The main change here is to modify argument parsing so as to not force
tag-changes to be a list, and to let notmuch-tag handle prompting the
user when required.  doc strings are also updated and cleaned up.
---
 emacs/notmuch-show.el |   26 +++---
 1 files changed, 15 insertions(+), 11 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index a4c313d..69bca02 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -1641,22 +1641,26 @@ TAG-CHANGES is a list of tag operations for 
`notmuch-tag'."
   (let* ((current-tags (notmuch-show-get-tags))
 (new-tags (notmuch-update-tags current-tags tag-changes)))
 (unless (equal current-tags new-tags)
-  (apply 'notmuch-tag (notmuch-show-get-message-id) tag-changes)
+  (funcall 'notmuch-tag (notmuch-show-get-message-id) tag-changes)
   (notmuch-show-set-tags new-tags
 
-(defun notmuch-show-tag (&optional initial-input)
-  "Change tags for the current message, read input from the minibuffer."
+(defun notmuch-show-tag (&optional tag-changes)
+  "Change tags for the current message.
+
+See `notmuch-tag' for information on the format of TAG-CHANGES."
   (interactive)
-  (let ((tag-changes (notmuch-read-tag-changes
- initial-input (notmuch-show-get-message-id
-(apply 'notmuch-show-tag-message tag-changes)))
+  (setq tag-changes (funcall 'notmuch-tag (notmuch-show-get-message-id) 
tag-changes))
+  (let* ((current-tags (notmuch-show-get-tags))
+(new-tags (notmuch-update-tags current-tags tag-changes)))
+(unless (equal current-tags new-tags)
+  (notmuch-show-set-tags new-tags
 
-(defun notmuch-show-tag-all (&rest tag-changes)
-  "Change tags for all messages in the current buffer.
+(defun notmuch-show-tag-all (&optional tag-changes)
+  "Change tags for all messages in the current show buffer.
 
-TAG-CHANGES is a list of tag operations for `notmuch-tag'."
-  (interactive (notmuch-read-tag-changes nil notmuch-show-thread-id))
-  (apply 'notmuch-tag (notmuch-show-get-messages-ids-search) tag-changes)
+See `notmuch-tag' for information on the format of TAG-CHANGES."
+  (interactive)
+  (setq tag-changes (funcall 'notmuch-tag 
(notmuch-show-get-messages-ids-search) tag-changes))
   (notmuch-show-mapc
(lambda ()
  (let* ((current-tags (notmuch-show-get-tags))
-- 
1.7.9.1

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 6/8] emacs: eliminate search-tag-thread in favor of just search-tag

2012-04-07 Thread Jameson Graef Rollins
notmuch-search-tag-thread is now completely redundant with
notmuch-search-tag so we eliminate it to simplify the interface.
---
 emacs/notmuch.el |8 +---
 1 files changed, 1 insertions(+), 7 deletions(-)

diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index a03a526..d79a448 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -517,12 +517,6 @@ and will also appear in a buffer named \"*Notmuch 
errors*\"."
(forward-line 1))
   output)))
 
-(defun notmuch-search-tag-thread (&rest tag-changes)
-  "Change tags for the currently selected thread.
-
-See `notmuch-search-tag-region' for details."
-  (apply 'notmuch-search-tag-region (point) (point) tag-changes))
-
 (defun notmuch-search-tag-region (beg end &optional tag-changes)
   "Change tags for threads in the given region."
   (let ((search-string (notmuch-search-find-thread-id-region-search beg end)))
@@ -560,7 +554,7 @@ See `notmuch-tag' for information on the format of 
TAG-CHANGES."
 
 This function advances the next thread when finished."
   (interactive)
-  (notmuch-search-tag-thread "-inbox")
+  (notmuch-search-tag "-inbox")
   (notmuch-search-next-thread))
 
 (defvar notmuch-search-process-filter-data nil
-- 
1.7.9.1

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 3/8] emacs: have tag-completion return all tags for nil input

2012-04-07 Thread Jameson Graef Rollins
Previously the function would fail if the initial input was nil.  Now
it will return a list of all tags, which obviously makes much more
sense.
---
 emacs/notmuch-tag.el |2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/emacs/notmuch-tag.el b/emacs/notmuch-tag.el
index 5240d13..b1848b4 100644
--- a/emacs/notmuch-tag.el
+++ b/emacs/notmuch-tag.el
@@ -55,6 +55,8 @@ the messages that were tagged"
 `notmuch-read-tag-changes' function.")
 
 (defun notmuch-tag-completions (&optional search-terms)
+  (if (null search-terms)
+  (setq search-terms (list "*")))
   (split-string
(with-output-to-string
  (with-current-buffer standard-output
-- 
1.7.9.1

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 1/8] emacs: create notmuch-tag.el, and move appropriate functions from notmuch.el

2012-04-07 Thread Jameson Graef Rollins
Tagging functions are used in notmuch.el, notmuch-show.el, and
notmuch-message.el.  There are enough common functions for tagging
that it makes sense to put them all in their own library.

No code is modified, just moved around.
---
 emacs/Makefile.local |1 +
 emacs/notmuch-message.el |1 +
 emacs/notmuch-show.el|3 +-
 emacs/notmuch-tag.el |  133 ++
 emacs/notmuch.el |  107 +
 5 files changed, 137 insertions(+), 108 deletions(-)
 create mode 100644 emacs/notmuch-tag.el

diff --git a/emacs/Makefile.local b/emacs/Makefile.local
index 4fee0e8..fb82247 100644
--- a/emacs/Makefile.local
+++ b/emacs/Makefile.local
@@ -13,6 +13,7 @@ emacs_sources := \
$(dir)/notmuch-maildir-fcc.el \
$(dir)/notmuch-message.el \
$(dir)/notmuch-crypto.el \
+   $(dir)/notmuch-tag.el \
$(dir)/coolj.el \
$(dir)/notmuch-print.el
 
diff --git a/emacs/notmuch-message.el b/emacs/notmuch-message.el
index 3010281..5964caa 100644
--- a/emacs/notmuch-message.el
+++ b/emacs/notmuch-message.el
@@ -20,6 +20,7 @@
 ;; Authors: Jesse Rosenthal 
 
 (require 'message)
+(require 'notmuch-tag)
 (require 'notmuch-mua)
 
 (defcustom notmuch-message-replied-tags '("replied")
diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 30b26d1..a4c313d 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -30,6 +30,7 @@
 (require 'goto-addr)
 
 (require 'notmuch-lib)
+(require 'notmuch-tag)
 (require 'notmuch-query)
 (require 'notmuch-wash)
 (require 'notmuch-mua)
@@ -38,10 +39,8 @@
 
 (declare-function notmuch-call-notmuch-process "notmuch" (&rest args))
 (declare-function notmuch-fontify-headers "notmuch" nil)
-(declare-function notmuch-read-tag-changes "notmuch" (&optional initial-input 
&rest search-terms))
 (declare-function notmuch-search-next-thread "notmuch" nil)
 (declare-function notmuch-search-show-thread "notmuch" nil)
-(declare-function notmuch-update-tags "notmuch" (current-tags tag-changes))
 
 (defcustom notmuch-message-headers '("Subject" "To" "Cc" "Date")
   "Headers that should be shown in a message, in this order.
diff --git a/emacs/notmuch-tag.el b/emacs/notmuch-tag.el
new file mode 100644
index 000..81b4b00
--- /dev/null
+++ b/emacs/notmuch-tag.el
@@ -0,0 +1,133 @@
+;; notmuch-tag.el --- tag messages within emacs
+;;
+;; Copyright © Carl Worth
+;;
+;; This file is part of Notmuch.
+;;
+;; Notmuch is free software: you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Notmuch is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Notmuch.  If not, see .
+;;
+;; Authors: Carl Worth 
+
+(eval-when-compile (require 'cl))
+(require 'crm)
+(require 'notmuch-lib)
+
+(defcustom notmuch-before-tag-hook nil
+  "Hooks that are run before tags of a message are modified.
+
+'tags' will contain the tags that are about to be added or removed as
+a list of strings of the form \"+TAG\" or \"-TAG\".
+'query' will be a string containing the search query that determines
+the messages that are about to be tagged"
+
+  :type 'hook
+  :options '(notmuch-hl-line-mode)
+  :group 'notmuch-hooks)
+
+(defcustom notmuch-after-tag-hook nil
+  "Hooks that are run after tags of a message are modified.
+
+'tags' will contain the tags that were added or removed as
+a list of strings of the form \"+TAG\" or \"-TAG\".
+'query' will be a string containing the search query that determines
+the messages that were tagged"
+  :type 'hook
+  :options '(notmuch-hl-line-mode)
+  :group 'notmuch-hooks)
+
+(defvar notmuch-select-tag-history nil
+  "Variable to store minibuffer history for
+`notmuch-select-tag-with-completion' function.")
+
+(defvar notmuch-read-tag-changes-history nil
+  "Variable to store minibuffer history for
+`notmuch-read-tag-changes' function.")
+
+(defun notmuch-tag-completions (&optional search-terms)
+  (split-string
+   (with-output-to-string
+ (with-current-buffer standard-output
+   (apply 'call-process notmuch-command nil t
+ nil "search-tags" search-terms)))
+   "\n+" t))
+
+(defun notmuch-select-tag-with-completion (prompt &rest search-terms)
+  (let ((tag-list (notmuch-tag-completions search-terms)))
+(completing-read prompt tag-list nil nil nil 'notmuch-select-tag-history)))
+
+(defun notmuch-read-tag-changes (&optional initial-input &rest search-terms)
+  (let* ((all-tag-list (notmuch-tag-completions))
+(add-tag-list (mapcar (apply-partially 'concat "+") all-tag-list))
+(r

[PATCH 0/6] Finish show rewrite

2012-04-07 Thread Austin Clements
The long-awaited and oft-belated conclusion of the show rewrite.  All
of the formatters have been converted to the new style, so this series
just rips out unused code and does a little cleanup.

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 4/6] show: Remove unused fields from notmuch_show_format

2012-04-07 Thread Austin Clements
These fields were only used by old-style formatters.
---
 notmuch-client.h |   23 ---
 1 files changed, 0 insertions(+), 23 deletions(-)

diff --git a/notmuch-client.h b/notmuch-client.h
index 34155fc..f0fb748 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -70,29 +70,6 @@ typedef struct notmuch_show_format {
 notmuch_status_t (*part) (const void *ctx,
  struct mime_node *node, int indent,
  const struct notmuch_show_params *params);
-const char *message_start;
-void (*message) (const void *ctx,
-notmuch_message_t *message,
-int indent);
-const char *header_start;
-void (*header) (const void *ctx,
-   notmuch_message_t *message);
-void (*header_message_part) (GMimeMessage *message);
-const char *header_end;
-const char *body_start;
-void (*part_start) (GMimeObject *part,
-   int *part_count);
-void (*part_encstatus) (int status);
-#ifdef GMIME_ATLEAST_26
-void (*part_sigstatus) (GMimeSignatureList* siglist);
-#else
-void (*part_sigstatus) (const GMimeSignatureValidity* validity);
-#endif
-void (*part_content) (GMimeObject *part);
-void (*part_end) (GMimeObject *part);
-const char *part_sep;
-const char *body_end;
-const char *message_end;
 const char *message_set_sep;
 const char *message_set_end;
 } notmuch_show_format_t;
-- 
1.7.9.1

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 1/6] Sync schemata with current code structure

2012-04-07 Thread Austin Clements
The schema itself hasn't changed, but many of the references to
functions in notmuch-show.c were out of date.
---
 devel/schemata |   21 +++--
 1 files changed, 7 insertions(+), 14 deletions(-)

diff --git a/devel/schemata b/devel/schemata
index 728a46f..977cea7 100644
--- a/devel/schemata
+++ b/devel/schemata
@@ -36,7 +36,7 @@ thread_node = [
 [thread_node*]# children of message
 ]
 
-# A message (show_message)
+# A message (format_part_json)
 message = {
 # (format_message_json)
 id: messageid,
@@ -50,18 +50,13 @@ message = {
 body:   [part]
 }
 
-# A MIME part (show_message_body)
+# A MIME part (format_part_json)
 part = {
-# format_part_start_json
 id: int|string, # part id (currently DFS part number)
 
-# format_part_encstatus_json
 encstatus?: encstatus,
-
-# format_part_sigstatus_json
 sigstatus?: sigstatus,
 
-# format_part_content_json
 content-type:   string,
 content-id?:string,
 # if content-type starts with "multipart/":
@@ -77,9 +72,7 @@ part = {
 content?:   string
 }
 
-# The headers of a message (format_headers_json with raw headers
-# and reply = FALSE) or a part (format_headers_message_part_json
-# with pretty-printed headers)
+# The headers of a message or part (format_headers_json with reply = FALSE)
 headers = {
 Subject:string,
 From:   string,
@@ -89,14 +82,14 @@ headers = {
 Date:   string
 }
 
-# Encryption status (format_part_encstatus_json)
+# Encryption status (format_part_json)
 encstatus = [{status: "good"|"bad"}]
 
 # Signature status (format_part_sigstatus_json)
 sigstatus = [signature*]
 
 signature = {
-# signature_status_to_string
+# (signature_status_to_string)
 status: "none"|"good"|"bad"|"error"|"unknown",
 # if status is "good":
 fingerprint?:   string,
@@ -142,14 +135,14 @@ notmuch reply schema
 
 
 reply = {
-# The headers of the constructed reply (format_headers_json with
-# raw headers and reply = TRUE)
+# The headers of the constructed reply
 reply-headers: reply_headers,
 
 # As in the show format (format_part_json)
 original: message
 }
 
+# Reply headers (format_headers_json with reply = TRUE)
 reply_headers = {
 Subject:string,
 From:   string,
-- 
1.7.9.1

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 2/6] show: Remove support for old-style formatters in show_message

2012-04-07 Thread Austin Clements
show_message used to have a compatibility path for old-style
formatters.  This removes that.
---
 notmuch-show.c |   52 +---
 1 files changed, 13 insertions(+), 39 deletions(-)

diff --git a/notmuch-show.c b/notmuch-show.c
index 0bf5e21..5a71115 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -815,46 +815,20 @@ show_message (void *ctx,
  int indent,
  notmuch_show_params_t *params)
 {
-if (format->part) {
-   void *local = talloc_new (ctx);
-   mime_node_t *root, *part;
-   notmuch_status_t status;
-
-   status = mime_node_open (local, message, params->cryptoctx,
-params->decrypt, &root);
-   if (status)
-   goto DONE;
-   part = mime_node_seek_dfs (root, (params->part < 0 ? 0 : params->part));
-   if (part)
-   status = format->part (local, part, indent, params);
-  DONE:
-   talloc_free (local);
-   return status;
-}
-
-if (params->part <= 0) {
-   fputs (format->message_start, stdout);
-   if (format->message)
-   format->message(ctx, message, indent);
-
-   fputs (format->header_start, stdout);
-   if (format->header)
-   format->header(ctx, message);
-   fputs (format->header_end, stdout);
-
-   fputs (format->body_start, stdout);
-}
-
-if (format->part_content)
-   show_message_body (message, format, params);
-
-if (params->part <= 0) {
-   fputs (format->body_end, stdout);
-
-   fputs (format->message_end, stdout);
-}
+void *local = talloc_new (ctx);
+mime_node_t *root, *part;
+notmuch_status_t status;
 
-return NOTMUCH_STATUS_SUCCESS;
+status = mime_node_open (local, message, params->cryptoctx,
+params->decrypt, &root);
+if (status)
+   goto DONE;
+part = mime_node_seek_dfs (root, (params->part < 0 ? 0 : params->part));
+if (part)
+   status = format->part (local, part, indent, params);
+  DONE:
+talloc_free (local);
+return status;
 }
 
 static notmuch_status_t
-- 
1.7.9.1

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 3/6] Remove show-message.c

2012-04-07 Thread Austin Clements
There are no more calls to show_message_body.
---
 Makefile.local   |1 -
 notmuch-client.h |5 ---
 show-message.c   |  106 --
 3 files changed, 0 insertions(+), 112 deletions(-)
 delete mode 100644 show-message.c

diff --git a/Makefile.local b/Makefile.local
index 1131dea..935f0f1 100644
--- a/Makefile.local
+++ b/Makefile.local
@@ -301,7 +301,6 @@ notmuch_client_srcs =   \
notmuch-tag.c   \
notmuch-time.c  \
query-string.c  \
-   show-message.c  \
mime-node.c \
json.c
 
diff --git a/notmuch-client.h b/notmuch-client.h
index 203ac49..34155fc 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -184,11 +184,6 @@ char *
 query_string_from_args (void *ctx, int argc, char *argv[]);
 
 notmuch_status_t
-show_message_body (notmuch_message_t *message,
-  const notmuch_show_format_t *format,
-  notmuch_show_params_t *params);
-
-notmuch_status_t
 show_one_part (const char *filename, int part);
 
 void
diff --git a/show-message.c b/show-message.c
deleted file mode 100644
index 83ecf81..000
--- a/show-message.c
+++ /dev/null
@@ -1,106 +0,0 @@
-/* notmuch - Not much of an email program, (just index and search)
- *
- * Copyright © 2009 Carl Worth
- * Copyright © 2009 Keith Packard
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see http://www.gnu.org/licenses/ .
- *
- * Authors: Carl Worth 
- * Keith Packard 
- */
-
-#include "notmuch-client.h"
-
-typedef struct show_message_state {
-int part_count;
-} show_message_state_t;
-
-static void
-show_message_part (mime_node_t *node,
-  show_message_state_t *state,
-  const notmuch_show_format_t *format,
-  int first)
-{
-/* Formatters expect the envelope for embedded message parts */
-GMimeObject *part = node->envelope_part ?
-   GMIME_OBJECT (node->envelope_part) : node->part;
-int i;
-
-if (!first)
-   fputs (format->part_sep, stdout);
-
-/* Format this part */
-if (format->part_start)
-   format->part_start (part, &(state->part_count));
-
-if (node->decrypt_attempted && format->part_encstatus)
-   format->part_encstatus (node->decrypt_success);
-
-if (node->verify_attempted && format->part_sigstatus)
-#ifdef GMIME_ATLEAST_26
-   format->part_sigstatus (node->sig_list);
-#else
-   format->part_sigstatus (node->sig_validity);
-#endif
-
-format->part_content (part);
-
-if (node->envelope_part) {
-   fputs (format->header_start, stdout);
-   if (format->header_message_part)
-   format->header_message_part (GMIME_MESSAGE (node->part));
-   fputs (format->header_end, stdout);
-
-   fputs (format->body_start, stdout);
-}
-
-/* Recurse over the children */
-state->part_count += 1;
-for (i = 0; i < node->nchildren; i++)
-   show_message_part (mime_node_child (node, i), state, format, i == 0);
-
-/* Finish this part */
-if (node->envelope_part)
-   fputs (format->body_end, stdout);
-
-if (format->part_end)
-   format->part_end (part);
-}
-
-notmuch_status_t
-show_message_body (notmuch_message_t *message,
-  const notmuch_show_format_t *format,
-  notmuch_show_params_t *params)
-{
-notmuch_status_t ret;
-show_message_state_t state;
-mime_node_t *root, *part;
-
-ret = mime_node_open (NULL, message, params->cryptoctx, params->decrypt,
- &root);
-if (ret)
-   return ret;
-
-/* The caller of show_message_body has already handled the
- * outermost envelope, so skip it. */
-state.part_count = MAX (params->part, 1);
-
-part = mime_node_seek_dfs (root, state.part_count);
-if (part)
-   show_message_part (part, &state, format, TRUE);
-
-talloc_free (root);
-
-return NOTMUCH_STATUS_SUCCESS;
-}
-- 
1.7.9.1

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 6/6] show: Remove empty message_set_{start,sep,end} fields

2012-04-07 Thread Austin Clements
Setting these to NULL is equivalent to the empty string now.
---
 notmuch-show.c |9 -
 1 files changed, 0 insertions(+), 9 deletions(-)

diff --git a/notmuch-show.c b/notmuch-show.c
index ef26ad2..7929476 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -26,10 +26,7 @@ format_part_text (const void *ctx, mime_node_t *node,
  int indent, const notmuch_show_params_t *params);
 
 static const notmuch_show_format_t format_text = {
-.message_set_start = "",
 .part = format_part_text,
-.message_set_sep = "",
-.message_set_end = ""
 };
 
 static notmuch_status_t
@@ -48,10 +45,7 @@ format_part_mbox (const void *ctx, mime_node_t *node,
  int indent, const notmuch_show_params_t *params);
 
 static const notmuch_show_format_t format_mbox = {
-.message_set_start = "",
 .part = format_part_mbox,
-.message_set_sep = "",
-.message_set_end = ""
 };
 
 static notmuch_status_t
@@ -60,10 +54,7 @@ format_part_raw (unused (const void *ctx), mime_node_t *node,
 unused (const notmuch_show_params_t *params));
 
 static const notmuch_show_format_t format_raw = {
-.message_set_start = "",
 .part = format_part_raw,
-.message_set_sep = "",
-.message_set_end = ""
 };
 
 static const char *
-- 
1.7.9.1

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 5/6] show: Support NULL values for message_set_{start, sep, end}

2012-04-07 Thread Austin Clements
Many formats don't need these, so it's more convenient if they don't
have to set them at all.
---
 notmuch-show.c |   24 +++-
 1 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/notmuch-show.c b/notmuch-show.c
index 5a71115..ef26ad2 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -844,17 +844,19 @@ show_messages (void *ctx,
 int next_indent;
 notmuch_status_t status, res = NOTMUCH_STATUS_SUCCESS;
 
-fputs (format->message_set_start, stdout);
+if (format->message_set_start)
+   fputs (format->message_set_start, stdout);
 
 for (;
 notmuch_messages_valid (messages);
 notmuch_messages_move_to_next (messages))
 {
-   if (!first_set)
+   if (!first_set && format->message_set_sep)
fputs (format->message_set_sep, stdout);
first_set = 0;
 
-   fputs (format->message_set_start, stdout);
+   if (format->message_set_start)
+   fputs (format->message_set_start, stdout);
 
message = notmuch_messages_get (messages);
 
@@ -868,7 +870,7 @@ show_messages (void *ctx,
res = status;
next_indent = indent + 1;
 
-   if (!status)
+   if (!status && format->message_set_sep)
fputs (format->message_set_sep, stdout);
}
 
@@ -882,10 +884,12 @@ show_messages (void *ctx,
 
notmuch_message_destroy (message);
 
-   fputs (format->message_set_end, stdout);
+   if (format->message_set_end)
+   fputs (format->message_set_end, stdout);
 }
 
-fputs (format->message_set_end, stdout);
+if (format->message_set_end)
+   fputs (format->message_set_end, stdout);
 
 return res;
 }
@@ -931,7 +935,8 @@ do_show (void *ctx,
 int first_toplevel = 1;
 notmuch_status_t status, res = NOTMUCH_STATUS_SUCCESS;
 
-fputs (format->message_set_start, stdout);
+if (format->message_set_start)
+   fputs (format->message_set_start, stdout);
 
 for (threads = notmuch_query_search_threads (query);
 notmuch_threads_valid (threads);
@@ -945,7 +950,7 @@ do_show (void *ctx,
INTERNAL_ERROR ("Thread %s has no toplevel messages.\n",
notmuch_thread_get_thread_id (thread));
 
-   if (!first_toplevel)
+   if (!first_toplevel && format->message_set_sep)
fputs (format->message_set_sep, stdout);
first_toplevel = 0;
 
@@ -957,7 +962,8 @@ do_show (void *ctx,
 
 }
 
-fputs (format->message_set_end, stdout);
+if (format->message_set_end)
+   fputs (format->message_set_end, stdout);
 
 return res != NOTMUCH_STATUS_SUCCESS;
 }
-- 
1.7.9.1

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH] News for raw format changes

2012-04-07 Thread Austin Clements
---
 NEWS |   11 +++
 1 files changed, 11 insertions(+), 0 deletions(-)

diff --git a/NEWS b/NEWS
index a618a9d..c1704e0 100644
--- a/NEWS
+++ b/NEWS
@@ -41,6 +41,17 @@ Tag exclusion
 
 notmuch config set search.exclude_tags deleted spam
 
+Raw show format changes
+
+  The output of show --format=raw has changed for multipart and
+  message parts.  Previously, the output was a mash of somewhat-parsed
+  headers and transfer-decoded bodies.  Now, such parts are reproduced
+  faithfully from the original source.  Message parts (which includes
+  part 0) output the full message, including the message headers (but
+  not the transfer headers).  Multipart parts output the part as
+  encoded in the original message, including the part's headers.  Leaf
+  parts, as before, output the part's transfer-decoded body.
+
 Emacs Interface
 ---
 
-- 
1.7.9.1

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH v4 0/6] Move --no-exclude to --exclude=(true|false|flag)

2012-04-07 Thread Jameson Graef Rollins
On Sat, Apr 07 2012, Mark Walters  wrote:
> This is version 4 of the exclude= patch set. Version 3 was at [1].
>
> The only changes relative to version 3 are in the tests. As suggested
> by jrollins [2] I have added some systematic count and show tests and
> moved all the exclude tests to the file test/excludes.

Tested.  LGTM.

jamie.


pgpuDTVsG7Zdp.pgp
Description: PGP signature
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH v4 0/6] Move --no-exclude to --exclude=(true|false|flag)

2012-04-07 Thread David Bremner
Mark Walters  writes:

> This is version 4 of the exclude= patch set. Version 3 was at [1].
>
> The only changes relative to version 3 are in the tests. As suggested
> by jrollins [2] I have added some systematic count and show tests and
> moved all the exclude tests to the file test/excludes.

Pushed.

d
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH 7/8] emacs: modify show tag functions to use new notmuch-tag interface

2012-04-07 Thread Mark Walters

On Sun, 08 Apr 2012, Jameson Graef Rollins  wrote:
> The main change here is to modify argument parsing so as to not force
> tag-changes to be a list, and to let notmuch-tag handle prompting the
> user when required.  doc strings are also updated and cleaned up.
> ---
>  emacs/notmuch-show.el |   26 +++---
>  1 files changed, 15 insertions(+), 11 deletions(-)
>
> diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
> index a4c313d..69bca02 100644
> --- a/emacs/notmuch-show.el
> +++ b/emacs/notmuch-show.el
> @@ -1641,22 +1641,26 @@ TAG-CHANGES is a list of tag operations for 
> `notmuch-tag'."
>(let* ((current-tags (notmuch-show-get-tags))
>(new-tags (notmuch-update-tags current-tags tag-changes)))
>  (unless (equal current-tags new-tags)
> -  (apply 'notmuch-tag (notmuch-show-get-message-id) tag-changes)
> +  (funcall 'notmuch-tag (notmuch-show-get-message-id) tag-changes)
>(notmuch-show-set-tags new-tags
>  
> -(defun notmuch-show-tag (&optional initial-input)
> -  "Change tags for the current message, read input from the minibuffer."
> +(defun notmuch-show-tag (&optional tag-changes)
> +  "Change tags for the current message.
> +
> +See `notmuch-tag' for information on the format of TAG-CHANGES."
>(interactive)
> -  (let ((tag-changes (notmuch-read-tag-changes
> -   initial-input (notmuch-show-get-message-id
> -(apply 'notmuch-show-tag-message tag-changes)))
> +  (setq tag-changes (funcall 'notmuch-tag (notmuch-show-get-message-id) 
> tag-changes))
> +  (let* ((current-tags (notmuch-show-get-tags))
> +  (new-tags (notmuch-update-tags current-tags tag-changes)))
> +(unless (equal current-tags new-tags)
> +  (notmuch-show-set-tags new-tags

Hi. If I am following this correctly the setq line funcalls notmuch tag
regardless of whether there will be a tag change.
 
whereas the code from patch 8/8
>-(defun notmuch-show-tag-message (&rest tag-changes)
>-  "Change tags for the current message.
>-
>-TAG-CHANGES is a list of tag operations for `notmuch-tag'."
>-  (let* ((current-tags (notmuch-show-get-tags))
>-   (new-tags (notmuch-update-tags current-tags tag-changes)))
>-(unless (equal current-tags new-tags)
>-  (funcall 'notmuch-tag (notmuch-show-get-message-id) tag-changes)
>-  (notmuch-show-set-tags new-tags
>-

seems to only do the funcall when the tags change.

I think this is what is making the two tests fail: they count the number
of invocations of notmuch and in case there is one invocation of notmuch
show and one of notmuch tag -unread message-id, where before it was just
the single notmuch show.

Best wishes

Mark
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH] Record dependencies during build instead of before

2012-04-07 Thread Austin Clements
Previously, the makefile created dependency files in a separate, first
pass.  In particular, include-ing the dependency files would cause
make to attempt to rebuild those files using the dependency-generation
rules in the makefile.  Unfortunately, this approach required obtuse
rules and silently delayed the start of the build process (by quite a
bit on a clean tree without any dependency files).  Worse, this
required the dependency files to themselves depend on all of the
headers the source file depended on, which meant that, if a header
file was removed, the depedency file could not be updated because of a
missing dependency (!), which would cause make to silently fail.

This patch eliminates the dependency generation rules and instead
generates dependency files as a side-effect of the regular build rule.
On the first build, we don't need to know the dependencies beforehand;
the object file doesn't exist, so it will be built anyway.  On
subsequent builds, if a header file is updated, the dependency rules
generated by the previous build will force a rebuild.  If a source
file is updated, the dependency rules may be stale, but it doesn't
matter because the updated source file will force a rebuild.

In the final case above, the stale dependency rules may refer to a
header file that no longer exists but is also no longer needed.  In
order to prevent this from breaking the build, we also pass gcc the
-MP option, which generates phony targets for every depended-on header
file, so make won't complain if it can't find them during a later
build.
---
The description is way more complicated than the patch.

 Makefile.local |   18 --
 1 files changed, 4 insertions(+), 14 deletions(-)

diff --git a/Makefile.local b/Makefile.local
index 1131dea..525eda0 100644
--- a/Makefile.local
+++ b/Makefile.local
@@ -256,23 +256,12 @@ endif
 quiet ?= $($(shell echo $1 | sed -e s'/ .*//'))
 
 %.o: %.cc $(global_deps)
+   @mkdir -p .deps/$(@D)
+   $(call quiet,CXX $(CXXFLAGS)) -c $(FINAL_CXXFLAGS) $< -o $@ -MD -MP -MF 
.deps/$*.d
-   $(call quiet,CXX $(CXXFLAGS)) -c $(FINAL_CXXFLAGS) $< -o $@
 
 %.o: %.c $(global_deps)
+   @mkdir -p .deps/$(@D)
+   $(call quiet,CC $(CFLAGS)) -c $(FINAL_CFLAGS) $< -o $@ -MD -MP -MF 
.deps/$*.d
-   $(call quiet,CC $(CFLAGS)) -c $(FINAL_CFLAGS) $< -o $@
-
-.deps/%.d: %.c $(global_deps)
-   @set -e; rm -f $@; mkdir -p $$(dirname $@) ; \
-   $(CC) -M $(CPPFLAGS) $(FINAL_CFLAGS) $< > $@. 2>/dev/null ; \
-   sed 's,'$$(basename $*)'\.o[ :]*,$*.o $@ : ,g' < $@. > $@; \
-   rm -f $@.
-
-.deps/%.d: %.cc $(global_deps)
-   @set -e; rm -f $@; mkdir -p $$(dirname $@) ; \
-   $(CXX) -M $(CPPFLAGS) $(FINAL_CXXFLAGS) $< > $@. 2>/dev/null ; \
-   sed 's,'$$(basename $*)'\.o[ :]*,$*.o $@ : ,g' < $@. > $@; \
-   rm -f $@.
 
 .PHONY : clean
 clean:
-- 
1.7.9.1

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH v4 0/6] Move --no-exclude to --exclude=(true|false|flag)

2012-04-07 Thread Mark Walters
This is version 4 of the exclude= patch set. Version 3 was at [1].

The only changes relative to version 3 are in the tests. As suggested
by jrollins [2] I have added some systematic count and show tests and
moved all the exclude tests to the file test/excludes.

Best wishes

Mark

[1] id:"1333716551-29153-1-git-send-email-markwalters1009 at gmail.com"
[2] id:"877gxs7ryv.fsf at servo.finestructure.net"

Mark Walters (6):
  lib: change default for notmuch_query_set_omit_excluded
  cli: move count to the new --exclude=(true|false|flag) naming scheme.
  cli: move search to the new --exclude= naming scheme.
  cli: move show to the new --exclude= option naming scheme.
  test: add some exclude tests
  emacs: make show set --exclude=false

 emacs/notmuch-show.el |6 +-
 lib/notmuch.h |   23 ++-
 lib/query.cc  |   10 +-
 man/man1/notmuch-count.1  |5 +-
 man/man1/notmuch-search.1 |   12 +-
 man/man1/notmuch-show.1   |   16 ++-
 notmuch-client.h  |1 +
 notmuch-count.c   |   17 ++-
 notmuch-search.c  |   32 +++-
 notmuch-show.c|   50 --
 test/count|   21 ---
 test/excludes |  423 +
 test/notmuch-test |1 +
 test/search   |   48 -
 14 files changed, 544 insertions(+), 121 deletions(-)
 create mode 100755 test/excludes

-- 
1.7.9.1



[PATCH v4 1/6] lib: change default for notmuch_query_set_omit_excluded

2012-04-07 Thread Mark Walters
---
 lib/notmuch.h |   23 ++-
 lib/query.cc  |   10 +-
 2 files changed, 23 insertions(+), 10 deletions(-)

diff --git a/lib/notmuch.h b/lib/notmuch.h
index babd208..673c423 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -449,12 +449,25 @@ typedef enum {
 const char *
 notmuch_query_get_query_string (notmuch_query_t *query);

-/* Specify whether to results should omit the excluded results rather
- * than just marking them excluded. This is useful for passing a
- * notmuch_messages_t not containing the excluded messages to other
- * functions. */
+/* Specify whether to omit excluded results or simply flag them.  By
+ * default, this is set to TRUE.
+ *
+ * If this is TRUE, notmuch_query_search_messages will omit excluded
+ * messages from the results.  notmuch_query_search_threads will omit
+ * threads that match only in excluded messages, but will include all
+ * messages in threads that match in at least one non-excluded
+ * message.
+ *
+ * The performance difference when calling
+ * notmuch_query_search_messages should be relatively small (and both
+ * should be very fast).  However, in some cases,
+ * notmuch_query_search_threads is very much faster when omitting
+ * excluded messages as it does not need to construct the threads that
+ * only match in excluded messages.
+ */
+
 void
-notmuch_query_set_omit_excluded_messages (notmuch_query_t *query, 
notmuch_bool_t omit);
+notmuch_query_set_omit_excluded (notmuch_query_t *query, notmuch_bool_t 
omit_excluded);

 /* Specify the sorting desired for this query. */
 void
diff --git a/lib/query.cc b/lib/query.cc
index 68ac1e4..e9c1a2d 100644
--- a/lib/query.cc
+++ b/lib/query.cc
@@ -28,7 +28,7 @@ struct _notmuch_query {
 const char *query_string;
 notmuch_sort_t sort;
 notmuch_string_list_t *exclude_terms;
-notmuch_bool_t omit_excluded_messages;
+notmuch_bool_t omit_excluded;
 };

 typedef struct _notmuch_mset_messages {
@@ -92,7 +92,7 @@ notmuch_query_create (notmuch_database_t *notmuch,

 query->exclude_terms = _notmuch_string_list_create (query);

-query->omit_excluded_messages = FALSE;
+query->omit_excluded = TRUE;

 return query;
 }
@@ -104,9 +104,9 @@ notmuch_query_get_query_string (notmuch_query_t *query)
 }

 void
-notmuch_query_set_omit_excluded_messages (notmuch_query_t *query, 
notmuch_bool_t omit)
+notmuch_query_set_omit_excluded (notmuch_query_t *query, notmuch_bool_t 
omit_excluded)
 {
-query->omit_excluded_messages = omit;
+query->omit_excluded = omit_excluded;
 }

 void
@@ -220,7 +220,7 @@ notmuch_query_search_messages (notmuch_query_t *query)
if (query->exclude_terms) {
exclude_query = _notmuch_exclude_tags (query, final_query);

-   if (query->omit_excluded_messages)
+   if (query->omit_excluded)
final_query = Xapian::Query (Xapian::Query::OP_AND_NOT,
 final_query, exclude_query);
else {
-- 
1.7.9.1



[PATCH v4 2/6] cli: move count to the new --exclude=(true|false|flag) naming scheme.

2012-04-07 Thread Mark Walters
Move the option --no-exclude to the --exclude= scheme. Since there is
no way to flag messages only true and false are implemented. Note
that, for consistency with other commands, this is implemented as a
keyword option rather than a boolean option.
---
 man/man1/notmuch-count.1 |5 +++--
 notmuch-count.c  |   17 -
 test/count   |4 ++--
 3 files changed, 17 insertions(+), 9 deletions(-)

diff --git a/man/man1/notmuch-count.1 b/man/man1/notmuch-count.1
index 35ecc53..d6cbf07 100644
--- a/man/man1/notmuch-count.1
+++ b/man/man1/notmuch-count.1
@@ -41,9 +41,10 @@ Output the number of matching threads.

 .RS 4
 .TP 4
-.BR \-\-no\-exclude
+.BR \-\-exclude=(true|false)

-Do not exclude the messages matching search.exclude_tags in the config file.
+Specify whether to omit messages matching search.tag_exclude from the
+count (the default) or not.
 .RE
 .RE
 .RE
diff --git a/notmuch-count.c b/notmuch-count.c
index 46b76ae..b76690c 100644
--- a/notmuch-count.c
+++ b/notmuch-count.c
@@ -26,6 +26,12 @@ enum {
 OUTPUT_MESSAGES,
 };

+/* The following is to allow future options to be added more easily */
+enum {
+EXCLUDE_TRUE,
+EXCLUDE_FALSE,
+};
+
 int
 notmuch_count_command (void *ctx, int argc, char *argv[])
 {
@@ -35,7 +41,7 @@ notmuch_count_command (void *ctx, int argc, char *argv[])
 char *query_str;
 int opt_index;
 int output = OUTPUT_MESSAGES;
-notmuch_bool_t no_exclude = FALSE;
+int exclude = EXCLUDE_TRUE;
 unsigned int i;

 notmuch_opt_desc_t options[] = {
@@ -43,7 +49,10 @@ notmuch_count_command (void *ctx, int argc, char *argv[])
  (notmuch_keyword_t []){ { "threads", OUTPUT_THREADS },
  { "messages", OUTPUT_MESSAGES },
  { 0, 0 } } },
-   { NOTMUCH_OPT_BOOLEAN, &no_exclude, "no-exclude", 'd', 0 },
+   { NOTMUCH_OPT_KEYWORD, &exclude, "exclude", 'x',
+ (notmuch_keyword_t []){ { "true", EXCLUDE_TRUE },
+ { "false", EXCLUDE_FALSE },
+ { 0, 0 } } },
{ 0, 0, 0, 0, 0 }
 };

@@ -78,7 +87,7 @@ notmuch_count_command (void *ctx, int argc, char *argv[])
return 1;
 }

-if (!no_exclude) {
+if (exclude == EXCLUDE_TRUE) {
const char **search_exclude_tags;
size_t search_exclude_tags_length;

@@ -88,8 +97,6 @@ notmuch_count_command (void *ctx, int argc, char *argv[])
notmuch_query_add_tag_exclude (query, search_exclude_tags[i]);
 }

-notmuch_query_set_omit_excluded_messages (query, TRUE);
-
 switch (output) {
 case OUTPUT_MESSAGES:
printf ("%u\n", notmuch_query_count_messages (query));
diff --git a/test/count b/test/count
index b97fc06..fd387e5 100755
--- a/test/count
+++ b/test/count
@@ -53,9 +53,9 @@ test_expect_equal \
 "1" \
 "`notmuch count subject:deleted and tag:deleted`"

-test_begin_subtest "count \"deleted\" messages, with --no-exclude"
+test_begin_subtest "count \"deleted\" messages, --exclude=false"
 test_expect_equal \
 "3" \
-"`notmuch count --no-exclude subject:deleted`"
+"`notmuch count --exclude=false subject:deleted`"

 test_done
-- 
1.7.9.1



[PATCH v4 3/6] cli: move search to the new --exclude= naming scheme.

2012-04-07 Thread Mark Walters
This commit replaces the --no-exclude option with a
--exclude=(true|false|flag) option. The default is to omit the
excluded messages.

The flag option only makes sense if output=summary (as otherwise there
is nowhere to print the flag). In summary output exclude=false and
exclude=flag give almost identical output:
they differ in that with the exclude=flag option the match count
(i.e., the x in [x/n] in the output) is the number of matching
non-excluded messages rather than the number of matching messages.

Note this changes the default for output=summary when no --exclude=
option is given: it used to default to flag and now defaults to true
(i.e. omit excluded messages). This is neccesary to keep the cli
output uncluttered and for speed reasons.
---
 man/man1/notmuch-search.1 |   12 +---
 notmuch-search.c  |   32 +++-
 2 files changed, 32 insertions(+), 12 deletions(-)

diff --git a/man/man1/notmuch-search.1 b/man/man1/notmuch-search.1
index 06d81a6..ebb61fc 100644
--- a/man/man1/notmuch-search.1
+++ b/man/man1/notmuch-search.1
@@ -114,9 +114,15 @@ Limit the number of displayed results to N.

 .RS 4
 .TP 4
-.BR \-\-no\-exclude
-
-Do not exclude the messages matching search.exclude_tags in the config file.
+.BR \-\-exclude=(true|false|flag)
+
+Specify whether to omit messages matching search.tag_exclude from the
+search results (the default) or not. The extra option
+.B flag
+only has an effect when
+.B --output=summary
+In this case all matching threads are returned but the "match count"
+is the number of matching non-excluded messages in the thread.
 .RE

 .SH SEE ALSO
diff --git a/notmuch-search.c b/notmuch-search.c
index f6061e4..1cc8430 100644
--- a/notmuch-search.c
+++ b/notmuch-search.c
@@ -210,9 +210,6 @@ do_search_threads (const search_format_t *format,
 int first_thread = 1;
 int i;

-if (output == OUTPUT_THREADS)
-   notmuch_query_set_omit_excluded_messages (query, TRUE);
-
 if (offset < 0) {
offset += notmuch_query_count_threads (query);
if (offset < 0)
@@ -303,8 +300,6 @@ do_search_messages (const search_format_t *format,
 int first_message = 1;
 int i;

-notmuch_query_set_omit_excluded_messages (query, TRUE);
-
 if (offset < 0) {
offset += notmuch_query_count_messages (query);
if (offset < 0)
@@ -376,7 +371,6 @@ do_search_tags (notmuch_database_t *notmuch,
 const char *tag;
 int first_tag = 1;

-notmuch_query_set_omit_excluded_messages (query, TRUE);
 /* should the following only special case if no excluded terms
  * specified? */

@@ -422,6 +416,12 @@ do_search_tags (notmuch_database_t *notmuch,
 return 0;
 }

+enum {
+EXCLUDE_TRUE,
+EXCLUDE_FALSE,
+EXCLUDE_FLAG,
+};
+
 int
 notmuch_search_command (void *ctx, int argc, char *argv[])
 {
@@ -435,7 +435,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
 output_t output = OUTPUT_SUMMARY;
 int offset = 0;
 int limit = -1; /* unlimited */
-notmuch_bool_t no_exclude = FALSE;
+int exclude = EXCLUDE_TRUE;
 unsigned int i;

 enum { NOTMUCH_FORMAT_JSON, NOTMUCH_FORMAT_TEXT }
@@ -457,7 +457,11 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
  { "files", OUTPUT_FILES },
  { "tags", OUTPUT_TAGS },
  { 0, 0 } } },
-   { NOTMUCH_OPT_BOOLEAN, &no_exclude, "no-exclude", 'd', 0 },
+{ NOTMUCH_OPT_KEYWORD, &exclude, "exclude", 'x',
+  (notmuch_keyword_t []){ { "true", EXCLUDE_TRUE },
+  { "false", EXCLUDE_FALSE },
+  { "flag", EXCLUDE_FLAG },
+  { 0, 0 } } },
{ NOTMUCH_OPT_INT, &offset, "offset", 'O', 0 },
{ NOTMUCH_OPT_INT, &limit, "limit", 'L', 0  },
{ 0, 0, 0, 0, 0 }
@@ -505,7 +509,15 @@ notmuch_search_command (void *ctx, int argc, char *argv[])

 notmuch_query_set_sort (query, sort);

-if (!no_exclude) {
+if (exclude == EXCLUDE_FLAG && output != OUTPUT_SUMMARY) {
+   /* If we are not doing summary output there is nowhere to
+* print the excluded flag so fall back on including the
+* excluded messages. */
+   fprintf (stderr, "Warning: this output format cannot flag excluded 
messages.\n");
+   exclude = EXCLUDE_FALSE;
+}
+
+if (exclude == EXCLUDE_TRUE || exclude == EXCLUDE_FLAG) {
const char **search_exclude_tags;
size_t search_exclude_tags_length;

@@ -513,6 +525,8 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
(config, &search_exclude_tags_length);
for (i = 0; i < search_exclude_tags_length; i++)
notmuch_query_add_tag_exclude (query, search_exclude_tags[i]);
+   if (exclude == EXCLUDE_FLAG)
+   notmuch_query_set_omit_excluded (query, FALSE);
 }

 switch (output) {
-- 
1.7.9.1



[PATCH v4 4/6] cli: move show to the new --exclude= option naming scheme.

2012-04-07 Thread Mark Walters
This moves notmuch show to the --exclude=(true|false) naming
scheme. When exclude=false show returns all threads that match
including those that only match in an excluded message. The excluded
messages are flagged.

When exclude=true the behaviour depends on whether --entire-thread is
set. If it is not set then show only returns the messages which match
and are not excluded. If it is set then show returns all messages in
the threads that match in a non-excluded message, flagging the excluded
messages in these threads. The rationale is that it is awkward to use
a thread with some missing messages.
---
 man/man1/notmuch-show.1 |   16 +-
 notmuch-client.h|1 +
 notmuch-show.c  |   50 +-
 3 files changed, 46 insertions(+), 21 deletions(-)

diff --git a/man/man1/notmuch-show.1 b/man/man1/notmuch-show.1
index b81cce6..83cc575 100644
--- a/man/man1/notmuch-show.1
+++ b/man/man1/notmuch-show.1
@@ -135,9 +135,21 @@ content.

 .RS 4
 .TP 4
-.B \-\-no-exclude
+.BR \-\-exclude=(true|false)
+
+Specify whether to omit threads only matching search.tag_exclude from
+the search results (the default) or not. In either case the excluded
+message will be marked with the exclude flag (except when output=mbox
+when there is nowhere to put the flag).
+
+If --entire-thread is specified then complete threads are returned
+regardless (with the excluded flag being set when appropriate) but
+threads that only match in an excluded message are not returned when
+.B --exclude=true.
+
+The default is
+.B --exclude=true.

-Do not exclude the messages matching search.exclude_tags in the config file.
 .RE

 A common use of
diff --git a/notmuch-client.h b/notmuch-client.h
index 203ac49..880b153 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -99,6 +99,7 @@ typedef struct notmuch_show_format {

 typedef struct notmuch_show_params {
 notmuch_bool_t entire_thread;
+notmuch_bool_t omit_excluded;
 notmuch_bool_t raw;
 int part;
 #ifdef GMIME_ATLEAST_26
diff --git a/notmuch-show.c b/notmuch-show.c
index 0bf5e21..7af8e64 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -866,6 +866,7 @@ show_messages (void *ctx,
 {
 notmuch_message_t *message;
 notmuch_bool_t match;
+notmuch_bool_t excluded;
 int first_set = 1;
 int next_indent;
 notmuch_status_t status, res = NOTMUCH_STATUS_SUCCESS;
@@ -885,10 +886,11 @@ show_messages (void *ctx,
message = notmuch_messages_get (messages);

match = notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_MATCH);
+   excluded = notmuch_message_get_flag (message, 
NOTMUCH_MESSAGE_FLAG_EXCLUDED);

next_indent = indent;

-   if (match || params->entire_thread) {
+   if ((match && (!excluded || !params->omit_excluded)) || 
params->entire_thread) {
status = show_message (ctx, format, message, indent, params);
if (status && !res)
res = status;
@@ -996,6 +998,12 @@ enum {
 NOTMUCH_FORMAT_RAW
 };

+/* The following is to allow future options to be added more easily */
+enum {
+EXCLUDE_TRUE,
+EXCLUDE_FALSE,
+};
+
 int
 notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[]))
 {
@@ -1005,10 +1013,10 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
 char *query_string;
 int opt_index, ret;
 const notmuch_show_format_t *format = &format_text;
-notmuch_show_params_t params = { .part = -1 };
+notmuch_show_params_t params = { .part = -1, .omit_excluded = TRUE };
 int format_sel = NOTMUCH_FORMAT_NOT_SPECIFIED;
 notmuch_bool_t verify = FALSE;
-notmuch_bool_t no_exclude = FALSE;
+int exclude = EXCLUDE_TRUE;

 notmuch_opt_desc_t options[] = {
{ NOTMUCH_OPT_KEYWORD, &format_sel, "format", 'f',
@@ -1017,11 +1025,14 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
  { "mbox", NOTMUCH_FORMAT_MBOX },
  { "raw", NOTMUCH_FORMAT_RAW },
  { 0, 0 } } },
+{ NOTMUCH_OPT_KEYWORD, &exclude, "exclude", 'x',
+  (notmuch_keyword_t []){ { "true", EXCLUDE_TRUE },
+  { "false", EXCLUDE_FALSE },
+  { 0, 0 } } },
{ NOTMUCH_OPT_INT, ¶ms.part, "part", 'p', 0 },
{ NOTMUCH_OPT_BOOLEAN, ¶ms.entire_thread, "entire-thread", 't', 0 },
{ NOTMUCH_OPT_BOOLEAN, ¶ms.decrypt, "decrypt", 'd', 0 },
{ NOTMUCH_OPT_BOOLEAN, &verify, "verify", 'v', 0 },
-   { NOTMUCH_OPT_BOOLEAN, &no_exclude, "no-exclude", 'n', 0 },
{ 0, 0, 0, 0, 0 }
 };

@@ -1110,29 +1121,30 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
return 1;
 }

-/* if format=mbox then we can not output excluded messages as
- * there is no way to make the exclude flag available */
-if (format_sel == NOTMUCH_FORMA

[PATCH v4 5/6] test: add some exclude tests

2012-04-07 Thread Mark Walters
Systematically test the exclude options for search. Also move the
search existing exclude tests into the new test. There is some overlap
between the two sets of tests but many of the existing ones are there
because they triggered bugs in the past so I have kept them to ensure
coverage.
---
 test/count|   21 ---
 test/excludes |  423 +
 test/notmuch-test |1 +
 test/search   |   48 --
 4 files changed, 424 insertions(+), 69 deletions(-)
 create mode 100755 test/excludes

diff --git a/test/count b/test/count
index fd387e5..300b171 100755
--- a/test/count
+++ b/test/count
@@ -37,25 +37,4 @@ test_expect_equal \
 "0" \
 "`notmuch count --output=threads ${SEARCH}`"

-test_begin_subtest "count excluding \"deleted\" messages"
-notmuch config set search.exclude_tags deleted
-generate_message '[subject]="Not deleted"'
-generate_message '[subject]="Another not deleted"'
-generate_message '[subject]="Deleted"'
-notmuch new > /dev/null
-notmuch tag +deleted id:$gen_msg_id
-test_expect_equal \
-"2" \
-"`notmuch count subject:deleted`"
-
-test_begin_subtest "count \"deleted\" messages, exclude overridden"
-test_expect_equal \
-"1" \
-"`notmuch count subject:deleted and tag:deleted`"
-
-test_begin_subtest "count \"deleted\" messages, --exclude=false"
-test_expect_equal \
-"3" \
-"`notmuch count --exclude=false subject:deleted`"
-
 test_done
diff --git a/test/excludes b/test/excludes
new file mode 100755
index 000..24d653e
--- /dev/null
+++ b/test/excludes
@@ -0,0 +1,423 @@
+#!/usr/bin/env bash
+test_description='"notmuch search, count and show" with excludes in several 
variations'
+. ./test-lib.sh
+
+# Generates a thread consisting of a top level message and 'length'
+# replies. The subject of the top message 'subject: top message"
+# and the subject of the nth reply in the thread is "subject: reply n"
+generate_thread ()
+{
+local subject="$1"
+local length="$2"
+generate_message '[subject]="'"${subject}: top message"'"' '[body]="'"body 
of top message"'"'
+parent_id=$gen_msg_id
+gen_thread_msg_id[0]=$gen_msg_id
+for i in `seq 1 $length`
+do
+   generate_message '[subject]="'"${subject}: reply $i"'"' \
+"[in-reply-to]=\<$parent_id\>" \
+'[body]="'"body of reply $i"'"'
+   gen_thread_msg_id[$i]=$gen_msg_id
+   parent_id=$gen_msg_id
+done
+notmuch new > /dev/null
+# We cannot retrieve the thread_id until after we have run notmuch new.
+gen_thread_id=`notmuch search --output=threads id:${gen_thread_msg_id[0]}`
+}
+
+#
+# These are the original search exclude tests.
+
+test_begin_subtest "Search, exclude \"deleted\" messages from search"
+notmuch config set search.exclude_tags deleted
+generate_message '[subject]="Not deleted"'
+not_deleted_id=$gen_msg_id
+generate_message '[subject]="Deleted"'
+notmuch new > /dev/null
+notmuch tag +deleted id:$gen_msg_id
+deleted_id=$gen_msg_id
+output=$(notmuch search subject:deleted | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; 
Not deleted (inbox unread)"
+
+test_begin_subtest "Search, exclude \"deleted\" messages from message search"
+output=$(notmuch search --output=messages subject:deleted | 
notmuch_search_sanitize)
+test_expect_equal "$output" "id:$not_deleted_id"
+
+test_begin_subtest "Search, exclude \"deleted\" messages from message search 
--exclude=false"
+output=$(notmuch search --exclude=false --output=messages subject:deleted | 
notmuch_search_sanitize)
+test_expect_equal "$output" "id:$not_deleted_id
+id:$deleted_id"
+
+test_begin_subtest "Search, exclude \"deleted\" messages from message search 
(non-existent exclude-tag)"
+notmuch config set search.exclude_tags deleted non_existent_tag
+output=$(notmuch search --output=messages subject:deleted | 
notmuch_search_sanitize)
+test_expect_equal "$output" "id:$not_deleted_id"
+notmuch config set search.exclude_tags deleted
+
+test_begin_subtest "Search, exclude \"deleted\" messages from search, 
overridden"
+output=$(notmuch search subject:deleted and tag:deleted | 
notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; 
Deleted (deleted inbox unread)"
+
+test_begin_subtest "Search, exclude \"deleted\" messages from threads"
+add_message '[subject]="Not deleted reply"' '[in-reply-to]="<$gen_msg_id>"'
+output=$(notmuch search subject:deleted | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; 
Not deleted (inbox unread)
+thread:XXX   2001-01-05 [1/2] Notmuch Test Suite; Not deleted reply (deleted 
inbox unread)"
+
+test_begin_subtest "Search, don't exclude \"deleted\" messages when 
--exclude=flag specified"
+output=$(notmuch search --exclude=flag subject:deleted | 
notmuch_search_sanitize)
+test_expect_equal "

[PATCH v4 6/6] emacs: make show set --exclude=false

2012-04-07 Thread Mark Walters
Show has to set --exclude=false to deal with cases where it is asked
to show a single excluded message. It uses JSON so it can easily pass
the exclude information to the user.
---
 emacs/notmuch-show.el |6 --
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 6d3fe62..30b26d1 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -1060,13 +1060,15 @@ function is used."
   (append (list "\'") basic-args
   (list "and (" notmuch-show-query-context ")\'"))
 (append (list "\'") basic-args (list "\'")
-   (notmuch-show-insert-forest (notmuch-query-get-threads args))
+   (notmuch-show-insert-forest (notmuch-query-get-threads
+(cons "--exclude=false" args)))
;; If the query context reduced the results to nothing, run
;; the basic query.
(when (and (eq (buffer-size) 0)
   notmuch-show-query-context)
  (notmuch-show-insert-forest
-  (notmuch-query-get-threads basic-args
+  (notmuch-query-get-threads
+   (cons "--exclude=false" basic-args)

   (jit-lock-register #'notmuch-show-buttonise-links)

-- 
1.7.9.1



Why not tags inside messages?

2012-04-07 Thread David Belohrad
Dear all,

I'd love to use notmuch with offline imap ?to work rather on local copy of 
messages, than using remote notmuch, which is slightly slower due to bandwidth 
limitation of my vdsl line. There is however fundamental problem of syncing 
flags between two instances of notmuch. So my question is, whether it would be 
possible, when tagging message, to store the tag as well in the message itself. 
Might this help to sync across multiple instances?

Another thing is, that I'd love to have native android app working over remote 
notmuch to work as my email agent. Is there anything like this? I guess not...

Thanks

D.




Odesl?no z tabletu Samsung
-- next part --
An HTML attachment was scrubbed...
URL: 
<http://notmuchmail.org/pipermail/notmuch/attachments/20120407/700094c0/attachment.html>


Why not tags inside messages?

2012-04-07 Thread James Vasile
On Sat, 07 Apr 2012 18:46:03 +0200, David Belohrad  wrote:
> Dear all,
> 
> I'd love to use notmuch with offline imap ?to work rather on local
> copy of messages, than using remote notmuch, which is slightly slower
> due to bandwidth limitation of my vdsl line. There is however
> fundamental problem of syncing flags between two instances of
> notmuch. So my question is, whether it would be possible, when tagging
> message, to store the tag as well in the message itself. Might this
> help to sync across multiple instances?


Why not tags inside messages?

2012-04-07 Thread Adam Wolfe Gordon
Hi David,

On Sat, Apr 7, 2012 at 10:46, David Belohrad  wrote:
> I'd love to use notmuch with offline imap ?to work rather on local copy of
> messages, than using remote notmuch, which is slightly slower due to
> bandwidth limitation of my vdsl line. There is however fundamental problem
> of syncing flags between two instances of notmuch. So my question is,
> whether it would be possible, when tagging message, to store the tag as well
> in the message itself. Might this help to sync across multiple instances?

One solution that various people have used (I've used it for backup)
is to make the .notmuch directory in the maildir into a git
repository, and sync it to various machines using git push/git pull.
You can do the push/pull manually or in a notmuch hook to keep things
synced. I'm not sure if this is any better for your purposes than
using remote notmuch, but it would keep things local most of the time.

> Another thing is, that I'd love to have native android app working over
> remote notmuch to work as my email agent. Is there anything like this? I
> guess not...

I started working on one once, using python to write a little notmuch
server that produced JSON for various things, and an Android app that
contacted the server and displayed things nicely. It only got as far
as being able to list tags and count messages. It's probably something
I'll pick up again at some point, and of course I'd be happy to share
code if people are willing to help.

I know another Android client has been mentioned on IRC, but I'm not
sure if it got any further than mine.


[PATCH v4 0/6] Move --no-exclude to --exclude=(true|false|flag)

2012-04-07 Thread Austin Clements
LGTM.

If for some reason you roll another version, you should update the
commit message on the test patch, but that's obviously not enough to
hold this series up.

Quoth Mark Walters on Apr 07 at  5:10 pm:
> This is version 4 of the exclude= patch set. Version 3 was at [1].
> 
> The only changes relative to version 3 are in the tests. As suggested
> by jrollins [2] I have added some systematic count and show tests and
> moved all the exclude tests to the file test/excludes.
> 
> Best wishes
> 
> Mark
> 
> [1] id:"1333716551-29153-1-git-send-email-markwalters1009 at gmail.com"
> [2] id:"877gxs7ryv.fsf at servo.finestructure.net"


[PATCH 8/8] emacs: eliminate show-tag-message in favor of just show-tag

2012-04-07 Thread Jameson Graef Rollins
notmuch-show-tag-message is now completely redundant with
notmuch-show-tag so we eliminate it to simplify the interface.
---
 emacs/notmuch-show.el |   14 ++
 1 files changed, 2 insertions(+), 12 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 69bca02..f174910 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -1396,7 +1396,7 @@ current thread."

 (defun notmuch-show-mark-read ()
   "Mark the current message as read."
-  (notmuch-show-tag-message "-unread"))
+  (notmuch-show-tag "-unread"))

 ;; Functions for getting attributes of several messages in the current
 ;; thread.
@@ -1634,16 +1634,6 @@ than only the current message."
(message (format "Command '%s' exited abnormally with code %d"
 shell-command exit-code

-(defun notmuch-show-tag-message (&rest tag-changes)
-  "Change tags for the current message.
-
-TAG-CHANGES is a list of tag operations for `notmuch-tag'."
-  (let* ((current-tags (notmuch-show-get-tags))
-(new-tags (notmuch-update-tags current-tags tag-changes)))
-(unless (equal current-tags new-tags)
-  (funcall 'notmuch-tag (notmuch-show-get-message-id) tag-changes)
-  (notmuch-show-set-tags new-tags
-
 (defun notmuch-show-tag (&optional tag-changes)
   "Change tags for the current message.

@@ -1768,7 +1758,7 @@ If a prefix argument is given, the message will be
 removed)."
   (interactive "P")
   (let ((op (if unarchive "+" "-")))
-(notmuch-show-tag-message (concat op "inbox"
+(notmuch-show-tag (concat op "inbox"

 (defun notmuch-show-archive-message-then-next-or-exit ()
   "Archive the current message, then show the next open message in the current 
thread.
-- 
1.7.9.1



[PATCH 4/8] emacs: allow notmuch-tag to accept string inputs and prompt for tags

2012-04-07 Thread Jameson Graef Rollins
notmuch-tag is extended to accept various formats of the tag changes.
In particular, user prompting for tag changes is now incorporated
here, so it is common for modes.
---
 emacs/notmuch-tag.el |   20 +++-
 1 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/emacs/notmuch-tag.el b/emacs/notmuch-tag.el
index b1848b4..ed59c2d 100644
--- a/emacs/notmuch-tag.el
+++ b/emacs/notmuch-tag.el
@@ -108,18 +108,26 @@ from TAGS if present."
   (error "Changed tag must be of the form `+this_tag' or 
`-that_tag'")
 (sort result-tags 'string<)))

-(defun notmuch-tag (query &rest tag-changes)
+(defun notmuch-tag (query &optional tag-changes)
   "Add/remove tags in TAG-CHANGES to messages matching QUERY.

-TAG-CHANGES should be a list of strings of the form \"+tag\" or
-\"-tag\" and QUERY should be a string containing the
-search-query.
+QUERY should be a string containing the search-terms.
+TAG-CHANGES can take multiple forms.  If TAG-CHANGES is a list of
+strings of the form \"+tag\" or \"-tag\" then those are the tag
+changes applied.  If TAG-CHANGES is a string then it is
+interpreted as a single tag change.  If TAG-CHANGES is the string
+\"-\" or \"+\", or null, then the user is prompted to enter the
+tag changes.

 Note: Other code should always use this function alter tags of
 messages instead of running (notmuch-call-notmuch-process \"tag\" ..)
 directly, so that hooks specified in notmuch-before-tag-hook and
 notmuch-after-tag-hook will be run."
   ;; Perform some validation
+  (if (string-or-null-p tag-changes)
+  (if (or (string= tag-changes "-") (string= tag-changes "+") (null 
tag-changes))
+ (setq tag-changes (notmuch-read-tag-changes tag-changes query))
+   (setq tag-changes (list tag-changes
   (mapc (lambda (tag-change)
  (unless (string-match-p "^[-+]\\S-+$" tag-change)
(error "Tag must be of the form `+this_tag' or `-that_tag'")))
@@ -128,7 +136,9 @@ notmuch-after-tag-hook will be run."
 (run-hooks 'notmuch-before-tag-hook)
 (apply 'notmuch-call-notmuch-process "tag"
   (append tag-changes (list "--" query)))
-(run-hooks 'notmuch-after-tag-hook)))
+(run-hooks 'notmuch-after-tag-hook))
+  ;; return the list of actual changed tags
+  tag-changes)

 ;;

-- 
1.7.9.1



[PATCH 2/8] emacs: update tag-completion function

2012-04-07 Thread Jameson Graef Rollins
"search-tags" is deprecated, so we move to the more modern and
supported "search --output=tags".
---
 emacs/notmuch-tag.el |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/emacs/notmuch-tag.el b/emacs/notmuch-tag.el
index 81b4b00..5240d13 100644
--- a/emacs/notmuch-tag.el
+++ b/emacs/notmuch-tag.el
@@ -59,7 +59,7 @@ the messages that were tagged"
(with-output-to-string
  (with-current-buffer standard-output
(apply 'call-process notmuch-command nil t
- nil "search-tags" search-terms)))
+ nil "search" "--output=tags" search-terms)))
"\n+" t))

 (defun notmuch-select-tag-with-completion (prompt &rest search-terms)
-- 
1.7.9.1



[PATCH 5/8] emacs: modify search tag functions to use new notmuch-tag interface

2012-04-07 Thread Jameson Graef Rollins
The main change here is to modify argument parsing so as to not force
tag-changes to be a list, and to let notmuch-tag handle prompting the
user when required.  doc strings are also updated and cleaned up.
---
 emacs/notmuch.el |   36 +---
 1 files changed, 13 insertions(+), 23 deletions(-)

diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index 9aec96d..a03a526 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -523,13 +523,10 @@ and will also appear in a buffer named \"*Notmuch 
errors*\"."
 See `notmuch-search-tag-region' for details."
   (apply 'notmuch-search-tag-region (point) (point) tag-changes))

-(defun notmuch-search-tag-region (beg end &rest tag-changes)
-  "Change tags for threads in the given region.
-
-TAGS is a list of tag operations for `notmuch-tag'.  The tags are
-added or removed for all threads in the region from BEG to END."
+(defun notmuch-search-tag-region (beg end &optional tag-changes)
+  "Change tags for threads in the given region."
   (let ((search-string (notmuch-search-find-thread-id-region-search beg end)))
-(apply 'notmuch-tag search-string tag-changes)
+(setq tag-changes (funcall 'notmuch-tag search-string tag-changes))
 (save-excursion
   (let ((last-line (line-number-at-pos end))
(max-line (- (line-number-at-pos (point-max)) 2)))
@@ -539,14 +536,14 @@ added or removed for all threads in the region from BEG 
to END."
   (notmuch-update-tags (notmuch-search-get-tags) tag-changes))
  (forward-line))

-(defun notmuch-search-tag (&optional initial-input)
-  "Change tags for the currently selected thread or region."
+(defun notmuch-search-tag (&optional tag-changes)
+  "Change tags for the currently selected thread or region.
+
+See `notmuch-tag' for information on the format of TAG-CHANGES."
   (interactive)
   (let* ((beg (if (region-active-p) (region-beginning) (point)))
-(end (if (region-active-p) (region-end) (point)))
-(search-string (notmuch-search-find-thread-id-region-search beg end))
-(tags (notmuch-read-tag-changes initial-input search-string)))
-(apply 'notmuch-search-tag-region beg end tags)))
+(end (if (region-active-p) (region-end) (point
+(funcall 'notmuch-search-tag-region beg end tag-changes)))

 (defun notmuch-search-add-tag ()
   "Same as `notmuch-search-tag' but sets initial input to '+'."
@@ -790,18 +787,11 @@ non-authors is found, assume that all of the authors 
match."
  (goto-char found-target)))
   (delete-process proc

-(defun notmuch-search-tag-all (&rest tag-changes)
-  "Add/remove tags from all matching messages.
+(defun notmuch-search-tag-all (&optional tag-changes)
+  "Add/remove tags from all messages in current search buffer.

-This command adds or removes tags from all messages matching the
-current search terms. When called interactively, this command
-will prompt for tags to be added or removed. Tags prefixed with
-'+' will be added and tags prefixed with '-' will be removed.
-
-Each character of the tag name may consist of alphanumeric
-characters as well as `_.+-'.
-"
-  (interactive (notmuch-read-tag-changes))
+See `notmuch-tag' for information on the format of TAG-CHANGES."
+  (interactive)
   (apply 'notmuch-tag notmuch-search-query-string tag-changes))

 (defun notmuch-search-buffer-title (query)
-- 
1.7.9.1



emacs tagging cleanup

2012-04-07 Thread Jameson Graef Rollins
This is a rework of the series [0].  It addresses some of the comments
from Dmitry, and extends the scope to clean up the tagging interface
in both search and show mode.

[0] id:"154853-25729-1-git-send-email-jrollins at finestructure.net"

The goal here is to present a cleaner tagging interface to the user.
We want things to be simple, not confusing or redundant.  To that end
I have extended the notmuch-tag function to handle prompting if
needed.  The main user-facing functions are now:

  notmuch-search-tag  tag thread or region
  notmuch-search-tag-all  tag all thread in search buffer
  notmuch-show-tagtag message
  notmuch-show-tag-alltag all message in show buffer

I think this provides a much cleaner interface that is more useful to
users.  In particular, this improves the ability to tag regions in
search mode.

I have eliminated two user-facing functions (notmuch-search-tag-thread
and notmuch-show-tag-message) since they are now redundant.  This
might cause a slight hiccup for those using those functions, but I
think it's better in the long run.

Unfortunately something in the last patch (last two patches, I guess)
is now causing a two of our more esoteric tests to fail.  After
spending half the day trying to figure out why I'm at a loss.  And I
don't want all this work to be wasted so I'm submitting it anyway.
Hopefully someone (maybe the creator of those tests?) can figure out
what's going on.

jamie.



[PATCH 7/8] emacs: modify show tag functions to use new notmuch-tag interface

2012-04-07 Thread Jameson Graef Rollins
The main change here is to modify argument parsing so as to not force
tag-changes to be a list, and to let notmuch-tag handle prompting the
user when required.  doc strings are also updated and cleaned up.
---
 emacs/notmuch-show.el |   26 +++---
 1 files changed, 15 insertions(+), 11 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index a4c313d..69bca02 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -1641,22 +1641,26 @@ TAG-CHANGES is a list of tag operations for 
`notmuch-tag'."
   (let* ((current-tags (notmuch-show-get-tags))
 (new-tags (notmuch-update-tags current-tags tag-changes)))
 (unless (equal current-tags new-tags)
-  (apply 'notmuch-tag (notmuch-show-get-message-id) tag-changes)
+  (funcall 'notmuch-tag (notmuch-show-get-message-id) tag-changes)
   (notmuch-show-set-tags new-tags

-(defun notmuch-show-tag (&optional initial-input)
-  "Change tags for the current message, read input from the minibuffer."
+(defun notmuch-show-tag (&optional tag-changes)
+  "Change tags for the current message.
+
+See `notmuch-tag' for information on the format of TAG-CHANGES."
   (interactive)
-  (let ((tag-changes (notmuch-read-tag-changes
- initial-input (notmuch-show-get-message-id
-(apply 'notmuch-show-tag-message tag-changes)))
+  (setq tag-changes (funcall 'notmuch-tag (notmuch-show-get-message-id) 
tag-changes))
+  (let* ((current-tags (notmuch-show-get-tags))
+(new-tags (notmuch-update-tags current-tags tag-changes)))
+(unless (equal current-tags new-tags)
+  (notmuch-show-set-tags new-tags

-(defun notmuch-show-tag-all (&rest tag-changes)
-  "Change tags for all messages in the current buffer.
+(defun notmuch-show-tag-all (&optional tag-changes)
+  "Change tags for all messages in the current show buffer.

-TAG-CHANGES is a list of tag operations for `notmuch-tag'."
-  (interactive (notmuch-read-tag-changes nil notmuch-show-thread-id))
-  (apply 'notmuch-tag (notmuch-show-get-messages-ids-search) tag-changes)
+See `notmuch-tag' for information on the format of TAG-CHANGES."
+  (interactive)
+  (setq tag-changes (funcall 'notmuch-tag 
(notmuch-show-get-messages-ids-search) tag-changes))
   (notmuch-show-mapc
(lambda ()
  (let* ((current-tags (notmuch-show-get-tags))
-- 
1.7.9.1



[PATCH 6/8] emacs: eliminate search-tag-thread in favor of just search-tag

2012-04-07 Thread Jameson Graef Rollins
notmuch-search-tag-thread is now completely redundant with
notmuch-search-tag so we eliminate it to simplify the interface.
---
 emacs/notmuch.el |8 +---
 1 files changed, 1 insertions(+), 7 deletions(-)

diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index a03a526..d79a448 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -517,12 +517,6 @@ and will also appear in a buffer named \"*Notmuch 
errors*\"."
(forward-line 1))
   output)))

-(defun notmuch-search-tag-thread (&rest tag-changes)
-  "Change tags for the currently selected thread.
-
-See `notmuch-search-tag-region' for details."
-  (apply 'notmuch-search-tag-region (point) (point) tag-changes))
-
 (defun notmuch-search-tag-region (beg end &optional tag-changes)
   "Change tags for threads in the given region."
   (let ((search-string (notmuch-search-find-thread-id-region-search beg end)))
@@ -560,7 +554,7 @@ See `notmuch-tag' for information on the format of 
TAG-CHANGES."

 This function advances the next thread when finished."
   (interactive)
-  (notmuch-search-tag-thread "-inbox")
+  (notmuch-search-tag "-inbox")
   (notmuch-search-next-thread))

 (defvar notmuch-search-process-filter-data nil
-- 
1.7.9.1



[PATCH 3/8] emacs: have tag-completion return all tags for nil input

2012-04-07 Thread Jameson Graef Rollins
Previously the function would fail if the initial input was nil.  Now
it will return a list of all tags, which obviously makes much more
sense.
---
 emacs/notmuch-tag.el |2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/emacs/notmuch-tag.el b/emacs/notmuch-tag.el
index 5240d13..b1848b4 100644
--- a/emacs/notmuch-tag.el
+++ b/emacs/notmuch-tag.el
@@ -55,6 +55,8 @@ the messages that were tagged"
 `notmuch-read-tag-changes' function.")

 (defun notmuch-tag-completions (&optional search-terms)
+  (if (null search-terms)
+  (setq search-terms (list "*")))
   (split-string
(with-output-to-string
  (with-current-buffer standard-output
-- 
1.7.9.1



[PATCH 1/8] emacs: create notmuch-tag.el, and move appropriate functions from notmuch.el

2012-04-07 Thread Jameson Graef Rollins
Tagging functions are used in notmuch.el, notmuch-show.el, and
notmuch-message.el.  There are enough common functions for tagging
that it makes sense to put them all in their own library.

No code is modified, just moved around.
---
 emacs/Makefile.local |1 +
 emacs/notmuch-message.el |1 +
 emacs/notmuch-show.el|3 +-
 emacs/notmuch-tag.el |  133 ++
 emacs/notmuch.el |  107 +
 5 files changed, 137 insertions(+), 108 deletions(-)
 create mode 100644 emacs/notmuch-tag.el

diff --git a/emacs/Makefile.local b/emacs/Makefile.local
index 4fee0e8..fb82247 100644
--- a/emacs/Makefile.local
+++ b/emacs/Makefile.local
@@ -13,6 +13,7 @@ emacs_sources := \
$(dir)/notmuch-maildir-fcc.el \
$(dir)/notmuch-message.el \
$(dir)/notmuch-crypto.el \
+   $(dir)/notmuch-tag.el \
$(dir)/coolj.el \
$(dir)/notmuch-print.el

diff --git a/emacs/notmuch-message.el b/emacs/notmuch-message.el
index 3010281..5964caa 100644
--- a/emacs/notmuch-message.el
+++ b/emacs/notmuch-message.el
@@ -20,6 +20,7 @@
 ;; Authors: Jesse Rosenthal 

 (require 'message)
+(require 'notmuch-tag)
 (require 'notmuch-mua)

 (defcustom notmuch-message-replied-tags '("replied")
diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 30b26d1..a4c313d 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -30,6 +30,7 @@
 (require 'goto-addr)

 (require 'notmuch-lib)
+(require 'notmuch-tag)
 (require 'notmuch-query)
 (require 'notmuch-wash)
 (require 'notmuch-mua)
@@ -38,10 +39,8 @@

 (declare-function notmuch-call-notmuch-process "notmuch" (&rest args))
 (declare-function notmuch-fontify-headers "notmuch" nil)
-(declare-function notmuch-read-tag-changes "notmuch" (&optional initial-input 
&rest search-terms))
 (declare-function notmuch-search-next-thread "notmuch" nil)
 (declare-function notmuch-search-show-thread "notmuch" nil)
-(declare-function notmuch-update-tags "notmuch" (current-tags tag-changes))

 (defcustom notmuch-message-headers '("Subject" "To" "Cc" "Date")
   "Headers that should be shown in a message, in this order.
diff --git a/emacs/notmuch-tag.el b/emacs/notmuch-tag.el
new file mode 100644
index 000..81b4b00
--- /dev/null
+++ b/emacs/notmuch-tag.el
@@ -0,0 +1,133 @@
+;; notmuch-tag.el --- tag messages within emacs
+;;
+;; Copyright ? Carl Worth
+;;
+;; This file is part of Notmuch.
+;;
+;; Notmuch is free software: you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Notmuch is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Notmuch.  If not, see .
+;;
+;; Authors: Carl Worth 
+
+(eval-when-compile (require 'cl))
+(require 'crm)
+(require 'notmuch-lib)
+
+(defcustom notmuch-before-tag-hook nil
+  "Hooks that are run before tags of a message are modified.
+
+'tags' will contain the tags that are about to be added or removed as
+a list of strings of the form \"+TAG\" or \"-TAG\".
+'query' will be a string containing the search query that determines
+the messages that are about to be tagged"
+
+  :type 'hook
+  :options '(notmuch-hl-line-mode)
+  :group 'notmuch-hooks)
+
+(defcustom notmuch-after-tag-hook nil
+  "Hooks that are run after tags of a message are modified.
+
+'tags' will contain the tags that were added or removed as
+a list of strings of the form \"+TAG\" or \"-TAG\".
+'query' will be a string containing the search query that determines
+the messages that were tagged"
+  :type 'hook
+  :options '(notmuch-hl-line-mode)
+  :group 'notmuch-hooks)
+
+(defvar notmuch-select-tag-history nil
+  "Variable to store minibuffer history for
+`notmuch-select-tag-with-completion' function.")
+
+(defvar notmuch-read-tag-changes-history nil
+  "Variable to store minibuffer history for
+`notmuch-read-tag-changes' function.")
+
+(defun notmuch-tag-completions (&optional search-terms)
+  (split-string
+   (with-output-to-string
+ (with-current-buffer standard-output
+   (apply 'call-process notmuch-command nil t
+ nil "search-tags" search-terms)))
+   "\n+" t))
+
+(defun notmuch-select-tag-with-completion (prompt &rest search-terms)
+  (let ((tag-list (notmuch-tag-completions search-terms)))
+(completing-read prompt tag-list nil nil nil 'notmuch-select-tag-history)))
+
+(defun notmuch-read-tag-changes (&optional initial-input &rest search-terms)
+  (let* ((all-tag-list (notmuch-tag-completions))
+(add-tag-list (mapcar (apply-partially 'concat "+") all-tag-list))
+(remove-

[PATCH 0/6] Finish show rewrite

2012-04-07 Thread Austin Clements
The long-awaited and oft-belated conclusion of the show rewrite.  All
of the formatters have been converted to the new style, so this series
just rips out unused code and does a little cleanup.



[PATCH 4/6] show: Remove unused fields from notmuch_show_format

2012-04-07 Thread Austin Clements
These fields were only used by old-style formatters.
---
 notmuch-client.h |   23 ---
 1 files changed, 0 insertions(+), 23 deletions(-)

diff --git a/notmuch-client.h b/notmuch-client.h
index 34155fc..f0fb748 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -70,29 +70,6 @@ typedef struct notmuch_show_format {
 notmuch_status_t (*part) (const void *ctx,
  struct mime_node *node, int indent,
  const struct notmuch_show_params *params);
-const char *message_start;
-void (*message) (const void *ctx,
-notmuch_message_t *message,
-int indent);
-const char *header_start;
-void (*header) (const void *ctx,
-   notmuch_message_t *message);
-void (*header_message_part) (GMimeMessage *message);
-const char *header_end;
-const char *body_start;
-void (*part_start) (GMimeObject *part,
-   int *part_count);
-void (*part_encstatus) (int status);
-#ifdef GMIME_ATLEAST_26
-void (*part_sigstatus) (GMimeSignatureList* siglist);
-#else
-void (*part_sigstatus) (const GMimeSignatureValidity* validity);
-#endif
-void (*part_content) (GMimeObject *part);
-void (*part_end) (GMimeObject *part);
-const char *part_sep;
-const char *body_end;
-const char *message_end;
 const char *message_set_sep;
 const char *message_set_end;
 } notmuch_show_format_t;
-- 
1.7.9.1



[PATCH 1/6] Sync schemata with current code structure

2012-04-07 Thread Austin Clements
The schema itself hasn't changed, but many of the references to
functions in notmuch-show.c were out of date.
---
 devel/schemata |   21 +++--
 1 files changed, 7 insertions(+), 14 deletions(-)

diff --git a/devel/schemata b/devel/schemata
index 728a46f..977cea7 100644
--- a/devel/schemata
+++ b/devel/schemata
@@ -36,7 +36,7 @@ thread_node = [
 [thread_node*]# children of message
 ]

-# A message (show_message)
+# A message (format_part_json)
 message = {
 # (format_message_json)
 id: messageid,
@@ -50,18 +50,13 @@ message = {
 body:   [part]
 }

-# A MIME part (show_message_body)
+# A MIME part (format_part_json)
 part = {
-# format_part_start_json
 id: int|string, # part id (currently DFS part number)

-# format_part_encstatus_json
 encstatus?: encstatus,
-
-# format_part_sigstatus_json
 sigstatus?: sigstatus,

-# format_part_content_json
 content-type:   string,
 content-id?:string,
 # if content-type starts with "multipart/":
@@ -77,9 +72,7 @@ part = {
 content?:   string
 }

-# The headers of a message (format_headers_json with raw headers
-# and reply = FALSE) or a part (format_headers_message_part_json
-# with pretty-printed headers)
+# The headers of a message or part (format_headers_json with reply = FALSE)
 headers = {
 Subject:string,
 From:   string,
@@ -89,14 +82,14 @@ headers = {
 Date:   string
 }

-# Encryption status (format_part_encstatus_json)
+# Encryption status (format_part_json)
 encstatus = [{status: "good"|"bad"}]

 # Signature status (format_part_sigstatus_json)
 sigstatus = [signature*]

 signature = {
-# signature_status_to_string
+# (signature_status_to_string)
 status: "none"|"good"|"bad"|"error"|"unknown",
 # if status is "good":
 fingerprint?:   string,
@@ -142,14 +135,14 @@ notmuch reply schema
 

 reply = {
-# The headers of the constructed reply (format_headers_json with
-# raw headers and reply = TRUE)
+# The headers of the constructed reply
 reply-headers: reply_headers,

 # As in the show format (format_part_json)
 original: message
 }

+# Reply headers (format_headers_json with reply = TRUE)
 reply_headers = {
 Subject:string,
 From:   string,
-- 
1.7.9.1



[PATCH 2/6] show: Remove support for old-style formatters in show_message

2012-04-07 Thread Austin Clements
show_message used to have a compatibility path for old-style
formatters.  This removes that.
---
 notmuch-show.c |   52 +---
 1 files changed, 13 insertions(+), 39 deletions(-)

diff --git a/notmuch-show.c b/notmuch-show.c
index 0bf5e21..5a71115 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -815,46 +815,20 @@ show_message (void *ctx,
  int indent,
  notmuch_show_params_t *params)
 {
-if (format->part) {
-   void *local = talloc_new (ctx);
-   mime_node_t *root, *part;
-   notmuch_status_t status;
-
-   status = mime_node_open (local, message, params->cryptoctx,
-params->decrypt, &root);
-   if (status)
-   goto DONE;
-   part = mime_node_seek_dfs (root, (params->part < 0 ? 0 : params->part));
-   if (part)
-   status = format->part (local, part, indent, params);
-  DONE:
-   talloc_free (local);
-   return status;
-}
-
-if (params->part <= 0) {
-   fputs (format->message_start, stdout);
-   if (format->message)
-   format->message(ctx, message, indent);
-
-   fputs (format->header_start, stdout);
-   if (format->header)
-   format->header(ctx, message);
-   fputs (format->header_end, stdout);
-
-   fputs (format->body_start, stdout);
-}
-
-if (format->part_content)
-   show_message_body (message, format, params);
-
-if (params->part <= 0) {
-   fputs (format->body_end, stdout);
-
-   fputs (format->message_end, stdout);
-}
+void *local = talloc_new (ctx);
+mime_node_t *root, *part;
+notmuch_status_t status;

-return NOTMUCH_STATUS_SUCCESS;
+status = mime_node_open (local, message, params->cryptoctx,
+params->decrypt, &root);
+if (status)
+   goto DONE;
+part = mime_node_seek_dfs (root, (params->part < 0 ? 0 : params->part));
+if (part)
+   status = format->part (local, part, indent, params);
+  DONE:
+talloc_free (local);
+return status;
 }

 static notmuch_status_t
-- 
1.7.9.1



[PATCH 3/6] Remove show-message.c

2012-04-07 Thread Austin Clements
There are no more calls to show_message_body.
---
 Makefile.local   |1 -
 notmuch-client.h |5 ---
 show-message.c   |  106 --
 3 files changed, 0 insertions(+), 112 deletions(-)
 delete mode 100644 show-message.c

diff --git a/Makefile.local b/Makefile.local
index 1131dea..935f0f1 100644
--- a/Makefile.local
+++ b/Makefile.local
@@ -301,7 +301,6 @@ notmuch_client_srcs =   \
notmuch-tag.c   \
notmuch-time.c  \
query-string.c  \
-   show-message.c  \
mime-node.c \
json.c

diff --git a/notmuch-client.h b/notmuch-client.h
index 203ac49..34155fc 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -184,11 +184,6 @@ char *
 query_string_from_args (void *ctx, int argc, char *argv[]);

 notmuch_status_t
-show_message_body (notmuch_message_t *message,
-  const notmuch_show_format_t *format,
-  notmuch_show_params_t *params);
-
-notmuch_status_t
 show_one_part (const char *filename, int part);

 void
diff --git a/show-message.c b/show-message.c
deleted file mode 100644
index 83ecf81..000
--- a/show-message.c
+++ /dev/null
@@ -1,106 +0,0 @@
-/* notmuch - Not much of an email program, (just index and search)
- *
- * Copyright ? 2009 Carl Worth
- * Copyright ? 2009 Keith Packard
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see http://www.gnu.org/licenses/ .
- *
- * Authors: Carl Worth 
- * Keith Packard 
- */
-
-#include "notmuch-client.h"
-
-typedef struct show_message_state {
-int part_count;
-} show_message_state_t;
-
-static void
-show_message_part (mime_node_t *node,
-  show_message_state_t *state,
-  const notmuch_show_format_t *format,
-  int first)
-{
-/* Formatters expect the envelope for embedded message parts */
-GMimeObject *part = node->envelope_part ?
-   GMIME_OBJECT (node->envelope_part) : node->part;
-int i;
-
-if (!first)
-   fputs (format->part_sep, stdout);
-
-/* Format this part */
-if (format->part_start)
-   format->part_start (part, &(state->part_count));
-
-if (node->decrypt_attempted && format->part_encstatus)
-   format->part_encstatus (node->decrypt_success);
-
-if (node->verify_attempted && format->part_sigstatus)
-#ifdef GMIME_ATLEAST_26
-   format->part_sigstatus (node->sig_list);
-#else
-   format->part_sigstatus (node->sig_validity);
-#endif
-
-format->part_content (part);
-
-if (node->envelope_part) {
-   fputs (format->header_start, stdout);
-   if (format->header_message_part)
-   format->header_message_part (GMIME_MESSAGE (node->part));
-   fputs (format->header_end, stdout);
-
-   fputs (format->body_start, stdout);
-}
-
-/* Recurse over the children */
-state->part_count += 1;
-for (i = 0; i < node->nchildren; i++)
-   show_message_part (mime_node_child (node, i), state, format, i == 0);
-
-/* Finish this part */
-if (node->envelope_part)
-   fputs (format->body_end, stdout);
-
-if (format->part_end)
-   format->part_end (part);
-}
-
-notmuch_status_t
-show_message_body (notmuch_message_t *message,
-  const notmuch_show_format_t *format,
-  notmuch_show_params_t *params)
-{
-notmuch_status_t ret;
-show_message_state_t state;
-mime_node_t *root, *part;
-
-ret = mime_node_open (NULL, message, params->cryptoctx, params->decrypt,
- &root);
-if (ret)
-   return ret;
-
-/* The caller of show_message_body has already handled the
- * outermost envelope, so skip it. */
-state.part_count = MAX (params->part, 1);
-
-part = mime_node_seek_dfs (root, state.part_count);
-if (part)
-   show_message_part (part, &state, format, TRUE);
-
-talloc_free (root);
-
-return NOTMUCH_STATUS_SUCCESS;
-}
-- 
1.7.9.1



[PATCH 6/6] show: Remove empty message_set_{start,sep,end} fields

2012-04-07 Thread Austin Clements
Setting these to NULL is equivalent to the empty string now.
---
 notmuch-show.c |9 -
 1 files changed, 0 insertions(+), 9 deletions(-)

diff --git a/notmuch-show.c b/notmuch-show.c
index ef26ad2..7929476 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -26,10 +26,7 @@ format_part_text (const void *ctx, mime_node_t *node,
  int indent, const notmuch_show_params_t *params);

 static const notmuch_show_format_t format_text = {
-.message_set_start = "",
 .part = format_part_text,
-.message_set_sep = "",
-.message_set_end = ""
 };

 static notmuch_status_t
@@ -48,10 +45,7 @@ format_part_mbox (const void *ctx, mime_node_t *node,
  int indent, const notmuch_show_params_t *params);

 static const notmuch_show_format_t format_mbox = {
-.message_set_start = "",
 .part = format_part_mbox,
-.message_set_sep = "",
-.message_set_end = ""
 };

 static notmuch_status_t
@@ -60,10 +54,7 @@ format_part_raw (unused (const void *ctx), mime_node_t *node,
 unused (const notmuch_show_params_t *params));

 static const notmuch_show_format_t format_raw = {
-.message_set_start = "",
 .part = format_part_raw,
-.message_set_sep = "",
-.message_set_end = ""
 };

 static const char *
-- 
1.7.9.1



[PATCH 5/6] show: Support NULL values for message_set_{start, sep, end}

2012-04-07 Thread Austin Clements
Many formats don't need these, so it's more convenient if they don't
have to set them at all.
---
 notmuch-show.c |   24 +++-
 1 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/notmuch-show.c b/notmuch-show.c
index 5a71115..ef26ad2 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -844,17 +844,19 @@ show_messages (void *ctx,
 int next_indent;
 notmuch_status_t status, res = NOTMUCH_STATUS_SUCCESS;

-fputs (format->message_set_start, stdout);
+if (format->message_set_start)
+   fputs (format->message_set_start, stdout);

 for (;
 notmuch_messages_valid (messages);
 notmuch_messages_move_to_next (messages))
 {
-   if (!first_set)
+   if (!first_set && format->message_set_sep)
fputs (format->message_set_sep, stdout);
first_set = 0;

-   fputs (format->message_set_start, stdout);
+   if (format->message_set_start)
+   fputs (format->message_set_start, stdout);

message = notmuch_messages_get (messages);

@@ -868,7 +870,7 @@ show_messages (void *ctx,
res = status;
next_indent = indent + 1;

-   if (!status)
+   if (!status && format->message_set_sep)
fputs (format->message_set_sep, stdout);
}

@@ -882,10 +884,12 @@ show_messages (void *ctx,

notmuch_message_destroy (message);

-   fputs (format->message_set_end, stdout);
+   if (format->message_set_end)
+   fputs (format->message_set_end, stdout);
 }

-fputs (format->message_set_end, stdout);
+if (format->message_set_end)
+   fputs (format->message_set_end, stdout);

 return res;
 }
@@ -931,7 +935,8 @@ do_show (void *ctx,
 int first_toplevel = 1;
 notmuch_status_t status, res = NOTMUCH_STATUS_SUCCESS;

-fputs (format->message_set_start, stdout);
+if (format->message_set_start)
+   fputs (format->message_set_start, stdout);

 for (threads = notmuch_query_search_threads (query);
 notmuch_threads_valid (threads);
@@ -945,7 +950,7 @@ do_show (void *ctx,
INTERNAL_ERROR ("Thread %s has no toplevel messages.\n",
notmuch_thread_get_thread_id (thread));

-   if (!first_toplevel)
+   if (!first_toplevel && format->message_set_sep)
fputs (format->message_set_sep, stdout);
first_toplevel = 0;

@@ -957,7 +962,8 @@ do_show (void *ctx,

 }

-fputs (format->message_set_end, stdout);
+if (format->message_set_end)
+   fputs (format->message_set_end, stdout);

 return res != NOTMUCH_STATUS_SUCCESS;
 }
-- 
1.7.9.1



[PATCH] News for raw format changes

2012-04-07 Thread Austin Clements
---
 NEWS |   11 +++
 1 files changed, 11 insertions(+), 0 deletions(-)

diff --git a/NEWS b/NEWS
index a618a9d..c1704e0 100644
--- a/NEWS
+++ b/NEWS
@@ -41,6 +41,17 @@ Tag exclusion

 notmuch config set search.exclude_tags deleted spam

+Raw show format changes
+
+  The output of show --format=raw has changed for multipart and
+  message parts.  Previously, the output was a mash of somewhat-parsed
+  headers and transfer-decoded bodies.  Now, such parts are reproduced
+  faithfully from the original source.  Message parts (which includes
+  part 0) output the full message, including the message headers (but
+  not the transfer headers).  Multipart parts output the part as
+  encoded in the original message, including the part's headers.  Leaf
+  parts, as before, output the part's transfer-decoded body.
+
 Emacs Interface
 ---

-- 
1.7.9.1



[PATCH v4 0/6] Move --no-exclude to --exclude=(true|false|flag)

2012-04-07 Thread Jameson Graef Rollins
On Sat, Apr 07 2012, Mark Walters  wrote:
> This is version 4 of the exclude= patch set. Version 3 was at [1].
>
> The only changes relative to version 3 are in the tests. As suggested
> by jrollins [2] I have added some systematic count and show tests and
> moved all the exclude tests to the file test/excludes.

Tested.  LGTM.

jamie.
-- next part --
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 835 bytes
Desc: not available
URL: 
<http://notmuchmail.org/pipermail/notmuch/attachments/20120407/153f10b8/attachment.pgp>


[PATCH v4 0/6] Move --no-exclude to --exclude=(true|false|flag)

2012-04-07 Thread David Bremner
Mark Walters  writes:

> This is version 4 of the exclude= patch set. Version 3 was at [1].
>
> The only changes relative to version 3 are in the tests. As suggested
> by jrollins [2] I have added some systematic count and show tests and
> moved all the exclude tests to the file test/excludes.

Pushed.

d