unofficial mirror of notmuch@notmuchmail.org
 help / color / mirror / code / Atom feed
* [RFC PATCH v2 0/3] notmuch-pick: an emacs threaded message view with split-pane
@ 2012-02-12 18:49 Mark Walters
  2012-02-12 18:49 ` [RFC PATCH v2 1/3] cli: notmuch-show changes to support pick Mark Walters
                   ` (16 more replies)
  0 siblings, 17 replies; 26+ messages in thread
From: Mark Walters @ 2012-02-12 18:49 UTC (permalink / raw)
  To: notmuch

Here is a rebased version of the notmuch-pick patch set
id:"87d39k1gvi.fsf@qmul.ac.uk". It now applies directly 
to master since Jani's notmuch-show command line parsing 
has been pushed.

It includes the significant bug fix (at least for anyone working 
with a dark background) from Daniel making matched messages 
highlight color both configurable and have a sensible default.
These are in the notmuch-pick subgroup of the customize menus.

Best wishes

Mark

Mark Walters (3):
  cli: notmuch-show changes to support pick
  emacs: changes to other files to support notmuch-pick
  emacs: add notmuch-pick itself

 emacs/Makefile.local   |    3 +-
 emacs/notmuch-hello.el |   10 +
 emacs/notmuch-lib.el   |    4 +
 emacs/notmuch-pick.el  |  585 ++++++++++++++++++++++++++++++++++++++++++++++++
 emacs/notmuch-query.el |    4 +-
 emacs/notmuch-show.el  |   25 ++-
 emacs/notmuch.el       |    8 +
 notmuch-client.h       |    9 +-
 notmuch-show.c         |   90 +++++++-
 9 files changed, 722 insertions(+), 16 deletions(-)
 create mode 100644 emacs/notmuch-pick.el

-- 
1.7.2.3

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [RFC PATCH v2 1/3] cli: notmuch-show changes to support pick
  2012-02-12 18:49 [RFC PATCH v2 0/3] notmuch-pick: an emacs threaded message view with split-pane Mark Walters
@ 2012-02-12 18:49 ` Mark Walters
  2012-02-12 21:08   ` Daniel Schoepe
  2012-02-12 22:08   ` Mark Walters
  2012-02-12 18:49 ` [RFC PATCH v2 2/3] emacs: changes to other files to support notmuch-pick Mark Walters
                   ` (15 subsequent siblings)
  16 siblings, 2 replies; 26+ messages in thread
From: Mark Walters @ 2012-02-12 18:49 UTC (permalink / raw)
  To: notmuch

---
 notmuch-client.h |    9 +++++-
 notmuch-show.c   |   90 ++++++++++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 88 insertions(+), 11 deletions(-)

diff --git a/notmuch-client.h b/notmuch-client.h
index 60828aa..b4dc7bf 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -97,10 +97,17 @@ typedef struct notmuch_show_format {
     const char *message_set_end;
 } notmuch_show_format_t;
 
+enum {
+    NOTMUCH_SHOW_THREAD_MATCH,
+    NOTMUCH_SHOW_THREAD_ENTIRE,
+    NOTMUCH_SHOW_THREAD_NONE
+};
+
 typedef struct notmuch_show_params {
-    notmuch_bool_t entire_thread;
+    int entire_thread;
     notmuch_bool_t raw;
     int part;
+    int headers_only;
 #ifdef GMIME_ATLEAST_26
     GMimeCryptoContext* cryptoctx;
 #else
diff --git a/notmuch-show.c b/notmuch-show.c
index d930f94..ec2b078 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -841,7 +841,7 @@ show_message (void *ctx,
 	fputs (format->body_start, stdout);
     }
 
-    if (format->part_content)
+    if (format->part_content && !params->headers_only)
 	show_message_body (message, format, params);
 
     if (params->part <= 0) {
@@ -888,11 +888,16 @@ show_messages (void *ctx,
 	    fputs (format->message_set_sep, stdout);
 	}
 
-	show_messages (ctx,
-		       format,
-		       notmuch_message_get_replies (message),
-		       next_indent,
-		       params);
+	if (params->entire_thread != NOTMUCH_SHOW_THREAD_NONE)
+	    show_messages (ctx,
+			   format,
+			   notmuch_message_get_replies (message),
+			   next_indent,
+			   params);
+	else {
+	    fputs (format->message_set_start, stdout);
+	    fputs (format->message_set_end, stdout);
+	}
 
 	notmuch_message_destroy (message);
 
@@ -902,6 +907,50 @@ show_messages (void *ctx,
     fputs (format->message_set_end, stdout);
 }
 
+static int
+do_show_messages (void *ctx,
+		  notmuch_query_t *query,
+		  const notmuch_show_format_t *format,
+		  notmuch_show_params_t *params)
+{
+    notmuch_messages_t *messages;
+    notmuch_message_t *message;
+    int first_set = 1;
+
+    fputs (format->message_set_start, stdout);
+    messages = notmuch_query_search_messages (query);
+
+    for (;
+	 notmuch_messages_valid (messages);
+	 notmuch_messages_move_to_next (messages))
+    {
+	if (!first_set)
+	    fputs (format->message_set_sep, stdout);
+	first_set = 0;
+
+	fputs (format->message_set_start, stdout);
+	fputs (format->message_set_start, stdout);
+
+	message = notmuch_messages_get (messages);
+	notmuch_message_set_flag (message, NOTMUCH_MESSAGE_FLAG_MATCH, 1);
+	show_message (ctx, format, message, 0, params);
+
+	fputs (format->message_set_sep, stdout);
+
+	fputs (format->message_set_start, stdout);
+	fputs (format->message_set_end, stdout);
+
+
+	notmuch_message_destroy (message);
+
+	fputs (format->message_set_end, stdout);
+	fputs (format->message_set_end, stdout);
+    }
+
+    fputs (format->message_set_end, stdout);
+    return 0;
+}
+
 /* Formatted output of single message */
 static int
 do_show_single (void *ctx,
@@ -1029,11 +1078,13 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[]))
     notmuch_database_t *notmuch;
     notmuch_query_t *query;
     char *query_string;
-    int opt_index, ret;
+    int opt_index, ret, entire_thread;
+    notmuch_sort_t sort = NOTMUCH_SORT_NEWEST_FIRST;
     const notmuch_show_format_t *format = &format_text;
     notmuch_show_params_t params = { .part = -1 };
     int format_sel = NOTMUCH_FORMAT_NOT_SPECIFIED;
     notmuch_bool_t verify = FALSE;
+    notmuch_bool_t headers_only = FALSE;
 
     notmuch_opt_desc_t options[] = {
 	{ NOTMUCH_OPT_KEYWORD, &format_sel, "format", 'f',
@@ -1042,10 +1093,19 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[]))
 				  { "mbox", NOTMUCH_FORMAT_MBOX },
 				  { "raw", NOTMUCH_FORMAT_RAW },
 				  { 0, 0 } } },
+	{ NOTMUCH_OPT_KEYWORD, &sort, "sort", 's',
+	  (notmuch_keyword_t []){ { "oldest-first", NOTMUCH_SORT_OLDEST_FIRST },
+				  { "newest-first", NOTMUCH_SORT_NEWEST_FIRST },
+				  { 0, 0 } } },
 	{ NOTMUCH_OPT_INT, &params.part, "part", 'p', 0 },
-	{ NOTMUCH_OPT_BOOLEAN, &params.entire_thread, "entire-thread", 't', 0 },
+	{ NOTMUCH_OPT_KEYWORD, &entire_thread, "thread", 't',
+	  (notmuch_keyword_t []){ { "match", NOTMUCH_SHOW_THREAD_MATCH, },
+				  { "entire", NOTMUCH_SHOW_THREAD_ENTIRE },
+				  { "none", NOTMUCH_SHOW_THREAD_NONE },
+				  { 0, 0 } } },
 	{ NOTMUCH_OPT_BOOLEAN, &params.decrypt, "decrypt", 'd', 0 },
 	{ NOTMUCH_OPT_BOOLEAN, &verify, "verify", 'v', 0 },
+	{ NOTMUCH_OPT_BOOLEAN, &headers_only, "headers-only", 'h', 0 },
 	{ 0, 0, 0, 0, 0 }
     };
 
@@ -1055,6 +1115,9 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[]))
 	return 1;
     }
 
+    params.entire_thread = entire_thread;
+    params.headers_only = headers_only;
+
     if (format_sel == NOTMUCH_FORMAT_NOT_SPECIFIED) {
 	/* if part was requested and format was not specified, use format=raw */
 	if (params.part >= 0)
@@ -1066,7 +1129,9 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[]))
     switch (format_sel) {
     case NOTMUCH_FORMAT_JSON:
 	format = &format_json;
-	params.entire_thread = TRUE;
+	if (!params.entire_thread) params.entire_thread = NOTMUCH_SHOW_THREAD_ENTIRE;
+	//      params.entire_thread = 1;
+
 	break;
     case NOTMUCH_FORMAT_TEXT:
 	format = &format_text;
@@ -1133,10 +1198,15 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[]))
 	return 1;
     }
 
+    notmuch_query_set_sort (query, sort);
+
     if (params.part >= 0)
 	ret = do_show_single (ctx, query, format, &params);
     else
-	ret = do_show (ctx, query, format, &params);
+	if (params.entire_thread == NOTMUCH_SHOW_THREAD_NONE)
+	    ret = do_show_messages (ctx, query, format, &params);
+	else
+	    ret = do_show (ctx, query, format, &params);
 
     notmuch_query_destroy (query);
     notmuch_database_close (notmuch);
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC PATCH v2 2/3] emacs: changes to other files to support notmuch-pick
  2012-02-12 18:49 [RFC PATCH v2 0/3] notmuch-pick: an emacs threaded message view with split-pane Mark Walters
  2012-02-12 18:49 ` [RFC PATCH v2 1/3] cli: notmuch-show changes to support pick Mark Walters
@ 2012-02-12 18:49 ` Mark Walters
  2012-02-12 22:27   ` Mark Walters
  2012-02-12 18:49 ` [RFC PATCH v2 3/3] emacs: add notmuch-pick itself Mark Walters
                   ` (14 subsequent siblings)
  16 siblings, 1 reply; 26+ messages in thread
From: Mark Walters @ 2012-02-12 18:49 UTC (permalink / raw)
  To: notmuch

---
 emacs/Makefile.local   |    3 ++-
 emacs/notmuch-hello.el |   10 ++++++++++
 emacs/notmuch-lib.el   |    4 ++++
 emacs/notmuch-query.el |    4 +++-
 emacs/notmuch-show.el  |   25 ++++++++++++++++++++++---
 emacs/notmuch.el       |    8 ++++++++
 6 files changed, 49 insertions(+), 5 deletions(-)

diff --git a/emacs/Makefile.local b/emacs/Makefile.local
index 4fee0e8..2922d9e 100644
--- a/emacs/Makefile.local
+++ b/emacs/Makefile.local
@@ -14,7 +14,8 @@ emacs_sources := \
 	$(dir)/notmuch-message.el \
 	$(dir)/notmuch-crypto.el \
 	$(dir)/coolj.el \
-	$(dir)/notmuch-print.el
+	$(dir)/notmuch-print.el \
+	$(dir)/notmuch-pick.el
 
 emacs_images := \
 	$(srcdir)/$(dir)/notmuch-logo.png
diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
index d17a30f..6d28a7e 100644
--- a/emacs/notmuch-hello.el
+++ b/emacs/notmuch-hello.el
@@ -27,6 +27,7 @@
 (require 'notmuch-mua)
 
 (declare-function notmuch-search "notmuch" (query &optional oldest-first target-thread target-line continuation))
+(declare-function notmuch-pick "notmuch-pick" (query &optional query-context buffer-name))
 (declare-function notmuch-poll "notmuch" ())
 
 (defcustom notmuch-hello-recent-searches-max 10
@@ -181,6 +182,14 @@ International Bureau of Weights and Measures."
   (notmuch-search search notmuch-search-oldest-first nil nil
 		  #'notmuch-hello-search-continuation))
 
+(defun notmuch-hello-pick (&optional search)
+  (interactive)
+  (unless (null search)
+    (setq search (notmuch-hello-trim search))
+    (let ((history-delete-duplicates t))
+      (add-to-history 'notmuch-search-history search)))
+  (notmuch-pick search))
+
 (defun notmuch-hello-add-saved-search (widget)
   (interactive)
   (let ((search (widget-value
@@ -345,6 +354,7 @@ should be. Returns a cons cell `(tags-per-line width)'."
     (define-key map (kbd "<C-tab>") 'widget-backward)
     (define-key map "m" 'notmuch-mua-new-mail)
     (define-key map "s" 'notmuch-hello-search)
+    (define-key map "z" 'notmuch-hello-pick)
     map)
   "Keymap for \"notmuch hello\" buffers.")
 (fset 'notmuch-hello-mode-map notmuch-hello-mode-map)
diff --git a/emacs/notmuch-lib.el b/emacs/notmuch-lib.el
index d315f76..b88bb80 100644
--- a/emacs/notmuch-lib.el
+++ b/emacs/notmuch-lib.el
@@ -40,6 +40,10 @@
   "Showing messages and threads."
   :group 'notmuch)
 
+(defgroup notmuch-pick nil
+  "Showing message and thread structure."
+  :group 'notmuch)
+
 (defgroup notmuch-send nil
   "Sending messages from Notmuch."
   :group 'notmuch)
diff --git a/emacs/notmuch-query.el b/emacs/notmuch-query.el
index d66baea..b3c91a3 100644
--- a/emacs/notmuch-query.el
+++ b/emacs/notmuch-query.el
@@ -22,7 +22,7 @@
 (require 'notmuch-lib)
 (require 'json)
 
-(defun notmuch-query-get-threads (search-terms)
+(defun notmuch-query-get-threads (search-terms &rest extra-format)
   "Return a list of threads of messages matching SEARCH-TERMS.
 
 A thread is a forest or list of trees. A tree is a two element
@@ -33,6 +33,8 @@ is a possibly empty forest of replies.
 	 (json-object-type 'plist)
 	 (json-array-type 'list)
 	 (json-false 'nil))
+    (if extra-format
+	(setq args (append args extra-format)))
     (if notmuch-show-process-crypto
 	(setq args (append args '("--decrypt"))))
     (setq args (append args search-terms))
diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 43408d9..1adf964 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -42,6 +42,7 @@
 (declare-function notmuch-search-next-thread "notmuch" nil)
 (declare-function notmuch-search-show-thread "notmuch" nil)
 (declare-function notmuch-update-tags "notmuch" (current-tags tag-changes))
+(declare-function notmuch-pick "notmuch-pick" (query &optional query-context buffer-name))
 
 (defcustom notmuch-message-headers '("Subject" "To" "Cc" "Date")
   "Headers that should be shown in a message, in this order.
@@ -151,6 +152,12 @@ indentation."
 (make-variable-buffer-local 'notmuch-show-elide-non-matching-messages)
 (put 'notmuch-show-elide-non-matching-messages 'permanent-local t)
 
+;; This is very similar to the previous variable: they should be
+;; unified. MJW
+(defvar notmuch-show-just-matches nil)
+(make-variable-buffer-local 'notmuch-show-just-matches)
+(put 'notmuch-show-just-matches 'permanent-local t)
+
 (defvar notmuch-show-indent-content t)
 (make-variable-buffer-local 'notmuch-show-indent-content)
 (put 'notmuch-show-indent-content 'permanent-local t)
@@ -1013,7 +1020,7 @@ a corresponding notmuch search."
 			'face goto-address-mail-face))))
 
 ;;;###autoload
-(defun notmuch-show (thread-id &optional parent-buffer query-context buffer-name)
+(defun notmuch-show (thread-id &optional parent-buffer query-context buffer-name just-matches)
   "Run \"notmuch show\" with the given thread ID and display results.
 
 The optional PARENT-BUFFER is the notmuch-search buffer from
@@ -1046,8 +1053,11 @@ function is used."
 
     (setq notmuch-show-thread-id thread-id
 	  notmuch-show-parent-buffer parent-buffer
-	  notmuch-show-query-context query-context)
-    (notmuch-show-worker)))
+	  notmuch-show-query-context query-context
+	  notmuch-show-just-matches just-matches)
+
+    (notmuch-show-worker)
+    (current-buffer)))
 
 (defun notmuch-show-worker ()
   (let ((inhibit-read-only t))
@@ -1064,6 +1074,8 @@ function is used."
 		       (append (list "\'") basic-args
 			       (list "and (" notmuch-show-query-context ")\'"))
 		     (append (list "\'") basic-args (list "\'")))))
+	(if notmuch-show-just-matches
+	    (setq args (append (list "--thread=none") args)))
 	(notmuch-show-insert-forest (notmuch-query-get-threads args))
 	;; If the query context reduced the results to nothing, run
 	;; the basic query.
@@ -1158,6 +1170,8 @@ buffer is stored and re-applied after the refresh."
 	(define-key map (kbd "<backtab>") 'notmuch-show-previous-button)
 	(define-key map (kbd "TAB") 'notmuch-show-next-button)
 	(define-key map "s" 'notmuch-search)
+	(define-key map "z" 'notmuch-pick)
+	(define-key map "Z" 'notmuch-show-pick-current-query)
 	(define-key map "m" 'notmuch-mua-new-mail)
 	(define-key map "f" 'notmuch-show-forward-message)
 	(define-key map "r" 'notmuch-show-reply-sender)
@@ -1565,6 +1579,11 @@ to show, nil otherwise."
   (notmuch-show-mark-read)
   (notmuch-show-message-adjust))
 
+(defun notmuch-show-pick-current-query ()
+  "Call notmuch pick with the current query"
+  (interactive)
+  (notmuch-pick notmuch-show-thread-id notmuch-show-query-context))
+
 (defun notmuch-show-view-raw-message ()
   "View the file holding the current message."
   (interactive)
diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index 5b4f1c5..43e77d0 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -54,6 +54,7 @@
 
 (require 'notmuch-lib)
 (require 'notmuch-show)
+(require 'notmuch-pick)
 (require 'notmuch-mua)
 (require 'notmuch-hello)
 (require 'notmuch-maildir-fcc)
@@ -272,6 +273,8 @@ For a mouse binding, return nil."
     (define-key map "R" 'notmuch-search-reply-to-thread)
     (define-key map "m" 'notmuch-mua-new-mail)
     (define-key map "s" 'notmuch-search)
+    (define-key map "z" 'notmuch-pick)
+    (define-key map "Z" 'notmuch-search-pick-current-query)
     (define-key map "o" 'notmuch-search-toggle-order)
     (define-key map "c" 'notmuch-search-stash-map)
     (define-key map "=" 'notmuch-search-refresh-view)
@@ -1021,6 +1024,11 @@ same relative position within the new buffer."
     (notmuch-search query oldest-first target-thread target-line continuation)
     (goto-char (point-min))))
 
+(defun notmuch-search-pick-current-query ()
+  "Call notmuch pick with the current query"
+  (interactive)
+  (notmuch-pick notmuch-search-query-string))
+
 (defcustom notmuch-poll-script nil
   "An external script to incorporate new mail into the notmuch database.
 
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC PATCH v2 3/3] emacs: add notmuch-pick itself
  2012-02-12 18:49 [RFC PATCH v2 0/3] notmuch-pick: an emacs threaded message view with split-pane Mark Walters
  2012-02-12 18:49 ` [RFC PATCH v2 1/3] cli: notmuch-show changes to support pick Mark Walters
  2012-02-12 18:49 ` [RFC PATCH v2 2/3] emacs: changes to other files to support notmuch-pick Mark Walters
@ 2012-02-12 18:49 ` Mark Walters
  2012-02-12 20:39 ` [RFC PATCH v2 0/3] notmuch-pick: an emacs threaded message view with split-pane Jameson Graef Rollins
                   ` (13 subsequent siblings)
  16 siblings, 0 replies; 26+ messages in thread
From: Mark Walters @ 2012-02-12 18:49 UTC (permalink / raw)
  To: notmuch

---
 emacs/notmuch-pick.el |  585 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 585 insertions(+), 0 deletions(-)
 create mode 100644 emacs/notmuch-pick.el

diff --git a/emacs/notmuch-pick.el b/emacs/notmuch-pick.el
new file mode 100644
index 0000000..46eb720
--- /dev/null
+++ b/emacs/notmuch-pick.el
@@ -0,0 +1,585 @@
+;; notmuch-pick.el --- displaying notmuch forests.
+;;
+;; Copyright © Carl Worth
+;; Copyright © David Edmondson
+;;
+;; This file is part of Notmuch.
+;;
+;; Notmuch is free software: you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Notmuch is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Notmuch.  If not, see <http://www.gnu.org/licenses/>.
+;;
+;; Authors: David Edmondson <dme@dme.org>
+
+(require 'mail-parse)
+
+(require 'notmuch-lib)
+(require 'notmuch-query)
+(require 'notmuch-show)
+(eval-when-compile (require 'cl))
+
+(declare-function notmuch-call-notmuch-process "notmuch" (&rest args))
+(declare-function notmuch-show "notmuch-show" (&rest args))
+(declare-function notmuch-tag "notmuch" (query &rest tags))
+(declare-function notmuch-show-strip-re "notmuch-show" (subject))
+(declare-function notmuch-show-clean-address "notmuch-show" (parsed-address))
+(declare-function notmuch-show-spaces-n "notmuch-show" (n))
+(declare-function notmuch-read-query "notmuch" (prompt))
+(declare-function notmuch-read-tag-changes "notmuch" (&optional initial-input &rest search-terms))
+(declare-function notmuch-update-tags "notmuch" (current-tags tag-changes))
+
+(defcustom notmuch-pick-author-width 20
+  "Width of the author field."
+  :type 'integer
+  :group 'notmuch-pick)
+
+(defface notmuch-pick-match-face
+  '((((class color)
+      (background dark))
+     (:foreground "white"))
+    (((class color)
+      (background light))
+     (:foreground "black"))
+    (t (:bold t)))
+  "Face used in pick mode for matching messages."
+  :group 'notmuch-pick)
+
+(defface notmuch-pick-no-match-face
+  '((t (:foreground "gray")))
+  "Face used in pick mode for messages not matching the query."
+  :group 'notmuch-pick)
+
+(defvar notmuch-pick-previous-subject "")
+(make-variable-buffer-local 'notmuch-pick-previous-subject)
+
+(defvar notmuch-pick-thread-id nil)
+(make-variable-buffer-local 'notmuch-pick-thread-id)
+(defvar notmuch-pick-query-context nil)
+(make-variable-buffer-local 'notmuch-pick-query-context)
+(defvar notmuch-pick-buffer-name nil)
+(make-variable-buffer-local 'notmuch-pick-buffer-name)
+(defvar notmuch-pick-view-just-messages nil)
+(make-variable-buffer-local 'notmuch-pick-view-just-messages)
+(put 'notmuch-pick-view-just-messages 'permanent-local t)
+(defvar notmuch-pick-message-window nil)
+(make-variable-buffer-local 'notmuch-pick-message-window)
+(put 'notmuch-pick-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)
+(defvar notmuch-pick-oldest-first nil)
+(make-variable-buffer-local 'notmuch-pick-oldest-first)
+(put 'notmuch-pick-oldest-first 'permanent-local t)
+
+(defvar notmuch-pick-mode-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map (kbd "RET") 'notmuch-pick-show-message)
+    (define-key map [mouse-1] 'notmuch-pick-show-message)
+    (define-key map "q" 'notmuch-pick-quit)
+    (define-key map "x" 'notmuch-pick-quit)
+    (define-key map "?" 'notmuch-help)
+    (define-key map "a" 'notmuch-pick-archive-message)
+    (define-key map "=" 'notmuch-pick-refresh-view)
+    (define-key map "t" 'notmuch-pick-toggle-view)
+    (define-key map "o" 'notmuch-pick-toggle-order)
+    (define-key map "s" 'notmuch-search)
+    (define-key map "z" 'notmuch-pick)
+    (define-key map "m" 'notmuch-pick-new-mail)
+    (define-key map "f" 'notmuch-pick-forward-message)
+    (define-key map "r" 'notmuch-pick-reply-sender)
+    (define-key map "R" 'notmuch-pick-reply)
+    (define-key map "n" 'notmuch-pick-next-message)
+    (define-key map "p" 'notmuch-pick-prev-message)
+    (define-key map "|" 'notmuch-pick-pipe-message)
+    (define-key map "-" 'notmuch-pick-remove-tag)
+    (define-key map "+" 'notmuch-pick-add-tag)
+;;    (define-key map " " 'notmuch-pick-scroll-message-window)
+    (define-key map " " 'notmuch-pick-scroll-or-next)
+    (define-key map "b" 'notmuch-pick-scroll-message-window-back)
+    map))
+(fset 'notmuch-pick-mode-map notmuch-pick-mode-map)
+
+(defun notmuch-pick-get-message-properties ()
+  "Return the properties of the current message as a plist.
+
+Some useful entries are:
+:headers - Property list containing the headers :Date, :Subject, :From, etc.
+:tags - Tags for this message"
+  (save-excursion
+    (beginning-of-line)
+    (get-text-property (point) :notmuch-message-properties)))
+
+(defun notmuch-pick-set-message-properties (props)
+  (save-excursion
+    (beginning-of-line)
+    (put-text-property (point) (+ (point) 1) :notmuch-message-properties props)))
+
+(defun notmuch-pick-set-prop (prop val &optional props)
+  (let ((inhibit-read-only t)
+	(props (or props
+		   (notmuch-pick-get-message-properties))))
+    (plist-put props prop val)
+    (notmuch-pick-set-message-properties props)))
+
+(defun notmuch-pick-get-prop (prop &optional props)
+  (let ((props (or props
+		   (notmuch-pick-get-message-properties))))
+    (plist-get props prop)))
+
+(defun notmuch-pick-set-tags (tags)
+  "Set the tags of the current message."
+  (notmuch-pick-set-prop :tags tags))
+
+(defun notmuch-pick-get-tags ()
+  "Return the tags of the current message."
+  (notmuch-pick-get-prop :tags))
+
+(defun notmuch-pick-tag-message (&rest tag-changes)
+  "Change tags for the current message.
+
+TAG-CHANGES is a list of tag operations for `notmuch-tag'."
+  (let* ((current-tags (notmuch-pick-get-tags))
+	 (new-tags (notmuch-update-tags current-tags tag-changes)))
+    (unless (equal current-tags new-tags)
+      (apply 'notmuch-tag (notmuch-pick-get-message-id) tag-changes)
+      (notmuch-pick-set-tags new-tags))))
+
+(defun notmuch-pick-tag (&optional initial-input)
+  "Change tags for the current message, read input from the minibuffer."
+  (interactive)
+  (let ((tag-changes (notmuch-read-tag-changes
+		      initial-input (notmuch-pick-get-message-id))))
+    (apply 'notmuch-pick-tag-message tag-changes)))
+
+(defun notmuch-pick-add-tag ()
+  "Same as `notmuch-pick-tag' but sets initial input to '+'."
+  (interactive)
+  (notmuch-pick-tag "+"))
+
+(defun notmuch-pick-remove-tag ()
+  "Same as `notmuch-pick-tag' but sets initial input to '-'."
+  (interactive)
+  (notmuch-pick-tag "-"))
+
+(defun notmuch-pick-get-message-id ()
+  "Return the message id of the current message."
+  (concat "id:\"" (notmuch-pick-get-prop :id) "\""))
+
+(defun notmuch-pick-get-match ()
+  "Return whether the current message is a match."
+  (interactive)
+  (notmuch-pick-get-prop :match))
+
+(defun notmuch-pick-show-message ()
+  "Show the current message."
+  (interactive)
+  (let ((id (notmuch-pick-get-message-id))
+	(inhibit-read-only t)
+	buffer)
+    (when id
+      ;; we close and reopen the window to kill off un-needed buffers
+      ;; this might cause flickering but seems ok
+      (notmuch-pick-close-message-window)
+      (setq notmuch-pick-message-window
+	    (split-window-vertically (/ (window-height) 4)))
+      (with-selected-window notmuch-pick-message-window
+	(setq buffer (notmuch-show id nil nil nil t))))
+    (setq notmuch-pick-message-buffer buffer)))
+
+(defun notmuch-pick-scroll-message-window ()
+  "Scroll the message window (if it exists)"
+  (interactive)
+  (when (window-live-p notmuch-pick-message-window)
+    (with-selected-window notmuch-pick-message-window
+      (if (pos-visible-in-window-p (point-max))
+	  t
+	(scroll-up)))))
+
+(defun notmuch-pick-scroll-message-window-back ()
+  "Scroll the message window back(if it exists)"
+  (interactive)
+  (when (window-live-p notmuch-pick-message-window)
+    (with-selected-window notmuch-pick-message-window
+      (if (pos-visible-in-window-p (point-min))
+	  t
+	(scroll-down)))))
+
+(defun notmuch-pick-scroll-or-next ()
+  "Scroll the message window. If it at end go to next message."
+  (interactive)
+  (when (notmuch-pick-scroll-message-window)
+    (notmuch-pick-next-message)))
+
+(defun notmuch-pick-toggle-order ()
+  "Toggle the current search order.
+
+By default, the \"inbox\" view created by `notmuch' is displayed
+in chronological order (oldest thread at the beginning of the
+buffer), while any global searches created by `notmuch-search'
+are displayed in reverse-chronological order (newest thread at
+the beginning of the buffer).
+
+This command toggles the sort order for the current search."
+  (interactive)
+  (let ((inhibit-read-only t))
+    (if notmuch-pick-oldest-first
+	(message "Showing newest messages first")
+      (message "Showing oldest messages first"))
+    (set 'notmuch-pick-oldest-first (not notmuch-pick-oldest-first))
+    (notmuch-pick-refresh-view)))
+
+(defun notmuch-pick-quit ()
+  "Close the split view or exit pick."
+  (interactive)
+  (unless (notmuch-pick-close-message-window)
+    (kill-buffer (current-buffer))))
+
+(defun notmuch-pick-close-message-window ()
+  "Close the message-window. Return t if close succeeds."
+  (interactive)
+  (when (and (window-live-p notmuch-pick-message-window)
+	     (not (window-full-height-p notmuch-pick-message-window)))
+    (delete-window notmuch-pick-message-window)
+    (unless (get-buffer-window-list notmuch-pick-message-buffer)
+      (kill-buffer notmuch-pick-message-buffer))
+    t))
+
+(defun notmuch-pick-archive-message ()
+  "Archive the current message and move to next message."
+  (interactive)
+  (let ((id (notmuch-pick-get-message-id)))
+    (when id
+      (notmuch-tag id "-inbox" )
+      (forward-line))))
+
+(defun notmuch-pick-prev-message ()
+  "Move to previous matching message."
+  (interactive)
+  (forward-line -1)
+  (while (and (not (bobp)) (not (notmuch-pick-get-match)))
+    (forward-line -1))
+  (when (window-live-p notmuch-pick-message-window)
+    (notmuch-pick-show-message)))
+
+(defun notmuch-pick-next-message ()
+  "Move to next matching message."
+  (interactive)
+  (forward-line)
+  (while (and (not (eobp)) (not (notmuch-pick-get-match)))
+    (forward-line))
+  (when (window-live-p notmuch-pick-message-window)
+    (notmuch-pick-show-message)))
+
+(defun notmuch-pick-refresh-view ()
+  "Refresh view."
+  (interactive)
+  (let ((inhibit-read-only t)
+	(thread-id notmuch-pick-thread-id)
+	(query-context notmuch-pick-query-context)
+	(buffer-name notmuch-pick-buffer-name))
+    (erase-buffer)
+    (notmuch-pick-worker thread-id  query-context buffer-name)))
+
+(defun notmuch-pick-toggle-view ()
+  "Toggle showing threads or as isolated messages."
+  (interactive)
+  (let ((inhibit-read-only t))
+    (if notmuch-pick-view-just-messages
+	(message "Showing as threads")
+      (message "Showing as single messages"))
+    (setq notmuch-pick-view-just-messages (not notmuch-pick-view-just-messages))
+    (notmuch-pick-refresh-view)))
+
+(defun notmuch-pick-string-width (string width &optional right)
+  (let ((s (format (format "%%%s%ds" (if right "" "-") width)
+		   string)))
+    (if (> (length s) width)
+	(substring s 0 width)
+      s)))
+
+(defmacro with-current-notmuch-pick-message (&rest body)
+  "Evaluate body with current buffer set to the text of current message"
+  `(save-excursion
+     (let ((id (notmuch-pick-get-message-id)))
+       (let ((buf (generate-new-buffer (concat "*notmuch-msg-" id "*"))))
+         (with-current-buffer buf
+	    (call-process notmuch-command nil t nil "show" "--format=raw" id)
+           ,@body)
+	 (kill-buffer buf)))))
+
+(defun notmuch-pick-new-mail (&optional prompt-for-sender)
+  "Compose new mail."
+  (interactive "P")
+  (notmuch-pick-close-message-window)
+  (notmuch-mua-new-mail prompt-for-sender ))
+
+(defun notmuch-pick-forward-message (&optional prompt-for-sender)
+  "Forward the current message."
+  (interactive "P")
+  (notmuch-pick-close-message-window)
+  (with-current-notmuch-pick-message
+   (notmuch-mua-new-forward-message prompt-for-sender)))
+
+(defun notmuch-pick-reply (&optional prompt-for-sender)
+  "Reply to the sender and all recipients of the current message."
+  (interactive "P")
+  (notmuch-pick-close-message-window)
+  (notmuch-mua-new-reply (notmuch-pick-get-message-id) prompt-for-sender t))
+
+(defun notmuch-pick-reply-sender (&optional prompt-for-sender)
+  "Reply to the sender of the current message."
+  (interactive "P")
+  (notmuch-pick-close-message-window)
+  (notmuch-mua-new-reply (notmuch-pick-get-message-id) prompt-for-sender nil))
+
+;; Shamelessly stolen from notmuch-show.el: maybe should be unified MJW
+(defun notmuch-pick-pipe-message (command)
+  "Pipe the contents of the current message to the given command.
+
+The given command will be executed with the raw contents of the
+current email message as stdin. Anything printed by the command
+to stdout or stderr will appear in the *notmuch-pipe* buffer.
+
+When invoked with a prefix argument, the command will receive all
+open messages in the current thread (formatted as an mbox) rather
+than only the current message."
+  (interactive "sPipe message to command: ")
+  (let ((shell-command
+	 (concat notmuch-command " show --format=raw "
+		 (shell-quote-argument (notmuch-pick-get-message-id)) " | " command))
+	 (buf (get-buffer-create (concat "*notmuch-pipe*"))))
+    (with-current-buffer buf
+      (setq buffer-read-only nil)
+      (erase-buffer)
+      (let ((exit-code (call-process-shell-command shell-command nil buf)))
+	(goto-char (point-max))
+	(set-buffer-modified-p nil)
+	(setq buffer-read-only t)
+	(unless (zerop exit-code)
+	  (switch-to-buffer-other-window buf)
+	  (message (format "Command '%s' exited abnormally with code %d"
+			   shell-command exit-code)))))))
+
+;; Shamelessly stolen from notmuch-show.el: should be unified MJW
+(defun notmuch-pick-clean-address (address)
+  "Try to clean a single email ADDRESS for display.  Return
+unchanged ADDRESS if parsing fails."
+  (condition-case nil
+    (let (p-name p-address)
+      ;; It would be convenient to use `mail-header-parse-address',
+      ;; but that expects un-decoded mailbox parts, whereas our
+      ;; mailbox parts are already decoded (and hence may contain
+      ;; UTF-8). Given that notmuch should handle most of the awkward
+      ;; cases, some simple string deconstruction should be sufficient
+      ;; here.
+      (cond
+       ;; "User <user@dom.ain>" style.
+       ((string-match "\\(.*\\) <\\(.*\\)>" address)
+	(setq p-name (match-string 1 address)
+	      p-address (match-string 2 address)))
+
+       ;; "<user@dom.ain>" style.
+       ((string-match "<\\(.*\\)>" address)
+	(setq p-address (match-string 1 address)))
+
+       ;; Everything else.
+       (t
+	(setq p-address address)))
+
+      (when p-name
+	;; Remove elements of the mailbox part that are not relevant for
+	;; display, even if they are required during transport:
+	;;
+	;; Backslashes.
+	(setq p-name (replace-regexp-in-string "\\\\" "" p-name))
+
+	;; Outer single and double quotes, which might be nested.
+	(loop
+	 with start-of-loop
+	 do (setq start-of-loop p-name)
+
+	 when (string-match "^\"\\(.*\\)\"$" p-name)
+	 do (setq p-name (match-string 1 p-name))
+
+	 when (string-match "^'\\(.*\\)'$" p-name)
+	 do (setq p-name (match-string 1 p-name))
+
+	 until (string= start-of-loop p-name)))
+
+      ;; If the address is 'foo@bar.com <foo@bar.com>' then show just
+      ;; 'foo@bar.com'.
+      (when (string= p-name p-address)
+	(setq p-name nil))
+
+      ;; If we have a name return that otherwise return the address.
+      (if (not p-name)
+	  p-address
+	p-name))
+    (error address)))
+
+(defun notmuch-pick-insert-msg (msg depth tree-status)
+  (let* ((headers (plist-get msg :headers))
+	 (match (plist-get msg :match))
+	 (tags (plist-get msg :tags))
+	 (bare-subject (notmuch-show-strip-re (plist-get headers :Subject)))
+	 (message-face (if match
+			   'notmuch-pick-match-face
+			 'notmuch-pick-no-match-face)))
+
+    (insert (propertize (concat
+			 (notmuch-pick-string-width
+			  (plist-get msg :date_relative) 12 t)
+			 "  "
+			 (format "%-75s"
+				 (concat
+				  (notmuch-pick-string-width
+				   (notmuch-pick-clean-address (plist-get headers :From))
+				   (if notmuch-pick-view-just-messages
+				       (+ notmuch-pick-author-width 3)
+				     notmuch-pick-author-width))
+				  " "
+				  (unless notmuch-pick-view-just-messages
+				    (mapconcat #'identity (reverse tree-status) ""))
+				  (if (string= notmuch-pick-previous-subject bare-subject)
+				      " ..."
+				    bare-subject)))
+			 (if tags
+			     (concat " ("
+				     (mapconcat #'identity tags ", ") ")"))
+			 "") 'face message-face))
+    (notmuch-pick-set-message-properties msg)
+    (insert "\n")
+
+    (setq notmuch-pick-previous-subject bare-subject)))
+
+(defun notmuch-pick-insert-tree (tree depth tree-status first last)
+  "Insert the message tree TREE at depth DEPTH in the current thread."
+  (let ((msg (car tree))
+	(replies (cadr tree)))
+
+      (cond
+       ((and (< 0 depth) (not last))
+	(push "├" tree-status))
+       ((and (< 0 depth) last)
+	(push "╰" tree-status))
+       ((and (eq 0 depth) first last)
+;;	  (push "─" tree-status)) choice between this and next line is matter of taste MJW
+	(push " " tree-status))
+       ((and (eq 0 depth) first (not last))
+	  (push "┬" tree-status))
+       ((and (eq 0 depth) (not first) last)
+	(push "╰" tree-status))
+       ((and (eq 0 depth) (not first) (not last))
+	(push "├" tree-status)))
+
+      (push (concat (if replies "┬" "─") "►") tree-status)
+      (notmuch-pick-insert-msg msg depth tree-status)
+      (pop tree-status)
+      (pop tree-status)
+
+      (if last
+	  (push " " tree-status)
+	(push "│" tree-status))
+
+    (notmuch-pick-insert-thread replies (1+ depth) tree-status)))
+
+(defun notmuch-pick-insert-thread (thread depth tree-status)
+  "Insert the thread THREAD at depth DEPTH >= 1 in the current forest."
+  (let ((n (length thread)))
+    (loop for tree in thread
+	  for count from 1 to n
+
+	  do (notmuch-pick-insert-tree tree depth tree-status (eq count 1) (eq count n)))))
+
+(defun notmuch-pick-insert-forest (forest)
+  (mapc '(lambda (thread)
+	   (let (tree-status)
+	     ;; Reset at the start of each main thread.
+	     (setq notmuch-pick-previous-subject nil)
+	     (notmuch-pick-insert-thread thread 0 tree-status)))
+	forest))
+
+(defun notmuch-pick-mode ()
+  "Major mode displaying messages (as opposed to threads) of of a notmuch search.
+
+This buffer contains the results of a \"notmuch pick\" of your
+email archives. Each line in the buffer represents a single
+message giving the relative date, the author, subject, and any
+tags.
+
+Pressing \\[notmuch-pick-show-message] on any line displays that message.
+
+Complete list of currently available key bindings:
+
+\\{notmuch-pick-mode-map}"
+
+  (interactive)
+  (kill-all-local-variables)
+  (use-local-map notmuch-pick-mode-map)
+  (setq major-mode 'notmuch-pick-mode
+	mode-name "notmuch-pick")
+  (hl-line-mode 1)
+  (setq buffer-read-only t
+	truncate-lines t))
+
+(defun notmuch-pick-worker (thread-id &optional query-context buffer-name)
+  (interactive)
+  (notmuch-pick-mode)
+  (setq notmuch-pick-thread-id thread-id)
+  (setq notmuch-pick-query-context query-context)
+  (setq notmuch-pick-buffer-name buffer-name)
+
+  (erase-buffer)
+  (goto-char (point-min))
+  (save-excursion
+    (let* ((basic-args (list thread-id))
+	   (args (if query-context
+		     (append (list "\'") basic-args (list "and (" query-context ")\'"))
+		   (append (list "\'") basic-args (list "\'"))))
+	   (message-arg (if notmuch-pick-view-just-messages
+			    "--thread=none"
+			  "--thread=entire"))
+	   (sort-arg (if notmuch-pick-oldest-first
+			  "--sort=oldest-first"
+			"--sort=newest-first")))
+
+      (notmuch-pick-insert-forest (notmuch-query-get-threads args "--headers-only" message-arg sort-arg))
+      ;; If the query context reduced the results to nothing, run
+      ;; the basic query.
+      (when (and (eq (buffer-size) 0)
+		 query-context)
+	(notmuch-pick-insert-forest
+	 (notmuch-query-get-threads basic-args message-arg sort-arg))))))
+
+(defun notmuch-pick (&optional query query-context buffer-name)
+  "Run notmuch pick with the given `query' and display the results"
+  (interactive "sNotmuch pick: ")
+  (if (null query)
+      (setq query (notmuch-read-query "Notmuch pick: ")))
+  (let ((buffer (get-buffer-create (generate-new-buffer-name
+				    (or buffer-name
+					(concat "*notmuch-" query "*")))))
+	(inhibit-read-only t))
+
+    (switch-to-buffer buffer)
+    ;; Don't track undo information for this buffer
+    (set 'buffer-undo-list t)
+
+    (notmuch-pick-worker query query-context buffer-name)
+
+    (setq truncate-lines t)))
+
+;;  (use-local-map notmuch-pick-mode-map))
+
+;;
+
+(provide 'notmuch-pick)
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [RFC PATCH v2 0/3] notmuch-pick: an emacs threaded message view with split-pane
  2012-02-12 18:49 [RFC PATCH v2 0/3] notmuch-pick: an emacs threaded message view with split-pane Mark Walters
                   ` (2 preceding siblings ...)
  2012-02-12 18:49 ` [RFC PATCH v2 3/3] emacs: add notmuch-pick itself Mark Walters
@ 2012-02-12 20:39 ` Jameson Graef Rollins
  2012-02-12 21:51   ` Mark Walters
  2012-02-13  1:20 ` [RFC PATCH v3 00/11] " Mark Walters
                   ` (12 subsequent siblings)
  16 siblings, 1 reply; 26+ messages in thread
From: Jameson Graef Rollins @ 2012-02-12 20:39 UTC (permalink / raw)
  To: Mark Walters, notmuch

[-- Attachment #1: Type: text/plain, Size: 820 bytes --]

On Sun, 12 Feb 2012 18:49:36 +0000, Mark Walters <markwalters1009@gmail.com> wrote:
> Here is a rebased version of the notmuch-pick patch set
> id:"87d39k1gvi.fsf@qmul.ac.uk". It now applies directly 
> to master since Jani's notmuch-show command line parsing 
> has been pushed.

Hey, Mark.  Thanks for working on this.  However, none of the patches
have commit messages, so there's no explanation for what any of the
patches are supposed to do.  This is particularly bothersome for the
first patch, which introduces a lot of unexplained changes to the cli.

I think I would like to review this patch set, since I think I'm
interested in the functionality it may be introducing, but without any
commit messages or explanation what the patches are meant to do it's
kind of a non starter for me.

jamie.

[-- Attachment #2: Type: application/pgp-signature, Size: 835 bytes --]

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC PATCH v2 1/3] cli: notmuch-show changes to support pick
  2012-02-12 18:49 ` [RFC PATCH v2 1/3] cli: notmuch-show changes to support pick Mark Walters
@ 2012-02-12 21:08   ` Daniel Schoepe
  2012-02-12 22:08   ` Mark Walters
  1 sibling, 0 replies; 26+ messages in thread
From: Daniel Schoepe @ 2012-02-12 21:08 UTC (permalink / raw)
  To: Mark Walters, notmuch

[-- Attachment #1: Type: text/plain, Size: 1991 bytes --]

On Sun, 12 Feb 2012 18:49:37 +0000, Mark Walters <markwalters1009@gmail.com> wrote:
> +    int opt_index, ret, entire_thread;
> +    notmuch_sort_t sort = NOTMUCH_SORT_NEWEST_FIRST;
>      const notmuch_show_format_t *format = &format_text;
>      notmuch_show_params_t params = { .part = -1 };
>      int format_sel = NOTMUCH_FORMAT_NOT_SPECIFIED;
>      notmuch_bool_t verify = FALSE;
> +    notmuch_bool_t headers_only = FALSE;
>  
>      notmuch_opt_desc_t options[] = {
>  	{ NOTMUCH_OPT_KEYWORD, &format_sel, "format", 'f',
> @@ -1042,10 +1093,19 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[]))
>  				  { "mbox", NOTMUCH_FORMAT_MBOX },
>  				  { "raw", NOTMUCH_FORMAT_RAW },
>  				  { 0, 0 } } },
> +	{ NOTMUCH_OPT_KEYWORD, &sort, "sort", 's',
> +	  (notmuch_keyword_t []){ { "oldest-first", NOTMUCH_SORT_OLDEST_FIRST },
> +				  { "newest-first", NOTMUCH_SORT_NEWEST_FIRST },
> +				  { 0, 0 } } },
>  	{ NOTMUCH_OPT_INT, &params.part, "part", 'p', 0 },
> -	{ NOTMUCH_OPT_BOOLEAN, &params.entire_thread, "entire-thread", 't', 0 },
> +	{ NOTMUCH_OPT_KEYWORD, &entire_thread, "thread", 't',
> +	  (notmuch_keyword_t []){ { "match", NOTMUCH_SHOW_THREAD_MATCH, },
> +				  { "entire", NOTMUCH_SHOW_THREAD_ENTIRE },
> +				  { "none", NOTMUCH_SHOW_THREAD_NONE },
> +				  { 0, 0 } } },
>  	{ NOTMUCH_OPT_BOOLEAN, &params.decrypt, "decrypt", 'd', 0 },
>  	{ NOTMUCH_OPT_BOOLEAN, &verify, "verify", 'v', 0 },
> +	{ NOTMUCH_OPT_BOOLEAN, &headers_only, "headers-only", 'h', 0 },
>  	{ 0, 0, 0, 0, 0 }
>      };
>  
> @@ -1055,6 +1115,9 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[]))
>  	return 1;
>      }
>  
> +    params.entire_thread = entire_thread;

entire_thread is not initialized here, if there is no --thread
argument. The rest of the code makes this result in the same behavior as
--thread=entire, but it should be initialized to
NOTMUCH_SHOW_THREAD_MATCH.

Cheers,
Daniel

[-- Attachment #2: Type: application/pgp-signature, Size: 835 bytes --]

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC PATCH v2 0/3] notmuch-pick: an emacs threaded message view with split-pane
  2012-02-12 20:39 ` [RFC PATCH v2 0/3] notmuch-pick: an emacs threaded message view with split-pane Jameson Graef Rollins
@ 2012-02-12 21:51   ` Mark Walters
  0 siblings, 0 replies; 26+ messages in thread
From: Mark Walters @ 2012-02-12 21:51 UTC (permalink / raw)
  To: Jameson Graef Rollins, notmuch

On Sun, 12 Feb 2012 12:39:13 -0800, Jameson Graef Rollins <jrollins@finestructure.net> wrote:
> On Sun, 12 Feb 2012 18:49:36 +0000, Mark Walters <markwalters1009@gmail.com> wrote:
> > Here is a rebased version of the notmuch-pick patch set
> > id:"87d39k1gvi.fsf@qmul.ac.uk". It now applies directly 
> > to master since Jani's notmuch-show command line parsing 
> > has been pushed.
> 
> Hey, Mark.  Thanks for working on this.  However, none of the patches
> have commit messages, so there's no explanation for what any of the
> patches are supposed to do.  This is particularly bothersome for the
> first patch, which introduces a lot of unexplained changes to the cli.
> 
> I think I would like to review this patch set, since I think I'm
> interested in the functionality it may be introducing, but without any
> commit messages or explanation what the patches are meant to do it's
> kind of a non starter for me.

Hi 

At the moment I was mostly looking for feedback on whether people like
the final outcome (i.e., whether people liked it enough to be worth
tidying). I will add comments on the first two patches.

Best wishes

Mark

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC PATCH v2 1/3] cli: notmuch-show changes to support pick
  2012-02-12 18:49 ` [RFC PATCH v2 1/3] cli: notmuch-show changes to support pick Mark Walters
  2012-02-12 21:08   ` Daniel Schoepe
@ 2012-02-12 22:08   ` Mark Walters
  1 sibling, 0 replies; 26+ messages in thread
From: Mark Walters @ 2012-02-12 22:08 UTC (permalink / raw)
  To: notmuch


This patch adds the following features to notmuch-show.c

a --headers-only option which just outputs the headers of a message
(i.e. it omits the bodies). This is not strictly needed by
notmuch-pick.el but it gives a speed-up of at least a factor of a two;
moreover it reduces the memory usage of the emacs part hugely.

a --sort=oldest-first|newest-first option to allow notmuch-pick.el to
choose the sort order.

a --thread=none option to tell it to return just the matching messages
with not threading information at all. This is used by notmuch-pick.el
to display an unthreaded message view (e.g., for an inbox). It is also
useful for displaying a single message in the pick view as show is much
faster at showing  a single message than the whole thread.

The other options for --thread of --thread=entire|match replace the
--entire-thread option.

Presumably this should really be split into three separate patches, but
advice on this is gratefully received!

Thanks

Mark

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC PATCH v2 2/3] emacs: changes to other files to support notmuch-pick
  2012-02-12 18:49 ` [RFC PATCH v2 2/3] emacs: changes to other files to support notmuch-pick Mark Walters
@ 2012-02-12 22:27   ` Mark Walters
  0 siblings, 0 replies; 26+ messages in thread
From: Mark Walters @ 2012-02-12 22:27 UTC (permalink / raw)
  To: notmuch


This patch adds 

entries to notmuch-pick to notmuch-hello.el notmuch.el and
notmuch-show.el.

the option to view the current search in pick mode (from either
notmuch-show.el or notmuch.el)

a defcustom group for notmuch-pick.

make notmuch-show (the main function) return the buffer it uses. This is
used by notmuch-pick to try and make sure it only kills the correct
buffer.

Add an extra parameter to notmuch-query-get-threads (in
notmuch-query.el) so that extra parameters can be passed to control the
sort order, the --headers-only option, and threading etc.

Finally add an option to notmuch-show to get it to pass the
--thread=none option (so that just the matching messages are returned
with no threading). This is used to show a single message (e.g. when the
query is a single message-id).

Again advice on how to split up this patch is gratefully received!

Best wishes

Mark

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [RFC PATCH v3 00/11] notmuch-pick: an emacs threaded message view with split-pane
  2012-02-12 18:49 [RFC PATCH v2 0/3] notmuch-pick: an emacs threaded message view with split-pane Mark Walters
                   ` (3 preceding siblings ...)
  2012-02-12 20:39 ` [RFC PATCH v2 0/3] notmuch-pick: an emacs threaded message view with split-pane Jameson Graef Rollins
@ 2012-02-13  1:20 ` Mark Walters
  2012-02-14 12:28   ` Mark Walters
  2012-02-13  1:20 ` [RFC PATCH v3 01/11] cli: add --headers_only option to notmuch-show.c Mark Walters
                   ` (11 subsequent siblings)
  16 siblings, 1 reply; 26+ messages in thread
From: Mark Walters @ 2012-02-13  1:20 UTC (permalink / raw)
  To: notmuch

Here is a split up version of the patches with (I hope) reasonable 
commit messages. (Magit is amazing.)                                                                          

I have not split up the new notmuch-pick file but the cli and other
emacs bits should be managable. (Note intermediate emacs points may
not compile as they add references to notmuch-pick in the existing
code.)                                                                                                        

I have included another bugfix from Daniel (entire-thread was used 
uninitialised in notmuch-show.c)                                                                              

The only functional change is to add Daniel's notmuch-search-pick-thread
function to notmuch.el (bound to M-RET) which views the currently 
selected thread in notmuch-pick.                                                                              

I also found one stale change which I removed.   

Best wishes

Mark


Mark Walters (11):
  cli: add --headers_only option to notmuch-show.c
  cli: add sort options to notmuch-show.c
  cli: add --thread= option to notmuch-show
  emacs: add entry to notmuch-pick from notmuch-hello.el
  emacs: add defcustom group for notmuch-pick
  emacs: add extra parameters option to notmuch-query-get-threads
  emacs: add entry to notmuch-pick from notmuch.el
  emacs: add the entry to notmuch-pick to notmuch-show.el
  emacs: make notmuch-show return its buffer
  emacs: notmuch-show.el just show the actual matching messages
  emacs: add notmuch-pick itself

 emacs/Makefile.local   |    3 +-
 emacs/notmuch-hello.el |   10 +
 emacs/notmuch-lib.el   |    4 +
 emacs/notmuch-pick.el  |  585 ++++++++++++++++++++++++++++++++++++++++++++++++
 emacs/notmuch-query.el |    4 +-
 emacs/notmuch-show.el  |   25 ++-
 emacs/notmuch.el       |   20 ++
 notmuch-client.h       |    9 +-
 notmuch-show.c         |   73 ++++++-
 9 files changed, 723 insertions(+), 10 deletions(-)
 create mode 100644 emacs/notmuch-pick.el

-- 
1.7.2.3

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [RFC PATCH v3 01/11] cli: add --headers_only option to notmuch-show.c
  2012-02-12 18:49 [RFC PATCH v2 0/3] notmuch-pick: an emacs threaded message view with split-pane Mark Walters
                   ` (4 preceding siblings ...)
  2012-02-13  1:20 ` [RFC PATCH v3 00/11] " Mark Walters
@ 2012-02-13  1:20 ` Mark Walters
  2012-02-13  1:20 ` [RFC PATCH v3 02/11] cli: add sort options " Mark Walters
                   ` (10 subsequent siblings)
  16 siblings, 0 replies; 26+ messages in thread
From: Mark Walters @ 2012-02-13  1:20 UTC (permalink / raw)
  To: notmuch

This option just outputs the headers of a message
(i.e. it omits the bodies).

This is used by notmuch-pick.el (although not needed) because it gives a
speed-up of at least a factor of a two; moreover it reduces the memory
usage in emacs hugely.
---
 notmuch-client.h |    1 +
 notmuch-show.c   |    6 +++++-
 2 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/notmuch-client.h b/notmuch-client.h
index 60828aa..0da2d8d 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -101,6 +101,7 @@ typedef struct notmuch_show_params {
     notmuch_bool_t entire_thread;
     notmuch_bool_t raw;
     int part;
+    int headers_only;
 #ifdef GMIME_ATLEAST_26
     GMimeCryptoContext* cryptoctx;
 #else
diff --git a/notmuch-show.c b/notmuch-show.c
index d930f94..9d73685 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -841,7 +841,7 @@ show_message (void *ctx,
 	fputs (format->body_start, stdout);
     }
 
-    if (format->part_content)
+    if (format->part_content && !params->headers_only)
 	show_message_body (message, format, params);
 
     if (params->part <= 0) {
@@ -1034,6 +1034,7 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[]))
     notmuch_show_params_t params = { .part = -1 };
     int format_sel = NOTMUCH_FORMAT_NOT_SPECIFIED;
     notmuch_bool_t verify = FALSE;
+    notmuch_bool_t headers_only = FALSE;
 
     notmuch_opt_desc_t options[] = {
 	{ NOTMUCH_OPT_KEYWORD, &format_sel, "format", 'f',
@@ -1046,6 +1047,7 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[]))
 	{ NOTMUCH_OPT_BOOLEAN, &params.entire_thread, "entire-thread", 't', 0 },
 	{ NOTMUCH_OPT_BOOLEAN, &params.decrypt, "decrypt", 'd', 0 },
 	{ NOTMUCH_OPT_BOOLEAN, &verify, "verify", 'v', 0 },
+	{ NOTMUCH_OPT_BOOLEAN, &headers_only, "headers-only", 'h', 0 },
 	{ 0, 0, 0, 0, 0 }
     };
 
@@ -1055,6 +1057,8 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[]))
 	return 1;
     }
 
+    params.headers_only = headers_only;
+
     if (format_sel == NOTMUCH_FORMAT_NOT_SPECIFIED) {
 	/* if part was requested and format was not specified, use format=raw */
 	if (params.part >= 0)
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC PATCH v3 02/11] cli: add sort options to notmuch-show.c
  2012-02-12 18:49 [RFC PATCH v2 0/3] notmuch-pick: an emacs threaded message view with split-pane Mark Walters
                   ` (5 preceding siblings ...)
  2012-02-13  1:20 ` [RFC PATCH v3 01/11] cli: add --headers_only option to notmuch-show.c Mark Walters
@ 2012-02-13  1:20 ` Mark Walters
  2012-02-13  1:20 ` [RFC PATCH v3 03/11] cli: add --thread= option to notmuch-show Mark Walters
                   ` (9 subsequent siblings)
  16 siblings, 0 replies; 26+ messages in thread
From: Mark Walters @ 2012-02-13  1:20 UTC (permalink / raw)
  To: notmuch

Add the option --sort=newest-first|oldest-first to notmuch-show. This
is used by notmuch-pick.el
---
 notmuch-show.c |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/notmuch-show.c b/notmuch-show.c
index 9d73685..8f6e520 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -1030,6 +1030,7 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[]))
     notmuch_query_t *query;
     char *query_string;
     int opt_index, ret;
+    notmuch_sort_t sort = NOTMUCH_SORT_NEWEST_FIRST;
     const notmuch_show_format_t *format = &format_text;
     notmuch_show_params_t params = { .part = -1 };
     int format_sel = NOTMUCH_FORMAT_NOT_SPECIFIED;
@@ -1043,6 +1044,10 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[]))
 				  { "mbox", NOTMUCH_FORMAT_MBOX },
 				  { "raw", NOTMUCH_FORMAT_RAW },
 				  { 0, 0 } } },
+	{ NOTMUCH_OPT_KEYWORD, &sort, "sort", 's',
+	  (notmuch_keyword_t []){ { "oldest-first", NOTMUCH_SORT_OLDEST_FIRST },
+				  { "newest-first", NOTMUCH_SORT_NEWEST_FIRST },
+				  { 0, 0 } } },
 	{ NOTMUCH_OPT_INT, &params.part, "part", 'p', 0 },
 	{ NOTMUCH_OPT_BOOLEAN, &params.entire_thread, "entire-thread", 't', 0 },
 	{ NOTMUCH_OPT_BOOLEAN, &params.decrypt, "decrypt", 'd', 0 },
@@ -1137,6 +1142,8 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[]))
 	return 1;
     }
 
+    notmuch_query_set_sort (query, sort);
+
     if (params.part >= 0)
 	ret = do_show_single (ctx, query, format, &params);
     else
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC PATCH v3 03/11] cli: add --thread= option to notmuch-show
  2012-02-12 18:49 [RFC PATCH v2 0/3] notmuch-pick: an emacs threaded message view with split-pane Mark Walters
                   ` (6 preceding siblings ...)
  2012-02-13  1:20 ` [RFC PATCH v3 02/11] cli: add sort options " Mark Walters
@ 2012-02-13  1:20 ` Mark Walters
  2012-02-13  1:20 ` [RFC PATCH v3 04/11] emacs: add entry to notmuch-pick from notmuch-hello.el Mark Walters
                   ` (8 subsequent siblings)
  16 siblings, 0 replies; 26+ messages in thread
From: Mark Walters @ 2012-02-13  1:20 UTC (permalink / raw)
  To: notmuch

The possible values are --thread=none|entire|match.

`entire' is exactly the existing option --entire-thread.

`match' is exactly the existing case when --entire-thread is not specified.

`none' is a new option to return just the matching messages with no
threading information at all.

The `none' option is used by notmuch-pick.el to display an unthreaded
message view (e.g., for an inbox). It is also useful for displaying a
single message in the notmuch-pick view as show/emacs is much faster at
showing a single message than the whole thread.

The default remains as before: `match' in all cases except when
--format=json is specified when `entire' is used.
---
 notmuch-client.h |    8 ++++++-
 notmuch-show.c   |   60 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 64 insertions(+), 4 deletions(-)

diff --git a/notmuch-client.h b/notmuch-client.h
index 0da2d8d..b4dc7bf 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -97,8 +97,14 @@ typedef struct notmuch_show_format {
     const char *message_set_end;
 } notmuch_show_format_t;
 
+enum {
+    NOTMUCH_SHOW_THREAD_MATCH,
+    NOTMUCH_SHOW_THREAD_ENTIRE,
+    NOTMUCH_SHOW_THREAD_NONE
+};
+
 typedef struct notmuch_show_params {
-    notmuch_bool_t entire_thread;
+    int entire_thread;
     notmuch_bool_t raw;
     int part;
     int headers_only;
diff --git a/notmuch-show.c b/notmuch-show.c
index 8f6e520..3f8618b 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -893,13 +893,56 @@ show_messages (void *ctx,
 		       notmuch_message_get_replies (message),
 		       next_indent,
 		       params);
+	notmuch_message_destroy (message);
+
+	fputs (format->message_set_end, stdout);
+    }
+
+    fputs (format->message_set_end, stdout);
+}
+
+static int
+do_show_messages (void *ctx,
+		  notmuch_query_t *query,
+		  const notmuch_show_format_t *format,
+		  notmuch_show_params_t *params)
+{
+    notmuch_messages_t *messages;
+    notmuch_message_t *message;
+    int first_set = 1;
+
+    fputs (format->message_set_start, stdout);
+    messages = notmuch_query_search_messages (query);
+
+    for (;
+	 notmuch_messages_valid (messages);
+	 notmuch_messages_move_to_next (messages))
+    {
+	if (!first_set)
+	    fputs (format->message_set_sep, stdout);
+	first_set = 0;
+
+	fputs (format->message_set_start, stdout);
+	fputs (format->message_set_start, stdout);
+
+	message = notmuch_messages_get (messages);
+	notmuch_message_set_flag (message, NOTMUCH_MESSAGE_FLAG_MATCH, 1);
+	show_message (ctx, format, message, 0, params);
+
+	fputs (format->message_set_sep, stdout);
+
+	fputs (format->message_set_start, stdout);
+	fputs (format->message_set_end, stdout);
+
 
 	notmuch_message_destroy (message);
 
 	fputs (format->message_set_end, stdout);
+	fputs (format->message_set_end, stdout);
     }
 
     fputs (format->message_set_end, stdout);
+    return 0;
 }
 
 /* Formatted output of single message */
@@ -1030,6 +1073,7 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[]))
     notmuch_query_t *query;
     char *query_string;
     int opt_index, ret;
+    int entire_thread = NOTMUCH_SHOW_THREAD_MATCH;
     notmuch_sort_t sort = NOTMUCH_SORT_NEWEST_FIRST;
     const notmuch_show_format_t *format = &format_text;
     notmuch_show_params_t params = { .part = -1 };
@@ -1049,7 +1093,11 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[]))
 				  { "newest-first", NOTMUCH_SORT_NEWEST_FIRST },
 				  { 0, 0 } } },
 	{ NOTMUCH_OPT_INT, &params.part, "part", 'p', 0 },
-	{ NOTMUCH_OPT_BOOLEAN, &params.entire_thread, "entire-thread", 't', 0 },
+	{ NOTMUCH_OPT_KEYWORD, &entire_thread, "thread", 't',
+	  (notmuch_keyword_t []){ { "match", NOTMUCH_SHOW_THREAD_MATCH, },
+				  { "entire", NOTMUCH_SHOW_THREAD_ENTIRE },
+				  { "none", NOTMUCH_SHOW_THREAD_NONE },
+				  { 0, 0 } } },
 	{ NOTMUCH_OPT_BOOLEAN, &params.decrypt, "decrypt", 'd', 0 },
 	{ NOTMUCH_OPT_BOOLEAN, &verify, "verify", 'v', 0 },
 	{ NOTMUCH_OPT_BOOLEAN, &headers_only, "headers-only", 'h', 0 },
@@ -1062,6 +1110,7 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[]))
 	return 1;
     }
 
+    params.entire_thread = entire_thread;
     params.headers_only = headers_only;
 
     if (format_sel == NOTMUCH_FORMAT_NOT_SPECIFIED) {
@@ -1075,7 +1124,9 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[]))
     switch (format_sel) {
     case NOTMUCH_FORMAT_JSON:
 	format = &format_json;
-	params.entire_thread = TRUE;
+	/* This may not still be wanted */
+	if (params.entire_thread == NOTMUCH_SHOW_THREAD_MATCH)
+	    params.entire_thread = NOTMUCH_SHOW_THREAD_ENTIRE;
 	break;
     case NOTMUCH_FORMAT_TEXT:
 	format = &format_text;
@@ -1147,7 +1198,10 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[]))
     if (params.part >= 0)
 	ret = do_show_single (ctx, query, format, &params);
     else
-	ret = do_show (ctx, query, format, &params);
+	if (params.entire_thread == NOTMUCH_SHOW_THREAD_NONE)
+	    ret = do_show_messages (ctx, query, format, &params);
+	else
+	    ret = do_show (ctx, query, format, &params);
 
     notmuch_query_destroy (query);
     notmuch_database_close (notmuch);
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC PATCH v3 04/11] emacs: add entry to notmuch-pick from notmuch-hello.el
  2012-02-12 18:49 [RFC PATCH v2 0/3] notmuch-pick: an emacs threaded message view with split-pane Mark Walters
                   ` (7 preceding siblings ...)
  2012-02-13  1:20 ` [RFC PATCH v3 03/11] cli: add --thread= option to notmuch-show Mark Walters
@ 2012-02-13  1:20 ` Mark Walters
  2012-02-13  1:20 ` [RFC PATCH v3 05/11] emacs: add defcustom group for notmuch-pick Mark Walters
                   ` (7 subsequent siblings)
  16 siblings, 0 replies; 26+ messages in thread
From: Mark Walters @ 2012-02-13  1:20 UTC (permalink / raw)
  To: notmuch

Add an entry to notmuch-pick from notmuch-hello and bind it to 'z'.
---
 emacs/notmuch-hello.el |   10 ++++++++++
 1 files changed, 10 insertions(+), 0 deletions(-)

diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
index d17a30f..6d28a7e 100644
--- a/emacs/notmuch-hello.el
+++ b/emacs/notmuch-hello.el
@@ -27,6 +27,7 @@
 (require 'notmuch-mua)
 
 (declare-function notmuch-search "notmuch" (query &optional oldest-first target-thread target-line continuation))
+(declare-function notmuch-pick "notmuch-pick" (query &optional query-context buffer-name))
 (declare-function notmuch-poll "notmuch" ())
 
 (defcustom notmuch-hello-recent-searches-max 10
@@ -181,6 +182,14 @@ International Bureau of Weights and Measures."
   (notmuch-search search notmuch-search-oldest-first nil nil
 		  #'notmuch-hello-search-continuation))
 
+(defun notmuch-hello-pick (&optional search)
+  (interactive)
+  (unless (null search)
+    (setq search (notmuch-hello-trim search))
+    (let ((history-delete-duplicates t))
+      (add-to-history 'notmuch-search-history search)))
+  (notmuch-pick search))
+
 (defun notmuch-hello-add-saved-search (widget)
   (interactive)
   (let ((search (widget-value
@@ -345,6 +354,7 @@ should be. Returns a cons cell `(tags-per-line width)'."
     (define-key map (kbd "<C-tab>") 'widget-backward)
     (define-key map "m" 'notmuch-mua-new-mail)
     (define-key map "s" 'notmuch-hello-search)
+    (define-key map "z" 'notmuch-hello-pick)
     map)
   "Keymap for \"notmuch hello\" buffers.")
 (fset 'notmuch-hello-mode-map notmuch-hello-mode-map)
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC PATCH v3 05/11] emacs: add defcustom group for notmuch-pick
  2012-02-12 18:49 [RFC PATCH v2 0/3] notmuch-pick: an emacs threaded message view with split-pane Mark Walters
                   ` (8 preceding siblings ...)
  2012-02-13  1:20 ` [RFC PATCH v3 04/11] emacs: add entry to notmuch-pick from notmuch-hello.el Mark Walters
@ 2012-02-13  1:20 ` Mark Walters
  2012-02-13  1:20 ` [RFC PATCH v3 06/11] emacs: add extra parameters option to notmuch-query-get-threads Mark Walters
                   ` (6 subsequent siblings)
  16 siblings, 0 replies; 26+ messages in thread
From: Mark Walters @ 2012-02-13  1:20 UTC (permalink / raw)
  To: notmuch

---
 emacs/notmuch-lib.el |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/emacs/notmuch-lib.el b/emacs/notmuch-lib.el
index d315f76..b88bb80 100644
--- a/emacs/notmuch-lib.el
+++ b/emacs/notmuch-lib.el
@@ -40,6 +40,10 @@
   "Showing messages and threads."
   :group 'notmuch)
 
+(defgroup notmuch-pick nil
+  "Showing message and thread structure."
+  :group 'notmuch)
+
 (defgroup notmuch-send nil
   "Sending messages from Notmuch."
   :group 'notmuch)
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC PATCH v3 06/11] emacs: add extra parameters option to notmuch-query-get-threads
  2012-02-12 18:49 [RFC PATCH v2 0/3] notmuch-pick: an emacs threaded message view with split-pane Mark Walters
                   ` (9 preceding siblings ...)
  2012-02-13  1:20 ` [RFC PATCH v3 05/11] emacs: add defcustom group for notmuch-pick Mark Walters
@ 2012-02-13  1:20 ` Mark Walters
  2012-02-13  1:20 ` [RFC PATCH v3 07/11] emacs: add entry to notmuch-pick from notmuch.el Mark Walters
                   ` (5 subsequent siblings)
  16 siblings, 0 replies; 26+ messages in thread
From: Mark Walters @ 2012-02-13  1:20 UTC (permalink / raw)
  To: notmuch

Add an extra parameter to notmuch-query-get-threads (in
notmuch-query.el) so that callers can pass in extra parameters to
control the sort order, the --headers-only option, and threading etc.
---
 emacs/notmuch-query.el |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/emacs/notmuch-query.el b/emacs/notmuch-query.el
index d66baea..b3c91a3 100644
--- a/emacs/notmuch-query.el
+++ b/emacs/notmuch-query.el
@@ -22,7 +22,7 @@
 (require 'notmuch-lib)
 (require 'json)
 
-(defun notmuch-query-get-threads (search-terms)
+(defun notmuch-query-get-threads (search-terms &rest extra-format)
   "Return a list of threads of messages matching SEARCH-TERMS.
 
 A thread is a forest or list of trees. A tree is a two element
@@ -33,6 +33,8 @@ is a possibly empty forest of replies.
 	 (json-object-type 'plist)
 	 (json-array-type 'list)
 	 (json-false 'nil))
+    (if extra-format
+	(setq args (append args extra-format)))
     (if notmuch-show-process-crypto
 	(setq args (append args '("--decrypt"))))
     (setq args (append args search-terms))
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC PATCH v3 07/11] emacs: add entry to notmuch-pick from notmuch.el
  2012-02-12 18:49 [RFC PATCH v2 0/3] notmuch-pick: an emacs threaded message view with split-pane Mark Walters
                   ` (10 preceding siblings ...)
  2012-02-13  1:20 ` [RFC PATCH v3 06/11] emacs: add extra parameters option to notmuch-query-get-threads Mark Walters
@ 2012-02-13  1:20 ` Mark Walters
  2012-02-13  1:20 ` [RFC PATCH v3 08/11] emacs: add the entry to notmuch-pick to notmuch-show.el Mark Walters
                   ` (4 subsequent siblings)
  16 siblings, 0 replies; 26+ messages in thread
From: Mark Walters @ 2012-02-13  1:20 UTC (permalink / raw)
  To: notmuch

Add bindings 'z' to enter a notmuch-pick search and 'Z' to go straight
to the current search (i.e. the on being viewed in notmuch.el buffer)
in notmuch-pick. Also add binding `M-RET' to view the currently selected
thread with notmuch-pick.
---
 emacs/notmuch.el |   20 ++++++++++++++++++++
 1 files changed, 20 insertions(+), 0 deletions(-)

diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index 5b4f1c5..28f7953 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -54,6 +54,7 @@
 
 (require 'notmuch-lib)
 (require 'notmuch-show)
+(require 'notmuch-pick)
 (require 'notmuch-mua)
 (require 'notmuch-hello)
 (require 'notmuch-maildir-fcc)
@@ -272,6 +273,8 @@ For a mouse binding, return nil."
     (define-key map "R" 'notmuch-search-reply-to-thread)
     (define-key map "m" 'notmuch-mua-new-mail)
     (define-key map "s" 'notmuch-search)
+    (define-key map "z" 'notmuch-pick)
+    (define-key map "Z" 'notmuch-search-pick-current-query)
     (define-key map "o" 'notmuch-search-toggle-order)
     (define-key map "c" 'notmuch-search-stash-map)
     (define-key map "=" 'notmuch-search-refresh-view)
@@ -284,6 +287,7 @@ For a mouse binding, return nil."
     (define-key map "-" 'notmuch-search-remove-tag)
     (define-key map "+" 'notmuch-search-add-tag)
     (define-key map (kbd "RET") 'notmuch-search-show-thread)
+    (define-key map (kbd "M-RET") 'notmuch-search-pick-thread)
     map)
   "Keymap for \"notmuch search\" buffers.")
 (fset 'notmuch-search-mode-map notmuch-search-mode-map)
@@ -1021,6 +1025,22 @@ same relative position within the new buffer."
     (notmuch-search query oldest-first target-thread target-line continuation)
     (goto-char (point-min))))
 
+(defun notmuch-search-pick-current-query ()
+  "Call notmuch pick with the current query"
+  (interactive)
+  (notmuch-pick notmuch-search-query-string))
+
+(defun notmuch-search-pick-thread ()
+  "Show the selected thread with notmuch-pick"
+  (interactive)
+  (notmuch-pick (notmuch-search-find-thread-id)
+		notmuch-search-query-string
+		(notmuch-prettify-subject (notmuch-search-find-subject)))
+  (unless (notmuch-pick-get-match)
+    (notmuch-pick-next-message))
+  (notmuch-pick-show-message))
+
+
 (defcustom notmuch-poll-script nil
   "An external script to incorporate new mail into the notmuch database.
 
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC PATCH v3 08/11] emacs: add the entry to notmuch-pick to notmuch-show.el
  2012-02-12 18:49 [RFC PATCH v2 0/3] notmuch-pick: an emacs threaded message view with split-pane Mark Walters
                   ` (11 preceding siblings ...)
  2012-02-13  1:20 ` [RFC PATCH v3 07/11] emacs: add entry to notmuch-pick from notmuch.el Mark Walters
@ 2012-02-13  1:20 ` Mark Walters
  2012-02-13  1:20 ` [RFC PATCH v3 09/11] emacs: make notmuch-show return its buffer Mark Walters
                   ` (3 subsequent siblings)
  16 siblings, 0 replies; 26+ messages in thread
From: Mark Walters @ 2012-02-13  1:20 UTC (permalink / raw)
  To: notmuch

Add key bindings 'z' to enter a notmuch-pick search and 'Z' to view
the current `show' (i.e. a thread-id with some query) in notmuch-pick.
---
 emacs/notmuch-show.el |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 43408d9..244e18d 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -42,6 +42,7 @@
 (declare-function notmuch-search-next-thread "notmuch" nil)
 (declare-function notmuch-search-show-thread "notmuch" nil)
 (declare-function notmuch-update-tags "notmuch" (current-tags tag-changes))
+(declare-function notmuch-pick "notmuch-pick" (query &optional query-context buffer-name))
 
 (defcustom notmuch-message-headers '("Subject" "To" "Cc" "Date")
   "Headers that should be shown in a message, in this order.
@@ -1158,6 +1159,8 @@ buffer is stored and re-applied after the refresh."
 	(define-key map (kbd "<backtab>") 'notmuch-show-previous-button)
 	(define-key map (kbd "TAB") 'notmuch-show-next-button)
 	(define-key map "s" 'notmuch-search)
+	(define-key map "z" 'notmuch-pick)
+	(define-key map "Z" 'notmuch-show-pick-current-query)
 	(define-key map "m" 'notmuch-mua-new-mail)
 	(define-key map "f" 'notmuch-show-forward-message)
 	(define-key map "r" 'notmuch-show-reply-sender)
@@ -1565,6 +1568,11 @@ to show, nil otherwise."
   (notmuch-show-mark-read)
   (notmuch-show-message-adjust))
 
+(defun notmuch-show-pick-current-query ()
+  "Call notmuch pick with the current query"
+  (interactive)
+  (notmuch-pick notmuch-show-thread-id notmuch-show-query-context))
+
 (defun notmuch-show-view-raw-message ()
   "View the file holding the current message."
   (interactive)
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC PATCH v3 09/11] emacs: make notmuch-show return its buffer
  2012-02-12 18:49 [RFC PATCH v2 0/3] notmuch-pick: an emacs threaded message view with split-pane Mark Walters
                   ` (12 preceding siblings ...)
  2012-02-13  1:20 ` [RFC PATCH v3 08/11] emacs: add the entry to notmuch-pick to notmuch-show.el Mark Walters
@ 2012-02-13  1:20 ` Mark Walters
  2012-02-13  1:20 ` [RFC PATCH v3 10/11] emacs: notmuch-show.el just show the actual matching messages Mark Walters
                   ` (2 subsequent siblings)
  16 siblings, 0 replies; 26+ messages in thread
From: Mark Walters @ 2012-02-13  1:20 UTC (permalink / raw)
  To: notmuch

notmuch-pick uses the returned buffer to try and make sure it does not
close the wrong buffer.
---
 emacs/notmuch-show.el |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 244e18d..8a8acf6 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -1048,7 +1048,8 @@ function is used."
     (setq notmuch-show-thread-id thread-id
 	  notmuch-show-parent-buffer parent-buffer
 	  notmuch-show-query-context query-context)
-    (notmuch-show-worker)))
+    (notmuch-show-worker)
+    (current-buffer)))
 
 (defun notmuch-show-worker ()
   (let ((inhibit-read-only t))
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC PATCH v3 10/11] emacs: notmuch-show.el just show the actual matching messages
  2012-02-12 18:49 [RFC PATCH v2 0/3] notmuch-pick: an emacs threaded message view with split-pane Mark Walters
                   ` (13 preceding siblings ...)
  2012-02-13  1:20 ` [RFC PATCH v3 09/11] emacs: make notmuch-show return its buffer Mark Walters
@ 2012-02-13  1:20 ` Mark Walters
  2012-02-13  1:20 ` [RFC PATCH v3 11/11] emacs: add notmuch-pick itself Mark Walters
  2012-02-13  9:05 ` [RFC PATCH v2 0/3] notmuch-pick: an emacs threaded message view with split-pane Aneesh Kumar K.V
  16 siblings, 0 replies; 26+ messages in thread
From: Mark Walters @ 2012-02-13  1:20 UTC (permalink / raw)
  To: notmuch

Allow a parameter to notmuch-show to just show the matching
messages. This is very similar to
notmuch-show-elide-non-matching-messages but since it calls
notmuch-show.c with the --thread=none parameter it does not keep any
threading information.

In particular the sort order is different: the elide-non-matching
sorts by thread and just omits the non-matching messages, this option
sorts by message.

It is likely that the two should be unified.
---
 emacs/notmuch-show.el |   14 ++++++++++++--
 1 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 8a8acf6..1adf964 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -152,6 +152,12 @@ indentation."
 (make-variable-buffer-local 'notmuch-show-elide-non-matching-messages)
 (put 'notmuch-show-elide-non-matching-messages 'permanent-local t)
 
+;; This is very similar to the previous variable: they should be
+;; unified. MJW
+(defvar notmuch-show-just-matches nil)
+(make-variable-buffer-local 'notmuch-show-just-matches)
+(put 'notmuch-show-just-matches 'permanent-local t)
+
 (defvar notmuch-show-indent-content t)
 (make-variable-buffer-local 'notmuch-show-indent-content)
 (put 'notmuch-show-indent-content 'permanent-local t)
@@ -1014,7 +1020,7 @@ a corresponding notmuch search."
 			'face goto-address-mail-face))))
 
 ;;;###autoload
-(defun notmuch-show (thread-id &optional parent-buffer query-context buffer-name)
+(defun notmuch-show (thread-id &optional parent-buffer query-context buffer-name just-matches)
   "Run \"notmuch show\" with the given thread ID and display results.
 
 The optional PARENT-BUFFER is the notmuch-search buffer from
@@ -1047,7 +1053,9 @@ function is used."
 
     (setq notmuch-show-thread-id thread-id
 	  notmuch-show-parent-buffer parent-buffer
-	  notmuch-show-query-context query-context)
+	  notmuch-show-query-context query-context
+	  notmuch-show-just-matches just-matches)
+
     (notmuch-show-worker)
     (current-buffer)))
 
@@ -1066,6 +1074,8 @@ function is used."
 		       (append (list "\'") basic-args
 			       (list "and (" notmuch-show-query-context ")\'"))
 		     (append (list "\'") basic-args (list "\'")))))
+	(if notmuch-show-just-matches
+	    (setq args (append (list "--thread=none") args)))
 	(notmuch-show-insert-forest (notmuch-query-get-threads args))
 	;; If the query context reduced the results to nothing, run
 	;; the basic query.
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC PATCH v3 11/11] emacs: add notmuch-pick itself
  2012-02-12 18:49 [RFC PATCH v2 0/3] notmuch-pick: an emacs threaded message view with split-pane Mark Walters
                   ` (14 preceding siblings ...)
  2012-02-13  1:20 ` [RFC PATCH v3 10/11] emacs: notmuch-show.el just show the actual matching messages Mark Walters
@ 2012-02-13  1:20 ` Mark Walters
  2012-02-13  9:05 ` [RFC PATCH v2 0/3] notmuch-pick: an emacs threaded message view with split-pane Aneesh Kumar K.V
  16 siblings, 0 replies; 26+ messages in thread
From: Mark Walters @ 2012-02-13  1:20 UTC (permalink / raw)
  To: notmuch

This adds the main notmuch-pick.el file itself
---
 emacs/Makefile.local  |    3 +-
 emacs/notmuch-pick.el |  585 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 587 insertions(+), 1 deletions(-)
 create mode 100644 emacs/notmuch-pick.el

diff --git a/emacs/Makefile.local b/emacs/Makefile.local
index 4fee0e8..2922d9e 100644
--- a/emacs/Makefile.local
+++ b/emacs/Makefile.local
@@ -14,7 +14,8 @@ emacs_sources := \
 	$(dir)/notmuch-message.el \
 	$(dir)/notmuch-crypto.el \
 	$(dir)/coolj.el \
-	$(dir)/notmuch-print.el
+	$(dir)/notmuch-print.el \
+	$(dir)/notmuch-pick.el
 
 emacs_images := \
 	$(srcdir)/$(dir)/notmuch-logo.png
diff --git a/emacs/notmuch-pick.el b/emacs/notmuch-pick.el
new file mode 100644
index 0000000..46eb720
--- /dev/null
+++ b/emacs/notmuch-pick.el
@@ -0,0 +1,585 @@
+;; notmuch-pick.el --- displaying notmuch forests.
+;;
+;; Copyright © Carl Worth
+;; Copyright © David Edmondson
+;;
+;; This file is part of Notmuch.
+;;
+;; Notmuch is free software: you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Notmuch is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Notmuch.  If not, see <http://www.gnu.org/licenses/>.
+;;
+;; Authors: David Edmondson <dme@dme.org>
+
+(require 'mail-parse)
+
+(require 'notmuch-lib)
+(require 'notmuch-query)
+(require 'notmuch-show)
+(eval-when-compile (require 'cl))
+
+(declare-function notmuch-call-notmuch-process "notmuch" (&rest args))
+(declare-function notmuch-show "notmuch-show" (&rest args))
+(declare-function notmuch-tag "notmuch" (query &rest tags))
+(declare-function notmuch-show-strip-re "notmuch-show" (subject))
+(declare-function notmuch-show-clean-address "notmuch-show" (parsed-address))
+(declare-function notmuch-show-spaces-n "notmuch-show" (n))
+(declare-function notmuch-read-query "notmuch" (prompt))
+(declare-function notmuch-read-tag-changes "notmuch" (&optional initial-input &rest search-terms))
+(declare-function notmuch-update-tags "notmuch" (current-tags tag-changes))
+
+(defcustom notmuch-pick-author-width 20
+  "Width of the author field."
+  :type 'integer
+  :group 'notmuch-pick)
+
+(defface notmuch-pick-match-face
+  '((((class color)
+      (background dark))
+     (:foreground "white"))
+    (((class color)
+      (background light))
+     (:foreground "black"))
+    (t (:bold t)))
+  "Face used in pick mode for matching messages."
+  :group 'notmuch-pick)
+
+(defface notmuch-pick-no-match-face
+  '((t (:foreground "gray")))
+  "Face used in pick mode for messages not matching the query."
+  :group 'notmuch-pick)
+
+(defvar notmuch-pick-previous-subject "")
+(make-variable-buffer-local 'notmuch-pick-previous-subject)
+
+(defvar notmuch-pick-thread-id nil)
+(make-variable-buffer-local 'notmuch-pick-thread-id)
+(defvar notmuch-pick-query-context nil)
+(make-variable-buffer-local 'notmuch-pick-query-context)
+(defvar notmuch-pick-buffer-name nil)
+(make-variable-buffer-local 'notmuch-pick-buffer-name)
+(defvar notmuch-pick-view-just-messages nil)
+(make-variable-buffer-local 'notmuch-pick-view-just-messages)
+(put 'notmuch-pick-view-just-messages 'permanent-local t)
+(defvar notmuch-pick-message-window nil)
+(make-variable-buffer-local 'notmuch-pick-message-window)
+(put 'notmuch-pick-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)
+(defvar notmuch-pick-oldest-first nil)
+(make-variable-buffer-local 'notmuch-pick-oldest-first)
+(put 'notmuch-pick-oldest-first 'permanent-local t)
+
+(defvar notmuch-pick-mode-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map (kbd "RET") 'notmuch-pick-show-message)
+    (define-key map [mouse-1] 'notmuch-pick-show-message)
+    (define-key map "q" 'notmuch-pick-quit)
+    (define-key map "x" 'notmuch-pick-quit)
+    (define-key map "?" 'notmuch-help)
+    (define-key map "a" 'notmuch-pick-archive-message)
+    (define-key map "=" 'notmuch-pick-refresh-view)
+    (define-key map "t" 'notmuch-pick-toggle-view)
+    (define-key map "o" 'notmuch-pick-toggle-order)
+    (define-key map "s" 'notmuch-search)
+    (define-key map "z" 'notmuch-pick)
+    (define-key map "m" 'notmuch-pick-new-mail)
+    (define-key map "f" 'notmuch-pick-forward-message)
+    (define-key map "r" 'notmuch-pick-reply-sender)
+    (define-key map "R" 'notmuch-pick-reply)
+    (define-key map "n" 'notmuch-pick-next-message)
+    (define-key map "p" 'notmuch-pick-prev-message)
+    (define-key map "|" 'notmuch-pick-pipe-message)
+    (define-key map "-" 'notmuch-pick-remove-tag)
+    (define-key map "+" 'notmuch-pick-add-tag)
+;;    (define-key map " " 'notmuch-pick-scroll-message-window)
+    (define-key map " " 'notmuch-pick-scroll-or-next)
+    (define-key map "b" 'notmuch-pick-scroll-message-window-back)
+    map))
+(fset 'notmuch-pick-mode-map notmuch-pick-mode-map)
+
+(defun notmuch-pick-get-message-properties ()
+  "Return the properties of the current message as a plist.
+
+Some useful entries are:
+:headers - Property list containing the headers :Date, :Subject, :From, etc.
+:tags - Tags for this message"
+  (save-excursion
+    (beginning-of-line)
+    (get-text-property (point) :notmuch-message-properties)))
+
+(defun notmuch-pick-set-message-properties (props)
+  (save-excursion
+    (beginning-of-line)
+    (put-text-property (point) (+ (point) 1) :notmuch-message-properties props)))
+
+(defun notmuch-pick-set-prop (prop val &optional props)
+  (let ((inhibit-read-only t)
+	(props (or props
+		   (notmuch-pick-get-message-properties))))
+    (plist-put props prop val)
+    (notmuch-pick-set-message-properties props)))
+
+(defun notmuch-pick-get-prop (prop &optional props)
+  (let ((props (or props
+		   (notmuch-pick-get-message-properties))))
+    (plist-get props prop)))
+
+(defun notmuch-pick-set-tags (tags)
+  "Set the tags of the current message."
+  (notmuch-pick-set-prop :tags tags))
+
+(defun notmuch-pick-get-tags ()
+  "Return the tags of the current message."
+  (notmuch-pick-get-prop :tags))
+
+(defun notmuch-pick-tag-message (&rest tag-changes)
+  "Change tags for the current message.
+
+TAG-CHANGES is a list of tag operations for `notmuch-tag'."
+  (let* ((current-tags (notmuch-pick-get-tags))
+	 (new-tags (notmuch-update-tags current-tags tag-changes)))
+    (unless (equal current-tags new-tags)
+      (apply 'notmuch-tag (notmuch-pick-get-message-id) tag-changes)
+      (notmuch-pick-set-tags new-tags))))
+
+(defun notmuch-pick-tag (&optional initial-input)
+  "Change tags for the current message, read input from the minibuffer."
+  (interactive)
+  (let ((tag-changes (notmuch-read-tag-changes
+		      initial-input (notmuch-pick-get-message-id))))
+    (apply 'notmuch-pick-tag-message tag-changes)))
+
+(defun notmuch-pick-add-tag ()
+  "Same as `notmuch-pick-tag' but sets initial input to '+'."
+  (interactive)
+  (notmuch-pick-tag "+"))
+
+(defun notmuch-pick-remove-tag ()
+  "Same as `notmuch-pick-tag' but sets initial input to '-'."
+  (interactive)
+  (notmuch-pick-tag "-"))
+
+(defun notmuch-pick-get-message-id ()
+  "Return the message id of the current message."
+  (concat "id:\"" (notmuch-pick-get-prop :id) "\""))
+
+(defun notmuch-pick-get-match ()
+  "Return whether the current message is a match."
+  (interactive)
+  (notmuch-pick-get-prop :match))
+
+(defun notmuch-pick-show-message ()
+  "Show the current message."
+  (interactive)
+  (let ((id (notmuch-pick-get-message-id))
+	(inhibit-read-only t)
+	buffer)
+    (when id
+      ;; we close and reopen the window to kill off un-needed buffers
+      ;; this might cause flickering but seems ok
+      (notmuch-pick-close-message-window)
+      (setq notmuch-pick-message-window
+	    (split-window-vertically (/ (window-height) 4)))
+      (with-selected-window notmuch-pick-message-window
+	(setq buffer (notmuch-show id nil nil nil t))))
+    (setq notmuch-pick-message-buffer buffer)))
+
+(defun notmuch-pick-scroll-message-window ()
+  "Scroll the message window (if it exists)"
+  (interactive)
+  (when (window-live-p notmuch-pick-message-window)
+    (with-selected-window notmuch-pick-message-window
+      (if (pos-visible-in-window-p (point-max))
+	  t
+	(scroll-up)))))
+
+(defun notmuch-pick-scroll-message-window-back ()
+  "Scroll the message window back(if it exists)"
+  (interactive)
+  (when (window-live-p notmuch-pick-message-window)
+    (with-selected-window notmuch-pick-message-window
+      (if (pos-visible-in-window-p (point-min))
+	  t
+	(scroll-down)))))
+
+(defun notmuch-pick-scroll-or-next ()
+  "Scroll the message window. If it at end go to next message."
+  (interactive)
+  (when (notmuch-pick-scroll-message-window)
+    (notmuch-pick-next-message)))
+
+(defun notmuch-pick-toggle-order ()
+  "Toggle the current search order.
+
+By default, the \"inbox\" view created by `notmuch' is displayed
+in chronological order (oldest thread at the beginning of the
+buffer), while any global searches created by `notmuch-search'
+are displayed in reverse-chronological order (newest thread at
+the beginning of the buffer).
+
+This command toggles the sort order for the current search."
+  (interactive)
+  (let ((inhibit-read-only t))
+    (if notmuch-pick-oldest-first
+	(message "Showing newest messages first")
+      (message "Showing oldest messages first"))
+    (set 'notmuch-pick-oldest-first (not notmuch-pick-oldest-first))
+    (notmuch-pick-refresh-view)))
+
+(defun notmuch-pick-quit ()
+  "Close the split view or exit pick."
+  (interactive)
+  (unless (notmuch-pick-close-message-window)
+    (kill-buffer (current-buffer))))
+
+(defun notmuch-pick-close-message-window ()
+  "Close the message-window. Return t if close succeeds."
+  (interactive)
+  (when (and (window-live-p notmuch-pick-message-window)
+	     (not (window-full-height-p notmuch-pick-message-window)))
+    (delete-window notmuch-pick-message-window)
+    (unless (get-buffer-window-list notmuch-pick-message-buffer)
+      (kill-buffer notmuch-pick-message-buffer))
+    t))
+
+(defun notmuch-pick-archive-message ()
+  "Archive the current message and move to next message."
+  (interactive)
+  (let ((id (notmuch-pick-get-message-id)))
+    (when id
+      (notmuch-tag id "-inbox" )
+      (forward-line))))
+
+(defun notmuch-pick-prev-message ()
+  "Move to previous matching message."
+  (interactive)
+  (forward-line -1)
+  (while (and (not (bobp)) (not (notmuch-pick-get-match)))
+    (forward-line -1))
+  (when (window-live-p notmuch-pick-message-window)
+    (notmuch-pick-show-message)))
+
+(defun notmuch-pick-next-message ()
+  "Move to next matching message."
+  (interactive)
+  (forward-line)
+  (while (and (not (eobp)) (not (notmuch-pick-get-match)))
+    (forward-line))
+  (when (window-live-p notmuch-pick-message-window)
+    (notmuch-pick-show-message)))
+
+(defun notmuch-pick-refresh-view ()
+  "Refresh view."
+  (interactive)
+  (let ((inhibit-read-only t)
+	(thread-id notmuch-pick-thread-id)
+	(query-context notmuch-pick-query-context)
+	(buffer-name notmuch-pick-buffer-name))
+    (erase-buffer)
+    (notmuch-pick-worker thread-id  query-context buffer-name)))
+
+(defun notmuch-pick-toggle-view ()
+  "Toggle showing threads or as isolated messages."
+  (interactive)
+  (let ((inhibit-read-only t))
+    (if notmuch-pick-view-just-messages
+	(message "Showing as threads")
+      (message "Showing as single messages"))
+    (setq notmuch-pick-view-just-messages (not notmuch-pick-view-just-messages))
+    (notmuch-pick-refresh-view)))
+
+(defun notmuch-pick-string-width (string width &optional right)
+  (let ((s (format (format "%%%s%ds" (if right "" "-") width)
+		   string)))
+    (if (> (length s) width)
+	(substring s 0 width)
+      s)))
+
+(defmacro with-current-notmuch-pick-message (&rest body)
+  "Evaluate body with current buffer set to the text of current message"
+  `(save-excursion
+     (let ((id (notmuch-pick-get-message-id)))
+       (let ((buf (generate-new-buffer (concat "*notmuch-msg-" id "*"))))
+         (with-current-buffer buf
+	    (call-process notmuch-command nil t nil "show" "--format=raw" id)
+           ,@body)
+	 (kill-buffer buf)))))
+
+(defun notmuch-pick-new-mail (&optional prompt-for-sender)
+  "Compose new mail."
+  (interactive "P")
+  (notmuch-pick-close-message-window)
+  (notmuch-mua-new-mail prompt-for-sender ))
+
+(defun notmuch-pick-forward-message (&optional prompt-for-sender)
+  "Forward the current message."
+  (interactive "P")
+  (notmuch-pick-close-message-window)
+  (with-current-notmuch-pick-message
+   (notmuch-mua-new-forward-message prompt-for-sender)))
+
+(defun notmuch-pick-reply (&optional prompt-for-sender)
+  "Reply to the sender and all recipients of the current message."
+  (interactive "P")
+  (notmuch-pick-close-message-window)
+  (notmuch-mua-new-reply (notmuch-pick-get-message-id) prompt-for-sender t))
+
+(defun notmuch-pick-reply-sender (&optional prompt-for-sender)
+  "Reply to the sender of the current message."
+  (interactive "P")
+  (notmuch-pick-close-message-window)
+  (notmuch-mua-new-reply (notmuch-pick-get-message-id) prompt-for-sender nil))
+
+;; Shamelessly stolen from notmuch-show.el: maybe should be unified MJW
+(defun notmuch-pick-pipe-message (command)
+  "Pipe the contents of the current message to the given command.
+
+The given command will be executed with the raw contents of the
+current email message as stdin. Anything printed by the command
+to stdout or stderr will appear in the *notmuch-pipe* buffer.
+
+When invoked with a prefix argument, the command will receive all
+open messages in the current thread (formatted as an mbox) rather
+than only the current message."
+  (interactive "sPipe message to command: ")
+  (let ((shell-command
+	 (concat notmuch-command " show --format=raw "
+		 (shell-quote-argument (notmuch-pick-get-message-id)) " | " command))
+	 (buf (get-buffer-create (concat "*notmuch-pipe*"))))
+    (with-current-buffer buf
+      (setq buffer-read-only nil)
+      (erase-buffer)
+      (let ((exit-code (call-process-shell-command shell-command nil buf)))
+	(goto-char (point-max))
+	(set-buffer-modified-p nil)
+	(setq buffer-read-only t)
+	(unless (zerop exit-code)
+	  (switch-to-buffer-other-window buf)
+	  (message (format "Command '%s' exited abnormally with code %d"
+			   shell-command exit-code)))))))
+
+;; Shamelessly stolen from notmuch-show.el: should be unified MJW
+(defun notmuch-pick-clean-address (address)
+  "Try to clean a single email ADDRESS for display.  Return
+unchanged ADDRESS if parsing fails."
+  (condition-case nil
+    (let (p-name p-address)
+      ;; It would be convenient to use `mail-header-parse-address',
+      ;; but that expects un-decoded mailbox parts, whereas our
+      ;; mailbox parts are already decoded (and hence may contain
+      ;; UTF-8). Given that notmuch should handle most of the awkward
+      ;; cases, some simple string deconstruction should be sufficient
+      ;; here.
+      (cond
+       ;; "User <user@dom.ain>" style.
+       ((string-match "\\(.*\\) <\\(.*\\)>" address)
+	(setq p-name (match-string 1 address)
+	      p-address (match-string 2 address)))
+
+       ;; "<user@dom.ain>" style.
+       ((string-match "<\\(.*\\)>" address)
+	(setq p-address (match-string 1 address)))
+
+       ;; Everything else.
+       (t
+	(setq p-address address)))
+
+      (when p-name
+	;; Remove elements of the mailbox part that are not relevant for
+	;; display, even if they are required during transport:
+	;;
+	;; Backslashes.
+	(setq p-name (replace-regexp-in-string "\\\\" "" p-name))
+
+	;; Outer single and double quotes, which might be nested.
+	(loop
+	 with start-of-loop
+	 do (setq start-of-loop p-name)
+
+	 when (string-match "^\"\\(.*\\)\"$" p-name)
+	 do (setq p-name (match-string 1 p-name))
+
+	 when (string-match "^'\\(.*\\)'$" p-name)
+	 do (setq p-name (match-string 1 p-name))
+
+	 until (string= start-of-loop p-name)))
+
+      ;; If the address is 'foo@bar.com <foo@bar.com>' then show just
+      ;; 'foo@bar.com'.
+      (when (string= p-name p-address)
+	(setq p-name nil))
+
+      ;; If we have a name return that otherwise return the address.
+      (if (not p-name)
+	  p-address
+	p-name))
+    (error address)))
+
+(defun notmuch-pick-insert-msg (msg depth tree-status)
+  (let* ((headers (plist-get msg :headers))
+	 (match (plist-get msg :match))
+	 (tags (plist-get msg :tags))
+	 (bare-subject (notmuch-show-strip-re (plist-get headers :Subject)))
+	 (message-face (if match
+			   'notmuch-pick-match-face
+			 'notmuch-pick-no-match-face)))
+
+    (insert (propertize (concat
+			 (notmuch-pick-string-width
+			  (plist-get msg :date_relative) 12 t)
+			 "  "
+			 (format "%-75s"
+				 (concat
+				  (notmuch-pick-string-width
+				   (notmuch-pick-clean-address (plist-get headers :From))
+				   (if notmuch-pick-view-just-messages
+				       (+ notmuch-pick-author-width 3)
+				     notmuch-pick-author-width))
+				  " "
+				  (unless notmuch-pick-view-just-messages
+				    (mapconcat #'identity (reverse tree-status) ""))
+				  (if (string= notmuch-pick-previous-subject bare-subject)
+				      " ..."
+				    bare-subject)))
+			 (if tags
+			     (concat " ("
+				     (mapconcat #'identity tags ", ") ")"))
+			 "") 'face message-face))
+    (notmuch-pick-set-message-properties msg)
+    (insert "\n")
+
+    (setq notmuch-pick-previous-subject bare-subject)))
+
+(defun notmuch-pick-insert-tree (tree depth tree-status first last)
+  "Insert the message tree TREE at depth DEPTH in the current thread."
+  (let ((msg (car tree))
+	(replies (cadr tree)))
+
+      (cond
+       ((and (< 0 depth) (not last))
+	(push "├" tree-status))
+       ((and (< 0 depth) last)
+	(push "╰" tree-status))
+       ((and (eq 0 depth) first last)
+;;	  (push "─" tree-status)) choice between this and next line is matter of taste MJW
+	(push " " tree-status))
+       ((and (eq 0 depth) first (not last))
+	  (push "┬" tree-status))
+       ((and (eq 0 depth) (not first) last)
+	(push "╰" tree-status))
+       ((and (eq 0 depth) (not first) (not last))
+	(push "├" tree-status)))
+
+      (push (concat (if replies "┬" "─") "►") tree-status)
+      (notmuch-pick-insert-msg msg depth tree-status)
+      (pop tree-status)
+      (pop tree-status)
+
+      (if last
+	  (push " " tree-status)
+	(push "│" tree-status))
+
+    (notmuch-pick-insert-thread replies (1+ depth) tree-status)))
+
+(defun notmuch-pick-insert-thread (thread depth tree-status)
+  "Insert the thread THREAD at depth DEPTH >= 1 in the current forest."
+  (let ((n (length thread)))
+    (loop for tree in thread
+	  for count from 1 to n
+
+	  do (notmuch-pick-insert-tree tree depth tree-status (eq count 1) (eq count n)))))
+
+(defun notmuch-pick-insert-forest (forest)
+  (mapc '(lambda (thread)
+	   (let (tree-status)
+	     ;; Reset at the start of each main thread.
+	     (setq notmuch-pick-previous-subject nil)
+	     (notmuch-pick-insert-thread thread 0 tree-status)))
+	forest))
+
+(defun notmuch-pick-mode ()
+  "Major mode displaying messages (as opposed to threads) of of a notmuch search.
+
+This buffer contains the results of a \"notmuch pick\" of your
+email archives. Each line in the buffer represents a single
+message giving the relative date, the author, subject, and any
+tags.
+
+Pressing \\[notmuch-pick-show-message] on any line displays that message.
+
+Complete list of currently available key bindings:
+
+\\{notmuch-pick-mode-map}"
+
+  (interactive)
+  (kill-all-local-variables)
+  (use-local-map notmuch-pick-mode-map)
+  (setq major-mode 'notmuch-pick-mode
+	mode-name "notmuch-pick")
+  (hl-line-mode 1)
+  (setq buffer-read-only t
+	truncate-lines t))
+
+(defun notmuch-pick-worker (thread-id &optional query-context buffer-name)
+  (interactive)
+  (notmuch-pick-mode)
+  (setq notmuch-pick-thread-id thread-id)
+  (setq notmuch-pick-query-context query-context)
+  (setq notmuch-pick-buffer-name buffer-name)
+
+  (erase-buffer)
+  (goto-char (point-min))
+  (save-excursion
+    (let* ((basic-args (list thread-id))
+	   (args (if query-context
+		     (append (list "\'") basic-args (list "and (" query-context ")\'"))
+		   (append (list "\'") basic-args (list "\'"))))
+	   (message-arg (if notmuch-pick-view-just-messages
+			    "--thread=none"
+			  "--thread=entire"))
+	   (sort-arg (if notmuch-pick-oldest-first
+			  "--sort=oldest-first"
+			"--sort=newest-first")))
+
+      (notmuch-pick-insert-forest (notmuch-query-get-threads args "--headers-only" message-arg sort-arg))
+      ;; If the query context reduced the results to nothing, run
+      ;; the basic query.
+      (when (and (eq (buffer-size) 0)
+		 query-context)
+	(notmuch-pick-insert-forest
+	 (notmuch-query-get-threads basic-args message-arg sort-arg))))))
+
+(defun notmuch-pick (&optional query query-context buffer-name)
+  "Run notmuch pick with the given `query' and display the results"
+  (interactive "sNotmuch pick: ")
+  (if (null query)
+      (setq query (notmuch-read-query "Notmuch pick: ")))
+  (let ((buffer (get-buffer-create (generate-new-buffer-name
+				    (or buffer-name
+					(concat "*notmuch-" query "*")))))
+	(inhibit-read-only t))
+
+    (switch-to-buffer buffer)
+    ;; Don't track undo information for this buffer
+    (set 'buffer-undo-list t)
+
+    (notmuch-pick-worker query query-context buffer-name)
+
+    (setq truncate-lines t)))
+
+;;  (use-local-map notmuch-pick-mode-map))
+
+;;
+
+(provide 'notmuch-pick)
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [RFC PATCH v2 0/3] notmuch-pick: an emacs threaded message view with split-pane
  2012-02-12 18:49 [RFC PATCH v2 0/3] notmuch-pick: an emacs threaded message view with split-pane Mark Walters
                   ` (15 preceding siblings ...)
  2012-02-13  1:20 ` [RFC PATCH v3 11/11] emacs: add notmuch-pick itself Mark Walters
@ 2012-02-13  9:05 ` Aneesh Kumar K.V
  2012-02-13 18:16   ` Mark Walters
  16 siblings, 1 reply; 26+ messages in thread
From: Aneesh Kumar K.V @ 2012-02-13  9:05 UTC (permalink / raw)
  To: Mark Walters, notmuch

On Sun, 12 Feb 2012 18:49:36 +0000, Mark Walters <markwalters1009@gmail.com> wrote:
> Here is a rebased version of the notmuch-pick patch set
> id:"87d39k1gvi.fsf@qmul.ac.uk". It now applies directly 
> to master since Jani's notmuch-show command line parsing 
> has been pushed.
> 
> It includes the significant bug fix (at least for anyone working 
> with a dark background) from Daniel making matched messages 
> highlight color both configurable and have a sensible default.
> These are in the notmuch-pick subgroup of the customize menus.
> 

Really nice patchset. It would be really nice if we can get the serach
limit patchset before this. That way the pick result will be limitted.
I also noticied that mails are not marked as read when i select them in
the notmuch-pick mode. Also for me the tree structures appears as
below. 

 Today 00:19  Mark Walters          ├┬►[RFC PATCH v2 1/3] cli: notmuch-show changes to support pick (notmuch)
 Today 02:38  Daniel Schoepe        │├─► ...                                              (notmuch, signed)
 Today 03:38  Mark Walters          │╰─► ...                                              (notmuch)
 Today 00:19  Mark Walters          ├┬►[RFC PATCH v2 2/3] emacs: changes to other files to support notmuch-pick (notmuch)
 Today 03:57  Mark Walters          │╰─► ...                                              (notmuch)
 Today 00:19  Mark Walters          ├─►[RFC PATCH v2 3/3] emacs: add notmuch-pick itself  (notmuch)

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC PATCH v2 0/3] notmuch-pick: an emacs threaded message view with split-pane
  2012-02-13  9:05 ` [RFC PATCH v2 0/3] notmuch-pick: an emacs threaded message view with split-pane Aneesh Kumar K.V
@ 2012-02-13 18:16   ` Mark Walters
  0 siblings, 0 replies; 26+ messages in thread
From: Mark Walters @ 2012-02-13 18:16 UTC (permalink / raw)
  To: Aneesh Kumar K.V, notmuch

On Mon, 13 Feb 2012 14:35:31 +0530, "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com> wrote:
> On Sun, 12 Feb 2012 18:49:36 +0000, Mark Walters <markwalters1009@gmail.com> wrote:
> > Here is a rebased version of the notmuch-pick patch set
> > id:"87d39k1gvi.fsf@qmul.ac.uk". It now applies directly 
> > to master since Jani's notmuch-show command line parsing 
> > has been pushed.
> > 
> > It includes the significant bug fix (at least for anyone working 
> > with a dark background) from Daniel making matched messages 
> > highlight color both configurable and have a sensible default.
> > These are in the notmuch-pick subgroup of the customize menus.
> > 

Hi

> Really nice patchset. It would be really nice if we can get the serach
> limit patchset before this. That way the pick result will be limitted.

Do you mean id:"1327692900-22926-1-git-send-email-jani@nikula.org"? That
would not affect notmuch-pick. In fact, since notmuch-pick uses
notmuch-show.c rather than notmuch-search.c the cli doesn't have the
--limit option. You are quite right that this may be the way to go
though.

> I also noticied that mails are not marked as read when i select them in
> the notmuch-pick mode. Also for me the tree structures appears as
> below. 

Are they not marked as read at all, or just not marked as read in the
notmuch-pick display (try pressing '=' and see if they are shown
correctly on refresh). It would be very nice to have the tags refresh
automatically but I have not implemented it (it may be beyond my lisp-fu).

>  Today 00:19  Mark Walters          ├┬►[RFC PATCH v2 1/3] cli: notmuch-show changes to support pick (notmuch)
>  Today 02:38  Daniel Schoepe        │├─► ...                                              (notmuch, signed)
>  Today 03:38  Mark Walters          │╰─► ...                                              (notmuch)
>  Today 00:19  Mark Walters          ├┬►[RFC PATCH v2 2/3] emacs: changes to other files to support notmuch-pick (notmuch)
>  Today 03:57  Mark Walters          │╰─► ...                                              (notmuch)
>  Today 00:19  Mark Walters          ├─►[RFC PATCH v2 3/3] emacs: add notmuch-pick itself  (notmuch)

I am not quite sure what this looks like (as I am not sure what is my
emacs doing things and what is what you sent. Could you send me a
screenshot (and an explanation of what is wrong if it is not clear from
the screenshot)?

Thanks

Mark

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC PATCH v3 00/11] notmuch-pick: an emacs threaded message view with split-pane
  2012-02-13  1:20 ` [RFC PATCH v3 00/11] " Mark Walters
@ 2012-02-14 12:28   ` Mark Walters
  2012-02-14 15:21     ` Austin Clements
  0 siblings, 1 reply; 26+ messages in thread
From: Mark Walters @ 2012-02-14 12:28 UTC (permalink / raw)
  To: notmuch


I have now done some benchmarking/profiling of the notmuch-pick
mode. These are all done running locally (i.e., no ssh, nfs or anything)
but on a fairly old computer with a slow hard disk. The timings given
are for the second run (so the files and database are in cache).

The profiling is done by inserting (message "%s" (current-time)) at
various points.

For displaying the thread structure of the whole notmuch mailing list
archive (circa 10,000 messages) it takes about 18 seconds which breaks
down as 6.5 seconds for the cli part, 9.5 seconds for the json parsing
in emacs and 1.5 seconds for constructing the thread structure and
writing the buffer in emacs.

Using Austin's optimised json.el (id:"20110720205007.GB21316@mit.edu")
the 9.5 seconds reduces to about 2.5 seconds (so the total reduces to
about 10.5 seconds).

I think the 6.5 seconds of command line time involves quite a lot of
parsing of the message files (to get the headers) and this could
probably be sped up by storing more of the headers in the database, or
just not outputting all of them. Removing all of the calls to
notmuch_message_get_header seems to reduce the 6.5s to about 1.5s

In other cases, though, notmuch-pick is a noticeable speed win: namely
`picking' is faster than `showing' for longer threads (as one would
expect since pick only gets the thread structure and one message body
whereas show gets the thread structure and all messages bodies). So for
a thread of 170 messages show takes 5 seconds and pick takes less than
0.5 seconds, and for a thread of 30 messages show takes 600 milliseconds
and pick takes takes 150 milliseconds.

Finally, if notmuch-pick were able to do work asynchronously (as
notmuch-search does now) then I think all the speed concerns would go
away. However, I am not sure how to do incremental json parsing.

Best wishes

Mark

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC PATCH v3 00/11] notmuch-pick: an emacs threaded message view with split-pane
  2012-02-14 12:28   ` Mark Walters
@ 2012-02-14 15:21     ` Austin Clements
  2012-02-15  9:27       ` Mark Walters
  0 siblings, 1 reply; 26+ messages in thread
From: Austin Clements @ 2012-02-14 15:21 UTC (permalink / raw)
  To: Mark Walters; +Cc: notmuch

Quoth Mark Walters on Feb 14 at 12:28 pm:
> Finally, if notmuch-pick were able to do work asynchronously (as
> notmuch-search does now) then I think all the speed concerns would go
> away. However, I am not sure how to do incremental json parsing.

For JSON search, at least, I think we've concluded that it should put
newlines at strategic places in the JSON output (and never anywhere
else) so that it's easy for a consumer to know when it has a complete
JSON object and hand it to the JSON parser.  E.g.,

[{"thread":"X", timestamp: 42, ...}
,{"thread":"Y", timestamp: 24, ...}
]

This "framed JSON" works really well for the flat output of search.
It's obviously trickier to apply to show's hierarchical output.  But,
perhaps this will inspire you.

(One possibility: we could rework show's output to be non-hierarchical
and use the above framing; that is, it could be a sequence of message
objects that each indicate which earlier message object they're a
reply to, probably restricted to DFS order.)

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC PATCH v3 00/11] notmuch-pick: an emacs threaded message view with split-pane
  2012-02-14 15:21     ` Austin Clements
@ 2012-02-15  9:27       ` Mark Walters
  0 siblings, 0 replies; 26+ messages in thread
From: Mark Walters @ 2012-02-15  9:27 UTC (permalink / raw)
  To: Austin Clements; +Cc: notmuch

[-- Attachment #1: Type: text/plain, Size: 1919 bytes --]

On Tue, 14 Feb 2012 10:21:14 -0500, Austin Clements <amdragon@MIT.EDU> wrote:
> Quoth Mark Walters on Feb 14 at 12:28 pm:
> > Finally, if notmuch-pick were able to do work asynchronously (as
> > notmuch-search does now) then I think all the speed concerns would go
> > away. However, I am not sure how to do incremental json parsing.
> 
> For JSON search, at least, I think we've concluded that it should put
> newlines at strategic places in the JSON output (and never anywhere
> else) so that it's easy for a consumer to know when it has a complete
> JSON object and hand it to the JSON parser.  E.g.,
> 
> [{"thread":"X", timestamp: 42, ...}
> ,{"thread":"Y", timestamp: 24, ...}
> ]
> 
> This "framed JSON" works really well for the flat output of search.
> It's obviously trickier to apply to show's hierarchical output.  But,
> perhaps this will inspire you.
> 
> (One possibility: we could rework show's output to be non-hierarchical
> and use the above framing; that is, it could be a sequence of message
> objects that each indicate which earlier message object they're a
> reply to, probably restricted to DFS order.)

Here is a (very early version) of an async notmuch-pick based on the
above idea. This is on top of the previous patch series. There are two
attached patches: the first is a very small patch to notmuch-show.c to
print newlines between threads (since this is sufficient framing for
notmuch-pick; obviously it does not help notmuch-show at all).

The second patch implements the async handling in notmuch-pick.el. This
is probably very inefficient, and doubtless has significant bugs, but it
seems to mostly work and does display the first page of results almost
immediately even on very large queries so I think this is the right way
to go.

I am mostly posting it so people can play with the functionality but
cleanups, bugfixes, bug reports etc are gratefully received!

Best wishes

Mark


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-cli-notmuch-show-with-framing-newlines-between-threa.patch --]
[-- Type: text/x-diff, Size: 1401 bytes --]

From 5622a3ed7b486edc360ffa764756ce76f69ac032 Mon Sep 17 00:00:00 2001
From: Mark Walters <markwalters1009@gmail.com>
Date: Tue, 14 Feb 2012 19:33:56 +0000
Subject: [PATCH 1/2] cli: notmuch-show with framing newlines between threads in JSON

Add newlines between complete threads to make asynchronous parsing
of the JSON easier
---
 notmuch-show.c |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/notmuch-show.c b/notmuch-show.c
index 3f8618b..a7cc684 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -912,6 +912,7 @@ do_show_messages (void *ctx,
     int first_set = 1;
 
     fputs (format->message_set_start, stdout);
+    fputs ("\n", stdout);
     messages = notmuch_query_search_messages (query);
 
     for (;
@@ -939,6 +940,7 @@ do_show_messages (void *ctx,
 
 	fputs (format->message_set_end, stdout);
 	fputs (format->message_set_end, stdout);
+	fputs ("\n", stdout);
     }
 
     fputs (format->message_set_end, stdout);
@@ -1029,6 +1031,7 @@ do_show (void *ctx,
     int first_toplevel = 1;
 
     fputs (format->message_set_start, stdout);
+    fputs ("\n", stdout);
 
     for (threads = notmuch_query_search_threads (query);
 	 notmuch_threads_valid (threads);
@@ -1047,6 +1050,7 @@ do_show (void *ctx,
 	first_toplevel = 0;
 
 	show_messages (ctx, format, messages, 0, params);
+	fputs ("\n", stdout);
 
 	notmuch_thread_destroy (thread);
 
-- 
1.7.2.3


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0002-emacs-a-semi-working-async-pick.patch --]
[-- Type: text/x-diff, Size: 6221 bytes --]

From c3bcd7d11b67a15a1760505c036e760e7028b125 Mon Sep 17 00:00:00 2001
From: Mark Walters <markwalters1009@gmail.com>
Date: Mon, 13 Feb 2012 23:31:45 +0000
Subject: [PATCH 2/2] emacs: a  semi-working async pick

---
 emacs/notmuch-pick.el |  111 ++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 87 insertions(+), 24 deletions(-)

diff --git a/emacs/notmuch-pick.el b/emacs/notmuch-pick.el
index 46eb720..f944d79 100644
--- a/emacs/notmuch-pick.el
+++ b/emacs/notmuch-pick.el
@@ -287,7 +287,7 @@ This command toggles the sort order for the current search."
 	(query-context notmuch-pick-query-context)
 	(buffer-name notmuch-pick-buffer-name))
     (erase-buffer)
-    (notmuch-pick-worker thread-id  query-context buffer-name)))
+    (notmuch-pick-worker thread-id  query-context (get-buffer buffer-name))))
 
 (defun notmuch-pick-toggle-view ()
   "Toggle showing threads or as isolated messages."
@@ -531,34 +531,97 @@ Complete list of currently available key bindings:
   (setq buffer-read-only t
 	truncate-lines t))
 
-(defun notmuch-pick-worker (thread-id &optional query-context buffer-name)
+(defvar notmuch-pick-process-filter-data nil
+  "Data that has not yet been processed.")
+(make-variable-buffer-local 'notmuch-pick-process-filter-data)
+
+(defun notmuch-pick-process-sentinel (proc msg)
+  "Add a message to let user know when \"notmuch pick\" exits"
+  (let ((buffer (process-buffer proc))
+	(status (process-status proc))
+	(exit-status (process-exit-status proc))
+	(never-found-target-thread nil))
+    (if (memq status '(exit signal))
+	(if (buffer-live-p buffer)
+	    (with-current-buffer buffer
+	      (save-excursion
+		(let ((inhibit-read-only t)
+		      (atbob (bobp)))
+		  (goto-char (point-max))
+		  (if (eq status 'signal)
+		      (insert "Incomplete search results (pick process was killed).\n"))
+		  (when (eq status 'exit)
+		    (if (not (string= notmuch-pick-process-filter-data "\n]"))
+			(insert (concat "Error: Unexpected output from notmuch pick:\n"
+					notmuch-pick-process-filter-data)))
+		    (insert "End of search results.")
+		    (unless (= exit-status 0)
+		      (insert (format " (process returned %d)" exit-status)))
+		    (insert "\n")))))))))
+
+(defun notmuch-pick-process-filter (proc string)
+  "Process and filter the output of \"notmuch show\" (for pick)"
+  (let ((buffer (process-buffer proc)))
+    (if (buffer-live-p buffer)
+	(with-current-buffer buffer
+	  (save-excursion
+	    (let ((line 0)
+		  (more t)
+		  (inhibit-read-only t)
+		  (string (concat notmuch-pick-process-filter-data string)))
+	      (while (string-match "\n.*\n" string)
+		(let ((frame (match-string 0 string))
+		      (frame-end (match-end 0)))
+		  (when (or (= (elt frame 1) ?\[) (= (elt frame 1) ?,))
+		    (let (json)
+		      (with-temp-buffer
+			(let ((json-object-type 'plist)
+			      (json-array-type 'list)
+			      (json-false 'nil))
+			  (insert frame)
+			  (goto-char (point-min))
+			  (search-forward "[")
+			  (backward-char)
+			  (setq json (json-read))))
+		      (goto-char (point-max))
+		      (notmuch-pick-insert-forest (list json))))
+		  (setq string (substring string (- frame-end 1)))))
+	      (setq notmuch-pick-process-filter-data string)))))))
+
+(defun notmuch-pick-worker (thread-id &optional query-context buffer)
   (interactive)
   (notmuch-pick-mode)
   (setq notmuch-pick-thread-id thread-id)
   (setq notmuch-pick-query-context query-context)
-  (setq notmuch-pick-buffer-name buffer-name)
+  (setq notmuch-pick-buffer-name (buffer-name buffer))
 
   (erase-buffer)
   (goto-char (point-min))
-  (save-excursion
-    (let* ((basic-args (list thread-id))
-	   (args (if query-context
-		     (append (list "\'") basic-args (list "and (" query-context ")\'"))
-		   (append (list "\'") basic-args (list "\'"))))
-	   (message-arg (if notmuch-pick-view-just-messages
-			    "--thread=none"
-			  "--thread=entire"))
-	   (sort-arg (if notmuch-pick-oldest-first
-			  "--sort=oldest-first"
-			"--sort=newest-first")))
-
-      (notmuch-pick-insert-forest (notmuch-query-get-threads args "--headers-only" message-arg sort-arg))
-      ;; If the query context reduced the results to nothing, run
-      ;; the basic query.
-      (when (and (eq (buffer-size) 0)
-		 query-context)
-	(notmuch-pick-insert-forest
-	 (notmuch-query-get-threads basic-args message-arg sort-arg))))))
+  (let* (args
+	 (basic-args thread-id)
+	 (search-args (concat
+		       basic-args (if query-context (concat " and (" query-context ")"))))
+	 (message-arg (if notmuch-pick-view-just-messages
+			  "--thread=none"
+			"--thread=entire"))
+	 (sort-arg (if notmuch-pick-oldest-first
+		       "--sort=oldest-first"
+		     "--sort=newest-first"))
+	 (proc (start-process
+		"notmuch-pick" buffer
+		notmuch-command "show" "--headers-only" "--format=json"
+		message-arg sort-arg search-args)))
+    (set-process-sentinel proc 'notmuch-pick-process-sentinel)
+    (set-process-filter proc 'notmuch-pick-process-filter)
+    (set-process-query-on-exit-flag proc nil)))
+;;      (notmuch-pick-insert-forest (notmuch-query-get-threads args "--headers-only" message-arg sort-arg))
+;;     (message "time3 (end forest): %s" (current-time))
+;; If the query context reduced the results to nothing, run
+;; the basic query.
+;;      (when (and (eq (buffer-size) 0)
+;;		 query-context)
+;;	(notmuch-pick-insert-forest
+;;	 (notmuch-query-get-threads basic-args message-arg sort-arg))))))
 
 (defun notmuch-pick (&optional query query-context buffer-name)
   "Run notmuch pick with the given `query' and display the results"
@@ -567,14 +630,14 @@ Complete list of currently available key bindings:
       (setq query (notmuch-read-query "Notmuch pick: ")))
   (let ((buffer (get-buffer-create (generate-new-buffer-name
 				    (or buffer-name
-					(concat "*notmuch-" query "*")))))
+					(concat "*notmuch-pick-" query "*")))))
 	(inhibit-read-only t))
 
     (switch-to-buffer buffer)
     ;; Don't track undo information for this buffer
     (set 'buffer-undo-list t)
 
-    (notmuch-pick-worker query query-context buffer-name)
+    (notmuch-pick-worker query query-context buffer)
 
     (setq truncate-lines t)))
 
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2012-02-15  9:26 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-02-12 18:49 [RFC PATCH v2 0/3] notmuch-pick: an emacs threaded message view with split-pane Mark Walters
2012-02-12 18:49 ` [RFC PATCH v2 1/3] cli: notmuch-show changes to support pick Mark Walters
2012-02-12 21:08   ` Daniel Schoepe
2012-02-12 22:08   ` Mark Walters
2012-02-12 18:49 ` [RFC PATCH v2 2/3] emacs: changes to other files to support notmuch-pick Mark Walters
2012-02-12 22:27   ` Mark Walters
2012-02-12 18:49 ` [RFC PATCH v2 3/3] emacs: add notmuch-pick itself Mark Walters
2012-02-12 20:39 ` [RFC PATCH v2 0/3] notmuch-pick: an emacs threaded message view with split-pane Jameson Graef Rollins
2012-02-12 21:51   ` Mark Walters
2012-02-13  1:20 ` [RFC PATCH v3 00/11] " Mark Walters
2012-02-14 12:28   ` Mark Walters
2012-02-14 15:21     ` Austin Clements
2012-02-15  9:27       ` Mark Walters
2012-02-13  1:20 ` [RFC PATCH v3 01/11] cli: add --headers_only option to notmuch-show.c Mark Walters
2012-02-13  1:20 ` [RFC PATCH v3 02/11] cli: add sort options " Mark Walters
2012-02-13  1:20 ` [RFC PATCH v3 03/11] cli: add --thread= option to notmuch-show Mark Walters
2012-02-13  1:20 ` [RFC PATCH v3 04/11] emacs: add entry to notmuch-pick from notmuch-hello.el Mark Walters
2012-02-13  1:20 ` [RFC PATCH v3 05/11] emacs: add defcustom group for notmuch-pick Mark Walters
2012-02-13  1:20 ` [RFC PATCH v3 06/11] emacs: add extra parameters option to notmuch-query-get-threads Mark Walters
2012-02-13  1:20 ` [RFC PATCH v3 07/11] emacs: add entry to notmuch-pick from notmuch.el Mark Walters
2012-02-13  1:20 ` [RFC PATCH v3 08/11] emacs: add the entry to notmuch-pick to notmuch-show.el Mark Walters
2012-02-13  1:20 ` [RFC PATCH v3 09/11] emacs: make notmuch-show return its buffer Mark Walters
2012-02-13  1:20 ` [RFC PATCH v3 10/11] emacs: notmuch-show.el just show the actual matching messages Mark Walters
2012-02-13  1:20 ` [RFC PATCH v3 11/11] emacs: add notmuch-pick itself Mark Walters
2012-02-13  9:05 ` [RFC PATCH v2 0/3] notmuch-pick: an emacs threaded message view with split-pane Aneesh Kumar K.V
2012-02-13 18:16   ` Mark Walters

Code repositories for project(s) associated with this public inbox

	https://yhetil.org/notmuch.git/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).