]> git.notmuchmail.org Git - notmuch/blobdiff - emacs/notmuch-hello.el
emacs: hello: use batch count
[notmuch] / emacs / notmuch-hello.el
index 28f39f19a8cb4724642e51b522d2b64282139510..cda79f1dde695aabadd5f80f49f22d07af22b737 100644 (file)
@@ -41,7 +41,7 @@
 
 (defun notmuch-sort-saved-searches (alist)
   "Generate an alphabetically sorted saved searches alist."
-  (sort alist (lambda (a b) (string< (car a) (car b)))))
+  (sort (copy-sequence alist) (lambda (a b) (string< (car a) (car b)))))
 
 (defcustom notmuch-saved-search-sort-function nil
   "Function used to sort the saved searches for the notmuch-hello view.
@@ -154,11 +154,6 @@ International Bureau of Weights and Measures."
 (defvar notmuch-hello-url "http://notmuchmail.org"
   "The `notmuch' web site.")
 
-(defvar notmuch-hello-search-pos nil
-  "Position of search widget, if any.
-
-This should only be set by `notmuch-hello-insert-search'.")
-
 (defvar notmuch-hello-custom-section-options
   '((:filter (string :tag "Filter for each tag"))
     (:filter-count (string :tag "Different filter to generate message counts"))
@@ -187,7 +182,7 @@ This should only be set by `notmuch-hello-insert-search'.")
   :tag "Customized queries section (see docstring for details)"
   :type
   `(list :tag ""
-        (const :tag "" notmuch-hello-insert-query-list)
+        (const :tag "" notmuch-hello-insert-searches)
         (string :tag "Title for this section")
         (repeat :tag "Queries"
                 (cons (string :tag "Name") (string :tag "Query")))
@@ -209,11 +204,8 @@ function produces a section simply by adding content to the current
 buffer.  A section should not end with an empty line, because a
 newline will be inserted after each section by `notmuch-hello'.
 
-Each function should take no arguments.  If the produced section
-includes `notmuch-hello-target' (i.e. cursor should be positioned
-inside this section), the function should return this element's
-position.
-Otherwise, it should return nil.
+Each function should take no arguments. The return value is
+ignored.
 
 For convenience an element can also be a list of the form (FUNC ARG1
 ARG2 .. ARGN) in which case FUNC will be applied to the rest of the
@@ -226,7 +218,7 @@ by an additional filter query. Similarly, the count of messages
 displayed next to the buttons can be generated by applying a
 different filter to the tag query. These filters are also
 supported for \"Customized queries section\" items."
-  :group 'notmuch
+  :group 'notmuch-hello
   :type
   '(repeat
     (choice (function-item notmuch-hello-insert-header)
@@ -240,15 +232,6 @@ supported for \"Customized queries section\" items."
            notmuch-hello-query-section
            (function :tag "Custom section"))))
 
-(defvar notmuch-hello-target nil
-  "Button text at position of point before rebuilding the notmuch-buffer.
-
-This variable contains the text of the button, if any, the
-point was positioned at before the notmuch-hello buffer was
-rebuilt. This should never actually be global and is defined as a
-defvar only for documentation purposes and to avoid a compiler
-warning about it occurring as a free variable.")
-
 (defvar notmuch-hello-hidden-sections nil
   "List of sections titles whose contents are hidden")
 
@@ -398,26 +381,38 @@ The result is the list of elements of the form (NAME QUERY COUNT).
 The values :show-empty-searches, :filter and :filter-count from
 options will be handled as specified for
 `notmuch-hello-insert-searches'."
-  (notmuch-remove-if-not
-   #'identity
-   (mapcar
-    (lambda (elem)
-      (let* ((name (car elem))
-            (query-and-count (if (consp (cdr elem))
-                                 ;; do we have a different query for the message count?
-                                 (cons (second elem) (third elem))
-                               (cons (cdr elem) (cdr elem))))
-            (message-count
-             (string-to-number
-              (notmuch-saved-search-count
-               (notmuch-hello-filtered-query (cdr query-and-count)
-                                             (or (plist-get options :filter-count)
-                                                (plist-get options :filter)))))))
-       (and (or (plist-get options :show-empty-searches) (> message-count 0))
-            (list name (notmuch-hello-filtered-query
-                        (car query-and-count) (plist-get options :filter))
-                  message-count))))
-    query-alist)))
+  (with-temp-buffer
+    (dolist (elem query-alist nil)
+      (let ((count-query (if (consp (cdr elem))
+                            ;; do we have a different query for the message count?
+                            (third elem)
+                          (cdr elem))))
+       (insert
+        (notmuch-hello-filtered-query count-query
+                                      (or (plist-get options :filter-count)
+                                          (plist-get options :filter)))
+        "\n")))
+
+    (call-process-region (point-min) (point-max) notmuch-command
+                        t t nil "count" "--batch")
+    (goto-char (point-min))
+
+    (notmuch-remove-if-not
+     #'identity
+     (mapcar
+      (lambda (elem)
+       (let ((name (car elem))
+             (search-query (if (consp (cdr elem))
+                                ;; do we have a different query for the message count?
+                                (second elem)
+                             (cdr elem)))
+             (message-count (prog1 (read (current-buffer))
+                               (forward-line 1))))
+         (and (or (plist-get options :show-empty-searches) (> message-count 0))
+              (list name (notmuch-hello-filtered-query
+                          search-query (plist-get options :filter))
+                    message-count))))
+      query-alist))))
 
 (defun notmuch-hello-insert-buttons (searches)
   "Insert buttons for SEARCHES.
@@ -429,51 +424,41 @@ 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))
+        (column-width (cdr tags-and-width))
+        (column-indent 0)
         (count 0)
         (reordered-list (notmuch-hello-reflect searches tags-per-line))
         ;; Hack the display of the buttons used.
         (widget-push-button-prefix "")
-        (widget-push-button-suffix "")
-        (found-target-pos nil))
+        (widget-push-button-suffix ""))
     ;; dme: It feels as though there should be a better way to
     ;; implement this loop than using an incrementing counter.
     (mapc (lambda (elem)
            ;; (not elem) indicates an empty slot in the matrix.
            (when elem
+             (if (> column-indent 0)
+                 (widget-insert (make-string column-indent ? )))
              (let* ((name (first elem))
                     (query (second elem))
-                    (msg-count (third elem))
-                    (formatted-name (format "%s " name)))
+                    (msg-count (third elem)))
                (widget-insert (format "%8s "
                                       (notmuch-hello-nice-number msg-count)))
-               (if (string= formatted-name notmuch-hello-target)
-                   (setq found-target-pos (point-marker)))
                (widget-create 'push-button
                               :notify #'notmuch-hello-widget-search
                               :notmuch-search-terms query
-                              formatted-name)
-               (unless (eq (% count tags-per-line) (1- tags-per-line))
-                 ;; If this is not the last tag on the line, insert
-                 ;; enough space to consume the rest of the column.
-                 ;; Because the button for the name is `(1+ (length
-                 ;; name))' long (due to the trailing space) we can
-                 ;; just insert `(- widest (length name))' spaces - the
-                 ;; column separator is included in the button if
-                 ;; `(equal widest (length name)'.
-                 (widget-insert (make-string (max 0
-                                                  (- widest (length name)))
-                                             ? )))))
+                              name)
+               (setq column-indent
+                     (1+ (max 0 (- column-width (length name)))))))
            (setq count (1+ count))
-           (if (eq (% count tags-per-line) 0)
-               (widget-insert "\n")))
+           (when (eq (% count tags-per-line) 0)
+             (setq column-indent 0)
+             (widget-insert "\n")))
          reordered-list)
 
     ;; If the last line was not full (and hence did not include a
     ;; carriage return), insert one now.
     (unless (eq (% count tags-per-line) 0)
-      (widget-insert "\n"))
-    found-target-pos))
+      (widget-insert "\n"))))
 
 (defimage notmuch-hello-logo ((:type png :file "notmuch-logo.png")))
 
@@ -527,11 +512,11 @@ Complete list of currently available key bindings:
 (defun notmuch-hello-generate-tag-alist (&optional hide-tags)
   "Return an alist from tags to queries to display in the all-tags section."
   (mapcar (lambda (tag)
-           (cons tag (format "tag:%s" tag)))
+           (cons tag (concat "tag:" (notmuch-escape-boolean-term tag))))
          (notmuch-remove-if-not
           (lambda (tag)
             (not (member tag hide-tags)))
-          (process-lines notmuch-command "search-tags"))))
+          (process-lines notmuch-command "search" "--output=tags" "*"))))
 
 (defun notmuch-hello-insert-header ()
   "Insert the default notmuch-hello header."
@@ -577,8 +562,7 @@ Complete list of currently available key bindings:
                       (funcall notmuch-saved-search-sort-function
                                notmuch-saved-searches)
                     notmuch-saved-searches)
-                  :show-empty-searches notmuch-show-empty-saved-searches))
-       found-target-pos)
+                  :show-empty-searches notmuch-show-empty-saved-searches)))
     (when searches
       (widget-insert "Saved searches: ")
       (widget-create 'push-button
@@ -587,15 +571,12 @@ Complete list of currently available key bindings:
                     "edit")
       (widget-insert "\n\n")
       (let ((start (point)))
-       (setq found-target-pos
-             (notmuch-hello-insert-buttons searches))
-       (indent-rigidly start (point) notmuch-hello-indent)
-       found-target-pos))))
+       (notmuch-hello-insert-buttons searches)
+       (indent-rigidly start (point) notmuch-hello-indent)))))
 
 (defun notmuch-hello-insert-search ()
   "Insert a search widget."
   (widget-insert "Search: ")
-  (setq notmuch-hello-search-pos (point-marker))
   (widget-create 'editable-field
                 ;; Leave some space at the start and end of the
                 ;; search boxes.
@@ -695,16 +676,13 @@ Supports the following entries in OPTIONS as a plist:
                                (notmuch-hello-update))
                     "hide"))
     (widget-insert "\n")
-    (let (target-pos)
-      (when (not is-hidden)
-       (let ((searches (apply 'notmuch-hello-query-counts query-alist options)))
-         (when (or (not (plist-get options :hide-if-empty))
-                   searches)
-           (widget-insert "\n")
-           (setq target-pos
-                 (notmuch-hello-insert-buttons searches))
-           (indent-rigidly start (point) notmuch-hello-indent))))
-      target-pos)))
+    (when (not is-hidden)
+      (let ((searches (apply 'notmuch-hello-query-counts query-alist options)))
+       (when (or (not (plist-get options :hide-if-empty))
+                 searches)
+         (widget-insert "\n")
+         (notmuch-hello-insert-buttons searches)
+         (indent-rigidly start (point) notmuch-hello-indent))))))
 
 (defun notmuch-hello-insert-tags-section (&optional title &rest options)
   "Insert a section displaying all tags with message counts.
@@ -723,7 +701,7 @@ following:
   "Show an entry for each saved search and inboxed messages for each tag"
   (notmuch-hello-insert-searches "What's in your inbox"
                                 (append
-                                 (notmuch-saved-searches)
+                                 notmuch-saved-searches
                                  (notmuch-hello-generate-tag-alist))
                                 :filter "tag:inbox"))
 
@@ -760,22 +738,12 @@ following:
   "Run notmuch and display saved searches, known tags, etc."
   (interactive)
 
-  ;; Jump through a hoop to get this value from the deprecated variable
-  ;; name (`notmuch-folders') or from the default value.
-  (unless notmuch-saved-searches
-    (setq notmuch-saved-searches (notmuch-saved-searches)))
-
   (if no-display
       (set-buffer "*notmuch-hello*")
     (switch-to-buffer "*notmuch-hello*"))
 
-  (let ((notmuch-hello-target (if (widget-at)
-                                 (widget-value (widget-at))
-                               (condition-case nil
-                                   (progn
-                                     (widget-forward 1)
-                                     (widget-value (widget-at)))
-                                 (error nil))))
+  (let ((target-line (line-number-at-pos))
+       (target-column (current-column))
        (inhibit-read-only t))
 
     ;; Delete all editable widget fields.  Editable widget fields are
@@ -794,30 +762,25 @@ following:
       (mapc 'delete-overlay (car all))
       (mapc 'delete-overlay (cdr all)))
 
-    (let (final-target-pos)
-      (mapc
-       (lambda (section)
-        (let ((point-before (point))
-              (result (if (functionp section)
-                          (funcall section)
-                        (apply (car section) (cdr section)))))
-          (if (and (not final-target-pos) (integer-or-marker-p result))
-              (setq final-target-pos result))
-          ;; don't insert a newline when the previous section didn't show
-          ;; anything.
-          (unless (eq (point) point-before)
-            (widget-insert "\n"))))
-       notmuch-hello-sections)
-      (widget-setup)
-
-      (when final-target-pos
-       (goto-char final-target-pos)
-       (unless (widget-at)
-         (widget-forward 1)))
-
-      (unless (widget-at)
-       (when notmuch-hello-search-pos
-         (goto-char notmuch-hello-search-pos)))))
+    (mapc
+     (lambda (section)
+       (let ((point-before (point)))
+        (if (functionp section)
+            (funcall section)
+          (apply (car section) (cdr section)))
+        ;; don't insert a newline when the previous section didn't
+        ;; show anything.
+        (unless (eq (point) point-before)
+          (widget-insert "\n"))))
+     notmuch-hello-sections)
+    (widget-setup)
+
+    ;; Move point back to where it was before refresh. Use line and
+    ;; column instead of point directly to be insensitive to additions
+    ;; and removals of text within earlier lines.
+    (goto-char (point-min))
+    (forward-line (1- target-line))
+    (move-to-column target-column))
   (run-hooks 'notmuch-hello-refresh-hook)
   (setq notmuch-hello-first-run nil))