[PATCH 0/2] emacs: User-defined sections in notmuch-hello

Michal Sojka sojkam1 at fel.cvut.cz
Mon Jul 4 17:00:33 PDT 2011


On Wed, 29 Jun 2011, Daniel Schoepe wrote:
> Unfortunately the customize-interface for more customized entries in
> notmuch-hello-sections looks a bit weird, but I couldn't figure out how
> to get rid of the empty lines produced by generating the lambda expression
> needed.

Hi Daniel,

this looks really great and it comes at the right time for me. I can use
it for creating a custom section "What's in your inbox" - a
functionality which I previously implemented in my personal branch [*]
but I was unable to rebase it on the current HEAD. Basically, it took
all saved searches and tag searches, filtered them with tag:inbox and
displayed the buttons for those searches.

With your patch it is "quite easy" to implement such a functionality.
There are a few problems, though.

First, the customization interface for the custom sections (not the
predefined ones) is very confusing. I was not able to use it at all.
Instead I hacked the source code (see below) to add my section to the
notmuch-hello-sections list.

Second, when I tried to understand your patch, I found some names of
functions and variables quite confusing. In the patch below, I tried to
give them a better names and I also updated the documentation. Feel free
to use my changes for your later patch submission.

And last but not least, you allow quite wild modifications of tag
searches (e.g. in notmuch-hello-generate-tag-alist), but is might be
also useful to use such modifications for other searches. For example, I
want to modify the saved searches in a similar way.
 
> To avoid unnecessary complexity in the code this patch removes
> aligning all the tag entries in different sections (e.g. saved
> searches and all tags) the same way. So if someone really thinks this
> was an important features, please yell loudly.

I do not miss this at all.

And here are my changes to your patch, which you might use as a
suggestions for a next version of your patch. As I wrote above, it
renames some functions and variables to more understandable names,
updates documentation and adds a custom section for my personal use (I
can live with this custom section in my .emacs if others do not like
it).

Cheers,
-Michal

diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
index e4c9307..226024c 100644
--- a/emacs/notmuch-hello.el
+++ b/emacs/notmuch-hello.el
@@ -124,6 +124,7 @@ Typically \",\" in the US and UK and \".\" in Europe."
 
 (defcustom notmuch-hello-sections
   (list #'notmuch-hello-insert-header
+	#'notmuch-hello-insert-inbox
 	#'notmuch-hello-insert-saved-searches
 	#'notmuch-hello-insert-search
 	#'notmuch-hello-insert-recent-searches
@@ -205,8 +206,8 @@ in the order they appear in this list."
     (message "Saved '%s' as '%s'." search name)
     (notmuch-hello-update)))
 
-(defun notmuch-hello-longest-label (tag-alist)
-  (or (loop for elem in tag-alist
+(defun notmuch-hello-longest-label (searches-alist)
+  (or (loop for elem in searches-alist
 	    maximize (length (car elem)))
       0))
 
@@ -270,11 +271,18 @@ should be. Returns a cons cell `(tags-per-line width)'."
 				   (* tags-per-line (+ 9 1))))
 			   tags-per-line))))
 
-(defun notmuch-hello-query-entries (tag-alist &optional hide-empty)
-  "Compute list of counts and queries for TAG-ALIST.
+(defun notmuch-hello-query-counts (query-alist &optional hide-empty)
+  "Compute list of counts of matched messages from QUERY-ALIST.
 
-If HIDE-EMPTY is non-nil, entries with no matching messages will be
-removed from the result."
+QUERY-ALIST must be a list containing elements of the form (NAME . QUERY)
+or (NAME QUERY COUNT-QUERY). If the latter form is used,
+COUNT-QUERY specifies an alternate query to be used to generate
+the count for the associated query.
+
+The result is the list of elements of the form (NAME QUERY COUNT).
+
+If HIDE-EMPTY is non-nil, searches with no matching messages
+(COUNT equal to zero) will be removed from the result."
   (notmuch-remove-if-not
    #'identity
    (mapcar
@@ -289,21 +297,21 @@ removed from the result."
 				 (cdr query-and-count)))))
 	(and (or (not hide-empty) (> message-count 0))
 	   (list name (car query-and-count) message-count))))
-    tag-alist)))
+    query-alist)))
 
-(defun notmuch-hello-insert-tags (entries)
-  "Insert query items from ENTRIES.
+(defun notmuch-hello-insert-buttons (searches)
+  "Insert buttons for SEARCHES.
 
-ENTRIES must be a list containing lists of the form (NAME QUERY COUNT), where
+SEARCHES must be a list containing lists of the form (NAME QUERY COUNT), where
 QUERY is the query to start when the button for the corresponding entry is
 activated. COUNT should be the number of messages matching the query.
-Such a list can be computed with `notmuch-hello-query-entries'."
-  (let* ((widest (notmuch-hello-longest-label entries))
+Such a list can be computed with `notmuch-hello-query-counts'."
+  (let* ((widest (notmuch-hello-longest-label searches))
 	 (tags-and-width (notmuch-hello-tags-per-line widest))
 	 (tags-per-line (car tags-and-width))
 	 (widest (cdr tags-and-width))
 	 (count 0)
-	 (reordered-list (notmuch-hello-reflect entries tags-per-line))
+	 (reordered-list (notmuch-hello-reflect searches tags-per-line))
 	 ;; Hack the display of the buttons used.
 	 (widget-push-button-prefix "")
 	 (widget-push-button-suffix "")
@@ -337,7 +345,7 @@ Such a list can be computed with `notmuch-hello-query-entries'."
 	    (setq count (1+ count))
 	    (if (eq (% count tags-per-line) 0)
 		(widget-insert "\n")))
-	  entries)
+	  searches)
 
     ;; If the last line was not full (and hence did not include a
     ;; carriage return), insert one now.
@@ -398,26 +406,36 @@ Complete list of currently available key bindings:
   ;;(setq buffer-read-only t)
   )
 
-(defun notmuch-hello-make-query (tag make-query)
+(defun notmuch-hello-make-tag-query (tag filter)
+  "Constructs a query to search all messages tagged by TAG and
+matching FILTER.
+
+If FILTER is a string, it is directly used in the returned query.
+
+If FILTER is a function, it is called with TAG as a parameter and
+the string it returns is used as the filter.
+
+Finally, if FILTER is `t' it is ignored.
+"
   (cond
-   ((functionp make-query)
-    (let ((result (funcall make-query tag)))
+   ((functionp filter)
+    (let ((result (funcall filter tag)))
       (and result (concat "tag:" tag " and (" result ")"))))
-   ((stringp make-query)
-    (concat "tag:" tag " and (" make-query ")"))
+   ((stringp filter)
+    (concat "tag:" tag " and (" filter ")"))
    (t (concat "tag:" tag))))
 
-(defun notmuch-hello-generate-tag-alist (&optional hide-tags make-query make-count)
+(defun notmuch-hello-generate-tag-alist (&optional hide-tags filter-query filter-count)
   "Return an alist from tags to queries to display in the all-tags section."
   (notmuch-remove-if-not
    #'identity
    (mapcar (lambda (tag)
-	     (let ((query (notmuch-hello-make-query tag make-query)))
+	     (let ((query (notmuch-hello-make-tag-query tag filter-query)))
 	       (when query
-		 (if make-count
-		     (list tag (notmuch-hello-make-query tag make-query)
-			   (notmuch-hello-make-query tag make-count))
-		   (cons tag (notmuch-hello-make-query tag make-query))))))
+		 (if filter-count
+		     (list tag (notmuch-hello-make-tag-query tag filter-query)
+			   (notmuch-hello-make-tag-query tag filter-count))
+		   (cons tag (notmuch-hello-make-tag-query tag filter-query))))))
 	   (notmuch-remove-if-not
 	    (lambda (tag)
 	      (not (member tag hide-tags)))
@@ -462,11 +480,11 @@ Complete list of currently available key bindings:
 
 (defun notmuch-hello-insert-saved-searches ()
   "Insert the saved-searches section."
-  (let ((entries (notmuch-hello-query-entries
+  (let ((searches (notmuch-hello-query-counts
 		  notmuch-saved-searches
 		  (not notmuch-show-empty-saved-searches)))
 	found-target-pos final-target-pos)
-    (when entries
+    (when searches
       (widget-insert "\nSaved searches: ")
       (widget-create 'push-button
 		     :notify (lambda (&rest ignore)
@@ -476,7 +494,7 @@ Complete list of currently available key bindings:
       (setq final-target-pos (point-marker))
       (let ((start (point)))
 	(setq found-target-pos
-	      (notmuch-hello-insert-tags entries))
+	      (notmuch-hello-insert-buttons searches))
 	(if found-target-pos
 	    (setq final-target-pos found-target-pos))
 	(indent-rigidly start (point) notmuch-hello-indent)
@@ -539,19 +557,19 @@ Complete list of currently available key bindings:
 	    notmuch-hello-recent-searches)
       (indent-rigidly start (point) notmuch-hello-indent))))
 
-(defun notmuch-hello-insert-query-list (title query-alist &rest options)
-  "Insert a section with TITLE showing tags from QUERY-ALIST.
-
-Supports the following entries in OPTIONS as a plist:
-:initially-hidden - if non-nil, section will be hidden on startup
-:hide-empty-tags - hide entries with no matching messages
-:hide-if-empty - hide if no entries would be shown
-   (only makes sense with :hide-empty-tags)
+(defun notmuch-hello-insert-searches (title query-alist &rest options)
+  "Insert a section with TITLE showing a list of buttons made from QUERY-ALIST.
 
 QUERY-ALIST must be a list containing elements of the form (NAME . QUERY)
 or (NAME QUERY COUNT-QUERY). If the latter form is used,
 COUNT-QUERY specifies an alternate query to be used to generate
-the count for the associated tag."
+the count for the associated tag.
+
+Supports the following entries in OPTIONS as a plist:
+:initially-hidden - if non-nil, section will be hidden on startup
+:hide-empty-searches - hide buttons with no matching messages
+:hide-if-empty - hide if no buttons would be shown
+   (only makes sense with :hide-empty-searches)"
   (widget-insert title)
   (if (and notmuch-hello-first-run (plist-get options :initially-hidden))
       (add-to-list 'notmuch-hello-hidden-sections title))
@@ -572,21 +590,21 @@ the count for the associated tag."
 		     "hide"))
     (widget-insert "\n")
     (let (target-pos
-	  (entries (notmuch-hello-query-entries
-		    query-alist (plist-get options :hide-empty-tags))))
+	  (searches (notmuch-hello-query-counts
+		    query-alist (plist-get options :hide-empty-searches))))
       (when (and (not is-hidden)
 	       (or (not (plist-get options :hide-if-empty))
-		  entries))
+		  searches))
 	(widget-insert "\n")
 	(setq target-pos
-	      (notmuch-hello-insert-tags entries))
+	      (notmuch-hello=-insert-buttons searches))
 	(indent-rigidly start (point) notmuch-hello-indent)
 	target-pos))))
 
 (defun notmuch-hello-insert-tags-section (&rest options)
   "Insert a section displaying all tags and message counts for each.
 
-Allowed options are those accepted by `notmuch-hello-insert-query-list' and the
+Allowed options are those accepted by `notmuch-hello-insert-searches' and the
 following:
 
 :title - Title for this section, defaults to \"All tags: \"
@@ -596,7 +614,7 @@ following:
 :make-count - Seperate query to generate the count that should be displayed for each
     tag. Accepts the same values as :make-query
 :hide-tags - List of tags that should be excluded."
-  (apply 'notmuch-hello-insert-query-list
+  (apply 'notmuch-hello-insert-searches
 	 (or (plist-get options :title) "All tags: ")
 	 (notmuch-hello-generate-tag-alist
 	  (plist-get options :hide-tags)
@@ -604,6 +622,15 @@ following:
 	  (plist-get options :make-count))
 	 options))
 
+(defun notmuch-hello-insert-inbox ()
+  (notmuch-hello-insert-searches "What's in your inbox: "
+				 (mapcar (lambda (elem)
+					   (cons (car elem) (concat "tag:inbox and (" (cdr elem) ")")))
+					 (append
+					  (notmuch-saved-searches)
+					  (notmuch-hello-generate-tag-alist)))
+				 :hide-empty-searches t))
+
 (defun notmuch-hello-insert-alltags ()
   "Insert a section displaying all tags and associated message counts"
   (notmuch-hello-insert-tags-section :initially-hidden
-- 
1.7.5.4



Footnotes:

[*] id:"1275633449-17134-1-git-send-email-sojkam1 at fel.cvut.cz"


More information about the notmuch mailing list