[PATCH 2/3] perf-test: cache unpacked corpus

2012-12-04 Thread Austin Clements
On Mon, 03 Dec 2012, david at tethera.net wrote:
> From: David Bremner 
>
> Unpacking is not really the expensive step (compared to the initial
> notmuch new), but this is a pre-requisite to caching the database.
> ---
>  performance-test/.gitignore   |1 +
>  performance-test/Makefile.local   |2 +-
>  performance-test/perf-test-lib.sh |   51 
> +
>  3 files changed, 31 insertions(+), 23 deletions(-)
>
> diff --git a/performance-test/.gitignore b/performance-test/.gitignore
> index 53f2697..7e20f7c 100644
> --- a/performance-test/.gitignore
> +++ b/performance-test/.gitignore
> @@ -1 +1,2 @@
>  tmp.*/
> +corpus.mail.*/
> diff --git a/performance-test/Makefile.local b/performance-test/Makefile.local
> index 5d2acbd..eb713d0 100644
> --- a/performance-test/Makefile.local
> +++ b/performance-test/Makefile.local
> @@ -29,4 +29,4 @@ $(TXZFILE):
>  download-corpus:
>   wget -O ${TXZFILE} ${DEFAULT_URL}
>  
> -CLEAN := $(CLEAN) $(dir)/tmp.*
> +CLEAN := $(CLEAN) $(dir)/tmp.* $(dir)/corpus.mail.*
> diff --git a/performance-test/perf-test-lib.sh 
> b/performance-test/perf-test-lib.sh
> index bba793d..9fbf874 100644
> --- a/performance-test/perf-test-lib.sh
> +++ b/performance-test/perf-test-lib.sh
> @@ -35,37 +35,44 @@ then
>   exit 1
>  fi
>  
> +CORPUS_DIR=${TEST_DIRECTORY}/corpus.mail.$corpus_size
>  add_email_corpus ()
>  {
>  rm -rf ${MAIL_DIR}
> +if [ ! -d $CORPUS_DIR ]; then
> + case "$corpus_size" in
> + small)
> + arg="mail/enron/bailey-s"
> + ;;
> + medium)
> + arg="mail/notmuch-archive"
> + ;;
> + *)
> + arg=mail
> + esac
>  
> -case "$1" in
> - --small)
> - arg="mail/enron/bailey-s"
> - ;;
> - --medium)
> - arg="mail/notmuch-archive"
> - ;;

The README still refers to these arguments, so it should be updated,
too.

> - *)
> - arg=mail
> -esac
> + if command -v pixz > /dev/null; then
> + XZ=pixz
> + else
> + XZ=xz
> + fi
>  
> -if command -v pixz > /dev/null; then
> - XZ=pixz
> -else
> - XZ=xz
> -fi
> + printf "Unpacking corpus\n"
> + mkdir $CORPUS_DIR
> +
> + tar --checkpoint=.5000 --extract --strip-components=2 \
> + --directory $CORPUS_DIR \
> + --use-compress-program ${XZ} \
> + --file ../download/notmuch-email-corpus-${PERFTEST_VERSION}.tar.xz \
> + notmuch-email-corpus/"$arg"
>  
> -printf "Unpacking corpus\n"
> -tar --checkpoint=.5000 --extract --strip-components=1 \
> - --directory ${TMP_DIRECTORY} \
> - --use-compress-program ${XZ} \
> - --file ../download/notmuch-email-corpus-${PERFTEST_VERSION}.tar.xz \
> - notmuch-email-corpus/"$arg"
> + printf "\n"
>  
> -printf "\n"
> +fi
> +cp -lr $CORPUS_DIR $MAIL_DIR
>  }
>  
> +
>  print_header () {
>  printf "[v%4s]   
> Wall(s)\tUsr(s)\tSys(s)\tRes(K)\tIn(512B)\tOut(512B)\n" \
>  ${PERFTEST_VERSION}
> -- 
> 1.7.10.4
>
> ___
> notmuch mailing list
> notmuch at notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 3/3] emacs: show: add invisibility button action

2012-12-04 Thread Mark Walters
This adds a button action to show hidden parts. In this version "t"
toggles the visibility of a part. In addition "RET" on a non-shown
part shows it.

The button is used to hide parts when appropriate (eg text/html in
multipart/alternative).
---
 emacs/notmuch-show.el |   36 +++-
 1 files changed, 35 insertions(+), 1 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 3215ebc..a4daff8 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -478,6 +478,7 @@ message at DEPTH in the current thread."
 (define-key map "v" 'notmuch-show-part-button-view)
 (define-key map "o" 'notmuch-show-part-button-interactively-view)
 (define-key map "|" 'notmuch-show-part-button-pipe)
+(define-key map "t" 'notmuch-show-toggle-invisible-part-action)
 map)
   "Submap for button commands")
 (fset 'notmuch-show-part-button-map notmuch-show-part-button-map)
@@ -555,6 +556,31 @@ message at DEPTH in the current thread."
 (let ((handle (mm-make-handle (current-buffer) (list content-type
   (mm-pipe-part handle

+;; This is taken from notmuch-wash: maybe it should be unified?
+(defun notmuch-show-toggle-invisible-part-action ( button 
no-redisplay)
+  (interactive)
+  (let* ((button (or button (button-at (point
+(overlay (button-get button 'overlay))
+(invis-spec (button-get button 'invisibility-spec))
+(show (invisible-p invis-spec)))
+(when overlay
+  (if show
+ (remove-from-invisibility-spec invis-spec)
+   (add-to-invisibility-spec invis-spec))
+  (let* ((new-start (button-start button))
+(button-label (button-get button :base-label))
+(old-point (point))
+(inhibit-read-only t))
+   (goto-char new-start)
+   (insert "[ " button-label (if show " ]" " (not shown) ]"))
+   (let ((old-end (button-end button)))
+ (move-overlay button new-start (point))
+ (delete-region (point) old-end))
+   (goto-char (min old-point (1- (button-end button)
+  (unless no-redisplay
+   (force-window-update)
+   (redisplay t)
+
 (defun notmuch-show-multipart/*-to-list (part)
   (mapcar (lambda (inner-part) (plist-get inner-part :content-type))
  (plist-get part :content)))
@@ -867,6 +893,11 @@ message at DEPTH in the current thread."

(button-put button 'invisibility-spec invis-spec)
(button-put button 'overlay overlay))
+
+  ;; We toggle the button for hidden parts as that gets the
+  ;; button label right.
+  (when not-shown
+   (notmuch-show-toggle-invisible-part-action button t))
   (goto-char (point-max)

 (defun notmuch-show-insert-bodypart (msg part depth  not-shown)
@@ -1996,7 +2027,10 @@ the user (see 
`notmuch-show-stash-mlarchive-link-alist')."

 (defun notmuch-show-part-button-default ( button)
   (interactive)
-  (notmuch-show-part-button-internal button 
notmuch-show-part-button-default-action))
+  (let ((button (or button (button-at (point)
+(if (invisible-p (button-get button 'invisibility-spec))
+   (notmuch-show-toggle-invisible-part-action button)
+  (notmuch-show-part-button-internal button 
notmuch-show-part-button-default-action

 (defun notmuch-show-part-button-save ( button)
   (interactive)
-- 
1.7.9.1



[PATCH 2/3] emacs: show: add overlays for each part

2012-12-04 Thread Mark Walters
This make notmuch-show-insert-bodypart add an overlay for any
non-trivial part with a button header (currently the first text/plain
part does not have a button). At this point the overlay is available
to the button but there is no action using it yet.

In addition a not-shown variable which is used to request the part be
hidden by default down to the overlay but this is not acted on yet.
---
 emacs/notmuch-show.el |   62 +---
 1 files changed, 48 insertions(+), 14 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index f8ce037..3215ebc 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -569,10 +569,9 @@ message at DEPTH in the current thread."
 ;; should be chosen if there are more than one that match?
 (mapc (lambda (inner-part)
(let ((inner-type (plist-get inner-part :content-type)))
- (if (or notmuch-show-all-multipart/alternative-parts
- (string= chosen-type inner-type))
- (notmuch-show-insert-bodypart msg inner-part depth)
-   (notmuch-show-insert-part-header (plist-get inner-part :id) 
inner-type inner-type nil " (not shown)"
+ (notmuch-show-insert-bodypart msg inner-part depth
+   (not (or 
notmuch-show-all-multipart/alternative-parts
+(string= chosen-type 
inner-type))
  inner-parts)

 (when notmuch-show-indent-multipart
@@ -840,17 +839,52 @@ message at DEPTH in the current thread."
   (setq handlers (cdr handlers
   t)

-(defun notmuch-show-insert-bodypart (msg part depth)
-  "Insert the body part PART at depth DEPTH in the current thread."
+(defun notmuch-show-insert-part-overlays (msg beg end not-shown)
+  "Add an overlay to the part between BEG and END"
+  (let* ((button (button-at beg))
+(part-beg (and button (1+ (button-end button)
+
+;; If the part contains no text we do not make it toggleable.
+(unless (or (not button) (eq part-beg end))
+  (let ((base-label (button-get button :base-label))
+   (overlay (make-overlay part-beg end))
+   (message-invis-spec (plist-get msg :message-invis-spec))
+   (invis-spec (make-symbol "notmuch-part-region")))
+
+   (overlay-put overlay 'invisible (list invis-spec message-invis-spec))
+   (overlay-put overlay 'isearch-open-invisible 
#'notmuch-wash-region-isearch-show)
+   (overlay-put overlay 'priority 10)
+   (overlay-put overlay 'type "part")
+   ;; Now we have to add invis-spec to every overlay this
+   ;; overlay contains, otherwise these inner overlays will
+   ;; override this one.
+   (mapc (lambda (inner)
+   (when (and (>= (overlay-start inner) part-beg)
+  (<= (overlay-end inner) end))
+ (overlay-put inner 'invisible
+  (cons invis-spec (overlay-get inner 
'invisible)
+ (overlays-in part-beg end))
+
+   (button-put button 'invisibility-spec invis-spec)
+   (button-put button 'overlay overlay))
+  (goto-char (point-max)
+
+(defun notmuch-show-insert-bodypart (msg part depth  not-shown)
+  "Insert the body part PART at depth DEPTH in the current thread.
+
+If not-shown is TRUE then initially hide this part."
   (let ((content-type (downcase (plist-get part :content-type)))
-   (nth (plist-get part :id)))
-(notmuch-show-insert-bodypart-internal msg part content-type nth depth 
content-type))
-  ;; Some of the body part handlers leave point somewhere up in the
-  ;; part, so we make sure that we're down at the end.
-  (goto-char (point-max))
-  ;; Ensure that the part ends with a carriage return.
-  (unless (bolp)
-(insert "\n")))
+   (nth (plist-get part :id))
+   (beg (point)))
+
+(notmuch-show-insert-bodypart-internal msg part content-type nth depth 
content-type)
+;; Some of the body part handlers leave point somewhere up in the
+;; part, so we make sure that we're down at the end.
+(goto-char (point-max))
+;; Ensure that the part ends with a carriage return.
+(unless (bolp)
+  (insert "\n"))
+(notmuch-show-insert-part-overlays msg beg (point) not-shown)))

 (defun notmuch-show-insert-body (msg body depth)
   "Insert the body BODY at depth DEPTH in the current thread."
-- 
1.7.9.1



[PATCH 1/3] emacs: show: modify insert-part-header to save the button text

2012-12-04 Thread Mark Walters
This just make notmuch-show-insert-part-header save the basic button
text for parts as an attribute. This makes it simpler for the button
action (added in a later patch) to reword the label as appropriate (eg
append "(not shown)" or not as appropriate).
---
 emacs/notmuch-show.el |   19 ++-
 1 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index d7fa10e..f8ce037 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -483,17 +483,18 @@ message at DEPTH in the current thread."
 (fset 'notmuch-show-part-button-map notmuch-show-part-button-map)

 (defun notmuch-show-insert-part-header (nth content-type declared-type 
 name comment)
-  (let ((button))
+  (let ((button)
+   (base-label (concat (if name (concat name ": ") "")
+   declared-type
+   (if (not (string-equal declared-type content-type))
+   (concat " (as " content-type ")")
+ "")
+   (or comment ""
+
 (setq button
  (insert-button
-  (concat "[ "
-  (if name (concat name ": ") "")
-  declared-type
-  (if (not (string-equal declared-type content-type))
-  (concat " (as " content-type ")")
-"")
-  (or comment "")
-  " ]")
+  (concat "[ " base-label " ]")
+  :base-label base-label
   :type 'notmuch-show-part-button-type
   :notmuch-part nth
   :notmuch-filename name
-- 
1.7.9.1



[PATCH 0/3] Use invisibility to toggle display of all parts including multipart

2012-12-04 Thread Mark Walters
This patch aims to do the same as
id:1354496317-24564-1-git-send-email-markwalters1009 at gmail.com but
rather than reloading the buffer it uses invisibility. 

Most of the invisibility stuff was taken from notmuch-wash and adapted
to this situation.

The general interface is that any part can have its visibility
toggled: in this version by "t" on the part button. In addition "RET"
on the part button of any "not shown" part will show it.

Whilst a main driver was being able to view different parts of a
multipart/alternative message, this also allows the user to toggle
images or large inline text attachments (eg text/x-tex) for
example. Indeed, even multipart part buttons can be toggled which
remove the whole tree beneath: it is unclear whether this last is useful.

The invisibility approach has some advantages over the reloading
approach. It does not disrupt the rest of the buffer (eg
collapsed/expanded citations remain), it does not require an extra
call to the database with the possible addition of messages to the
buffer, and it fits more naturally with the other hidden/not-hidden
items.

Best wishes

Mark


Mark Walters (3):
  emacs: show: modify insert-part-header to save the button text
  emacs: show: add overlays for each part
  emacs: show: add invisibility button action

 emacs/notmuch-show.el |  117 +++--
 1 files changed, 93 insertions(+), 24 deletions(-)

-- 
1.7.9.1



[PATCH 3/3] test: use perl instead of sed -r for portability

2012-12-04 Thread Jani Nikula
Our OS X users report -r is not a supported option for sed. Use perl
instead.
---
 test/test-lib.sh |2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/test-lib.sh b/test/test-lib.sh
index f169785..31ed107 100644
--- a/test/test-lib.sh
+++ b/test/test-lib.sh
@@ -576,7 +576,7 @@ NOTMUCH_NEW ()

 notmuch_search_sanitize ()
 {
-sed -r -e 's/("?thread"?: ?)("?)("?)/\1\2XXX\3/'
+perl -pe 's/("?thread"?: ?)("?)("?)/\1\2XXX\3/'
 }

 NOTMUCH_SHOW_FILENAME_SQUELCH='s,filename:.*/mail,filename:/XXX/mail,'
-- 
1.7.10.4



[PATCH 2/3] test: wrap 'wc -l' results in arithmetic evaluation to strip whitespace

2012-12-04 Thread Jani Nikula
This is for portability, as 'wc -l' emits whitespace on some BSD
variants. Suggested by Tomi Ollila .

---

Updated version of id:1338361324-57289-8-git-send-email-pioto at pioto.org
---
 test/count |   12 
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/test/count b/test/count
index 8e587ff..879b114 100755
--- a/test/count
+++ b/test/count
@@ -4,24 +4,28 @@ test_description='"notmuch count" for messages and threads'

 add_email_corpus

+# Note: The 'wc -l' results below are wrapped in arithmetic evaluation
+# $((...)) to strip whitespace. This is for portability, as 'wc -l'
+# emits whitespace on some BSD variants.
+
 test_begin_subtest "message count is the default for notmuch count"
 test_expect_equal \
-"`notmuch search --output=messages '*' | wc -l`" \
+"$((`notmuch search --output=messages '*' | wc -l`))" \
 "`notmuch count '*'`"

 test_begin_subtest "message count with --output=messages"
 test_expect_equal \
-"`notmuch search --output=messages '*' | wc -l`" \
+"$((`notmuch search --output=messages '*' | wc -l`))" \
 "`notmuch count --output=messages '*'`"

 test_begin_subtest "thread count with --output=threads"
 test_expect_equal \
-"`notmuch search --output=threads '*' | wc -l`" \
+"$((`notmuch search --output=threads '*' | wc -l`))" \
 "`notmuch count --output=threads '*'`"

 test_begin_subtest "thread count is the default for notmuch search"
 test_expect_equal \
-"`notmuch search '*' | wc -l`" \
+"$((`notmuch search '*' | wc -l`))" \
 "`notmuch count --output=threads '*'`"

 test_begin_subtest "count with no matching messages"
-- 
1.7.10.4



[PATCH 1/3] test: fix count test

2012-12-04 Thread Jani Nikula
The quoting for ${SEARCH} is broken when it's supposed to be '*', and
it seems tricky to get it right. Just drop the variable and use '*'
directly. Before this, none of the messages ever matched, and the test
was comparing zeros.
---
 test/count |   23 ++-
 1 file changed, 10 insertions(+), 13 deletions(-)

diff --git a/test/count b/test/count
index 300b171..8e587ff 100755
--- a/test/count
+++ b/test/count
@@ -4,37 +4,34 @@ test_description='"notmuch count" for messages and threads'

 add_email_corpus

-SEARCH="\"*\""
-
 test_begin_subtest "message count is the default for notmuch count"
 test_expect_equal \
-"`notmuch search --output=messages ${SEARCH} | wc -l`" \
-"`notmuch count ${SEARCH}`"
+"`notmuch search --output=messages '*' | wc -l`" \
+"`notmuch count '*'`"

 test_begin_subtest "message count with --output=messages"
 test_expect_equal \
-"`notmuch search --output=messages ${SEARCH} | wc -l`" \
-"`notmuch count --output=messages ${SEARCH}`"
+"`notmuch search --output=messages '*' | wc -l`" \
+"`notmuch count --output=messages '*'`"

 test_begin_subtest "thread count with --output=threads"
 test_expect_equal \
-"`notmuch search --output=threads ${SEARCH} | wc -l`" \
-"`notmuch count --output=threads ${SEARCH}`"
+"`notmuch search --output=threads '*' | wc -l`" \
+"`notmuch count --output=threads '*'`"

 test_begin_subtest "thread count is the default for notmuch search"
 test_expect_equal \
-"`notmuch search ${SEARCH} | wc -l`" \
-"`notmuch count --output=threads ${SEARCH}`"
+"`notmuch search '*' | wc -l`" \
+"`notmuch count --output=threads '*'`"

-SEARCH="from:cworth and not from:cworth"
 test_begin_subtest "count with no matching messages"
 test_expect_equal \
 "0" \
-"`notmuch count --output=messages ${SEARCH}`"
+"`notmuch count --output=messages from:cworth and not from:cworth`"

 test_begin_subtest "count with no matching threads"
 test_expect_equal \
 "0" \
-"`notmuch count --output=threads ${SEARCH}`"
+"`notmuch count --output=threads from:cworth and not from:cworth`"

 test_done
-- 
1.7.10.4



[PATCH 0/3] test fixes, portability

2012-12-04 Thread Jani Nikula
I had a glance at a 'make test' report on OS X [1], and tried to fix a
few things from there. While at it, noticed that count test is horribly
broken.

BR,
Jani.

[1] https://spod.gy/p/u9j3zxg96vu6k3wy

Jani Nikula (3):
  test: fix count test
  test: wrap 'wc -l' results in arithmetic evaluation to strip
whitespace
  test: use perl instead of sed -r for portability

 test/count   |   25 +
 test/test-lib.sh |2 +-
 2 files changed, 14 insertions(+), 13 deletions(-)

-- 
1.7.10.4



[PATCH v2 0/5] New output format sexp (Lisp S-Expressions)

2012-12-04 Thread Jani Nikula

Hi Peter -

On Tue, 04 Dec 2012, Peter Feigl  wrote:
> This patch series adds a new output format "sexp" to notmuch-reply,
> notmuch-show and notmuch-search. These are useful for the Android mobile
> client and perhaps other Lisp programs as well.
> After the switch to a generic structured output printer, which was
> committed some months ago, these patches just add another one (like the
> json structured output printer).
> Basic tests and updates to the man pages are also included.
>
>
> Peter Feigl (5):
>   Adding an S-expression structured output printer.
>   Rename the -json printer functions in notmuch-reply and
> notmuch-show to generic -sprinter functions.
>   Use the S-Expression structured printer in notmuch-show,
> notmuch-reply and notmuch-search.

Patches 1-3 look good.

>   Adding tests for --format=sexp.

Did not review.

>   Updating man pages for new S-Expression output format.

Did not review, but noticed it adds lines with trailing whitespace.


BR,
Jani.


>
>  Makefile.local|   1 +
>  man/man1/notmuch-reply.1  |  14 ++-
>  man/man1/notmuch-search.1 |  15 +--
>  man/man1/notmuch-show.1   |  36 +--
>  notmuch-client.h  |   8 +-
>  notmuch-reply.c   |  43 
>  notmuch-search.c  |   6 +-
>  notmuch-show.c|  48 +
>  sprinter-sexp.c   | 250 
> ++
>  sprinter.h|   4 +
>  test/notmuch-test |   1 +
>  test/sexp |  48 +
>  12 files changed, 414 insertions(+), 60 deletions(-)
>  create mode 100644 sprinter-sexp.c
>  create mode 100755 test/sexp
>
> -- 
> 1.8.0
>
> ___
> notmuch mailing list
> notmuch at notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH] NEWS: removal of notmuch-folders

2012-12-04 Thread Jani Nikula
---
 NEWS |   10 ++
 1 file changed, 10 insertions(+)

diff --git a/NEWS b/NEWS
index dadf92a..34e7a28 100644
--- a/NEWS
+++ b/NEWS
@@ -18,6 +18,16 @@ Bcc and Reply-To headers are now available in notmuch show 
json output
   For example notmuch Emacs client can now have these headers visible
   when the headers are added to the `notmuch-message-headers` variable.

+Emacs Interface
+---
+
+Removal of the deprecated `notmuch-folders` variable
+
+  `notmuch-folders` has been deprecated since the introduction of saved
+  searches and the notmuch hello view in notmuch 0.3. `notmuch-folders`
+  has now been removed. Any remaining users should migrate to
+  `notmuch-saved-searches`.
+
 Library changes
 ---

-- 
1.7.10.4



[PATCH v2 5/5] Updating man pages for new S-Expression output format.

2012-12-04 Thread Peter Feigl
Add sections about the new S-Expression output format (--format=sexp) to
the notmuch-search, notmuch-reply and notmuch-show man pages.
---
 man/man1/notmuch-reply.1  | 14 ++
 man/man1/notmuch-search.1 | 15 ---
 man/man1/notmuch-show.1   | 36 
 3 files changed, 46 insertions(+), 19 deletions(-)

diff --git a/man/man1/notmuch-reply.1 b/man/man1/notmuch-reply.1
index d264060..8ee1805 100644
--- a/man/man1/notmuch-reply.1
+++ b/man/man1/notmuch-reply.1
@@ -37,7 +37,7 @@ Supported options for
 include
 .RS
 .TP 4
-.BR \-\-format= ( default | json | headers\-only )
+.BR \-\-format= ( default | json | sexp | headers\-only )
 .RS
 .TP 4
 .BR default
@@ -48,6 +48,11 @@ Produces JSON output containing headers for a reply message 
and the
 contents of the original message. This output can be used by a client
 to create a reply message intelligently.
 .TP
+.BR sexp
+Produces S-Expression output containing headers for a reply message and 
+the contents of the original message. This output can be used by a client
+to create a reply message intelligently.
+.TP
 .BR headers\-only
 Only produces In\-Reply\-To, References, To, Cc, and Bcc headers.
 .RE
@@ -74,8 +79,8 @@ user's addresses.

 Decrypt any MIME encrypted parts found in the selected content
 (ie. "multipart/encrypted" parts). Status of the decryption will be
-reported (currently only supported with --format=json) and the
-multipart/encrypted part will be replaced by the decrypted
+reported (currently only supported with --format=json and --format=sexp)
+and the multipart/encrypted part will be replaced by the decrypted
 content.
 .RE

@@ -89,7 +94,8 @@ id:), but it can be useful to reply to several 
messages at
 once. For example, when a series of patches are sent in a single
 thread, replying to the entire thread allows for the reply to comment
 on issues found in multiple patches. The default format supports
-replying to multiple messages at once, but the JSON format does not.
+replying to multiple messages at once, but the JSON and S-Expression 
+format does not.
 .RE
 .RE

diff --git a/man/man1/notmuch-search.1 b/man/man1/notmuch-search.1
index 6ccd3b8..498232d 100644
--- a/man/man1/notmuch-search.1
+++ b/man/man1/notmuch-search.1
@@ -25,9 +25,9 @@ Supported options for
 include
 .RS 4
 .TP 4
-.BR \-\-format= ( json | text )
+.BR \-\-format= ( json | sexp | text )

-Presents the results in either JSON or plain-text (default).
+Presents the results in either JSON, S-Expressions or plain-text (default).
 .RE

 .RS 4
@@ -49,7 +49,7 @@ the authors of the thread and the subject.

 Output the thread IDs of all threads with any message matching the
 search terms, either one per line (\-\-format=text) or as a JSON array
-(\-\-format=json).
+(\-\-format=json) or an S-Expression list (\-\-format=sexp).
 .RE
 .RS 4
 .TP 4
@@ -57,22 +57,23 @@ search terms, either one per line (\-\-format=text) or as a 
JSON array

 Output the message IDs of all messages matching the search terms,
 either one per line (\-\-format=text) or as a JSON array
-(\-\-format=json).
+(\-\-format=json) or as an S-Expression list (\-\-format=sexp).
 .RE
 .RS 4
 .TP 4
 .B files

 Output the filenames of all messages matching the search terms, either
-one per line (\-\-format=text) or as a JSON array (\-\-format=json).
+one per line (\-\-format=text) or as a JSON array (\-\-format=json) or 
+as an S-Expression list (\-\-format=sexp).
 .RE
 .RS 4
 .TP 4
 .B tags

 Output all tags that appear on any message matching the search terms,
-either one per line (\-\-format=text) or as a JSON array
-(\-\-format=json).
+either one per line (\-\-format=text) or as a JSON array (\-\-format=json) 
+or as an S-Expression list (\-\-format=sexp).
 .RE
 .RE

diff --git a/man/man1/notmuch-show.1 b/man/man1/notmuch-show.1
index 4481f21..25b5bb8 100644
--- a/man/man1/notmuch-show.1
+++ b/man/man1/notmuch-show.1
@@ -31,12 +31,14 @@ If true,
 outputs all messages in the thread of any message matching the search
 terms; if false, it outputs only the matching messages. For
 .B --format=json
+and
+.B --format=sexp
 this defaults to true.  For other formats, this defaults to false.
 .RE

 .RS 4
 .TP 4
-.B \-\-format=(text|json|mbox|raw)
+.B \-\-format=(text|json|sexp|mbox|raw)

 .RS 4
 .TP 4
@@ -60,11 +62,29 @@ format is more robust than the text format for automated
 processing. The nested structure of multipart MIME messages is
 reflected in nested JSON output. By default JSON output includes all
 messages in a matching thread; that is, by default,
+
 .B \-\-format=json
 sets
 .B "\-\-entire\-thread"
 The caller can disable this behaviour by setting
 .B \-\-entire\-thread=false
+.RE
+.RS 4
+.TP 4
+.B sexp
+
+The output is formatted as an S-Expression (sexp). This
+format is more robust than the text format for automated
+processing. The nested structure of multipart MIME messages is
+reflected in nested S-Expression output. By default, 
+S-Expression output includes 

[PATCH v2 4/5] Adding tests for --format=sexp.

2012-12-04 Thread Peter Feigl
Add basic tests, the same as for json, for the S-Expression output
format.
---
 test/notmuch-test |  1 +
 test/sexp | 48 
 2 files changed, 49 insertions(+)
 create mode 100755 test/sexp

diff --git a/test/notmuch-test b/test/notmuch-test
index a6ef34f..ca9c3dc 100755
--- a/test/notmuch-test
+++ b/test/notmuch-test
@@ -31,6 +31,7 @@ TESTS="
   excludes
   tagging
   json
+  sexp
   text
   multipart
   thread-naming
diff --git a/test/sexp b/test/sexp
new file mode 100755
index 000..fdc9de6
--- /dev/null
+++ b/test/sexp
@@ -0,0 +1,48 @@
+#!/usr/bin/env bash
+test_description="--format=sexp output"
+. ./test-lib.sh
+
+test_begin_subtest "Show message: sexp"
+add_message "[subject]=\"sexp-show-subject\"" "[date]=\"Sat, 01 Jan 2000 
12:00:00 -\"" "[bcc]=\"test_suite+bcc at notmuchmail.org\"" 
"[reply-to]=\"test_suite+replyto at notmuchmail.org\"" 
"[body]=\"sexp-show-message\""
+output=$(notmuch show --format=sexp "sexp-show-message")
+test_expect_equal "$output" "(id \"msg-001 at notmuch-test-suite\") (match 
t) (excluded nil) (filename 
\"/home/nex/notmuch-sexp/test/tmp.sexp/mail/msg-001\") (timestamp 946728000) 
(date_relative \"2000-01-01\") (tags (\"inbox\" \"unread\")) (headers ((Subject 
\"sexp-show-subject\") (From \"Notmuch Test Suite \") (To \"Notmuch Test Suite \") 
(Bcc \"test_suite+bcc at notmuchmail.org\") (Reply-To \"test_suite+replyto at 
notmuchmail.org\") (Date \"Sat, 01 Jan 2000 12:00:00 +\"))) (body (((id 1) 
(content-type \"text/plain\") (content \"sexp-show-message\n\") ("
+
+# This should be the same output as above.
+test_begin_subtest "Show message: sexp --body=true"
+output=$(notmuch show --format=sexp --body=true "sexp-show-message")
+test_expect_equal "$output" "(id \"msg-001 at notmuch-test-suite\") (match 
t) (excluded nil) (filename 
\"/home/nex/notmuch-sexp/test/tmp.sexp/mail/msg-001\") (timestamp 946728000) 
(date_relative \"2000-01-01\") (tags (\"inbox\" \"unread\")) (headers ((Subject 
\"sexp-show-subject\") (From \"Notmuch Test Suite \") (To \"Notmuch Test Suite \") 
(Bcc \"test_suite+bcc at notmuchmail.org\") (Reply-To \"test_suite+replyto at 
notmuchmail.org\") (Date \"Sat, 01 Jan 2000 12:00:00 +\"))) (body (((id 1) 
(content-type \"text/plain\") (content \"sexp-show-message\n\") ("
+
+test_begin_subtest "Show message: sexp --body=false"
+output=$(notmuch show --format=sexp --body=false "sexp-show-message")
+test_expect_equal "$output" "(id \"msg-001 at notmuch-test-suite\") (match 
t) (excluded nil) (filename 
\"/home/nex/notmuch-sexp/test/tmp.sexp/mail/msg-001\") (timestamp 946728000) 
(date_relative \"2000-01-01\") (tags (\"inbox\" \"unread\")) (headers ((Subject 
\"sexp-show-subject\") (From \"Notmuch Test Suite \") (To \"Notmuch Test Suite \") 
(Bcc \"test_suite+bcc at notmuchmail.org\") (Reply-To \"test_suite+replyto at 
notmuchmail.org\") (Date \"Sat, 01 Jan 2000 12:00:00 +\" ("
+
+test_begin_subtest "Search message: sexp"
+add_message "[subject]=\"sexp-search-subject\"" "[date]=\"Sat, 01 Jan 2000 
12:00:00 -\"" "[body]=\"sexp-search-message\""
+output=$(notmuch search --format=sexp "sexp-search-message" | 
notmuch_search_sanitize)
+test_expect_equal "$output" "(((thread \"0002\") (timestamp 
946728000) (date_relative \"2000-01-01\") (matched 1) (total 1) (authors 
\"Notmuch Test Suite\") (subject \"sexp-search-subject\") (tags (\"inbox\" 
\"unread\""
+
+test_begin_subtest "Show message: sexp, utf-8"
+add_message "[subject]=\"sexp-show-utf8-body-s?bj?ct\"" "[date]=\"Sat, 01 Jan 
2000 12:00:00 -\"" "[body]=\"js?n-show-m?ssage\""
+output=$(notmuch show --format=sexp "js?n-show-m?ssage")
+test_expect_equal "$output" "(id \"msg-003 at notmuch-test-suite\") (match 
t) (excluded nil) (filename 
\"/home/nex/notmuch-sexp/test/tmp.sexp/mail/msg-003\") (timestamp 946728000) 
(date_relative \"2000-01-01\") (tags (\"inbox\" \"unread\")) (headers ((Subject 
\"sexp-show-utf8-body-s?bj?ct\") (From \"Notmuch Test Suite \") (To \"Notmuch Test Suite \") 
(Date \"Sat, 01 Jan 2000 12:00:00 +\"))) (body (((id 1) (content-type 
\"text/plain\") (content \"js?n-show-m?ssage\n\") ("
+
+test_begin_subtest "Show message: sexp, inline attachment filename"
+subject='sexp-show-inline-attachment-filename'
+id="sexp-show-inline-attachment-filename at notmuchmail.org"
+emacs_deliver_message \
+"$subject" \
+'This is a test message with inline attachment with a filename' \
+"(mml-attach-file \"$TEST_DIRECTORY/README\" nil nil \"inline\")
+ (message-goto-eoh)
+ (insert \"Message-ID: <$id>\n\")"
+output=$(notmuch show --format=sexp "id:$id")
+filename=$(notmuch search --output=files "id:$id")
+test_expect_equal "$output" "(id \"sexp-show-inline-attachment-filename at 
notmuchmail.org\") (match t) (excluded nil) (filename \"$filename\") (timestamp 
946728000) (date_relative \"2000-01-01\") (tags (\"inbox\")) (headers ((Subject 

[PATCH v2 3/5] Use the S-Expression structured printer in notmuch-show, notmuch-reply and notmuch-search.

2012-12-04 Thread Peter Feigl
This patch uses the new S-Expression printer in the notmuch CLI (show,
search and reply). You can now use --format=sexp for any of them.
---
 notmuch-reply.c  |  5 +
 notmuch-search.c |  6 +-
 notmuch-show.c   | 18 ++
 3 files changed, 24 insertions(+), 5 deletions(-)

diff --git a/notmuch-reply.c b/notmuch-reply.c
index 53aefa7..69fd256 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -697,6 +697,7 @@ notmuch_reply_format_headers_only(void *ctx,
 enum {
 FORMAT_DEFAULT,
 FORMAT_JSON,
+FORMAT_SEXP,
 FORMAT_HEADERS_ONLY,
 };

@@ -724,6 +725,7 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
{ NOTMUCH_OPT_KEYWORD, , "format", 'f',
  (notmuch_keyword_t []){ { "default", FORMAT_DEFAULT },
  { "json", FORMAT_JSON },
+ { "sexp", FORMAT_SEXP },
  { "headers-only", FORMAT_HEADERS_ONLY },
  { 0, 0 } } },
{ NOTMUCH_OPT_KEYWORD, _all, "reply-to", 'r',
@@ -745,6 +747,9 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
 } else if (format == FORMAT_JSON) {
reply_format_func = notmuch_reply_format_sprinter;
sp = sprinter_json_create (ctx, stdout);
+} else if (format == FORMAT_SEXP) {
+   reply_format_func = notmuch_reply_format_sprinter;
+   sp = sprinter_sexp_create (ctx, stdout);
 } else {
reply_format_func = notmuch_reply_format_default;
 }
diff --git a/notmuch-search.c b/notmuch-search.c
index 830c4e4..6218622 100644
--- a/notmuch-search.c
+++ b/notmuch-search.c
@@ -305,7 +305,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
 int exclude = EXCLUDE_TRUE;
 unsigned int i;

-enum { NOTMUCH_FORMAT_JSON, NOTMUCH_FORMAT_TEXT }
+enum { NOTMUCH_FORMAT_JSON, NOTMUCH_FORMAT_TEXT, NOTMUCH_FORMAT_SEXP }
format_sel = NOTMUCH_FORMAT_TEXT;

 notmuch_opt_desc_t options[] = {
@@ -315,6 +315,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
  { 0, 0 } } },
{ NOTMUCH_OPT_KEYWORD, _sel, "format", 'f',
  (notmuch_keyword_t []){ { "json", NOTMUCH_FORMAT_JSON },
+ { "sexp", NOTMUCH_FORMAT_SEXP },
  { "text", NOTMUCH_FORMAT_TEXT },
  { 0, 0 } } },
{ NOTMUCH_OPT_KEYWORD, , "output", 'o',
@@ -347,6 +348,9 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
 case NOTMUCH_FORMAT_JSON:
format = sprinter_json_create (ctx, stdout);
break;
+case NOTMUCH_FORMAT_SEXP:
+   format = sprinter_sexp_create (ctx, stdout);
+   break;
 default:
/* this should never happen */
INTERNAL_ERROR("no output format selected");
diff --git a/notmuch-show.c b/notmuch-show.c
index 38c621f..d4860f1 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -40,6 +40,11 @@ static const notmuch_show_format_t format_json = {
 .part = format_part_sprinter_entry,
 };

+static const notmuch_show_format_t format_sexp = {
+.new_sprinter = sprinter_sexp_create,
+.part = format_part_sprinter_entry,
+};
+
 static notmuch_status_t
 format_part_mbox (const void *ctx, sprinter_t *sp, mime_node_t *node,
  int indent, const notmuch_show_params_t *params);
@@ -110,7 +115,7 @@ _get_one_line_summary (const void *ctx, notmuch_message_t 
*message)
 static void
 format_message_sprinter (sprinter_t *sp, notmuch_message_t *message)
 {
-/* Any changes to the JSON format should be reflected in the file
+/* Any changes to the JSON or S-Expression format should be reflected in 
the file
  * devel/schemata. */

 void *local = talloc_new (NULL);
@@ -1012,6 +1017,7 @@ do_show (void *ctx,
 enum {
 NOTMUCH_FORMAT_NOT_SPECIFIED,
 NOTMUCH_FORMAT_JSON,
+NOTMUCH_FORMAT_SEXP,
 NOTMUCH_FORMAT_TEXT,
 NOTMUCH_FORMAT_MBOX,
 NOTMUCH_FORMAT_RAW
@@ -1056,6 +1062,7 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
{ NOTMUCH_OPT_KEYWORD, _sel, "format", 'f',
  (notmuch_keyword_t []){ { "json", NOTMUCH_FORMAT_JSON },
  { "text", NOTMUCH_FORMAT_TEXT },
+ { "sexp", NOTMUCH_FORMAT_SEXP },
  { "mbox", NOTMUCH_FORMAT_MBOX },
  { "raw", NOTMUCH_FORMAT_RAW },
  { 0, 0 } } },
@@ -1100,6 +1107,9 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
 case NOTMUCH_FORMAT_TEXT:
format = _text;
break;
+case NOTMUCH_FORMAT_SEXP:
+   format = _sexp;
+   break;
 case NOTMUCH_FORMAT_MBOX:
if (params.part > 0) {
fprintf (stderr, "Error: specifying parts is incompatible with mbox 
output format.\n");
@@ -1120,7 +1130,7 @@ notmuch_show_command (void *ctx, unused (int 

[PATCH v2 2/5] Rename the -json printer functions in notmuch-reply and notmuch-show to generic -sprinter functions.

2012-12-04 Thread Peter Feigl
All the structured output functions in notmuch-reply and notmuch-show
are renamed to a generic name (as they do not contain any json-specific
code anyway). This patch is a preparation to actually using the new
S-Expression sprinter in notmuch-reply and notmuch-show.
---
 notmuch-client.h |  8 
 notmuch-reply.c  | 38 +-
 notmuch-show.c   | 30 +++---
 3 files changed, 40 insertions(+), 36 deletions(-)

diff --git a/notmuch-client.h b/notmuch-client.h
index ae9344b..1c336dc 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -175,12 +175,12 @@ notmuch_status_t
 show_one_part (const char *filename, int part);

 void
-format_part_json (const void *ctx, struct sprinter *sp, mime_node_t *node,
- notmuch_bool_t first, notmuch_bool_t output_body);
+format_part_sprinter (const void *ctx, struct sprinter *sp, mime_node_t *node,
+ notmuch_bool_t first, notmuch_bool_t output_body);

 void
-format_headers_json (struct sprinter *sp, GMimeMessage *message,
-notmuch_bool_t reply);
+format_headers_sprinter (struct sprinter *sp, GMimeMessage *message,
+notmuch_bool_t reply);

 typedef enum {
 NOTMUCH_SHOW_TEXT_PART_REPLY = 1 << 0,
diff --git a/notmuch-reply.c b/notmuch-reply.c
index e60a264..53aefa7 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -548,7 +548,8 @@ notmuch_reply_format_default(void *ctx,
 notmuch_config_t *config,
 notmuch_query_t *query,
 notmuch_show_params_t *params,
-notmuch_bool_t reply_all)
+notmuch_bool_t reply_all,
+unused (sprinter_t *sp))
 {
 GMimeMessage *reply;
 notmuch_messages_t *messages;
@@ -587,17 +588,17 @@ notmuch_reply_format_default(void *ctx,
 }

 static int
-notmuch_reply_format_json(void *ctx,
- notmuch_config_t *config,
- notmuch_query_t *query,
- notmuch_show_params_t *params,
- notmuch_bool_t reply_all)
+notmuch_reply_format_sprinter(void *ctx,
+ notmuch_config_t *config,
+ notmuch_query_t *query,
+ notmuch_show_params_t *params,
+ notmuch_bool_t reply_all,
+ sprinter_t *sp)
 {
 GMimeMessage *reply;
 notmuch_messages_t *messages;
 notmuch_message_t *message;
 mime_node_t *node;
-sprinter_t *sp;

 if (notmuch_query_count_messages (query) != 1) {
fprintf (stderr, "Error: search term did not match precisely one 
message.\n");
@@ -613,18 +614,17 @@ notmuch_reply_format_json(void *ctx,
 if (!reply)
return 1;

-sp = sprinter_json_create (ctx, stdout);
 sp->begin_map (sp);

 /* The headers of the reply message we've created */
 sp->map_key (sp, "reply-headers");
-format_headers_json (sp, reply, TRUE);
+format_headers_sprinter (sp, reply, TRUE);
 g_object_unref (G_OBJECT (reply));
 reply = NULL;

 /* Start the original */
 sp->map_key (sp, "original");
-format_part_json (ctx, sp, node, TRUE, TRUE);
+format_part_sprinter (ctx, sp, node, TRUE, TRUE);

 /* End */
 sp->end (sp);
@@ -639,7 +639,8 @@ notmuch_reply_format_headers_only(void *ctx,
  notmuch_config_t *config,
  notmuch_query_t *query,
  unused (notmuch_show_params_t *params),
- notmuch_bool_t reply_all)
+ notmuch_bool_t reply_all,
+ unused (sprinter_t *sp))
 {
 GMimeMessage *reply;
 notmuch_messages_t *messages;
@@ -707,7 +708,7 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
 notmuch_query_t *query;
 char *query_string;
 int opt_index, ret = 0;
-int (*reply_format_func)(void *ctx, notmuch_config_t *config, 
notmuch_query_t *query, notmuch_show_params_t *params, notmuch_bool_t 
reply_all);
+int (*reply_format_func)(void *ctx, notmuch_config_t *config, 
notmuch_query_t *query, notmuch_show_params_t *params, notmuch_bool_t 
reply_all, struct sprinter *sp);
 notmuch_show_params_t params = {
.part = -1,
.crypto = {
@@ -717,6 +718,7 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
 };
 int format = FORMAT_DEFAULT;
 int reply_all = TRUE;
+struct sprinter *sp = NULL;

 notmuch_opt_desc_t options[] = {
{ NOTMUCH_OPT_KEYWORD, , "format", 'f',
@@ -738,12 +740,14 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
return 1;
 }

-if (format == FORMAT_HEADERS_ONLY)
+if (format == FORMAT_HEADERS_ONLY) {
reply_format_func = notmuch_reply_format_headers_only;
-

[PATCH v2 1/5] Adding an S-expression structured output printer.

2012-12-04 Thread Peter Feigl
This commit adds a structured output printer for Lisp
S-Expressions. Later commits will use this printer in notmuch search,
show and reply.

The structure is the same as json, but:
- arrays are written as lists: ("foo" "bar" "baaz" 1 2 3)
- maps are written as a-lists: ((key "value") (other-key "other-value"))
- true is written as t
- false is written as nil
- null is written as nil
---
 Makefile.local  |   1 +
 sprinter-sexp.c | 250 
 sprinter.h  |   4 +
 3 files changed, 255 insertions(+)
 create mode 100644 sprinter-sexp.c

diff --git a/Makefile.local b/Makefile.local
index 2b91946..0db1713 100644
--- a/Makefile.local
+++ b/Makefile.local
@@ -270,6 +270,7 @@ notmuch_client_srcs =   \
notmuch-tag.c   \
notmuch-time.c  \
sprinter-json.c \
+   sprinter-sexp.c \
sprinter-text.c \
query-string.c  \
mime-node.c \
diff --git a/sprinter-sexp.c b/sprinter-sexp.c
new file mode 100644
index 000..6d6bbad
--- /dev/null
+++ b/sprinter-sexp.c
@@ -0,0 +1,250 @@
+/* notmuch - Not much of an email program, (just index and search)
+ *
+ * Copyright ? 2012 Carl Worth
+ *
+ * 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/ .
+ *
+ * Author: Carl Worth 
+ */
+
+#include 
+#include 
+#include 
+#include "sprinter.h"
+
+struct sprinter_sexp {
+struct sprinter vtable;
+FILE *stream;
+/* Top of the state stack, or NULL if the printer is not currently
+ * inside any aggregate types. */
+struct sexp_state *state;
+
+/* A flag to signify that a separator should be inserted in the
+ * output as soon as possible.
+ */
+notmuch_bool_t insert_separator;
+};
+
+struct sexp_state {
+struct sexp_state *parent;
+
+/* True if nothing has been printed in this aggregate yet.
+ * Suppresses the space before a value. */
+notmuch_bool_t first;
+
+/* True if the state is a map state.
+ * Used to add a space between key/value pairs. */
+notmuch_bool_t in_map;
+
+/* The character that closes the current aggregate. */
+char close;
+};
+
+/* Helper function to set up the stream to print a value.  If this
+ * value follows another value, prints a space. */
+static struct sprinter_sexp *
+sexp_begin_value (struct sprinter *sp)
+{
+struct sprinter_sexp *sps = (struct sprinter_sexp *) sp;
+
+if (sps->state) {
+   if (! sps->state->first) {
+   if (sps->insert_separator) {
+   fputc ('\n', sps->stream);
+   sps->insert_separator = FALSE;
+   } else {
+   if (! sps->state->in_map)
+   fputc (' ', sps->stream);
+   }
+   } else {
+   sps->state->first = FALSE;
+   }
+}
+return sps;
+}
+
+/* Helper function to begin an aggregate type.  Prints the open
+ * character and pushes a new state frame. */
+static void
+sexp_begin_aggregate (struct sprinter *sp, char open, char close)
+{
+struct sprinter_sexp *sps = sexp_begin_value (sp);
+struct sexp_state *state = talloc (sps, struct sexp_state);
+fputc (open, sps->stream);
+state->parent = sps->state;
+state->first = TRUE;
+state->in_map = FALSE;
+state->close = close;
+sps->state = state;
+}
+
+static void
+sexp_begin_map (struct sprinter *sp)
+{
+struct sprinter_sexp *sps = (struct sprinter_sexp *) sp;
+sexp_begin_aggregate (sp, '(', ')');
+sps->state->in_map = TRUE;
+}
+
+static void
+sexp_begin_list (struct sprinter *sp)
+{
+sexp_begin_aggregate (sp, '(', ')');
+}
+
+static void
+sexp_end (struct sprinter *sp)
+{
+struct sprinter_sexp *sps = (struct sprinter_sexp *) sp;
+struct sexp_state *state = sps->state;
+
+if (sps->state->in_map)
+   fputc (')', sps->stream);
+fputc (sps->state->close, sps->stream);
+sps->state = state->parent;
+talloc_free (state);
+if (sps->state == NULL)
+   fputc ('\n', sps->stream);
+}
+
+static void
+sexp_string_len_internal (struct sprinter *sp, const char *val, size_t len, 
notmuch_bool_t quote)
+{
+static const char *const escapes[] = {
+   ['\"'] = "\\\"", ['\\'] = "", ['\b'] = "\\b",
+   ['\f'] = "\\f",  ['\n'] = "\\n",  ['\t'] = "\\t"
+};
+struct sprinter_sexp *sps = sexp_begin_value (sp);
+
+if(quote)
+  

[PATCH v2 0/5] New output format sexp (Lisp S-Expressions)

2012-12-04 Thread Peter Feigl
This patch series adds a new output format "sexp" to notmuch-reply,
notmuch-show and notmuch-search. These are useful for the Android mobile
client and perhaps other Lisp programs as well.
After the switch to a generic structured output printer, which was
committed some months ago, these patches just add another one (like the
json structured output printer).
Basic tests and updates to the man pages are also included.


Peter Feigl (5):
  Adding an S-expression structured output printer.
  Rename the -json printer functions in notmuch-reply and
notmuch-show to generic -sprinter functions.
  Use the S-Expression structured printer in notmuch-show,
notmuch-reply and notmuch-search.
  Adding tests for --format=sexp.
  Updating man pages for new S-Expression output format.

 Makefile.local|   1 +
 man/man1/notmuch-reply.1  |  14 ++-
 man/man1/notmuch-search.1 |  15 +--
 man/man1/notmuch-show.1   |  36 +--
 notmuch-client.h  |   8 +-
 notmuch-reply.c   |  43 
 notmuch-search.c  |   6 +-
 notmuch-show.c|  48 +
 sprinter-sexp.c   | 250 ++
 sprinter.h|   4 +
 test/notmuch-test |   1 +
 test/sexp |  48 +
 12 files changed, 414 insertions(+), 60 deletions(-)
 create mode 100644 sprinter-sexp.c
 create mode 100755 test/sexp

-- 
1.8.0



[PATCH 1/1] Fixing failing JSON tests.

2012-12-04 Thread Peter Feigl
On Tue, 4 Dec 2012 09:35:41 -0500, Austin Clements  wrote:
> I must be missing something...  These both look like whitespace-only
> changes, which test_expect_equal_json normalizes.  Did you change
> something else, too?

They are, bremner on IRC was so kind to point out that my using Python
3.3 may be connected to the problem. I'll investigate further on why
exactly I get this behaviour.


using the List-Post header to reply to mailing lists

2012-12-04 Thread Kushal Kumaran
Hi,

I've been using notmuch with emacs for a while now.  I subscribe to a
few mailing lists where Reply-To-All is severely frowned upon, so I
wanted to be able to use the List-Post header (RFC2369) when replying to
mailing list posts.  I've hacked notmuch-reply.c for my purposes, but I
was wondering how other people manage.

As it stands, this patch is entirely unsuitable for merging.  At least
the following issues will need to be resolved first:

- should an additional command-line option be added to invoke this
  behaviour?  My personal preference is to just use the List-Post header
  whenever possible, if --reply-to=all is not given.

- should anything be done if the List-Post header has a URL which is not
  a mailto: URL (start a web browser?).  None of the mailing lists I'm
  subscribed to puts anything other than mailto.  The patch ignores the
  header if the URL is not a mailto.

- needs tests

- needs documentation

If anyone has alternatives to doing this kind of URL parsing, I'm
interested.  Comments regarding my pathetic knowledge of gmime are also
welcome.  If no one things notmuch needs this functionality, I will just
hold on to it for my personal use.

---
 notmuch-reply.c |   68 ---
 1 file changed, 60 insertions(+), 8 deletions(-)

diff --git a/notmuch-reply.c b/notmuch-reply.c
index e60a264..82f5a35 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -172,6 +172,11 @@ address_is_users (const char *address, notmuch_config_t 
*config)
 return address_match (address, config, STRING_IS_USER_ADDRESS) != NULL;
 }

+typedef enum {
+rfc822,
+url
+} address_format_t;
+
 /* Scan addresses in 'list'.
  *
  * If 'message' is non-NULL, then for each address in 'list' that is
@@ -231,6 +236,37 @@ scan_address_list (InternetAddressList *list,
 return n;
 }

+InternetAddressList *list_post_url_to_address_list(const char *header_value) {
+size_t recipients_len = strlen(header_value);
+size_t list_post_prefix_len = strlen("

[PATCH] Adding parse-time to test/.gitignore

2012-12-04 Thread Peter Feigl
test/parse-time is a binary that is generated when running make test. It should 
be ignored by git.
---
 test/.gitignore | 1 +
 1 file changed, 1 insertion(+)

diff --git a/test/.gitignore b/test/.gitignore
index 1eff7ce..97e0248 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -5,4 +5,5 @@ symbol-test
 arg-test
 hex-xcode
 random-corpus
+parse-time
 tmp.*
-- 
1.8.0



[PATCH 1/2] cli: fix notmuch top level argument parsing

2012-12-04 Thread Michal Nazarewicz
On Mon, Dec 03 2012, Jani Nikula wrote:
> And I'm not even sure strncmp is faster than strcmp, as it has to keep
> track of count.

Good point.

-- 
Best regards, _ _
.o. | Liege of Serenely Enlightened Majesty of  o' \,=./ `o
..o | Computer Science,  Micha? ?mina86? Nazarewicz(o o)
ooo +--ooO--(_)--Ooo--
-- 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/20121204/5502600a/attachment.pgp>


[PATCH 1/1] Changing build tool for test/random-corpus to CXX instead of CC.

2012-12-04 Thread Peter Feigl
Without this change, GCC complains as follows:
gcc  test/random-corpus.o test/database-test.o notmuch-config.o 
command-line-arguments.o lib/libnotmuch.a util/libutil.a 
parse-time-string/libparse-time-string.a -o test/random-corpus -lgmime-2.6 
-lgio-2.0 -lgobject-2.0 -lglib-2.0   -Wl,-rpath,/usr/lib -ltalloc   -lxapian
/usr/bin/ld: lib/libnotmuch.a(database.o): undefined reference to symbol 
'_ZNSs4_Rep10_M_destroyERKSaIcE@@GLIBCXX_3.4'
/usr/bin/ld: note: '_ZNSs4_Rep10_M_destroyERKSaIcE@@GLIBCXX_3.4' is defined in 
DSO /usr/lib/libstdc++.so.6 so try adding it to the linker command line
/usr/lib/libstdc++.so.6: could not read symbols: Invalid operation
collect2: error: ld returned 1 exit status
make: *** [test/random-corpus] Error 1
---
 test/Makefile.local | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/Makefile.local b/test/Makefile.local
index 6a9f15e..2ec6595 100644
--- a/test/Makefile.local
+++ b/test/Makefile.local
@@ -22,7 +22,7 @@ random_corpus_deps =  $(dir)/random-corpus.o  
$(dir)/database-test.o \
parse-time-string/libparse-time-string.a

 $(dir)/random-corpus: $(random_corpus_deps)
-   $(call quiet,CC) $(CFLAGS_FINAL) $^ -o $@ $(CONFIGURE_LDFLAGS)
+   $(call quiet,CXX) $(CFLAGS_FINAL) $^ -o $@ $(CONFIGURE_LDFLAGS)

 $(dir)/smtp-dummy: $(smtp_dummy_modules)
$(call quiet,CC) $^ -o $@
-- 
1.8.0



[PATCH 1/1] Fixing failing JSON tests.

2012-12-04 Thread Peter Feigl
Two --format=json tests were failing, both due changes in the output
format introduced by the structured formatting code. This patch updates
the expected output.
---
 test/json | 12 ++--
 1 file changed, 2 insertions(+), 10 deletions(-)

diff --git a/test/json b/test/json
index bfafd55..75b732f 100755
--- a/test/json
+++ b/test/json
@@ -32,7 +32,7 @@ test_expect_equal_json "$output" "[{\"thread\": \"XXX\",
 test_begin_subtest "Show message: json, utf-8"
 add_message "[subject]=\"json-show-utf8-body-s?bj?ct\"" "[date]=\"Sat, 01 Jan 
2000 12:00:00 -\"" "[body]=\"js?n-show-m?ssage\""
 output=$(notmuch show --format=json "js?n-show-m?ssage")
-test_expect_equal_json "$output" "[[[{\"id\": \"${gen_msg_id}\", \"match\": 
true, \"excluded\": false, \"filename\": \"${gen_msg_filename}\", 
\"timestamp\": 946728000, \"date_relative\": \"2000-01-01\", \"tags\": 
[\"inbox\",\"unread\"], \"headers\": {\"Subject\": 
\"json-show-utf8-body-s?bj?ct\", \"From\": \"Notmuch Test Suite \", \"To\": \"Notmuch Test Suite \", \"Date\": \"Sat, 01 Jan 2000 12:00:00 +\"}, \"body\": 
[{\"id\": 1, \"content-type\": \"text/plain\", \"content\": 
\"js?n-show-m?ssage\n\"}]}, ["
+test_expect_equal_json "$output" "[[[{\"id\": \"${gen_msg_id}\", \"match\": 
true, \"excluded\": false, \"filename\": \"${gen_msg_filename}\", 
\"timestamp\": 946728000, \"date_relative\": \"2000-01-01\", \"tags\": 
[\"inbox\", \"unread\"], \"headers\": {\"Subject\": 
\"json-show-utf8-body-s?bj?ct\", \"From\": \"Notmuch Test Suite \", \"To\": \"Notmuch Test Suite \", \"Date\": \"Sat, 01 Jan 2000 12:00:00 +\"}, \"body\": 
[{\"id\": 1, \"content-type\": \"text/plain\", \"content\": 
\"js?n-show-m?ssage\n\"}]}, ["

 test_begin_subtest "Show message: json, inline attachment filename"
 subject='json-show-inline-attachment-filename'
@@ -50,14 +50,6 @@ test_expect_equal_json "$output" "[[[{\"id\": \"$id\", 
\"match\": true, \"exclud
 test_begin_subtest "Search message: json, utf-8"
 add_message "[subject]=\"json-search-utf8-body-s?bj?ct\"" "[date]=\"Sat, 01 
Jan 2000 12:00:00 -\"" "[body]=\"js?n-search-m?ssage\""
 output=$(notmuch search --format=json "js?n-search-m?ssage" | 
notmuch_search_sanitize)
-test_expect_equal_json "$output" "[{\"thread\": \"XXX\",
- \"timestamp\": 946728000,
- \"date_relative\": \"2000-01-01\",
- \"matched\": 1,
- \"total\": 1,
- \"authors\": \"Notmuch Test Suite\",
- \"subject\": \"json-search-utf8-body-s?bj?ct\",
- \"tags\": [\"inbox\",
- \"unread\"]}]"
+test_expect_equal_json "$output" "[{\"thread\": \"XXX\", \"timestamp\": 
946728000, \"date_relative\": \"2000-01-01\", \"matched\": 1, \"total\": 1, 
\"authors\": \"Notmuch Test Suite\", \"subject\": 
\"json-search-utf8-body-s?bj?ct\", \"tags\": [\"inbox\", \"unread\"]}]"

 test_done
-- 
1.8.0



[PATCH v2 4/5] Adding tests for --format=sexp.

2012-12-04 Thread Austin Clements
It would be nice to use something like test_expect_equal_json for this
(probably based on Emacs' pp function), but this is fine for now.

On Tue, 04 Dec 2012, Peter Feigl  wrote:
> Add basic tests, the same as for json, for the S-Expression output
> format.
> ---
>  test/notmuch-test |  1 +
>  test/sexp | 48 
>  2 files changed, 49 insertions(+)
>  create mode 100755 test/sexp
>
> diff --git a/test/notmuch-test b/test/notmuch-test
> index a6ef34f..ca9c3dc 100755
> --- a/test/notmuch-test
> +++ b/test/notmuch-test
> @@ -31,6 +31,7 @@ TESTS="
>excludes
>tagging
>json
> +  sexp
>text
>multipart
>thread-naming
> diff --git a/test/sexp b/test/sexp
> new file mode 100755
> index 000..fdc9de6
> --- /dev/null
> +++ b/test/sexp
> @@ -0,0 +1,48 @@
> +#!/usr/bin/env bash
> +test_description="--format=sexp output"
> +. ./test-lib.sh
> +
> +test_begin_subtest "Show message: sexp"
> +add_message "[subject]=\"sexp-show-subject\"" "[date]=\"Sat, 01 Jan 2000 
> 12:00:00 -\"" "[bcc]=\"test_suite+bcc at notmuchmail.org\"" 
> "[reply-to]=\"test_suite+replyto at notmuchmail.org\"" 
> "[body]=\"sexp-show-message\""
> +output=$(notmuch show --format=sexp "sexp-show-message")
> +test_expect_equal "$output" "(id \"msg-001 at notmuch-test-suite\") 
> (match t) (excluded nil) (filename 
> \"/home/nex/notmuch-sexp/test/tmp.sexp/mail/msg-001\") (timestamp 946728000) 
> (date_relative \"2000-01-01\") (tags (\"inbox\" \"unread\")) (headers 
> ((Subject \"sexp-show-subject\") (From \"Notmuch Test Suite  notmuchmail.org>\") (To \"Notmuch Test Suite  notmuchmail.org>\") (Bcc \"test_suite+bcc at notmuchmail.org\") (Reply-To 
> \"test_suite+replyto at notmuchmail.org\") (Date \"Sat, 01 Jan 2000 12:00:00 
> +\"))) (body (((id 1) (content-type \"text/plain\") (content 
> \"sexp-show-message\n\") ("
> +
> +# This should be the same output as above.
> +test_begin_subtest "Show message: sexp --body=true"
> +output=$(notmuch show --format=sexp --body=true "sexp-show-message")
> +test_expect_equal "$output" "(id \"msg-001 at notmuch-test-suite\") 
> (match t) (excluded nil) (filename 
> \"/home/nex/notmuch-sexp/test/tmp.sexp/mail/msg-001\") (timestamp 946728000) 
> (date_relative \"2000-01-01\") (tags (\"inbox\" \"unread\")) (headers 
> ((Subject \"sexp-show-subject\") (From \"Notmuch Test Suite  notmuchmail.org>\") (To \"Notmuch Test Suite  notmuchmail.org>\") (Bcc \"test_suite+bcc at notmuchmail.org\") (Reply-To 
> \"test_suite+replyto at notmuchmail.org\") (Date \"Sat, 01 Jan 2000 12:00:00 
> +\"))) (body (((id 1) (content-type \"text/plain\") (content 
> \"sexp-show-message\n\") ("
> +
> +test_begin_subtest "Show message: sexp --body=false"
> +output=$(notmuch show --format=sexp --body=false "sexp-show-message")
> +test_expect_equal "$output" "(id \"msg-001 at notmuch-test-suite\") 
> (match t) (excluded nil) (filename 
> \"/home/nex/notmuch-sexp/test/tmp.sexp/mail/msg-001\") (timestamp 946728000) 
> (date_relative \"2000-01-01\") (tags (\"inbox\" \"unread\")) (headers 
> ((Subject \"sexp-show-subject\") (From \"Notmuch Test Suite  notmuchmail.org>\") (To \"Notmuch Test Suite  notmuchmail.org>\") (Bcc \"test_suite+bcc at notmuchmail.org\") (Reply-To 
> \"test_suite+replyto at notmuchmail.org\") (Date \"Sat, 01 Jan 2000 12:00:00 
> +\" ("
> +
> +test_begin_subtest "Search message: sexp"
> +add_message "[subject]=\"sexp-search-subject\"" "[date]=\"Sat, 01 Jan 2000 
> 12:00:00 -\"" "[body]=\"sexp-search-message\""
> +output=$(notmuch search --format=sexp "sexp-search-message" | 
> notmuch_search_sanitize)
> +test_expect_equal "$output" "(((thread \"0002\") (timestamp 
> 946728000) (date_relative \"2000-01-01\") (matched 1) (total 1) (authors 
> \"Notmuch Test Suite\") (subject \"sexp-search-subject\") (tags (\"inbox\" 
> \"unread\""
> +
> +test_begin_subtest "Show message: sexp, utf-8"
> +add_message "[subject]=\"sexp-show-utf8-body-s?bj?ct\"" "[date]=\"Sat, 01 
> Jan 2000 12:00:00 -\"" "[body]=\"js?n-show-m?ssage\""
> +output=$(notmuch show --format=sexp "js?n-show-m?ssage")
> +test_expect_equal "$output" "(id \"msg-003 at notmuch-test-suite\") 
> (match t) (excluded nil) (filename 
> \"/home/nex/notmuch-sexp/test/tmp.sexp/mail/msg-003\") (timestamp 946728000) 
> (date_relative \"2000-01-01\") (tags (\"inbox\" \"unread\")) (headers 
> ((Subject \"sexp-show-utf8-body-s?bj?ct\") (From \"Notmuch Test Suite 
> \") (To \"Notmuch Test Suite  notmuchmail.org>\") (Date \"Sat, 01 Jan 2000 12:00:00 +\"))) (body (((id 
> 1) (content-type \"text/plain\") (content \"js?n-show-m?ssage\n\") ("
> +
> +test_begin_subtest "Show message: sexp, inline attachment filename"
> +subject='sexp-show-inline-attachment-filename'
> +id="sexp-show-inline-attachment-filename at notmuchmail.org"
> +emacs_deliver_message \
> +"$subject" \
> +'This is a test message with inline attachment with a 

[PATCH v2 3/5] Use the S-Expression structured printer in notmuch-show, notmuch-reply and notmuch-search.

2012-12-04 Thread Austin Clements
On Tue, 04 Dec 2012, Peter Feigl  wrote:
> This patch uses the new S-Expression printer in the notmuch CLI (show,
> search and reply). You can now use --format=sexp for any of them.
> ---
>  notmuch-reply.c  |  5 +
>  notmuch-search.c |  6 +-
>  notmuch-show.c   | 18 ++
>  3 files changed, 24 insertions(+), 5 deletions(-)
>
> diff --git a/notmuch-reply.c b/notmuch-reply.c
> index 53aefa7..69fd256 100644
> --- a/notmuch-reply.c
> +++ b/notmuch-reply.c
> @@ -697,6 +697,7 @@ notmuch_reply_format_headers_only(void *ctx,
>  enum {
>  FORMAT_DEFAULT,
>  FORMAT_JSON,
> +FORMAT_SEXP,
>  FORMAT_HEADERS_ONLY,
>  };
>  
> @@ -724,6 +725,7 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
>   { NOTMUCH_OPT_KEYWORD, , "format", 'f',
> (notmuch_keyword_t []){ { "default", FORMAT_DEFAULT },
> { "json", FORMAT_JSON },
> +   { "sexp", FORMAT_SEXP },

"sexpa" if we're going to support both alists and plists?  Same for the
others.

> { "headers-only", FORMAT_HEADERS_ONLY },
> { 0, 0 } } },
>   { NOTMUCH_OPT_KEYWORD, _all, "reply-to", 'r',
> @@ -745,6 +747,9 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
>  } else if (format == FORMAT_JSON) {
>   reply_format_func = notmuch_reply_format_sprinter;
>   sp = sprinter_json_create (ctx, stdout);
> +} else if (format == FORMAT_SEXP) {
> + reply_format_func = notmuch_reply_format_sprinter;
> + sp = sprinter_sexp_create (ctx, stdout);
>  } else {
>   reply_format_func = notmuch_reply_format_default;
>  }
> diff --git a/notmuch-search.c b/notmuch-search.c
> index 830c4e4..6218622 100644
> --- a/notmuch-search.c
> +++ b/notmuch-search.c
> @@ -305,7 +305,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
>  int exclude = EXCLUDE_TRUE;
>  unsigned int i;
>  
> -enum { NOTMUCH_FORMAT_JSON, NOTMUCH_FORMAT_TEXT }
> +enum { NOTMUCH_FORMAT_JSON, NOTMUCH_FORMAT_TEXT, NOTMUCH_FORMAT_SEXP }
>   format_sel = NOTMUCH_FORMAT_TEXT;
>  
>  notmuch_opt_desc_t options[] = {
> @@ -315,6 +315,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
> { 0, 0 } } },
>   { NOTMUCH_OPT_KEYWORD, _sel, "format", 'f',
> (notmuch_keyword_t []){ { "json", NOTMUCH_FORMAT_JSON },
> +   { "sexp", NOTMUCH_FORMAT_SEXP },
> { "text", NOTMUCH_FORMAT_TEXT },
> { 0, 0 } } },
>   { NOTMUCH_OPT_KEYWORD, , "output", 'o',
> @@ -347,6 +348,9 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
>  case NOTMUCH_FORMAT_JSON:
>   format = sprinter_json_create (ctx, stdout);
>   break;
> +case NOTMUCH_FORMAT_SEXP:
> + format = sprinter_sexp_create (ctx, stdout);
> + break;
>  default:
>   /* this should never happen */
>   INTERNAL_ERROR("no output format selected");
> diff --git a/notmuch-show.c b/notmuch-show.c
> index 38c621f..d4860f1 100644
> --- a/notmuch-show.c
> +++ b/notmuch-show.c
> @@ -40,6 +40,11 @@ static const notmuch_show_format_t format_json = {
>  .part = format_part_sprinter_entry,
>  };
>  
> +static const notmuch_show_format_t format_sexp = {
> +.new_sprinter = sprinter_sexp_create,
> +.part = format_part_sprinter_entry,
> +};
> +
>  static notmuch_status_t
>  format_part_mbox (const void *ctx, sprinter_t *sp, mime_node_t *node,
> int indent, const notmuch_show_params_t *params);
> @@ -110,7 +115,7 @@ _get_one_line_summary (const void *ctx, notmuch_message_t 
> *message)
>  static void
>  format_message_sprinter (sprinter_t *sp, notmuch_message_t *message)
>  {
> -/* Any changes to the JSON format should be reflected in the file
> +/* Any changes to the JSON or S-Expression format should be reflected in 
> the file
>   * devel/schemata. */

Please re-wrap this comment to 72 columns.

>  
>  void *local = talloc_new (NULL);
> @@ -1012,6 +1017,7 @@ do_show (void *ctx,
>  enum {
>  NOTMUCH_FORMAT_NOT_SPECIFIED,
>  NOTMUCH_FORMAT_JSON,
> +NOTMUCH_FORMAT_SEXP,
>  NOTMUCH_FORMAT_TEXT,
>  NOTMUCH_FORMAT_MBOX,
>  NOTMUCH_FORMAT_RAW
> @@ -1056,6 +1062,7 @@ notmuch_show_command (void *ctx, unused (int argc), 
> unused (char *argv[]))
>   { NOTMUCH_OPT_KEYWORD, _sel, "format", 'f',
> (notmuch_keyword_t []){ { "json", NOTMUCH_FORMAT_JSON },
> { "text", NOTMUCH_FORMAT_TEXT },
> +   { "sexp", NOTMUCH_FORMAT_SEXP },
> { "mbox", NOTMUCH_FORMAT_MBOX },
> { "raw", NOTMUCH_FORMAT_RAW },
> { 0, 0 } } },
> @@ -1100,6 +1107,9 @@ notmuch_show_command (void *ctx, unused (int argc), 
> unused (char *argv[]))
>  case NOTMUCH_FORMAT_TEXT:
>   

[PATCH v2 2/5] Rename the -json printer functions in notmuch-reply and notmuch-show to generic -sprinter functions.

2012-12-04 Thread Austin Clements
On Tue, 04 Dec 2012, Peter Feigl  wrote:
> All the structured output functions in notmuch-reply and notmuch-show
> are renamed to a generic name (as they do not contain any json-specific
> code anyway). This patch is a preparation to actually using the new
> S-Expression sprinter in notmuch-reply and notmuch-show.
> ---
>  notmuch-client.h |  8 
>  notmuch-reply.c  | 38 +-
>  notmuch-show.c   | 30 +++---
>  3 files changed, 40 insertions(+), 36 deletions(-)
>
> diff --git a/notmuch-client.h b/notmuch-client.h
> index ae9344b..1c336dc 100644
> --- a/notmuch-client.h
> +++ b/notmuch-client.h
> @@ -175,12 +175,12 @@ notmuch_status_t
>  show_one_part (const char *filename, int part);
>  
>  void
> -format_part_json (const void *ctx, struct sprinter *sp, mime_node_t *node,
> -   notmuch_bool_t first, notmuch_bool_t output_body);
> +format_part_sprinter (const void *ctx, struct sprinter *sp, mime_node_t 
> *node,
> +   notmuch_bool_t first, notmuch_bool_t output_body);
>  
>  void
> -format_headers_json (struct sprinter *sp, GMimeMessage *message,
> -  notmuch_bool_t reply);
> +format_headers_sprinter (struct sprinter *sp, GMimeMessage *message,
> +  notmuch_bool_t reply);
>  
>  typedef enum {
>  NOTMUCH_SHOW_TEXT_PART_REPLY = 1 << 0,
> diff --git a/notmuch-reply.c b/notmuch-reply.c
> index e60a264..53aefa7 100644
> --- a/notmuch-reply.c
> +++ b/notmuch-reply.c
> @@ -548,7 +548,8 @@ notmuch_reply_format_default(void *ctx,
>notmuch_config_t *config,
>notmuch_query_t *query,
>notmuch_show_params_t *params,
> -  notmuch_bool_t reply_all)
> +  notmuch_bool_t reply_all,
> +  unused (sprinter_t *sp))
>  {
>  GMimeMessage *reply;
>  notmuch_messages_t *messages;
> @@ -587,17 +588,17 @@ notmuch_reply_format_default(void *ctx,
>  }
>  
>  static int
> -notmuch_reply_format_json(void *ctx,
> -   notmuch_config_t *config,
> -   notmuch_query_t *query,
> -   notmuch_show_params_t *params,
> -   notmuch_bool_t reply_all)
> +notmuch_reply_format_sprinter(void *ctx,
> +   notmuch_config_t *config,
> +   notmuch_query_t *query,
> +   notmuch_show_params_t *params,
> +   notmuch_bool_t reply_all,
> +   sprinter_t *sp)
>  {
>  GMimeMessage *reply;
>  notmuch_messages_t *messages;
>  notmuch_message_t *message;
>  mime_node_t *node;
> -sprinter_t *sp;
>  
>  if (notmuch_query_count_messages (query) != 1) {
>   fprintf (stderr, "Error: search term did not match precisely one 
> message.\n");
> @@ -613,18 +614,17 @@ notmuch_reply_format_json(void *ctx,
>  if (!reply)
>   return 1;
>  
> -sp = sprinter_json_create (ctx, stdout);
>  sp->begin_map (sp);
>  
>  /* The headers of the reply message we've created */
>  sp->map_key (sp, "reply-headers");
> -format_headers_json (sp, reply, TRUE);
> +format_headers_sprinter (sp, reply, TRUE);
>  g_object_unref (G_OBJECT (reply));
>  reply = NULL;
>  
>  /* Start the original */
>  sp->map_key (sp, "original");
> -format_part_json (ctx, sp, node, TRUE, TRUE);
> +format_part_sprinter (ctx, sp, node, TRUE, TRUE);
>  
>  /* End */
>  sp->end (sp);
> @@ -639,7 +639,8 @@ notmuch_reply_format_headers_only(void *ctx,
> notmuch_config_t *config,
> notmuch_query_t *query,
> unused (notmuch_show_params_t *params),
> -   notmuch_bool_t reply_all)
> +   notmuch_bool_t reply_all,
> +   unused (sprinter_t *sp))
>  {
>  GMimeMessage *reply;
>  notmuch_messages_t *messages;
> @@ -707,7 +708,7 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
>  notmuch_query_t *query;
>  char *query_string;
>  int opt_index, ret = 0;
> -int (*reply_format_func)(void *ctx, notmuch_config_t *config, 
> notmuch_query_t *query, notmuch_show_params_t *params, notmuch_bool_t 
> reply_all);
> +int (*reply_format_func)(void *ctx, notmuch_config_t *config, 
> notmuch_query_t *query, notmuch_show_params_t *params, notmuch_bool_t 
> reply_all, struct sprinter *sp);

Yikes.  This could use some line wrapping.

This patch LGTM other than this.

>  notmuch_show_params_t params = {
>   .part = -1,
>   .crypto = {
> @@ -717,6 +718,7 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
>  };
>  int format = FORMAT_DEFAULT;
>  int reply_all = TRUE;
> +struct sprinter *sp = NULL;
>  
>  notmuch_opt_desc_t 

[PATCH v2 1/5] Adding an S-expression structured output printer.

2012-12-04 Thread Austin Clements
On Tue, 04 Dec 2012, Peter Feigl  wrote:
> This commit adds a structured output printer for Lisp
> S-Expressions. Later commits will use this printer in notmuch search,
> show and reply.
>
> The structure is the same as json, but:
> - arrays are written as lists: ("foo" "bar" "baaz" 1 2 3)
> - maps are written as a-lists: ((key "value") (other-key "other-value"))

I thought the plan was to use plists.  Or are we going to support both?

> - true is written as t
> - false is written as nil
> - null is written as nil
> ---
>  Makefile.local  |   1 +
>  sprinter-sexp.c | 250 
> 
>  sprinter.h  |   4 +
>  3 files changed, 255 insertions(+)
>  create mode 100644 sprinter-sexp.c
>
> diff --git a/Makefile.local b/Makefile.local
> index 2b91946..0db1713 100644
> --- a/Makefile.local
> +++ b/Makefile.local
> @@ -270,6 +270,7 @@ notmuch_client_srcs = \
>   notmuch-tag.c   \
>   notmuch-time.c  \
>   sprinter-json.c \
> + sprinter-sexp.c \
>   sprinter-text.c \
>   query-string.c  \
>   mime-node.c \
> diff --git a/sprinter-sexp.c b/sprinter-sexp.c
> new file mode 100644
> index 000..6d6bbad
> --- /dev/null
> +++ b/sprinter-sexp.c
> @@ -0,0 +1,250 @@
> +/* notmuch - Not much of an email program, (just index and search)
> + *
> + * Copyright ? 2012 Carl Worth

This should probably be your name.

> + *
> + * 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/ .
> + *
> + * Author: Carl Worth 

Same here.

> + */
> +
> +#include 
> +#include 
> +#include 
> +#include "sprinter.h"
> +
> +struct sprinter_sexp {
> +struct sprinter vtable;
> +FILE *stream;
> +/* Top of the state stack, or NULL if the printer is not currently
> + * inside any aggregate types. */
> +struct sexp_state *state;
> +
> +/* A flag to signify that a separator should be inserted in the
> + * output as soon as possible.
> + */
> +notmuch_bool_t insert_separator;
> +};
> +
> +struct sexp_state {
> +struct sexp_state *parent;
> +
> +/* True if nothing has been printed in this aggregate yet.
> + * Suppresses the space before a value. */
> +notmuch_bool_t first;
> +
> +/* True if the state is a map state.
> + * Used to add a space between key/value pairs. */
> +notmuch_bool_t in_map;

Maybe in_alist?

> +
> +/* The character that closes the current aggregate. */
> +char close;

Given that the close character is always ')', why have this field?

> +};
> +
> +/* Helper function to set up the stream to print a value.  If this
> + * value follows another value, prints a space. */
> +static struct sprinter_sexp *
> +sexp_begin_value (struct sprinter *sp)
> +{
> +struct sprinter_sexp *sps = (struct sprinter_sexp *) sp;
> +
> +if (sps->state) {
> + if (! sps->state->first) {
> + if (sps->insert_separator) {
> + fputc ('\n', sps->stream);
> + sps->insert_separator = FALSE;
> + } else {
> + if (! sps->state->in_map)
> + fputc (' ', sps->stream);
> + }
> + } else {
> + sps->state->first = FALSE;
> + }
> +}
> +return sps;
> +}
> +
> +/* Helper function to begin an aggregate type.  Prints the open
> + * character and pushes a new state frame. */
> +static void
> +sexp_begin_aggregate (struct sprinter *sp, char open, char close)

The open and close arguments seem unnecessary here, since they're always
'(' and ')'.  Perhaps this should instead take in_map as an argument?

> +{
> +struct sprinter_sexp *sps = sexp_begin_value (sp);
> +struct sexp_state *state = talloc (sps, struct sexp_state);
> +fputc (open, sps->stream);
> +state->parent = sps->state;
> +state->first = TRUE;
> +state->in_map = FALSE;
> +state->close = close;
> +sps->state = state;
> +}
> +
> +static void
> +sexp_begin_map (struct sprinter *sp)
> +{
> +struct sprinter_sexp *sps = (struct sprinter_sexp *) sp;
> +sexp_begin_aggregate (sp, '(', ')');
> +sps->state->in_map = TRUE;
> +}
> +
> +static void
> +sexp_begin_list (struct sprinter *sp)
> +{
> +sexp_begin_aggregate (sp, '(', ')');
> +}
> +
> +static void
> +sexp_end (struct sprinter *sp)
> +{
> +struct sprinter_sexp *sps = (struct sprinter_sexp *) 

[PATCH] test: Fix UTF-8 JSON tests in Python 3

2012-12-04 Thread Austin Clements
test_expect_equal_json uses json.tool from the system Python.  While
Python 2 wasn't picky about the encoding of stdin, Python 3 decodes
stdin strictly according to the environment.  Since we set LC_ALL=C
for the tests, Python 3's json.tool was assuming stdin would be in
ASCII and aborting when it couldn't decode the UTF-8 characters from
some of the JSON tests.  This patch sets the PYTHONIOENCODING
environment variable to utf-8 when invoking json.tool to override
Python's default encoding choice.
---
 test/test-lib.sh |9 +++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/test/test-lib.sh b/test/test-lib.sh
index f169785..9487526 100644
--- a/test/test-lib.sh
+++ b/test/test-lib.sh
@@ -534,8 +534,13 @@ test_expect_equal_file ()
 # canonicalized before diff'ing.  If an argument cannot be parsed, it
 # is used unchanged so that there's something to diff against.
 test_expect_equal_json () {
-output=$(echo "$1" | python -mjson.tool || echo "$1")
-expected=$(echo "$2" | python -mjson.tool || echo "$2")
+# The test suite forces LC_ALL=C, but this causes Python 3 to
+# decode stdin as ASCII.  We need to read JSON in UTF-8, so
+# override Python's stdio encoding defaults.
+output=$(echo "$1" | PYTHONIOENCODING=utf-8 python -mjson.tool \
+|| echo "$1")
+expected=$(echo "$2" | PYTHONIOENCODING=utf-8 python -mjson.tool \
+|| echo "$2")
 shift 2
 test_expect_equal "$output" "$expected" "$@"
 }
-- 
1.7.10.4



[PATCH 1/1] Changing build tool for test/random-corpus to CXX instead of CC.

2012-12-04 Thread Austin Clements
LGTM.  I think we build the main notmuch binary with g++ for the same
reason.

Quoth Peter Feigl on Dec 04 at  2:47 pm:
> Without this change, GCC complains as follows:
> gcc  test/random-corpus.o test/database-test.o notmuch-config.o 
> command-line-arguments.o lib/libnotmuch.a util/libutil.a 
> parse-time-string/libparse-time-string.a -o test/random-corpus -lgmime-2.6 
> -lgio-2.0 -lgobject-2.0 -lglib-2.0   -Wl,-rpath,/usr/lib -ltalloc   -lxapian
> /usr/bin/ld: lib/libnotmuch.a(database.o): undefined reference to symbol 
> '_ZNSs4_Rep10_M_destroyERKSaIcE@@GLIBCXX_3.4'
> /usr/bin/ld: note: '_ZNSs4_Rep10_M_destroyERKSaIcE@@GLIBCXX_3.4' is defined 
> in DSO /usr/lib/libstdc++.so.6 so try adding it to the linker command line
> /usr/lib/libstdc++.so.6: could not read symbols: Invalid operation
> collect2: error: ld returned 1 exit status
> make: *** [test/random-corpus] Error 1
> ---
>  test/Makefile.local | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/test/Makefile.local b/test/Makefile.local
> index 6a9f15e..2ec6595 100644
> --- a/test/Makefile.local
> +++ b/test/Makefile.local
> @@ -22,7 +22,7 @@ random_corpus_deps =  $(dir)/random-corpus.o  
> $(dir)/database-test.o \
>   parse-time-string/libparse-time-string.a
>  
>  $(dir)/random-corpus: $(random_corpus_deps)
> - $(call quiet,CC) $(CFLAGS_FINAL) $^ -o $@ $(CONFIGURE_LDFLAGS)
> + $(call quiet,CXX) $(CFLAGS_FINAL) $^ -o $@ $(CONFIGURE_LDFLAGS)
>  
>  $(dir)/smtp-dummy: $(smtp_dummy_modules)
>   $(call quiet,CC) $^ -o $@


[PATCH 1/1] Fixing failing JSON tests.

2012-12-04 Thread Austin Clements
I must be missing something...  These both look like whitespace-only
changes, which test_expect_equal_json normalizes.  Did you change
something else, too?

Quoth Peter Feigl on Dec 04 at  2:46 pm:
> Two --format=json tests were failing, both due changes in the output
> format introduced by the structured formatting code. This patch updates
> the expected output.
> ---
>  test/json | 12 ++--
>  1 file changed, 2 insertions(+), 10 deletions(-)
> 
> diff --git a/test/json b/test/json
> index bfafd55..75b732f 100755
> --- a/test/json
> +++ b/test/json
> @@ -32,7 +32,7 @@ test_expect_equal_json "$output" "[{\"thread\": \"XXX\",
>  test_begin_subtest "Show message: json, utf-8"
>  add_message "[subject]=\"json-show-utf8-body-s?bj?ct\"" "[date]=\"Sat, 01 
> Jan 2000 12:00:00 -\"" "[body]=\"js?n-show-m?ssage\""
>  output=$(notmuch show --format=json "js?n-show-m?ssage")
> -test_expect_equal_json "$output" "[[[{\"id\": \"${gen_msg_id}\", \"match\": 
> true, \"excluded\": false, \"filename\": \"${gen_msg_filename}\", 
> \"timestamp\": 946728000, \"date_relative\": \"2000-01-01\", \"tags\": 
> [\"inbox\",\"unread\"], \"headers\": {\"Subject\": 
> \"json-show-utf8-body-s?bj?ct\", \"From\": \"Notmuch Test Suite  at notmuchmail.org>\", \"To\": \"Notmuch Test Suite  notmuchmail.org>\", \"Date\": \"Sat, 01 Jan 2000 12:00:00 +\"}, \"body\": 
> [{\"id\": 1, \"content-type\": \"text/plain\", \"content\": 
> \"js?n-show-m?ssage\n\"}]}, ["
> +test_expect_equal_json "$output" "[[[{\"id\": \"${gen_msg_id}\", \"match\": 
> true, \"excluded\": false, \"filename\": \"${gen_msg_filename}\", 
> \"timestamp\": 946728000, \"date_relative\": \"2000-01-01\", \"tags\": 
> [\"inbox\", \"unread\"], \"headers\": {\"Subject\": 
> \"json-show-utf8-body-s?bj?ct\", \"From\": \"Notmuch Test Suite  at notmuchmail.org>\", \"To\": \"Notmuch Test Suite  notmuchmail.org>\", \"Date\": \"Sat, 01 Jan 2000 12:00:00 +\"}, \"body\": 
> [{\"id\": 1, \"content-type\": \"text/plain\", \"content\": 
> \"js?n-show-m?ssage\n\"}]}, ["
>  
>  test_begin_subtest "Show message: json, inline attachment filename"
>  subject='json-show-inline-attachment-filename'
> @@ -50,14 +50,6 @@ test_expect_equal_json "$output" "[[[{\"id\": \"$id\", 
> \"match\": true, \"exclud
>  test_begin_subtest "Search message: json, utf-8"
>  add_message "[subject]=\"json-search-utf8-body-s?bj?ct\"" "[date]=\"Sat, 01 
> Jan 2000 12:00:00 -\"" "[body]=\"js?n-search-m?ssage\""
>  output=$(notmuch search --format=json "js?n-search-m?ssage" | 
> notmuch_search_sanitize)
> -test_expect_equal_json "$output" "[{\"thread\": \"XXX\",
> - \"timestamp\": 946728000,
> - \"date_relative\": \"2000-01-01\",
> - \"matched\": 1,
> - \"total\": 1,
> - \"authors\": \"Notmuch Test Suite\",
> - \"subject\": \"json-search-utf8-body-s?bj?ct\",
> - \"tags\": [\"inbox\",
> - \"unread\"]}]"
> +test_expect_equal_json "$output" "[{\"thread\": \"XXX\", \"timestamp\": 
> 946728000, \"date_relative\": \"2000-01-01\", \"matched\": 1, \"total\": 1, 
> \"authors\": \"Notmuch Test Suite\", \"subject\": 
> \"json-search-utf8-body-s?bj?ct\", \"tags\": [\"inbox\", \"unread\"]}]"
>  
>  test_done


[PATCH 1/2] cli: fix notmuch top level argument parsing

2012-12-04 Thread David Bremner
Jani Nikula  writes:

> Use strcmp instead of STRNCMP_LITERAL, which matches the prefix
> instead of the whole argument.

pushed both, 

d


[PATCH] emacs: drop support for deprecated notmuch-folders

2012-12-04 Thread David Bremner
Jani Nikula  writes:

> Remove notmuch-folders which has been deprecated since
>
> commit a4669217600e4536dc0c49f0255af5e2d9bc183f
> Author: Carl Worth 
> Date:   Mon Apr 26 22:42:07 2010 -0700

pushed, 

d

PS: NEWS-worthy?


[PATCH] test: fix an evident copy-paste error in argument parsing test

2012-12-04 Thread David Bremner
Jani Nikula  writes:

> ---
>  test/arg-test.c   |2 +-
>  test/argument-parsing |2 +-
>  2 files changed, 2 insertions(+), 2 deletions(-)

pushed,

d


[PATCH] test: fix an evident copy-paste error in argument parsing test

2012-12-04 Thread Jani Nikula
---
 test/arg-test.c   |2 +-
 test/argument-parsing |2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/test/arg-test.c b/test/arg-test.c
index adc56e3..6c49eac 100644
--- a/test/arg-test.c
+++ b/test/arg-test.c
@@ -41,7 +41,7 @@ int main(int argc, char **argv){
printf("positional arg 1 %s\n", pos_arg1);

 if (pos_arg2)
-   printf("positional arg 2 %s\n", pos_arg1);
+   printf("positional arg 2 %s\n", pos_arg2);


 for ( ; opt_index < argc ; opt_index ++) {
diff --git a/test/argument-parsing b/test/argument-parsing
index 672de0b..94e9087 100755
--- a/test/argument-parsing
+++ b/test/argument-parsing
@@ -9,7 +9,7 @@ keyword 1
 int 7
 string foo
 positional arg 1 pos1
-positional arg 2 pos1
+positional arg 2 pos2
 EOF
 test_expect_equal_file OUTPUT EXPECTED

-- 
1.7.10.4



[PATCH 2/4] perf-test: bump corpus version to 0.3

2012-12-04 Thread David Bremner
david at tethera.net writes:

> From: David Bremner 
>
> The new version ships with some tags, and an updated archive of the
> notmuch mailing list.

Because of scarce disk space on notmuchmail.org, currently you have to
grab the corpus from 

http://tesseract.cs.unb.ca/notmuch/notmuch-email-corpus-0.3.tar.xz
http://tesseract.cs.unb.ca/notmuch/notmuch-email-corpus-0.3.tar.xz.asc

d

P.S. In partial answer to id:87txs4cy7v.fsf at nikula.org, the new optimization
seems to be just as fast, even with the additional tags.


[PATCH 4/4] perf-test: add nmbug tags to default database

2012-12-04 Thread da...@tethera.net
From: David Bremner 

This makes the tag set a bit less boring, and also acts as a benchmark
on its own.
---
 performance-test/basic |2 ++
 1 file changed, 2 insertions(+)

diff --git a/performance-test/basic b/performance-test/basic
index 41a7ff1..3225983 100755
--- a/performance-test/basic
+++ b/performance-test/basic
@@ -10,6 +10,8 @@ print_header

 time_run 'initial notmuch new' 'notmuch new'

+time_run 'load nmbug tags' 'notmuch restore --accumulate < 
corpus.tags/nmbug.sup-dump'
+
 cache_database

 time_run 'second notmuch new' 'notmuch new'
-- 
1.7.10.4



[PATCH 3/4] perf-test: unpack tags.

2012-12-04 Thread da...@tethera.net
From: David Bremner 

It's a bit annoying to call tar twice, but we cache the results so it
isn't as bad as it could be.
---
 performance-test/Makefile.local   |1 +
 performance-test/perf-test-lib.sh |   25 +++--
 2 files changed, 20 insertions(+), 6 deletions(-)

diff --git a/performance-test/Makefile.local b/performance-test/Makefile.local
index b136a88..cdd7f19 100644
--- a/performance-test/Makefile.local
+++ b/performance-test/Makefile.local
@@ -30,3 +30,4 @@ download-corpus:
wget -O ${TXZFILE} ${DEFAULT_URL}

 CLEAN := $(CLEAN) $(dir)/tmp.* $(dir)/corpus.mail.* $(dir)/notmuch.cache.*
+CLEAN := $(CLEAN) $(dir)/corpus.tags
diff --git a/performance-test/perf-test-lib.sh 
b/performance-test/perf-test-lib.sh
index 08e2ebd..40c88c9 100644
--- a/performance-test/perf-test-lib.sh
+++ b/performance-test/perf-test-lib.sh
@@ -41,6 +41,13 @@ DB_CACHE_DIR=${TEST_DIRECTORY}/notmuch.cache.$corpus_size
 add_email_corpus ()
 {
 rm -rf ${MAIL_DIR}
+
+if command -v pixz > /dev/null; then
+   XZ=pixz
+else
+   XZ=xz
+fi
+
 if [ ! -d $CORPUS_DIR ]; then
case "$corpus_size" in
small)
@@ -53,12 +60,6 @@ add_email_corpus ()
arg=mail
esac

-   if command -v pixz > /dev/null; then
-   XZ=pixz
-   else
-   XZ=xz
-   fi
-
printf "Unpacking corpus\n"
mkdir $CORPUS_DIR

@@ -72,6 +73,18 @@ add_email_corpus ()

 fi

+if [ ! -d $TEST_DIRECTORY/corpus.tags ]; then
+
+   mkdir $TEST_DIRECTORY/corpus.tags
+
+   tar --extract --strip-components=2 \
+   --directory $TEST_DIRECTORY/corpus.tags \
+   --use-compress-program ${XZ} \
+   --file ../download/notmuch-email-corpus-${PERFTEST_VERSION}.tar.xz \
+   notmuch-email-corpus/tags
+fi
+
+cp -lr $TEST_DIRECTORY/corpus.tags $TMP_DIRECTORY
 cp -lr $CORPUS_DIR $MAIL_DIR

 if [ -d $DB_CACHE_DIR ]; then
-- 
1.7.10.4



[PATCH 2/4] perf-test: bump corpus version to 0.3

2012-12-04 Thread da...@tethera.net
From: David Bremner 

The new version ships with some tags, and an updated archive of the
notmuch mailing list.
---
 performance-test/download/notmuch-email-corpus-0.2.tar.xz.asc |9 -
 performance-test/download/notmuch-email-corpus-0.3.tar.xz.asc |9 +
 performance-test/version.sh   |2 +-
 3 files changed, 10 insertions(+), 10 deletions(-)
 delete mode 100644 
performance-test/download/notmuch-email-corpus-0.2.tar.xz.asc
 create mode 100644 
performance-test/download/notmuch-email-corpus-0.3.tar.xz.asc

diff --git a/performance-test/download/notmuch-email-corpus-0.2.tar.xz.asc 
b/performance-test/download/notmuch-email-corpus-0.2.tar.xz.asc
deleted file mode 100644
index c8b4b3d..000
--- a/performance-test/download/notmuch-email-corpus-0.2.tar.xz.asc
+++ /dev/null
@@ -1,9 +0,0 @@
--BEGIN PGP SIGNATURE-
-Version: GnuPG v1.4.12 (GNU/Linux)
-
-iJwEAAECAAYFAlCsvx0ACgkQTiiN/0Um85kZAwP9GgOQ22jK8mr5X4pT/mB8EjSH
-QbndlxxbRrP0ChTqjBQoD3IsTHjNL7W572BfXb/MNo94R/iIQ7yTHCDVNuwBhvKd
-7qgIuW2FUS1uTfJRP5KBNf8JPuin+6wqGe8/+y/iOs+XJSdiYg1ElS49Ntnpg0yl
-btImgEcxTxQ2qfzDS1g=
-=iuZR
--END PGP SIGNATURE-
diff --git a/performance-test/download/notmuch-email-corpus-0.3.tar.xz.asc 
b/performance-test/download/notmuch-email-corpus-0.3.tar.xz.asc
new file mode 100644
index 000..f109e81
--- /dev/null
+++ b/performance-test/download/notmuch-email-corpus-0.3.tar.xz.asc
@@ -0,0 +1,9 @@
+-BEGIN PGP SIGNATURE-
+Version: GnuPG v1.4.12 (GNU/Linux)
+
+iJwEAAECAAYFAlC9a90ACgkQTiiN/0Um85nAMAP+LCWdKzolcl/KW+JcCd0Dk+9v
+0vvtBVEhBes0TbK6iWrxCV2OIuYG/RhnFlJTZ4MjgaTRxzDubpC+JktaJdLmIQUN
+B7ZIDMjFduCwmtyLiuu/00CjxJKUXm7vx+ULGpvp0uxFE/vaqGP997BHwBjjfBVm
+YX6BlLX1SV6TfENkuRE=
+=Mks5
+-END PGP SIGNATURE-
diff --git a/performance-test/version.sh b/performance-test/version.sh
index d9270b1..afafc73 100644
--- a/performance-test/version.sh
+++ b/performance-test/version.sh
@@ -1,3 +1,3 @@
 # this should be both a valid Makefile fragment and valid POSIX(ish) shell.

-PERFTEST_VERSION=0.2
+PERFTEST_VERSION=0.3
-- 
1.7.10.4



[PATCH 1/4] perf-test: add corpus size to output, compact I/O stats

2012-12-04 Thread da...@tethera.net
From: David Bremner 

Austin suggested a while ago that the corpus size be printed in the
header. In the end it seems the corpus will be fixed per test script,
so this suggestion indeed makes sense.

The tabbing was wrapping on my usual 80 column terminal, so I joined
the input and output columns together.
---
 performance-test/perf-test-lib.sh |6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/performance-test/perf-test-lib.sh 
b/performance-test/perf-test-lib.sh
index c9b131a..08e2ebd 100644
--- a/performance-test/perf-test-lib.sh
+++ b/performance-test/perf-test-lib.sh
@@ -92,14 +92,14 @@ uncache_database () {
 }

 print_header () {
-printf "[v%4s]   
Wall(s)\tUsr(s)\tSys(s)\tRes(K)\tIn(512B)\tOut(512B)\n" \
-  ${PERFTEST_VERSION}
+printf "[v%4s %6s]Wall(s)\tUsr(s)\tSys(s)\tRes(K)\tIn/Out(512B)\n" 
\
+  ${PERFTEST_VERSION} ${corpus_size}
 }

 time_run () {
 printf "%-22s" "$1"
 if test "$verbose" != "t"; then exec 4>test.output 3>&4; fi
-if ! eval >&3 "/usr/bin/time -f '%e\t%U\t%S\t%M\t%I\t%O' $2" ; then
+if ! eval >&3 "/usr/bin/time -f '%e\t%U\t%S\t%M\t%I/%O' $2" ; then
test_failure=$(($test_failure + 1))
 fi
 }
-- 
1.7.10.4



[PATCH 1/2] cli: fix notmuch top level argument parsing

2012-12-04 Thread Jani Nikula
On Mon, 03 Dec 2012, Michal Nazarewicz  wrote:
> On Mon, Dec 03 2012, Jani Nikula wrote:
>> Use strcmp instead of STRNCMP_LITERAL, which matches the prefix
>> instead of the whole argument.
>
> Perhaps add and use this instead:
>
> #define STRCMP_LITERAL(var, literal) \
> strncmp ((var), (literal), sizeof (literal))

That's broken the same way STRNCMP_LITERAL is broken in this use case:
it matches if literal is a prefix of var.

BR,
Jani.


>
> Than again, it's argument parsing so hardly a performance critical path,
> so maybe readability is more important.
>
>> ---
>>  notmuch.c |4 ++--
>>  1 file changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/notmuch.c b/notmuch.c
>> index 477a09c..4ff66e3 100644
>> --- a/notmuch.c
>> +++ b/notmuch.c
>> @@ -245,10 +245,10 @@ main (int argc, char *argv[])
>>  if (argc == 1)
>>  return notmuch (local);
>>  
>> -if (STRNCMP_LITERAL (argv[1], "--help") == 0)
>> +if (strcmp (argv[1], "--help") == 0)
>>  return notmuch_help_command (NULL, argc - 1, [1]);
>>  
>> -if (STRNCMP_LITERAL (argv[1], "--version") == 0) {
>> +if (strcmp (argv[1], "--version") == 0) {
>>  printf ("notmuch " STRINGIFY(NOTMUCH_VERSION) "\n");
>>  return 0;
>>  }
>
> -- 
> Best regards, _ _
> .o. | Liege of Serenely Enlightened Majesty of  o' \,=./ `o
> ..o | Computer Science,  Micha? ?mina86? Nazarewicz(o o)
> ooo +--ooO--(_)--Ooo--


[RFC PATCH] cli: add --remove-all option to "notmuch tag"

2012-12-04 Thread Jani Nikula
Add --remove-all option to "notmuch tag" to remove all tags matching
query before applying the tag changes. This allows removal 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

---

It's completely untested...

This is on top of David's batch tagging branch new-tagging at
git://pivot.cs.unb.ca/notmuch.git

If there's interest, I'll spin a new version with tests and man page
changes after David's stuff has been merged.
---
 notmuch-tag.c |   32 
 1 file changed, 20 insertions(+), 12 deletions(-)

diff --git a/notmuch-tag.c b/notmuch-tag.c
index e4fca67..67624cc 100644
--- a/notmuch-tag.c
+++ b/notmuch-tag.c
@@ -119,12 +119,15 @@ tag_query (void *ctx, notmuch_database_t *notmuch, const 
char *query_string,
 notmuch_messages_t *messages;
 notmuch_message_t *message;

-/* 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);
@@ -140,7 +143,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);
-   tag_op_list_apply (message, tag_ops, flags | TAG_FLAG_PRE_OPTIMIZED);
+   tag_op_list_apply (message, tag_ops, flags);
notmuch_message_destroy (message);
 }

@@ -157,8 +160,9 @@ notmuch_tag_command (void *ctx, int argc, char *argv[])
 notmuch_config_t *config;
 notmuch_database_t *notmuch;
 struct sigaction action;
-tag_op_flag_t synchronize_flags = TAG_FLAG_NONE;
+tag_op_flag_t flags = TAG_FLAG_NONE;
 notmuch_bool_t batch = FALSE;
+notmuch_bool_t remove_all = FALSE;
 FILE *input = stdin;
 char *input_file_name = NULL;
 int i, opt_index;
@@ -174,6 +178,7 @@ notmuch_tag_command (void *ctx, 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 }
 };

@@ -230,7 +235,7 @@ notmuch_tag_command (void *ctx, int argc, char *argv[])
}
}

-   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;
}
@@ -252,7 +257,10 @@ notmuch_tag_command (void *ctx, int argc, char *argv[])
return 1;

 if (notmuch_config_get_maildir_synchronize_flags (config))
-   synchronize_flags = TAG_FLAG_MAILDIR_SYNC;
+   flags |= TAG_FLAG_MAILDIR_SYNC;
+
+if (remove_all)
+   flags |= TAG_FLAG_REMOVE_ALL;

 if (batch) {

@@ -280,14 +288,14 @@ notmuch_tag_command (void *ctx, int argc, char *argv[])
continue;

if (ret < 0 || tag_query (ctx, notmuch, query_string,
- tag_ops, synchronize_flags))
+ tag_ops, flags))
break;
}

if (line)
free (line);
 } else
-   ret = tag_query (ctx, notmuch, query_string, tag_ops, 
synchronize_flags);
+   ret = tag_query (ctx, notmuch, query_string, tag_ops, flags);

 notmuch_database_destroy (notmuch);

-- 
1.7.10.4



using the List-Post header to reply to mailing lists

2012-12-04 Thread Kushal Kumaran
Hi,

I've been using notmuch with emacs for a while now.  I subscribe to a
few mailing lists where Reply-To-All is severely frowned upon, so I
wanted to be able to use the List-Post header (RFC2369) when replying to
mailing list posts.  I've hacked notmuch-reply.c for my purposes, but I
was wondering how other people manage.

As it stands, this patch is entirely unsuitable for merging.  At least
the following issues will need to be resolved first:

- should an additional command-line option be added to invoke this
  behaviour?  My personal preference is to just use the List-Post header
  whenever possible, if --reply-to=all is not given.

- should anything be done if the List-Post header has a URL which is not
  a mailto: URL (start a web browser?).  None of the mailing lists I'm
  subscribed to puts anything other than mailto.  The patch ignores the
  header if the URL is not a mailto.

- needs tests

- needs documentation

If anyone has alternatives to doing this kind of URL parsing, I'm
interested.  Comments regarding my pathetic knowledge of gmime are also
welcome.  If no one things notmuch needs this functionality, I will just
hold on to it for my personal use.

---
 notmuch-reply.c |   68 ---
 1 file changed, 60 insertions(+), 8 deletions(-)

diff --git a/notmuch-reply.c b/notmuch-reply.c
index e60a264..82f5a35 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -172,6 +172,11 @@ address_is_users (const char *address, notmuch_config_t 
*config)
 return address_match (address, config, STRING_IS_USER_ADDRESS) != NULL;
 }

+typedef enum {
+rfc822,
+url
+} address_format_t;
+
 /* Scan addresses in 'list'.
  *
  * If 'message' is non-NULL, then for each address in 'list' that is
@@ -231,6 +236,37 @@ scan_address_list (InternetAddressList *list,
 return n;
 }

+InternetAddressList *list_post_url_to_address_list(const char *header_value) {
+size_t recipients_len = strlen(header_value);
+size_t list_post_prefix_len = strlen(mailto:;);
+char *list_post_url;
+InternetAddressList *list;
+InternetAddress *list_post_addr;
+
+recipients_len = strlen(header_value);
+
+if (strncmp(header_value, mailto:;, list_post_prefix_len) != 0) {
+   return NULL;
+}
+
+if (header_value[recipients_len - 1] != '') {
+   return NULL;
+}
+
+list_post_url = xstrdup(header_value);
+list_post_url[recipients_len - 1] = '\0';
+list_post_addr = internet_address_mailbox_new(NULL, list_post_url +
+ list_post_prefix_len);
+list = internet_address_list_new();
+if (list == NULL) {
+   return NULL;
+}
+internet_address_list_add(list, list_post_addr);
+free(list_post_url);
+
+return list;
+}
+
 /* Scan addresses in 'recipients'.
  *
  * See the documentation of scan_address_list() above. This function
@@ -242,6 +278,7 @@ scan_address_string (const char *recipients,
 notmuch_config_t *config,
 GMimeMessage *message,
 GMimeRecipientType type,
+address_format_t format,
 const char **user_from)
 {
 InternetAddressList *list;
@@ -249,9 +286,21 @@ scan_address_string (const char *recipients,
 if (recipients == NULL)
return 0;

-list = internet_address_list_parse_string (recipients);
-if (list == NULL)
-   return 0;
+switch (format) {
+case rfc822:
+   list = internet_address_list_parse_string (recipients);
+   if (list == NULL)
+   return 0;
+
+   break;
+
+case url:
+   list = list_post_url_to_address_list (recipients);
+   if (list == NULL)
+   return 0;
+
+   break;
+}

 return scan_address_list (list, config, message, type, user_from);
 }
@@ -317,11 +366,13 @@ add_recipients_from_message (GMimeMessage *reply,
const char *header;
const char *fallback;
GMimeRecipientType recipient_type;
+   address_format_t format;
 } reply_to_map[] = {
-   { reply-to, from, GMIME_RECIPIENT_TYPE_TO  },
-   { to, NULL, GMIME_RECIPIENT_TYPE_TO  },
-   { cc, NULL, GMIME_RECIPIENT_TYPE_CC  },
-   { bcc,NULL, GMIME_RECIPIENT_TYPE_BCC }
+   { list-post,  NULL, GMIME_RECIPIENT_TYPE_TO,  url },
+   { reply-to, from, GMIME_RECIPIENT_TYPE_TO,  rfc822  },
+   { to, NULL, GMIME_RECIPIENT_TYPE_TO,  rfc822  },
+   { cc, NULL, GMIME_RECIPIENT_TYPE_CC,  rfc822  },
+   { bcc,NULL, GMIME_RECIPIENT_TYPE_BCC, rfc822  }
 };
 const char *from_addr = NULL;
 unsigned int i;
@@ -353,7 +404,8 @@ add_recipients_from_message (GMimeMessage *reply,
 reply_to_map[i].fallback);

n += scan_address_string (recipients, config, reply,
- reply_to_map[i].recipient_type, from_addr);
+  

Re: [PATCH] test: fix an evident copy-paste error in argument parsing test

2012-12-04 Thread David Bremner
Jani Nikula j...@nikula.org writes:

 ---
  test/arg-test.c   |2 +-
  test/argument-parsing |2 +-
  2 files changed, 2 insertions(+), 2 deletions(-)

pushed,

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


Re: [PATCH] emacs: drop support for deprecated notmuch-folders

2012-12-04 Thread David Bremner
Jani Nikula j...@nikula.org writes:

 Remove notmuch-folders which has been deprecated since

 commit a4669217600e4536dc0c49f0255af5e2d9bc183f
 Author: Carl Worth cwo...@cworth.org
 Date:   Mon Apr 26 22:42:07 2010 -0700

pushed, 

d

PS: NEWS-worthy?
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH 1/2] cli: fix notmuch top level argument parsing

2012-12-04 Thread David Bremner
Jani Nikula j...@nikula.org writes:

 Use strcmp instead of STRNCMP_LITERAL, which matches the prefix
 instead of the whole argument.

pushed both, 

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


[PATCH 1/1] Fixing failing JSON tests.

2012-12-04 Thread Peter Feigl
Two --format=json tests were failing, both due changes in the output
format introduced by the structured formatting code. This patch updates
the expected output.
---
 test/json | 12 ++--
 1 file changed, 2 insertions(+), 10 deletions(-)

diff --git a/test/json b/test/json
index bfafd55..75b732f 100755
--- a/test/json
+++ b/test/json
@@ -32,7 +32,7 @@ test_expect_equal_json $output [{\thread\: \XXX\,
 test_begin_subtest Show message: json, utf-8
 add_message [subject]=\json-show-utf8-body-sübjéct\ [date]=\Sat, 01 Jan 
2000 12:00:00 -\ [body]=\jsön-show-méssage\
 output=$(notmuch show --format=json jsön-show-méssage)
-test_expect_equal_json $output [[[{\id\: \${gen_msg_id}\, \match\: 
true, \excluded\: false, \filename\: \${gen_msg_filename}\, 
\timestamp\: 946728000, \date_relative\: \2000-01-01\, \tags\: 
[\inbox\,\unread\], \headers\: {\Subject\: 
\json-show-utf8-body-sübjéct\, \From\: \Notmuch Test Suite 
test_su...@notmuchmail.org\, \To\: \Notmuch Test Suite 
test_su...@notmuchmail.org\, \Date\: \Sat, 01 Jan 2000 12:00:00 +\}, 
\body\: [{\id\: 1, \content-type\: \text/plain\, \content\: 
\jsön-show-méssage\n\}]}, [
+test_expect_equal_json $output [[[{\id\: \${gen_msg_id}\, \match\: 
true, \excluded\: false, \filename\: \${gen_msg_filename}\, 
\timestamp\: 946728000, \date_relative\: \2000-01-01\, \tags\: 
[\inbox\, \unread\], \headers\: {\Subject\: 
\json-show-utf8-body-sübjéct\, \From\: \Notmuch Test Suite 
test_su...@notmuchmail.org\, \To\: \Notmuch Test Suite 
test_su...@notmuchmail.org\, \Date\: \Sat, 01 Jan 2000 12:00:00 +\}, 
\body\: [{\id\: 1, \content-type\: \text/plain\, \content\: 
\jsön-show-méssage\n\}]}, [
 
 test_begin_subtest Show message: json, inline attachment filename
 subject='json-show-inline-attachment-filename'
@@ -50,14 +50,6 @@ test_expect_equal_json $output [[[{\id\: \$id\, 
\match\: true, \exclud
 test_begin_subtest Search message: json, utf-8
 add_message [subject]=\json-search-utf8-body-sübjéct\ [date]=\Sat, 01 
Jan 2000 12:00:00 -\ [body]=\jsön-search-méssage\
 output=$(notmuch search --format=json jsön-search-méssage | 
notmuch_search_sanitize)
-test_expect_equal_json $output [{\thread\: \XXX\,
- \timestamp\: 946728000,
- \date_relative\: \2000-01-01\,
- \matched\: 1,
- \total\: 1,
- \authors\: \Notmuch Test Suite\,
- \subject\: \json-search-utf8-body-sübjéct\,
- \tags\: [\inbox\,
- \unread\]}]
+test_expect_equal_json $output [{\thread\: \XXX\, \timestamp\: 
946728000, \date_relative\: \2000-01-01\, \matched\: 1, \total\: 1, 
\authors\: \Notmuch Test Suite\, \subject\: 
\json-search-utf8-body-sübjéct\, \tags\: [\inbox\, \unread\]}]
 
 test_done
-- 
1.8.0

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


[PATCH 1/1] Changing build tool for test/random-corpus to CXX instead of CC.

2012-12-04 Thread Peter Feigl
Without this change, GCC complains as follows:
gcc  test/random-corpus.o test/database-test.o notmuch-config.o 
command-line-arguments.o lib/libnotmuch.a util/libutil.a 
parse-time-string/libparse-time-string.a -o test/random-corpus -lgmime-2.6 
-lgio-2.0 -lgobject-2.0 -lglib-2.0   -Wl,-rpath,/usr/lib -ltalloc   -lxapian
/usr/bin/ld: lib/libnotmuch.a(database.o): undefined reference to symbol 
'_ZNSs4_Rep10_M_destroyERKSaIcE@@GLIBCXX_3.4'
/usr/bin/ld: note: '_ZNSs4_Rep10_M_destroyERKSaIcE@@GLIBCXX_3.4' is defined in 
DSO /usr/lib/libstdc++.so.6 so try adding it to the linker command line
/usr/lib/libstdc++.so.6: could not read symbols: Invalid operation
collect2: error: ld returned 1 exit status
make: *** [test/random-corpus] Error 1
---
 test/Makefile.local | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/Makefile.local b/test/Makefile.local
index 6a9f15e..2ec6595 100644
--- a/test/Makefile.local
+++ b/test/Makefile.local
@@ -22,7 +22,7 @@ random_corpus_deps =  $(dir)/random-corpus.o  
$(dir)/database-test.o \
parse-time-string/libparse-time-string.a
 
 $(dir)/random-corpus: $(random_corpus_deps)
-   $(call quiet,CC) $(CFLAGS_FINAL) $^ -o $@ $(CONFIGURE_LDFLAGS)
+   $(call quiet,CXX) $(CFLAGS_FINAL) $^ -o $@ $(CONFIGURE_LDFLAGS)
 
 $(dir)/smtp-dummy: $(smtp_dummy_modules)
$(call quiet,CC) $^ -o $@
-- 
1.8.0

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


Re: [PATCH 1/2] cli: fix notmuch top level argument parsing

2012-12-04 Thread Michal Nazarewicz
On Mon, Dec 03 2012, Jani Nikula wrote:
 And I'm not even sure strncmp is faster than strcmp, as it has to keep
 track of count.

Good point.

-- 
Best regards, _ _
.o. | Liege of Serenely Enlightened Majesty of  o' \,=./ `o
..o | Computer Science,  Michał “mina86” Nazarewicz(o o)
ooo +email/xmpp: m...@google.com--ooO--(_)--Ooo--

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


[PATCH] Adding parse-time to test/.gitignore

2012-12-04 Thread Peter Feigl
test/parse-time is a binary that is generated when running make test. It should 
be ignored by git.
---
 test/.gitignore | 1 +
 1 file changed, 1 insertion(+)

diff --git a/test/.gitignore b/test/.gitignore
index 1eff7ce..97e0248 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -5,4 +5,5 @@ symbol-test
 arg-test
 hex-xcode
 random-corpus
+parse-time
 tmp.*
-- 
1.8.0

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


Re: [PATCH 1/1] Fixing failing JSON tests.

2012-12-04 Thread Austin Clements
I must be missing something...  These both look like whitespace-only
changes, which test_expect_equal_json normalizes.  Did you change
something else, too?

Quoth Peter Feigl on Dec 04 at  2:46 pm:
 Two --format=json tests were failing, both due changes in the output
 format introduced by the structured formatting code. This patch updates
 the expected output.
 ---
  test/json | 12 ++--
  1 file changed, 2 insertions(+), 10 deletions(-)
 
 diff --git a/test/json b/test/json
 index bfafd55..75b732f 100755
 --- a/test/json
 +++ b/test/json
 @@ -32,7 +32,7 @@ test_expect_equal_json $output [{\thread\: \XXX\,
  test_begin_subtest Show message: json, utf-8
  add_message [subject]=\json-show-utf8-body-sübjéct\ [date]=\Sat, 01 
 Jan 2000 12:00:00 -\ [body]=\jsön-show-méssage\
  output=$(notmuch show --format=json jsön-show-méssage)
 -test_expect_equal_json $output [[[{\id\: \${gen_msg_id}\, \match\: 
 true, \excluded\: false, \filename\: \${gen_msg_filename}\, 
 \timestamp\: 946728000, \date_relative\: \2000-01-01\, \tags\: 
 [\inbox\,\unread\], \headers\: {\Subject\: 
 \json-show-utf8-body-sübjéct\, \From\: \Notmuch Test Suite 
 test_su...@notmuchmail.org\, \To\: \Notmuch Test Suite 
 test_su...@notmuchmail.org\, \Date\: \Sat, 01 Jan 2000 12:00:00 
 +\}, \body\: [{\id\: 1, \content-type\: \text/plain\, 
 \content\: \jsön-show-méssage\n\}]}, [
 +test_expect_equal_json $output [[[{\id\: \${gen_msg_id}\, \match\: 
 true, \excluded\: false, \filename\: \${gen_msg_filename}\, 
 \timestamp\: 946728000, \date_relative\: \2000-01-01\, \tags\: 
 [\inbox\, \unread\], \headers\: {\Subject\: 
 \json-show-utf8-body-sübjéct\, \From\: \Notmuch Test Suite 
 test_su...@notmuchmail.org\, \To\: \Notmuch Test Suite 
 test_su...@notmuchmail.org\, \Date\: \Sat, 01 Jan 2000 12:00:00 
 +\}, \body\: [{\id\: 1, \content-type\: \text/plain\, 
 \content\: \jsön-show-méssage\n\}]}, [
  
  test_begin_subtest Show message: json, inline attachment filename
  subject='json-show-inline-attachment-filename'
 @@ -50,14 +50,6 @@ test_expect_equal_json $output [[[{\id\: \$id\, 
 \match\: true, \exclud
  test_begin_subtest Search message: json, utf-8
  add_message [subject]=\json-search-utf8-body-sübjéct\ [date]=\Sat, 01 
 Jan 2000 12:00:00 -\ [body]=\jsön-search-méssage\
  output=$(notmuch search --format=json jsön-search-méssage | 
 notmuch_search_sanitize)
 -test_expect_equal_json $output [{\thread\: \XXX\,
 - \timestamp\: 946728000,
 - \date_relative\: \2000-01-01\,
 - \matched\: 1,
 - \total\: 1,
 - \authors\: \Notmuch Test Suite\,
 - \subject\: \json-search-utf8-body-sübjéct\,
 - \tags\: [\inbox\,
 - \unread\]}]
 +test_expect_equal_json $output [{\thread\: \XXX\, \timestamp\: 
 946728000, \date_relative\: \2000-01-01\, \matched\: 1, \total\: 1, 
 \authors\: \Notmuch Test Suite\, \subject\: 
 \json-search-utf8-body-sübjéct\, \tags\: [\inbox\, \unread\]}]
  
  test_done
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH 1/1] Changing build tool for test/random-corpus to CXX instead of CC.

2012-12-04 Thread Austin Clements
LGTM.  I think we build the main notmuch binary with g++ for the same
reason.

Quoth Peter Feigl on Dec 04 at  2:47 pm:
 Without this change, GCC complains as follows:
 gcc  test/random-corpus.o test/database-test.o notmuch-config.o 
 command-line-arguments.o lib/libnotmuch.a util/libutil.a 
 parse-time-string/libparse-time-string.a -o test/random-corpus -lgmime-2.6 
 -lgio-2.0 -lgobject-2.0 -lglib-2.0   -Wl,-rpath,/usr/lib -ltalloc   -lxapian
 /usr/bin/ld: lib/libnotmuch.a(database.o): undefined reference to symbol 
 '_ZNSs4_Rep10_M_destroyERKSaIcE@@GLIBCXX_3.4'
 /usr/bin/ld: note: '_ZNSs4_Rep10_M_destroyERKSaIcE@@GLIBCXX_3.4' is defined 
 in DSO /usr/lib/libstdc++.so.6 so try adding it to the linker command line
 /usr/lib/libstdc++.so.6: could not read symbols: Invalid operation
 collect2: error: ld returned 1 exit status
 make: *** [test/random-corpus] Error 1
 ---
  test/Makefile.local | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)
 
 diff --git a/test/Makefile.local b/test/Makefile.local
 index 6a9f15e..2ec6595 100644
 --- a/test/Makefile.local
 +++ b/test/Makefile.local
 @@ -22,7 +22,7 @@ random_corpus_deps =  $(dir)/random-corpus.o  
 $(dir)/database-test.o \
   parse-time-string/libparse-time-string.a
  
  $(dir)/random-corpus: $(random_corpus_deps)
 - $(call quiet,CC) $(CFLAGS_FINAL) $^ -o $@ $(CONFIGURE_LDFLAGS)
 + $(call quiet,CXX) $(CFLAGS_FINAL) $^ -o $@ $(CONFIGURE_LDFLAGS)
  
  $(dir)/smtp-dummy: $(smtp_dummy_modules)
   $(call quiet,CC) $^ -o $@
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH 1/1] Fixing failing JSON tests.

2012-12-04 Thread Peter Feigl
On Tue, 4 Dec 2012 09:35:41 -0500, Austin Clements amdra...@mit.edu wrote:
 I must be missing something...  These both look like whitespace-only
 changes, which test_expect_equal_json normalizes.  Did you change
 something else, too?

They are, bremner on IRC was so kind to point out that my using Python
3.3 may be connected to the problem. I'll investigate further on why
exactly I get this behaviour.
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH v2 0/5] New output format sexp (Lisp S-Expressions)

2012-12-04 Thread Peter Feigl
This patch series adds a new output format sexp to notmuch-reply,
notmuch-show and notmuch-search. These are useful for the Android mobile
client and perhaps other Lisp programs as well.
After the switch to a generic structured output printer, which was
committed some months ago, these patches just add another one (like the
json structured output printer).
Basic tests and updates to the man pages are also included.


Peter Feigl (5):
  Adding an S-expression structured output printer.
  Rename the -json printer functions in notmuch-reply and
notmuch-show to generic -sprinter functions.
  Use the S-Expression structured printer in notmuch-show,
notmuch-reply and notmuch-search.
  Adding tests for --format=sexp.
  Updating man pages for new S-Expression output format.

 Makefile.local|   1 +
 man/man1/notmuch-reply.1  |  14 ++-
 man/man1/notmuch-search.1 |  15 +--
 man/man1/notmuch-show.1   |  36 +--
 notmuch-client.h  |   8 +-
 notmuch-reply.c   |  43 
 notmuch-search.c  |   6 +-
 notmuch-show.c|  48 +
 sprinter-sexp.c   | 250 ++
 sprinter.h|   4 +
 test/notmuch-test |   1 +
 test/sexp |  48 +
 12 files changed, 414 insertions(+), 60 deletions(-)
 create mode 100644 sprinter-sexp.c
 create mode 100755 test/sexp

-- 
1.8.0

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


[PATCH v2 2/5] Rename the -json printer functions in notmuch-reply and notmuch-show to generic -sprinter functions.

2012-12-04 Thread Peter Feigl
All the structured output functions in notmuch-reply and notmuch-show
are renamed to a generic name (as they do not contain any json-specific
code anyway). This patch is a preparation to actually using the new
S-Expression sprinter in notmuch-reply and notmuch-show.
---
 notmuch-client.h |  8 
 notmuch-reply.c  | 38 +-
 notmuch-show.c   | 30 +++---
 3 files changed, 40 insertions(+), 36 deletions(-)

diff --git a/notmuch-client.h b/notmuch-client.h
index ae9344b..1c336dc 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -175,12 +175,12 @@ notmuch_status_t
 show_one_part (const char *filename, int part);
 
 void
-format_part_json (const void *ctx, struct sprinter *sp, mime_node_t *node,
- notmuch_bool_t first, notmuch_bool_t output_body);
+format_part_sprinter (const void *ctx, struct sprinter *sp, mime_node_t *node,
+ notmuch_bool_t first, notmuch_bool_t output_body);
 
 void
-format_headers_json (struct sprinter *sp, GMimeMessage *message,
-notmuch_bool_t reply);
+format_headers_sprinter (struct sprinter *sp, GMimeMessage *message,
+notmuch_bool_t reply);
 
 typedef enum {
 NOTMUCH_SHOW_TEXT_PART_REPLY = 1  0,
diff --git a/notmuch-reply.c b/notmuch-reply.c
index e60a264..53aefa7 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -548,7 +548,8 @@ notmuch_reply_format_default(void *ctx,
 notmuch_config_t *config,
 notmuch_query_t *query,
 notmuch_show_params_t *params,
-notmuch_bool_t reply_all)
+notmuch_bool_t reply_all,
+unused (sprinter_t *sp))
 {
 GMimeMessage *reply;
 notmuch_messages_t *messages;
@@ -587,17 +588,17 @@ notmuch_reply_format_default(void *ctx,
 }
 
 static int
-notmuch_reply_format_json(void *ctx,
- notmuch_config_t *config,
- notmuch_query_t *query,
- notmuch_show_params_t *params,
- notmuch_bool_t reply_all)
+notmuch_reply_format_sprinter(void *ctx,
+ notmuch_config_t *config,
+ notmuch_query_t *query,
+ notmuch_show_params_t *params,
+ notmuch_bool_t reply_all,
+ sprinter_t *sp)
 {
 GMimeMessage *reply;
 notmuch_messages_t *messages;
 notmuch_message_t *message;
 mime_node_t *node;
-sprinter_t *sp;
 
 if (notmuch_query_count_messages (query) != 1) {
fprintf (stderr, Error: search term did not match precisely one 
message.\n);
@@ -613,18 +614,17 @@ notmuch_reply_format_json(void *ctx,
 if (!reply)
return 1;
 
-sp = sprinter_json_create (ctx, stdout);
 sp-begin_map (sp);
 
 /* The headers of the reply message we've created */
 sp-map_key (sp, reply-headers);
-format_headers_json (sp, reply, TRUE);
+format_headers_sprinter (sp, reply, TRUE);
 g_object_unref (G_OBJECT (reply));
 reply = NULL;
 
 /* Start the original */
 sp-map_key (sp, original);
-format_part_json (ctx, sp, node, TRUE, TRUE);
+format_part_sprinter (ctx, sp, node, TRUE, TRUE);
 
 /* End */
 sp-end (sp);
@@ -639,7 +639,8 @@ notmuch_reply_format_headers_only(void *ctx,
  notmuch_config_t *config,
  notmuch_query_t *query,
  unused (notmuch_show_params_t *params),
- notmuch_bool_t reply_all)
+ notmuch_bool_t reply_all,
+ unused (sprinter_t *sp))
 {
 GMimeMessage *reply;
 notmuch_messages_t *messages;
@@ -707,7 +708,7 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
 notmuch_query_t *query;
 char *query_string;
 int opt_index, ret = 0;
-int (*reply_format_func)(void *ctx, notmuch_config_t *config, 
notmuch_query_t *query, notmuch_show_params_t *params, notmuch_bool_t 
reply_all);
+int (*reply_format_func)(void *ctx, notmuch_config_t *config, 
notmuch_query_t *query, notmuch_show_params_t *params, notmuch_bool_t 
reply_all, struct sprinter *sp);
 notmuch_show_params_t params = {
.part = -1,
.crypto = {
@@ -717,6 +718,7 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
 };
 int format = FORMAT_DEFAULT;
 int reply_all = TRUE;
+struct sprinter *sp = NULL;
 
 notmuch_opt_desc_t options[] = {
{ NOTMUCH_OPT_KEYWORD, format, format, 'f',
@@ -738,12 +740,14 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
return 1;
 }
 
-if (format == FORMAT_HEADERS_ONLY)
+if (format == FORMAT_HEADERS_ONLY) {
reply_format_func = notmuch_reply_format_headers_only;
-  

[PATCH v2 3/5] Use the S-Expression structured printer in notmuch-show, notmuch-reply and notmuch-search.

2012-12-04 Thread Peter Feigl
This patch uses the new S-Expression printer in the notmuch CLI (show,
search and reply). You can now use --format=sexp for any of them.
---
 notmuch-reply.c  |  5 +
 notmuch-search.c |  6 +-
 notmuch-show.c   | 18 ++
 3 files changed, 24 insertions(+), 5 deletions(-)

diff --git a/notmuch-reply.c b/notmuch-reply.c
index 53aefa7..69fd256 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -697,6 +697,7 @@ notmuch_reply_format_headers_only(void *ctx,
 enum {
 FORMAT_DEFAULT,
 FORMAT_JSON,
+FORMAT_SEXP,
 FORMAT_HEADERS_ONLY,
 };
 
@@ -724,6 +725,7 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
{ NOTMUCH_OPT_KEYWORD, format, format, 'f',
  (notmuch_keyword_t []){ { default, FORMAT_DEFAULT },
  { json, FORMAT_JSON },
+ { sexp, FORMAT_SEXP },
  { headers-only, FORMAT_HEADERS_ONLY },
  { 0, 0 } } },
{ NOTMUCH_OPT_KEYWORD, reply_all, reply-to, 'r',
@@ -745,6 +747,9 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
 } else if (format == FORMAT_JSON) {
reply_format_func = notmuch_reply_format_sprinter;
sp = sprinter_json_create (ctx, stdout);
+} else if (format == FORMAT_SEXP) {
+   reply_format_func = notmuch_reply_format_sprinter;
+   sp = sprinter_sexp_create (ctx, stdout);
 } else {
reply_format_func = notmuch_reply_format_default;
 }
diff --git a/notmuch-search.c b/notmuch-search.c
index 830c4e4..6218622 100644
--- a/notmuch-search.c
+++ b/notmuch-search.c
@@ -305,7 +305,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
 int exclude = EXCLUDE_TRUE;
 unsigned int i;
 
-enum { NOTMUCH_FORMAT_JSON, NOTMUCH_FORMAT_TEXT }
+enum { NOTMUCH_FORMAT_JSON, NOTMUCH_FORMAT_TEXT, NOTMUCH_FORMAT_SEXP }
format_sel = NOTMUCH_FORMAT_TEXT;
 
 notmuch_opt_desc_t options[] = {
@@ -315,6 +315,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
  { 0, 0 } } },
{ NOTMUCH_OPT_KEYWORD, format_sel, format, 'f',
  (notmuch_keyword_t []){ { json, NOTMUCH_FORMAT_JSON },
+ { sexp, NOTMUCH_FORMAT_SEXP },
  { text, NOTMUCH_FORMAT_TEXT },
  { 0, 0 } } },
{ NOTMUCH_OPT_KEYWORD, output, output, 'o',
@@ -347,6 +348,9 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
 case NOTMUCH_FORMAT_JSON:
format = sprinter_json_create (ctx, stdout);
break;
+case NOTMUCH_FORMAT_SEXP:
+   format = sprinter_sexp_create (ctx, stdout);
+   break;
 default:
/* this should never happen */
INTERNAL_ERROR(no output format selected);
diff --git a/notmuch-show.c b/notmuch-show.c
index 38c621f..d4860f1 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -40,6 +40,11 @@ static const notmuch_show_format_t format_json = {
 .part = format_part_sprinter_entry,
 };
 
+static const notmuch_show_format_t format_sexp = {
+.new_sprinter = sprinter_sexp_create,
+.part = format_part_sprinter_entry,
+};
+
 static notmuch_status_t
 format_part_mbox (const void *ctx, sprinter_t *sp, mime_node_t *node,
  int indent, const notmuch_show_params_t *params);
@@ -110,7 +115,7 @@ _get_one_line_summary (const void *ctx, notmuch_message_t 
*message)
 static void
 format_message_sprinter (sprinter_t *sp, notmuch_message_t *message)
 {
-/* Any changes to the JSON format should be reflected in the file
+/* Any changes to the JSON or S-Expression format should be reflected in 
the file
  * devel/schemata. */
 
 void *local = talloc_new (NULL);
@@ -1012,6 +1017,7 @@ do_show (void *ctx,
 enum {
 NOTMUCH_FORMAT_NOT_SPECIFIED,
 NOTMUCH_FORMAT_JSON,
+NOTMUCH_FORMAT_SEXP,
 NOTMUCH_FORMAT_TEXT,
 NOTMUCH_FORMAT_MBOX,
 NOTMUCH_FORMAT_RAW
@@ -1056,6 +1062,7 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
{ NOTMUCH_OPT_KEYWORD, format_sel, format, 'f',
  (notmuch_keyword_t []){ { json, NOTMUCH_FORMAT_JSON },
  { text, NOTMUCH_FORMAT_TEXT },
+ { sexp, NOTMUCH_FORMAT_SEXP },
  { mbox, NOTMUCH_FORMAT_MBOX },
  { raw, NOTMUCH_FORMAT_RAW },
  { 0, 0 } } },
@@ -1100,6 +1107,9 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
 case NOTMUCH_FORMAT_TEXT:
format = format_text;
break;
+case NOTMUCH_FORMAT_SEXP:
+   format = format_sexp;
+   break;
 case NOTMUCH_FORMAT_MBOX:
if (params.part  0) {
fprintf (stderr, Error: specifying parts is incompatible with mbox 
output format.\n);
@@ -1120,7 +1130,7 @@ notmuch_show_command (void *ctx, 

[PATCH v2 1/5] Adding an S-expression structured output printer.

2012-12-04 Thread Peter Feigl
This commit adds a structured output printer for Lisp
S-Expressions. Later commits will use this printer in notmuch search,
show and reply.

The structure is the same as json, but:
- arrays are written as lists: (foo bar baaz 1 2 3)
- maps are written as a-lists: ((key value) (other-key other-value))
- true is written as t
- false is written as nil
- null is written as nil
---
 Makefile.local  |   1 +
 sprinter-sexp.c | 250 
 sprinter.h  |   4 +
 3 files changed, 255 insertions(+)
 create mode 100644 sprinter-sexp.c

diff --git a/Makefile.local b/Makefile.local
index 2b91946..0db1713 100644
--- a/Makefile.local
+++ b/Makefile.local
@@ -270,6 +270,7 @@ notmuch_client_srcs =   \
notmuch-tag.c   \
notmuch-time.c  \
sprinter-json.c \
+   sprinter-sexp.c \
sprinter-text.c \
query-string.c  \
mime-node.c \
diff --git a/sprinter-sexp.c b/sprinter-sexp.c
new file mode 100644
index 000..6d6bbad
--- /dev/null
+++ b/sprinter-sexp.c
@@ -0,0 +1,250 @@
+/* notmuch - Not much of an email program, (just index and search)
+ *
+ * Copyright © 2012 Carl Worth
+ *
+ * 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/ .
+ *
+ * Author: Carl Worth cwo...@cworth.org
+ */
+
+#include stdbool.h
+#include stdio.h
+#include talloc.h
+#include sprinter.h
+
+struct sprinter_sexp {
+struct sprinter vtable;
+FILE *stream;
+/* Top of the state stack, or NULL if the printer is not currently
+ * inside any aggregate types. */
+struct sexp_state *state;
+
+/* A flag to signify that a separator should be inserted in the
+ * output as soon as possible.
+ */
+notmuch_bool_t insert_separator;
+};
+
+struct sexp_state {
+struct sexp_state *parent;
+
+/* True if nothing has been printed in this aggregate yet.
+ * Suppresses the space before a value. */
+notmuch_bool_t first;
+
+/* True if the state is a map state.
+ * Used to add a space between key/value pairs. */
+notmuch_bool_t in_map;
+
+/* The character that closes the current aggregate. */
+char close;
+};
+
+/* Helper function to set up the stream to print a value.  If this
+ * value follows another value, prints a space. */
+static struct sprinter_sexp *
+sexp_begin_value (struct sprinter *sp)
+{
+struct sprinter_sexp *sps = (struct sprinter_sexp *) sp;
+
+if (sps-state) {
+   if (! sps-state-first) {
+   if (sps-insert_separator) {
+   fputc ('\n', sps-stream);
+   sps-insert_separator = FALSE;
+   } else {
+   if (! sps-state-in_map)
+   fputc (' ', sps-stream);
+   }
+   } else {
+   sps-state-first = FALSE;
+   }
+}
+return sps;
+}
+
+/* Helper function to begin an aggregate type.  Prints the open
+ * character and pushes a new state frame. */
+static void
+sexp_begin_aggregate (struct sprinter *sp, char open, char close)
+{
+struct sprinter_sexp *sps = sexp_begin_value (sp);
+struct sexp_state *state = talloc (sps, struct sexp_state);
+fputc (open, sps-stream);
+state-parent = sps-state;
+state-first = TRUE;
+state-in_map = FALSE;
+state-close = close;
+sps-state = state;
+}
+
+static void
+sexp_begin_map (struct sprinter *sp)
+{
+struct sprinter_sexp *sps = (struct sprinter_sexp *) sp;
+sexp_begin_aggregate (sp, '(', ')');
+sps-state-in_map = TRUE;
+}
+
+static void
+sexp_begin_list (struct sprinter *sp)
+{
+sexp_begin_aggregate (sp, '(', ')');
+}
+
+static void
+sexp_end (struct sprinter *sp)
+{
+struct sprinter_sexp *sps = (struct sprinter_sexp *) sp;
+struct sexp_state *state = sps-state;
+
+if (sps-state-in_map)
+   fputc (')', sps-stream);
+fputc (sps-state-close, sps-stream);
+sps-state = state-parent;
+talloc_free (state);
+if (sps-state == NULL)
+   fputc ('\n', sps-stream);
+}
+
+static void
+sexp_string_len_internal (struct sprinter *sp, const char *val, size_t len, 
notmuch_bool_t quote)
+{
+static const char *const escapes[] = {
+   ['\'] = \\\, ['\\'] = , ['\b'] = \\b,
+   ['\f'] = \\f,  ['\n'] = \\n,  ['\t'] = \\t
+};
+struct sprinter_sexp *sps = sexp_begin_value (sp);
+
+if(quote)
+   fputc ('', 

[PATCH v2 5/5] Updating man pages for new S-Expression output format.

2012-12-04 Thread Peter Feigl
Add sections about the new S-Expression output format (--format=sexp) to
the notmuch-search, notmuch-reply and notmuch-show man pages.
---
 man/man1/notmuch-reply.1  | 14 ++
 man/man1/notmuch-search.1 | 15 ---
 man/man1/notmuch-show.1   | 36 
 3 files changed, 46 insertions(+), 19 deletions(-)

diff --git a/man/man1/notmuch-reply.1 b/man/man1/notmuch-reply.1
index d264060..8ee1805 100644
--- a/man/man1/notmuch-reply.1
+++ b/man/man1/notmuch-reply.1
@@ -37,7 +37,7 @@ Supported options for
 include
 .RS
 .TP 4
-.BR \-\-format= ( default | json | headers\-only )
+.BR \-\-format= ( default | json | sexp | headers\-only )
 .RS
 .TP 4
 .BR default
@@ -48,6 +48,11 @@ Produces JSON output containing headers for a reply message 
and the
 contents of the original message. This output can be used by a client
 to create a reply message intelligently.
 .TP
+.BR sexp
+Produces S-Expression output containing headers for a reply message and 
+the contents of the original message. This output can be used by a client
+to create a reply message intelligently.
+.TP
 .BR headers\-only
 Only produces In\-Reply\-To, References, To, Cc, and Bcc headers.
 .RE
@@ -74,8 +79,8 @@ user's addresses.
 
 Decrypt any MIME encrypted parts found in the selected content
 (ie. multipart/encrypted parts). Status of the decryption will be
-reported (currently only supported with --format=json) and the
-multipart/encrypted part will be replaced by the decrypted
+reported (currently only supported with --format=json and --format=sexp)
+and the multipart/encrypted part will be replaced by the decrypted
 content.
 .RE
 
@@ -89,7 +94,8 @@ id:message-id), but it can be useful to reply to several 
messages at
 once. For example, when a series of patches are sent in a single
 thread, replying to the entire thread allows for the reply to comment
 on issues found in multiple patches. The default format supports
-replying to multiple messages at once, but the JSON format does not.
+replying to multiple messages at once, but the JSON and S-Expression 
+format does not.
 .RE
 .RE
 
diff --git a/man/man1/notmuch-search.1 b/man/man1/notmuch-search.1
index 6ccd3b8..498232d 100644
--- a/man/man1/notmuch-search.1
+++ b/man/man1/notmuch-search.1
@@ -25,9 +25,9 @@ Supported options for
 include
 .RS 4
 .TP 4
-.BR \-\-format= ( json | text )
+.BR \-\-format= ( json | sexp | text )
 
-Presents the results in either JSON or plain-text (default).
+Presents the results in either JSON, S-Expressions or plain-text (default).
 .RE
 
 .RS 4
@@ -49,7 +49,7 @@ the authors of the thread and the subject.
 
 Output the thread IDs of all threads with any message matching the
 search terms, either one per line (\-\-format=text) or as a JSON array
-(\-\-format=json).
+(\-\-format=json) or an S-Expression list (\-\-format=sexp).
 .RE
 .RS 4
 .TP 4
@@ -57,22 +57,23 @@ search terms, either one per line (\-\-format=text) or as a 
JSON array
 
 Output the message IDs of all messages matching the search terms,
 either one per line (\-\-format=text) or as a JSON array
-(\-\-format=json).
+(\-\-format=json) or as an S-Expression list (\-\-format=sexp).
 .RE
 .RS 4
 .TP 4
 .B files
 
 Output the filenames of all messages matching the search terms, either
-one per line (\-\-format=text) or as a JSON array (\-\-format=json).
+one per line (\-\-format=text) or as a JSON array (\-\-format=json) or 
+as an S-Expression list (\-\-format=sexp).
 .RE
 .RS 4
 .TP 4
 .B tags
 
 Output all tags that appear on any message matching the search terms,
-either one per line (\-\-format=text) or as a JSON array
-(\-\-format=json).
+either one per line (\-\-format=text) or as a JSON array (\-\-format=json) 
+or as an S-Expression list (\-\-format=sexp).
 .RE
 .RE
 
diff --git a/man/man1/notmuch-show.1 b/man/man1/notmuch-show.1
index 4481f21..25b5bb8 100644
--- a/man/man1/notmuch-show.1
+++ b/man/man1/notmuch-show.1
@@ -31,12 +31,14 @@ If true,
 outputs all messages in the thread of any message matching the search
 terms; if false, it outputs only the matching messages. For
 .B --format=json
+and
+.B --format=sexp
 this defaults to true.  For other formats, this defaults to false.
 .RE
 
 .RS 4
 .TP 4
-.B \-\-format=(text|json|mbox|raw)
+.B \-\-format=(text|json|sexp|mbox|raw)
 
 .RS 4
 .TP 4
@@ -60,11 +62,29 @@ format is more robust than the text format for automated
 processing. The nested structure of multipart MIME messages is
 reflected in nested JSON output. By default JSON output includes all
 messages in a matching thread; that is, by default,
+
 .B \-\-format=json
 sets
 .B \-\-entire\-thread
 The caller can disable this behaviour by setting
 .B \-\-entire\-thread=false
+.RE
+.RS 4
+.TP 4
+.B sexp
+
+The output is formatted as an S-Expression (sexp). This
+format is more robust than the text format for automated
+processing. The nested structure of multipart MIME messages is
+reflected in nested S-Expression output. By default, 

[PATCH v2 4/5] Adding tests for --format=sexp.

2012-12-04 Thread Peter Feigl
Add basic tests, the same as for json, for the S-Expression output
format.
---
 test/notmuch-test |  1 +
 test/sexp | 48 
 2 files changed, 49 insertions(+)
 create mode 100755 test/sexp

diff --git a/test/notmuch-test b/test/notmuch-test
index a6ef34f..ca9c3dc 100755
--- a/test/notmuch-test
+++ b/test/notmuch-test
@@ -31,6 +31,7 @@ TESTS=
   excludes
   tagging
   json
+  sexp
   text
   multipart
   thread-naming
diff --git a/test/sexp b/test/sexp
new file mode 100755
index 000..fdc9de6
--- /dev/null
+++ b/test/sexp
@@ -0,0 +1,48 @@
+#!/usr/bin/env bash
+test_description=--format=sexp output
+. ./test-lib.sh
+
+test_begin_subtest Show message: sexp
+add_message [subject]=\sexp-show-subject\ [date]=\Sat, 01 Jan 2000 
12:00:00 -\ [bcc]=\test_suite+...@notmuchmail.org\ 
[reply-to]=\test_suite+repl...@notmuchmail.org\ 
[body]=\sexp-show-message\
+output=$(notmuch show --format=sexp sexp-show-message)
+test_expect_equal $output (id \msg-001@notmuch-test-suite\) (match t) 
(excluded nil) (filename \/home/nex/notmuch-sexp/test/tmp.sexp/mail/msg-001\) 
(timestamp 946728000) (date_relative \2000-01-01\) (tags (\inbox\ 
\unread\)) (headers ((Subject \sexp-show-subject\) (From \Notmuch Test 
Suite test_su...@notmuchmail.org\) (To \Notmuch Test Suite 
test_su...@notmuchmail.org\) (Bcc \test_suite+...@notmuchmail.org\) 
(Reply-To \test_suite+repl...@notmuchmail.org\) (Date \Sat, 01 Jan 2000 
12:00:00 +\))) (body (((id 1) (content-type \text/plain\) (content 
\sexp-show-message\n\) (
+
+# This should be the same output as above.
+test_begin_subtest Show message: sexp --body=true
+output=$(notmuch show --format=sexp --body=true sexp-show-message)
+test_expect_equal $output (id \msg-001@notmuch-test-suite\) (match t) 
(excluded nil) (filename \/home/nex/notmuch-sexp/test/tmp.sexp/mail/msg-001\) 
(timestamp 946728000) (date_relative \2000-01-01\) (tags (\inbox\ 
\unread\)) (headers ((Subject \sexp-show-subject\) (From \Notmuch Test 
Suite test_su...@notmuchmail.org\) (To \Notmuch Test Suite 
test_su...@notmuchmail.org\) (Bcc \test_suite+...@notmuchmail.org\) 
(Reply-To \test_suite+repl...@notmuchmail.org\) (Date \Sat, 01 Jan 2000 
12:00:00 +\))) (body (((id 1) (content-type \text/plain\) (content 
\sexp-show-message\n\) (
+
+test_begin_subtest Show message: sexp --body=false
+output=$(notmuch show --format=sexp --body=false sexp-show-message)
+test_expect_equal $output (id \msg-001@notmuch-test-suite\) (match t) 
(excluded nil) (filename \/home/nex/notmuch-sexp/test/tmp.sexp/mail/msg-001\) 
(timestamp 946728000) (date_relative \2000-01-01\) (tags (\inbox\ 
\unread\)) (headers ((Subject \sexp-show-subject\) (From \Notmuch Test 
Suite test_su...@notmuchmail.org\) (To \Notmuch Test Suite 
test_su...@notmuchmail.org\) (Bcc \test_suite+...@notmuchmail.org\) 
(Reply-To \test_suite+repl...@notmuchmail.org\) (Date \Sat, 01 Jan 2000 
12:00:00 +\ (
+
+test_begin_subtest Search message: sexp
+add_message [subject]=\sexp-search-subject\ [date]=\Sat, 01 Jan 2000 
12:00:00 -\ [body]=\sexp-search-message\
+output=$(notmuch search --format=sexp sexp-search-message | 
notmuch_search_sanitize)
+test_expect_equal $output (((thread \0002\) (timestamp 
946728000) (date_relative \2000-01-01\) (matched 1) (total 1) (authors 
\Notmuch Test Suite\) (subject \sexp-search-subject\) (tags (\inbox\ 
\unread\
+
+test_begin_subtest Show message: sexp, utf-8
+add_message [subject]=\sexp-show-utf8-body-sübjéct\ [date]=\Sat, 01 Jan 
2000 12:00:00 -\ [body]=\jsön-show-méssage\
+output=$(notmuch show --format=sexp jsön-show-méssage)
+test_expect_equal $output (id \msg-003@notmuch-test-suite\) (match t) 
(excluded nil) (filename \/home/nex/notmuch-sexp/test/tmp.sexp/mail/msg-003\) 
(timestamp 946728000) (date_relative \2000-01-01\) (tags (\inbox\ 
\unread\)) (headers ((Subject \sexp-show-utf8-body-sübjéct\) (From 
\Notmuch Test Suite test_su...@notmuchmail.org\) (To \Notmuch Test Suite 
test_su...@notmuchmail.org\) (Date \Sat, 01 Jan 2000 12:00:00 +\))) 
(body (((id 1) (content-type \text/plain\) (content 
\jsön-show-méssage\n\) (
+
+test_begin_subtest Show message: sexp, inline attachment filename
+subject='sexp-show-inline-attachment-filename'
+id=sexp-show-inline-attachment-filen...@notmuchmail.org
+emacs_deliver_message \
+$subject \
+'This is a test message with inline attachment with a filename' \
+(mml-attach-file \$TEST_DIRECTORY/README\ nil nil \inline\)
+ (message-goto-eoh)
+ (insert \Message-ID: $id\n\)
+output=$(notmuch show --format=sexp id:$id)
+filename=$(notmuch search --output=files id:$id)
+test_expect_equal $output (id 
\sexp-show-inline-attachment-filen...@notmuchmail.org\) (match t) (excluded 
nil) (filename \$filename\) (timestamp 946728000) (date_relative 
\2000-01-01\) (tags (\inbox\)) (headers ((Subject 
\sexp-show-inline-attachment-filename\) (From \Notmuch 

[PATCH] NEWS: removal of notmuch-folders

2012-12-04 Thread Jani Nikula
---
 NEWS |   10 ++
 1 file changed, 10 insertions(+)

diff --git a/NEWS b/NEWS
index dadf92a..34e7a28 100644
--- a/NEWS
+++ b/NEWS
@@ -18,6 +18,16 @@ Bcc and Reply-To headers are now available in notmuch show 
json output
   For example notmuch Emacs client can now have these headers visible
   when the headers are added to the `notmuch-message-headers` variable.
 
+Emacs Interface
+---
+
+Removal of the deprecated `notmuch-folders` variable
+
+  `notmuch-folders` has been deprecated since the introduction of saved
+  searches and the notmuch hello view in notmuch 0.3. `notmuch-folders`
+  has now been removed. Any remaining users should migrate to
+  `notmuch-saved-searches`.
+
 Library changes
 ---
 
-- 
1.7.10.4

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


Re: [PATCH v2 0/5] New output format sexp (Lisp S-Expressions)

2012-12-04 Thread Jani Nikula

Hi Peter -

On Tue, 04 Dec 2012, Peter Feigl cra...@gmx.net wrote:
 This patch series adds a new output format sexp to notmuch-reply,
 notmuch-show and notmuch-search. These are useful for the Android mobile
 client and perhaps other Lisp programs as well.
 After the switch to a generic structured output printer, which was
 committed some months ago, these patches just add another one (like the
 json structured output printer).
 Basic tests and updates to the man pages are also included.


 Peter Feigl (5):
   Adding an S-expression structured output printer.
   Rename the -json printer functions in notmuch-reply and
 notmuch-show to generic -sprinter functions.
   Use the S-Expression structured printer in notmuch-show,
 notmuch-reply and notmuch-search.

Patches 1-3 look good.

   Adding tests for --format=sexp.

Did not review.

   Updating man pages for new S-Expression output format.

Did not review, but noticed it adds lines with trailing whitespace.


BR,
Jani.



  Makefile.local|   1 +
  man/man1/notmuch-reply.1  |  14 ++-
  man/man1/notmuch-search.1 |  15 +--
  man/man1/notmuch-show.1   |  36 +--
  notmuch-client.h  |   8 +-
  notmuch-reply.c   |  43 
  notmuch-search.c  |   6 +-
  notmuch-show.c|  48 +
  sprinter-sexp.c   | 250 
 ++
  sprinter.h|   4 +
  test/notmuch-test |   1 +
  test/sexp |  48 +
  12 files changed, 414 insertions(+), 60 deletions(-)
  create mode 100644 sprinter-sexp.c
  create mode 100755 test/sexp

 -- 
 1.8.0

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


Re: [PATCH v2 1/5] Adding an S-expression structured output printer.

2012-12-04 Thread Austin Clements
On Tue, 04 Dec 2012, Peter Feigl cra...@gmx.net wrote:
 This commit adds a structured output printer for Lisp
 S-Expressions. Later commits will use this printer in notmuch search,
 show and reply.

 The structure is the same as json, but:
 - arrays are written as lists: (foo bar baaz 1 2 3)
 - maps are written as a-lists: ((key value) (other-key other-value))

I thought the plan was to use plists.  Or are we going to support both?

 - true is written as t
 - false is written as nil
 - null is written as nil
 ---
  Makefile.local  |   1 +
  sprinter-sexp.c | 250 
 
  sprinter.h  |   4 +
  3 files changed, 255 insertions(+)
  create mode 100644 sprinter-sexp.c

 diff --git a/Makefile.local b/Makefile.local
 index 2b91946..0db1713 100644
 --- a/Makefile.local
 +++ b/Makefile.local
 @@ -270,6 +270,7 @@ notmuch_client_srcs = \
   notmuch-tag.c   \
   notmuch-time.c  \
   sprinter-json.c \
 + sprinter-sexp.c \
   sprinter-text.c \
   query-string.c  \
   mime-node.c \
 diff --git a/sprinter-sexp.c b/sprinter-sexp.c
 new file mode 100644
 index 000..6d6bbad
 --- /dev/null
 +++ b/sprinter-sexp.c
 @@ -0,0 +1,250 @@
 +/* notmuch - Not much of an email program, (just index and search)
 + *
 + * Copyright © 2012 Carl Worth

This should probably be your name.

 + *
 + * 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/ .
 + *
 + * Author: Carl Worth cwo...@cworth.org

Same here.

 + */
 +
 +#include stdbool.h
 +#include stdio.h
 +#include talloc.h
 +#include sprinter.h
 +
 +struct sprinter_sexp {
 +struct sprinter vtable;
 +FILE *stream;
 +/* Top of the state stack, or NULL if the printer is not currently
 + * inside any aggregate types. */
 +struct sexp_state *state;
 +
 +/* A flag to signify that a separator should be inserted in the
 + * output as soon as possible.
 + */
 +notmuch_bool_t insert_separator;
 +};
 +
 +struct sexp_state {
 +struct sexp_state *parent;
 +
 +/* True if nothing has been printed in this aggregate yet.
 + * Suppresses the space before a value. */
 +notmuch_bool_t first;
 +
 +/* True if the state is a map state.
 + * Used to add a space between key/value pairs. */
 +notmuch_bool_t in_map;

Maybe in_alist?

 +
 +/* The character that closes the current aggregate. */
 +char close;

Given that the close character is always ')', why have this field?

 +};
 +
 +/* Helper function to set up the stream to print a value.  If this
 + * value follows another value, prints a space. */
 +static struct sprinter_sexp *
 +sexp_begin_value (struct sprinter *sp)
 +{
 +struct sprinter_sexp *sps = (struct sprinter_sexp *) sp;
 +
 +if (sps-state) {
 + if (! sps-state-first) {
 + if (sps-insert_separator) {
 + fputc ('\n', sps-stream);
 + sps-insert_separator = FALSE;
 + } else {
 + if (! sps-state-in_map)
 + fputc (' ', sps-stream);
 + }
 + } else {
 + sps-state-first = FALSE;
 + }
 +}
 +return sps;
 +}
 +
 +/* Helper function to begin an aggregate type.  Prints the open
 + * character and pushes a new state frame. */
 +static void
 +sexp_begin_aggregate (struct sprinter *sp, char open, char close)

The open and close arguments seem unnecessary here, since they're always
'(' and ')'.  Perhaps this should instead take in_map as an argument?

 +{
 +struct sprinter_sexp *sps = sexp_begin_value (sp);
 +struct sexp_state *state = talloc (sps, struct sexp_state);
 +fputc (open, sps-stream);
 +state-parent = sps-state;
 +state-first = TRUE;
 +state-in_map = FALSE;
 +state-close = close;
 +sps-state = state;
 +}
 +
 +static void
 +sexp_begin_map (struct sprinter *sp)
 +{
 +struct sprinter_sexp *sps = (struct sprinter_sexp *) sp;
 +sexp_begin_aggregate (sp, '(', ')');
 +sps-state-in_map = TRUE;
 +}
 +
 +static void
 +sexp_begin_list (struct sprinter *sp)
 +{
 +sexp_begin_aggregate (sp, '(', ')');
 +}
 +
 +static void
 +sexp_end (struct sprinter *sp)
 +{
 +struct sprinter_sexp *sps = (struct sprinter_sexp *) sp;
 +struct sexp_state *state = sps-state;
 +
 +if (sps-state-in_map)
 + fputc (')', sps-stream);
 +fputc 

Re: [PATCH v2 2/5] Rename the -json printer functions in notmuch-reply and notmuch-show to generic -sprinter functions.

2012-12-04 Thread Austin Clements
On Tue, 04 Dec 2012, Peter Feigl cra...@gmx.net wrote:
 All the structured output functions in notmuch-reply and notmuch-show
 are renamed to a generic name (as they do not contain any json-specific
 code anyway). This patch is a preparation to actually using the new
 S-Expression sprinter in notmuch-reply and notmuch-show.
 ---
  notmuch-client.h |  8 
  notmuch-reply.c  | 38 +-
  notmuch-show.c   | 30 +++---
  3 files changed, 40 insertions(+), 36 deletions(-)

 diff --git a/notmuch-client.h b/notmuch-client.h
 index ae9344b..1c336dc 100644
 --- a/notmuch-client.h
 +++ b/notmuch-client.h
 @@ -175,12 +175,12 @@ notmuch_status_t
  show_one_part (const char *filename, int part);
  
  void
 -format_part_json (const void *ctx, struct sprinter *sp, mime_node_t *node,
 -   notmuch_bool_t first, notmuch_bool_t output_body);
 +format_part_sprinter (const void *ctx, struct sprinter *sp, mime_node_t 
 *node,
 +   notmuch_bool_t first, notmuch_bool_t output_body);
  
  void
 -format_headers_json (struct sprinter *sp, GMimeMessage *message,
 -  notmuch_bool_t reply);
 +format_headers_sprinter (struct sprinter *sp, GMimeMessage *message,
 +  notmuch_bool_t reply);
  
  typedef enum {
  NOTMUCH_SHOW_TEXT_PART_REPLY = 1  0,
 diff --git a/notmuch-reply.c b/notmuch-reply.c
 index e60a264..53aefa7 100644
 --- a/notmuch-reply.c
 +++ b/notmuch-reply.c
 @@ -548,7 +548,8 @@ notmuch_reply_format_default(void *ctx,
notmuch_config_t *config,
notmuch_query_t *query,
notmuch_show_params_t *params,
 -  notmuch_bool_t reply_all)
 +  notmuch_bool_t reply_all,
 +  unused (sprinter_t *sp))
  {
  GMimeMessage *reply;
  notmuch_messages_t *messages;
 @@ -587,17 +588,17 @@ notmuch_reply_format_default(void *ctx,
  }
  
  static int
 -notmuch_reply_format_json(void *ctx,
 -   notmuch_config_t *config,
 -   notmuch_query_t *query,
 -   notmuch_show_params_t *params,
 -   notmuch_bool_t reply_all)
 +notmuch_reply_format_sprinter(void *ctx,
 +   notmuch_config_t *config,
 +   notmuch_query_t *query,
 +   notmuch_show_params_t *params,
 +   notmuch_bool_t reply_all,
 +   sprinter_t *sp)
  {
  GMimeMessage *reply;
  notmuch_messages_t *messages;
  notmuch_message_t *message;
  mime_node_t *node;
 -sprinter_t *sp;
  
  if (notmuch_query_count_messages (query) != 1) {
   fprintf (stderr, Error: search term did not match precisely one 
 message.\n);
 @@ -613,18 +614,17 @@ notmuch_reply_format_json(void *ctx,
  if (!reply)
   return 1;
  
 -sp = sprinter_json_create (ctx, stdout);
  sp-begin_map (sp);
  
  /* The headers of the reply message we've created */
  sp-map_key (sp, reply-headers);
 -format_headers_json (sp, reply, TRUE);
 +format_headers_sprinter (sp, reply, TRUE);
  g_object_unref (G_OBJECT (reply));
  reply = NULL;
  
  /* Start the original */
  sp-map_key (sp, original);
 -format_part_json (ctx, sp, node, TRUE, TRUE);
 +format_part_sprinter (ctx, sp, node, TRUE, TRUE);
  
  /* End */
  sp-end (sp);
 @@ -639,7 +639,8 @@ notmuch_reply_format_headers_only(void *ctx,
 notmuch_config_t *config,
 notmuch_query_t *query,
 unused (notmuch_show_params_t *params),
 -   notmuch_bool_t reply_all)
 +   notmuch_bool_t reply_all,
 +   unused (sprinter_t *sp))
  {
  GMimeMessage *reply;
  notmuch_messages_t *messages;
 @@ -707,7 +708,7 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
  notmuch_query_t *query;
  char *query_string;
  int opt_index, ret = 0;
 -int (*reply_format_func)(void *ctx, notmuch_config_t *config, 
 notmuch_query_t *query, notmuch_show_params_t *params, notmuch_bool_t 
 reply_all);
 +int (*reply_format_func)(void *ctx, notmuch_config_t *config, 
 notmuch_query_t *query, notmuch_show_params_t *params, notmuch_bool_t 
 reply_all, struct sprinter *sp);

Yikes.  This could use some line wrapping.

This patch LGTM other than this.

  notmuch_show_params_t params = {
   .part = -1,
   .crypto = {
 @@ -717,6 +718,7 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
  };
  int format = FORMAT_DEFAULT;
  int reply_all = TRUE;
 +struct sprinter *sp = NULL;
  
  notmuch_opt_desc_t options[] = {
   { NOTMUCH_OPT_KEYWORD, format, format, 'f',
 @@ -738,12 +740,14 @@ notmuch_reply_command (void *ctx, 

Re: [PATCH v2 3/5] Use the S-Expression structured printer in notmuch-show, notmuch-reply and notmuch-search.

2012-12-04 Thread Austin Clements
On Tue, 04 Dec 2012, Peter Feigl cra...@gmx.net wrote:
 This patch uses the new S-Expression printer in the notmuch CLI (show,
 search and reply). You can now use --format=sexp for any of them.
 ---
  notmuch-reply.c  |  5 +
  notmuch-search.c |  6 +-
  notmuch-show.c   | 18 ++
  3 files changed, 24 insertions(+), 5 deletions(-)

 diff --git a/notmuch-reply.c b/notmuch-reply.c
 index 53aefa7..69fd256 100644
 --- a/notmuch-reply.c
 +++ b/notmuch-reply.c
 @@ -697,6 +697,7 @@ notmuch_reply_format_headers_only(void *ctx,
  enum {
  FORMAT_DEFAULT,
  FORMAT_JSON,
 +FORMAT_SEXP,
  FORMAT_HEADERS_ONLY,
  };
  
 @@ -724,6 +725,7 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
   { NOTMUCH_OPT_KEYWORD, format, format, 'f',
 (notmuch_keyword_t []){ { default, FORMAT_DEFAULT },
 { json, FORMAT_JSON },
 +   { sexp, FORMAT_SEXP },

sexpa if we're going to support both alists and plists?  Same for the
others.

 { headers-only, FORMAT_HEADERS_ONLY },
 { 0, 0 } } },
   { NOTMUCH_OPT_KEYWORD, reply_all, reply-to, 'r',
 @@ -745,6 +747,9 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
  } else if (format == FORMAT_JSON) {
   reply_format_func = notmuch_reply_format_sprinter;
   sp = sprinter_json_create (ctx, stdout);
 +} else if (format == FORMAT_SEXP) {
 + reply_format_func = notmuch_reply_format_sprinter;
 + sp = sprinter_sexp_create (ctx, stdout);
  } else {
   reply_format_func = notmuch_reply_format_default;
  }
 diff --git a/notmuch-search.c b/notmuch-search.c
 index 830c4e4..6218622 100644
 --- a/notmuch-search.c
 +++ b/notmuch-search.c
 @@ -305,7 +305,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
  int exclude = EXCLUDE_TRUE;
  unsigned int i;
  
 -enum { NOTMUCH_FORMAT_JSON, NOTMUCH_FORMAT_TEXT }
 +enum { NOTMUCH_FORMAT_JSON, NOTMUCH_FORMAT_TEXT, NOTMUCH_FORMAT_SEXP }
   format_sel = NOTMUCH_FORMAT_TEXT;
  
  notmuch_opt_desc_t options[] = {
 @@ -315,6 +315,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
 { 0, 0 } } },
   { NOTMUCH_OPT_KEYWORD, format_sel, format, 'f',
 (notmuch_keyword_t []){ { json, NOTMUCH_FORMAT_JSON },
 +   { sexp, NOTMUCH_FORMAT_SEXP },
 { text, NOTMUCH_FORMAT_TEXT },
 { 0, 0 } } },
   { NOTMUCH_OPT_KEYWORD, output, output, 'o',
 @@ -347,6 +348,9 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
  case NOTMUCH_FORMAT_JSON:
   format = sprinter_json_create (ctx, stdout);
   break;
 +case NOTMUCH_FORMAT_SEXP:
 + format = sprinter_sexp_create (ctx, stdout);
 + break;
  default:
   /* this should never happen */
   INTERNAL_ERROR(no output format selected);
 diff --git a/notmuch-show.c b/notmuch-show.c
 index 38c621f..d4860f1 100644
 --- a/notmuch-show.c
 +++ b/notmuch-show.c
 @@ -40,6 +40,11 @@ static const notmuch_show_format_t format_json = {
  .part = format_part_sprinter_entry,
  };
  
 +static const notmuch_show_format_t format_sexp = {
 +.new_sprinter = sprinter_sexp_create,
 +.part = format_part_sprinter_entry,
 +};
 +
  static notmuch_status_t
  format_part_mbox (const void *ctx, sprinter_t *sp, mime_node_t *node,
 int indent, const notmuch_show_params_t *params);
 @@ -110,7 +115,7 @@ _get_one_line_summary (const void *ctx, notmuch_message_t 
 *message)
  static void
  format_message_sprinter (sprinter_t *sp, notmuch_message_t *message)
  {
 -/* Any changes to the JSON format should be reflected in the file
 +/* Any changes to the JSON or S-Expression format should be reflected in 
 the file
   * devel/schemata. */

Please re-wrap this comment to 72 columns.

  
  void *local = talloc_new (NULL);
 @@ -1012,6 +1017,7 @@ do_show (void *ctx,
  enum {
  NOTMUCH_FORMAT_NOT_SPECIFIED,
  NOTMUCH_FORMAT_JSON,
 +NOTMUCH_FORMAT_SEXP,
  NOTMUCH_FORMAT_TEXT,
  NOTMUCH_FORMAT_MBOX,
  NOTMUCH_FORMAT_RAW
 @@ -1056,6 +1062,7 @@ notmuch_show_command (void *ctx, unused (int argc), 
 unused (char *argv[]))
   { NOTMUCH_OPT_KEYWORD, format_sel, format, 'f',
 (notmuch_keyword_t []){ { json, NOTMUCH_FORMAT_JSON },
 { text, NOTMUCH_FORMAT_TEXT },
 +   { sexp, NOTMUCH_FORMAT_SEXP },
 { mbox, NOTMUCH_FORMAT_MBOX },
 { raw, NOTMUCH_FORMAT_RAW },
 { 0, 0 } } },
 @@ -1100,6 +1107,9 @@ notmuch_show_command (void *ctx, unused (int argc), 
 unused (char *argv[]))
  case NOTMUCH_FORMAT_TEXT:
   format = format_text;
   break;
 +case NOTMUCH_FORMAT_SEXP:
 + format = format_sexp;
 + 

Re: [PATCH v2 4/5] Adding tests for --format=sexp.

2012-12-04 Thread Austin Clements
It would be nice to use something like test_expect_equal_json for this
(probably based on Emacs' pp function), but this is fine for now.

On Tue, 04 Dec 2012, Peter Feigl cra...@gmx.net wrote:
 Add basic tests, the same as for json, for the S-Expression output
 format.
 ---
  test/notmuch-test |  1 +
  test/sexp | 48 
  2 files changed, 49 insertions(+)
  create mode 100755 test/sexp

 diff --git a/test/notmuch-test b/test/notmuch-test
 index a6ef34f..ca9c3dc 100755
 --- a/test/notmuch-test
 +++ b/test/notmuch-test
 @@ -31,6 +31,7 @@ TESTS=
excludes
tagging
json
 +  sexp
text
multipart
thread-naming
 diff --git a/test/sexp b/test/sexp
 new file mode 100755
 index 000..fdc9de6
 --- /dev/null
 +++ b/test/sexp
 @@ -0,0 +1,48 @@
 +#!/usr/bin/env bash
 +test_description=--format=sexp output
 +. ./test-lib.sh
 +
 +test_begin_subtest Show message: sexp
 +add_message [subject]=\sexp-show-subject\ [date]=\Sat, 01 Jan 2000 
 12:00:00 -\ [bcc]=\test_suite+...@notmuchmail.org\ 
 [reply-to]=\test_suite+repl...@notmuchmail.org\ 
 [body]=\sexp-show-message\
 +output=$(notmuch show --format=sexp sexp-show-message)
 +test_expect_equal $output (id \msg-001@notmuch-test-suite\) (match 
 t) (excluded nil) (filename 
 \/home/nex/notmuch-sexp/test/tmp.sexp/mail/msg-001\) (timestamp 946728000) 
 (date_relative \2000-01-01\) (tags (\inbox\ \unread\)) (headers 
 ((Subject \sexp-show-subject\) (From \Notmuch Test Suite 
 test_su...@notmuchmail.org\) (To \Notmuch Test Suite 
 test_su...@notmuchmail.org\) (Bcc \test_suite+...@notmuchmail.org\) 
 (Reply-To \test_suite+repl...@notmuchmail.org\) (Date \Sat, 01 Jan 2000 
 12:00:00 +\))) (body (((id 1) (content-type \text/plain\) (content 
 \sexp-show-message\n\) (
 +
 +# This should be the same output as above.
 +test_begin_subtest Show message: sexp --body=true
 +output=$(notmuch show --format=sexp --body=true sexp-show-message)
 +test_expect_equal $output (id \msg-001@notmuch-test-suite\) (match 
 t) (excluded nil) (filename 
 \/home/nex/notmuch-sexp/test/tmp.sexp/mail/msg-001\) (timestamp 946728000) 
 (date_relative \2000-01-01\) (tags (\inbox\ \unread\)) (headers 
 ((Subject \sexp-show-subject\) (From \Notmuch Test Suite 
 test_su...@notmuchmail.org\) (To \Notmuch Test Suite 
 test_su...@notmuchmail.org\) (Bcc \test_suite+...@notmuchmail.org\) 
 (Reply-To \test_suite+repl...@notmuchmail.org\) (Date \Sat, 01 Jan 2000 
 12:00:00 +\))) (body (((id 1) (content-type \text/plain\) (content 
 \sexp-show-message\n\) (
 +
 +test_begin_subtest Show message: sexp --body=false
 +output=$(notmuch show --format=sexp --body=false sexp-show-message)
 +test_expect_equal $output (id \msg-001@notmuch-test-suite\) (match 
 t) (excluded nil) (filename 
 \/home/nex/notmuch-sexp/test/tmp.sexp/mail/msg-001\) (timestamp 946728000) 
 (date_relative \2000-01-01\) (tags (\inbox\ \unread\)) (headers 
 ((Subject \sexp-show-subject\) (From \Notmuch Test Suite 
 test_su...@notmuchmail.org\) (To \Notmuch Test Suite 
 test_su...@notmuchmail.org\) (Bcc \test_suite+...@notmuchmail.org\) 
 (Reply-To \test_suite+repl...@notmuchmail.org\) (Date \Sat, 01 Jan 2000 
 12:00:00 +\ (
 +
 +test_begin_subtest Search message: sexp
 +add_message [subject]=\sexp-search-subject\ [date]=\Sat, 01 Jan 2000 
 12:00:00 -\ [body]=\sexp-search-message\
 +output=$(notmuch search --format=sexp sexp-search-message | 
 notmuch_search_sanitize)
 +test_expect_equal $output (((thread \0002\) (timestamp 
 946728000) (date_relative \2000-01-01\) (matched 1) (total 1) (authors 
 \Notmuch Test Suite\) (subject \sexp-search-subject\) (tags (\inbox\ 
 \unread\
 +
 +test_begin_subtest Show message: sexp, utf-8
 +add_message [subject]=\sexp-show-utf8-body-sübjéct\ [date]=\Sat, 01 
 Jan 2000 12:00:00 -\ [body]=\jsön-show-méssage\
 +output=$(notmuch show --format=sexp jsön-show-méssage)
 +test_expect_equal $output (id \msg-003@notmuch-test-suite\) (match 
 t) (excluded nil) (filename 
 \/home/nex/notmuch-sexp/test/tmp.sexp/mail/msg-003\) (timestamp 946728000) 
 (date_relative \2000-01-01\) (tags (\inbox\ \unread\)) (headers 
 ((Subject \sexp-show-utf8-body-sübjéct\) (From \Notmuch Test Suite 
 test_su...@notmuchmail.org\) (To \Notmuch Test Suite 
 test_su...@notmuchmail.org\) (Date \Sat, 01 Jan 2000 12:00:00 +\))) 
 (body (((id 1) (content-type \text/plain\) (content 
 \jsön-show-méssage\n\) (
 +
 +test_begin_subtest Show message: sexp, inline attachment filename
 +subject='sexp-show-inline-attachment-filename'
 +id=sexp-show-inline-attachment-filen...@notmuchmail.org
 +emacs_deliver_message \
 +$subject \
 +'This is a test message with inline attachment with a filename' \
 +(mml-attach-file \$TEST_DIRECTORY/README\ nil nil \inline\)
 + (message-goto-eoh)
 + (insert \Message-ID: $id\n\)
 +output=$(notmuch show --format=sexp id:$id)
 +filename=$(notmuch search 

[PATCH 1/3] test: fix count test

2012-12-04 Thread Jani Nikula
The quoting for ${SEARCH} is broken when it's supposed to be '*', and
it seems tricky to get it right. Just drop the variable and use '*'
directly. Before this, none of the messages ever matched, and the test
was comparing zeros.
---
 test/count |   23 ++-
 1 file changed, 10 insertions(+), 13 deletions(-)

diff --git a/test/count b/test/count
index 300b171..8e587ff 100755
--- a/test/count
+++ b/test/count
@@ -4,37 +4,34 @@ test_description='notmuch count for messages and threads'
 
 add_email_corpus
 
-SEARCH=\*\
-
 test_begin_subtest message count is the default for notmuch count
 test_expect_equal \
-`notmuch search --output=messages ${SEARCH} | wc -l` \
-`notmuch count ${SEARCH}`
+`notmuch search --output=messages '*' | wc -l` \
+`notmuch count '*'`
 
 test_begin_subtest message count with --output=messages
 test_expect_equal \
-`notmuch search --output=messages ${SEARCH} | wc -l` \
-`notmuch count --output=messages ${SEARCH}`
+`notmuch search --output=messages '*' | wc -l` \
+`notmuch count --output=messages '*'`
 
 test_begin_subtest thread count with --output=threads
 test_expect_equal \
-`notmuch search --output=threads ${SEARCH} | wc -l` \
-`notmuch count --output=threads ${SEARCH}`
+`notmuch search --output=threads '*' | wc -l` \
+`notmuch count --output=threads '*'`
 
 test_begin_subtest thread count is the default for notmuch search
 test_expect_equal \
-`notmuch search ${SEARCH} | wc -l` \
-`notmuch count --output=threads ${SEARCH}`
+`notmuch search '*' | wc -l` \
+`notmuch count --output=threads '*'`
 
-SEARCH=from:cworth and not from:cworth
 test_begin_subtest count with no matching messages
 test_expect_equal \
 0 \
-`notmuch count --output=messages ${SEARCH}`
+`notmuch count --output=messages from:cworth and not from:cworth`
 
 test_begin_subtest count with no matching threads
 test_expect_equal \
 0 \
-`notmuch count --output=threads ${SEARCH}`
+`notmuch count --output=threads from:cworth and not from:cworth`
 
 test_done
-- 
1.7.10.4

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


[PATCH 0/3] test fixes, portability

2012-12-04 Thread Jani Nikula
I had a glance at a 'make test' report on OS X [1], and tried to fix a
few things from there. While at it, noticed that count test is horribly
broken.

BR,
Jani.

[1] https://spod.gy/p/u9j3zxg96vu6k3wy

Jani Nikula (3):
  test: fix count test
  test: wrap 'wc -l' results in arithmetic evaluation to strip
whitespace
  test: use perl instead of sed -r for portability

 test/count   |   25 +
 test/test-lib.sh |2 +-
 2 files changed, 14 insertions(+), 13 deletions(-)

-- 
1.7.10.4

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


[PATCH 3/3] test: use perl instead of sed -r for portability

2012-12-04 Thread Jani Nikula
Our OS X users report -r is not a supported option for sed. Use perl
instead.
---
 test/test-lib.sh |2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/test-lib.sh b/test/test-lib.sh
index f169785..31ed107 100644
--- a/test/test-lib.sh
+++ b/test/test-lib.sh
@@ -576,7 +576,7 @@ NOTMUCH_NEW ()
 
 notmuch_search_sanitize ()
 {
-sed -r -e 's/(?thread?: ?)(?)(?)/\1\2XXX\3/'
+perl -pe 's/(?thread?: ?)(?)(?)/\1\2XXX\3/'
 }
 
 NOTMUCH_SHOW_FILENAME_SQUELCH='s,filename:.*/mail,filename:/XXX/mail,'
-- 
1.7.10.4

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


[PATCH 2/3] test: wrap 'wc -l' results in arithmetic evaluation to strip whitespace

2012-12-04 Thread Jani Nikula
This is for portability, as 'wc -l' emits whitespace on some BSD
variants. Suggested by Tomi Ollila tomi.oll...@iki.fi.

---

Updated version of id:1338361324-57289-8-git-send-email-pi...@pioto.org
---
 test/count |   12 
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/test/count b/test/count
index 8e587ff..879b114 100755
--- a/test/count
+++ b/test/count
@@ -4,24 +4,28 @@ test_description='notmuch count for messages and threads'
 
 add_email_corpus
 
+# Note: The 'wc -l' results below are wrapped in arithmetic evaluation
+# $((...)) to strip whitespace. This is for portability, as 'wc -l'
+# emits whitespace on some BSD variants.
+
 test_begin_subtest message count is the default for notmuch count
 test_expect_equal \
-`notmuch search --output=messages '*' | wc -l` \
+$((`notmuch search --output=messages '*' | wc -l`)) \
 `notmuch count '*'`
 
 test_begin_subtest message count with --output=messages
 test_expect_equal \
-`notmuch search --output=messages '*' | wc -l` \
+$((`notmuch search --output=messages '*' | wc -l`)) \
 `notmuch count --output=messages '*'`
 
 test_begin_subtest thread count with --output=threads
 test_expect_equal \
-`notmuch search --output=threads '*' | wc -l` \
+$((`notmuch search --output=threads '*' | wc -l`)) \
 `notmuch count --output=threads '*'`
 
 test_begin_subtest thread count is the default for notmuch search
 test_expect_equal \
-`notmuch search '*' | wc -l` \
+$((`notmuch search '*' | wc -l`)) \
 `notmuch count --output=threads '*'`
 
 test_begin_subtest count with no matching messages
-- 
1.7.10.4

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


Re: [PATCH 0/3] test fixes, portability

2012-12-04 Thread Tomi Ollila
On Tue, Dec 04 2012, Jani Nikula j...@nikula.org wrote:

 I had a glance at a 'make test' report on OS X [1], and tried to fix a
 few things from there. While at it, noticed that count test is horribly
 broken.

LGTM


 BR,
 Jani.

Tomi


 [1] https://spod.gy/p/u9j3zxg96vu6k3wy

 Jani Nikula (3):
   test: fix count test
   test: wrap 'wc -l' results in arithmetic evaluation to strip
 whitespace
   test: use perl instead of sed -r for portability

  test/count   |   25 +
  test/test-lib.sh |2 +-
  2 files changed, 14 insertions(+), 13 deletions(-)

 -- 
 1.7.10.4

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


Re: [PATCH 3/3] test: use perl instead of sed -r for portability

2012-12-04 Thread Michal Nazarewicz
On Tue, Dec 04 2012, Jani Nikula wrote:
 Our OS X users report -r is not a supported option for sed. Use perl
 instead.
 ---
  test/test-lib.sh |2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)

 diff --git a/test/test-lib.sh b/test/test-lib.sh
 index f169785..31ed107 100644
 --- a/test/test-lib.sh
 +++ b/test/test-lib.sh
 @@ -576,7 +576,7 @@ NOTMUCH_NEW ()
  
  notmuch_search_sanitize ()
  {
 -sed -r -e 's/(?thread?: ?)(?)(?)/\1\2XXX\3/'
 +perl -pe 's/(?thread?: ?)(?)(?)/\1\2XXX\3/'

Alternatively, this could just be convert into a basic regexp:

sed -e 's/\(\?thread\?: \?\?\)\(\?\)/\1XXX\2/'

which I think is even more portable, no?

  }
  
  NOTMUCH_SHOW_FILENAME_SQUELCH='s,filename:.*/mail,filename:/XXX/mail,'

-- 
Best regards, _ _
.o. | Liege of Serenely Enlightened Majesty of  o' \,=./ `o
..o | Computer Science,  Michał “mina86” Nazarewicz(o o)
ooo +email/xmpp: m...@google.com--ooO--(_)--Ooo--

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


Re: [PATCH 1/3] test: fix count test

2012-12-04 Thread Michal Nazarewicz
On Tue, Dec 04 2012, Jani Nikula wrote:
 The quoting for ${SEARCH} is broken when it's supposed to be '*', and

Why is it broken?  It does not appear to be broken to me and in fact the
test passes.

 it seems tricky to get it right. Just drop the variable and use '*'
 directly. Before this, none of the messages ever matched, and the test
 was comparing zeros.
 ---
  test/count |   23 ++-
  1 file changed, 10 insertions(+), 13 deletions(-)

 diff --git a/test/count b/test/count
 index 300b171..8e587ff 100755
 --- a/test/count
 +++ b/test/count
 @@ -4,37 +4,34 @@ test_description='notmuch count for messages and threads'
  
  add_email_corpus
  
 -SEARCH=\*\
 -
  test_begin_subtest message count is the default for notmuch count
  test_expect_equal \
 -`notmuch search --output=messages ${SEARCH} | wc -l` \
 -`notmuch count ${SEARCH}`
 +`notmuch search --output=messages '*' | wc -l` \
 +`notmuch count '*'`
  
  test_begin_subtest message count with --output=messages
  test_expect_equal \
 -`notmuch search --output=messages ${SEARCH} | wc -l` \
 -`notmuch count --output=messages ${SEARCH}`
 +`notmuch search --output=messages '*' | wc -l` \
 +`notmuch count --output=messages '*'`
  
  test_begin_subtest thread count with --output=threads
  test_expect_equal \
 -`notmuch search --output=threads ${SEARCH} | wc -l` \
 -`notmuch count --output=threads ${SEARCH}`
 +`notmuch search --output=threads '*' | wc -l` \
 +`notmuch count --output=threads '*'`
  
  test_begin_subtest thread count is the default for notmuch search
  test_expect_equal \
 -`notmuch search ${SEARCH} | wc -l` \
 -`notmuch count --output=threads ${SEARCH}`
 +`notmuch search '*' | wc -l` \
 +`notmuch count --output=threads '*'`
  
 -SEARCH=from:cworth and not from:cworth
  test_begin_subtest count with no matching messages
  test_expect_equal \
  0 \
 -`notmuch count --output=messages ${SEARCH}`
 +`notmuch count --output=messages from:cworth and not from:cworth`
  
  test_begin_subtest count with no matching threads
  test_expect_equal \
  0 \
 -`notmuch count --output=threads ${SEARCH}`
 +`notmuch count --output=threads from:cworth and not from:cworth`
  
  test_done

-- 
Best regards, _ _
.o. | Liege of Serenely Enlightened Majesty of  o' \,=./ `o
..o | Computer Science,  Michał “mina86” Nazarewicz(o o)
ooo +email/xmpp: m...@google.com--ooO--(_)--Ooo--

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


[PATCH 1/3] emacs: show: modify insert-part-header to save the button text

2012-12-04 Thread Mark Walters
This just make notmuch-show-insert-part-header save the basic button
text for parts as an attribute. This makes it simpler for the button
action (added in a later patch) to reword the label as appropriate (eg
append (not shown) or not as appropriate).
---
 emacs/notmuch-show.el |   19 ++-
 1 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index d7fa10e..f8ce037 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -483,17 +483,18 @@ message at DEPTH in the current thread.
 (fset 'notmuch-show-part-button-map notmuch-show-part-button-map)
 
 (defun notmuch-show-insert-part-header (nth content-type declared-type 
optional name comment)
-  (let ((button))
+  (let ((button)
+   (base-label (concat (if name (concat name : ) )
+   declared-type
+   (if (not (string-equal declared-type content-type))
+   (concat  (as  content-type ))
+ )
+   (or comment 
+
 (setq button
  (insert-button
-  (concat [ 
-  (if name (concat name : ) )
-  declared-type
-  (if (not (string-equal declared-type content-type))
-  (concat  (as  content-type ))
-)
-  (or comment )
-   ])
+  (concat [  base-label  ])
+  :base-label base-label
   :type 'notmuch-show-part-button-type
   :notmuch-part nth
   :notmuch-filename name
-- 
1.7.9.1

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


[PATCH 2/3] emacs: show: add overlays for each part

2012-12-04 Thread Mark Walters
This make notmuch-show-insert-bodypart add an overlay for any
non-trivial part with a button header (currently the first text/plain
part does not have a button). At this point the overlay is available
to the button but there is no action using it yet.

In addition a not-shown variable which is used to request the part be
hidden by default down to the overlay but this is not acted on yet.
---
 emacs/notmuch-show.el |   62 +---
 1 files changed, 48 insertions(+), 14 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index f8ce037..3215ebc 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -569,10 +569,9 @@ message at DEPTH in the current thread.
 ;; should be chosen if there are more than one that match?
 (mapc (lambda (inner-part)
(let ((inner-type (plist-get inner-part :content-type)))
- (if (or notmuch-show-all-multipart/alternative-parts
- (string= chosen-type inner-type))
- (notmuch-show-insert-bodypart msg inner-part depth)
-   (notmuch-show-insert-part-header (plist-get inner-part :id) 
inner-type inner-type nil  (not shown)
+ (notmuch-show-insert-bodypart msg inner-part depth
+   (not (or 
notmuch-show-all-multipart/alternative-parts
+(string= chosen-type 
inner-type))
  inner-parts)
 
 (when notmuch-show-indent-multipart
@@ -840,17 +839,52 @@ message at DEPTH in the current thread.
   (setq handlers (cdr handlers
   t)
 
-(defun notmuch-show-insert-bodypart (msg part depth)
-  Insert the body part PART at depth DEPTH in the current thread.
+(defun notmuch-show-insert-part-overlays (msg beg end not-shown)
+  Add an overlay to the part between BEG and END
+  (let* ((button (button-at beg))
+(part-beg (and button (1+ (button-end button)
+
+;; If the part contains no text we do not make it toggleable.
+(unless (or (not button) (eq part-beg end))
+  (let ((base-label (button-get button :base-label))
+   (overlay (make-overlay part-beg end))
+   (message-invis-spec (plist-get msg :message-invis-spec))
+   (invis-spec (make-symbol notmuch-part-region)))
+
+   (overlay-put overlay 'invisible (list invis-spec message-invis-spec))
+   (overlay-put overlay 'isearch-open-invisible 
#'notmuch-wash-region-isearch-show)
+   (overlay-put overlay 'priority 10)
+   (overlay-put overlay 'type part)
+   ;; Now we have to add invis-spec to every overlay this
+   ;; overlay contains, otherwise these inner overlays will
+   ;; override this one.
+   (mapc (lambda (inner)
+   (when (and (= (overlay-start inner) part-beg)
+  (= (overlay-end inner) end))
+ (overlay-put inner 'invisible
+  (cons invis-spec (overlay-get inner 
'invisible)
+ (overlays-in part-beg end))
+
+   (button-put button 'invisibility-spec invis-spec)
+   (button-put button 'overlay overlay))
+  (goto-char (point-max)
+
+(defun notmuch-show-insert-bodypart (msg part depth optional not-shown)
+  Insert the body part PART at depth DEPTH in the current thread.
+
+If not-shown is TRUE then initially hide this part.
   (let ((content-type (downcase (plist-get part :content-type)))
-   (nth (plist-get part :id)))
-(notmuch-show-insert-bodypart-internal msg part content-type nth depth 
content-type))
-  ;; Some of the body part handlers leave point somewhere up in the
-  ;; part, so we make sure that we're down at the end.
-  (goto-char (point-max))
-  ;; Ensure that the part ends with a carriage return.
-  (unless (bolp)
-(insert \n)))
+   (nth (plist-get part :id))
+   (beg (point)))
+
+(notmuch-show-insert-bodypart-internal msg part content-type nth depth 
content-type)
+;; Some of the body part handlers leave point somewhere up in the
+;; part, so we make sure that we're down at the end.
+(goto-char (point-max))
+;; Ensure that the part ends with a carriage return.
+(unless (bolp)
+  (insert \n))
+(notmuch-show-insert-part-overlays msg beg (point) not-shown)))
 
 (defun notmuch-show-insert-body (msg body depth)
   Insert the body BODY at depth DEPTH in the current thread.
-- 
1.7.9.1

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


[PATCH 3/3] emacs: show: add invisibility button action

2012-12-04 Thread Mark Walters
This adds a button action to show hidden parts. In this version t
toggles the visibility of a part. In addition RET on a non-shown
part shows it.

The button is used to hide parts when appropriate (eg text/html in
multipart/alternative).
---
 emacs/notmuch-show.el |   36 +++-
 1 files changed, 35 insertions(+), 1 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 3215ebc..a4daff8 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -478,6 +478,7 @@ message at DEPTH in the current thread.
 (define-key map v 'notmuch-show-part-button-view)
 (define-key map o 'notmuch-show-part-button-interactively-view)
 (define-key map | 'notmuch-show-part-button-pipe)
+(define-key map t 'notmuch-show-toggle-invisible-part-action)
 map)
   Submap for button commands)
 (fset 'notmuch-show-part-button-map notmuch-show-part-button-map)
@@ -555,6 +556,31 @@ message at DEPTH in the current thread.
 (let ((handle (mm-make-handle (current-buffer) (list content-type
   (mm-pipe-part handle
 
+;; This is taken from notmuch-wash: maybe it should be unified?
+(defun notmuch-show-toggle-invisible-part-action (optional button 
no-redisplay)
+  (interactive)
+  (let* ((button (or button (button-at (point
+(overlay (button-get button 'overlay))
+(invis-spec (button-get button 'invisibility-spec))
+(show (invisible-p invis-spec)))
+(when overlay
+  (if show
+ (remove-from-invisibility-spec invis-spec)
+   (add-to-invisibility-spec invis-spec))
+  (let* ((new-start (button-start button))
+(button-label (button-get button :base-label))
+(old-point (point))
+(inhibit-read-only t))
+   (goto-char new-start)
+   (insert [  button-label (if show  ]  (not shown) ]))
+   (let ((old-end (button-end button)))
+ (move-overlay button new-start (point))
+ (delete-region (point) old-end))
+   (goto-char (min old-point (1- (button-end button)
+  (unless no-redisplay
+   (force-window-update)
+   (redisplay t)
+
 (defun notmuch-show-multipart/*-to-list (part)
   (mapcar (lambda (inner-part) (plist-get inner-part :content-type))
  (plist-get part :content)))
@@ -867,6 +893,11 @@ message at DEPTH in the current thread.
 
(button-put button 'invisibility-spec invis-spec)
(button-put button 'overlay overlay))
+
+  ;; We toggle the button for hidden parts as that gets the
+  ;; button label right.
+  (when not-shown
+   (notmuch-show-toggle-invisible-part-action button t))
   (goto-char (point-max)
 
 (defun notmuch-show-insert-bodypart (msg part depth optional not-shown)
@@ -1996,7 +2027,10 @@ the user (see 
`notmuch-show-stash-mlarchive-link-alist').
 
 (defun notmuch-show-part-button-default (optional button)
   (interactive)
-  (notmuch-show-part-button-internal button 
notmuch-show-part-button-default-action))
+  (let ((button (or button (button-at (point)
+(if (invisible-p (button-get button 'invisibility-spec))
+   (notmuch-show-toggle-invisible-part-action button)
+  (notmuch-show-part-button-internal button 
notmuch-show-part-button-default-action
 
 (defun notmuch-show-part-button-save (optional button)
   (interactive)
-- 
1.7.9.1

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


Re: [PATCH 2/3] perf-test: cache unpacked corpus

2012-12-04 Thread Austin Clements
On Mon, 03 Dec 2012, da...@tethera.net wrote:
 From: David Bremner brem...@debian.org

 Unpacking is not really the expensive step (compared to the initial
 notmuch new), but this is a pre-requisite to caching the database.
 ---
  performance-test/.gitignore   |1 +
  performance-test/Makefile.local   |2 +-
  performance-test/perf-test-lib.sh |   51 
 +
  3 files changed, 31 insertions(+), 23 deletions(-)

 diff --git a/performance-test/.gitignore b/performance-test/.gitignore
 index 53f2697..7e20f7c 100644
 --- a/performance-test/.gitignore
 +++ b/performance-test/.gitignore
 @@ -1 +1,2 @@
  tmp.*/
 +corpus.mail.*/
 diff --git a/performance-test/Makefile.local b/performance-test/Makefile.local
 index 5d2acbd..eb713d0 100644
 --- a/performance-test/Makefile.local
 +++ b/performance-test/Makefile.local
 @@ -29,4 +29,4 @@ $(TXZFILE):
  download-corpus:
   wget -O ${TXZFILE} ${DEFAULT_URL}
  
 -CLEAN := $(CLEAN) $(dir)/tmp.*
 +CLEAN := $(CLEAN) $(dir)/tmp.* $(dir)/corpus.mail.*
 diff --git a/performance-test/perf-test-lib.sh 
 b/performance-test/perf-test-lib.sh
 index bba793d..9fbf874 100644
 --- a/performance-test/perf-test-lib.sh
 +++ b/performance-test/perf-test-lib.sh
 @@ -35,37 +35,44 @@ then
   exit 1
  fi
  
 +CORPUS_DIR=${TEST_DIRECTORY}/corpus.mail.$corpus_size
  add_email_corpus ()
  {
  rm -rf ${MAIL_DIR}
 +if [ ! -d $CORPUS_DIR ]; then
 + case $corpus_size in
 + small)
 + arg=mail/enron/bailey-s
 + ;;
 + medium)
 + arg=mail/notmuch-archive
 + ;;
 + *)
 + arg=mail
 + esac
  
 -case $1 in
 - --small)
 - arg=mail/enron/bailey-s
 - ;;
 - --medium)
 - arg=mail/notmuch-archive
 - ;;

The README still refers to these arguments, so it should be updated,
too.

 - *)
 - arg=mail
 -esac
 + if command -v pixz  /dev/null; then
 + XZ=pixz
 + else
 + XZ=xz
 + fi
  
 -if command -v pixz  /dev/null; then
 - XZ=pixz
 -else
 - XZ=xz
 -fi
 + printf Unpacking corpus\n
 + mkdir $CORPUS_DIR
 +
 + tar --checkpoint=.5000 --extract --strip-components=2 \
 + --directory $CORPUS_DIR \
 + --use-compress-program ${XZ} \
 + --file ../download/notmuch-email-corpus-${PERFTEST_VERSION}.tar.xz \
 + notmuch-email-corpus/$arg
  
 -printf Unpacking corpus\n
 -tar --checkpoint=.5000 --extract --strip-components=1 \
 - --directory ${TMP_DIRECTORY} \
 - --use-compress-program ${XZ} \
 - --file ../download/notmuch-email-corpus-${PERFTEST_VERSION}.tar.xz \
 - notmuch-email-corpus/$arg
 + printf \n
  
 -printf \n
 +fi
 +cp -lr $CORPUS_DIR $MAIL_DIR
  }
  
 +
  print_header () {
  printf [v%4s]   
 Wall(s)\tUsr(s)\tSys(s)\tRes(K)\tIn(512B)\tOut(512B)\n \
  ${PERFTEST_VERSION}
 -- 
 1.7.10.4

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


Re: [PATCH 3/3] perf-test: add caching of xapian database.

2012-12-04 Thread Austin Clements
This seems like an odd way to do this.  Timing the initial notmuch new
seems like the goal of exactly one performance test and irrelevant to
the others.  What about splitting basic into two tests: an explicit
notmuch new performance test and a separate test that does
dump/restore/tag.  The second test can always use a cached notmuch
database (creating it if necessary).  If you want to be really kind, the
notmuch new performance test could save its result as the database cache
if there isn't a database cache; then people don't have to build the
database twice if they (or notmuch-perf-test) run the tests in the right
order.

On Mon, 03 Dec 2012, da...@tethera.net wrote:
 From: David Bremner brem...@debian.org

 The caching and uncaching seem to be necessarily manual, as timing the
 initial notmuch new is one of our goals with this suite.
 ---
  performance-test/.gitignore   |1 +
  performance-test/Makefile.local   |2 +-
  performance-test/basic|5 +
  performance-test/perf-test-lib.sh |   18 ++
  4 files changed, 25 insertions(+), 1 deletion(-)

 diff --git a/performance-test/.gitignore b/performance-test/.gitignore
 index 7e20f7c..779a115 100644
 --- a/performance-test/.gitignore
 +++ b/performance-test/.gitignore
 @@ -1,2 +1,3 @@
  tmp.*/
  corpus.mail.*/
 +notmuch.cache.*/
 diff --git a/performance-test/Makefile.local b/performance-test/Makefile.local
 index eb713d0..b136a88 100644
 --- a/performance-test/Makefile.local
 +++ b/performance-test/Makefile.local
 @@ -29,4 +29,4 @@ $(TXZFILE):
  download-corpus:
   wget -O ${TXZFILE} ${DEFAULT_URL}
  
 -CLEAN := $(CLEAN) $(dir)/tmp.* $(dir)/corpus.mail.*
 +CLEAN := $(CLEAN) $(dir)/tmp.* $(dir)/corpus.mail.* $(dir)/notmuch.cache.*
 diff --git a/performance-test/basic b/performance-test/basic
 index 9d015ee..41a7ff1 100755
 --- a/performance-test/basic
 +++ b/performance-test/basic
 @@ -2,11 +2,16 @@
  
  . ./perf-test-lib.sh
  
 +uncache_database
 +
  add_email_corpus
  
  print_header
  
  time_run 'initial notmuch new' 'notmuch new'
 +
 +cache_database
 +
  time_run 'second notmuch new' 'notmuch new'
  time_run 'dump *' 'notmuch dump  tags.out'
  time_run 'restore *' 'notmuch restore  tags.out'
 diff --git a/performance-test/perf-test-lib.sh 
 b/performance-test/perf-test-lib.sh
 index 9fbf874..c9b131a 100644
 --- a/performance-test/perf-test-lib.sh
 +++ b/performance-test/perf-test-lib.sh
 @@ -36,6 +36,8 @@ then
  fi
  
  CORPUS_DIR=${TEST_DIRECTORY}/corpus.mail.$corpus_size
 +DB_CACHE_DIR=${TEST_DIRECTORY}/notmuch.cache.$corpus_size
 +
  add_email_corpus ()
  {
  rm -rf ${MAIL_DIR}
 @@ -69,9 +71,25 @@ add_email_corpus ()
   printf \n
  
  fi
 +
  cp -lr $CORPUS_DIR $MAIL_DIR
 +
 +if [ -d $DB_CACHE_DIR ]; then
 + cp -r $DB_CACHE_DIR ${MAIL_DIR}/.notmuch
 +fi
  }
  
 +cache_database () {
 +if [ -d $MAIL_DIR/.notmuch ]; then
 + cp -r $MAIL_DIR/.notmuch $DB_CACHE_DIR
 +else
 + echo Warning: No database found to cache
 +fi
 +}
 +
 +uncache_database () {
 +rm -rf $DB_CACHE_DIR
 +}
  
  print_header () {
  printf [v%4s]   
 Wall(s)\tUsr(s)\tSys(s)\tRes(K)\tIn(512B)\tOut(512B)\n \
 -- 
 1.7.10.4

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


Re: [PATCH 3/4] perf-test: unpack tags.

2012-12-04 Thread Austin Clements
On Mon, 03 Dec 2012, da...@tethera.net wrote:
 From: David Bremner brem...@debian.org

 It's a bit annoying to call tar twice, but we cache the results so it
 isn't as bad as it could be.
 ---
  performance-test/Makefile.local   |1 +
  performance-test/perf-test-lib.sh |   25 +++--
  2 files changed, 20 insertions(+), 6 deletions(-)

 diff --git a/performance-test/Makefile.local b/performance-test/Makefile.local
 index b136a88..cdd7f19 100644
 --- a/performance-test/Makefile.local
 +++ b/performance-test/Makefile.local
 @@ -30,3 +30,4 @@ download-corpus:
   wget -O ${TXZFILE} ${DEFAULT_URL}
  
  CLEAN := $(CLEAN) $(dir)/tmp.* $(dir)/corpus.mail.* $(dir)/notmuch.cache.*
 +CLEAN := $(CLEAN) $(dir)/corpus.tags
 diff --git a/performance-test/perf-test-lib.sh 
 b/performance-test/perf-test-lib.sh
 index 08e2ebd..40c88c9 100644
 --- a/performance-test/perf-test-lib.sh
 +++ b/performance-test/perf-test-lib.sh
 @@ -41,6 +41,13 @@ DB_CACHE_DIR=${TEST_DIRECTORY}/notmuch.cache.$corpus_size
  add_email_corpus ()
  {
  rm -rf ${MAIL_DIR}
 +
 +if command -v pixz  /dev/null; then
 + XZ=pixz
 +else
 + XZ=xz
 +fi
 +
  if [ ! -d $CORPUS_DIR ]; then
   case $corpus_size in
   small)
 @@ -53,12 +60,6 @@ add_email_corpus ()
   arg=mail
   esac
  
 - if command -v pixz  /dev/null; then
 - XZ=pixz
 - else
 - XZ=xz
 - fi
 -
   printf Unpacking corpus\n
   mkdir $CORPUS_DIR
  
 @@ -72,6 +73,18 @@ add_email_corpus ()
  
  fi
  
 +if [ ! -d $TEST_DIRECTORY/corpus.tags ]; then
 +
 + mkdir $TEST_DIRECTORY/corpus.tags
 +
 + tar --extract --strip-components=2 \
 + --directory $TEST_DIRECTORY/corpus.tags \
 + --use-compress-program ${XZ} \
 + --file ../download/notmuch-email-corpus-${PERFTEST_VERSION}.tar.xz \
 + notmuch-email-corpus/tags

Why not --strip-components=1 and unpack both mail/ and tags/ into a
single, shared corpus cache directory in one call to tar?  Since you're
going to cp -lr things anyway, you can structure the corpus cache
however is convenient.

 +fi
 +
 +cp -lr $TEST_DIRECTORY/corpus.tags $TMP_DIRECTORY
  cp -lr $CORPUS_DIR $MAIL_DIR
  
  if [ -d $DB_CACHE_DIR ]; then
 -- 
 1.7.10.4

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