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


Hello

On irc recently dme posted a patch notmuch-pick.el which provided a
threaded message view in the emacs interface. I have added substantially
to it and made some cli changes to support it better. See
http://kanelephant.com/screen.png for a screenshot.

It seems to be working well (although doubtless has bugs and lots of
room for improvement).

One important caveat is that it does call notmuch-show rather than
notmuch-search so it can be slow. Viewing 10000 notmuch messages takes
me 20 seconds with a warm cache and about a minute with a cold
cache. Viewing million message searches in this fashion is not
recommended! 

Note since I modify the notmuch-show.c backend this applies on top of
Jani's show parsing patches id:"cover.1328558175.git.jani@nikula.org"

The most important key bindings are as follows:

'z' enter a search to display in pick view (analogous to s; works in
hello, search, show and pick mode).

'Z' displays the current search in pick mode (works in search and show
mode)

In pick mode: RET displays a message (splitting the current window),
SPACE scrolls the message window and goes to next message when it
reaches the end, 'b' scrolls the message window back, 'p', 'n' move to
the next matching message, 'q' closes the message window (if open) or
quits the pick view.

't' toggles whether to show the messages as a thread-tree structure or
just as single messages, 'o' toggles the sort order. 

Most of the other commands I could think of work as I would expect (eg
tagging, piping, help etc)

Questions/thoughts and known bugs:

Do people like the rough idea? 

At the moment there is some shared code with notmuch-show.el. This could
be factored out: however, while this pick mode is WIP I don't think it
is worth it. I have tried to keep the impact on the current parts of the
emacs code and the command line interface fairly small.

I will send the patches as 3 bits: one is the command-line support
needed (i.e. changes to notmuch-show.c) one is the changes to the other
emacs files and the final one is the notmuch-pick.el file itself.

There are some things that need fixing: some of which are marked in the
code. For example the highlighting (lowlighting?) of non-matching
messages is hard-wired gray and should be a defcustom. The tags are not
in a nice tag face and do not update automatically. There should be an
option not to use the split-screen mode.

Anyway I am already finding it useful: show a long thread, press 'Z' to
see the thread structure nicely and then ...

Best wishes

Mark

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

* [RFC PATCH 1/3] cli: notmuch-show changes to support pick
  2012-02-12 10:32 RFC notmuch-pick: an emacs threaded message view with split-pane Mark Walters
@ 2012-02-12 10:36 ` Mark Walters
  2012-02-12 10:36 ` [RFC PATCH 2/3] emacs: changes to other files to support notmuch-pick Mark Walters
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 11+ messages in thread
From: Mark Walters @ 2012-02-12 10:36 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 c8fbd79..725d47d 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -876,7 +876,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) {
@@ -923,11 +923,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);
 
@@ -937,6 +942,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,
@@ -1064,11 +1113,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',
@@ -1077,10 +1128,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 }
     };
 
@@ -1090,6 +1150,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)
@@ -1101,7 +1164,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;
@@ -1168,10 +1233,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] 11+ messages in thread

* [RFC PATCH 2/3] emacs: changes to other files to support notmuch-pick
  2012-02-12 10:32 RFC notmuch-pick: an emacs threaded message view with split-pane Mark Walters
  2012-02-12 10:36 ` [RFC PATCH 1/3] cli: notmuch-show changes to support pick Mark Walters
@ 2012-02-12 10:36 ` Mark Walters
  2012-02-12 10:36 ` [RFC PATCH 3/3] emacs: add notmuch-pick itself Mark Walters
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 11+ messages in thread
From: Mark Walters @ 2012-02-12 10:36 UTC (permalink / raw)
  To: notmuch

---
 emacs/Makefile.local   |    3 ++-
 emacs/notmuch-hello.el |   10 ++++++++++
 emacs/notmuch-query.el |    4 +++-
 emacs/notmuch-show.el  |   19 +++++++++++++++----
 emacs/notmuch.el       |    8 ++++++++
 5 files changed, 38 insertions(+), 6 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-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 24fde05..825f7fe 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.
@@ -962,7 +963,7 @@ a corresponding notmuch search."
 			'face goto-address-mail-face))))
 
 ;;;###autoload
-(defun notmuch-show (thread-id &optional parent-buffer query-context buffer-name crypto-switch)
+(defun notmuch-show (thread-id &optional parent-buffer query-context buffer-name crypto-switch just-matches)
   "Run \"notmuch show\" with the given thread ID and display results.
 
 The optional PARENT-BUFFER is the notmuch-search buffer from
@@ -986,9 +987,9 @@ buffer."
   (let* ((process-crypto (if crypto-switch
 			     (not notmuch-crypto-process-mime)
 			   notmuch-crypto-process-mime)))
-    (notmuch-show-worker thread-id parent-buffer query-context buffer-name process-crypto)))
+    (notmuch-show-worker thread-id parent-buffer query-context buffer-name process-crypto just-matches)))
 
-(defun notmuch-show-worker (thread-id parent-buffer query-context buffer-name process-crypto)
+(defun notmuch-show-worker (thread-id parent-buffer query-context buffer-name process-crypto &optional just-matches)
   (let* ((buffer-name (generate-new-buffer-name
 		       (or buffer-name
 			   (concat "*notmuch-" thread-id "*"))))
@@ -1012,6 +1013,8 @@ buffer."
 	     (args (if query-context
 		       (append (list "\'") basic-args (list "and (" query-context ")\'"))
 		     (append (list "\'") basic-args (list "\'")))))
+	(if 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.
@@ -1031,7 +1034,8 @@ buffer."
     ;; Set the header line to the subject of the first open message.
     (setq header-line-format (notmuch-show-strip-re (notmuch-show-get-pretty-subject)))
 
-    (notmuch-show-mark-read)))
+    (notmuch-show-mark-read)
+    buffer))
 
 (defun notmuch-show-refresh-view (&optional crypto-switch)
   "Refresh the current view (with crypto switch if prefix given).
@@ -1073,6 +1077,8 @@ thread id.  If a prefix is given, crypto processing is toggled."
 	(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)
@@ -1476,6 +1482,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 8250961..e95842e 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] 11+ messages in thread

* [RFC PATCH 3/3] emacs: add notmuch-pick itself
  2012-02-12 10:32 RFC notmuch-pick: an emacs threaded message view with split-pane Mark Walters
  2012-02-12 10:36 ` [RFC PATCH 1/3] cli: notmuch-show changes to support pick Mark Walters
  2012-02-12 10:36 ` [RFC PATCH 2/3] emacs: changes to other files to support notmuch-pick Mark Walters
@ 2012-02-12 10:36 ` Mark Walters
       [not found] ` <87ehu0cf16.fsf@schoepe.localhost>
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 11+ messages in thread
From: Mark Walters @ 2012-02-12 10:36 UTC (permalink / raw)
  To: notmuch

---
 emacs/notmuch-pick.el |  570 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 570 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..4c91d7c
--- /dev/null
+++ b/emacs/notmuch-pick.el
@@ -0,0 +1,570 @@
+;; 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."
+  :group 'notmuch
+  :type 'int)
+
+(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 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)))
+	 ;; Face should be a defcustom or something MJW
+	 (message-face (if match
+			   '(:foreground "black")
+		       '(:foreground "gray"))))
+
+    (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] 11+ messages in thread

* Re: RFC notmuch-pick: an emacs threaded message view with split-pane
       [not found] ` <87ehu0cf16.fsf@schoepe.localhost>
@ 2012-02-12 14:31   ` Daniel Schoepe
  0 siblings, 0 replies; 11+ messages in thread
From: Daniel Schoepe @ 2012-02-12 14:31 UTC (permalink / raw)
  To: notmuch

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

Forgot to reply to the list....

On Sun, 12 Feb 2012 10:32:48 +0000, Mark Walters <markwalters1009@gmail.com> wrote:
> Questions/thoughts and known bugs:
> 
> Do people like the rough idea? 

I think it's a great idea. What I find especially nice about this, is
that it works for both, just showing the structure of one thread and the
traditional all-messages-matching-a-search view. I've actually rebound
<return> in notmuch-search to this and it works great so far:

(defun notmuch-search-pick ()
  "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))

> At the moment there is some shared code with notmuch-show.el. This could
> be factored out: however, while this pick mode is WIP I don't think it
> is worth it. I have tried to keep the impact on the current parts of the
> emacs code and the command line interface fairly small.
> 
> I will send the patches as 3 bits: one is the command-line support
> needed (i.e. changes to notmuch-show.c) one is the changes to the other
> emacs files and the final one is the notmuch-pick.el file itself.
> 
> There are some things that need fixing: some of which are marked in the
> code. For example the highlighting (lowlighting?) of non-matching
> messages is hard-wired gray and should be a defcustom. The tags are not
> in a nice tag face and do not update automatically. There should be an
> option not to use the split-screen mode.

Yeah, the hardcoded "black" is also pretty annoying if one uses a
black background. :)
I'll send a patch fixing that later.

> Anyway I am already finding it useful: show a long thread, press 'Z' to
> see the thread structure nicely and then ...

Yeah, that's basically my main use case, as I don't like dozens of
messages of the same thread cluttering up all the search results
(e.g. for tag:notmuch).

Thanks for the great work David and Mark, I've really been looking
forward to something that makes my half-baked attempt at thread
outlining [1] obsolete. :)

[1] id:"1324082126-25404-1-git-send-email-daniel@schoepe.org"

Cheers,
Daniel

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

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

* [PATCH 0/1] emacs: Make highlight-faces for pick configurable
  2012-02-12 10:32 RFC notmuch-pick: an emacs threaded message view with split-pane Mark Walters
                   ` (3 preceding siblings ...)
       [not found] ` <87ehu0cf16.fsf@schoepe.localhost>
@ 2012-02-12 14:47 ` Daniel Schoepe
  2012-02-12 14:47   ` [PATCH] " Daniel Schoepe
  2012-02-12 20:46 ` RFC notmuch-pick: an emacs threaded message view with split-pane Jameson Graef Rollins
  5 siblings, 1 reply; 11+ messages in thread
From: Daniel Schoepe @ 2012-02-12 14:47 UTC (permalink / raw)
  To: notmuch

This makes the faces notmuch-pick uses for high/"low"lighting configurable.
Obviously, this requires the rest of the patch series from this thread.

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

* [PATCH] emacs: Make highlight-faces for pick configurable
  2012-02-12 14:47 ` [PATCH 0/1] emacs: Make highlight-faces for pick configurable Daniel Schoepe
@ 2012-02-12 14:47   ` Daniel Schoepe
  2012-02-12 15:50     ` Mark Walters
  0 siblings, 1 reply; 11+ messages in thread
From: Daniel Schoepe @ 2012-02-12 14:47 UTC (permalink / raw)
  To: notmuch

---
 emacs/notmuch-pick.el |   21 ++++++++++++++++++---
 1 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/emacs/notmuch-pick.el b/emacs/notmuch-pick.el
index 4c91d7c..2bf1ae4 100644
--- a/emacs/notmuch-pick.el
+++ b/emacs/notmuch-pick.el
@@ -42,6 +42,22 @@
   :group 'notmuch
   :type 'int)
 
+(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)
+
+(defface notmuch-pick-no-match-face
+  '((t (:foreground "gray")))
+  "Face used in pick mode for messages not matching the query."
+  :group 'notmuch)
+
 (defvar notmuch-pick-previous-subject "")
 (make-variable-buffer-local 'notmuch-pick-previous-subject)
 
@@ -415,10 +431,9 @@ unchanged ADDRESS if parsing fails."
 	 (match (plist-get msg :match))
 	 (tags (plist-get msg :tags))
 	 (bare-subject (notmuch-show-strip-re (plist-get headers :Subject)))
-	 ;; Face should be a defcustom or something MJW
 	 (message-face (if match
-			   '(:foreground "black")
-		       '(:foreground "gray"))))
+			   'notmuch-pick-match-face
+			 'notmuch-pick-no-match-face)))
 
     (insert (propertize (concat
 			 (notmuch-pick-string-width
-- 
1.7.9

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

* Re: [PATCH] emacs: Make highlight-faces for pick configurable
  2012-02-12 14:47   ` [PATCH] " Daniel Schoepe
@ 2012-02-12 15:50     ` Mark Walters
  0 siblings, 0 replies; 11+ messages in thread
From: Mark Walters @ 2012-02-12 15:50 UTC (permalink / raw)
  To: Daniel Schoepe, notmuch

On Sun, 12 Feb 2012 15:47:18 +0100, Daniel Schoepe <daniel@schoepe.org> wrote:
> ---
>  emacs/notmuch-pick.el |   21 ++++++++++++++++++---
>  1 files changed, 18 insertions(+), 3 deletions(-)
> 
> diff --git a/emacs/notmuch-pick.el b/emacs/notmuch-pick.el
> index 4c91d7c..2bf1ae4 100644
> --- a/emacs/notmuch-pick.el
> +++ b/emacs/notmuch-pick.el
> @@ -42,6 +42,22 @@
>    :group 'notmuch
>    :type 'int)
>  
> +(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)
> +
> +(defface notmuch-pick-no-match-face
> +  '((t (:foreground "gray")))
> +  "Face used in pick mode for messages not matching the query."
> +  :group 'notmuch)
> +
>  (defvar notmuch-pick-previous-subject "")
>  (make-variable-buffer-local 'notmuch-pick-previous-subject)
>  
> @@ -415,10 +431,9 @@ unchanged ADDRESS if parsing fails."
>  	 (match (plist-get msg :match))
>  	 (tags (plist-get msg :tags))
>  	 (bare-subject (notmuch-show-strip-re (plist-get headers :Subject)))
> -	 ;; Face should be a defcustom or something MJW
>  	 (message-face (if match
> -			   '(:foreground "black")
> -		       '(:foreground "gray"))))
> +			   'notmuch-pick-match-face
> +			 'notmuch-pick-no-match-face)))
>  
>      (insert (propertize (concat
>  			 (notmuch-pick-string-width

This is great. (I had even thought about the hardwired gray: that should
work on both light and dark backgrounds but had forgotten all about the
"black").

Anyway this is the correct fix: thanks!

Mark

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

* Re: RFC notmuch-pick: an emacs threaded message view with split-pane
  2012-02-12 10:32 RFC notmuch-pick: an emacs threaded message view with split-pane Mark Walters
                   ` (4 preceding siblings ...)
  2012-02-12 14:47 ` [PATCH 0/1] emacs: Make highlight-faces for pick configurable Daniel Schoepe
@ 2012-02-12 20:46 ` Jameson Graef Rollins
  2012-02-12 20:59   ` Daniel Schoepe
  5 siblings, 1 reply; 11+ messages in thread
From: Jameson Graef Rollins @ 2012-02-12 20:46 UTC (permalink / raw)
  To: Mark Walters, notmuch

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

On Sun, 12 Feb 2012 10:32:48 +0000, Mark Walters <markwalters1009@gmail.com> wrote:
> On irc recently dme posted a patch notmuch-pick.el which provided a
> threaded message view in the emacs interface. I have added substantially
> to it and made some cli changes to support it better. See
> http://kanelephant.com/screen.png for a screenshot.
> 
> It seems to be working well (although doubtless has bugs and lots of
> room for improvement).
> 
> One important caveat is that it does call notmuch-show rather than
> notmuch-search so it can be slow. Viewing 10000 notmuch messages takes
> me 20 seconds with a warm cache and about a minute with a cold
> cache. Viewing million message searches in this fashion is not
> recommended! 

Hey, Mark.  I really like the idea, since I've been looking for
something like this for a while, but there's something I'm confused
about.  Is this meant to replace notmuch-search, or notmuch-show?  I had
been hoping for a notmuch *show* replacement that shows the nice tree
view for the thread, with a single message view below.  But it sounds
like you're meant to be replacing notmuch search?  That seems confusing
to me, particularly in light of the big performance hit you describe.

I'll wait for some further explanation before I jump into a full review.

jamie.

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

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

* Re: RFC notmuch-pick: an emacs threaded message view with split-pane
  2012-02-12 20:46 ` RFC notmuch-pick: an emacs threaded message view with split-pane Jameson Graef Rollins
@ 2012-02-12 20:59   ` Daniel Schoepe
  2012-02-12 21:43     ` Mark Walters
  0 siblings, 1 reply; 11+ messages in thread
From: Daniel Schoepe @ 2012-02-12 20:59 UTC (permalink / raw)
  To: Jameson Graef Rollins, Mark Walters, notmuch

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

On Sun, 12 Feb 2012 12:46:36 -0800, Jameson Graef Rollins <jrollins@finestructure.net> wrote:
> Hey, Mark.  I really like the idea, since I've been looking for
> something like this for a while, but there's something I'm confused
> about.  Is this meant to replace notmuch-search, or notmuch-show?  I had
> been hoping for a notmuch *show* replacement that shows the nice tree
> view for the thread, with a single message view below.  But it sounds
> like you're meant to be replacing notmuch search?  That seems confusing
> to me, particularly in light of the big performance hit you describe.

As far as I can tell, it is intended as a third option and can be used
for both, viewing all messages matching a search in a tree structure
(with a pane for an individual message) as in most other mail clients
(mutt, thunderbird, Gnus, etc.) and viewing a single thread in the
manner you described.

This has the added bonus, that it can be offered _in addition_ to show
in search, since I wouldn't want to give up the current
search-view. notmuch-show might also be preferred by some users (due to
its similarity to sup and gmail). Of course, this would mean that we
would have to maintain threading capabilities for two modes. (It relies
on show for displaying a single message, so that part is not
duplicated).

Cheers,
Daniel

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

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

* Re: RFC notmuch-pick: an emacs threaded message view with split-pane
  2012-02-12 20:59   ` Daniel Schoepe
@ 2012-02-12 21:43     ` Mark Walters
  0 siblings, 0 replies; 11+ messages in thread
From: Mark Walters @ 2012-02-12 21:43 UTC (permalink / raw)
  To: Daniel Schoepe, Jameson Graef Rollins, notmuch


On Sun, 12 Feb 2012 21:59:39 +0100, Daniel Schoepe <daniel@schoepe.org> wrote:
> On Sun, 12 Feb 2012 12:46:36 -0800, Jameson Graef Rollins <jrollins@finestructure.net> wrote:
> > Hey, Mark.  I really like the idea, since I've been looking for
> > something like this for a while, but there's something I'm confused
> > about.  Is this meant to replace notmuch-search, or notmuch-show?  I had
> > been hoping for a notmuch *show* replacement that shows the nice tree
> > view for the thread, with a single message view below.  But it sounds
> > like you're meant to be replacing notmuch search?  That seems confusing
> > to me, particularly in light of the big performance hit you describe.
> 
> As far as I can tell, it is intended as a third option and can be used
> for both, viewing all messages matching a search in a tree structure
> (with a pane for an individual message) as in most other mail clients
> (mutt, thunderbird, Gnus, etc.) and viewing a single thread in the
> manner you described.
> 
> This has the added bonus, that it can be offered _in addition_ to show
> in search, since I wouldn't want to give up the current
> search-view. notmuch-show might also be preferred by some users (due to
> its similarity to sup and gmail). Of course, this would mean that we
> would have to maintain threading capabilities for two modes. (It relies
> on show for displaying a single message, so that part is not
> duplicated).

This is exactly my view: it comes somewhere between search and show. I
use it both ways: as a view for my inbox (i.e., as a replacement for
search) and when I get lost "showing" a long thread. 

I haven't tried Daniel's suggestion of notmuch-search-pick (going from a
thread to the pick view of that thread). But I will add it as an option.

Best wishes

Mark

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

end of thread, other threads:[~2012-02-12 21:42 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-02-12 10:32 RFC notmuch-pick: an emacs threaded message view with split-pane Mark Walters
2012-02-12 10:36 ` [RFC PATCH 1/3] cli: notmuch-show changes to support pick Mark Walters
2012-02-12 10:36 ` [RFC PATCH 2/3] emacs: changes to other files to support notmuch-pick Mark Walters
2012-02-12 10:36 ` [RFC PATCH 3/3] emacs: add notmuch-pick itself Mark Walters
     [not found] ` <87ehu0cf16.fsf@schoepe.localhost>
2012-02-12 14:31   ` RFC notmuch-pick: an emacs threaded message view with split-pane Daniel Schoepe
2012-02-12 14:47 ` [PATCH 0/1] emacs: Make highlight-faces for pick configurable Daniel Schoepe
2012-02-12 14:47   ` [PATCH] " Daniel Schoepe
2012-02-12 15:50     ` Mark Walters
2012-02-12 20:46 ` RFC notmuch-pick: an emacs threaded message view with split-pane Jameson Graef Rollins
2012-02-12 20:59   ` Daniel Schoepe
2012-02-12 21:43     ` 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).