[RFC patch] emacs: skeleton of texinfo manual for emacs interface.

2013-03-09 Thread da...@tethera.net
From: David Bremner 

Currently this only attempts to document the notmuch-hello interface.
---

I have thought for a long time that we should have some unified
documentation for the emacs interface. This is some sketch of a
beginning.  Building such a document turns out to be a fair amount of
work, but I guess it should be possible to have something better than
what we have now (i.e. nothing). I did try to avoid duplication with
both the docstrings and the man pages. Eventually perhaps we should
have some common format to generate the man pages and info pages from,
but I didn't want to hold up the whole effort waiting for that.

One thing that would make this effort more bearable is being able to
re-use material from the wiki. Currently there is no license
information at all on that material; I'm not sure exactly how to
proceed.

To build this, use "makeinfo notmuch.texi"
You can then (perversely) view it without emacs with "info -f notmuch.info"
or in emacs with C-u C-h i notmuch.info.


 emacs/notmuch.texi | 274 +
 emacs/version.texi |   2 +
 2 files changed, 276 insertions(+)
 create mode 100644 emacs/notmuch.texi
 create mode 100644 emacs/version.texi

diff --git a/emacs/notmuch.texi b/emacs/notmuch.texi
new file mode 100644
index 000..d4f7296
--- /dev/null
+++ b/emacs/notmuch.texi
@@ -0,0 +1,274 @@
+\input texinfo   @c -*-texinfo-*-
+ at comment $Id at w{$}
+ at comment %**start of header
+ at setfilename notmuch.info
+ at include version.texi
+ at settitle Notmuch @value{VERSION}
+ at comment %**end of header
+
+ at macro keyindex {NAME}
+ at kindex \NAME\
+ at cindex \NAME\
+ at end macro
+
+ at macro funindex {NAME}
+ at findex \NAME\
+ at cindex \NAME\
+ at end macro
+
+ at macro varindex {NAME}
+ at vindex \NAME\
+ at cindex \NAME\
+ at end macro
+
+
+ at copying
+This manual is for Notmuch (version @value{VERSION}, @value{UPDATED})
+
+Copyright @copyright{} 2013 David Bremner
+
+This manual is distributed under the same terms as notmuch, which are as 
follows.
+ at quotation
+ 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/ .
+
+ at end quotation
+ at end copying
+
+ at dircategory Texinfo documentation system
+ at direntry
+* notmuch: (notmuch)Emacs interface to notmuch
+ at end direntry
+
+ at titlepage
+ at title Notmuch
+ at subtitle for version @value{VERSION}, @value{UPDATED}
+ at author David Bremner (@email{david@@tethera.net})
+ at page
+ at vskip 0pt plus 1filll
+ at insertcopying
+ at end titlepage
+
+ at contents
+
+ at ifnottex
+ at node Top
+ at top Notmuch
+
+This manual is for Notmuch (version @value{VERSION}, @value{UPDATED}).
+ at end ifnottex
+
+ at menu
+* About this Manual::
+* notmuch-hello::
+* notmuch-search::
+* Search Syntax::
+* Configuration::
+* Function Index::
+* Variable Index::
+* Index::
+ at end menu
+
+
+ at node About this Manual
+ at unnumbered About this Manual
+
+This manual covers only the emacs interface to notmuch. For
+information on the command line interface, see
+ at url{http://notmuchmail.org/manpages/notmuch-1,the notmuch man page}.
+To save
+typing, we will sometimes use @emph{notmuch} in this manual to refer
+to the Emacs interface to notmuch. If the distinction should every be
+important, we'll refer to the Emacs inteface as @emph{notmuch-emacs}.
+
+Notmuch-emacs is highly customizable via the the Emacs customization
+framework (or just by setting the appropriate variables).  We try to
+point out relevant variables in this manual, but in order to avoid
+duplication of information, but you can usually find the most detailed
+description in the varables docstring.
+
+ at node notmuch-hello
+ at chapter notmuch-hello
+
+ at funindex notmuch-hello
+ at funindex notmuch
+
+ at command{notmuch-hello} is the main entry point for notmuch. You can
+start it with @kbd{M-x notmuch} or @kbd{M-x notmuch-hello}. The
+startup screen looks something like the following. There are some
+hints at the bottom of the screen.  There are three main parts to the
+notmuch-hello screen, discussed below. The @strong{bold} text
+indicates buttons you can click with a mouse or by positioning the
+cursor and pressing @kbd{}
+
+ at example
+ at group
+
+
+   Welcome to @strong{notmuch}. You have 52 messages.
+
+Saved searches: @strong{[edit]}
+
+ 

[PATCH v2 6/6] emacs: hello: use batch count

2013-03-09 Thread Jani Nikula
From: Mark Walters 

This modifies notmuch hello to use the new count --batch
functionality. It should give exactly the same results as before but
under many conditions it should be much faster. In particular it is
much faster for remote use.

The code is a little ugly as it has to do some working out of the
query when asking the query and some when dealing with the result.
However, the code path is exactly the same in both local and remote
use.
---
 emacs/notmuch-hello.el |   52 +---
 1 file changed, 32 insertions(+), 20 deletions(-)

diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
index 00b78e1..cda79f1 100644
--- a/emacs/notmuch-hello.el
+++ b/emacs/notmuch-hello.el
@@ -381,26 +381,38 @@ The result is the list of elements of the form (NAME 
QUERY COUNT).
 The values :show-empty-searches, :filter and :filter-count from
 options will be handled as specified for
 `notmuch-hello-insert-searches'."
-  (notmuch-remove-if-not
-   #'identity
-   (mapcar
-(lambda (elem)
-  (let* ((name (car elem))
-(query-and-count (if (consp (cdr elem))
- ;; do we have a different query for the 
message count?
- (cons (second elem) (third elem))
-   (cons (cdr elem) (cdr elem
-(message-count
- (string-to-number
-  (notmuch-saved-search-count
-   (notmuch-hello-filtered-query (cdr query-and-count)
- (or (plist-get options 
:filter-count)
-(plist-get options 
:filter)))
-   (and (or (plist-get options :show-empty-searches) (> message-count 0))
-(list name (notmuch-hello-filtered-query
-(car query-and-count) (plist-get options :filter))
-  message-count
-query-alist)))
+  (with-temp-buffer
+(dolist (elem query-alist nil)
+  (let ((count-query (if (consp (cdr elem))
+;; do we have a different query for the message 
count?
+(third elem)
+  (cdr elem
+   (insert
+(notmuch-hello-filtered-query count-query
+  (or (plist-get options :filter-count)
+  (plist-get options :filter)))
+"\n")))
+
+(call-process-region (point-min) (point-max) notmuch-command
+t t nil "count" "--batch")
+(goto-char (point-min))
+
+(notmuch-remove-if-not
+ #'identity
+ (mapcar
+  (lambda (elem)
+   (let ((name (car elem))
+ (search-query (if (consp (cdr elem))
+;; do we have a different query for the 
message count?
+(second elem)
+ (cdr elem)))
+ (message-count (prog1 (read (current-buffer))
+   (forward-line 1
+ (and (or (plist-get options :show-empty-searches) (> message-count 0))
+  (list name (notmuch-hello-filtered-query
+  search-query (plist-get options :filter))
+message-count
+  query-alist

 (defun notmuch-hello-insert-buttons (searches)
   "Insert buttons for SEARCHES.
-- 
1.7.10.4



[PATCH v2 5/6] test: notmuch count --batch and --input options

2013-03-09 Thread Jani Nikula
---
 test/count |   46 ++
 1 file changed, 46 insertions(+)

diff --git a/test/count b/test/count
index 879b114..05713fd 100755
--- a/test/count
+++ b/test/count
@@ -38,4 +38,50 @@ test_expect_equal \
 "0" \
 "`notmuch count --output=threads from:cworth and not from:cworth`"

+test_begin_subtest "message count is the default for batch count"
+notmuch count --batch >OUTPUT >EXPECTED
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest "batch message count"
+notmuch count --batch --output=messages >OUTPUT >EXPECTED
+notmuch count --output=messages tag:inbox >>EXPECTED
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest "batch thread count"
+notmuch count --batch --output=threads >OUTPUT >EXPECTED
+notmuch count --output=threads from:cworth and not from:cworth >>EXPECTED
+notmuch count --output=threads foo >>EXPECTED
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest "batch message count with input file"
+cat >INPUT EXPECTED
+notmuch count --output=messages >>EXPECTED
+notmuch count --output=messages tag:inbox >>EXPECTED
+test_expect_equal_file EXPECTED OUTPUT
+
+
 test_done
-- 
1.7.10.4



[PATCH v2 4/6] man: document notmuch count --batch and --input options

2013-03-09 Thread Jani Nikula
---
 man/man1/notmuch-count.1 |   20 
 1 file changed, 20 insertions(+)

diff --git a/man/man1/notmuch-count.1 b/man/man1/notmuch-count.1
index 86a67fe..7fc4378 100644
--- a/man/man1/notmuch-count.1
+++ b/man/man1/notmuch-count.1
@@ -46,6 +46,26 @@ Output the number of matching threads.
 Specify whether to omit messages matching search.tag_exclude from the
 count (the default) or not.
 .RE
+
+.RS 4
+.TP 4
+.BR \-\-batch
+
+Read queries from a file (stdin by default), one per line, and output
+the number of matching messages (or threads) to stdout, one per
+line. On an empty input line the count of all messages (or threads) in
+the database will be output. This option is not compatible with
+specifying search terms on the command line.
+.RE
+
+.RS 4
+.TP 4
+.BR "\-\-input=" 
+
+Read input from given file, instead of from stdin. Implies
+.BR --batch .
+.RE
+
 .RE
 .RE

-- 
1.7.10.4



[PATCH v2 3/6] cli: add --batch option to notmuch count

2013-03-09 Thread Jani Nikula
Add support for reading queries from stdin, one per line, and writing
results to stdin, one per line.

This will bring considerable performance improvements when utilized in
Emacs notmuch-hello, especially so when running remote notmuch.
---
 notmuch-count.c |   52 ++--
 1 file changed, 50 insertions(+), 2 deletions(-)

diff --git a/notmuch-count.c b/notmuch-count.c
index 630f036..8772cff 100644
--- a/notmuch-count.c
+++ b/notmuch-count.c
@@ -62,6 +62,27 @@ print_count (notmuch_database_t *notmuch, const char 
*query_str,
 return 0;
 }

+static int
+count_file (notmuch_database_t *notmuch, FILE *input, const char 
**exclude_tags,
+   size_t exclude_tags_length, int output)
+{
+char *line = NULL;
+ssize_t line_len;
+size_t line_size;
+int ret = 0;
+
+while (!ret && (line_len = getline (, _size, input)) != -1) {
+   chomp_newline (line);
+   ret = print_count (notmuch, line, exclude_tags, exclude_tags_length,
+  output);
+}
+
+if (line)
+   free (line);
+
+return ret;
+}
+
 int
 notmuch_count_command (notmuch_config_t *config, int argc, char *argv[])
 {
@@ -72,6 +93,9 @@ notmuch_count_command (notmuch_config_t *config, int argc, 
char *argv[])
 int exclude = EXCLUDE_TRUE;
 const char **search_exclude_tags = NULL;
 size_t search_exclude_tags_length = 0;
+notmuch_bool_t batch = FALSE;
+FILE *input = stdin;
+char *input_file_name = NULL;
 int ret;

 notmuch_opt_desc_t options[] = {
@@ -83,6 +107,8 @@ notmuch_count_command (notmuch_config_t *config, int argc, 
char *argv[])
  (notmuch_keyword_t []){ { "true", EXCLUDE_TRUE },
  { "false", EXCLUDE_FALSE },
  { 0, 0 } } },
+   { NOTMUCH_OPT_BOOLEAN, , "batch", 0, 0 },
+   { NOTMUCH_OPT_STRING, _file_name, "input", 'i', 0 },
{ 0, 0, 0, 0, 0 }
 };

@@ -92,6 +118,21 @@ notmuch_count_command (notmuch_config_t *config, int argc, 
char *argv[])
return 1;
 }

+if (input_file_name) {
+   batch = TRUE;
+   input = fopen (input_file_name, "r");
+   if (input == NULL) {
+   fprintf (stderr, "Error opening %s for reading: %s\n",
+input_file_name, strerror (errno));
+   return 1;
+   }
+}
+
+if (batch && opt_index != argc) {
+   fprintf (stderr, "--batch and query string are not compatible\n");
+   return 1;
+}
+
 if (notmuch_database_open (notmuch_config_get_database_path (config),
   NOTMUCH_DATABASE_MODE_READ_ONLY, ))
return 1;
@@ -107,10 +148,17 @@ notmuch_count_command (notmuch_config_t *config, int 
argc, char *argv[])
(config, _exclude_tags_length);
 }

-ret = print_count (notmuch, query_str, search_exclude_tags,
-  search_exclude_tags_length, output);
+if (batch)
+   ret = count_file (notmuch, input, search_exclude_tags,
+ search_exclude_tags_length, output);
+else
+   ret = print_count (notmuch, query_str, search_exclude_tags,
+  search_exclude_tags_length, output);

 notmuch_database_destroy (notmuch);

+if (input != stdin)
+   fclose (input);
+
 return ret;
 }
-- 
1.7.10.4



[PATCH v2 2/6] cli: extract count printing to a separate function in notmuch count

2013-03-09 Thread Jani Nikula
Make count printing on a query string reusable. No functional changes.
---
 notmuch-count.c |   59 +--
 1 file changed, 36 insertions(+), 23 deletions(-)

diff --git a/notmuch-count.c b/notmuch-count.c
index c2f1b7d..630f036 100644
--- a/notmuch-count.c
+++ b/notmuch-count.c
@@ -32,16 +32,47 @@ enum {
 EXCLUDE_FALSE,
 };

+static int
+print_count (notmuch_database_t *notmuch, const char *query_str,
+const char **exclude_tags, size_t exclude_tags_length, int output)
+{
+notmuch_query_t *query;
+size_t i;
+
+query = notmuch_query_create (notmuch, query_str);
+if (query == NULL) {
+   fprintf (stderr, "Out of memory\n");
+   return 1;
+}
+
+for (i = 0; i < exclude_tags_length; i++)
+   notmuch_query_add_tag_exclude (query, exclude_tags[i]);
+
+switch (output) {
+case OUTPUT_MESSAGES:
+   printf ("%u\n", notmuch_query_count_messages (query));
+   break;
+case OUTPUT_THREADS:
+   printf ("%u\n", notmuch_query_count_threads (query));
+   break;
+}
+
+notmuch_query_destroy (query);
+
+return 0;
+}
+
 int
 notmuch_count_command (notmuch_config_t *config, int argc, char *argv[])
 {
 notmuch_database_t *notmuch;
-notmuch_query_t *query;
 char *query_str;
 int opt_index;
 int output = OUTPUT_MESSAGES;
 int exclude = EXCLUDE_TRUE;
-unsigned int i;
+const char **search_exclude_tags = NULL;
+size_t search_exclude_tags_length = 0;
+int ret;

 notmuch_opt_desc_t options[] = {
{ NOTMUCH_OPT_KEYWORD, , "output", 'o',
@@ -71,33 +102,15 @@ notmuch_count_command (notmuch_config_t *config, int argc, 
char *argv[])
return 1;
 }

-query = notmuch_query_create (notmuch, query_str);
-if (query == NULL) {
-   fprintf (stderr, "Out of memory\n");
-   return 1;
-}
-
 if (exclude == EXCLUDE_TRUE) {
-   const char **search_exclude_tags;
-   size_t search_exclude_tags_length;
-
search_exclude_tags = notmuch_config_get_search_exclude_tags
(config, _exclude_tags_length);
-   for (i = 0; i < search_exclude_tags_length; i++)
-   notmuch_query_add_tag_exclude (query, search_exclude_tags[i]);
 }

-switch (output) {
-case OUTPUT_MESSAGES:
-   printf ("%u\n", notmuch_query_count_messages (query));
-   break;
-case OUTPUT_THREADS:
-   printf ("%u\n", notmuch_query_count_threads (query));
-   break;
-}
+ret = print_count (notmuch, query_str, search_exclude_tags,
+  search_exclude_tags_length, output);

-notmuch_query_destroy (query);
 notmuch_database_destroy (notmuch);

-return 0;
+return ret;
 }
-- 
1.7.10.4



[PATCH v2 1/6] cli: remove useless strdup

2013-03-09 Thread Jani Nikula
---
 notmuch-count.c |4 
 1 file changed, 4 deletions(-)

diff --git a/notmuch-count.c b/notmuch-count.c
index 390794f..c2f1b7d 100644
--- a/notmuch-count.c
+++ b/notmuch-count.c
@@ -71,10 +71,6 @@ notmuch_count_command (notmuch_config_t *config, int argc, 
char *argv[])
return 1;
 }

-if (*query_str == '\0') {
-   query_str = talloc_strdup (config, "");
-}
-
 query = notmuch_query_create (notmuch, query_str);
 if (query == NULL) {
fprintf (stderr, "Out of memory\n");
-- 
1.7.10.4



[PATCH v2 0/6] batch count for notmuch-hello speedup

2013-03-09 Thread Jani Nikula
Rebased v2 of id:cover.1358273133.git.jani at nikula.org

Jani Nikula (5):
  cli: remove useless strdup
  cli: extract count printing to a separate function in notmuch count
  cli: add --batch option to notmuch count
  man: document notmuch count --batch and --input options
  test: notmuch count --batch and --input options

Mark Walters (1):
  emacs: hello: use batch count

 emacs/notmuch-hello.el   |   52 +-
 man/man1/notmuch-count.1 |   20 +
 notmuch-count.c  |  111 +++---
 test/count   |   46 +++
 4 files changed, 182 insertions(+), 47 deletions(-)

-- 
1.7.10.4



[PATCH v2 4/4] test: notmuch tag --remove-all

2013-03-09 Thread Jani Nikula
---
 test/tagging |   16 
 1 file changed, 16 insertions(+)

diff --git a/test/tagging b/test/tagging
index 1f5632c..dc118f3 100755
--- a/test/tagging
+++ b/test/tagging
@@ -30,6 +30,22 @@ test_expect_equal "$output" "\
 thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; One (inbox tag1 unread)
 thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; Two (inbox tag1 unread)"

+test_begin_subtest "Remove all"
+notmuch tag --remove-all One
+notmuch tag --remove-all +tag5 +tag6 +unread Two
+output=$(notmuch search \* | notmuch_search_sanitize)
+test_expect_equal "$output" "\
+thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; One ()
+thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; Two (tag5 tag6 unread)"
+
+test_begin_subtest "Remove all with a no-op"
+notmuch tag +inbox +tag1 +unread One
+notmuch tag --remove-all +foo +inbox +tag1 -foo +unread Two
+output=$(notmuch search \* | notmuch_search_sanitize)
+test_expect_equal "$output" "\
+thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; One (inbox tag1 unread)
+thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; Two (inbox tag1 unread)"
+
 test_begin_subtest "Special characters in tags"
 notmuch tag +':" ' \*
 notmuch tag -':" ' Two
-- 
1.7.10.4



[PATCH v2 3/4] man: document notmuch tag --remove-all

2013-03-09 Thread Jani Nikula
---
 man/man1/notmuch-tag.1 |   12 +++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/man/man1/notmuch-tag.1 b/man/man1/notmuch-tag.1
index 0052ca2..c7d7a4d 100644
--- a/man/man1/notmuch-tag.1
+++ b/man/man1/notmuch-tag.1
@@ -4,7 +4,7 @@ notmuch-tag \- add/remove tags for all messages matching the 
search terms

 .SH SYNOPSIS
 .B notmuch tag
-.RI "+<" tag ">|\-<" tag "> [...] [\-\-] <" search-term "> [...]"
+.RI [ options "...] +<" tag ">|\-<" tag "> [...] [\-\-] <" search-term "> 
[...]"

 .B notmuch tag
 .RI "--batch"
@@ -40,6 +40,16 @@ Supported options for
 include
 .RS 4
 .TP 4
+.BR \-\-remove\-all
+
+Remove all tags from each message matching the search terms before
+applying the tag changes appearing on the command line. This means
+setting the tags of each message to the tags to be added. If there are
+no tags to be added, the messages will have no tags.
+.RE
+
+.RS 4
+.TP 4
 .BR \-\-batch

 Read batch tagging operations from a file (stdin by default). This is more
-- 
1.7.10.4



[PATCH v2 2/4] cli: add --remove-all option to "notmuch tag"

2013-03-09 Thread Jani Nikula
Add --remove-all option to "notmuch tag" to remove all tags from the
messages matching query before applying the tag changes. This allows
removal of all tags and unconditional setting of the tags of a
message:

$ notmuch tag --remove-all id:foo at example.com
$ notmuch tag --remove-all +foo +bar id:foo at example.com

without having to resort to the complicated (and still quoting
broken):

$ notmuch tag $(notmuch search --output=tags '*' | sed 's/^/-/') \
  id:foo at example.com
$ notmuch tag $(notmuch search --output=tags '*' | sed 's/^/-/') \
  +foo +bar id:foo at example.com
---
 notmuch-tag.c |   28 
 1 file changed, 20 insertions(+), 8 deletions(-)

diff --git a/notmuch-tag.c b/notmuch-tag.c
index bc61aab..9a5d3e7 100644
--- a/notmuch-tag.c
+++ b/notmuch-tag.c
@@ -99,12 +99,15 @@ tag_query (void *ctx, notmuch_database_t *notmuch, const 
char *query_string,
 notmuch_message_t *message;
 int ret = NOTMUCH_STATUS_SUCCESS;

-/* Optimize the query so it excludes messages that already have
- * the specified set of tags. */
-query_string = _optimize_tag_query (ctx, query_string, tag_ops);
-if (query_string == NULL) {
-   fprintf (stderr, "Out of memory.\n");
-   return 1;
+if (! (flags & TAG_FLAG_REMOVE_ALL)) {
+   /* Optimize the query so it excludes messages that already
+* have the specified set of tags. */
+   query_string = _optimize_tag_query (ctx, query_string, tag_ops);
+   if (query_string == NULL) {
+   fprintf (stderr, "Out of memory.\n");
+   return 1;
+   }
+   flags |= TAG_FLAG_PRE_OPTIMIZED;
 }

 query = notmuch_query_create (notmuch, query_string);
@@ -120,7 +123,7 @@ tag_query (void *ctx, notmuch_database_t *notmuch, const 
char *query_string,
 notmuch_messages_valid (messages) && ! interrupted;
 notmuch_messages_move_to_next (messages)) {
message = notmuch_messages_get (messages);
-   ret = tag_op_list_apply (message, tag_ops, flags | 
TAG_FLAG_PRE_OPTIMIZED);
+   ret = tag_op_list_apply (message, tag_ops, flags);
notmuch_message_destroy (message);
if (ret != NOTMUCH_STATUS_SUCCESS)
break;
@@ -186,6 +189,7 @@ notmuch_tag_command (notmuch_config_t *config, int argc, 
char *argv[])
 struct sigaction action;
 tag_op_flag_t tag_flags = TAG_FLAG_NONE;
 notmuch_bool_t batch = FALSE;
+notmuch_bool_t remove_all = FALSE;
 FILE *input = stdin;
 char *input_file_name = NULL;
 int opt_index;
@@ -201,6 +205,7 @@ notmuch_tag_command (notmuch_config_t *config, int argc, 
char *argv[])
 notmuch_opt_desc_t options[] = {
{ NOTMUCH_OPT_BOOLEAN, , "batch", 0, 0 },
{ NOTMUCH_OPT_STRING, _file_name, "input", 'i', 0 },
+   { NOTMUCH_OPT_BOOLEAN, _all, "remove-all", 0, 0 },
{ 0, 0, 0, 0, 0 }
 };

@@ -223,6 +228,10 @@ notmuch_tag_command (notmuch_config_t *config, int argc, 
char *argv[])
fprintf (stderr, "Can't specify both cmdline and stdin!\n");
return 1;
}
+   if (remove_all) {
+   fprintf (stderr, "Can't specify both --remove-all and --batch\n");
+   return 1;
+   }
 } else {
tag_ops = tag_op_list_create (config);
if (tag_ops == NULL) {
@@ -234,7 +243,7 @@ notmuch_tag_command (notmuch_config_t *config, int argc, 
char *argv[])
_string, tag_ops))
return 1;

-   if (tag_op_list_size (tag_ops) == 0) {
+   if (tag_op_list_size (tag_ops) == 0 && ! remove_all) {
fprintf (stderr, "Error: 'notmuch tag' requires at least one tag to 
add or remove.\n");
return 1;
}
@@ -247,6 +256,9 @@ notmuch_tag_command (notmuch_config_t *config, int argc, 
char *argv[])
 if (notmuch_config_get_maildir_synchronize_flags (config))
tag_flags |= TAG_FLAG_MAILDIR_SYNC;

+if (remove_all)
+   tag_flags |= TAG_FLAG_REMOVE_ALL;
+
 if (batch)
ret = tag_file (config, notmuch, tag_flags, input);
 else
-- 
1.7.10.4



[PATCH v2 1/4] cli: make caller check tag count in parse_tag_command_line

2013-03-09 Thread Jani Nikula
---
 notmuch-tag.c |5 +
 tag-util.c|5 -
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/notmuch-tag.c b/notmuch-tag.c
index 0e73197..bc61aab 100644
--- a/notmuch-tag.c
+++ b/notmuch-tag.c
@@ -233,6 +233,11 @@ notmuch_tag_command (notmuch_config_t *config, int argc, 
char *argv[])
if (parse_tag_command_line (config, argc - opt_index, argv + opt_index,
_string, tag_ops))
return 1;
+
+   if (tag_op_list_size (tag_ops) == 0) {
+   fprintf (stderr, "Error: 'notmuch tag' requires at least one tag to 
add or remove.\n");
+   return 1;
+   }
 }

 if (notmuch_database_open (notmuch_config_get_database_path (config),
diff --git a/tag-util.c b/tag-util.c
index 701d329..c5f5859 100644
--- a/tag-util.c
+++ b/tag-util.c
@@ -188,11 +188,6 @@ parse_tag_command_line (void *ctx, int argc, char **argv,
tag_op_list_append (tag_ops, argv[i] + 1, is_remove);
 }

-if (tag_op_list_size (tag_ops) == 0) {
-   fprintf (stderr, "Error: 'notmuch tag' requires at least one tag to add 
or remove.\n");
-   return TAG_PARSE_INVALID;
-}
-
 *query_str = query_string_from_args (ctx, argc - i, [i]);

 if (*query_str == NULL || **query_str == '\0') {
-- 
1.7.10.4



[PATCH v2 0/4] cli: notmuch tag --remove-all option

2013-03-09 Thread Jani Nikula
Rebased version of
id:1a2c09adc1c963f1aa209c09143f85dca7634e11.1358876448.git.jani at nikula.org

Jani Nikula (4):
  cli: make caller check tag count in parse_tag_command_line
  cli: add --remove-all option to "notmuch tag"
  man: document notmuch tag --remove-all
  test: notmuch tag --remove-all

 man/man1/notmuch-tag.1 |   12 +++-
 notmuch-tag.c  |   31 ---
 tag-util.c |5 -
 test/tagging   |   16 
 4 files changed, 51 insertions(+), 13 deletions(-)

-- 
1.7.10.4



[PATCH v2 0/4] cli: notmuch tag --remove-all option

2013-03-09 Thread Jani Nikula
Rebased version of
id:1a2c09adc1c963f1aa209c09143f85dca7634e11.1358876448.git.j...@nikula.org

Jani Nikula (4):
  cli: make caller check tag count in parse_tag_command_line
  cli: add --remove-all option to notmuch tag
  man: document notmuch tag --remove-all
  test: notmuch tag --remove-all

 man/man1/notmuch-tag.1 |   12 +++-
 notmuch-tag.c  |   31 ---
 tag-util.c |5 -
 test/tagging   |   16 
 4 files changed, 51 insertions(+), 13 deletions(-)

-- 
1.7.10.4

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


[PATCH v2 1/4] cli: make caller check tag count in parse_tag_command_line

2013-03-09 Thread Jani Nikula
---
 notmuch-tag.c |5 +
 tag-util.c|5 -
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/notmuch-tag.c b/notmuch-tag.c
index 0e73197..bc61aab 100644
--- a/notmuch-tag.c
+++ b/notmuch-tag.c
@@ -233,6 +233,11 @@ notmuch_tag_command (notmuch_config_t *config, int argc, 
char *argv[])
if (parse_tag_command_line (config, argc - opt_index, argv + opt_index,
query_string, tag_ops))
return 1;
+
+   if (tag_op_list_size (tag_ops) == 0) {
+   fprintf (stderr, Error: 'notmuch tag' requires at least one tag to 
add or remove.\n);
+   return 1;
+   }
 }
 
 if (notmuch_database_open (notmuch_config_get_database_path (config),
diff --git a/tag-util.c b/tag-util.c
index 701d329..c5f5859 100644
--- a/tag-util.c
+++ b/tag-util.c
@@ -188,11 +188,6 @@ parse_tag_command_line (void *ctx, int argc, char **argv,
tag_op_list_append (tag_ops, argv[i] + 1, is_remove);
 }
 
-if (tag_op_list_size (tag_ops) == 0) {
-   fprintf (stderr, Error: 'notmuch tag' requires at least one tag to add 
or remove.\n);
-   return TAG_PARSE_INVALID;
-}
-
 *query_str = query_string_from_args (ctx, argc - i, argv[i]);
 
 if (*query_str == NULL || **query_str == '\0') {
-- 
1.7.10.4

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


[PATCH v2 2/4] cli: add --remove-all option to notmuch tag

2013-03-09 Thread Jani Nikula
Add --remove-all option to notmuch tag to remove all tags from the
messages matching query before applying the tag changes. This allows
removal of all tags and unconditional setting of the tags of a
message:

$ notmuch tag --remove-all id:f...@example.com
$ notmuch tag --remove-all +foo +bar id:f...@example.com

without having to resort to the complicated (and still quoting
broken):

$ notmuch tag $(notmuch search --output=tags '*' | sed 's/^/-/') \
  id:f...@example.com
$ notmuch tag $(notmuch search --output=tags '*' | sed 's/^/-/') \
  +foo +bar id:f...@example.com
---
 notmuch-tag.c |   28 
 1 file changed, 20 insertions(+), 8 deletions(-)

diff --git a/notmuch-tag.c b/notmuch-tag.c
index bc61aab..9a5d3e7 100644
--- a/notmuch-tag.c
+++ b/notmuch-tag.c
@@ -99,12 +99,15 @@ tag_query (void *ctx, notmuch_database_t *notmuch, const 
char *query_string,
 notmuch_message_t *message;
 int ret = NOTMUCH_STATUS_SUCCESS;
 
-/* Optimize the query so it excludes messages that already have
- * the specified set of tags. */
-query_string = _optimize_tag_query (ctx, query_string, tag_ops);
-if (query_string == NULL) {
-   fprintf (stderr, Out of memory.\n);
-   return 1;
+if (! (flags  TAG_FLAG_REMOVE_ALL)) {
+   /* Optimize the query so it excludes messages that already
+* have the specified set of tags. */
+   query_string = _optimize_tag_query (ctx, query_string, tag_ops);
+   if (query_string == NULL) {
+   fprintf (stderr, Out of memory.\n);
+   return 1;
+   }
+   flags |= TAG_FLAG_PRE_OPTIMIZED;
 }
 
 query = notmuch_query_create (notmuch, query_string);
@@ -120,7 +123,7 @@ tag_query (void *ctx, notmuch_database_t *notmuch, const 
char *query_string,
 notmuch_messages_valid (messages)  ! interrupted;
 notmuch_messages_move_to_next (messages)) {
message = notmuch_messages_get (messages);
-   ret = tag_op_list_apply (message, tag_ops, flags | 
TAG_FLAG_PRE_OPTIMIZED);
+   ret = tag_op_list_apply (message, tag_ops, flags);
notmuch_message_destroy (message);
if (ret != NOTMUCH_STATUS_SUCCESS)
break;
@@ -186,6 +189,7 @@ notmuch_tag_command (notmuch_config_t *config, int argc, 
char *argv[])
 struct sigaction action;
 tag_op_flag_t tag_flags = TAG_FLAG_NONE;
 notmuch_bool_t batch = FALSE;
+notmuch_bool_t remove_all = FALSE;
 FILE *input = stdin;
 char *input_file_name = NULL;
 int opt_index;
@@ -201,6 +205,7 @@ notmuch_tag_command (notmuch_config_t *config, int argc, 
char *argv[])
 notmuch_opt_desc_t options[] = {
{ NOTMUCH_OPT_BOOLEAN, batch, batch, 0, 0 },
{ NOTMUCH_OPT_STRING, input_file_name, input, 'i', 0 },
+   { NOTMUCH_OPT_BOOLEAN, remove_all, remove-all, 0, 0 },
{ 0, 0, 0, 0, 0 }
 };
 
@@ -223,6 +228,10 @@ notmuch_tag_command (notmuch_config_t *config, int argc, 
char *argv[])
fprintf (stderr, Can't specify both cmdline and stdin!\n);
return 1;
}
+   if (remove_all) {
+   fprintf (stderr, Can't specify both --remove-all and --batch\n);
+   return 1;
+   }
 } else {
tag_ops = tag_op_list_create (config);
if (tag_ops == NULL) {
@@ -234,7 +243,7 @@ notmuch_tag_command (notmuch_config_t *config, int argc, 
char *argv[])
query_string, tag_ops))
return 1;
 
-   if (tag_op_list_size (tag_ops) == 0) {
+   if (tag_op_list_size (tag_ops) == 0  ! remove_all) {
fprintf (stderr, Error: 'notmuch tag' requires at least one tag to 
add or remove.\n);
return 1;
}
@@ -247,6 +256,9 @@ notmuch_tag_command (notmuch_config_t *config, int argc, 
char *argv[])
 if (notmuch_config_get_maildir_synchronize_flags (config))
tag_flags |= TAG_FLAG_MAILDIR_SYNC;
 
+if (remove_all)
+   tag_flags |= TAG_FLAG_REMOVE_ALL;
+
 if (batch)
ret = tag_file (config, notmuch, tag_flags, input);
 else
-- 
1.7.10.4

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


[PATCH v2 3/4] man: document notmuch tag --remove-all

2013-03-09 Thread Jani Nikula
---
 man/man1/notmuch-tag.1 |   12 +++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/man/man1/notmuch-tag.1 b/man/man1/notmuch-tag.1
index 0052ca2..c7d7a4d 100644
--- a/man/man1/notmuch-tag.1
+++ b/man/man1/notmuch-tag.1
@@ -4,7 +4,7 @@ notmuch-tag \- add/remove tags for all messages matching the 
search terms
 
 .SH SYNOPSIS
 .B notmuch tag
-.RI + tag |\- tag  [...] [\-\-]  search-term  [...]
+.RI [ options ...] + tag |\- tag  [...] [\-\-]  search-term  
[...]
 
 .B notmuch tag
 .RI --batch
@@ -40,6 +40,16 @@ Supported options for
 include
 .RS 4
 .TP 4
+.BR \-\-remove\-all
+
+Remove all tags from each message matching the search terms before
+applying the tag changes appearing on the command line. This means
+setting the tags of each message to the tags to be added. If there are
+no tags to be added, the messages will have no tags.
+.RE
+
+.RS 4
+.TP 4
 .BR \-\-batch
 
 Read batch tagging operations from a file (stdin by default). This is more
-- 
1.7.10.4

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


[PATCH v2 4/4] test: notmuch tag --remove-all

2013-03-09 Thread Jani Nikula
---
 test/tagging |   16 
 1 file changed, 16 insertions(+)

diff --git a/test/tagging b/test/tagging
index 1f5632c..dc118f3 100755
--- a/test/tagging
+++ b/test/tagging
@@ -30,6 +30,22 @@ test_expect_equal $output \
 thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; One (inbox tag1 unread)
 thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; Two (inbox tag1 unread)
 
+test_begin_subtest Remove all
+notmuch tag --remove-all One
+notmuch tag --remove-all +tag5 +tag6 +unread Two
+output=$(notmuch search \* | notmuch_search_sanitize)
+test_expect_equal $output \
+thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; One ()
+thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; Two (tag5 tag6 unread)
+
+test_begin_subtest Remove all with a no-op
+notmuch tag +inbox +tag1 +unread One
+notmuch tag --remove-all +foo +inbox +tag1 -foo +unread Two
+output=$(notmuch search \* | notmuch_search_sanitize)
+test_expect_equal $output \
+thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; One (inbox tag1 unread)
+thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; Two (inbox tag1 unread)
+
 test_begin_subtest Special characters in tags
 notmuch tag +': ' \*
 notmuch tag -': ' Two
-- 
1.7.10.4

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


[PATCH v2 0/6] batch count for notmuch-hello speedup

2013-03-09 Thread Jani Nikula
Rebased v2 of id:cover.1358273133.git.j...@nikula.org

Jani Nikula (5):
  cli: remove useless strdup
  cli: extract count printing to a separate function in notmuch count
  cli: add --batch option to notmuch count
  man: document notmuch count --batch and --input options
  test: notmuch count --batch and --input options

Mark Walters (1):
  emacs: hello: use batch count

 emacs/notmuch-hello.el   |   52 +-
 man/man1/notmuch-count.1 |   20 +
 notmuch-count.c  |  111 +++---
 test/count   |   46 +++
 4 files changed, 182 insertions(+), 47 deletions(-)

-- 
1.7.10.4

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


[PATCH v2 1/6] cli: remove useless strdup

2013-03-09 Thread Jani Nikula
---
 notmuch-count.c |4 
 1 file changed, 4 deletions(-)

diff --git a/notmuch-count.c b/notmuch-count.c
index 390794f..c2f1b7d 100644
--- a/notmuch-count.c
+++ b/notmuch-count.c
@@ -71,10 +71,6 @@ notmuch_count_command (notmuch_config_t *config, int argc, 
char *argv[])
return 1;
 }
 
-if (*query_str == '\0') {
-   query_str = talloc_strdup (config, );
-}
-
 query = notmuch_query_create (notmuch, query_str);
 if (query == NULL) {
fprintf (stderr, Out of memory\n);
-- 
1.7.10.4

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


[PATCH v2 2/6] cli: extract count printing to a separate function in notmuch count

2013-03-09 Thread Jani Nikula
Make count printing on a query string reusable. No functional changes.
---
 notmuch-count.c |   59 +--
 1 file changed, 36 insertions(+), 23 deletions(-)

diff --git a/notmuch-count.c b/notmuch-count.c
index c2f1b7d..630f036 100644
--- a/notmuch-count.c
+++ b/notmuch-count.c
@@ -32,16 +32,47 @@ enum {
 EXCLUDE_FALSE,
 };
 
+static int
+print_count (notmuch_database_t *notmuch, const char *query_str,
+const char **exclude_tags, size_t exclude_tags_length, int output)
+{
+notmuch_query_t *query;
+size_t i;
+
+query = notmuch_query_create (notmuch, query_str);
+if (query == NULL) {
+   fprintf (stderr, Out of memory\n);
+   return 1;
+}
+
+for (i = 0; i  exclude_tags_length; i++)
+   notmuch_query_add_tag_exclude (query, exclude_tags[i]);
+
+switch (output) {
+case OUTPUT_MESSAGES:
+   printf (%u\n, notmuch_query_count_messages (query));
+   break;
+case OUTPUT_THREADS:
+   printf (%u\n, notmuch_query_count_threads (query));
+   break;
+}
+
+notmuch_query_destroy (query);
+
+return 0;
+}
+
 int
 notmuch_count_command (notmuch_config_t *config, int argc, char *argv[])
 {
 notmuch_database_t *notmuch;
-notmuch_query_t *query;
 char *query_str;
 int opt_index;
 int output = OUTPUT_MESSAGES;
 int exclude = EXCLUDE_TRUE;
-unsigned int i;
+const char **search_exclude_tags = NULL;
+size_t search_exclude_tags_length = 0;
+int ret;
 
 notmuch_opt_desc_t options[] = {
{ NOTMUCH_OPT_KEYWORD, output, output, 'o',
@@ -71,33 +102,15 @@ notmuch_count_command (notmuch_config_t *config, int argc, 
char *argv[])
return 1;
 }
 
-query = notmuch_query_create (notmuch, query_str);
-if (query == NULL) {
-   fprintf (stderr, Out of memory\n);
-   return 1;
-}
-
 if (exclude == EXCLUDE_TRUE) {
-   const char **search_exclude_tags;
-   size_t search_exclude_tags_length;
-
search_exclude_tags = notmuch_config_get_search_exclude_tags
(config, search_exclude_tags_length);
-   for (i = 0; i  search_exclude_tags_length; i++)
-   notmuch_query_add_tag_exclude (query, search_exclude_tags[i]);
 }
 
-switch (output) {
-case OUTPUT_MESSAGES:
-   printf (%u\n, notmuch_query_count_messages (query));
-   break;
-case OUTPUT_THREADS:
-   printf (%u\n, notmuch_query_count_threads (query));
-   break;
-}
+ret = print_count (notmuch, query_str, search_exclude_tags,
+  search_exclude_tags_length, output);
 
-notmuch_query_destroy (query);
 notmuch_database_destroy (notmuch);
 
-return 0;
+return ret;
 }
-- 
1.7.10.4

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


[PATCH v2 3/6] cli: add --batch option to notmuch count

2013-03-09 Thread Jani Nikula
Add support for reading queries from stdin, one per line, and writing
results to stdin, one per line.

This will bring considerable performance improvements when utilized in
Emacs notmuch-hello, especially so when running remote notmuch.
---
 notmuch-count.c |   52 ++--
 1 file changed, 50 insertions(+), 2 deletions(-)

diff --git a/notmuch-count.c b/notmuch-count.c
index 630f036..8772cff 100644
--- a/notmuch-count.c
+++ b/notmuch-count.c
@@ -62,6 +62,27 @@ print_count (notmuch_database_t *notmuch, const char 
*query_str,
 return 0;
 }
 
+static int
+count_file (notmuch_database_t *notmuch, FILE *input, const char 
**exclude_tags,
+   size_t exclude_tags_length, int output)
+{
+char *line = NULL;
+ssize_t line_len;
+size_t line_size;
+int ret = 0;
+
+while (!ret  (line_len = getline (line, line_size, input)) != -1) {
+   chomp_newline (line);
+   ret = print_count (notmuch, line, exclude_tags, exclude_tags_length,
+  output);
+}
+
+if (line)
+   free (line);
+
+return ret;
+}
+
 int
 notmuch_count_command (notmuch_config_t *config, int argc, char *argv[])
 {
@@ -72,6 +93,9 @@ notmuch_count_command (notmuch_config_t *config, int argc, 
char *argv[])
 int exclude = EXCLUDE_TRUE;
 const char **search_exclude_tags = NULL;
 size_t search_exclude_tags_length = 0;
+notmuch_bool_t batch = FALSE;
+FILE *input = stdin;
+char *input_file_name = NULL;
 int ret;
 
 notmuch_opt_desc_t options[] = {
@@ -83,6 +107,8 @@ notmuch_count_command (notmuch_config_t *config, int argc, 
char *argv[])
  (notmuch_keyword_t []){ { true, EXCLUDE_TRUE },
  { false, EXCLUDE_FALSE },
  { 0, 0 } } },
+   { NOTMUCH_OPT_BOOLEAN, batch, batch, 0, 0 },
+   { NOTMUCH_OPT_STRING, input_file_name, input, 'i', 0 },
{ 0, 0, 0, 0, 0 }
 };
 
@@ -92,6 +118,21 @@ notmuch_count_command (notmuch_config_t *config, int argc, 
char *argv[])
return 1;
 }
 
+if (input_file_name) {
+   batch = TRUE;
+   input = fopen (input_file_name, r);
+   if (input == NULL) {
+   fprintf (stderr, Error opening %s for reading: %s\n,
+input_file_name, strerror (errno));
+   return 1;
+   }
+}
+
+if (batch  opt_index != argc) {
+   fprintf (stderr, --batch and query string are not compatible\n);
+   return 1;
+}
+
 if (notmuch_database_open (notmuch_config_get_database_path (config),
   NOTMUCH_DATABASE_MODE_READ_ONLY, notmuch))
return 1;
@@ -107,10 +148,17 @@ notmuch_count_command (notmuch_config_t *config, int 
argc, char *argv[])
(config, search_exclude_tags_length);
 }
 
-ret = print_count (notmuch, query_str, search_exclude_tags,
-  search_exclude_tags_length, output);
+if (batch)
+   ret = count_file (notmuch, input, search_exclude_tags,
+ search_exclude_tags_length, output);
+else
+   ret = print_count (notmuch, query_str, search_exclude_tags,
+  search_exclude_tags_length, output);
 
 notmuch_database_destroy (notmuch);
 
+if (input != stdin)
+   fclose (input);
+
 return ret;
 }
-- 
1.7.10.4

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


[PATCH v2 4/6] man: document notmuch count --batch and --input options

2013-03-09 Thread Jani Nikula
---
 man/man1/notmuch-count.1 |   20 
 1 file changed, 20 insertions(+)

diff --git a/man/man1/notmuch-count.1 b/man/man1/notmuch-count.1
index 86a67fe..7fc4378 100644
--- a/man/man1/notmuch-count.1
+++ b/man/man1/notmuch-count.1
@@ -46,6 +46,26 @@ Output the number of matching threads.
 Specify whether to omit messages matching search.tag_exclude from the
 count (the default) or not.
 .RE
+
+.RS 4
+.TP 4
+.BR \-\-batch
+
+Read queries from a file (stdin by default), one per line, and output
+the number of matching messages (or threads) to stdout, one per
+line. On an empty input line the count of all messages (or threads) in
+the database will be output. This option is not compatible with
+specifying search terms on the command line.
+.RE
+
+.RS 4
+.TP 4
+.BR \-\-input= filename
+
+Read input from given file, instead of from stdin. Implies
+.BR --batch .
+.RE
+
 .RE
 .RE
 
-- 
1.7.10.4

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


[PATCH v2 5/6] test: notmuch count --batch and --input options

2013-03-09 Thread Jani Nikula
---
 test/count |   46 ++
 1 file changed, 46 insertions(+)

diff --git a/test/count b/test/count
index 879b114..05713fd 100755
--- a/test/count
+++ b/test/count
@@ -38,4 +38,50 @@ test_expect_equal \
 0 \
 `notmuch count --output=threads from:cworth and not from:cworth`
 
+test_begin_subtest message count is the default for batch count
+notmuch count --batch OUTPUT EOF
+
+from:cworth
+EOF
+notmuch count --output=messages EXPECTED
+notmuch count --output=messages from:cworth EXPECTED
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest batch message count
+notmuch count --batch --output=messages OUTPUT EOF
+from:cworth
+
+tag:inbox
+EOF
+notmuch count --output=messages from:cworth EXPECTED
+notmuch count --output=messages EXPECTED
+notmuch count --output=messages tag:inbox EXPECTED
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest batch thread count
+notmuch count --batch --output=threads OUTPUT EOF
+
+from:cworth
+from:cworth and not from:cworth
+foo
+EOF
+notmuch count --output=threads EXPECTED
+notmuch count --output=threads from:cworth EXPECTED
+notmuch count --output=threads from:cworth and not from:cworth EXPECTED
+notmuch count --output=threads foo EXPECTED
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest batch message count with input file
+cat INPUT EOF
+from:cworth
+
+tag:inbox
+EOF
+notmuch count --input=INPUT --output=messages OUTPUT
+notmuch count --output=messages from:cworth EXPECTED
+notmuch count --output=messages EXPECTED
+notmuch count --output=messages tag:inbox EXPECTED
+test_expect_equal_file EXPECTED OUTPUT
+
+
 test_done
-- 
1.7.10.4

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


[PATCH v2 6/6] emacs: hello: use batch count

2013-03-09 Thread Jani Nikula
From: Mark Walters markwalters1...@gmail.com

This modifies notmuch hello to use the new count --batch
functionality. It should give exactly the same results as before but
under many conditions it should be much faster. In particular it is
much faster for remote use.

The code is a little ugly as it has to do some working out of the
query when asking the query and some when dealing with the result.
However, the code path is exactly the same in both local and remote
use.
---
 emacs/notmuch-hello.el |   52 +---
 1 file changed, 32 insertions(+), 20 deletions(-)

diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
index 00b78e1..cda79f1 100644
--- a/emacs/notmuch-hello.el
+++ b/emacs/notmuch-hello.el
@@ -381,26 +381,38 @@ The result is the list of elements of the form (NAME 
QUERY COUNT).
 The values :show-empty-searches, :filter and :filter-count from
 options will be handled as specified for
 `notmuch-hello-insert-searches'.
-  (notmuch-remove-if-not
-   #'identity
-   (mapcar
-(lambda (elem)
-  (let* ((name (car elem))
-(query-and-count (if (consp (cdr elem))
- ;; do we have a different query for the 
message count?
- (cons (second elem) (third elem))
-   (cons (cdr elem) (cdr elem
-(message-count
- (string-to-number
-  (notmuch-saved-search-count
-   (notmuch-hello-filtered-query (cdr query-and-count)
- (or (plist-get options 
:filter-count)
-(plist-get options 
:filter)))
-   (and (or (plist-get options :show-empty-searches) ( message-count 0))
-(list name (notmuch-hello-filtered-query
-(car query-and-count) (plist-get options :filter))
-  message-count
-query-alist)))
+  (with-temp-buffer
+(dolist (elem query-alist nil)
+  (let ((count-query (if (consp (cdr elem))
+;; do we have a different query for the message 
count?
+(third elem)
+  (cdr elem
+   (insert
+(notmuch-hello-filtered-query count-query
+  (or (plist-get options :filter-count)
+  (plist-get options :filter)))
+\n)))
+
+(call-process-region (point-min) (point-max) notmuch-command
+t t nil count --batch)
+(goto-char (point-min))
+
+(notmuch-remove-if-not
+ #'identity
+ (mapcar
+  (lambda (elem)
+   (let ((name (car elem))
+ (search-query (if (consp (cdr elem))
+;; do we have a different query for the 
message count?
+(second elem)
+ (cdr elem)))
+ (message-count (prog1 (read (current-buffer))
+   (forward-line 1
+ (and (or (plist-get options :show-empty-searches) ( message-count 0))
+  (list name (notmuch-hello-filtered-query
+  search-query (plist-get options :filter))
+message-count
+  query-alist
 
 (defun notmuch-hello-insert-buttons (searches)
   Insert buttons for SEARCHES.
-- 
1.7.10.4

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


[RFC patch] emacs: skeleton of texinfo manual for emacs interface.

2013-03-09 Thread david
From: David Bremner brem...@debian.org

Currently this only attempts to document the notmuch-hello interface.
---

I have thought for a long time that we should have some unified
documentation for the emacs interface. This is some sketch of a
beginning.  Building such a document turns out to be a fair amount of
work, but I guess it should be possible to have something better than
what we have now (i.e. nothing). I did try to avoid duplication with
both the docstrings and the man pages. Eventually perhaps we should
have some common format to generate the man pages and info pages from,
but I didn't want to hold up the whole effort waiting for that.

One thing that would make this effort more bearable is being able to
re-use material from the wiki. Currently there is no license
information at all on that material; I'm not sure exactly how to
proceed.

To build this, use makeinfo notmuch.texi
You can then (perversely) view it without emacs with info -f notmuch.info
or in emacs with C-u C-h i notmuch.info.


 emacs/notmuch.texi | 274 +
 emacs/version.texi |   2 +
 2 files changed, 276 insertions(+)
 create mode 100644 emacs/notmuch.texi
 create mode 100644 emacs/version.texi

diff --git a/emacs/notmuch.texi b/emacs/notmuch.texi
new file mode 100644
index 000..d4f7296
--- /dev/null
+++ b/emacs/notmuch.texi
@@ -0,0 +1,274 @@
+\input texinfo   @c -*-texinfo-*-
+@comment $Id@w{$}
+@comment %**start of header
+@setfilename notmuch.info
+@include version.texi
+@settitle Notmuch @value{VERSION}
+@comment %**end of header
+
+@macro keyindex {NAME}
+@kindex \NAME\
+@cindex \NAME\
+@end macro
+
+@macro funindex {NAME}
+@findex \NAME\
+@cindex \NAME\
+@end macro
+
+@macro varindex {NAME}
+@vindex \NAME\
+@cindex \NAME\
+@end macro
+
+
+@copying
+This manual is for Notmuch (version @value{VERSION}, @value{UPDATED})
+
+Copyright @copyright{} 2013 David Bremner
+
+This manual is distributed under the same terms as notmuch, which are as 
follows.
+@quotation
+ 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/ .
+
+@end quotation
+@end copying
+
+@dircategory Texinfo documentation system
+@direntry
+* notmuch: (notmuch)Emacs interface to notmuch
+@end direntry
+
+@titlepage
+@title Notmuch
+@subtitle for version @value{VERSION}, @value{UPDATED}
+@author David Bremner (@email{david@@tethera.net})
+@page
+@vskip 0pt plus 1filll
+@insertcopying
+@end titlepage
+
+@contents
+
+@ifnottex
+@node Top
+@top Notmuch
+
+This manual is for Notmuch (version @value{VERSION}, @value{UPDATED}).
+@end ifnottex
+
+@menu
+* About this Manual::
+* notmuch-hello::
+* notmuch-search::
+* Search Syntax::
+* Configuration::
+* Function Index::
+* Variable Index::
+* Index::
+@end menu
+
+
+@node About this Manual
+@unnumbered About this Manual
+
+This manual covers only the emacs interface to notmuch. For
+information on the command line interface, see
+@url{http://notmuchmail.org/manpages/notmuch-1,the notmuch man page}.
+To save
+typing, we will sometimes use @emph{notmuch} in this manual to refer
+to the Emacs interface to notmuch. If the distinction should every be
+important, we'll refer to the Emacs inteface as @emph{notmuch-emacs}.
+
+Notmuch-emacs is highly customizable via the the Emacs customization
+framework (or just by setting the appropriate variables).  We try to
+point out relevant variables in this manual, but in order to avoid
+duplication of information, but you can usually find the most detailed
+description in the varables docstring.
+
+@node notmuch-hello
+@chapter notmuch-hello
+
+@funindex notmuch-hello
+@funindex notmuch
+
+@command{notmuch-hello} is the main entry point for notmuch. You can
+start it with @kbd{M-x notmuch} or @kbd{M-x notmuch-hello}. The
+startup screen looks something like the following. There are some
+hints at the bottom of the screen.  There are three main parts to the
+notmuch-hello screen, discussed below. The @strong{bold} text
+indicates buttons you can click with a mouse or by positioning the
+cursor and pressing @kbd{return}
+
+@example
+@group
+
+
+   Welcome to @strong{notmuch}. You have 52 messages.
+
+Saved searches: @strong{[edit]}
+
+ 52 @strong{inbox}   52 @strong{unread}
+
+Search: .
+
+All tags: