notmuch python bindings corrupt db index (was: gmail importer script)

2012-12-11 Thread Patrick Totzke
Quoting Jason A. Donenfeld (2012-12-11 13:47:32)
> On Tue, Dec 11, 2012 at 11:04 AM, Patrick Totzke
>  wrote:
> > I ended up killing the process after i saw that ETA was >3h.
> 
> Gmail's bottleneck. Very unfortunate. Leave it going over night.

OK, i assumed i'd not have to download all messages because i already have them
on disk -- synced via offlineimap. but then i remembered that OI stores uses
its own naming scheme for the files in a maildir. so thats probably why your 
script
did not realize theyre already there. (maybe it should? it could look up the 
MIDs from notmuch)

> > This broke my index!
> >
> > afterwards, a `notmuch new` printed
> >
> > A Xapian exception occurred creating a directory: Expected block
> > 485 to be level 1, not 0.
> >
> > I wasnt able to properly read the index anymore and had to
> > restore an old index dump. not cool!
> 
> 
> Can you provide any more information about this? The script properly
> uses atomic transactions. Any corruption here is the result of a
> notmuch library bug, which should be investigated.

i am kind of reluctant to reproduce this again (on my work-desktop).
All i did was start your script, writing to the index in another terminal in 
between (using alot)
possibly my cronjob fired a "notmuch new; afew.." in between also.
when I killed your script the index war broken.

Can i turn on some global logging for notmuch to debug this?
Maybe libnotmuch had trouble with so many db-writes at a time?

/p


-- next part --
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 198 bytes
Desc: signature
URL: 
<http://notmuchmail.org/pipermail/notmuch/attachments/20121211/254fef11/attachment.pgp>


Re: [PATCH 0/2] lib: Allow read-only messages to be synchronized to a writable database

2012-12-11 Thread Jameson Graef Rollins
On Mon, Dec 10 2012, Michael Forney  wrote:
>   lib: Replace freeze/thaw functionality with single sync function
>   lib: Allow synchronizing message changes with a separate database
> connection

Hi, Michael.  This series looks interesting but also too big for just
two patches.  I think it would be better to see the underlying
modifications to the lib in their own patches first, followed by patches
that fix the cli and the bindings.  I would make things much easier to
read.

jamie.


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


[PATCH 0/2] lib: Allow read-only messages to be synchronized to a writable database

2012-12-11 Thread Jameson Graef Rollins
On Mon, Dec 10 2012, Michael Forney  wrote:
>   lib: Replace freeze/thaw functionality with single sync function
>   lib: Allow synchronizing message changes with a separate database
> connection

Hi, Michael.  This series looks interesting but also too big for just
two patches.  I think it would be better to see the underlying
modifications to the lib in their own patches first, followed by patches
that fix the cli and the bindings.  I would make things much easier to
read.

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


Re: [PATCH v2 0/2] Add flush/reopen methods to notmuch_database_t

2012-12-11 Thread Michael Forney
On Thu, 18 Oct 2012 00:52:20 +0300, Adrien Bustany  wrote:
> The code of the patches in unchanged, but the formatting issues are now
> hopefully fixed.

I would like to bump this patch set. I also need these features from
libnotmuch. Currently there is no way to recover from Xapian errors,
which is pretty limiting.

If it is the flush/commit that is the issue, I would be happy to make an
updated patch set.

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


[PATCH v2 0/2] Add flush/reopen methods to notmuch_database_t

2012-12-11 Thread Michael Forney
On Thu, 18 Oct 2012 00:52:20 +0300, Adrien Bustany  
wrote:
> The code of the patches in unchanged, but the formatting issues are now
> hopefully fixed.

I would like to bump this patch set. I also need these features from
libnotmuch. Currently there is no way to recover from Xapian errors,
which is pretty limiting.

If it is the flush/commit that is the issue, I would be happy to make an
updated patch set.

-- 
Michael Forney 


notmuch python bindings corrupt db index (was: gmail importer script)

2012-12-11 Thread Jason A. Donenfeld
On Tue, Dec 11, 2012 at 11:04 AM, Patrick Totzke
 wrote:
> I ended up killing the process after i saw that ETA was >3h.

Gmail's bottleneck. Very unfortunate. Leave it going over night.

> This broke my index!
>
> afterwards, a `notmuch new` printed
>
> A Xapian exception occurred creating a directory: Expected block
> 485 to be level 1, not 0.
>
> I wasnt able to properly read the index anymore and had to
> restore an old index dump. not cool!


Can you provide any more information about this? The script properly
uses atomic transactions. Any corruption here is the result of a
notmuch library bug, which should be investigated.


Re: notmuch python bindings corrupt db index (was: gmail importer script)

2012-12-11 Thread Patrick Totzke
Quoting Jason A. Donenfeld (2012-12-11 13:47:32)
> On Tue, Dec 11, 2012 at 11:04 AM, Patrick Totzke
>  wrote:
> > I ended up killing the process after i saw that ETA was >3h.
> 
> Gmail's bottleneck. Very unfortunate. Leave it going over night.

OK, i assumed i'd not have to download all messages because i already have them
on disk -- synced via offlineimap. but then i remembered that OI stores uses
its own naming scheme for the files in a maildir. so thats probably why your 
script
did not realize theyre already there. (maybe it should? it could look up the 
MIDs from notmuch)

> > This broke my index!
> >
> > afterwards, a `notmuch new` printed
> >
> > A Xapian exception occurred creating a directory: Expected block
> > 485 to be level 1, not 0.
> >
> > I wasnt able to properly read the index anymore and had to
> > restore an old index dump. not cool!
> 
> 
> Can you provide any more information about this? The script properly
> uses atomic transactions. Any corruption here is the result of a
> notmuch library bug, which should be investigated.

i am kind of reluctant to reproduce this again (on my work-desktop).
All i did was start your script, writing to the index in another terminal in 
between (using alot)
possibly my cronjob fired a "notmuch new; afew.." in between also.
when I killed your script the index war broken.

Can i turn on some global logging for notmuch to debug this?
Maybe libnotmuch had trouble with so many db-writes at a time?

/p




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


gmail importer script

2012-12-11 Thread Jason A. Donenfeld
It seems to work, but i'm still waiting for the first run-through.

>
> Downloading messages: 457 of 22831|
>
> This takes ages. I hope it doesn't try to re-download all my messages
> everytime.
>

Nope. It's very smart about not doing that.


>
> Another thing:
> It seems that throughout its run, your script locks the notmuch database.
> This is particularly
> annoying if you want to read/tag mails while waiting for a long
> sync-process. I think you only
> really want to lock the index for a short time in the end.
> Do you write to the index directly after a msg is downloaded?
>

I tried to solve this by closing and opening the database each time, but it
actually reduced the performance considerably -- even slower than the gmail
download.
-- next part --
An HTML attachment was scrubbed...
URL: 
<http://notmuchmail.org/pipermail/notmuch/attachments/20121211/8268257c/attachment.html>


[PATCH] notmuch_message_file_get_header: use talloc for hash table entries

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

>
> On the other hand, as Tomi points out in id:m2a9tlfaza.fsf at 
> guru.guru-group.fi,
> Sometimes the string is allocated with with xmalloc.
>
> This patch tries to unify everything to use talloc.
>

This was meant to be in reply to id:m2a9tlfaza.fsf at guru.guru-group.fi,
but I fumbled it.



[PATCH] contrib: pick: bugfix for pick splitting the window excessively

2012-12-11 Thread David Bremner
Mark Walters  writes:

> Previously if you carried on past the last message in a pick view pick
> would get confused and `forget' about the split pane and would try and
> re-split when moving up again. This was due to faulty logic in
> notmuch-pick-show-message: something that should have been in the (when 
> message)
> clause was not.

Pushed, 

d


[PATCH v2 1/6] test: emacs: new tests "notmuch-show: {add, remove} multiple tags {to, from} single message"

2012-12-11 Thread David Bremner
Pieter Praet  writes:

> * test/emacs:
>
>   - Rename subtests "{Add,Remove} tag from notmuch-show view" to
> "notmuch-show: {add,remove} single tag {to,from} single message"
> to be consistent with the following tests.
>
>   - New subtest "notmuch-show: add multiple tags to single message":
> `notmuch-show-add-tag' ("+") can add multiple tags to a message.
>
>   - New subtest "notmuch-show: remove multiple tags from single message":
> `notmuch-show-remove-tag' ("-") can remove multiple tags from a message.

pushed this one test.

d


gmail importer script

2012-12-11 Thread Patrick Totzke
Quoting Jason A. Donenfeld (2012-12-11 09:12:56)
> It seems to work, but i'm still waiting for the first run-through.
> 
> 
> Downloading messages: 457 of 22831|
> 
> This takes ages. I hope it doesn't try to re-download all my messages
> everytime.
> 
> 
> Nope. It's very smart about not doing that.
> ?

hmmk

I ended up killing the process after i saw that ETA was >3h. This broke my 
index!
afterwards, a `notmuch new` printed 

A Xapian exception occurred creating a directory: Expected block
485 to be level 1, not 0.

I wasnt able to properly read the index anymore and had to
restore an old index dump. not cool!

/p


[PATCH 4/4] emacs: Add unit-tests for clickable tags

2012-12-11 Thread Damien Cassou
Signed-off-by: Damien Cassou 
---
 test/emacs |  103 
 1 file changed, 103 insertions(+)

diff --git a/test/emacs b/test/emacs
index 4e941bb..b7c5a93 100755
--- a/test/emacs
+++ b/test/emacs
@@ -840,5 +840,108 @@ test_emacs "(let ((mm-text-html-renderer
 test_expect_success "Rendering HTML mail with images" \
 'cat OUTPUT && grep -q smiley OUTPUT'

+test_begin_subtest "Extracting all tags from a thread"
+add_message \
+'[subject]="Extracting all tags from a thread"' \
+'[body]="body 1"'
+parent=${gen_msg_id}
+add_message \
+'[subject]="Extracting all tags from a thread"' \
+'[body]="body 2"' \
+"[in-reply-to]=\<$parent\>"
+add_message \
+'[subject]="Extracting all tags from a thread"' \
+'[body]="body 3"' \
+"[in-reply-to]=\<$parent\>"
+latest=${gen_msg_id}
+# Extract the thread-id from one of the emails
+thread_id=$(notmuch search --output=threads id:${latest})
+echo THREAD ID: '"'$thread_id'"'
+# Add tag "mytagfoo" to one of the emails
+notmuch tag +mytagfoo id:${latest}
+test_emacs_expect_t \
+"(notmuch-show \"${thread_id}\")
+ (let ((output (notmuch-show-thread-tags))
+   (expected '(\"inbox\" \"mytagfoo\" \"unread\")))
+  (notmuch-test-expect-equal
+ (sort output #'string<)
+ (sort expected #'string<)))"
+
+test_begin_subtest "The tags appear in the header-line of notmuch-show"
+add_message \
+'[subject]="foo bar"' \
+'[body]="body 1"'
+latest=${gen_msg_id}
+# Add tag "mytagfoo" to one of the emails
+notmuch tag +mytagfoo id:${latest}
+# Extract the thread-id from one of the emails
+thread_id=$(notmuch search --output=threads id:${latest})
+test_emacs_expect_t \
+"(notmuch-show \"${thread_id}\")
+ (if (string-match-p \"mytagfoo\" (format-mode-line header-line-format))
+ t
+   \"The tag 'mytagfoo' was not in the header-line-format\")"
+
+test_begin_subtest "The tags appear in the header-line of notmuch-show even 
after update"
+add_message \
+'[subject]="foo bar"' \
+'[body]="body 1"'
+latest=${gen_msg_id}
+# Extract the thread-id from one of the emails
+thread_id=$(notmuch search --output=threads id:${latest})
+test_emacs_expect_t \
+"(notmuch-show \"${thread_id}\")
+ (if (string-match-p \"mytagfoo\" (format-mode-line header-line-format))
+ (error \"There is no reason for 'mytagfoo' to be there.\"))
+ (notmuch-show-tag \"+mytagfoo\")
+ (if (string-match-p \"mytagfoo\" (format-mode-line header-line-format))
+ t
+   \"The tag 'mytagfoo' was not in the header-line-format\")"
+
+test_begin_subtest "The tags of notmuch-show emails are clickable"
+add_message \
+'[subject]="foo bar"' \
+'[body]="body 1"'
+latest=${gen_msg_id}
+# Add tag "mytagfoo" to one of the emails
+notmuch tag +mytagfoo id:${latest}
+# Extract the thread-id from one of the emails
+thread_id=$(notmuch search --output=threads id:${latest})
+test_emacs_expect_t \
+"(notmuch-show \"${thread_id}\")
+(goto-char (point-min))
+(re-search-forward \"mytagfoo\")
+(backward-char) ;; to be 'in' the tag
+(unless (eq major-mode 'notmuch-show-mode)
+   (error \"We must be in notmuch-show at this point but we are in %s.\" 
major-mode))
+(push-button) ;; simulate a press on the RET key
+(if (eq major-mode 'notmuch-search-mode)
+t
+   (format \"We must be in notmuch-search at this point but we are in 
%s.\" major-mode))"
+
+test_begin_subtest "The tags of notmuch-show emails are clickable even after 
update"
+add_message \
+'[subject]="foo bar"' \
+'[body]="body 1"'
+latest=${gen_msg_id}
+# Extract the thread-id from one of the emails
+thread_id=$(notmuch search --output=threads id:${latest})
+test_emacs_expect_t \
+"(notmuch-show \"${thread_id}\")
+(goto-char (point-min))
+(if (re-search-forward \"mytagfoo\" nil t)
+ (error \"There is no reason for 'mytagfoo' to be there.\"))
+(notmuch-show-tag \"+mytagfoo\")
+(goto-char (point-min))
+(unless (re-search-forward \"mytagfoo\" nil t)
+ (error \"The tag 'mytagfoo' must have been there.\"))
+(backward-char) ;; to be 'in' the tag
+(unless (eq major-mode 'notmuch-show-mode)
+   (error \"We must be in notmuch-show at this point but we are in %s.\" 
major-mode))
+(push-button) ;; simulate a press on the RET key
+(if (eq major-mode 'notmuch-search-mode)
+t
+   (format \"We must be in notmuch-search at this point but we are in 
%s.\" major-mode))"
+

 test_done
-- 
1.7.10.4



[PATCH 3/4] emacs: Make all tags in `notmuch-show' clickable

2012-12-11 Thread Damien Cassou
Signed-off-by: Damien Cassou 
---
 emacs/notmuch-show.el   |   15 +++
 emacs/notmuch-tagger.el |   33 +
 2 files changed, 40 insertions(+), 8 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index a71497a..93bce07 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -362,10 +362,8 @@ operation on the contents of the current buffer."
 (goto-char (notmuch-show-message-top))
 (if (re-search-forward "(\\([^()]*\\))$" (line-end-position) t)
(let ((inhibit-read-only t))
- (replace-match (concat "("
-(propertize (mapconcat 'identity tags " ")
-'face 'notmuch-tag-face)
-")")
+ (replace-match (propertize (notmuch-tagger-format-tags tags)
+'face 'notmuch-tag-face)
   (notmuch-show-update-header-line))

 (defun notmuch-clean-address (address)
@@ -442,10 +440,11 @@ message at DEPTH in the current thread."
(notmuch-show-clean-address (plist-get headers :From))
" ("
date
-   ") ("
-   (propertize (mapconcat 'identity tags " ")
-   'face 'notmuch-tag-face)
-   ")\n")
+   ") "
+   (propertize
+(notmuch-tagger-format-tags tags)
+'face 'notmuch-tag-face)
+   "\n")
 (overlay-put (make-overlay start (point)) 'face 
'notmuch-message-summary-face)))

 (defun notmuch-show-insert-header (header header-value)
diff --git a/emacs/notmuch-tagger.el b/emacs/notmuch-tagger.el
index 38b858a..35b81ca 100644
--- a/emacs/notmuch-tagger.el
+++ b/emacs/notmuch-tagger.el
@@ -44,12 +44,21 @@ test if the library is present before calling this 
function."
   (let ((tag (header-button-get button 'notmuch-tagger-tag)))
 (notmuch-tagger-goto-target tag)))

+(defun notmuch-tagger-body-button-action (button)
+  "Open `notmuch-search' for the tag referenced by BUTTON."
+  (let ((tag (button-get button 'notmuch-tagger-tag)))
+(notmuch-tagger-goto-target tag)))
+
 (eval-after-load "header-button"
   '(define-button-type 'notmuch-tagger-header-button-type
  'supertype 'header
  'action#'notmuch-tagger-header-button-action
  'follow-link t))

+(define-button-type 'notmuch-tagger-body-button-type
+  'action#'notmuch-tagger-body-button-action
+  'follow-link t)
+
 (defun notmuch-tagger-really-make-header-link (tag)
"Return a property list that presents a link to TAG.

@@ -73,6 +82,20 @@ if not."
   (notmuch-tagger-really-make-header-link tag)
 tag))

+(defun notmuch-tagger-make-body-link (tag)
+  "Return a property list that presents a link to TAG.
+The returned property list will not work in the header-line. For
+a link that works on the header-line, prefer
+`notmuch-tagger-make-header-link'."
+  (let ((button (copy-sequence tag)))
+(make-text-button
+ button nil
+ 'type 'notmuch-tagger-body-button-type
+ 'notmuch-tagger-tag tag
+ 'skip t ;; don't stop when using TAB
+ 'help-echo (format "%s: Search other messages like this" tag))
+button))
+
 (defun notmuch-tagger-format-tags-header-line (tags)
   "Format TAGS as a `mode-line-format' template.
 The result is suitable for inclusion in `header-line-format'."
@@ -83,5 +106,15 @@ The result is suitable for inclusion in 
`header-line-format'."
 " ")
")"))

+(defun notmuch-tagger-format-tags (tags)
+  "Format TAGS as a string suitable for insertion in a buffer.
+If the result of this function is to be used within the
+header-line, prefer `notmuch-tagger-format-tags-header-line'
+instead of this function."
+  (concat
+   "("
+   (mapconcat #'notmuch-tagger-make-body-link tags " ")
+   ")"))
+
 (provide 'notmuch-tagger)
 ;;; notmuch-tagger.el ends here
-- 
1.7.10.4



[PATCH 2/4] emacs: Make tags in notmuch-show header-line clickable

2012-12-11 Thread Damien Cassou
Signed-off-by: Damien Cassou 
---
 emacs/notmuch-tagger.el |   54 ++-
 1 file changed, 53 insertions(+), 1 deletion(-)

diff --git a/emacs/notmuch-tagger.el b/emacs/notmuch-tagger.el
index 6fcebff..38b858a 100644
--- a/emacs/notmuch-tagger.el
+++ b/emacs/notmuch-tagger.el
@@ -23,12 +23,64 @@
 ;;; Code:
 ;;

+(defun notmuch-tagger-header-button-present-p ()
+  "Check if `header-button' can be loaded or is already loaded.
+
+`header-button' is a third-party library which facilitates the
+creation of links in emacs header-line. This function tries to
+`require' `header-button' and returns nil if and only if this
+fails."
+  (require 'header-button nil t))
+
+(defun notmuch-tagger-goto-target (tag)
+  "Show a `notmuch-search' buffer for the TAG."
+  (notmuch-search (concat "tag:\"" tag "\"")))
+
+(defun notmuch-tagger-header-button-action (button)
+  "Open `notmuch-search' for the tag referenced by BUTTON.
+This function depends on the presence of the `header-button'
+library. Please call `notmuch-tagger-header-button-present-p' to
+test if the library is present before calling this function."
+  (let ((tag (header-button-get button 'notmuch-tagger-tag)))
+(notmuch-tagger-goto-target tag)))
+
+(eval-after-load "header-button"
+  '(define-button-type 'notmuch-tagger-header-button-type
+ 'supertype 'header
+ 'action#'notmuch-tagger-header-button-action
+ 'follow-link t))
+
+(defun notmuch-tagger-really-make-header-link (tag)
+   "Return a property list that presents a link to TAG.
+
+The returned property list will only work in the header-line.
+Additionally, this function depends on the presence of the
+`header-button' library. Please call
+`notmuch-tagger-header-button-present-p' to test if library is
+present before calling this function."
+   (header-button-format
+tag
+:type 'notmuch-tagger-header-button-type
+'notmuch-tagger-tag tag
+'help-echo (format "%s: Search other messages like this" tag)))
+
+(defun notmuch-tagger-make-header-link (tag)
+  "Return a property list to present TAG as a link to search.
+
+This only works if `header-button' is loaded. Simply returns tag
+if not."
+  (if (notmuch-tagger-header-button-present-p)
+  (notmuch-tagger-really-make-header-link tag)
+tag))
+
 (defun notmuch-tagger-format-tags-header-line (tags)
   "Format TAGS as a `mode-line-format' template.
 The result is suitable for inclusion in `header-line-format'."
   (list
"("
-   (notmuch-intersperse tags " ")
+   (notmuch-intersperse
+(mapcar #'notmuch-tagger-make-header-link tags)
+" ")
")"))

 (provide 'notmuch-tagger)
-- 
1.7.10.4



[PATCH 1/4] emacs: Add a thread's tags to notmuch-show header-line

2012-12-11 Thread Damien Cassou
Signed-off-by: Damien Cassou 
---
 emacs/notmuch-lib.el|   11 +--
 emacs/notmuch-show.el   |   27 +++
 emacs/notmuch-tagger.el |   35 +++
 3 files changed, 67 insertions(+), 6 deletions(-)
 create mode 100644 emacs/notmuch-tagger.el

diff --git a/emacs/notmuch-lib.el b/emacs/notmuch-lib.el
index 9c4ee71..3541bb7 100644
--- a/emacs/notmuch-lib.el
+++ b/emacs/notmuch-lib.el
@@ -603,8 +603,15 @@ left it."
 ;; Clear out what we've parsed
 (delete-region (point-min) (point

-
-
+(defun notmuch-intersperse (list sep)
+  "Return a list with all elements of LIST separated by SEP."
+  (let ((first t)
+(res nil))
+(dolist (elt list (nreverse res))
+  (unless first
+(push sep res))
+  (setq first nil)
+  (push elt res

 (provide 'notmuch-lib)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 7d9f8a9..a71497a 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -36,6 +36,7 @@
 (require 'notmuch-mua)
 (require 'notmuch-crypto)
 (require 'notmuch-print)
+(require 'notmuch-tagger)

 (declare-function notmuch-call-notmuch-process "notmuch" (&rest args))
 (declare-function notmuch-fontify-headers "notmuch" nil)
@@ -364,7 +365,8 @@ operation on the contents of the current buffer."
  (replace-match (concat "("
 (propertize (mapconcat 'identity tags " ")
 'face 'notmuch-tag-face)
-")"))
+")")
+  (notmuch-show-update-header-line))

 (defun notmuch-clean-address (address)
   "Try to clean a single email ADDRESS for display. Return a cons
@@ -1136,11 +1138,28 @@ function is used."

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

-  ;; Set the header line to the subject of the first message.
-  (setq header-line-format (notmuch-show-strip-re 
(notmuch-show-get-subject)))
-
+  (notmuch-show-update-header-line)
   (run-hooks 'notmuch-show-hook

+(defun notmuch-show-thread-tags ()
+  "Return the list of tags for the current thread."
+  (let ((tags (list)))
+(notmuch-show-mapc (lambda ()
+(mapcar (lambda (elt)
+  ;; Avoid adding duplicate tags
+  (add-to-list 'tags elt))
+(notmuch-show-get-tags
+tags))
+
+(defun notmuch-show-update-header-line ()
+  "Make the header-line show the thread's subject and tags."
+  (let ((thread-subject (notmuch-show-strip-re (notmuch-show-get-subject
+(setq header-line-format
+ (list
+  thread-subject
+  " "
+  (notmuch-tagger-format-tags-header-line 
(notmuch-show-thread-tags))
+
 (defun notmuch-show-capture-state ()
   "Capture the state of the current buffer.

diff --git a/emacs/notmuch-tagger.el b/emacs/notmuch-tagger.el
new file mode 100644
index 000..6fcebff
--- /dev/null
+++ b/emacs/notmuch-tagger.el
@@ -0,0 +1,35 @@
+;; notmuch-tagger.el --- Library to improve the way tags are displayed
+;;
+;; Copyright ? Damien Cassou
+;;
+;; This file is part of Notmuch.
+;;
+;; Notmuch is free software: you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Notmuch is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Notmuch.  If not, see .
+;;
+;; Authors: Damien Cassou 
+;;; Commentary:
+;;
+;;; Code:
+;;
+
+(defun notmuch-tagger-format-tags-header-line (tags)
+  "Format TAGS as a `mode-line-format' template.
+The result is suitable for inclusion in `header-line-format'."
+  (list
+   "("
+   (notmuch-intersperse tags " ")
+   ")"))
+
+(provide 'notmuch-tagger)
+;;; notmuch-tagger.el ends here
-- 
1.7.10.4



No subject

2012-12-11 Thread Damien Cassou
From: Damien Cassou 
Subject: [PATCH v4] emacs: display tags in notmuch-show with links
In-Reply-To: 

This patch obsoletes:
id:1355149964-27905-1-git-send-email-damien.cassou at gmail.com

[PATCH 1/4] emacs: Add a thread's tags to notmuch-show header-line
[PATCH 2/4] emacs: Make tags in notmuch-show header-line clickable
[PATCH 3/4] emacs: Make all tags in `notmuch-show' clickable
[PATCH 4/4] emacs: Add unit-tests for clickable tags

These patches make clickable all tags that appear in notmuch-show
buffers. Each tag is a link to open a new notmuch-search buffer for
this tag. Additionally, the buffer's header-line now shows the
thread's tags (clickable only if the `header-button' library is loaded
or loadable).

These patches are the first of an upcoming series whose goal is to
integrate notmuch-labeler into notmuch. See the following for more
details: https://github.com/DamienCassou/notmuch-labeler

With respect to v3, I took care of the comments you made:
- the header-line now updates when tags are changed
- the tags in the body stays clickable when tags are changed

Additionally, I added two unit tests to cover the above two comments
and fixed some others unit tests of mine.


[PATCH] notmuch_message_file_get_header: use talloc for hash table entries

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

Before this patch there is some strange mix of malloc/free and
g_malloc/g_free.  In particular, the pointer returned by
g_mime_utils_header_decode_text is from the following line in
rfc2047_decode_tokens

return g_string_free (decoded, FALSE);

The docs for g_string_free say

 Frees the memory allocated for the GString. If free_segment is TRUE
 it also frees the character data. If it's FALSE, the caller gains
 ownership of the buffer and must free it after use with g_free().

On the other hand, as Tomi points out in id:m2a9tlfaza.fsf at 
guru.guru-group.fi,
Sometimes the string is allocated with with xmalloc.

This patch tries to unify everything to use talloc.

Because of difficulties in error handling in a callback, we defer
deallocation of hash entries to when the parent context (the message)
is destroyed.

The function talloc_str_from_g might be overkill; it is currently only
used once.
---
 lib/message-file.c |   35 +--
 1 file changed, 25 insertions(+), 10 deletions(-)

diff --git a/lib/message-file.c b/lib/message-file.c
index 915aba8..f84e929 100644
--- a/lib/message-file.c
+++ b/lib/message-file.c
@@ -73,6 +73,15 @@ strcase_hash (const void *ptr)
 return hash;
 }

+static inline
+char *talloc_str_from_g (void *ctx, char *str)
+{
+char *dup = talloc_strdup (ctx, str);
+g_free(str);
+
+return dup;
+}
+
 static int
 _notmuch_message_file_destructor (notmuch_message_file_t *message)
 {
@@ -108,10 +117,13 @@ _notmuch_message_file_open_ctx (void *ctx, const char 
*filename)
 if (message->file == NULL)
goto FAIL;

+/* We choose not to pass talloc_free (or some wrapper), because we have no
+ * good way of dealing with its failure condition.
+ */
 message->headers = g_hash_table_new_full (strcase_hash,
  strcase_equal,
- free,
- free);
+ NULL,
+ NULL);

 message->parsing_started = 0;
 message->parsing_finished = 0;
@@ -151,7 +163,7 @@ notmuch_message_file_restrict_headersv 
(notmuch_message_file_t *message,
if (header == NULL)
break;
g_hash_table_insert (message->headers,
-xstrdup (header), NULL);
+talloc_strdup (message, header), NULL);
 }

 message->restrict_headers = 1;
@@ -299,13 +311,13 @@ notmuch_message_file_get_header (notmuch_message_file_t 
*message,

message->good_headers++;

-   header = xstrndup (message->line, colon - message->line);
+   header = talloc_strndup (message, message->line, colon - message->line);

if (message->restrict_headers &&
! g_hash_table_lookup_extended (message->headers,
header, NULL, NULL))
{
-   free (header);
+   talloc_free (header);
NEXT_HEADER_LINE (NULL);
continue;
}
@@ -324,7 +336,10 @@ notmuch_message_file_get_header (notmuch_message_file_t 
*message,
else
match = (strcasecmp (header, header_desired) == 0);

-   decoded_value = g_mime_utils_header_decode_text (message->value.str);
+   decoded_value =
+   talloc_str_from_g (message,
+  g_mime_utils_header_decode_text 
(message->value.str));
+
header_sofar = (char *)g_hash_table_lookup (message->headers, header);
/* we treat the Received: header special - we want to concat ALL of 
 * the Received: headers we encounter.
@@ -337,11 +352,11 @@ notmuch_message_file_get_header (notmuch_message_file_t 
*message,
/* we need to add the header to those we already collected */
newhdr = strlen(decoded_value);
hdrsofar = strlen(header_sofar);
-   combined_header = xmalloc(hdrsofar + newhdr + 2);
+   combined_header = talloc_size (message, hdrsofar + newhdr + 2);
strncpy(combined_header,header_sofar,hdrsofar);
*(combined_header+hdrsofar) = ' ';
strncpy(combined_header+hdrsofar+1,decoded_value,newhdr+1);
-   free (decoded_value);
+   talloc_free (decoded_value);
g_hash_table_insert (message->headers, header, combined_header);
}
} else {
@@ -349,8 +364,8 @@ notmuch_message_file_get_header (notmuch_message_file_t 
*message,
/* Only insert if we don't have a value for this header, yet. */
g_hash_table_insert (message->headers, header, decoded_value);
} else {
-   free (header);
-   free (decoded_value);
+   talloc_free (header);
+   talloc_free (decoded_value);
decoded_value = header_sofar;
}
}
-

gmail importer script

2012-12-11 Thread Patrick Totzke
Quoting Jason A. Donenfeld (2012-12-11 07:06:22)
> On Mon, Dec 10, 2012 at 6:46 PM, Jason A. Donenfeld  
> wrote:
> 
> 
> 
> On Mon, Dec 10, 2012 at 10:41 AM, Patrick Totzke  gmail.com>
> wrote:
> 
> It would, but its nicer not to load ressources you're not gonna use.
> Also, progressbar 2.2 seems to be the newest version you see on a
> reasonably new debian/ubuntu install.. 
> 
> 
> I'll consider it.
> 
> 
> --silent or -s now silences stdout.

It seems to work, but i'm still waiting for the first run-through.

Downloading messages: 457 of 22831|

This takes ages. I hope it doesn't try to re-download all my messages everytime.

Another thing:
It seems that throughout its run, your script locks the notmuch database. This 
is particularly
annoying if you want to read/tag mails while waiting for a long sync-process. I 
think you only
really want to lock the index for a short time in the end.
Do you write to the index directly after a msg is downloaded?

/p


gmail importer script

2012-12-11 Thread Jason A. Donenfeld
On Mon, Dec 10, 2012 at 6:46 PM, Jason A. Donenfeld  wrote:

>
>
> On Mon, Dec 10, 2012 at 10:41 AM, Patrick Totzke  gmail.com>wrote:
>>
>> It would, but its nicer not to load ressources you're not gonna use.
>> Also, progressbar 2.2 seems to be the newest version you see on a
>> reasonably new debian/ubuntu install.. 
>>
>
> I'll consider it.
>

--silent or -s now silences stdout.
-- next part --
An HTML attachment was scrubbed...
URL: 
<http://notmuchmail.org/pipermail/notmuch/attachments/20121211/3f915dd6/attachment.html>


[PATCH] _notmuch_message_index_file: unref (free) address lists from gmime.

2012-12-11 Thread Tomi Ollila
On Tue, Dec 11 2012, david at tethera.net wrote:

> From: David Bremner 
>
> Apparently as of GMime 2.4, you don't need to call
> internet_address_list_destroy anymore, but you still need to call
> g_object_unref (from the GMime Changelog).
>
> On the medium performance corpus, valgrind shows "possibly lost"
> leakage in "notmuch new" dropping from 7M to 300k.
> ---

LGTM.

Tomi


>  lib/index.cc |   12 +---
>  1 file changed, 9 insertions(+), 3 deletions(-)
>
> diff --git a/lib/index.cc b/lib/index.cc
> index da0e6ce..a2edd6d 100644
> --- a/lib/index.cc
> +++ b/lib/index.cc
> @@ -484,12 +484,18 @@ mboxes is deprecated and may be removed in the 
> future.\n", filename);
>  }
>  
>  from = g_mime_message_get_sender (mime_message);
> -addresses = internet_address_list_parse_string (from);
>  
> -_index_address_list (message, "from", addresses);
> +addresses = internet_address_list_parse_string (from);
> +if (addresses) {
> + _index_address_list (message, "from", addresses);
> + g_object_unref (addresses);
> +}
>  
>  addresses = g_mime_message_get_all_recipients (mime_message);
> -_index_address_list (message, "to", addresses);
> +if (addresses) {
> + _index_address_list (message, "to", addresses);
> + g_object_unref (addresses);
> +}
>  
>  subject = g_mime_message_get_subject (mime_message);
>  _notmuch_message_gen_terms (message, "subject", subject);
> -- 
> 1.7.10.4
>
> ___
> notmuch mailing list
> notmuch at notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH] notmuch_message_file_get_header: replace free with g_free

2012-12-11 Thread Tomi Ollila
On Tue, Dec 11 2012, david at tethera.net wrote:

> From: David Bremner 
>
> The pointer returned by g_mime_utils_header_decode_text is from the
> following line in rfc2047_decode_tokens
>
>   return g_string_free (decoded, FALSE);
>
> The docs for g_string_free say
>
>  Frees the memory allocated for the GString. If free_segment is TRUE
>  it also frees the character data. If it's FALSE, the caller gains
>  ownership of the buffer and must free it after use with g_free().
> ---

There is still some problem left: in the contex one can see the following
calls:

   g_hash_table_insert (message->headers, header, decoded_value);

and then

   combined_header = xmalloc(hdrsofar + newhdr + 2);
   strncpy(combined_header,header_sofar,hdrsofar);
   *(combined_header+hdrsofar) = ' ';
   strncpy(combined_header+hdrsofar+1,decoded_value,newhdr+1);
   g_free (decoded_value);
   g_hash_table_insert (message->headers, header, combined_header);

Now, decoded_value should always be freed with g_free() and combined_header
with free(), note also that the hash table is initialized with:

   message->headers = g_hash_table_new_full (strcase_hash,
 strcase_equal,
 free,
 free);

i.e. finally the allocated string is freed with free() (in case
we're freeing... I did not look so far...).

Maybe all allocations and frees in the values of this header hash table
should be converted to use g_ -functions ? (or start to use talloc contex
there)


Tomi





>  lib/message-file.c |4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/lib/message-file.c b/lib/message-file.c
> index 915aba8..976769d 100644
> --- a/lib/message-file.c
> +++ b/lib/message-file.c
> @@ -341,7 +341,7 @@ notmuch_message_file_get_header (notmuch_message_file_t 
> *message,
>   strncpy(combined_header,header_sofar,hdrsofar);
>   *(combined_header+hdrsofar) = ' ';
>   strncpy(combined_header+hdrsofar+1,decoded_value,newhdr+1);
> - free (decoded_value);
> + g_free (decoded_value);
>   g_hash_table_insert (message->headers, header, combined_header);
>   }
>   } else {
> @@ -350,7 +350,7 @@ notmuch_message_file_get_header (notmuch_message_file_t 
> *message,
>   g_hash_table_insert (message->headers, header, decoded_value);
>   } else {
>   free (header);
> - free (decoded_value);
> + g_free (decoded_value);
>   decoded_value = header_sofar;
>   }
>   }
> -- 
> 1.7.10.4
>
> ___
> notmuch mailing list
> notmuch at notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH] notmuch_message_file_get_header: use talloc for hash table entries

2012-12-11 Thread David Bremner
da...@tethera.net writes:

>
> On the other hand, as Tomi points out in id:m2a9tlfaza@guru.guru-group.fi,
> Sometimes the string is allocated with with xmalloc.
>
> This patch tries to unify everything to use talloc.
>

This was meant to be in reply to id:m2a9tlfaza@guru.guru-group.fi,
but I fumbled it.

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


Re: [PATCH] contrib: pick: bugfix for pick splitting the window excessively

2012-12-11 Thread David Bremner
Mark Walters  writes:

> Previously if you carried on past the last message in a pick view pick
> would get confused and `forget' about the split pane and would try and
> re-split when moving up again. This was due to faulty logic in
> notmuch-pick-show-message: something that should have been in the (when 
> message)
> clause was not.

Pushed, 

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


Re: [PATCH v2 1/6] test: emacs: new tests "notmuch-show: {add, remove} multiple tags {to, from} single message"

2012-12-11 Thread David Bremner
Pieter Praet  writes:

> * test/emacs:
>
>   - Rename subtests "{Add,Remove} tag from notmuch-show view" to
> "notmuch-show: {add,remove} single tag {to,from} single message"
> to be consistent with the following tests.
>
>   - New subtest "notmuch-show: add multiple tags to single message":
> `notmuch-show-add-tag' ("+") can add multiple tags to a message.
>
>   - New subtest "notmuch-show: remove multiple tags from single message":
> `notmuch-show-remove-tag' ("-") can remove multiple tags from a message.

pushed this one test.

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


[PATCH] notmuch_message_file_get_header: use talloc for hash table entries

2012-12-11 Thread david
From: David Bremner 

Before this patch there is some strange mix of malloc/free and
g_malloc/g_free.  In particular, the pointer returned by
g_mime_utils_header_decode_text is from the following line in
rfc2047_decode_tokens

return g_string_free (decoded, FALSE);

The docs for g_string_free say

 Frees the memory allocated for the GString. If free_segment is TRUE
 it also frees the character data. If it's FALSE, the caller gains
 ownership of the buffer and must free it after use with g_free().

On the other hand, as Tomi points out in id:m2a9tlfaza@guru.guru-group.fi,
Sometimes the string is allocated with with xmalloc.

This patch tries to unify everything to use talloc.

Because of difficulties in error handling in a callback, we defer
deallocation of hash entries to when the parent context (the message)
is destroyed.

The function talloc_str_from_g might be overkill; it is currently only
used once.
---
 lib/message-file.c |   35 +--
 1 file changed, 25 insertions(+), 10 deletions(-)

diff --git a/lib/message-file.c b/lib/message-file.c
index 915aba8..f84e929 100644
--- a/lib/message-file.c
+++ b/lib/message-file.c
@@ -73,6 +73,15 @@ strcase_hash (const void *ptr)
 return hash;
 }
 
+static inline
+char *talloc_str_from_g (void *ctx, char *str)
+{
+char *dup = talloc_strdup (ctx, str);
+g_free(str);
+
+return dup;
+}
+
 static int
 _notmuch_message_file_destructor (notmuch_message_file_t *message)
 {
@@ -108,10 +117,13 @@ _notmuch_message_file_open_ctx (void *ctx, const char 
*filename)
 if (message->file == NULL)
goto FAIL;
 
+/* We choose not to pass talloc_free (or some wrapper), because we have no
+ * good way of dealing with its failure condition.
+ */
 message->headers = g_hash_table_new_full (strcase_hash,
  strcase_equal,
- free,
- free);
+ NULL,
+ NULL);
 
 message->parsing_started = 0;
 message->parsing_finished = 0;
@@ -151,7 +163,7 @@ notmuch_message_file_restrict_headersv 
(notmuch_message_file_t *message,
if (header == NULL)
break;
g_hash_table_insert (message->headers,
-xstrdup (header), NULL);
+talloc_strdup (message, header), NULL);
 }
 
 message->restrict_headers = 1;
@@ -299,13 +311,13 @@ notmuch_message_file_get_header (notmuch_message_file_t 
*message,
 
message->good_headers++;
 
-   header = xstrndup (message->line, colon - message->line);
+   header = talloc_strndup (message, message->line, colon - message->line);
 
if (message->restrict_headers &&
! g_hash_table_lookup_extended (message->headers,
header, NULL, NULL))
{
-   free (header);
+   talloc_free (header);
NEXT_HEADER_LINE (NULL);
continue;
}
@@ -324,7 +336,10 @@ notmuch_message_file_get_header (notmuch_message_file_t 
*message,
else
match = (strcasecmp (header, header_desired) == 0);
 
-   decoded_value = g_mime_utils_header_decode_text (message->value.str);
+   decoded_value =
+   talloc_str_from_g (message,
+  g_mime_utils_header_decode_text 
(message->value.str));
+
header_sofar = (char *)g_hash_table_lookup (message->headers, header);
/* we treat the Received: header special - we want to concat ALL of 
 * the Received: headers we encounter.
@@ -337,11 +352,11 @@ notmuch_message_file_get_header (notmuch_message_file_t 
*message,
/* we need to add the header to those we already collected */
newhdr = strlen(decoded_value);
hdrsofar = strlen(header_sofar);
-   combined_header = xmalloc(hdrsofar + newhdr + 2);
+   combined_header = talloc_size (message, hdrsofar + newhdr + 2);
strncpy(combined_header,header_sofar,hdrsofar);
*(combined_header+hdrsofar) = ' ';
strncpy(combined_header+hdrsofar+1,decoded_value,newhdr+1);
-   free (decoded_value);
+   talloc_free (decoded_value);
g_hash_table_insert (message->headers, header, combined_header);
}
} else {
@@ -349,8 +364,8 @@ notmuch_message_file_get_header (notmuch_message_file_t 
*message,
/* Only insert if we don't have a value for this header, yet. */
g_hash_table_insert (message->headers, header, decoded_value);
} else {
-   free (header);
-   free (decoded_value);
+   talloc_free (header);
+   talloc_free (decoded_value);
decoded_value = header_sofar;
}
   

notmuch python bindings corrupt db index (was: gmail importer script)

2012-12-11 Thread Jason A. Donenfeld
On Tue, Dec 11, 2012 at 11:04 AM, Patrick Totzke
 wrote:
> I ended up killing the process after i saw that ETA was >3h.

Gmail's bottleneck. Very unfortunate. Leave it going over night.

> This broke my index!
>
> afterwards, a `notmuch new` printed
>
> A Xapian exception occurred creating a directory: Expected block
> 485 to be level 1, not 0.
>
> I wasnt able to properly read the index anymore and had to
> restore an old index dump. not cool!


Can you provide any more information about this? The script properly
uses atomic transactions. Any corruption here is the result of a
notmuch library bug, which should be investigated.
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: gmail importer script

2012-12-11 Thread Patrick Totzke
Quoting Jason A. Donenfeld (2012-12-11 09:12:56)
> It seems to work, but i'm still waiting for the first run-through.
> 
> 
> Downloading messages: 457 of 22831|
> 
> This takes ages. I hope it doesn't try to re-download all my messages
> everytime.
> 
> 
> Nope. It's very smart about not doing that.
>  

hmmk

I ended up killing the process after i saw that ETA was >3h. This broke my 
index!
afterwards, a `notmuch new` printed 

A Xapian exception occurred creating a directory: Expected block
485 to be level 1, not 0.

I wasnt able to properly read the index anymore and had to
restore an old index dump. not cool!

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


Re: gmail importer script

2012-12-11 Thread Jason A. Donenfeld
It seems to work, but i'm still waiting for the first run-through.

>
> Downloading messages: 457 of 22831|
>
> This takes ages. I hope it doesn't try to re-download all my messages
> everytime.
>

Nope. It's very smart about not doing that.


>
> Another thing:
> It seems that throughout its run, your script locks the notmuch database.
> This is particularly
> annoying if you want to read/tag mails while waiting for a long
> sync-process. I think you only
> really want to lock the index for a short time in the end.
> Do you write to the index directly after a msg is downloaded?
>

I tried to solve this by closing and opening the database each time, but it
actually reduced the performance considerably -- even slower than the gmail
download.
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: gmail importer script

2012-12-11 Thread Patrick Totzke
Quoting Jason A. Donenfeld (2012-12-11 07:06:22)
> On Mon, Dec 10, 2012 at 6:46 PM, Jason A. Donenfeld  wrote:
> 
> 
> 
> On Mon, Dec 10, 2012 at 10:41 AM, Patrick Totzke 
> wrote:
> 
> It would, but its nicer not to load ressources you're not gonna use.
> Also, progressbar 2.2 seems to be the newest version you see on a
> reasonably new debian/ubuntu install.. 
> 
> 
> I'll consider it.
> 
> 
> --silent or -s now silences stdout.

It seems to work, but i'm still waiting for the first run-through.

Downloading messages: 457 of 22831|

This takes ages. I hope it doesn't try to re-download all my messages everytime.

Another thing:
It seems that throughout its run, your script locks the notmuch database. This 
is particularly
annoying if you want to read/tag mails while waiting for a long sync-process. I 
think you only
really want to lock the index for a short time in the end.
Do you write to the index directly after a msg is downloaded?

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


[PATCH 4/4] emacs: Add unit-tests for clickable tags

2012-12-11 Thread Damien Cassou
Signed-off-by: Damien Cassou 
---
 test/emacs |  103 
 1 file changed, 103 insertions(+)

diff --git a/test/emacs b/test/emacs
index 4e941bb..b7c5a93 100755
--- a/test/emacs
+++ b/test/emacs
@@ -840,5 +840,108 @@ test_emacs "(let ((mm-text-html-renderer
 test_expect_success "Rendering HTML mail with images" \
 'cat OUTPUT && grep -q smiley OUTPUT'
 
+test_begin_subtest "Extracting all tags from a thread"
+add_message \
+'[subject]="Extracting all tags from a thread"' \
+'[body]="body 1"'
+parent=${gen_msg_id}
+add_message \
+'[subject]="Extracting all tags from a thread"' \
+'[body]="body 2"' \
+"[in-reply-to]=\<$parent\>"
+add_message \
+'[subject]="Extracting all tags from a thread"' \
+'[body]="body 3"' \
+"[in-reply-to]=\<$parent\>"
+latest=${gen_msg_id}
+# Extract the thread-id from one of the emails
+thread_id=$(notmuch search --output=threads id:${latest})
+echo THREAD ID: '"'$thread_id'"'
+# Add tag "mytagfoo" to one of the emails
+notmuch tag +mytagfoo id:${latest}
+test_emacs_expect_t \
+"(notmuch-show \"${thread_id}\")
+ (let ((output (notmuch-show-thread-tags))
+   (expected '(\"inbox\" \"mytagfoo\" \"unread\")))
+  (notmuch-test-expect-equal
+ (sort output #'string<)
+ (sort expected #'string<)))"
+
+test_begin_subtest "The tags appear in the header-line of notmuch-show"
+add_message \
+'[subject]="foo bar"' \
+'[body]="body 1"'
+latest=${gen_msg_id}
+# Add tag "mytagfoo" to one of the emails
+notmuch tag +mytagfoo id:${latest}
+# Extract the thread-id from one of the emails
+thread_id=$(notmuch search --output=threads id:${latest})
+test_emacs_expect_t \
+"(notmuch-show \"${thread_id}\")
+ (if (string-match-p \"mytagfoo\" (format-mode-line header-line-format))
+ t
+   \"The tag 'mytagfoo' was not in the header-line-format\")"
+
+test_begin_subtest "The tags appear in the header-line of notmuch-show even 
after update"
+add_message \
+'[subject]="foo bar"' \
+'[body]="body 1"'
+latest=${gen_msg_id}
+# Extract the thread-id from one of the emails
+thread_id=$(notmuch search --output=threads id:${latest})
+test_emacs_expect_t \
+"(notmuch-show \"${thread_id}\")
+ (if (string-match-p \"mytagfoo\" (format-mode-line header-line-format))
+ (error \"There is no reason for 'mytagfoo' to be there.\"))
+ (notmuch-show-tag \"+mytagfoo\")
+ (if (string-match-p \"mytagfoo\" (format-mode-line header-line-format))
+ t
+   \"The tag 'mytagfoo' was not in the header-line-format\")"
+
+test_begin_subtest "The tags of notmuch-show emails are clickable"
+add_message \
+'[subject]="foo bar"' \
+'[body]="body 1"'
+latest=${gen_msg_id}
+# Add tag "mytagfoo" to one of the emails
+notmuch tag +mytagfoo id:${latest}
+# Extract the thread-id from one of the emails
+thread_id=$(notmuch search --output=threads id:${latest})
+test_emacs_expect_t \
+"(notmuch-show \"${thread_id}\")
+(goto-char (point-min))
+(re-search-forward \"mytagfoo\")
+(backward-char) ;; to be 'in' the tag
+(unless (eq major-mode 'notmuch-show-mode)
+   (error \"We must be in notmuch-show at this point but we are in %s.\" 
major-mode))
+(push-button) ;; simulate a press on the RET key
+(if (eq major-mode 'notmuch-search-mode)
+t
+   (format \"We must be in notmuch-search at this point but we are in 
%s.\" major-mode))"
+
+test_begin_subtest "The tags of notmuch-show emails are clickable even after 
update"
+add_message \
+'[subject]="foo bar"' \
+'[body]="body 1"'
+latest=${gen_msg_id}
+# Extract the thread-id from one of the emails
+thread_id=$(notmuch search --output=threads id:${latest})
+test_emacs_expect_t \
+"(notmuch-show \"${thread_id}\")
+(goto-char (point-min))
+(if (re-search-forward \"mytagfoo\" nil t)
+ (error \"There is no reason for 'mytagfoo' to be there.\"))
+(notmuch-show-tag \"+mytagfoo\")
+(goto-char (point-min))
+(unless (re-search-forward \"mytagfoo\" nil t)
+ (error \"The tag 'mytagfoo' must have been there.\"))
+(backward-char) ;; to be 'in' the tag
+(unless (eq major-mode 'notmuch-show-mode)
+   (error \"We must be in notmuch-show at this point but we are in %s.\" 
major-mode))
+(push-button) ;; simulate a press on the RET key
+(if (eq major-mode 'notmuch-search-mode)
+t
+   (format \"We must be in notmuch-search at this point but we are in 
%s.\" major-mode))"
+
 
 test_done
-- 
1.7.10.4

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


[PATCH 1/4] emacs: Add a thread's tags to notmuch-show header-line

2012-12-11 Thread Damien Cassou
Signed-off-by: Damien Cassou 
---
 emacs/notmuch-lib.el|   11 +--
 emacs/notmuch-show.el   |   27 +++
 emacs/notmuch-tagger.el |   35 +++
 3 files changed, 67 insertions(+), 6 deletions(-)
 create mode 100644 emacs/notmuch-tagger.el

diff --git a/emacs/notmuch-lib.el b/emacs/notmuch-lib.el
index 9c4ee71..3541bb7 100644
--- a/emacs/notmuch-lib.el
+++ b/emacs/notmuch-lib.el
@@ -603,8 +603,15 @@ left it."
 ;; Clear out what we've parsed
 (delete-region (point-min) (point
 
-
-
+(defun notmuch-intersperse (list sep)
+  "Return a list with all elements of LIST separated by SEP."
+  (let ((first t)
+(res nil))
+(dolist (elt list (nreverse res))
+  (unless first
+(push sep res))
+  (setq first nil)
+  (push elt res
 
 (provide 'notmuch-lib)
 
diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 7d9f8a9..a71497a 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -36,6 +36,7 @@
 (require 'notmuch-mua)
 (require 'notmuch-crypto)
 (require 'notmuch-print)
+(require 'notmuch-tagger)
 
 (declare-function notmuch-call-notmuch-process "notmuch" (&rest args))
 (declare-function notmuch-fontify-headers "notmuch" nil)
@@ -364,7 +365,8 @@ operation on the contents of the current buffer."
  (replace-match (concat "("
 (propertize (mapconcat 'identity tags " ")
 'face 'notmuch-tag-face)
-")"))
+")")
+  (notmuch-show-update-header-line))
 
 (defun notmuch-clean-address (address)
   "Try to clean a single email ADDRESS for display. Return a cons
@@ -1136,11 +1138,28 @@ function is used."
 
   (jit-lock-register #'notmuch-show-buttonise-links)
 
-  ;; Set the header line to the subject of the first message.
-  (setq header-line-format (notmuch-show-strip-re 
(notmuch-show-get-subject)))
-
+  (notmuch-show-update-header-line)
   (run-hooks 'notmuch-show-hook
 
+(defun notmuch-show-thread-tags ()
+  "Return the list of tags for the current thread."
+  (let ((tags (list)))
+(notmuch-show-mapc (lambda ()
+(mapcar (lambda (elt)
+  ;; Avoid adding duplicate tags
+  (add-to-list 'tags elt))
+(notmuch-show-get-tags
+tags))
+
+(defun notmuch-show-update-header-line ()
+  "Make the header-line show the thread's subject and tags."
+  (let ((thread-subject (notmuch-show-strip-re (notmuch-show-get-subject
+(setq header-line-format
+ (list
+  thread-subject
+  " "
+  (notmuch-tagger-format-tags-header-line 
(notmuch-show-thread-tags))
+
 (defun notmuch-show-capture-state ()
   "Capture the state of the current buffer.
 
diff --git a/emacs/notmuch-tagger.el b/emacs/notmuch-tagger.el
new file mode 100644
index 000..6fcebff
--- /dev/null
+++ b/emacs/notmuch-tagger.el
@@ -0,0 +1,35 @@
+;; notmuch-tagger.el --- Library to improve the way tags are displayed
+;;
+;; Copyright © Damien Cassou
+;;
+;; This file is part of Notmuch.
+;;
+;; Notmuch is free software: you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Notmuch is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Notmuch.  If not, see .
+;;
+;; Authors: Damien Cassou 
+;;; Commentary:
+;;
+;;; Code:
+;;
+
+(defun notmuch-tagger-format-tags-header-line (tags)
+  "Format TAGS as a `mode-line-format' template.
+The result is suitable for inclusion in `header-line-format'."
+  (list
+   "("
+   (notmuch-intersperse tags " ")
+   ")"))
+
+(provide 'notmuch-tagger)
+;;; notmuch-tagger.el ends here
-- 
1.7.10.4

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


[PATCH 3/4] emacs: Make all tags in `notmuch-show' clickable

2012-12-11 Thread Damien Cassou
Signed-off-by: Damien Cassou 
---
 emacs/notmuch-show.el   |   15 +++
 emacs/notmuch-tagger.el |   33 +
 2 files changed, 40 insertions(+), 8 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index a71497a..93bce07 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -362,10 +362,8 @@ operation on the contents of the current buffer."
 (goto-char (notmuch-show-message-top))
 (if (re-search-forward "(\\([^()]*\\))$" (line-end-position) t)
(let ((inhibit-read-only t))
- (replace-match (concat "("
-(propertize (mapconcat 'identity tags " ")
-'face 'notmuch-tag-face)
-")")
+ (replace-match (propertize (notmuch-tagger-format-tags tags)
+'face 'notmuch-tag-face)
   (notmuch-show-update-header-line))
 
 (defun notmuch-clean-address (address)
@@ -442,10 +440,11 @@ message at DEPTH in the current thread."
(notmuch-show-clean-address (plist-get headers :From))
" ("
date
-   ") ("
-   (propertize (mapconcat 'identity tags " ")
-   'face 'notmuch-tag-face)
-   ")\n")
+   ") "
+   (propertize
+(notmuch-tagger-format-tags tags)
+'face 'notmuch-tag-face)
+   "\n")
 (overlay-put (make-overlay start (point)) 'face 
'notmuch-message-summary-face)))
 
 (defun notmuch-show-insert-header (header header-value)
diff --git a/emacs/notmuch-tagger.el b/emacs/notmuch-tagger.el
index 38b858a..35b81ca 100644
--- a/emacs/notmuch-tagger.el
+++ b/emacs/notmuch-tagger.el
@@ -44,12 +44,21 @@ test if the library is present before calling this 
function."
   (let ((tag (header-button-get button 'notmuch-tagger-tag)))
 (notmuch-tagger-goto-target tag)))
 
+(defun notmuch-tagger-body-button-action (button)
+  "Open `notmuch-search' for the tag referenced by BUTTON."
+  (let ((tag (button-get button 'notmuch-tagger-tag)))
+(notmuch-tagger-goto-target tag)))
+
 (eval-after-load "header-button"
   '(define-button-type 'notmuch-tagger-header-button-type
  'supertype 'header
  'action#'notmuch-tagger-header-button-action
  'follow-link t))
 
+(define-button-type 'notmuch-tagger-body-button-type
+  'action#'notmuch-tagger-body-button-action
+  'follow-link t)
+
 (defun notmuch-tagger-really-make-header-link (tag)
"Return a property list that presents a link to TAG.
 
@@ -73,6 +82,20 @@ if not."
   (notmuch-tagger-really-make-header-link tag)
 tag))
 
+(defun notmuch-tagger-make-body-link (tag)
+  "Return a property list that presents a link to TAG.
+The returned property list will not work in the header-line. For
+a link that works on the header-line, prefer
+`notmuch-tagger-make-header-link'."
+  (let ((button (copy-sequence tag)))
+(make-text-button
+ button nil
+ 'type 'notmuch-tagger-body-button-type
+ 'notmuch-tagger-tag tag
+ 'skip t ;; don't stop when using TAB
+ 'help-echo (format "%s: Search other messages like this" tag))
+button))
+
 (defun notmuch-tagger-format-tags-header-line (tags)
   "Format TAGS as a `mode-line-format' template.
 The result is suitable for inclusion in `header-line-format'."
@@ -83,5 +106,15 @@ The result is suitable for inclusion in 
`header-line-format'."
 " ")
")"))
 
+(defun notmuch-tagger-format-tags (tags)
+  "Format TAGS as a string suitable for insertion in a buffer.
+If the result of this function is to be used within the
+header-line, prefer `notmuch-tagger-format-tags-header-line'
+instead of this function."
+  (concat
+   "("
+   (mapconcat #'notmuch-tagger-make-body-link tags " ")
+   ")"))
+
 (provide 'notmuch-tagger)
 ;;; notmuch-tagger.el ends here
-- 
1.7.10.4

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


[PATCH 2/4] emacs: Make tags in notmuch-show header-line clickable

2012-12-11 Thread Damien Cassou
Signed-off-by: Damien Cassou 
---
 emacs/notmuch-tagger.el |   54 ++-
 1 file changed, 53 insertions(+), 1 deletion(-)

diff --git a/emacs/notmuch-tagger.el b/emacs/notmuch-tagger.el
index 6fcebff..38b858a 100644
--- a/emacs/notmuch-tagger.el
+++ b/emacs/notmuch-tagger.el
@@ -23,12 +23,64 @@
 ;;; Code:
 ;;
 
+(defun notmuch-tagger-header-button-present-p ()
+  "Check if `header-button' can be loaded or is already loaded.
+
+`header-button' is a third-party library which facilitates the
+creation of links in emacs header-line. This function tries to
+`require' `header-button' and returns nil if and only if this
+fails."
+  (require 'header-button nil t))
+
+(defun notmuch-tagger-goto-target (tag)
+  "Show a `notmuch-search' buffer for the TAG."
+  (notmuch-search (concat "tag:\"" tag "\"")))
+
+(defun notmuch-tagger-header-button-action (button)
+  "Open `notmuch-search' for the tag referenced by BUTTON.
+This function depends on the presence of the `header-button'
+library. Please call `notmuch-tagger-header-button-present-p' to
+test if the library is present before calling this function."
+  (let ((tag (header-button-get button 'notmuch-tagger-tag)))
+(notmuch-tagger-goto-target tag)))
+
+(eval-after-load "header-button"
+  '(define-button-type 'notmuch-tagger-header-button-type
+ 'supertype 'header
+ 'action#'notmuch-tagger-header-button-action
+ 'follow-link t))
+
+(defun notmuch-tagger-really-make-header-link (tag)
+   "Return a property list that presents a link to TAG.
+
+The returned property list will only work in the header-line.
+Additionally, this function depends on the presence of the
+`header-button' library. Please call
+`notmuch-tagger-header-button-present-p' to test if library is
+present before calling this function."
+   (header-button-format
+tag
+:type 'notmuch-tagger-header-button-type
+'notmuch-tagger-tag tag
+'help-echo (format "%s: Search other messages like this" tag)))
+
+(defun notmuch-tagger-make-header-link (tag)
+  "Return a property list to present TAG as a link to search.
+
+This only works if `header-button' is loaded. Simply returns tag
+if not."
+  (if (notmuch-tagger-header-button-present-p)
+  (notmuch-tagger-really-make-header-link tag)
+tag))
+
 (defun notmuch-tagger-format-tags-header-line (tags)
   "Format TAGS as a `mode-line-format' template.
 The result is suitable for inclusion in `header-line-format'."
   (list
"("
-   (notmuch-intersperse tags " ")
+   (notmuch-intersperse
+(mapcar #'notmuch-tagger-make-header-link tags)
+" ")
")"))
 
 (provide 'notmuch-tagger)
-- 
1.7.10.4

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


[no subject]

2012-12-11 Thread Damien Cassou
From: Damien Cassou 
Subject: [PATCH v4] emacs: display tags in notmuch-show with links
In-Reply-To: 

This patch obsoletes:
id:1355149964-27905-1-git-send-email-damien.cas...@gmail.com

[PATCH 1/4] emacs: Add a thread's tags to notmuch-show header-line
[PATCH 2/4] emacs: Make tags in notmuch-show header-line clickable
[PATCH 3/4] emacs: Make all tags in `notmuch-show' clickable
[PATCH 4/4] emacs: Add unit-tests for clickable tags

These patches make clickable all tags that appear in notmuch-show
buffers. Each tag is a link to open a new notmuch-search buffer for
this tag. Additionally, the buffer's header-line now shows the
thread's tags (clickable only if the `header-button' library is loaded
or loadable).

These patches are the first of an upcoming series whose goal is to
integrate notmuch-labeler into notmuch. See the following for more
details: https://github.com/DamienCassou/notmuch-labeler

With respect to v3, I took care of the comments you made:
- the header-line now updates when tags are changed
- the tags in the body stays clickable when tags are changed

Additionally, I added two unit tests to cover the above two comments
and fixed some others unit tests of mine.
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch