]> git.notmuchmail.org Git - notmuch/blobdiff - emacs/notmuch.el
test/emacs: tests for notmuch-{tree,unthreaded} with bad CWD
[notmuch] / emacs / notmuch.el
index f8c97c5df85db83a382f5e6b0a259b9135e4ee2f..2ef67c0e798dbc65c144cef77cd8642c506f98c0 100644 (file)
 
 ;;; Code:
 
-(eval-when-compile (require 'cl-lib))
-
 (require 'mm-view)
 (require 'message)
 
+(require 'hl-line)
+
 (require 'notmuch-lib)
 (require 'notmuch-tag)
 (require 'notmuch-show)
     ("authors" . "%-20s ")
     ("subject" . "%s ")
     ("tags" . "(%s)"))
-  "Search result formatting. Supported fields are:
-       date, count, authors, subject, tags
+  "Search result formatting.
+
+Supported fields are: date, count, authors, subject, tags.
 For example:
-       (setq notmuch-search-result-format \(\(\"authors\" . \"%-40s\"\)
-                                            \(\"subject\" . \"%s\"\)\)\)
+    (setq notmuch-search-result-format
+          '((\"authors\" . \"%-40s\")
+            (\"subject\" . \"%s\")))
+
 Line breaks are permitted in format strings (though this is
 currently experimental).  Note that a line break at the end of an
 \"authors\" field will get elided if the authors list is long;
 place it instead at the beginning of the following field.  To
 enter a line break when setting this variable with setq, use \\n.
 To enter a line break in customize, press \\[quoted-insert] C-j."
-  :type '(alist :key-type (string) :value-type (string))
+  :type '(alist :key-type string :value-type string)
   :group 'notmuch-search)
 
 ;; The name of this variable `notmuch-init-file' is consistent with the
@@ -114,8 +117,12 @@ there will be called at other points of notmuch execution."
   :type 'file
   :group 'notmuch)
 
-(defvar notmuch-query-history nil
-  "Variable to store minibuffer history for notmuch queries.")
+(defcustom notmuch-search-hook '(notmuch-hl-line-mode)
+  "List of functions to call when notmuch displays the search results."
+  :type 'hook
+  :options '(notmuch-hl-line-mode)
+  :group 'notmuch-search
+  :group 'notmuch-hooks)
 
 ;;; Mime Utilities
 
@@ -155,24 +162,6 @@ there will be called at other points of notmuch execution."
            (mm-save-part p))))
    mm-handle))
 
-;;; Integrations
-
-(require 'hl-line)
-
-(defun notmuch-hl-line-mode ()
-  (prog1 (hl-line-mode)
-    (when hl-line-overlay
-      (overlay-put hl-line-overlay 'priority 1))))
-
-;;; Options
-
-(defcustom notmuch-search-hook '(notmuch-hl-line-mode)
-  "List of functions to call when notmuch displays the search results."
-  :type 'hook
-  :options '(notmuch-hl-line-mode)
-  :group 'notmuch-search
-  :group 'notmuch-hooks)
-
 ;;; Keymap
 
 (defvar notmuch-search-mode-map
@@ -205,6 +194,15 @@ there will be called at other points of notmuch execution."
     map)
   "Keymap for \"notmuch search\" buffers.")
 
+;;; Internal Variables
+
+(defvar notmuch-query-history nil
+  "Variable to store minibuffer history for notmuch queries.")
+
+(defvar-local notmuch-search-query-string nil)
+(defvar-local notmuch-search-target-thread nil)
+(defvar-local notmuch-search-target-line nil)
+
 ;;; Stashing
 
 (defvar notmuch-search-stash-map
@@ -224,15 +222,7 @@ there will be called at other points of notmuch execution."
 (defun notmuch-stash-query ()
   "Copy current query to kill-ring."
   (interactive)
-  (notmuch-common-do-stash (notmuch-search-get-query)))
-
-;;; Variables
-
-(defvar notmuch-search-query-string)
-(defvar notmuch-search-target-thread)
-(defvar notmuch-search-target-line)
-
-(defvar notmuch-search-disjunctive-regexp "\\<[oO][rR]\\>")
+  (notmuch-common-do-stash notmuch-search-query-string))
 
 ;;; Movement
 
@@ -406,10 +396,6 @@ new, global search.
 Complete list of currently available key bindings:
 
 \\{notmuch-search-mode-map}"
-  (make-local-variable 'notmuch-search-query-string)
-  (make-local-variable 'notmuch-search-oldest-first)
-  (make-local-variable 'notmuch-search-target-thread)
-  (make-local-variable 'notmuch-search-target-line)
   (setq notmuch-buffer-refresh-function #'notmuch-search-refresh-view)
   (setq-local scroll-preserve-screen-position t)
   (add-to-invisibility-spec (cons 'ellipsis t))
@@ -536,17 +522,16 @@ With a prefix argument, invert the default value of
 `notmuch-show-only-matching-messages' when displaying the
 thread."
   (interactive "P")
-  (let ((thread-id (notmuch-search-find-thread-id))
-       (subject (notmuch-search-find-subject)))
-    (if (> (length thread-id) 0)
+  (let ((thread-id (notmuch-search-find-thread-id)))
+    (if thread-id
        (notmuch-show thread-id
                      elide-toggle
                      (current-buffer)
                      notmuch-search-query-string
                      ;; Name the buffer based on the subject.
-                     (concat "*"
-                             (truncate-string-to-width subject 30 nil nil t)
-                             "*"))
+                     (format "*%s*" (truncate-string-to-width
+                                     (notmuch-search-find-subject)
+                                     30 nil nil t)))
       (message "End of search results."))))
 
 (defun notmuch-tree-from-search-current-query ()
@@ -571,20 +556,21 @@ thread."
 (defun notmuch-search-reply-to-thread (&optional prompt-for-sender)
   "Begin composing a reply-all to the entire current thread in a new buffer."
   (interactive "P")
-  (let ((message-id (notmuch-search-find-thread-id)))
-    (notmuch-mua-new-reply message-id prompt-for-sender t)))
+  (notmuch-mua-new-reply (notmuch-search-find-thread-id)
+                        prompt-for-sender t))
 
 (defun notmuch-search-reply-to-thread-sender (&optional prompt-for-sender)
   "Begin composing a reply to the entire current thread in a new buffer."
   (interactive "P")
-  (let ((message-id (notmuch-search-find-thread-id)))
-    (notmuch-mua-new-reply message-id prompt-for-sender nil)))
+  (notmuch-mua-new-reply (notmuch-search-find-thread-id)
+                        prompt-for-sender nil))
 
 ;;; Tags
 
 (defun notmuch-search-set-tags (tags &optional pos)
-  (let ((new-result (plist-put (notmuch-search-get-result pos) :tags tags)))
-    (notmuch-search-update-result new-result pos)))
+  (notmuch-search-update-result
+   (plist-put (notmuch-search-get-result pos) :tags tags)
+   pos))
 
 (defun notmuch-search-get-tags (&optional pos)
   (plist-get (notmuch-search-get-result pos) :tags))
@@ -594,7 +580,7 @@ thread."
     (notmuch-search-foreach-result beg end
       (lambda (pos)
        (setq output (append output (notmuch-search-get-tags pos)))))
-    output))
+    (delete-dups output)))
 
 (defun notmuch-search-interactive-tag-changes (&optional initial-input)
   "Prompt for tag changes for the current thread or region.
@@ -831,13 +817,13 @@ non-authors is found, assume that all of the authors match."
        (setq invisible-string (notmuch-search-author-propertize invisible-string)))
       ;; If there is any invisible text, add it as a tooltip to the
       ;; visible text.
-      (unless (string= invisible-string "")
+      (unless (string-empty-p invisible-string)
        (setq visible-string
              (propertize visible-string
                          'help-echo (concat "..." invisible-string))))
       ;; Insert the visible and, if present, invisible author strings.
       (insert visible-string)
-      (unless (string= invisible-string "")
+      (unless (string-empty-p invisible-string)
        (let ((start (point))
              overlay)
          (insert invisible-string)
@@ -847,26 +833,28 @@ non-authors is found, assume that all of the authors match."
       (insert padding))))
 
 (defun notmuch-search-insert-field (field format-string result)
-  (cond
-   ((string-equal field "date")
-    (insert (propertize (format format-string (plist-get result :date_relative))
-                       'face 'notmuch-search-date)))
-   ((string-equal field "count")
-    (insert (propertize (format format-string
-                               (format "[%s/%s]" (plist-get result :matched)
-                                       (plist-get result :total)))
-                       'face 'notmuch-search-count)))
-   ((string-equal field "subject")
-    (insert (propertize (format format-string
-                               (notmuch-sanitize (plist-get result :subject)))
-                       'face 'notmuch-search-subject)))
-   ((string-equal field "authors")
-    (notmuch-search-insert-authors
-     format-string (notmuch-sanitize (plist-get result :authors))))
-   ((string-equal field "tags")
-    (let ((tags (plist-get result :tags))
-         (orig-tags (plist-get result :orig-tags)))
-      (insert (format format-string (notmuch-tag-format-tags tags orig-tags)))))))
+  (pcase field
+    ((pred functionp)
+     (insert (funcall field format-string result)))
+    ("date"
+     (insert (propertize (format format-string (plist-get result :date_relative))
+                        'face 'notmuch-search-date)))
+    ("count"
+     (insert (propertize (format format-string
+                                (format "[%s/%s]" (plist-get result :matched)
+                                        (plist-get result :total)))
+                        'face 'notmuch-search-count)))
+    ("subject"
+     (insert (propertize (format format-string
+                                (notmuch-sanitize (plist-get result :subject)))
+                        'face 'notmuch-search-subject)))
+    ("authors"
+     (notmuch-search-insert-authors format-string
+                                   (notmuch-sanitize (plist-get result :authors))))
+    ("tags"
+     (let ((tags (plist-get result :tags))
+          (orig-tags (plist-get result :orig-tags)))
+       (insert (format format-string (notmuch-tag-format-tags tags orig-tags)))))))
 
 (defun notmuch-search-show-result (result pos)
   "Insert RESULT at POS."
@@ -952,7 +940,7 @@ See `notmuch-tag' for information on the format of TAG-CHANGES."
 PROMPT is the string to prompt with."
   (let* ((all-tags
          (mapcar (lambda (tag) (notmuch-escape-boolean-term tag))
-                 (process-lines notmuch-command "search" "--output=tags" "*")))
+                 (notmuch--process-lines notmuch-command "search" "--output=tags" "*")))
         (completions
          (append (list "folder:" "path:" "thread:" "id:" "date:" "from:" "to:"
                        "subject:" "attachment:")
@@ -990,7 +978,8 @@ PROMPT is the string to prompt with."
 
 (put 'notmuch-search 'notmuch-doc "Search for messages.")
 ;;;###autoload
-(defun notmuch-search (&optional query oldest-first target-thread target-line no-display)
+(defun notmuch-search (&optional query oldest-first target-thread target-line
+                                no-display)
   "Display threads matching QUERY in a notmuch-search buffer.
 
 If QUERY is nil, it is read interactively from the minibuffer.
@@ -1028,16 +1017,15 @@ the configured default sort order."
     (setq notmuch-search-target-thread target-thread)
     (setq notmuch-search-target-line target-line)
     (notmuch-tag-clear-cache)
-    (let ((proc (get-buffer-process (current-buffer)))
-         (inhibit-read-only t))
-      (when proc
-       (error "notmuch search process already running for query `%s'" query))
+    (when (get-buffer-process buffer)
+      (error "notmuch search process already running for query `%s'" query))
+    (let ((inhibit-read-only t))
       (erase-buffer)
       (goto-char (point-min))
       (save-excursion
        (let ((proc (notmuch-start-notmuch
                     "notmuch-search" buffer #'notmuch-search-process-sentinel
-                    "search" "--format=sexp" "--format-version=4"
+                    "search" "--format=sexp" "--format-version=5"
                     (if oldest-first
                         "--sort=oldest-first"
                       "--sort=newest-first")
@@ -1060,13 +1048,12 @@ the new search results, then point will be placed on the same
 thread. Otherwise, point will be moved to attempt to be in the
 same relative position within the new buffer."
   (interactive)
-  (let ((target-line (line-number-at-pos))
-       (oldest-first notmuch-search-oldest-first)
-       (target-thread (notmuch-search-find-thread-id 'bare))
-       (query notmuch-search-query-string))
-    ;; notmuch-search erases the current buffer.
-    (notmuch-search query oldest-first target-thread target-line t)
-    (goto-char (point-min))))
+  (notmuch-search notmuch-search-query-string
+                 notmuch-search-oldest-first
+                 (notmuch-search-find-thread-id 'bare)
+                 (line-number-at-pos)
+                 t)
+  (goto-char (point-min)))
 
 (defun notmuch-search-toggle-order ()
   "Toggle the current search order.
@@ -1079,10 +1066,8 @@ default sort order is defined by `notmuch-search-oldest-first'."
 
 (defun notmuch-group-disjunctive-query-string (query-string)
   "Group query if it contains a complex expression.
-
-Enclose QUERY-STRING in parentheses if it matches
-`notmuch-search-disjunctive-regexp'."
-  (if (string-match-p notmuch-search-disjunctive-regexp query-string)
+Enclose QUERY-STRING in parentheses if contains \"OR\" operators."
+  (if (string-match-p "\\<[oO][rR]\\>" query-string)
       (concat "( " query-string " )")
     query-string))
 
@@ -1158,7 +1143,15 @@ If no notmuch buffers exist, run `notmuch'."
          (pop-to-buffer-same-window first))
       (notmuch))))
 
-;;; Imenu Support
+;;; Integrations
+;;;; Hl-line Support
+
+(defun notmuch-hl-line-mode ()
+  (prog1 (hl-line-mode)
+    (when hl-line-overlay
+      (overlay-put hl-line-overlay 'priority 1))))
+
+;;;; Imenu Support
 
 (defun notmuch-search-imenu-prev-index-position-function ()
   "Move point to previous message in notmuch-search buffer.
@@ -1169,14 +1162,12 @@ Used as`imenu-prev-index-position-function' in notmuch buffers."
   "Return imenu name for line at point.
 Used as `imenu-extract-index-name-function' in notmuch buffers.
 Point should be at the beginning of the line."
-  (let ((subject (notmuch-search-find-subject))
-       (author (notmuch-search-find-authors)))
-    (format "%s (%s)" subject author)))
+  (format "%s (%s)"
+         (notmuch-search-find-subject)
+         (notmuch-search-find-authors)))
 
 ;;; _
 
-(setq mail-user-agent 'notmuch-user-agent)
-
 (provide 'notmuch)
 
 ;; After provide to avoid loops if notmuch was require'd via notmuch-init-file.