]> git.notmuchmail.org Git - notmuch/blobdiff - notmuch.el
Makefile: Change default flags to -O2.
[notmuch] / notmuch.el
index 68a01187820d74849ec29d920c5ecfdaaae6e90b..c8639be529207fc85420e25be527712b590a1348 100644 (file)
@@ -19,6 +19,8 @@
 ;
 ; Authors: Carl Worth <cworth@cworth.org>
 
+(load "cl-seq")
+
 (defvar notmuch-show-mode-map
   (let ((map (make-sparse-keymap)))
     ; I don't actually want all of these toggle commands occupying
     ; toggling visibility of these components. Probably using
     ; overlays-at to query and manipulate the current overlay.
     (define-key map "a" 'notmuch-show-archive-thread)
+    (define-key map "A" 'notmuch-show-mark-read-then-archive-thread)
     (define-key map "b" 'notmuch-show-toggle-body-read-visible)
     (define-key map "c" 'notmuch-show-toggle-citations-visible)
     (define-key map "h" 'notmuch-show-toggle-headers-visible)
     (define-key map "n" 'notmuch-show-next-message)
+    (define-key map "N" 'notmuch-show-mark-read-then-next-open-message)
     (define-key map "p" 'notmuch-show-previous-message)
     (define-key map (kbd "C-n") 'notmuch-show-next-line)
     (define-key map (kbd "C-p") 'notmuch-show-previous-line)
@@ -44,6 +48,7 @@
     (define-key map "-" 'notmuch-show-remove-tag)
     (define-key map (kbd "DEL") 'notmuch-show-rewind)
     (define-key map " " 'notmuch-show-advance-marking-read-and-archiving)
+    (define-key map "|" 'notmuch-show-pipe-message)
     map)
   "Keymap for \"notmuch show\" buffers.")
 (fset 'notmuch-show-mode-map notmuch-show-mode-map)
@@ -63,8 +68,8 @@
 (set 'notmuch-show-part-end-regexp         "\fpart}")
 (set 'notmuch-show-marker-regexp "\f\\(message\\|header\\|body\\|attachment\\|part\\)[{}].*$")
 
-(set 'notmuch-show-id-regexp "ID: \\([^ ]*\\)")
-(set 'notmuch-show-filename-regexp "Filename: \\(.*\\)$")
+(set 'notmuch-show-id-regexp "id:\\([^ ]*\\)")
+(set 'notmuch-show-filename-regexp "filename:\\(.*\\)$")
 (set 'notmuch-show-tags-regexp "(\\([^)]*\\))$")
 
 ; XXX: This should be a generic function in emacs somewhere, not here
@@ -142,35 +147,34 @@ Unlike builtin `next-line' this version accepts no arguments."
     (re-search-forward notmuch-show-tags-regexp)
     (split-string (buffer-substring (match-beginning 1) (match-end 1)))))
 
-(defun notmuch-show-add-tag (tag)
+(defun notmuch-show-add-tag (&rest toadd)
+  "Add a tag to the current message."
   (interactive "sTag to add: ")
-  (notmuch-call-notmuch-process "tag" (concat "+" tag) (concat "id:" (notmuch-show-get-message-id)))
-  (notmuch-show-set-tags (delete-dups (sort (cons tag (notmuch-show-get-tags)) 'string<))))
-
-(defun notmuch-show-remove-tag (tag)
+  (apply 'notmuch-call-notmuch-process
+        (append (cons "tag"
+                      (mapcar (lambda (s) (concat "+" s)) toadd))
+                (cons (concat "id:" (notmuch-show-get-message-id)) nil)))
+  (notmuch-show-set-tags (sort (union toadd (notmuch-show-get-tags) :test 'string=) 'string<)))
+
+(defun notmuch-show-remove-tag (&rest toremove)
+  "Remove a tag from the current message."
   (interactive "sTag to remove: ")
   (let ((tags (notmuch-show-get-tags)))
-    (if (member tag tags)
+    (if (intersection tags toremove :test 'string=)
        (progn
-         (notmuch-call-notmuch-process "tag" (concat "-" tag) (concat "id:" (notmuch-show-get-message-id)))
-         (notmuch-show-set-tags (delete tag tags))))))
-
-(defun notmuch-show-archive-thread ()
-  "Archive each message in thread, and show next thread from search.
+         (apply 'notmuch-call-notmuch-process
+                (append (cons "tag"
+                              (mapcar (lambda (s) (concat "-" s)) toremove))
+                        (cons (concat "id:" (notmuch-show-get-message-id)) nil)))
+         (notmuch-show-set-tags (sort (set-difference tags toremove :test 'string=) 'string<))))))
 
-Archive each message currrently shown by removing the \"inbox\"
-tag from each. Then kill this buffer and show the next thread
-from the search from which this thread was originally shown.
-
-Note: This command is safe from any race condition of new messages
-being delivered to the same thread. It does not archive the
-entire thread, but only the messages shown in the current
-buffer."
-  (interactive)
+(defun notmuch-show-archive-thread-maybe-mark-read (markread)
   (save-excursion
     (goto-char (point-min))
     (while (not (eobp))
-      (notmuch-show-remove-tag "inbox")
+      (if markread
+         (notmuch-show-remove-tag "unread" "inbox")
+       (notmuch-show-remove-tag "inbox"))
       (if (not (eobp))
          (forward-char))
       (if (not (re-search-forward notmuch-show-message-begin-regexp nil t))
@@ -180,13 +184,52 @@ buffer."
     (if parent-buffer
        (progn
          (switch-to-buffer parent-buffer)
+         (forward-line)
          (notmuch-search-show-thread)))))
 
+(defun notmuch-show-mark-read-then-archive-thread ()
+  "Remove \"unread\" tag from each message, then archive and show next thread.
+
+Archive each message currrently shown by removing the \"unread\"
+and \"inbox\" tag from each. Then kill this buffer and show the
+next thread from the search from which this thread was originally
+shown.
+
+Note: This command is safe from any race condition of new messages
+being delivered to the same thread. It does not archive the
+entire thread, but only the messages shown in the current
+buffer."
+  (interactive)
+  (notmuch-show-archive-thread-maybe-mark-read t))
+
+(defun notmuch-show-archive-thread ()
+  "Archive each message in thread, and show next thread from search.
+
+Archive each message currrently shown by removing the \"inbox\"
+tag from each. Then kill this buffer and show the next thread
+from the search from which this thread was originally shown.
+
+Note: This command is safe from any race condition of new messages
+being delivered to the same thread. It does not archive the
+entire thread, but only the messages shown in the current
+buffer."
+  (interactive)
+  (notmuch-show-archive-thread-maybe-mark-read nil))
+
 (defun notmuch-show-view-raw-message ()
   "View the raw email of the current message."
   (interactive)
   (view-file (notmuch-show-get-filename)))
 
+(defun notmuch-show-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 *Messages* buffer."
+  (interactive "sPipe message to command: ")
+  (apply 'start-process-shell-command "notmuch-pipe-command" "*notmuch-pipe*" (split-string (concat command " < " (notmuch-show-get-filename)))))
+
 (defun notmuch-show-move-to-current-message-summary-line ()
   "Move to the beginning of the one-line summary of the current message.
 
@@ -256,6 +299,16 @@ there are no more unread messages past the current point."
   (if (not (notmuch-show-message-unread-p))
       (notmuch-show-next-message)))
 
+(defun notmuch-show-next-open-message ()
+  "Advance to the the next message which is not hidden.
+
+If read messages are currently hidden, advance to the next unread
+message. Otherwise, advance to the next message."
+  (if (or (memq 'notmuch-show-body-read buffer-invisibility-spec)
+         (assq 'notmuch-show-body-read buffer-invisibility-spec))
+      (notmuch-show-next-unread-message)
+    (notmuch-show-next-message)))
+
 (defun notmuch-show-previous-message ()
   "Backup to the beginning of the previous message in the buffer.
 
@@ -287,11 +340,11 @@ it."
       (notmuch-show-previous-message)
       (point))))
 
-(defun notmuch-show-mark-read-then-next-unread-message ()
+(defun notmuch-show-mark-read-then-next-open-message ()
   "Remove unread tag from current message, then advance to next unread message."
   (interactive)
   (notmuch-show-remove-tag "unread")
-  (notmuch-show-next-unread-message))
+  (notmuch-show-next-open-message))
 
 (defun notmuch-show-rewind ()
   "Do reverse scrolling compared to `notmuch-show-advance-marking-read-and-archiving'
@@ -326,7 +379,7 @@ scroll by a near screenful to read more of the message.
 
 Otherwise, (the end of the current message is already within the
 current window), remove the \"unread\" tag (if present) from the
-current message and advance to the next message.
+current message and advance to the next open message.
 
 Finally, if there is no further message to advance to, and this
 last message is already read, then archive the entire current
@@ -338,11 +391,10 @@ which this thread was originally shown."
        (unread (notmuch-show-message-unread-p)))
     (if (> next (window-end))
        (scroll-up nil)
-      (if unread
-         (notmuch-show-mark-read-then-next-unread-message)
-       (if (notmuch-show-last-message-p)
-           (notmuch-show-archive-thread)
-         (notmuch-show-next-unread-message))))))
+      (let ((last (notmuch-show-last-message-p)))
+       (notmuch-show-mark-read-then-next-open-message)
+       (if last
+           (notmuch-show-archive-thread))))))
 
 (defun notmuch-show-markup-citations-region (beg end)
   (goto-char beg)
@@ -357,7 +409,7 @@ which this thread was originally shown."
              (overlay-put overlay 'invisible 'notmuch-show-citation)
              (overlay-put overlay 'before-string
                           (concat "[" (number-to-string (count-lines beg-sub (point)))
-                                  " quoted lines.]\n")))))
+                                  "-line citation. Press 'c' to show.]\n")))))
       (if (looking-at "--[ ]?$")
          (let ((sig-lines (count-lines beg-sub end)))
            (if (<= sig-lines notmuch-show-signature-lines-max)
@@ -365,7 +417,7 @@ which this thread was originally shown."
                  (overlay-put (make-overlay beg-sub (+ beg-sub 1))
                               'before-string
                               (concat "[" (number-to-string sig-lines)
-                                      "-line signature.]"))
+                                      "-line signature. Press 's' to show.]"))
                  (overlay-put (make-overlay (+ beg-sub 2) end)
                               'invisible 'notmuch-show-signature)
                  (goto-char end)))))
@@ -385,9 +437,15 @@ which this thread was originally shown."
 
 (defun notmuch-show-markup-header ()
   (re-search-forward notmuch-show-header-begin-regexp)
-  (next-line 2)
+  (forward-line 1)
   (beginning-of-line)
   (let ((beg (point)))
+    (end-of-line)
+    ; Inverse video for subject
+    (overlay-put (make-overlay beg (point)) 'face '((cons :inverse-video t)))
+    (beginning-of-line)
+    (forward-line 2)
+    (set 'beg (point))
     (re-search-forward notmuch-show-header-end-regexp)
     (overlay-put (make-overlay beg (match-beginning 0))
                 'invisible 'notmuch-show-header)))
@@ -623,15 +681,16 @@ global search.
   (save-excursion
     (beginning-of-line)
     (let ((beg (point)))
-      (re-search-forward "[a-fA-F0-9]*")
+      (re-search-forward "thread:[a-fA-F0-9]*" nil t)
       (filter-buffer-substring beg (point)))))
 
 (defun notmuch-search-markup-this-thread-id ()
   (beginning-of-line)
   (let ((beg (point)))
-    (re-search-forward "[a-fA-F0-9]*")
-    (forward-char)
-    (overlay-put (make-overlay beg (point)) 'invisible 'notmuch-search)))
+    (if (re-search-forward "thread:[a-fA-F0-9]*" nil t)
+       (progn
+         (forward-char)
+         (overlay-put (make-overlay beg (point)) 'invisible 'notmuch-search)))))
 
 (defun notmuch-search-markup-thread-ids ()
   (save-excursion
@@ -655,12 +714,15 @@ global search.
 (defun notmuch-search-show-thread ()
   (interactive)
   (let ((thread-id (notmuch-search-find-thread-id)))
-    (forward-line)
     (if (> (length thread-id) 0)
        (notmuch-show thread-id (current-buffer))
       (error "End of search results"))))
 
 (defun notmuch-call-notmuch-process (&rest args)
+  "Synchronously invoke \"notmuch\" with the given list of arguments.
+
+Output from the process will be presented to the user as an error
+and will also appear in a buffer named \"*Notmuch errors*\"."
   (let ((error-buffer (get-buffer-create "*Notmuch errors*")))
     (with-current-buffer error-buffer
        (erase-buffer))
@@ -697,12 +759,12 @@ global search.
 
 (defun notmuch-search-add-tag (tag)
   (interactive "sTag to add: ")
-  (notmuch-call-notmuch-process "tag" (concat "+" tag) (concat "thread:" (notmuch-search-find-thread-id)))
+  (notmuch-call-notmuch-process "tag" (concat "+" tag) (notmuch-search-find-thread-id))
   (notmuch-search-set-tags (delete-dups (sort (cons tag (notmuch-search-get-tags)) 'string<))))
 
 (defun notmuch-search-remove-tag (tag)
   (interactive "sTag to remove: ")
-  (notmuch-call-notmuch-process "tag" (concat "-" tag) (concat "thread:" (notmuch-search-find-thread-id)))
+  (notmuch-call-notmuch-process "tag" (concat "-" tag) (notmuch-search-find-thread-id))
   (notmuch-search-set-tags (delete tag (notmuch-search-get-tags))))
 
 (defun notmuch-search-archive-thread ()