--- /dev/null
+Return-Path: <damien.cassou@gmail.com>\r
+X-Original-To: notmuch@notmuchmail.org\r
+Delivered-To: notmuch@notmuchmail.org\r
+Received: from localhost (localhost [127.0.0.1])\r
+ by olra.theworths.org (Postfix) with ESMTP id EA7A3431FB6\r
+ for <notmuch@notmuchmail.org>; Sat, 10 Nov 2012 08:42:35 -0800 (PST)\r
+X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
+X-Spam-Flag: NO\r
+X-Spam-Score: 1.7\r
+X-Spam-Level: *\r
+X-Spam-Status: No, score=1.7 tagged_above=-999 required=5\r
+ tests=[DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1,\r
+ FREEMAIL_FROM=0.001, FREEMAIL_REPLY=2.499, RCVD_IN_DNSWL_LOW=-0.7]\r
+ autolearn=disabled\r
+Received: from olra.theworths.org ([127.0.0.1])\r
+ by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
+ with ESMTP id 0sUuV0LU3a+5 for <notmuch@notmuchmail.org>;\r
+ Sat, 10 Nov 2012 08:42:34 -0800 (PST)\r
+Received: from mail-wi0-f179.google.com (mail-wi0-f179.google.com\r
+ [209.85.212.179]) (using TLSv1 with cipher RC4-SHA (128/128 bits))\r
+ (No client certificate requested)\r
+ by olra.theworths.org (Postfix) with ESMTPS id C4770431FAF\r
+ for <notmuch@notmuchmail.org>; Sat, 10 Nov 2012 08:42:33 -0800 (PST)\r
+Received: by mail-wi0-f179.google.com with SMTP id hm6so1027954wib.2\r
+ for <notmuch@notmuchmail.org>; Sat, 10 Nov 2012 08:42:32 -0800 (PST)\r
+DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113;\r
+ h=from:to:cc:subject:date:message-id:x-mailer:mime-version\r
+ :content-type:content-transfer-encoding;\r
+ bh=SokKGH5nL2A7mAwfJwWFkf3dGi1c6ohOxYnwTr9Cr/w=;\r
+ b=TK6sze1FbLOckGUlw+NMdx2Kytmz0sBCuYCrluwNfVBZtIjRLC10MvmbT37OLUYfHH\r
+ 5oX7RoMPbJBP1sD3KuYedWkRdMb+dmtwiyRjw1Bpxatqvg3CGOofB0LlXP1FwWTqI29Y\r
+ 2P4gbvN9XezWDiAbyWMlhIRJGPuWAo8x9cXwu/OFQgmwvO0lRf//N49n3BWwwv643krb\r
+ j9PssL9rGAtaaGu5LK9Ha80zfoTbxZ799/bfCMT9n9WrGqBTd9NyBY7n2cem1gFxCTvX\r
+ hGb43DiHsjvaFfr13x2hhBjSFc2wMw0dQ1uWvvjXqJ9vPzg/VqbhNh5m45o+yGUcHScV\r
+ KBWA==\r
+Received: by 10.180.97.35 with SMTP id dx3mr7785198wib.14.1352565752453;\r
+ Sat, 10 Nov 2012 08:42:32 -0800 (PST)\r
+Received: from localhost.localdomain (ble59-4-82-228-190-150.fbx.proxad.net.\r
+ [82.228.190.150])\r
+ by mx.google.com with ESMTPS id i6sm6952373wix.5.2012.11.10.08.42.31\r
+ (version=TLSv1/SSLv3 cipher=OTHER);\r
+ Sat, 10 Nov 2012 08:42:31 -0800 (PST)\r
+From: Damien Cassou <damien.cassou@gmail.com>\r
+To: notmuch mailing list <notmuch@notmuchmail.org>\r
+Subject: [PATCH v2] emacs: display tags in notmuch-show with links\r
+Date: Sat, 10 Nov 2012 17:41:59 +0100\r
+Message-Id: <1352565719-12397-1-git-send-email-damien.cassou@gmail.com>\r
+X-Mailer: git-send-email 1.7.10.4\r
+MIME-Version: 1.0\r
+Content-Type: text/plain; charset=UTF-8\r
+Content-Transfer-Encoding: 8bit\r
+X-BeenThere: notmuch@notmuchmail.org\r
+X-Mailman-Version: 2.1.13\r
+Precedence: list\r
+List-Id: "Use and development of the notmuch mail system."\r
+ <notmuch.notmuchmail.org>\r
+List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
+ <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
+List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
+List-Post: <mailto:notmuch@notmuchmail.org>\r
+List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
+List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
+ <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
+X-List-Received-Date: Sat, 10 Nov 2012 16:42:36 -0000\r
+\r
+This patch obsoletes\r
+id:1352234344-28119-1-git-send-email-damien.cassou@gmail.com\r
+\r
+This patch makes clickable all tags that appear in notmuch-show\r
+buffers. Each tag is a link to open a new notmuch-search buffer for\r
+this tag. Additionally, the buffer's header-line now shows the\r
+thread's tags (also clickable).\r
+\r
+This patch is the first one of an upcoming series whose goal is to\r
+integrate notmuch-labeler into notmuch. See the following for more\r
+details:\r
+https://github.com/DamienCassou/notmuch-labeler\r
+\r
+This patch includes header-button.el, a package contributed by Jonas\r
+Bernoulli that fixes a limitation of the button.el Emacs library.\r
+Jonas gave me the authorization to include the package in notmuch, but\r
+only if the package is first searched in the existing `load-path'. See\r
+this thread:\r
+id:CA+y5ggiGrAcicQLeskaXFoxYyJQVVXZ1VRX=XS8zPFR9_mBFxA@mail.gmail.com\r
+\r
+With respect to v1, I took care of the comments you made:\r
+- Renamed tager to tagger;\r
+- Avoided an additional call to notmuch by reading existing data in\r
+ the buffer with `notmuch-show-mapc';\r
+- As a result of previous point, a thread's tags now equals the union\r
+ of the emails' tags that are visible;\r
+- Stopped stripping "thread:" from the thread-id to add it back\r
+ later.\r
+\r
+With respect to v1, I added the following:\r
+- Each label on each message is now clickable;\r
+- Moved header-button.el to fallback-libs/ and only load this one when\r
+ it is not already in the `load-path'.\r
+\r
+You can follow this patch series on\r
+https://github.com/DamienCassou/notmuch/tree/labeler-integration\r
+\r
+Signed-off-by: Damien Cassou <damien.cassou@gmail.com>\r
+---\r
+ emacs/fallback-libs/.nosearch | 1 +\r
+ emacs/fallback-libs/header-button.el | 138 ++++++++++++++++++++++++++++++++++\r
+ emacs/notmuch-show.el | 33 ++++++--\r
+ emacs/notmuch-tagger.el | 129 +++++++++++++++++++++++++++++++\r
+ test/emacs | 61 +++++++++++++++\r
+ 5 files changed, 355 insertions(+), 7 deletions(-)\r
+ create mode 100644 emacs/fallback-libs/.nosearch\r
+ create mode 100644 emacs/fallback-libs/header-button.el\r
+ create mode 100644 emacs/notmuch-tagger.el\r
+\r
+diff --git a/emacs/fallback-libs/.nosearch b/emacs/fallback-libs/.nosearch\r
+new file mode 100644\r
+index 0000000..0a01dc9\r
+--- /dev/null\r
++++ b/emacs/fallback-libs/.nosearch\r
+@@ -0,0 +1 @@\r
++This file prevents Emacs from adding the directory to the `load-path'.\r
+diff --git a/emacs/fallback-libs/header-button.el b/emacs/fallback-libs/header-button.el\r
+new file mode 100644\r
+index 0000000..05f6f32\r
+--- /dev/null\r
++++ b/emacs/fallback-libs/header-button.el\r
+@@ -0,0 +1,138 @@\r
++;;; header-button.el --- clickable buttons in header lines\r
++\r
++;; Copyright (C) 2010-2012 Jonas Bernoulli\r
++\r
++;; Author: Jonas Bernoulli <jonas@bernoul.li>\r
++;; Created: 20100604\r
++;; Version: 0.2.2\r
++;; Homepage: https://github.com/tarsius/header-button\r
++;; Keywords: extensions\r
++\r
++;; This file is not part of GNU Emacs.\r
++\r
++;; This file is free software; you can redistribute it and/or modify\r
++;; it under the terms of the GNU General Public License as published by\r
++;; the Free Software Foundation; either version 3, or (at your option)\r
++;; any later version.\r
++\r
++;; This file is distributed in the hope that it will be useful,\r
++;; but WITHOUT ANY WARRANTY; without even the implied warranty of\r
++;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
++;; GNU General Public License for more details.\r
++\r
++;; You should have received a copy of the GNU General Public License\r
++;; along with this program. If not, see <http://www.gnu.org/licenses/>.\r
++\r
++;;; Commentary:\r
++\r
++;; This package extends `button' by adding support for adding buttons to\r
++;; the header line. Since the header line is very limited compared to a\r
++;; buffer most of the functionality provided by `button' is not available\r
++;; for buttons in the header line.\r
++\r
++;; While `button' provides the function `insert-button' (as well as\r
++;; others) to insert a button into a buffer at point, something similar\r
++;; can't be done here, due to the lack of point in header lines.\r
++\r
++;; Instead use `header-button-format' like this:\r
++;;\r
++;; (setq header-line-format\r
++;; (concat "Here's a button: "\r
++;; (header-button-format "Click me!" :action 'my-action)))\r
++\r
++;; Like with `button' you can create your own derived button types:\r
++;;\r
++;; (define-button-type 'my-header\r
++;; :supertype 'header\r
++;; :action 'my-action)\r
++;;\r
++;; (setq header-line-format\r
++;; (concat (header-button-format "Click me!" :action 'my-action) " "\r
++;; (header-button-format "No me!" :type 'my-header)))\r
++\r
++;; The function associated with `:action' is called with the button plist\r
++;; as only argument. Do no use `plist-get' to extract a value from it.\r
++;; Instead use `header-button-get' which will also extract values stored\r
++;; in it's type.\r
++;;\r
++;; (defun my-action (button)\r
++;; (message "This button labeled `%s' belongs to category `%s'"\r
++;; (header-button-label button)\r
++;; (header-button-get button 'category)))\r
++\r
++;;; Code:\r
++\r
++(require 'button)\r
++\r
++(defvar header-button-map\r
++ (let ((map (make-sparse-keymap)))\r
++ ;; $$$ follow-link does not work here\r
++ (define-key map [header-line mouse-1] 'header-button-push)\r
++ (define-key map [header-line mouse-2] 'header-button-push)\r
++ map)\r
++ "Keymap used by buttons in header lines.")\r
++\r
++(define-button-type 'header\r
++ 'keymap header-button-map\r
++ 'help-echo (purecopy "mouse-1: Push this button"))\r
++\r
++(defun header-button-get (button prop)\r
++ "Get the property of header button BUTTON named PROP."\r
++ (let ((entry (plist-member button prop)))\r
++ (if entry\r
++ (cadr entry)\r
++ (get (plist-get button 'category) prop))))\r
++\r
++(defun header-button-label (button)\r
++ "Return header button BUTTON's text label."\r
++ (plist-get button 'label))\r
++\r
++(defun header-button-format (label &rest properties)\r
++ "Format a header button string with the label LABEL.\r
++The remaining arguments form a sequence of PROPERTY VALUE pairs,\r
++specifying properties to add to the button.\r
++In addition, the keyword argument :type may be used to specify a\r
++button-type from which to inherit other properties; see\r
++`define-button-type'.\r
++\r
++To actually create the header button set the value of variable\r
++`header-line-format' to the string returned by this function\r
++\(or a string created by concatenating that string with others."\r
++ (let ((type-entry (or (plist-member properties 'type)\r
++ (plist-member properties :type))))\r
++ (when (plist-get properties 'category)\r
++ (error "Button `category' property may not be set directly"))\r
++ (if (null type-entry)\r
++ (setq properties\r
++ (cons 'category\r
++ (cons (button-category-symbol 'header) properties)))\r
++ (setcar type-entry 'category)\r
++ (setcar (cdr type-entry)\r
++ (button-category-symbol (car (cdr type-entry)))))\r
++ (apply #'propertize label\r
++ (nconc (list 'button (list t) 'label label) properties))))\r
++\r
++(defun header-button-activate (button)\r
++ "Call header button BUTTON's `:action' property."\r
++ ;; Older versions only supported `:action' but button.el uses\r
++ ;; `action' instead. Now we support both and query `:action'\r
++ ;; first because `action' defaults to function `ignore'.\r
++ (funcall (or (header-button-get button :action)\r
++ (header-button-get button 'action))\r
++ button))\r
++\r
++(defun header-button-push ()\r
++ "Perform the action specified by the pressed header button."\r
++ (interactive)\r
++ (let* ((posn (event-start last-command-event))\r
++ (object (posn-object posn))\r
++ (buffer (window-buffer (posn-window posn)))\r
++ (button (text-properties-at (cdr object) (car object))))\r
++ (with-current-buffer buffer\r
++ (header-button-activate button))))\r
++\r
++(provide 'header-button)\r
++;; Local Variables:\r
++;; indent-tabs-mode: nil\r
++;; End:\r
++;;; header-button.el ends here\r
+diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el\r
+index d061367..6f38381 100644\r
+--- a/emacs/notmuch-show.el\r
++++ b/emacs/notmuch-show.el\r
+@@ -36,6 +36,7 @@\r
+ (require 'notmuch-mua)\r
+ (require 'notmuch-crypto)\r
+ (require 'notmuch-print)\r
++(require 'notmuch-tagger)\r
+ \r
+ (declare-function notmuch-call-notmuch-process "notmuch" (&rest args))\r
+ (declare-function notmuch-fontify-headers "notmuch" nil)\r
+@@ -430,10 +431,11 @@ message at DEPTH in the current thread."\r
+ (notmuch-show-clean-address (plist-get headers :From))\r
+ " ("\r
+ date\r
+- ") ("\r
+- (propertize (mapconcat 'identity tags " ")\r
+- 'face 'notmuch-tag-face)\r
+- ")\n")\r
++ ") "\r
++ (propertize\r
++ (format-mode-line (notmuch-tagger-present-tags tags))\r
++ 'face 'notmuch-tag-face)\r
++ "\n")\r
+ (overlay-put (make-overlay start (point)) 'face 'notmuch-message-summary-face)))\r
+ \r
+ (defun notmuch-show-insert-header (header header-value)\r
+@@ -1082,11 +1084,28 @@ function is used."\r
+ \r
+ (jit-lock-register #'notmuch-show-buttonise-links)\r
+ \r
+- ;; Set the header line to the subject of the first message.\r
+- (setq header-line-format (notmuch-show-strip-re (notmuch-show-get-subject)))\r
+-\r
++ (notmuch-show-update-header-line)\r
+ (run-hooks 'notmuch-show-hook))))\r
+ \r
++(defun notmuch-show-thread-tags ()\r
++ "Return the list of tags for the current thread."\r
++ (let ((tags (list)))\r
++ (notmuch-show-mapc (lambda ()\r
++ (mapcar (lambda (elt)\r
++ ;; Avoid adding duplicate tags\r
++ (add-to-list 'tags elt))\r
++ (notmuch-show-get-tags))))\r
++ tags))\r
++\r
++(defun notmuch-show-update-header-line ()\r
++ "Make the header-line show the thread's subject and tags."\r
++ (let ((thread-subject (notmuch-show-strip-re (notmuch-show-get-subject))))\r
++ (setq header-line-format\r
++ (list\r
++ thread-subject\r
++ " "\r
++ (notmuch-tagger-present-tags (notmuch-show-thread-tags) t)))))\r
++\r
+ (defun notmuch-show-capture-state ()\r
+ "Capture the state of the current buffer.\r
+ \r
+diff --git a/emacs/notmuch-tagger.el b/emacs/notmuch-tagger.el\r
+new file mode 100644\r
+index 0000000..e825df5\r
+--- /dev/null\r
++++ b/emacs/notmuch-tagger.el\r
+@@ -0,0 +1,129 @@\r
++;; notmuch-tagger.el --- Library to show labels as links\r
++;;\r
++;; Copyright © Damien Cassou\r
++;;\r
++;; This file is part of Notmuch.\r
++;;\r
++;; Notmuch is free software: you can redistribute it and/or modify it\r
++;; under the terms of the GNU General Public License as published by\r
++;; the Free Software Foundation, either version 3 of the License, or\r
++;; (at your option) any later version.\r
++;;\r
++;; Notmuch is distributed in the hope that it will be useful, but\r
++;; WITHOUT ANY WARRANTY; without even the implied warranty of\r
++;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
++;; General Public License for more details.\r
++;;\r
++;; You should have received a copy of the GNU General Public License\r
++;; along with Notmuch. If not, see <http://www.gnu.org/licenses/>.\r
++;;\r
++;; Authors: Damien Cassou <damien.cassou@gmail.com>\r
++;;; Commentary:\r
++;;\r
++;;; Code:\r
++;;\r
++\r
++(require 'button)\r
++\r
++(or (require 'header-button nil t)\r
++ (let ((load-path\r
++ (cons (expand-file-name\r
++ "fallback-libs"\r
++ (file-name-directory (or load-file-name buffer-file-name)))\r
++ load-path)))\r
++ (require 'header-button)))\r
++\r
++(defun notmuch-tagger-separate-elems (list sep)\r
++ "Return a list with all elements of LIST separated by SEP."\r
++ (let ((first t)\r
++ (res nil))\r
++ (dolist (elt (reverse list) res)\r
++ (unless first\r
++ (push sep res))\r
++ (setq first nil)\r
++ (push elt res))))\r
++\r
++(defun notmuch-tagger-goto-target (target)\r
++ "Show a `notmuch-search' buffer for the TARGET tag."\r
++ (notmuch-search (concat "tag:" target)))\r
++\r
++(defun notmuch-tagger-headerline-button-action (button)\r
++ "Open `notmuch-search' for the tag referenced by BUTTON."\r
++ (let ((tag (header-button-get button 'notmuch-tagger-tag)))\r
++ (notmuch-tagger-goto-target tag)))\r
++\r
++(defun notmuch-tagger-body-button-action (button)\r
++ "Open `notmuch-search' for the tag referenced by BUTTON."\r
++ (let ((tag (button-get button 'notmuch-tagger-tag)))\r
++ (notmuch-tagger-goto-target tag)))\r
++\r
++(define-button-type 'notmuch-tagger-headerline-button-type\r
++ 'supertype 'header\r
++ 'action #'notmuch-tagger-headerline-button-action\r
++ 'follow-link t)\r
++\r
++(define-button-type 'notmuch-tagger-body-button-type\r
++ 'action #'notmuch-tagger-body-button-action\r
++ 'follow-link t)\r
++\r
++(defun notmuch-tagger-make-headerline-link (target)\r
++ "Return a property list that presents a link to TARGET.\r
++\r
++TARGET is a notmuch tag.\r
++The returned property list will only work in the header-line."\r
++ (header-button-format\r
++ target\r
++ :type 'notmuch-tagger-headerline-button-type\r
++ 'notmuch-tagger-tag target\r
++ 'help-echo (format "%s: Search other messages like this" target)))\r
++\r
++(defun notmuch-tagger-make-body-link (target)\r
++ "Return a property list that presents a link to TARGET.\r
++\r
++TARGET is a notmuch tag.\r
++The returned property list will work everywhere except in the\r
++header-line."\r
++ (let ((button (copy-sequence target)))\r
++ (make-text-button\r
++ button nil\r
++ 'type 'notmuch-tagger-body-button-type\r
++ 'notmuch-tagger-tag target\r
++ 'help-echo (format "%s: Search other messages like this" target))\r
++ button))\r
++\r
++(defun notmuch-tagger-make-link (target headerline)\r
++"Return a property list that presents a link to TARGET.\r
++\r
++TARGET is a notmuch tag.\r
++\r
++If HEADERLINE is non-nil the returned list will be ready for\r
++inclusion in the buffer's header-line. HEADERLINE must be nil in\r
++all other cases."\r
++ (if headerline\r
++ (notmuch-tagger-make-headerline-link target)\r
++ (notmuch-tagger-make-body-link target)))\r
++\r
++(defun notmuch-tagger-format-tags (tags &optional headerline)\r
++ "Return a format list for TAGS suitable for use in header line.\r
++See Info node `(elisp)Mode Line Format' for more information.\r
++\r
++If HEADERLINE is non-nil the returned list will be ready for\r
++inclusion in the buffer's header-line. HEADERLINE must be nil in\r
++all other cases."\r
++ (mapcar\r
++ (lambda (tag) (notmuch-tagger-make-link tag headerline))\r
++ tags))\r
++\r
++(defun notmuch-tagger-present-tags (tags &optional headerline)\r
++ "Return a property list which nicely presents all TAGS.\r
++\r
++If HEADERLINE is non-nil the returned list will be ready for\r
++inclusion in the buffer's header-line. HEADERLINE must be nil in\r
++all other cases."\r
++ (list\r
++ "("\r
++ (notmuch-tagger-separate-elems (notmuch-tagger-format-tags tags headerline) " ")\r
++ ")"))\r
++\r
++(provide 'notmuch-tagger)\r
++;;; notmuch-tagger.el ends here\r
+diff --git a/test/emacs b/test/emacs\r
+index 44f641e..ecdc841 100755\r
+--- a/test/emacs\r
++++ b/test/emacs\r
+@@ -820,5 +820,66 @@ Date: Fri, 05 Jan 2001 15:43:57 +0000\r
+ EOF\r
+ test_expect_equal_file OUTPUT EXPECTED\r
+ \r
++test_begin_subtest "Extracting all tags from a thread"\r
++add_message \\r
++ '[subject]="Extracting all tags from a thread"' \\r
++ '[body]="body 1"'\r
++parent=${gen_msg_id}\r
++add_message \\r
++ '[subject]="Extracting all tags from a thread"' \\r
++ '[body]="body 2"' \\r
++ "[in-reply-to]=\<$parent\>"\r
++add_message \\r
++ '[subject]="Extracting all tags from a thread"' \\r
++ '[body]="body 3"' \\r
++ "[in-reply-to]=\<$parent\>"\r
++latest=${gen_msg_id}\r
++# Extract the thread-id from one of the emails\r
++thread_id=$(notmuch search id:${latest} | sed -e "s/thread:\([a-f0-9]*\).*/\1/")\r
++# Add tag "mytagfoo" to one of the emails\r
++notmuch tag +mytagfoo id:${latest}\r
++test_emacs_expect_t \\r
++ "(notmuch-show \"thread:${thread_id}\")\r
++ (let ((output (notmuch-show-thread-tags))\r
++ (expected '(\"inbox\" \"mytagfoo\" \"unread\")))\r
++ (notmuch-test-expect-equal\r
++ (sort output #'string<)\r
++ (sort expected #'string<)))"\r
++\r
++test_begin_subtest "The tags appear in the header-line of notmuch-show"\r
++add_message \\r
++ '[subject]="foo bar"' \\r
++ '[body]="body 1"'\r
++parent=${gen_msg_id}\r
++# Add tag "mytagfoo" to one of the emails\r
++notmuch tag +mytagfoo id:${parent}\r
++# Extract the thread-id from one of the emails\r
++thread_id=$(notmuch search id:${latest} | sed -e "s/thread:\([a-f0-9]*\).*/\1/")\r
++test_emacs_expect_t \\r
++ "(notmuch-show \"thread:${thread_id}\")\r
++ (if (string-match-p \"mytagfoo\" (format-mode-line header-line-format))\r
++ t\r
++ \"The tag mytagfoo was not in the header-line-format\")"\r
++\r
++test_begin_subtest "The tags of notmuch-show emails are clickable"\r
++add_message \\r
++ '[subject]="foo bar"' \\r
++ '[body]="body 1"'\r
++parent=${gen_msg_id}\r
++# Add tag "mytagfoo" to one of the emails\r
++notmuch tag +mytagfoo id:${parent}\r
++# Extract the thread-id from one of the emails\r
++thread_id=$(notmuch search id:${latest} | sed -e "s/thread:\([a-f0-9]*\).*/\1/")\r
++test_emacs_expect_t \\r
++ "(notmuch-show \"thread:${thread_id}\")\r
++ (goto-char (point-min))\r
++ (re-search-forward \"mytagfoo\")\r
++ (backward-char) ;; to be 'in' the tag\r
++ (unless (eq major-mode 'notmuch-show-mode)\r
++ (error \"We must be in notmch-show at this point but we are in %s.\" major-mode))\r
++ (push-button) ;; simulate a press on the RET key\r
++ (if (eq major-mode 'notmuch-search-mode)\r
++ t\r
++ (format \"We must be in notmch-search at this point but we are in %s.\" major-mode))"\r
+ \r
+ test_done\r
+-- \r
+1.7.10.4\r
+\r