[PATCH v4 0/3] indicate length of omitted body content

2012-12-13 Thread Peter Wang
On Sun, 09 Dec 2012 19:21:18 +, Mark Walters  
wrote:
> 
> Hi (sorry Peter I had assumed git send-email would have cc'd you on my
> rebase earlier today)
> 
> There was some discussion about this patch series on irc and the general
> view was favourable but that, for consistency, all omitted parts should
> received a content-length (including text/html). This is a little messy
> to code into the if else stuff: Jani suggested putting
> content-length/content-encoding into a small function.
> 
> Anyway I had hope it was just a trivial rebase and could go in, but the
> above will take a bit longer to do neatly so I will leave it for now.

Ok. To save any potential duplicated work: I've updated the patch here,
save for test/sexp.  Waiting for that to be pushed before updating it.

Peter


[Patch v6 1/6] tag-util: factor out rules for illegal tags, use in parse_tag_line

2012-12-13 Thread Mark Walters

I don't know if this matters but it seems that one can still add a "-"
tag by doing something like

echo "+%2d -- search" | notmuch tag --batch

This might be the right thing to do but I thought I would mention it.

Best wishes

Mark

On Sun, 09 Dec 2012, david at tethera.net wrote:
> From: David Bremner 
>
> This will allow us to be consistent between batch tagging and command
> line tagging as far as what is an illegal tag.
> ---
>  tag-util.c |   35 ++-
>  1 file changed, 30 insertions(+), 5 deletions(-)
>
> diff --git a/tag-util.c b/tag-util.c
> index eab482f..c071ea8 100644
> --- a/tag-util.c
> +++ b/tag-util.c
> @@ -31,6 +31,29 @@ line_error (tag_parse_status_t status,
>  return status;
>  }
>  
> +/*
> + * Test tags for some forbidden cases.
> + *
> + * return: NULL if OK,
> + *  explanatory message otherwise.
> + */
> +
> +static const char *
> +illegal_tag (const char *tag, notmuch_bool_t remove) {
> +
> +if (*tag == '\0' && !remove)
> + return "adding empty tag";
> +
> +/* This disallows adding the non-removable tag "-" and
> + * enables notmuch tag to take long options more easily.
> + */
> +
> +if (*tag == '-' && !remove)
> + return  "adding tag starting with -";
> +
> +return NULL;
> +}
> +
>  tag_parse_status_t
>  parse_tag_line (void *ctx, char *line,
>   tag_op_flag_t flags,
> @@ -95,11 +118,13 @@ parse_tag_line (void *ctx, char *line,
>   remove = (*tok == '-');
>   tag = tok + 1;
>  
> - /* Maybe refuse empty tags. */
> - if (! (flags & TAG_FLAG_BE_GENEROUS) && *tag == '\0') {
> - ret = line_error (TAG_PARSE_INVALID, line_for_error,
> -   "empty tag");
> - goto DONE;
> + /* Maybe refuse illegal tags. */
> + if (! (flags & TAG_FLAG_BE_GENEROUS)) {
> + const char *msg = illegal_tag (tag, remove);
> + if (msg) {
> + ret = line_error (TAG_PARSE_INVALID, line_for_error, msg);
> + goto DONE;
> + }
>   }
>  
>   /* Decode tag. */
> -- 
> 1.7.10.4
>
> ___
> notmuch mailing list
> notmuch at notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch


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

2012-12-13 Thread Mark Walters

Hi 

I thought I had checked the test output but I am getting a failure: the
last test in emacs-show is failing (test_begin_subtest "id
buttonization")

I think it is just saying your patch is working and making the tag inbox
in the message line a button.

Best wishes

Mark





 On Thu, 13 Dec 2012, Damien Cassou  wrote:
> Signed-off-by: Damien Cassou 
> ---
>  test/emacs |  103 
> 
>  1 file changed, 103 insertions(+)
>
> diff --git a/test/emacs b/test/emacs
> index 5403930..af9d37c 100755
> --- a/test/emacs
> +++ b/test/emacs
> @@ -852,5 +852,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-se

gmail importer script

2012-12-13 Thread Patrick Totzke

Sorry, I'm misusing this thread as a bugtracker..


Traceback (most recent call last):4|   
| 10% ETA:  1:24:41   3.54  emails/s
  File "./gmail-notmuch.py", line 251, in 
main()
  File "./gmail-notmuch.py", line 89, in main
download_new_messages(imap, database, new_messages, destination)
  File "./gmail-notmuch.py", line 208, in download_new_messages
tag_message(database, dest, labels)
  File "./gmail-notmuch.py", line 168, in tag_message
raise e
notmuch.errors.FileNotEmailError



best,
/p


[PATCH v5] emacs: display tags in notmuch-show with links

2012-12-13 Thread Mark Walters

This version looks good to me: +1

Best wishes

Mark

On Thu, 13 Dec 2012, Damien Cassou  wrote:
> This patch obsoletes:
> id:1355216437-21109-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 v4, I took care of the comments you made:
>
> - integration of Mark Walters' patch to avoid duplicate update of the
>   header-line tags
> - implementation of Mark Walters' comment on sorting header-line tags
> ___
> notmuch mailing list
> notmuch at notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch


gmail importer script

2012-12-13 Thread Jason A. Donenfeld
\AllMail is the unlocalized generic version that maps to the localized
version, as are all the other back slash situations.


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

2012-12-13 Thread Patrick Totzke
Quoting Jason A. Donenfeld (2012-12-13 14:32:53)
> On Wed, Dec 12, 2012 at 9:49 PM, Austin Clements  wrote:
> > There should be no way to corrupt the database at this level through
> > the Xapian API, which means nothing libnotmuch can do (much less users
> > of libnotmuch) should be able to corrupt the database.  If you can
> > reproduce the problem, it's probably a serious bug in Xapian, but it
> > could also have been a file system bug or even random file system
> > corruption.
> 
> Well that's... troubling.
> 
> Patrick: could you please backup and try to reproduce? Otherwise I'll
> assume this was a one-off situation.


I tried it again, concurrently triggered some modifications
and killed the process afer a while.
(my modifications were not flushed during the run of your script as
the index was locked)
The index seems to be OK. So I'm afraid I cannot reproduce this reliably.
/p




gmail importer script

2012-12-13 Thread Jason A. Donenfeld
On Thu, Dec 13, 2012 at 3:35 PM, fREW Schmidt  wrote:
> I just mean a general programming technique.  As you get information
> about tags you hold them in memory and then sync it later and clear
> your memory.

Oh, yea, that's a great idea. I'll play with that. Good thinking.


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

2012-12-13 Thread Jason A. Donenfeld
On Wed, Dec 12, 2012 at 10:26 PM, David Bremner  wrote:
>
> One thing that Olly Betts mentioned is that there is a recently fixed
> bug in xapian with respect to multiple threads in the same process

The script's actually single threaded.


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

2012-12-13 Thread Jason A. Donenfeld
On Wed, Dec 12, 2012 at 9:49 PM, Austin Clements  wrote:
> There should be no way to corrupt the database at this level through
> the Xapian API, which means nothing libnotmuch can do (much less users
> of libnotmuch) should be able to corrupt the database.  If you can
> reproduce the problem, it's probably a serious bug in Xapian, but it
> could also have been a file system bug or even random file system
> corruption.

Well that's... troubling.

Patrick: could you please backup and try to reproduce? Otherwise I'll
assume this was a one-off situation.


Austin-- think you could do a quick review of the script to double
check and confirm I'm not doing anything nefarious?
http://git.zx2c4.com/gmail-notmuch/tree/gmail-notmuch.py


gmail importer script

2012-12-13 Thread Jason A. Donenfeld
Please don't reply offlist. This is message #2 that's been sent offlist.

On Thu, Dec 13, 2012 at 3:22 PM, fREW Schmidt 
> One thing you might want to try is to only open the notmuch index for
> writing at a specified sync time.

How do I do this? What's the python function? I couldn't find
anything. Would be interested in doing this though if it exists.

> Also I was going to say you might want to catch SIGINT like

The library already does this.


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

2012-12-13 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 5403930..af9d37c 100755
--- a/test/emacs
+++ b/test/emacs
@@ -852,5 +852,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-13 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 9c5a85e..8c07a00 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)
   (unless no-headerline-update
 (notmuch-show-update-header-line)))

@@ -443,10 +441,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-13 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-13 Thread Damien Cassou
Signed-off-by: Damien Cassou 
---
 emacs/notmuch-lib.el|   11 +--
 emacs/notmuch-show.el   |   37 +
 emacs/notmuch-tagger.el |   35 +++
 3 files changed, 73 insertions(+), 10 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..9c5a85e 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)
@@ -355,7 +356,7 @@ operation on the contents of the current buffer."
   "Return a string comprised of `n' spaces."
   (make-string n ? ))

-(defun notmuch-show-update-tags (tags)
+(defun notmuch-show-update-tags (tags &optional no-headerline-update)
   "Update the displayed tags of the current message."
   (save-excursion
 (goto-char (notmuch-show-message-top))
@@ -364,7 +365,9 @@ operation on the contents of the current buffer."
  (replace-match (concat "("
 (propertize (mapconcat 'identity tags " ")
 'face 'notmuch-tag-face)
-")"))
+")")
+  (unless no-headerline-update
+(notmuch-show-update-header-line)))

 (defun notmuch-clean-address (address)
   "Try to clean a single email ADDRESS for display. Return a cons
@@ -1136,11 +1139,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
+(sort tags 'string<)))
+
+(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.

@@ -1443,10 +1463,10 @@ current thread."
 (defun notmuch-show-get-depth ()
   (notmuch-show-get-prop :depth))

-(defun notmuch-show-set-tags (tags)
+(defun notmuch-show-set-tags (tags &optional no-headerline-update)
   "Set the tags of the current message."
   (notmuch-show-set-prop :tags tags)
-  (notmuch-show-update-tags tags))
+  (notmuch-show-update-tags tags no-headerline-update))

 (defun notmuch-show-get-tags ()
   "Return the tags of the current message."
@@ -1760,7 +1780,8 @@ See `notmuch-tag' for information on the format of 
TAG-CHANGES."
  (let* ((current-tags (notmuch-show-get-tags))
(new-tags (notmuch-update-tags current-tags tag-changes)))
(unless (equal current-tags new-tags)
-(notmuch-show-set-tags new-tags))
+(notmuch-show-set-tags new-tags t)
+  (notmuch-show-update-header-line))

 (defun notmuch-show-add-tag ()
   "Same as `notmuch-show-tag' but sets initial input to '+'."
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 

[PATCH v5] emacs: display tags in notmuch-show with links

2012-12-13 Thread Damien Cassou
This patch obsoletes:
id:1355216437-21109-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 v4, I took care of the comments you made:

- integration of Mark Walters' patch to avoid duplicate update of the
  header-line tags
- implementation of Mark Walters' comment on sorting header-line tags


Re: [Patch v6 1/6] tag-util: factor out rules for illegal tags, use in parse_tag_line

2012-12-13 Thread Mark Walters

I don't know if this matters but it seems that one can still add a "-"
tag by doing something like

echo "+%2d -- search" | notmuch tag --batch

This might be the right thing to do but I thought I would mention it.

Best wishes

Mark

On Sun, 09 Dec 2012, da...@tethera.net wrote:
> From: David Bremner 
>
> This will allow us to be consistent between batch tagging and command
> line tagging as far as what is an illegal tag.
> ---
>  tag-util.c |   35 ++-
>  1 file changed, 30 insertions(+), 5 deletions(-)
>
> diff --git a/tag-util.c b/tag-util.c
> index eab482f..c071ea8 100644
> --- a/tag-util.c
> +++ b/tag-util.c
> @@ -31,6 +31,29 @@ line_error (tag_parse_status_t status,
>  return status;
>  }
>  
> +/*
> + * Test tags for some forbidden cases.
> + *
> + * return: NULL if OK,
> + *  explanatory message otherwise.
> + */
> +
> +static const char *
> +illegal_tag (const char *tag, notmuch_bool_t remove) {
> +
> +if (*tag == '\0' && !remove)
> + return "adding empty tag";
> +
> +/* This disallows adding the non-removable tag "-" and
> + * enables notmuch tag to take long options more easily.
> + */
> +
> +if (*tag == '-' && !remove)
> + return  "adding tag starting with -";
> +
> +return NULL;
> +}
> +
>  tag_parse_status_t
>  parse_tag_line (void *ctx, char *line,
>   tag_op_flag_t flags,
> @@ -95,11 +118,13 @@ parse_tag_line (void *ctx, char *line,
>   remove = (*tok == '-');
>   tag = tok + 1;
>  
> - /* Maybe refuse empty tags. */
> - if (! (flags & TAG_FLAG_BE_GENEROUS) && *tag == '\0') {
> - ret = line_error (TAG_PARSE_INVALID, line_for_error,
> -   "empty tag");
> - goto DONE;
> + /* Maybe refuse illegal tags. */
> + if (! (flags & TAG_FLAG_BE_GENEROUS)) {
> + const char *msg = illegal_tag (tag, remove);
> + if (msg) {
> + ret = line_error (TAG_PARSE_INVALID, line_for_error, msg);
> + goto DONE;
> + }
>   }
>  
>   /* Decode tag. */
> -- 
> 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


[PATCH v4 0/3] indicate length of omitted body content

2012-12-13 Thread Mark Walters

On Thu, 13 Dec 2012, Peter Wang  wrote:
> On Sun, 09 Dec 2012 19:21:18 +, Mark Walters  gmail.com> wrote:
>> 
>> Hi (sorry Peter I had assumed git send-email would have cc'd you on my
>> rebase earlier today)
>> 
>> There was some discussion about this patch series on irc and the general
>> view was favourable but that, for consistency, all omitted parts should
>> received a content-length (including text/html). This is a little messy
>> to code into the if else stuff: Jani suggested putting
>> content-length/content-encoding into a small function.
>> 
>> Anyway I had hope it was just a trivial rebase and could go in, but the
>> above will take a bit longer to do neatly so I will leave it for now.
>
> Ok. To save any potential duplicated work: I've updated the patch here,
> save for test/sexp.  Waiting for that to be pushed before updating it.

Sorry I am confused: isn't test/sexp already in master?

Best wishes 

Mark


[no subject]

2012-12-13 Thread Mark Walters

Hi

This is looking good: I have two comments the second of which is significant.

The first is do you want to sort (alphabetically) the headerline tags?
As it stands they are in the order they appear in the thread which is
probably not what is wanted.

The second is that there is a notmuch-show-tag-all functions to tag all
messages in the thread. Your patch is quadratic for the update (as it
calculates the list of thread tags once for each message). The attached
patch would avoid this and doesn't look too bad. (Note I retained
no-headerline-update as an optional argument in case there are out of
tree callers, eg users' .emacs files)

[Note this is not purely of academic interest: on my test large thread
(178 messages) updating the display after tagging all messages took some
seconds without my patch and almost no time with it.]

Best wishes 

Mark

-- next part --
A non-text attachment was scrubbed...
Name: 0001-mjw-tweak.patch
Type: text/x-diff
Size: 2187 bytes
Desc: not available
URL: 
<http://notmuchmail.org/pipermail/notmuch/attachments/20121213/89dc1c66/attachment.patch>
-- next part --



On Tue, 11 Dec 2012, Damien Cassou  wrote:
> 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.
> ___
> notmuch mailing list
> notmuch at notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 07/10] emacs: Use --use-schema for search

2012-12-13 Thread Mark Walters
On Thu, 13 Dec 2012, Austin Clements  wrote:
> Quoth Mark Walters on Dec 08 at  8:48 am:
>> On Sun, 02 Dec 2012, Austin Clements  wrote:
>> > We detect the special exit statuses and use these to produce specific
>> > diagnostic messages.
>> > ---
>> >  emacs/notmuch-lib.el |   32 
>> >  emacs/notmuch.el |   17 +
>> >  2 files changed, 45 insertions(+), 4 deletions(-)
>> >
>> > diff --git a/emacs/notmuch-lib.el b/emacs/notmuch-lib.el
>> > index 9402456..49b0da6 100644
>> > --- a/emacs/notmuch-lib.el
>> > +++ b/emacs/notmuch-lib.el
>> > @@ -325,6 +325,38 @@ string), a property list of face attributes, or a 
>> > list of these."
>> >(put-text-property pos next 'face (cons face cur))
>> >(setq pos next)
>> >  
>> > +(defun notmuch-pop-up-error (msg)
>> > +  "Pop up an error buffer displaying MSG."
>> > +
>> > +  (let ((buf (get-buffer-create "*Notmuch errors*")))
>> > +(with-current-buffer buf
>> > +  (view-mode)
>> > +  (let ((inhibit-read-only t))
>> > +  (erase-buffer)
>> > +  (insert msg)
>> > +  (unless (bolp)
>> > +(insert "\n"))
>> > +  (goto-char (point-min
>> > +(pop-to-buffer buf)))
>> 
>> I am not sure about the erase-buffer in the above: do we definitely want
>> to remove all previous error information? For version mismatch possibly
>> we do but in patch 9 it is done for all show command-line error returns.
>
> Why wouldn't we want to use a cleared buffer in all cases?
> notmuch-pop-up-error is only ever used when a command terminates, so
> there's no danger of us clearing errors that the user hasn't seen yet.

Just to make sure I understand this: whenever an error occurs the error
popup appears so we see the message. Then the next error can safely
erase buffer before showing the new error message?

>> Incidentally why does show always pop-up an error but search only for
>> version-mismatches?
>
> Historical reasons, I suppose.  I was maintaining the status quo for
> search (which already had *some* error handling), but there was no
> error-handling status quo for show.  Probably search should be more
> vocal when the command fails.

Should notmuch-call-notmuch-process also be switched to this framework?
In particular that also puts errors in "*Notmuch errors*" so my earlier
concern may be valid in this case.

Best wishes

Mark
>
>> Otherwise this looks good to me (but I am not that familiar with lisp
>> error handling)
>> 
>> Best wishes
>> 
>> Mark
>> 
>> 
>> 
>> 
>> 
>> 
>> > +(defun notmuch-version-mismatch-error (exit-status)
>> > +  "Signal a schema version mismatch error.
>> > +
>> > +EXIT-STATUS must be the exit status of the notmuch CLI command,
>> > +and must have the value 20 or 21.  This function will pop up an
>> > +error buffer with a descriptive message and signal an error."
>> > +  (cond ((= exit-status 20)
>> > +   (notmuch-pop-up-error "Error: Version mismatch.
>> > +Emacs requested an older output format than supported by the notmuch CLI.
>> > +You may need to restart Emacs or upgrade your notmuch Emacs package."))
>> > +  ((= exit-status 21)
>> > +   (notmuch-pop-up-error "Error: Version mismatch.
>> > +Emacs requested a newer output format than supported by the notmuch CLI.
>> > +You may need to restart Emacs or upgrade your notmuch package."))
>> > +  (t
>> > +   (error "Bad exit status %d" exit-status)))
>> > +  (error "notmuch CLI version mismatch"))
>> > +
>> >  ;; Compatibility functions for versions of emacs before emacs 23.
>> >  ;;
>> >  ;; Both functions here were copied from emacs 23 with the following 
>> > copyright:
>> > diff --git a/emacs/notmuch.el b/emacs/notmuch.el
>> > index f9454d8..e1f28ca 100644
>> > --- a/emacs/notmuch.el
>> > +++ b/emacs/notmuch.el
>> > @@ -644,6 +644,7 @@ of the result."
>> >(exit-status (process-exit-status proc))
>> >(never-found-target-thread nil))
>> >  (when (memq status '(exit signal))
>> > +  (catch 'return
>> >(kill-buffer (process-get proc 'parse-buf))
>> >(if (buffer-live-p buffer)
>> >(with-current-buffer buffer
>> > @@ -655,8 +656,16 @@ of the result."
>> >  (insert "Incomplete search results (search process was 
>> > killed).\n"))
>> >  (when (eq status 'exit)
>> >(insert "End of search results.")
>> > -  (unless (= exit-status 0)
>> > -(insert (format " (process returned %d)" exit-status)))
>> > +  (cond ((or (= exit-status 20) (= exit-status 21))
>> > + (kill-buffer)
>> > + (condition-case err
>> > + (notmuch-version-mismatch-error exit-status)
>> > +   ;; Strange things happen when you signal
>> > +   ;; an error from a sentinel.
>> > +   (error (throw 'return nil
>> > +((/= exit-status 0)
>> > + (insert (format " (process returned %d)"
>> > +  

[PATCH (draft)] contrib: pick: close message pane when quitting from show in the message pane

2012-12-13 Thread Mark Walters
This is a way of trying to make sure notmuch-pick cleans up the split
buffer after itself.
---

Currently if the focus gets into the message pane and then the user
quits from that pane the display stays split. This is an attempt to
fix that. This seems to work but I don't know if there is a better
solution. However, I would welcome any feedback on the user experience
with this patch applied.

Best wishes

Mark




 contrib/notmuch-pick/notmuch-pick.el |   17 +
 1 files changed, 17 insertions(+), 0 deletions(-)

diff --git a/contrib/notmuch-pick/notmuch-pick.el 
b/contrib/notmuch-pick/notmuch-pick.el
index 043e9e7..79ef319 100644
--- a/contrib/notmuch-pick/notmuch-pick.el
+++ b/contrib/notmuch-pick/notmuch-pick.el
@@ -160,6 +160,9 @@
 (defvar notmuch-pick-message-window nil)
 (make-variable-buffer-local 'notmuch-pick-message-window)
 (put 'notmuch-pick-message-window 'permanent-local t)
+(defvar notmuch-show-message-window nil)
+(make-variable-buffer-local 'notmuch-show-message-window)
+(put 'notmuch-show-message-window 'permanent-local t)
 (defvar notmuch-pick-message-buffer nil)
 (make-variable-buffer-local 'notmuch-pick-message-buffer-name)
 (put 'notmuch-pick-message-buffer-name 'permanent-local t)
@@ -389,6 +392,16 @@ Does NOT change the database."
 (notmuch-prettify-subject (notmuch-search-find-subject)))
   (notmuch-pick-show-match-message-with-wait))

+;;over-ride this function to try and kill off message panes
+(defun notmuch-kill-this-buffer ()
+  "Kill the current buffer."
+  (interactive)
+  (let ((buffer (current-buffer)))
+(when (and (window-live-p notmuch-show-message-window)
+(eq (window-buffer notmuch-show-message-window) buffer))
+  (delete-window notmuch-show-message-window))
+(kill-buffer buffer)))
+
 (defun notmuch-pick-show-message ()
   "Show the current message (in split-pane)."
   (interactive)
@@ -406,6 +419,10 @@ Does NOT change the database."
(let ((notmuch-show-indent-messages-width 0))
  (setq current-prefix-arg '(4))
  (setq buffer (notmuch-show id nil nil nil
+  ;; We need the let as notmuch-pick-message-window is buffer local.
+  (let ((window notmuch-pick-message-window))
+   (with-current-buffer buffer
+ (setq notmuch-show-message-window window)))
   (notmuch-pick-tag-update-display (list "-unread"))
   (setq notmuch-pick-message-buffer buffer

-- 
1.7.9.1



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

2012-12-13 Thread Mark Walters

Hi 

I thought I had checked the test output but I am getting a failure: the
last test in emacs-show is failing (test_begin_subtest "id
buttonization")

I think it is just saying your patch is working and making the tag inbox
in the message line a button.

Best wishes

Mark





 On Thu, 13 Dec 2012, Damien Cassou  wrote:
> Signed-off-by: Damien Cassou 
> ---
>  test/emacs |  103 
> 
>  1 file changed, 103 insertions(+)
>
> diff --git a/test/emacs b/test/emacs
> index 5403930..af9d37c 100755
> --- a/test/emacs
> +++ b/test/emacs
> @@ -852,5 +852,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-se

gmail importer script

2012-12-13 Thread fREW Schmidt
On Thu, Dec 13, 2012 at 03:28:30PM +0100, Jason A. Donenfeld wrote:
> On Thu, Dec 13, 2012 at 3:19 PM, fREW Schmidt  wrote:
> >> Okay, I've updated it to dynamically find the All Mail folder.
> >
> > I can't seem to find it now, but I read that Gmail actually localizes
> > the name of various folders, so I think All Mail will actually be
> > called something else for non-english speakers.  It might be a good
> > idea for you to at least make it a config option.
>
> A) Why are you replying off list?
>
> B) Did you totally miss my message directly above yours where I wrote
> "Okay, I've updated it to dynamically find the All Mail folder"?

Right, I did see that and I did look at the code; all I'm saying is
that Gmail may localize AllMail as I'm fairly sure they localize the
other builtin labels
(http://git.zx2c4.com/gmail-notmuch/tree/gmail-notmuch.py#n214)

I could certainly be wrong though, I haven't looked at this at such a
low level before.

--
fREW Schmidt
http://blog.afoolishmanifesto.com
-- next part --
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: 
<http://notmuchmail.org/pipermail/notmuch/attachments/20121213/06c6ef37/attachment-0001.pgp>


[PATCH v2 5/5] emacs: show: set default show-all-multipart/alternatives to nil

2012-12-13 Thread Mark Walters
Now that the invisibility display of parts is present we no longer
need to force the display of all multipart/alternatives: users can
toggle them for themselves when needed.
---
 emacs/notmuch-show.el |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 202258f..c43dd32 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -94,7 +94,7 @@ visible for any given message."
   :group 'notmuch-hooks)

 ;; Mostly useful for debugging.
-(defcustom notmuch-show-all-multipart/alternative-parts t
+(defcustom notmuch-show-all-multipart/alternative-parts nil
   "Should all parts of multipart/alternative parts be shown?"
   :type 'boolean
   :group 'notmuch-show)
-- 
1.7.9.1



[PATCH v2 4/5] emacs: wash: fix fake-diff part to include msg parameter

2012-12-13 Thread Mark Walters
The fake-diff part from notmuch wash did not pass the msg parameter to
notmuch-show-insert-bodypart. Previously this did not matter, but is
now needed to get the overlays right for invisibility.
---
 emacs/notmuch-wash.el |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/emacs/notmuch-wash.el b/emacs/notmuch-wash.el
index 7d003a2..b2affba 100644
--- a/emacs/notmuch-wash.el
+++ b/emacs/notmuch-wash.el
@@ -378,7 +378,7 @@ for error."
   (plist-get
(plist-get msg :headers) :Subject
(delete-region (point-min) (point-max))
-   (notmuch-show-insert-bodypart nil part depth)
+   (notmuch-show-insert-bodypart msg part depth)

 ;;

-- 
1.7.9.1



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

2012-12-13 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, 34 insertions(+), 2 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 3f2f277..202258f 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)
@@ -554,6 +555,28 @@ 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)
+  (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 " ]" " (hidden) ]"))
+   (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
+
 (defun notmuch-show-multipart/*-to-list (part)
   (mapcar (lambda (inner-part) (plist-get inner-part :content-type))
  (plist-get part :content)))
@@ -863,7 +886,13 @@ message at DEPTH in the current thread."
   (cons invis-spec (overlay-get inner 
'invisible)

(button-put button 'invisibility-spec invis-spec)
-   (button-put button 'overlay overlay)
+   (button-put button 'overlay overlay))
+
+  ;; We toggle the button for hidden parts as that gets the
+  ;; button label right.
+  (save-excursion
+   (when hide
+ (notmuch-show-toggle-invisible-part-action button))

 (defun notmuch-show-insert-bodypart (msg part depth &optional hide)
   "Insert the body part PART at depth DEPTH in the current thread.
@@ -1992,7 +2021,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 (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



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

2012-12-13 Thread Mark Walters
This makes 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 the argument HIDE is passed down to
notmuch-show-insert-part-overlays to request that the part be hidden
by default but this is not acted on yet.
---
 emacs/notmuch-show.el |   61 +
 1 files changed, 46 insertions(+), 15 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 06f7ca5..3f2f277 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -567,11 +567,10 @@ message at DEPTH in the current thread."
 ;; but it's not clear that this is the wrong thing to do - which
 ;; 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)"
+   (let* ((inner-type (plist-get inner-part :content-type))
+ (hide (not (or notmuch-show-all-multipart/alternative-parts
+  (string= chosen-type inner-type)
+ (notmuch-show-insert-bodypart msg inner-part depth hide)))
  inner-parts)

 (when notmuch-show-indent-multipart
@@ -839,17 +838,49 @@ 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 hide)
+  "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.
+(when (and button (/= 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 '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.
+   (dolist (inner (overlays-in part-beg end))
+ (when (and (>= (overlay-start inner) part-beg)
+  (<= (overlay-end inner) end))
+ (overlay-put inner 'invisible
+  (cons invis-spec (overlay-get inner 
'invisible)
+
+   (button-put button 'invisibility-spec invis-spec)
+   (button-put button 'overlay overlay)
+
+(defun notmuch-show-insert-bodypart (msg part depth &optional hide)
+  "Insert the body part PART at depth DEPTH in the current thread.
+
+If HIDE is non-nil 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) hide)))

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



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

2012-12-13 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 |   18 +-
 1 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index d7fa10e..06f7ca5 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -483,17 +483,17 @@ 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 (when name (concat name ": "))
+   declared-type
+   (unless (string-equal declared-type content-type)
+ (concat " (as " content-type ")"))
+   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 v2 0/5] Use invisibility to toggle display of all parts including multipart

2012-12-13 Thread Mark Walters
This is version 2 of the patch series (version 1 at
id:1354663662-20524-1-git-send-email-markwalters1009 at gmail.com)

Almost all of the changes and fixes are in response to Austin's
review. I have changed things as he suggested.

There are two small extra tiny patches in this version: I set the
default value of notmuch-show-all-multipart/alternative-parts to nil.

The second is to fix a bug reported by Jani: that fake-patch parts (as
provided by notmuch-wash) did not get hidden when the whole message
was hidden.  This was due to notmuch-wash-convert-inline-patch-to-part
not passing a msg on down to notmuch-show-insert-bodypart. Previously
this did not matter but with with this series msg is needed to
construct the correct overlays.

Best wishes

Mark




Mark Walters (5):
  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: wash: fix fake-diff part to include msg parameter
  emacs: show: set default show-all-multipart/alternatives to nil

 emacs/notmuch-show.el |  115 ++---
 emacs/notmuch-wash.el |2 +-
 2 files changed, 90 insertions(+), 27 deletions(-)

-- 
1.7.9.1



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

2012-12-13 Thread Mark Walters

On Tue, 11 Dec 2012, Austin Clements  wrote:
> On Tue, 04 Dec 2012, Mark Walters  wrote:
>> 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) ]"))
>
> s/not shown/hidden/?

Done

>
>> +(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)

This is where point gets left by this toggle button function: I don't
know if it should move point. Mostly it only matters if the user uses
the mouse (as otherwise point is on the button).

>> +  (unless no-redisplay
>> +(force-window-update)
>> +(redisplay t)
>
> Is the t argument necessary?  Actually, are either (force-window-update)
> or (redisplay) necessary?

None of this seems needed: I had just copied it from notmuch-wash. 

Best wishes

Mark

>> +
>>  (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


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

2012-12-13 Thread Mark Walters

Hi 

Many thanks for the review: I will post a new version shortly. Some
comments inline below:

On Tue, 11 Dec 2012, Austin Clements  wrote:
> On Tue, 04 Dec 2012, Mark Walters  wrote:
>> This make notmuch-show-insert-bodypart add an overlay for any
>
> s/make/makes/
>
>> 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
>
> not-shown is really an argument (I found this confusing).
>
>> 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
>
> Since notmuch-show-all-multipart/alternative-parts was basically a hack
> around our poor multipart/alternative support, I think this series (or a
> follow up patch) should change its default to nil or even eliminate it
> entirely.

I have added a patch at the end setting this to nil by default.

>> + (string= chosen-type 
>> inner-type))
>
> You could let-bind the (not (or ..)) to some variable ("hide" perhaps)
> in the let above to avoid this crazy line length.
>
>>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)
>
> s/not-shown/hide/?  Or hidden?
>
>> +  "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))
>
> (when (and button (/= 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))
>
> Non-trivial buffer invisibility specs are really bad for performance
> (Emacs' renderer does the obvious O(n^2) thing when rendering a buffer
> with an invisibility spec).  Unfortunately, because of notmuch-wash and
> the way overlays with trivial 'invisible properties combine with
> overlays with list-type 'invisible properties combine, I don't think it
> can be avoided.  But if we get rid of buffer invisibility specs from
> notmuch-wash, this code can also get much simpler.

How do you plan to get rid of the invisibility properties from notmuch
wash? 

>> +(overlay-put overlay 'isearch-open-invisible 
>> #'notmuch-wash-region-isearch-show)
>
> This will leave the "(not shown)" in the part header if isearch unfolds
> the part.
>
> Do we even want isearch to unfold parts?  It's not clear we do for
> multipart/alternative.  If we do, probably the right thing is something
> like

I don't think we want to search hidden bodyparts so I just deleted this
line.

>
> (overlay-put overlay 'notmuch-show-part-button button)
> (overlay-put overlay 'isearch-open-invisible #'notmuch-show-part-isearch-open)
>
> (defun notmuch-show-part-isearch-open (overlay)
>   (notmuch-show-toggle-invisible-part-action
>(overlay-get overlay 'notmuch-show-part-button)))
>
>> +(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.
>
> Interesting.  In the simple case of using nil or t for 'invisible, the
> specs do combine as one would expect, but you're right that, with a
> non-trivial i

Re: gmail importer script

2012-12-13 Thread Patrick Totzke

Sorry, I'm misusing this thread as a bugtracker..


Traceback (most recent call last):4|   
| 10% ETA:  1:24:41   3.54  emails/s
  File "./gmail-notmuch.py", line 251, in 
main()
  File "./gmail-notmuch.py", line 89, in main
download_new_messages(imap, database, new_messages, destination)
  File "./gmail-notmuch.py", line 208, in download_new_messages
tag_message(database, dest, labels)
  File "./gmail-notmuch.py", line 168, in tag_message
raise e
notmuch.errors.FileNotEmailError



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


Re: [PATCH v5] emacs: display tags in notmuch-show with links

2012-12-13 Thread Mark Walters

This version looks good to me: +1

Best wishes

Mark

On Thu, 13 Dec 2012, Damien Cassou  wrote:
> This patch obsoletes:
> id:1355216437-21109-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 v4, I took care of the comments you made:
>
> - integration of Mark Walters' patch to avoid duplicate update of the
>   header-line tags
> - implementation of Mark Walters' comment on sorting header-line tags
> ___
> notmuch mailing list
> notmuch@notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


gmail importer script

2012-12-13 Thread fREW Schmidt
On Thu, Dec 13, 2012 at 03:30:19PM +0100, Jason A. Donenfeld wrote:
> Please don't reply offlist. This is message #2 that's been sent offlist.

Oh I'm sorry, that was an accident.

> On Thu, Dec 13, 2012 at 3:22 PM, fREW Schmidt 
> > One thing you might want to try is to only open the notmuch index for
> > writing at a specified sync time.
>
> How do I do this? What's the python function? I couldn't find
> anything. Would be interested in doing this though if it exists.

I just mean a general programming technique.  As you get information
about tags you hold them in memory and then sync it later and clear
your memory.

> > Also I was going to say you might want to catch SIGINT like
>
> The library already does this.

--
fREW Schmidt
http://blog.afoolishmanifesto.com
-- next part --
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: 
<http://notmuchmail.org/pipermail/notmuch/attachments/20121213/f29b8470/attachment.pgp>


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

2012-12-13 Thread Patrick Totzke
Quoting Jason A. Donenfeld (2012-12-13 14:32:53)
> On Wed, Dec 12, 2012 at 9:49 PM, Austin Clements  wrote:
> > There should be no way to corrupt the database at this level through
> > the Xapian API, which means nothing libnotmuch can do (much less users
> > of libnotmuch) should be able to corrupt the database.  If you can
> > reproduce the problem, it's probably a serious bug in Xapian, but it
> > could also have been a file system bug or even random file system
> > corruption.
> 
> Well that's... troubling.
> 
> Patrick: could you please backup and try to reproduce? Otherwise I'll
> assume this was a one-off situation.


I tried it again, concurrently triggered some modifications
and killed the process afer a while.
(my modifications were not flushed during the run of your script as
the index was locked)
The index seems to be OK. So I'm afraid I cannot reproduce this reliably.
/p


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


Re: gmail importer script

2012-12-13 Thread Jason A. Donenfeld
\AllMail is the unlocalized generic version that maps to the localized
version, as are all the other back slash situations.
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: gmail importer script

2012-12-13 Thread fREW Schmidt
On Thu, Dec 13, 2012 at 03:28:30PM +0100, Jason A. Donenfeld wrote:
> On Thu, Dec 13, 2012 at 3:19 PM, fREW Schmidt  wrote:
> >> Okay, I've updated it to dynamically find the All Mail folder.
> >
> > I can't seem to find it now, but I read that Gmail actually localizes
> > the name of various folders, so I think All Mail will actually be
> > called something else for non-english speakers.  It might be a good
> > idea for you to at least make it a config option.
>
> A) Why are you replying off list?
>
> B) Did you totally miss my message directly above yours where I wrote
> "Okay, I've updated it to dynamically find the All Mail folder"?

Right, I did see that and I did look at the code; all I'm saying is
that Gmail may localize AllMail as I'm fairly sure they localize the
other builtin labels
(http://git.zx2c4.com/gmail-notmuch/tree/gmail-notmuch.py#n214)

I could certainly be wrong though, I haven't looked at this at such a
low level before.

--
fREW Schmidt
http://blog.afoolishmanifesto.com


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


Re: gmail importer script

2012-12-13 Thread Jason A. Donenfeld
On Thu, Dec 13, 2012 at 3:35 PM, fREW Schmidt  wrote:
> I just mean a general programming technique.  As you get information
> about tags you hold them in memory and then sync it later and clear
> your memory.

Oh, yea, that's a great idea. I'll play with that. Good thinking.
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: gmail importer script

2012-12-13 Thread fREW Schmidt
On Thu, Dec 13, 2012 at 03:30:19PM +0100, Jason A. Donenfeld wrote:
> Please don't reply offlist. This is message #2 that's been sent offlist.

Oh I'm sorry, that was an accident.

> On Thu, Dec 13, 2012 at 3:22 PM, fREW Schmidt 
> > One thing you might want to try is to only open the notmuch index for
> > writing at a specified sync time.
>
> How do I do this? What's the python function? I couldn't find
> anything. Would be interested in doing this though if it exists.

I just mean a general programming technique.  As you get information
about tags you hold them in memory and then sync it later and clear
your memory.

> > Also I was going to say you might want to catch SIGINT like
>
> The library already does this.

--
fREW Schmidt
http://blog.afoolishmanifesto.com


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


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

2012-12-13 Thread Jason A. Donenfeld
On Wed, Dec 12, 2012 at 10:26 PM, David Bremner  wrote:
>
> One thing that Olly Betts mentioned is that there is a recently fixed
> bug in xapian with respect to multiple threads in the same process

The script's actually single threaded.
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


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

2012-12-13 Thread Jason A. Donenfeld
On Wed, Dec 12, 2012 at 9:49 PM, Austin Clements  wrote:
> There should be no way to corrupt the database at this level through
> the Xapian API, which means nothing libnotmuch can do (much less users
> of libnotmuch) should be able to corrupt the database.  If you can
> reproduce the problem, it's probably a serious bug in Xapian, but it
> could also have been a file system bug or even random file system
> corruption.

Well that's... troubling.

Patrick: could you please backup and try to reproduce? Otherwise I'll
assume this was a one-off situation.


Austin-- think you could do a quick review of the script to double
check and confirm I'm not doing anything nefarious?
http://git.zx2c4.com/gmail-notmuch/tree/gmail-notmuch.py
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: gmail importer script

2012-12-13 Thread Jason A. Donenfeld
Please don't reply offlist. This is message #2 that's been sent offlist.

On Thu, Dec 13, 2012 at 3:22 PM, fREW Schmidt 
> One thing you might want to try is to only open the notmuch index for
> writing at a specified sync time.

How do I do this? What's the python function? I couldn't find
anything. Would be interested in doing this though if it exists.

> Also I was going to say you might want to catch SIGINT like

The library already does this.
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH v4 0/3] indicate length of omitted body content

2012-12-13 Thread Peter Wang
On Thu, 13 Dec 2012 12:52:50 +, Mark Walters  
wrote:
> 
> Sorry I am confused: isn't test/sexp already in master?

You're right, somehow I missed it.

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


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

2012-12-13 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 5403930..af9d37c 100755
--- a/test/emacs
+++ b/test/emacs
@@ -852,5 +852,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 3/4] emacs: Make all tags in `notmuch-show' clickable

2012-12-13 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 9c5a85e..8c07a00 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)
   (unless no-headerline-update
 (notmuch-show-update-header-line)))
 
@@ -443,10 +441,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 1/4] emacs: Add a thread's tags to notmuch-show header-line

2012-12-13 Thread Damien Cassou
Signed-off-by: Damien Cassou 
---
 emacs/notmuch-lib.el|   11 +--
 emacs/notmuch-show.el   |   37 +
 emacs/notmuch-tagger.el |   35 +++
 3 files changed, 73 insertions(+), 10 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..9c5a85e 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)
@@ -355,7 +356,7 @@ operation on the contents of the current buffer."
   "Return a string comprised of `n' spaces."
   (make-string n ? ))
 
-(defun notmuch-show-update-tags (tags)
+(defun notmuch-show-update-tags (tags &optional no-headerline-update)
   "Update the displayed tags of the current message."
   (save-excursion
 (goto-char (notmuch-show-message-top))
@@ -364,7 +365,9 @@ operation on the contents of the current buffer."
  (replace-match (concat "("
 (propertize (mapconcat 'identity tags " ")
 'face 'notmuch-tag-face)
-")"))
+")")
+  (unless no-headerline-update
+(notmuch-show-update-header-line)))
 
 (defun notmuch-clean-address (address)
   "Try to clean a single email ADDRESS for display. Return a cons
@@ -1136,11 +1139,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
+(sort tags 'string<)))
+
+(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.
 
@@ -1443,10 +1463,10 @@ current thread."
 (defun notmuch-show-get-depth ()
   (notmuch-show-get-prop :depth))
 
-(defun notmuch-show-set-tags (tags)
+(defun notmuch-show-set-tags (tags &optional no-headerline-update)
   "Set the tags of the current message."
   (notmuch-show-set-prop :tags tags)
-  (notmuch-show-update-tags tags))
+  (notmuch-show-update-tags tags no-headerline-update))
 
 (defun notmuch-show-get-tags ()
   "Return the tags of the current message."
@@ -1760,7 +1780,8 @@ See `notmuch-tag' for information on the format of 
TAG-CHANGES."
  (let* ((current-tags (notmuch-show-get-tags))
(new-tags (notmuch-update-tags current-tags tag-changes)))
(unless (equal current-tags new-tags)
-(notmuch-show-set-tags new-tags))
+(notmuch-show-set-tags new-tags t)
+  (notmuch-show-update-header-line))
 
 (defun notmuch-show-add-tag ()
   "Same as `notmuch-show-tag' but sets initial input to '+'."
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 impl

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

2012-12-13 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


[PATCH v5] emacs: display tags in notmuch-show with links

2012-12-13 Thread Damien Cassou
This patch obsoletes:
id:1355216437-21109-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 v4, I took care of the comments you made:

- integration of Mark Walters' patch to avoid duplicate update of the
  header-line tags
- implementation of Mark Walters' comment on sorting header-line tags
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH v4 0/3] indicate length of omitted body content

2012-12-13 Thread Mark Walters

On Thu, 13 Dec 2012, Peter Wang  wrote:
> On Sun, 09 Dec 2012 19:21:18 +, Mark Walters  
> wrote:
>> 
>> Hi (sorry Peter I had assumed git send-email would have cc'd you on my
>> rebase earlier today)
>> 
>> There was some discussion about this patch series on irc and the general
>> view was favourable but that, for consistency, all omitted parts should
>> received a content-length (including text/html). This is a little messy
>> to code into the if else stuff: Jani suggested putting
>> content-length/content-encoding into a small function.
>> 
>> Anyway I had hope it was just a trivial rebase and could go in, but the
>> above will take a bit longer to do neatly so I will leave it for now.
>
> Ok. To save any potential duplicated work: I've updated the patch here,
> save for test/sexp.  Waiting for that to be pushed before updating it.

Sorry I am confused: isn't test/sexp already in master?

Best wishes 

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


Re: [PATCH v4 0/3] indicate length of omitted body content

2012-12-13 Thread Peter Wang
On Sun, 09 Dec 2012 19:21:18 +, Mark Walters  
wrote:
> 
> Hi (sorry Peter I had assumed git send-email would have cc'd you on my
> rebase earlier today)
> 
> There was some discussion about this patch series on irc and the general
> view was favourable but that, for consistency, all omitted parts should
> received a content-length (including text/html). This is a little messy
> to code into the if else stuff: Jani suggested putting
> content-length/content-encoding into a small function.
> 
> Anyway I had hope it was just a trivial rebase and could go in, but the
> above will take a bit longer to do neatly so I will leave it for now.

Ok. To save any potential duplicated work: I've updated the patch here,
save for test/sexp.  Waiting for that to be pushed before updating it.

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


Re:

2012-12-13 Thread Mark Walters

Hi

This is looking good: I have two comments the second of which is significant.

The first is do you want to sort (alphabetically) the headerline tags?
As it stands they are in the order they appear in the thread which is
probably not what is wanted.

The second is that there is a notmuch-show-tag-all functions to tag all
messages in the thread. Your patch is quadratic for the update (as it
calculates the list of thread tags once for each message). The attached
patch would avoid this and doesn't look too bad. (Note I retained
no-headerline-update as an optional argument in case there are out of
tree callers, eg users' .emacs files)

[Note this is not purely of academic interest: on my test large thread
(178 messages) updating the display after tagging all messages took some
seconds without my patch and almost no time with it.]

Best wishes 

Mark

>From ab15a4bdb50bcf6b2851806195bbe8bea3b099dc Mon Sep 17 00:00:00 2001
From: Mark Walters 
Date: Thu, 13 Dec 2012 11:23:09 +
Subject: [PATCH] Avoid quadratic update

---
 emacs/notmuch-show.el |   12 +++-
 1 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 93bce07..8dd6010 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -356,7 +356,7 @@ operation on the contents of the current buffer."
   "Return a string comprised of `n' spaces."
   (make-string n ? ))
 
-(defun notmuch-show-update-tags (tags)
+(defun notmuch-show-update-tags (tags &optional no-headerline-update)
   "Update the displayed tags of the current message."
   (save-excursion
 (goto-char (notmuch-show-message-top))
@@ -364,7 +364,8 @@ operation on the contents of the current buffer."
 	(let ((inhibit-read-only t))
 	  (replace-match (propertize (notmuch-tagger-format-tags tags)
  'face 'notmuch-tag-face)
-  (notmuch-show-update-header-line))
+  (unless no-headerline-update
+(notmuch-show-update-header-line)))
 
 (defun notmuch-clean-address (address)
   "Try to clean a single email ADDRESS for display. Return a cons
@@ -1461,10 +1462,10 @@ current thread."
 (defun notmuch-show-get-depth ()
   (notmuch-show-get-prop :depth))
 
-(defun notmuch-show-set-tags (tags)
+(defun notmuch-show-set-tags (tags &optional no-headerline-update)
   "Set the tags of the current message."
   (notmuch-show-set-prop :tags tags)
-  (notmuch-show-update-tags tags))
+  (notmuch-show-update-tags tags no-headerline-update))
 
 (defun notmuch-show-get-tags ()
   "Return the tags of the current message."
@@ -1778,7 +1779,8 @@ See `notmuch-tag' for information on the format of TAG-CHANGES."
  (let* ((current-tags (notmuch-show-get-tags))
 	(new-tags (notmuch-update-tags current-tags tag-changes)))
(unless (equal current-tags new-tags)
-	 (notmuch-show-set-tags new-tags))
+	 (notmuch-show-set-tags new-tags t)
+  (notmuch-show-update-header-line))
 
 (defun notmuch-show-add-tag ()
   "Same as `notmuch-show-tag' but sets initial input to '+'."
-- 
1.7.9.1




On Tue, 11 Dec 2012, Damien Cassou  wrote:
> 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
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH 07/10] emacs: Use --use-schema for search

2012-12-13 Thread Mark Walters
On Thu, 13 Dec 2012, Austin Clements  wrote:
> Quoth Mark Walters on Dec 08 at  8:48 am:
>> On Sun, 02 Dec 2012, Austin Clements  wrote:
>> > We detect the special exit statuses and use these to produce specific
>> > diagnostic messages.
>> > ---
>> >  emacs/notmuch-lib.el |   32 
>> >  emacs/notmuch.el |   17 +
>> >  2 files changed, 45 insertions(+), 4 deletions(-)
>> >
>> > diff --git a/emacs/notmuch-lib.el b/emacs/notmuch-lib.el
>> > index 9402456..49b0da6 100644
>> > --- a/emacs/notmuch-lib.el
>> > +++ b/emacs/notmuch-lib.el
>> > @@ -325,6 +325,38 @@ string), a property list of face attributes, or a 
>> > list of these."
>> >(put-text-property pos next 'face (cons face cur))
>> >(setq pos next)
>> >  
>> > +(defun notmuch-pop-up-error (msg)
>> > +  "Pop up an error buffer displaying MSG."
>> > +
>> > +  (let ((buf (get-buffer-create "*Notmuch errors*")))
>> > +(with-current-buffer buf
>> > +  (view-mode)
>> > +  (let ((inhibit-read-only t))
>> > +  (erase-buffer)
>> > +  (insert msg)
>> > +  (unless (bolp)
>> > +(insert "\n"))
>> > +  (goto-char (point-min
>> > +(pop-to-buffer buf)))
>> 
>> I am not sure about the erase-buffer in the above: do we definitely want
>> to remove all previous error information? For version mismatch possibly
>> we do but in patch 9 it is done for all show command-line error returns.
>
> Why wouldn't we want to use a cleared buffer in all cases?
> notmuch-pop-up-error is only ever used when a command terminates, so
> there's no danger of us clearing errors that the user hasn't seen yet.

Just to make sure I understand this: whenever an error occurs the error
popup appears so we see the message. Then the next error can safely
erase buffer before showing the new error message?

>> Incidentally why does show always pop-up an error but search only for
>> version-mismatches?
>
> Historical reasons, I suppose.  I was maintaining the status quo for
> search (which already had *some* error handling), but there was no
> error-handling status quo for show.  Probably search should be more
> vocal when the command fails.

Should notmuch-call-notmuch-process also be switched to this framework?
In particular that also puts errors in "*Notmuch errors*" so my earlier
concern may be valid in this case.

Best wishes

Mark
>
>> Otherwise this looks good to me (but I am not that familiar with lisp
>> error handling)
>> 
>> Best wishes
>> 
>> Mark
>> 
>> 
>> 
>> 
>> 
>> 
>> > +(defun notmuch-version-mismatch-error (exit-status)
>> > +  "Signal a schema version mismatch error.
>> > +
>> > +EXIT-STATUS must be the exit status of the notmuch CLI command,
>> > +and must have the value 20 or 21.  This function will pop up an
>> > +error buffer with a descriptive message and signal an error."
>> > +  (cond ((= exit-status 20)
>> > +   (notmuch-pop-up-error "Error: Version mismatch.
>> > +Emacs requested an older output format than supported by the notmuch CLI.
>> > +You may need to restart Emacs or upgrade your notmuch Emacs package."))
>> > +  ((= exit-status 21)
>> > +   (notmuch-pop-up-error "Error: Version mismatch.
>> > +Emacs requested a newer output format than supported by the notmuch CLI.
>> > +You may need to restart Emacs or upgrade your notmuch package."))
>> > +  (t
>> > +   (error "Bad exit status %d" exit-status)))
>> > +  (error "notmuch CLI version mismatch"))
>> > +
>> >  ;; Compatibility functions for versions of emacs before emacs 23.
>> >  ;;
>> >  ;; Both functions here were copied from emacs 23 with the following 
>> > copyright:
>> > diff --git a/emacs/notmuch.el b/emacs/notmuch.el
>> > index f9454d8..e1f28ca 100644
>> > --- a/emacs/notmuch.el
>> > +++ b/emacs/notmuch.el
>> > @@ -644,6 +644,7 @@ of the result."
>> >(exit-status (process-exit-status proc))
>> >(never-found-target-thread nil))
>> >  (when (memq status '(exit signal))
>> > +  (catch 'return
>> >(kill-buffer (process-get proc 'parse-buf))
>> >(if (buffer-live-p buffer)
>> >(with-current-buffer buffer
>> > @@ -655,8 +656,16 @@ of the result."
>> >  (insert "Incomplete search results (search process was 
>> > killed).\n"))
>> >  (when (eq status 'exit)
>> >(insert "End of search results.")
>> > -  (unless (= exit-status 0)
>> > -(insert (format " (process returned %d)" exit-status)))
>> > +  (cond ((or (= exit-status 20) (= exit-status 21))
>> > + (kill-buffer)
>> > + (condition-case err
>> > + (notmuch-version-mismatch-error exit-status)
>> > +   ;; Strange things happen when you signal
>> > +   ;; an error from a sentinel.
>> > +   (error (throw 'return nil
>> > +((/= exit-status 0)
>> > + (insert (format " (process returned %d)"
>> > +  

[PATCH (draft)] contrib: pick: close message pane when quitting from show in the message pane

2012-12-13 Thread Mark Walters
This is a way of trying to make sure notmuch-pick cleans up the split
buffer after itself.
---

Currently if the focus gets into the message pane and then the user
quits from that pane the display stays split. This is an attempt to
fix that. This seems to work but I don't know if there is a better
solution. However, I would welcome any feedback on the user experience
with this patch applied.

Best wishes

Mark




 contrib/notmuch-pick/notmuch-pick.el |   17 +
 1 files changed, 17 insertions(+), 0 deletions(-)

diff --git a/contrib/notmuch-pick/notmuch-pick.el 
b/contrib/notmuch-pick/notmuch-pick.el
index 043e9e7..79ef319 100644
--- a/contrib/notmuch-pick/notmuch-pick.el
+++ b/contrib/notmuch-pick/notmuch-pick.el
@@ -160,6 +160,9 @@
 (defvar notmuch-pick-message-window nil)
 (make-variable-buffer-local 'notmuch-pick-message-window)
 (put 'notmuch-pick-message-window 'permanent-local t)
+(defvar notmuch-show-message-window nil)
+(make-variable-buffer-local 'notmuch-show-message-window)
+(put 'notmuch-show-message-window 'permanent-local t)
 (defvar notmuch-pick-message-buffer nil)
 (make-variable-buffer-local 'notmuch-pick-message-buffer-name)
 (put 'notmuch-pick-message-buffer-name 'permanent-local t)
@@ -389,6 +392,16 @@ Does NOT change the database."
 (notmuch-prettify-subject (notmuch-search-find-subject)))
   (notmuch-pick-show-match-message-with-wait))
 
+;;over-ride this function to try and kill off message panes
+(defun notmuch-kill-this-buffer ()
+  "Kill the current buffer."
+  (interactive)
+  (let ((buffer (current-buffer)))
+(when (and (window-live-p notmuch-show-message-window)
+(eq (window-buffer notmuch-show-message-window) buffer))
+  (delete-window notmuch-show-message-window))
+(kill-buffer buffer)))
+
 (defun notmuch-pick-show-message ()
   "Show the current message (in split-pane)."
   (interactive)
@@ -406,6 +419,10 @@ Does NOT change the database."
(let ((notmuch-show-indent-messages-width 0))
  (setq current-prefix-arg '(4))
  (setq buffer (notmuch-show id nil nil nil
+  ;; We need the let as notmuch-pick-message-window is buffer local.
+  (let ((window notmuch-pick-message-window))
+   (with-current-buffer buffer
+ (setq notmuch-show-message-window window)))
   (notmuch-pick-tag-update-display (list "-unread"))
   (setq notmuch-pick-message-buffer buffer
 
-- 
1.7.9.1

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


[PATCH v2 5/5] emacs: show: set default show-all-multipart/alternatives to nil

2012-12-13 Thread Mark Walters
Now that the invisibility display of parts is present we no longer
need to force the display of all multipart/alternatives: users can
toggle them for themselves when needed.
---
 emacs/notmuch-show.el |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 202258f..c43dd32 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -94,7 +94,7 @@ visible for any given message."
   :group 'notmuch-hooks)
 
 ;; Mostly useful for debugging.
-(defcustom notmuch-show-all-multipart/alternative-parts t
+(defcustom notmuch-show-all-multipart/alternative-parts nil
   "Should all parts of multipart/alternative parts be shown?"
   :type 'boolean
   :group 'notmuch-show)
-- 
1.7.9.1

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


[PATCH v2 4/5] emacs: wash: fix fake-diff part to include msg parameter

2012-12-13 Thread Mark Walters
The fake-diff part from notmuch wash did not pass the msg parameter to
notmuch-show-insert-bodypart. Previously this did not matter, but is
now needed to get the overlays right for invisibility.
---
 emacs/notmuch-wash.el |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/emacs/notmuch-wash.el b/emacs/notmuch-wash.el
index 7d003a2..b2affba 100644
--- a/emacs/notmuch-wash.el
+++ b/emacs/notmuch-wash.el
@@ -378,7 +378,7 @@ for error."
   (plist-get
(plist-get msg :headers) :Subject
(delete-region (point-min) (point-max))
-   (notmuch-show-insert-bodypart nil part depth)
+   (notmuch-show-insert-bodypart msg part depth)
 
 ;;
 
-- 
1.7.9.1

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


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

2012-12-13 Thread Mark Walters
This makes 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 the argument HIDE is passed down to
notmuch-show-insert-part-overlays to request that the part be hidden
by default but this is not acted on yet.
---
 emacs/notmuch-show.el |   61 +
 1 files changed, 46 insertions(+), 15 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 06f7ca5..3f2f277 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -567,11 +567,10 @@ message at DEPTH in the current thread."
 ;; but it's not clear that this is the wrong thing to do - which
 ;; 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)"
+   (let* ((inner-type (plist-get inner-part :content-type))
+ (hide (not (or notmuch-show-all-multipart/alternative-parts
+  (string= chosen-type inner-type)
+ (notmuch-show-insert-bodypart msg inner-part depth hide)))
  inner-parts)
 
 (when notmuch-show-indent-multipart
@@ -839,17 +838,49 @@ 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 hide)
+  "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.
+(when (and button (/= 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 '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.
+   (dolist (inner (overlays-in part-beg end))
+ (when (and (>= (overlay-start inner) part-beg)
+  (<= (overlay-end inner) end))
+ (overlay-put inner 'invisible
+  (cons invis-spec (overlay-get inner 
'invisible)
+
+   (button-put button 'invisibility-spec invis-spec)
+   (button-put button 'overlay overlay)
+
+(defun notmuch-show-insert-bodypart (msg part depth &optional hide)
+  "Insert the body part PART at depth DEPTH in the current thread.
+
+If HIDE is non-nil 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) hide)))
 
 (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 v2 3/5] emacs: show: add invisibility button action

2012-12-13 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, 34 insertions(+), 2 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 3f2f277..202258f 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)
@@ -554,6 +555,28 @@ 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)
+  (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 " ]" " (hidden) ]"))
+   (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
+
 (defun notmuch-show-multipart/*-to-list (part)
   (mapcar (lambda (inner-part) (plist-get inner-part :content-type))
  (plist-get part :content)))
@@ -863,7 +886,13 @@ message at DEPTH in the current thread."
   (cons invis-spec (overlay-get inner 
'invisible)
 
(button-put button 'invisibility-spec invis-spec)
-   (button-put button 'overlay overlay)
+   (button-put button 'overlay overlay))
+
+  ;; We toggle the button for hidden parts as that gets the
+  ;; button label right.
+  (save-excursion
+   (when hide
+ (notmuch-show-toggle-invisible-part-action button))
 
 (defun notmuch-show-insert-bodypart (msg part depth &optional hide)
   "Insert the body part PART at depth DEPTH in the current thread.
@@ -1992,7 +2021,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 (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


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

2012-12-13 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 |   18 +-
 1 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index d7fa10e..06f7ca5 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -483,17 +483,17 @@ 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 (when name (concat name ": "))
+   declared-type
+   (unless (string-equal declared-type content-type)
+ (concat " (as " content-type ")"))
+   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 v2 0/5] Use invisibility to toggle display of all parts including multipart

2012-12-13 Thread Mark Walters
This is version 2 of the patch series (version 1 at
id:1354663662-20524-1-git-send-email-markwalters1...@gmail.com)

Almost all of the changes and fixes are in response to Austin's
review. I have changed things as he suggested.

There are two small extra tiny patches in this version: I set the
default value of notmuch-show-all-multipart/alternative-parts to nil.

The second is to fix a bug reported by Jani: that fake-patch parts (as
provided by notmuch-wash) did not get hidden when the whole message
was hidden.  This was due to notmuch-wash-convert-inline-patch-to-part
not passing a msg on down to notmuch-show-insert-bodypart. Previously
this did not matter but with with this series msg is needed to
construct the correct overlays.

Best wishes

Mark




Mark Walters (5):
  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: wash: fix fake-diff part to include msg parameter
  emacs: show: set default show-all-multipart/alternatives to nil

 emacs/notmuch-show.el |  115 ++---
 emacs/notmuch-wash.el |2 +-
 2 files changed, 90 insertions(+), 27 deletions(-)

-- 
1.7.9.1

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


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

2012-12-13 Thread Mark Walters

On Tue, 11 Dec 2012, Austin Clements  wrote:
> On Tue, 04 Dec 2012, Mark Walters  wrote:
>> 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) ]"))
>
> s/not shown/hidden/?

Done

>
>> +(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)

This is where point gets left by this toggle button function: I don't
know if it should move point. Mostly it only matters if the user uses
the mouse (as otherwise point is on the button).

>> +  (unless no-redisplay
>> +(force-window-update)
>> +(redisplay t)
>
> Is the t argument necessary?  Actually, are either (force-window-update)
> or (redisplay) necessary?

None of this seems needed: I had just copied it from notmuch-wash. 

Best wishes

Mark

>> +
>>  (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] emacs: show: add overlays for each part

2012-12-13 Thread Mark Walters

Hi 

Many thanks for the review: I will post a new version shortly. Some
comments inline below:

On Tue, 11 Dec 2012, Austin Clements  wrote:
> On Tue, 04 Dec 2012, Mark Walters  wrote:
>> This make notmuch-show-insert-bodypart add an overlay for any
>
> s/make/makes/
>
>> 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
>
> not-shown is really an argument (I found this confusing).
>
>> 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
>
> Since notmuch-show-all-multipart/alternative-parts was basically a hack
> around our poor multipart/alternative support, I think this series (or a
> follow up patch) should change its default to nil or even eliminate it
> entirely.

I have added a patch at the end setting this to nil by default.

>> + (string= chosen-type 
>> inner-type))
>
> You could let-bind the (not (or ..)) to some variable ("hide" perhaps)
> in the let above to avoid this crazy line length.
>
>>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)
>
> s/not-shown/hide/?  Or hidden?
>
>> +  "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))
>
> (when (and button (/= 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))
>
> Non-trivial buffer invisibility specs are really bad for performance
> (Emacs' renderer does the obvious O(n^2) thing when rendering a buffer
> with an invisibility spec).  Unfortunately, because of notmuch-wash and
> the way overlays with trivial 'invisible properties combine with
> overlays with list-type 'invisible properties combine, I don't think it
> can be avoided.  But if we get rid of buffer invisibility specs from
> notmuch-wash, this code can also get much simpler.

How do you plan to get rid of the invisibility properties from notmuch
wash? 

>> +(overlay-put overlay 'isearch-open-invisible 
>> #'notmuch-wash-region-isearch-show)
>
> This will leave the "(not shown)" in the part header if isearch unfolds
> the part.
>
> Do we even want isearch to unfold parts?  It's not clear we do for
> multipart/alternative.  If we do, probably the right thing is something
> like

I don't think we want to search hidden bodyparts so I just deleted this
line.

>
> (overlay-put overlay 'notmuch-show-part-button button)
> (overlay-put overlay 'isearch-open-invisible #'notmuch-show-part-isearch-open)
>
> (defun notmuch-show-part-isearch-open (overlay)
>   (notmuch-show-toggle-invisible-part-action
>(overlay-get overlay 'notmuch-show-part-button)))
>
>> +(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.
>
> Interesting.  In the simple case of using nil or t for 'invisible, the
> specs do combine as one would expect, but you're right that, with a
> non-trivial i