2012-05-01 21:45:54 +02:00
|
|
|
|
;;; mu4e-headers.el -- part of mu4e, the mu mail user agent
|
2011-09-12 19:52:32 +02:00
|
|
|
|
;;
|
2012-01-06 11:31:28 +01:00
|
|
|
|
;; Copyright (C) 2011-2012 Dirk-Jan C. Binnema
|
2011-09-12 19:52:32 +02:00
|
|
|
|
|
|
|
|
|
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
|
|
|
|
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
|
|
|
|
|
|
|
|
|
;; This file is not part of GNU Emacs.
|
|
|
|
|
;;
|
|
|
|
|
;; GNU Emacs 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.
|
|
|
|
|
|
|
|
|
|
;; GNU Emacs 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
|
|
;;; Commentary:
|
|
|
|
|
|
2012-05-01 21:45:54 +02:00
|
|
|
|
;; In this file are function related mu4e-headers-mode, to creating the list of
|
2012-03-31 16:20:03 +02:00
|
|
|
|
;; one-line descriptions of emails, aka 'headers' (not to be confused with
|
|
|
|
|
;; headers like 'To:' or 'Subject:')
|
2011-09-12 19:52:32 +02:00
|
|
|
|
|
2011-09-18 22:57:46 +02:00
|
|
|
|
;; Code:
|
2012-06-10 15:14:21 +02:00
|
|
|
|
(eval-when-compile (byte-compile-disable-warning 'cl-functions))
|
2012-04-24 20:12:15 +02:00
|
|
|
|
(require 'cl)
|
2012-04-09 15:34:52 +02:00
|
|
|
|
|
2012-06-14 18:10:02 +02:00
|
|
|
|
(require 'fringe)
|
2012-04-24 20:12:15 +02:00
|
|
|
|
(require 'hl-line)
|
2012-06-14 18:10:02 +02:00
|
|
|
|
|
2012-04-09 10:51:24 +02:00
|
|
|
|
(require 'mu4e-utils) ;; utility functions
|
2012-06-10 15:14:21 +02:00
|
|
|
|
(require 'mu4e-proc)
|
2012-04-09 15:34:52 +02:00
|
|
|
|
(require 'mu4e-vars)
|
2012-04-23 18:07:20 +02:00
|
|
|
|
(require 'mu4e-mark)
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(require 'mu4e-compose)
|
2012-04-24 17:13:12 +02:00
|
|
|
|
(require 'mu4e-actions)
|
2012-09-26 11:25:38 +02:00
|
|
|
|
(require 'mu4e-message)
|
2012-04-24 17:13:12 +02:00
|
|
|
|
|
|
|
|
|
;; the headers view
|
|
|
|
|
(defgroup mu4e-headers nil
|
|
|
|
|
"Settings for the headers view."
|
|
|
|
|
:group 'mu4e)
|
|
|
|
|
|
|
|
|
|
(defcustom mu4e-headers-fields
|
2012-10-22 19:27:14 +02:00
|
|
|
|
'( (:human-date . 12)
|
2012-04-24 17:13:12 +02:00
|
|
|
|
(:flags . 6)
|
|
|
|
|
(:from . 22)
|
|
|
|
|
(:subject . nil))
|
|
|
|
|
"A list of header fields to show in the headers buffer, and their
|
2012-05-02 16:22:45 +02:00
|
|
|
|
respective widths in characters. A width of `nil' means
|
|
|
|
|
'unrestricted', and this is best reserved fo the rightmost (last)
|
|
|
|
|
field. For the complete list of available headers, see
|
2012-07-10 10:51:54 +02:00
|
|
|
|
`mu4e-header-info'."
|
2012-04-24 17:13:12 +02:00
|
|
|
|
:type (list 'symbol)
|
|
|
|
|
:group 'mu4e-headers)
|
|
|
|
|
|
2012-10-19 11:02:13 +02:00
|
|
|
|
(defcustom mu4e-headers-date-format "%x"
|
2012-04-24 17:13:12 +02:00
|
|
|
|
"Date format to use in the headers view, in the format of
|
|
|
|
|
`format-time-string'."
|
|
|
|
|
:type 'string
|
|
|
|
|
:group 'mu4e-headers)
|
|
|
|
|
|
2012-10-19 11:02:13 +02:00
|
|
|
|
(defcustom mu4e-headers-time-format "%X"
|
|
|
|
|
"Time format to use in the headers view, in the format of
|
|
|
|
|
`format-time-string'."
|
|
|
|
|
:type 'string
|
|
|
|
|
:group 'mu4e-headers)
|
|
|
|
|
|
2012-04-24 17:13:12 +02:00
|
|
|
|
(defcustom mu4e-headers-visible-lines 10
|
|
|
|
|
"Number of lines to display in the header view when using the
|
|
|
|
|
horizontal split-view. This includes the header-line at the top,
|
|
|
|
|
and the mode-line."
|
|
|
|
|
:type 'integer
|
|
|
|
|
:group 'mu4e-headers)
|
|
|
|
|
|
|
|
|
|
(defcustom mu4e-headers-visible-columns 30
|
|
|
|
|
"Number of columns to display for the header view when using the
|
|
|
|
|
vertical split-view."
|
|
|
|
|
:type 'integer
|
|
|
|
|
:group 'mu4e-headers)
|
2012-04-28 08:08:28 +02:00
|
|
|
|
|
2012-08-27 17:04:58 +02:00
|
|
|
|
|
|
|
|
|
;; marks for headers of the form; each is a cons-cell (basic . fancy)
|
|
|
|
|
;; each of which is basic ascii char and something fancy, respectively
|
2012-09-28 16:11:12 +02:00
|
|
|
|
(defvar mu4e-headers-draft-mark (purecopy '("D" . "⚒")) "Draft.")
|
|
|
|
|
(defvar mu4e-headers-flagged-mark (purecopy '("F" . "⚑")) "Flagged.")
|
|
|
|
|
(defvar mu4e-headers-new-mark (purecopy '("N" . "⭑")) "New.")
|
|
|
|
|
(defvar mu4e-headers-passed-mark (purecopy '("P" . "❯")) "Passed (fwd).")
|
|
|
|
|
(defvar mu4e-headers-replied-mark (purecopy '("R" . "❮")) "Replied.")
|
|
|
|
|
(defvar mu4e-headers-seen-mark (purecopy '("S" . "✔")) "Seen.")
|
|
|
|
|
(defvar mu4e-headers-trashed-mark (purecopy '("T" . "♻")) "Trashed.")
|
|
|
|
|
(defvar mu4e-headers-attach-mark (purecopy '("a" . "⚓")) "W/ attachments.")
|
|
|
|
|
(defvar mu4e-headers-encrypted-mark (purecopy '("x" . "⚴")) "Encrypted.")
|
|
|
|
|
(defvar mu4e-headers-signed-mark (purecopy '("s" . "☡")) "Signed.")
|
|
|
|
|
(defvar mu4e-headers-unread-mark (purecopy '("u" . "☐")) "Unread.")
|
2012-08-27 17:04:58 +02:00
|
|
|
|
|
|
|
|
|
;; thread prefix marks
|
2012-09-28 16:11:12 +02:00
|
|
|
|
(defvar mu4e-headers-has-child-prefix (purecopy '("+" . "◼")) "Parent.")
|
|
|
|
|
(defvar mu4e-headers-empty-parent-prefix (purecopy '("-" . "◽")) "Orphan.")
|
|
|
|
|
(defvar mu4e-headers-first-child-prefix (purecopy '("\\" . "┗▶")) "First child.")
|
|
|
|
|
(defvar mu4e-headers-duplicate-prefix (purecopy '("=" . "⚌")) "Duplicate.")
|
|
|
|
|
(defvar mu4e-headers-default-prefix (purecopy '("|" . "┃")) "Default.")
|
2012-08-27 17:04:58 +02:00
|
|
|
|
|
|
|
|
|
|
2012-04-24 17:13:12 +02:00
|
|
|
|
(defvar mu4e-headers-actions
|
2012-06-11 15:40:23 +02:00
|
|
|
|
'( ("capture message" . mu4e-action-capture-message))
|
2012-04-24 17:13:12 +02:00
|
|
|
|
"List of actions to perform on messages in the headers list. The actions
|
|
|
|
|
are of the form:
|
|
|
|
|
(NAME SHORTCUT FUNC) where:
|
|
|
|
|
* NAME is the name of the action (e.g. \"Count lines\")
|
|
|
|
|
* SHORTCUT is a one-character shortcut to call this action
|
|
|
|
|
* FUNC is a function which receives a message plist as an argument.")
|
2012-06-10 10:19:51 +02:00
|
|
|
|
|
2012-06-14 20:54:24 +02:00
|
|
|
|
(defvar mu4e-headers-custom-markers
|
|
|
|
|
'(("Older than"
|
|
|
|
|
(lambda (msg date) (time-less-p (mu4e-msg-field msg :date) date))
|
|
|
|
|
(lambda () (mu4e-get-time-date "Match messages before: ")))
|
|
|
|
|
("Newer than"
|
|
|
|
|
(lambda (msg date) (time-less-p date (mu4e-msg-field msg :date)))
|
|
|
|
|
(lambda () (mu4e-get-time-date "Match messages after: ")))
|
|
|
|
|
("Bigger than"
|
|
|
|
|
(lambda (msg bytes) (> (mu4e-msg-field msg :size) (* 1024 bytes)))
|
|
|
|
|
(lambda () (read-number "Match messages bigger than (Kbytes): "))))
|
|
|
|
|
"List of custom markers -- functions to mark message that match
|
|
|
|
|
some custom function. Each of the list members has the following format:
|
|
|
|
|
(NAME PREDICATE-FUNC PARAM-FUNC)
|
|
|
|
|
* NAME is the name of the predicate function, and the first character
|
|
|
|
|
is the shortcut (so keep those unique).
|
2012-07-10 18:15:13 +02:00
|
|
|
|
* PREDICATE-FUNC is a function that takes two parameters, MSG
|
|
|
|
|
and (optionally) PARAM, and should return non-nil when there's a
|
|
|
|
|
match.
|
2012-06-14 20:54:24 +02:00
|
|
|
|
* PARAM-FUNC is function that is evaluated once, and its value is then passed to
|
|
|
|
|
PREDICATE-FUNC as PARAM. This is useful for getting user-input.")
|
|
|
|
|
|
2012-07-11 09:21:09 +02:00
|
|
|
|
(defvar mu4e-headers-sortfield :date
|
2012-06-10 10:19:51 +02:00
|
|
|
|
"Field to sort the headers by. Field must be a symbol, one of:
|
2012-10-19 11:02:13 +02:00
|
|
|
|
:date, :subject, :size, :prio, :from, :to.")
|
2012-06-10 10:19:51 +02:00
|
|
|
|
|
|
|
|
|
(defvar mu4e-headers-sort-revert t
|
|
|
|
|
"Whether to revert the sort-order, i.e. Z->A instead of A-Z. When
|
2012-10-02 23:06:25 +02:00
|
|
|
|
sorting by date, it's useful to go from biggest to smallest, so
|
|
|
|
|
newest messages come first.")
|
2012-06-10 10:19:51 +02:00
|
|
|
|
|
|
|
|
|
(defvar mu4e-headers-show-threads t
|
|
|
|
|
"Whether to show threads in the headers list.")
|
2012-04-24 17:13:12 +02:00
|
|
|
|
|
2012-06-10 12:24:41 +02:00
|
|
|
|
(defvar mu4e-headers-full-search nil
|
|
|
|
|
"Whether to show all results (or just up to
|
|
|
|
|
`mu4e-search-results-limit')")
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
2012-04-24 17:13:12 +02:00
|
|
|
|
|
|
|
|
|
|
2011-09-12 19:52:32 +02:00
|
|
|
|
;;;; internal variables/constants ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
2012-04-28 08:08:28 +02:00
|
|
|
|
|
|
|
|
|
;; docid cookies
|
2012-09-16 20:46:47 +02:00
|
|
|
|
(defconst mu4e~headers-docid-pre (purecopy "\376")
|
2012-05-02 16:22:45 +02:00
|
|
|
|
"Each header starts (invisibly) with the `mu4e~headers-docid-pre',
|
|
|
|
|
followed by the docid, followed by `mu4e~headers-docid-post'.")
|
2012-09-16 20:46:47 +02:00
|
|
|
|
(defconst mu4e~headers-docid-post (purecopy "\377")
|
2012-05-02 16:22:45 +02:00
|
|
|
|
"Each header starts (invisibly) with the `mu4e~headers-docid-pre',
|
|
|
|
|
followed by the docid, followed by `mu4e~headers-docid-post'.")
|
2012-04-24 20:12:15 +02:00
|
|
|
|
|
2012-05-20 18:59:57 +02:00
|
|
|
|
(defvar mu4e~headers-view-win nil
|
|
|
|
|
"The view window connected to this headers view.")
|
2012-08-01 09:48:56 +02:00
|
|
|
|
|
2012-06-10 10:19:51 +02:00
|
|
|
|
(defvar mu4e~headers-sortfield-choices
|
2012-07-11 09:21:09 +02:00
|
|
|
|
'( ("date" . :date)
|
|
|
|
|
("from" . :from)
|
|
|
|
|
("prio" . :prio)
|
|
|
|
|
("zsize" . :size)
|
|
|
|
|
("subject" . :subject)
|
|
|
|
|
("to" . :to))
|
2012-06-10 10:19:51 +02:00
|
|
|
|
"List of cells describing the various sort-options (in the format
|
|
|
|
|
needed for `mu4e-read-option'.")
|
2012-08-01 09:48:56 +02:00
|
|
|
|
|
2012-06-10 10:19:51 +02:00
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
2012-05-20 18:59:57 +02:00
|
|
|
|
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(defun mu4e~headers-clear ()
|
2012-03-25 12:28:06 +02:00
|
|
|
|
"Clear the header buffer and related data structures."
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(when (buffer-live-p mu4e~headers-buffer)
|
2012-03-25 12:28:06 +02:00
|
|
|
|
(let ((inhibit-read-only t))
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(with-current-buffer mu4e~headers-buffer
|
2012-03-25 12:28:06 +02:00
|
|
|
|
(erase-buffer)
|
2012-06-11 11:03:37 +02:00
|
|
|
|
(mu4e~mark-clear)))))
|
2012-03-25 12:28:06 +02:00
|
|
|
|
|
2011-09-18 13:39:36 +02:00
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
;; handler functions
|
|
|
|
|
;;
|
2012-04-23 19:35:14 +02:00
|
|
|
|
;; next are a bunch of handler functions; those will be called from mu4e~proc in
|
2011-09-18 13:39:36 +02:00
|
|
|
|
;; response to output from the server process
|
|
|
|
|
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(defun mu4e~headers-view-handler (msg)
|
2011-09-18 13:39:36 +02:00
|
|
|
|
"Handler function for displaying a message."
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(mu4e-view msg mu4e~headers-buffer))
|
2011-09-12 19:52:32 +02:00
|
|
|
|
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(defun mu4e~headers-update-handler (msg is-move)
|
2011-09-18 13:39:36 +02:00
|
|
|
|
"Update handler, will be called when a message has been updated
|
|
|
|
|
in the database. This function will update the current list of
|
|
|
|
|
headers."
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(when (buffer-live-p mu4e~headers-buffer)
|
|
|
|
|
(with-current-buffer mu4e~headers-buffer
|
2012-09-26 11:25:38 +02:00
|
|
|
|
(let* ((docid (mu4e-message-field msg :docid))
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(point (mu4e~headers-docid-pos docid)))
|
2011-09-22 20:01:35 +02:00
|
|
|
|
(when point ;; is the message present in this list?
|
2012-04-09 22:48:30 +02:00
|
|
|
|
|
2011-09-30 07:37:47 +02:00
|
|
|
|
;; if it's marked, unmark it now
|
2012-04-23 18:07:20 +02:00
|
|
|
|
(when (mu4e-mark-docid-marked-p docid)
|
|
|
|
|
(mu4e-mark-set 'unmark))
|
2012-04-09 22:48:30 +02:00
|
|
|
|
|
2012-04-11 01:08:02 +02:00
|
|
|
|
;; re-use the thread info from the old one; this is needed because
|
2012-05-06 20:38:29 +02:00
|
|
|
|
;; *update* messages don't have thread info by themselves (unlike
|
2012-04-11 01:08:02 +02:00
|
|
|
|
;; search results)
|
2012-05-06 20:38:29 +02:00
|
|
|
|
;; since we still have the search results, re-use
|
|
|
|
|
;; those
|
2012-04-11 01:08:02 +02:00
|
|
|
|
(plist-put msg :thread
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(mu4e~headers-field-for-docid docid :thread))
|
2012-04-11 01:08:02 +02:00
|
|
|
|
|
2012-03-25 12:28:06 +02:00
|
|
|
|
;; first, remove the old one (otherwise, we'd have two headers with
|
2011-09-30 07:37:47 +02:00
|
|
|
|
;; the same docid...
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(mu4e~headers-remove-handler docid)
|
2011-11-20 09:31:38 +01:00
|
|
|
|
|
2011-12-13 08:07:38 +01:00
|
|
|
|
;; if we we're actually viewing this message (in mu4e-view mode), we
|
2012-04-29 21:04:35 +02:00
|
|
|
|
;; update it; that way, the flags can be updated, as well as the path
|
|
|
|
|
;; (which is useful for viewing the raw message)
|
|
|
|
|
(let ((viewbuf (get-buffer mu4e~view-buffer-name)))
|
2011-11-20 09:31:38 +01:00
|
|
|
|
(when (and viewbuf (buffer-live-p viewbuf))
|
|
|
|
|
(with-current-buffer viewbuf
|
2012-04-29 21:04:35 +02:00
|
|
|
|
(when (eq docid (plist-get mu4e~view-msg :docid))
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(mu4e-view msg mu4e~headers-buffer)))))
|
2011-11-20 09:31:38 +01:00
|
|
|
|
|
2011-09-30 07:37:47 +02:00
|
|
|
|
;; now, if this update was about *moving* a message, we don't show it
|
|
|
|
|
;; anymore (of course, we cannot be sure if the message really no
|
|
|
|
|
;; longer matches the query, but this seem a good heuristic.
|
|
|
|
|
;; if it was only a flag-change, show the message with its updated flags.
|
|
|
|
|
(unless is-move
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(mu4e~headers-header-handler msg point))
|
2012-04-09 22:48:30 +02:00
|
|
|
|
|
|
|
|
|
;; attempt to highlight the corresponding line and make it visible
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(mu4e~headers-highlight docid))))))
|
2011-09-30 07:37:47 +02:00
|
|
|
|
|
2011-09-18 13:39:36 +02:00
|
|
|
|
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(defun mu4e~headers-remove-handler (docid)
|
2012-04-24 20:12:15 +02:00
|
|
|
|
"Remove handler, will be called when a message with DOCID has
|
|
|
|
|
been removed from the database. This function will hide the removed
|
|
|
|
|
message from the current list of headers. If the message is not
|
|
|
|
|
present, don't do anything."
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(when (buffer-live-p mu4e~headers-buffer)
|
|
|
|
|
(with-current-buffer mu4e~headers-buffer
|
|
|
|
|
(mu4e~headers-remove-header docid t))))
|
2011-09-12 19:52:32 +02:00
|
|
|
|
|
2011-11-23 23:15:34 +01:00
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
2011-09-20 22:59:20 +02:00
|
|
|
|
|
2012-08-28 11:10:56 +02:00
|
|
|
|
(defsubst mu4e~headers-contact-str (contacts)
|
2011-11-09 07:35:24 +01:00
|
|
|
|
"Turn the list of contacts CONTACTS (with elements (NAME . EMAIL)
|
|
|
|
|
into a string."
|
|
|
|
|
(mapconcat
|
|
|
|
|
(lambda (ct)
|
|
|
|
|
(let ((name (car ct)) (email (cdr ct)))
|
|
|
|
|
(or name email "?"))) contacts ", "))
|
|
|
|
|
|
2012-08-27 17:04:58 +02:00
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
(defsubst mu4e~headers-thread-prefix (thread)
|
2011-11-20 00:19:07 +01:00
|
|
|
|
"Calculate the thread prefix based on thread info THREAD."
|
2012-08-27 17:04:58 +02:00
|
|
|
|
(when thread
|
|
|
|
|
(let ((get-prefix
|
2012-08-28 11:10:56 +02:00
|
|
|
|
(lambda (cell) (if mu4e-use-fancy-chars (cdr cell) (car cell)))))
|
2011-11-20 00:19:07 +01:00
|
|
|
|
(concat
|
2012-08-27 17:04:58 +02:00
|
|
|
|
(make-string (* (if (plist-get thread :empty-parent) 0 2)
|
|
|
|
|
(plist-get thread :level)) ?\s)
|
2011-11-20 00:19:07 +01:00
|
|
|
|
(cond
|
2012-09-15 20:10:46 +02:00
|
|
|
|
((plist-get thread :has-child)
|
|
|
|
|
(funcall get-prefix mu4e-headers-has-child-prefix))
|
|
|
|
|
((plist-get thread :empty-parent)
|
|
|
|
|
(funcall get-prefix mu4e-headers-empty-parent-prefix))
|
|
|
|
|
((plist-get thread :first-child)
|
|
|
|
|
(funcall get-prefix mu4e-headers-first-child-prefix))
|
|
|
|
|
((plist-get thread :duplicate)
|
|
|
|
|
(funcall get-prefix mu4e-headers-duplicate-prefix))
|
|
|
|
|
(t
|
|
|
|
|
(funcall get-prefix mu4e-headers-default-prefix)))
|
2012-08-27 17:04:58 +02:00
|
|
|
|
" "))))
|
|
|
|
|
|
|
|
|
|
(defsubst mu4e~headers-flags-str (flags)
|
|
|
|
|
"Get a display string for the flags; note, there is
|
|
|
|
|
`mu4e-flags-to-string' but that is for internal use; this function
|
|
|
|
|
is for display. (This difference is significant, since internally,
|
|
|
|
|
the Maildir spec determines what the flags look like, while our
|
|
|
|
|
display may be different)."
|
|
|
|
|
(let ((str)
|
|
|
|
|
(get-prefix
|
2012-08-28 11:10:56 +02:00
|
|
|
|
(lambda (cell) (if mu4e-use-fancy-chars (cdr cell) (car cell)))))
|
2012-08-27 17:04:58 +02:00
|
|
|
|
(dolist (flag flags)
|
|
|
|
|
(setq str
|
|
|
|
|
(concat str
|
|
|
|
|
(case flag
|
|
|
|
|
('draft (funcall get-prefix mu4e-headers-draft-mark))
|
|
|
|
|
('flagged (funcall get-prefix mu4e-headers-flagged-mark))
|
|
|
|
|
('new (funcall get-prefix mu4e-headers-new-mark))
|
|
|
|
|
('passed (funcall get-prefix mu4e-headers-passed-mark))
|
|
|
|
|
('replied (funcall get-prefix mu4e-headers-replied-mark))
|
|
|
|
|
('seen (funcall get-prefix mu4e-headers-seen-mark))
|
|
|
|
|
('trashed (funcall get-prefix mu4e-headers-trashed-mark))
|
|
|
|
|
('attach (funcall get-prefix mu4e-headers-attach-mark))
|
|
|
|
|
('encrypted (funcall get-prefix mu4e-headers-encrypted-mark))
|
|
|
|
|
('signed (funcall get-prefix mu4e-headers-signed-mark))
|
|
|
|
|
('unread (funcall get-prefix mu4e-headers-unread-mark))))))
|
|
|
|
|
str))
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
|
2011-11-09 07:35:24 +01:00
|
|
|
|
|
2012-05-13 12:12:03 +02:00
|
|
|
|
(defconst mu4e-headers-from-or-to-prefix '("" . "To ")
|
|
|
|
|
"Prefix for the :from-or-to field when it is showing,
|
|
|
|
|
respectively, From: or To:. It's a cons cell with the car element
|
|
|
|
|
being the From: prefix, the cdr element the To: prefix.")
|
2012-05-04 07:58:02 +02:00
|
|
|
|
|
2012-09-15 20:10:46 +02:00
|
|
|
|
(defsubst mu4e~headers-from-or-to (msg)
|
2012-10-19 15:01:55 +02:00
|
|
|
|
"When the from address for message MSG is one of the the user's addresses,
|
|
|
|
|
(as per `mu4e-user-mail-address-list'), show the To address;
|
|
|
|
|
otherwise ; show the from address; prefixed with the appropriate
|
2012-09-15 20:10:46 +02:00
|
|
|
|
`mu4e-headers-from-or-to-prefix'."
|
2012-09-26 11:25:38 +02:00
|
|
|
|
(let ((addr (cdr-safe (car-safe (mu4e-message-field msg :from)))))
|
2012-10-19 15:01:55 +02:00
|
|
|
|
(if (mu4e-user-mail-address-p addr)
|
2012-09-15 20:10:46 +02:00
|
|
|
|
(concat (cdr mu4e-headers-from-or-to-prefix)
|
2012-09-26 11:25:38 +02:00
|
|
|
|
(mu4e~headers-contact-str (mu4e-message-field msg :to)))
|
2012-09-15 20:10:46 +02:00
|
|
|
|
(concat (car mu4e-headers-from-or-to-prefix)
|
2012-09-26 11:25:38 +02:00
|
|
|
|
(mu4e~headers-contact-str (mu4e-message-field msg :from))))))
|
2012-09-15 20:10:46 +02:00
|
|
|
|
|
2012-10-19 11:02:13 +02:00
|
|
|
|
(defsubst mu4e~headers-human-date (msg)
|
|
|
|
|
"Show a 'human' date -- that is, if the date is today, show the
|
2012-10-22 19:27:14 +02:00
|
|
|
|
date, otherwise, show the time. The formats used for date and time
|
|
|
|
|
are `mu4e-headers-date-format' and `mu4e-headers-time-format'."
|
2012-10-19 11:02:13 +02:00
|
|
|
|
(let ((date (mu4e-msg-field msg :date)))
|
|
|
|
|
(if (= (nth 3 (decode-time date)) (nth 3 (decode-time (current-time))))
|
|
|
|
|
(format-time-string mu4e-headers-time-format date)
|
|
|
|
|
(format-time-string mu4e-headers-date-format date))))
|
|
|
|
|
|
|
|
|
|
;; note: this function is very performance-sensitive
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(defun mu4e~headers-header-handler (msg &optional point)
|
2012-10-19 11:02:13 +02:00
|
|
|
|
"Create a one line description of MSG in this buffer, at POINT,
|
2011-09-30 07:37:47 +02:00
|
|
|
|
if provided, or at the end of the buffer otherwise."
|
2012-10-19 11:02:13 +02:00
|
|
|
|
(let ((docid (mu4e-message-field msg :docid)) (line ""))
|
|
|
|
|
(dolist (f-w mu4e-headers-fields)
|
|
|
|
|
(let ((field (car f-w)) (width (cdr f-w))
|
|
|
|
|
(val (mu4e-message-field msg (car f-w))) (str))
|
|
|
|
|
(setq str
|
|
|
|
|
(case field
|
|
|
|
|
(:subject
|
|
|
|
|
(concat ;; prefix subject with a thread indicator
|
|
|
|
|
(mu4e~headers-thread-prefix (mu4e-message-field msg :thread))
|
|
|
|
|
;; "["(plist-get (mu4e-message-field msg :thread) :path) "] "
|
|
|
|
|
val))
|
|
|
|
|
((:maildir :path) val)
|
|
|
|
|
((:to :from :cc :bcc) (mu4e~headers-contact-str val))
|
|
|
|
|
;; if we (ie. `user-mail-address' is the 'From', show
|
|
|
|
|
;; 'To', otherwise show From
|
|
|
|
|
(:from-or-to (mu4e~headers-from-or-to msg))
|
|
|
|
|
(:date (format-time-string mu4e-headers-date-format val))
|
|
|
|
|
(:human-date (mu4e~headers-human-date msg))
|
|
|
|
|
(:flags (propertize (mu4e~headers-flags-str val)
|
|
|
|
|
'help-echo (format "%S" val)))
|
|
|
|
|
(:size (mu4e-display-size val))
|
|
|
|
|
(t (mu4e-error "Unsupported header field (%S)" field))))
|
|
|
|
|
(when str
|
|
|
|
|
(setq line
|
|
|
|
|
(concat line
|
|
|
|
|
(if (not width)
|
|
|
|
|
str
|
|
|
|
|
(truncate-string-to-width str width 0 ?\s t)) " ")))))
|
|
|
|
|
;; now, propertize it.
|
|
|
|
|
(setq line (propertize line 'face
|
|
|
|
|
(case (car-safe (mu4e-message-field msg :flags))
|
|
|
|
|
('draft 'mu4e-draft-face)
|
|
|
|
|
('trash 'mu4e-trashed-face)
|
|
|
|
|
((unread new) 'mu4e-unread-face)
|
|
|
|
|
('flagged 'mu4e-flagged-face)
|
|
|
|
|
((replied passed) 'mu4e-replied-face)
|
|
|
|
|
(t 'mu4e-header-face))))
|
|
|
|
|
;; now, append the header line
|
2012-10-22 19:27:14 +02:00
|
|
|
|
(mu4e~headers-add-header line docid point msg)))
|
2011-10-25 07:43:24 +02:00
|
|
|
|
|
2012-09-16 20:46:47 +02:00
|
|
|
|
(defconst mu4e~no-matches (purecopy "No matching messages found"))
|
|
|
|
|
(defconst mu4e~end-of-results (purecopy "End of search results"))
|
|
|
|
|
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(defun mu4e~headers-found-handler (count)
|
2011-10-25 07:43:24 +02:00
|
|
|
|
"Create a one line description of the number of headers found
|
|
|
|
|
after the end of the search results."
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(when (buffer-live-p mu4e~headers-buffer)
|
|
|
|
|
(with-current-buffer mu4e~headers-buffer
|
2011-10-25 07:43:24 +02:00
|
|
|
|
(save-excursion
|
|
|
|
|
(goto-char (point-max))
|
2012-03-28 18:00:10 +02:00
|
|
|
|
(let ((inhibit-read-only t)
|
|
|
|
|
(str (if (= 0 count)
|
2012-09-16 20:46:47 +02:00
|
|
|
|
mu4e~no-matches
|
|
|
|
|
mu4e~end-of-results)))
|
2012-03-28 18:00:10 +02:00
|
|
|
|
(insert (propertize str 'face 'mu4e-system-face 'intangible t))
|
|
|
|
|
(unless (= 0 count)
|
2012-05-02 16:22:45 +02:00
|
|
|
|
(mu4e-message "Found %d matching message%s"
|
2012-04-09 15:34:52 +02:00
|
|
|
|
count (if (= 1 count) "" "s"))
|
|
|
|
|
;; highlight the first message
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(mu4e~headers-highlight (mu4e~headers-docid-at-point (point-min)))))))))
|
2011-09-12 19:52:32 +02:00
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
2012-06-15 10:46:11 +02:00
|
|
|
|
|
2012-06-14 18:10:02 +02:00
|
|
|
|
|
2012-09-27 20:53:21 +02:00
|
|
|
|
(defmacro mu4e~headers-defun-mark-for (mark)
|
2012-06-14 18:10:02 +02:00
|
|
|
|
"Define a function mu4e~headers-mark-MARK."
|
2012-09-27 20:53:21 +02:00
|
|
|
|
(let ((funcname (intern (concat "mu4e-headers-mark-for-" (symbol-name mark))))
|
2012-06-14 18:10:02 +02:00
|
|
|
|
(docstring (concat "Mark header at point with " (symbol-name mark) ".")))
|
|
|
|
|
`(defun ,funcname () ,docstring
|
|
|
|
|
(interactive)
|
|
|
|
|
(mu4e-headers-mark-and-next (quote ,mark)))))
|
2012-06-15 10:46:11 +02:00
|
|
|
|
|
2012-06-14 18:10:02 +02:00
|
|
|
|
;; define our mark functions; there must be some way to do this in a loop but
|
|
|
|
|
;; since `mu4e~headers-defun-mark-func' is a macro, the argument must be a
|
|
|
|
|
;; literal value.
|
2012-09-27 20:53:21 +02:00
|
|
|
|
(mu4e~headers-defun-mark-for refile)
|
2012-10-06 19:47:59 +02:00
|
|
|
|
(mu4e~headers-defun-mark-for something)
|
2012-09-27 20:53:21 +02:00
|
|
|
|
(mu4e~headers-defun-mark-for delete)
|
|
|
|
|
(mu4e~headers-defun-mark-for flag)
|
|
|
|
|
(mu4e~headers-defun-mark-for move)
|
|
|
|
|
(mu4e~headers-defun-mark-for read)
|
|
|
|
|
(mu4e~headers-defun-mark-for trash)
|
|
|
|
|
(mu4e~headers-defun-mark-for unflag)
|
|
|
|
|
(mu4e~headers-defun-mark-for unmark)
|
|
|
|
|
(mu4e~headers-defun-mark-for unread)
|
2011-09-12 19:52:32 +02:00
|
|
|
|
|
2012-05-12 08:58:29 +02:00
|
|
|
|
|
2012-05-06 15:55:14 +02:00
|
|
|
|
;;; headers-mode and mode-map ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(defvar mu4e-headers-mode-map nil
|
2011-12-13 08:07:38 +01:00
|
|
|
|
"Keymap for *mu4e-headers* buffers.")
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(unless mu4e-headers-mode-map
|
|
|
|
|
(setq mu4e-headers-mode-map
|
2011-10-18 11:39:49 +02:00
|
|
|
|
(let ((map (make-sparse-keymap)))
|
|
|
|
|
|
2012-05-02 16:22:45 +02:00
|
|
|
|
(define-key map "s" 'mu4e-headers-search)
|
2012-06-07 15:30:33 +02:00
|
|
|
|
(define-key map "S" 'mu4e-headers-search-edit)
|
2012-05-07 09:05:31 +02:00
|
|
|
|
|
2012-07-18 13:48:28 +02:00
|
|
|
|
(define-key map "/" 'mu4e-headers-search-narrow)
|
2012-08-01 09:48:56 +02:00
|
|
|
|
|
2012-05-10 08:55:28 +02:00
|
|
|
|
(define-key map "j" 'mu4e~headers-jump-to-maildir)
|
2012-05-12 08:58:29 +02:00
|
|
|
|
|
2012-05-07 09:05:31 +02:00
|
|
|
|
(define-key map (kbd "<M-left>") 'mu4e-headers-query-prev)
|
2012-07-18 13:48:28 +02:00
|
|
|
|
(define-key map (kbd "\\") 'mu4e-headers-query-prev)
|
2012-05-07 09:05:31 +02:00
|
|
|
|
(define-key map (kbd "<M-right>") 'mu4e-headers-query-next)
|
2012-08-01 09:48:56 +02:00
|
|
|
|
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(define-key map "b" 'mu4e-headers-search-bookmark)
|
2012-05-05 10:07:58 +02:00
|
|
|
|
(define-key map "B" 'mu4e-headers-search-bookmark-edit)
|
2012-05-12 08:58:29 +02:00
|
|
|
|
|
2012-06-10 10:19:51 +02:00
|
|
|
|
(define-key map "O" 'mu4e-headers-change-sorting)
|
|
|
|
|
(define-key map "P" 'mu4e-headers-toggle-threading)
|
2012-06-10 12:24:41 +02:00
|
|
|
|
(define-key map "Q" 'mu4e-headers-toggle-full-search)
|
2012-06-10 10:19:51 +02:00
|
|
|
|
|
2012-06-11 11:03:37 +02:00
|
|
|
|
(define-key map "q" 'mu4e~headers-quit-buffer)
|
|
|
|
|
(define-key map "z" 'mu4e~headers-quit-buffer)
|
2012-04-11 01:08:02 +02:00
|
|
|
|
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(define-key map "r" 'mu4e-headers-rerun-search)
|
|
|
|
|
(define-key map "g" 'mu4e-headers-rerun-search) ;; for compatibility
|
2012-05-12 08:58:29 +02:00
|
|
|
|
|
2012-05-10 08:55:28 +02:00
|
|
|
|
(define-key map "%" 'mu4e-headers-mark-pattern)
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(define-key map "t" 'mu4e-headers-mark-subthread)
|
|
|
|
|
(define-key map "T" 'mu4e-headers-mark-thread)
|
2012-04-28 08:08:28 +02:00
|
|
|
|
|
2012-04-11 01:08:02 +02:00
|
|
|
|
|
2012-05-11 09:27:06 +02:00
|
|
|
|
;; navigation between messages
|
|
|
|
|
(define-key map "p" 'mu4e-headers-prev)
|
|
|
|
|
(define-key map "n" 'mu4e-headers-next)
|
|
|
|
|
(define-key map (kbd "<M-up>") 'mu4e-headers-prev)
|
|
|
|
|
(define-key map (kbd "<M-down>") 'mu4e-headers-next)
|
|
|
|
|
|
2012-05-14 09:45:39 +02:00
|
|
|
|
;; change the number of headers
|
|
|
|
|
(define-key map (kbd "C-+") 'mu4e-headers-split-view-resize)
|
|
|
|
|
(define-key map (kbd "C--")
|
|
|
|
|
(lambda () (interactive) (mu4e-headers-split-view-resize -1)))
|
|
|
|
|
(define-key map (kbd "<C-kp-add>") 'mu4e-headers-split-view-resize)
|
|
|
|
|
(define-key map (kbd "<C-kp-subtract>")
|
|
|
|
|
(lambda () (interactive) (mu4e-headers-split-view-resize -1)))
|
2012-05-12 08:58:29 +02:00
|
|
|
|
|
2012-05-16 19:47:13 +02:00
|
|
|
|
|
2012-04-09 10:51:24 +02:00
|
|
|
|
;; switching to view mode (if it's visible)
|
|
|
|
|
(define-key map "y" 'mu4e-select-other-view)
|
2012-04-11 01:08:02 +02:00
|
|
|
|
|
2012-04-23 18:07:20 +02:00
|
|
|
|
;; marking/unmarking ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
2012-09-27 20:53:21 +02:00
|
|
|
|
(define-key map (kbd "<backspace>") 'mu4e-headers-mark-for-trash)
|
|
|
|
|
(define-key map (kbd "d") 'mu4e-headers-mark-for-trash)
|
|
|
|
|
(define-key map (kbd "<delete>") 'mu4e-headers-mark-for-delete)
|
|
|
|
|
(define-key map (kbd "<deletechar>") 'mu4e-headers-mark-for-delete)
|
|
|
|
|
(define-key map (kbd "D") 'mu4e-headers-mark-for-delete)
|
|
|
|
|
(define-key map (kbd "m") 'mu4e-headers-mark-for-move)
|
|
|
|
|
(define-key map (kbd "r") 'mu4e-headers-mark-for-refile)
|
2012-10-22 19:27:14 +02:00
|
|
|
|
|
2012-09-28 16:11:12 +02:00
|
|
|
|
(define-key map (kbd "?") 'mu4e-headers-mark-for-unread)
|
|
|
|
|
(define-key map (kbd "!") 'mu4e-headers-mark-for-read)
|
2012-10-22 19:27:14 +02:00
|
|
|
|
|
2012-09-27 20:53:21 +02:00
|
|
|
|
(define-key map (kbd "u") 'mu4e-headers-mark-for-unmark)
|
|
|
|
|
(define-key map (kbd "+") 'mu4e-headers-mark-for-flag)
|
|
|
|
|
(define-key map (kbd "-") 'mu4e-headers-mark-for-unflag)
|
|
|
|
|
(define-key map (kbd "&") 'mu4e-headers-mark-for-custom)
|
|
|
|
|
|
2012-10-06 19:47:59 +02:00
|
|
|
|
;; (define-key map (kbd "*") 'mu4e-headers-mark-for-something)
|
|
|
|
|
;; (define-key map (kbd "<kp-multiply>") 'mu4e-headers-mark-for-something)
|
|
|
|
|
|
|
|
|
|
(define-key map (kbd "<insertchar>") 'mu4e-headers-mark-for-something)
|
|
|
|
|
(define-key map (kbd "<insert>") 'mu4e-headers-mark-for-something)
|
|
|
|
|
|
2012-10-22 19:27:14 +02:00
|
|
|
|
|
2012-06-14 18:10:02 +02:00
|
|
|
|
(define-key map (kbd "#") 'mu4e-mark-resolve-deferred-marks)
|
2012-06-15 10:46:11 +02:00
|
|
|
|
|
2012-04-23 18:07:20 +02:00
|
|
|
|
(define-key map "U" 'mu4e-mark-unmark-all)
|
|
|
|
|
(define-key map "x" 'mu4e-mark-execute-all)
|
2012-05-10 08:55:28 +02:00
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
2012-04-28 08:08:28 +02:00
|
|
|
|
|
2012-09-27 11:53:16 +02:00
|
|
|
|
(define-key map "A" 'mu4e-headers-action)
|
2012-04-28 08:08:28 +02:00
|
|
|
|
|
2011-10-18 11:39:49 +02:00
|
|
|
|
;; message composition
|
2011-12-15 07:51:39 +01:00
|
|
|
|
(define-key map "R" 'mu4e-compose-reply)
|
|
|
|
|
(define-key map "F" 'mu4e-compose-forward)
|
|
|
|
|
(define-key map "C" 'mu4e-compose-new)
|
2012-03-25 12:28:06 +02:00
|
|
|
|
(define-key map "E" 'mu4e-compose-edit)
|
2011-10-18 11:39:49 +02:00
|
|
|
|
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(define-key map (kbd "RET") 'mu4e-headers-view-message)
|
|
|
|
|
(define-key map [mouse-2] 'mu4e-headers-view-message)
|
2011-12-26 11:18:12 +01:00
|
|
|
|
|
2012-04-16 17:31:48 +02:00
|
|
|
|
(define-key map "$" 'mu4e-show-log)
|
2011-12-15 07:51:39 +01:00
|
|
|
|
(define-key map "H" 'mu4e-display-manual)
|
2011-10-18 11:39:49 +02:00
|
|
|
|
|
|
|
|
|
;; menu
|
|
|
|
|
(define-key map [menu-bar] (make-sparse-keymap))
|
|
|
|
|
(let ((menumap (make-sparse-keymap "Headers")))
|
|
|
|
|
(define-key map [menu-bar headers] (cons "Headers" menumap))
|
|
|
|
|
|
2012-06-11 11:03:37 +02:00
|
|
|
|
(define-key menumap [mu4e~headers-quit-buffer]
|
|
|
|
|
'("Quit view" . mu4e~headers-quit-buffer))
|
2011-12-15 07:51:39 +01:00
|
|
|
|
(define-key menumap [display-help] '("Help" . mu4e-display-manual))
|
|
|
|
|
|
2011-10-18 11:39:49 +02:00
|
|
|
|
(define-key menumap [sepa0] '("--"))
|
2012-04-28 08:08:28 +02:00
|
|
|
|
|
2012-04-23 18:07:20 +02:00
|
|
|
|
(define-key menumap [execute-marks] '("Execute marks"
|
|
|
|
|
. mu4e-mark-execute-all))
|
|
|
|
|
(define-key menumap [unmark-all] '("Unmark all" . mu4e-mark-unmark-all))
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(define-key menumap [unmark] '("Unmark" . mu4e~headers-mark-unmark))
|
2011-10-18 11:39:49 +02:00
|
|
|
|
|
2012-06-10 10:19:51 +02:00
|
|
|
|
(define-key menumap [mark-pattern] '("Mark pattern" .
|
|
|
|
|
mu4e-headers-mark-pattern))
|
|
|
|
|
(define-key menumap [mark-as-read] '("Mark as read" .
|
|
|
|
|
mu4e~headers-mark-read))
|
2012-02-27 22:41:11 +01:00
|
|
|
|
(define-key menumap [mark-as-unread]
|
2012-05-01 21:45:54 +02:00
|
|
|
|
'("Mark as unread" . mu4e~headers-mark-unread))
|
2012-02-09 20:10:33 +01:00
|
|
|
|
|
2012-02-27 22:41:11 +01:00
|
|
|
|
(define-key menumap [mark-delete]
|
2012-05-01 21:45:54 +02:00
|
|
|
|
'("Mark for deletion" . mu4e~headers-mark-delete))
|
2012-04-23 18:07:20 +02:00
|
|
|
|
(define-key menumap [mark-trash]
|
2012-05-01 21:45:54 +02:00
|
|
|
|
'("Mark for trash" . mu4e~headers-mark-trash))
|
2012-04-23 18:07:20 +02:00
|
|
|
|
(define-key menumap [mark-move]
|
2012-09-27 11:01:26 +02:00
|
|
|
|
'("Mark for move" . mu4e~headers-mark-move))
|
2011-10-18 11:39:49 +02:00
|
|
|
|
(define-key menumap [sepa1] '("--"))
|
|
|
|
|
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(define-key menumap [compose-new] '("Compose new" . mu4e-compose-new))
|
|
|
|
|
(define-key menumap [forward] '("Forward" . mu4e-compose-forward))
|
|
|
|
|
(define-key menumap [reply] '("Reply" . mu4e-compose-reply))
|
2011-10-18 11:39:49 +02:00
|
|
|
|
(define-key menumap [sepa2] '("--"))
|
|
|
|
|
|
2012-05-10 08:55:28 +02:00
|
|
|
|
(define-key menumap [query-next] '("Next query" . mu4e-headers-query-next))
|
2012-06-10 10:19:51 +02:00
|
|
|
|
(define-key menumap [query-prev] '("Previous query" .
|
|
|
|
|
mu4e-headers-query-prev))
|
|
|
|
|
(define-key menumap [narrow-search] '("Narrow search" .
|
|
|
|
|
mu4e-headers-search-narrow))
|
|
|
|
|
(define-key menumap [bookmark] '("Search bookmark" .
|
|
|
|
|
mu4e-headers-search-bookmark))
|
|
|
|
|
(define-key menumap [jump] '("Jump to maildir" .
|
|
|
|
|
mu4e~headers-jump-to-maildir))
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(define-key menumap [refresh] '("Refresh" . mu4e-headers-rerun-search))
|
2012-05-02 16:22:45 +02:00
|
|
|
|
(define-key menumap [search] '("Search" . mu4e-headers-search))
|
2011-12-15 07:51:39 +01:00
|
|
|
|
|
2012-05-10 08:55:28 +02:00
|
|
|
|
|
2011-10-18 11:39:49 +02:00
|
|
|
|
(define-key menumap [sepa3] '("--"))
|
2011-10-25 07:43:24 +02:00
|
|
|
|
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(define-key menumap [view] '("View" . mu4e-headers-view-message))
|
|
|
|
|
(define-key menumap [next] '("Next" . mu4e-headers-next))
|
|
|
|
|
(define-key menumap [previous] '("Previous" . mu4e-headers-prev))
|
2011-10-18 11:39:49 +02:00
|
|
|
|
(define-key menumap [sepa4] '("--")))
|
|
|
|
|
map)))
|
|
|
|
|
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(fset 'mu4e-headers-mode-map mu4e-headers-mode-map)
|
2012-09-16 20:46:47 +02:00
|
|
|
|
|
2012-07-11 09:21:09 +02:00
|
|
|
|
(defun mu4e~header-line-format ()
|
|
|
|
|
"Get the format for the header line."
|
|
|
|
|
(cons
|
|
|
|
|
(make-string
|
|
|
|
|
(+ mu4e~mark-fringe-len (floor (fringe-columns 'left t))) ?\s)
|
|
|
|
|
(mapcar
|
|
|
|
|
(lambda (item)
|
|
|
|
|
(let* ((field (car item)) (width (cdr item))
|
|
|
|
|
(info (cdr (assoc field mu4e-header-info)))
|
2012-07-11 10:36:05 +02:00
|
|
|
|
(sortable (plist-get info :sortable))
|
2012-07-11 09:21:09 +02:00
|
|
|
|
(help (plist-get info :help))
|
2012-09-16 20:46:47 +02:00
|
|
|
|
(uparrow (if mu4e-use-fancy-chars " ▲" " ^"))
|
|
|
|
|
(downarrow (if mu4e-use-fancy-chars " ▼" " V"))
|
2012-07-11 09:21:09 +02:00
|
|
|
|
;; triangle to mark the sorted-by column
|
2012-08-28 11:10:56 +02:00
|
|
|
|
(arrow
|
2012-07-11 10:36:05 +02:00
|
|
|
|
(when (and sortable (eq (car item) mu4e-headers-sortfield))
|
2012-08-28 11:10:56 +02:00
|
|
|
|
(if mu4e-headers-sort-revert downarrow uparrow)))
|
2012-09-16 20:46:47 +02:00
|
|
|
|
(name (concat (plist-get info :shortname) arrow))
|
2012-07-11 10:36:05 +02:00
|
|
|
|
(map (make-sparse-keymap)))
|
|
|
|
|
(when sortable
|
|
|
|
|
(define-key map [header-line mouse-1]
|
|
|
|
|
(lambda (&optional e)
|
|
|
|
|
;; getting the field, inspired by `tabulated-list-col-sort'
|
|
|
|
|
(interactive "e")
|
2012-08-01 09:48:56 +02:00
|
|
|
|
(let* ((obj (posn-object (event-start e)))
|
2012-07-11 10:36:05 +02:00
|
|
|
|
(field
|
|
|
|
|
(and obj (get-text-property 0 'field (car obj)))))
|
|
|
|
|
(if (eq field mu4e-headers-sortfield)
|
|
|
|
|
(setq mu4e-headers-sort-revert (not mu4e-headers-sort-revert))
|
2012-09-15 20:10:46 +02:00
|
|
|
|
(setq mu4e-headers-sortfield field)))
|
2012-07-11 10:36:05 +02:00
|
|
|
|
(mu4e-headers-rerun-search))))
|
2012-07-11 09:21:09 +02:00
|
|
|
|
(concat
|
|
|
|
|
(propertize
|
|
|
|
|
(if width
|
|
|
|
|
(truncate-string-to-width name width 0 ?\s t)
|
|
|
|
|
name)
|
2012-09-16 20:46:47 +02:00
|
|
|
|
'face (if arrow 'bold 'fixed-pitch)
|
2012-07-11 09:21:09 +02:00
|
|
|
|
'help-echo help
|
2012-07-11 10:36:05 +02:00
|
|
|
|
'mouse-face (when sortable 'highlight)
|
|
|
|
|
'keymap (when sortable map)
|
|
|
|
|
'field field) " ")))
|
2012-07-11 09:21:09 +02:00
|
|
|
|
mu4e-headers-fields)))
|
2011-10-18 11:39:49 +02:00
|
|
|
|
|
2012-08-01 09:48:56 +02:00
|
|
|
|
|
2012-08-14 09:20:27 +02:00
|
|
|
|
(defvar mu4e-headers-mode-abbrev-table nil)
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(define-derived-mode mu4e-headers-mode special-mode
|
2012-03-27 20:16:32 +02:00
|
|
|
|
"mu4e:headers"
|
2012-01-14 10:05:23 +01:00
|
|
|
|
"Major mode for displaying mu4e search results.
|
2012-05-01 21:45:54 +02:00
|
|
|
|
\\{mu4e-headers-mode-map}."
|
|
|
|
|
(use-local-map mu4e-headers-mode-map)
|
2012-05-05 10:07:58 +02:00
|
|
|
|
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(make-local-variable 'mu4e~headers-proc)
|
2012-05-12 08:58:29 +02:00
|
|
|
|
(make-local-variable 'mu4e~highlighted-docid)
|
2012-04-08 11:43:37 +02:00
|
|
|
|
(make-local-variable 'global-mode-string)
|
2012-07-11 10:36:05 +02:00
|
|
|
|
(set (make-local-variable 'hl-line-face) 'mu4e-header-highlight-face)
|
2012-09-16 20:46:47 +02:00
|
|
|
|
|
2011-09-12 19:52:32 +02:00
|
|
|
|
(setq
|
|
|
|
|
truncate-lines t
|
2011-12-23 18:09:03 +01:00
|
|
|
|
buffer-undo-list t ;; don't record undo information
|
2012-04-08 11:43:37 +02:00
|
|
|
|
overwrite-mode 'overwrite-mode-binary
|
2012-07-11 09:21:09 +02:00
|
|
|
|
header-line-format (mu4e~header-line-format))
|
2011-12-29 09:39:30 +01:00
|
|
|
|
|
2012-07-11 09:21:09 +02:00
|
|
|
|
(mu4e~mark-initialize) ;; initialize the marking subsystem
|
|
|
|
|
(hl-line-mode 1))
|
2012-08-01 09:48:56 +02:00
|
|
|
|
|
2012-04-08 19:28:49 +02:00
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
2012-04-09 15:34:52 +02:00
|
|
|
|
;;; higlighting
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(defvar mu4e~highlighted-docid nil
|
2012-07-11 09:21:09 +02:00
|
|
|
|
"The highlighted docid")
|
2012-04-09 15:34:52 +02:00
|
|
|
|
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(defun mu4e~headers-highlight (docid)
|
2012-04-09 15:34:52 +02:00
|
|
|
|
"Highlight the header with DOCID, or do nothing if it's not
|
|
|
|
|
found. Also, unhighlight any previously highlighted headers."
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(with-current-buffer mu4e~headers-buffer
|
2012-04-09 15:34:52 +02:00
|
|
|
|
(save-excursion
|
|
|
|
|
;; first, unhighlight the previously highlighted docid, if any
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(when (and mu4e~highlighted-docid
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(mu4e~headers-goto-docid mu4e~highlighted-docid))
|
2012-04-09 15:34:52 +02:00
|
|
|
|
(hl-line-unhighlight))
|
|
|
|
|
;; now, highlight the new one
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(when (mu4e~headers-goto-docid docid)
|
2012-04-09 15:34:52 +02:00
|
|
|
|
(hl-line-highlight)))
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(setq mu4e~highlighted-docid docid)))
|
2012-04-09 15:34:52 +02:00
|
|
|
|
|
2012-04-11 01:08:02 +02:00
|
|
|
|
|
2012-04-09 15:34:52 +02:00
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(defun mu4e~headers-select-window ()
|
2012-03-25 12:28:06 +02:00
|
|
|
|
"When there is a visible window for the headers buffer, make sure
|
|
|
|
|
to select it. This is needed when adding new headers, otherwise
|
|
|
|
|
adding a lot of new headers looks really choppy."
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(let ((win (get-buffer-window mu4e~headers-buffer)))
|
2012-04-07 16:59:08 +02:00
|
|
|
|
(when win (select-window win))))
|
|
|
|
|
|
|
|
|
|
;;;; headers in the buffer are prefixed by an invisible string with the docid
|
|
|
|
|
;;;; followed by an EOT ('end-of-transmission', \004, ^D) non-printable ascii
|
|
|
|
|
;;;; character. this string also has a text-property with the docid. the former
|
|
|
|
|
;;;; is used for quickly finding a certain header, the latter for retrieving the
|
|
|
|
|
;;;; docid at point without string matching etc.
|
|
|
|
|
|
2012-08-27 17:04:58 +02:00
|
|
|
|
(defsubst mu4e~headers-docid-cookie (docid)
|
2012-04-07 16:59:08 +02:00
|
|
|
|
"Create an invisible string containing DOCID; this is to be used
|
|
|
|
|
at the beginning of lines to identify headers."
|
2012-04-26 21:42:15 +02:00
|
|
|
|
(propertize (format "%s%d%s"
|
2012-05-01 21:45:54 +02:00
|
|
|
|
mu4e~headers-docid-pre docid mu4e~headers-docid-post)
|
2012-10-22 19:27:14 +02:00
|
|
|
|
'docid docid 'invisible t));;
|
2012-04-07 16:59:08 +02:00
|
|
|
|
|
2012-08-27 17:04:58 +02:00
|
|
|
|
(defsubst mu4e~headers-docid-at-point (&optional point)
|
2012-04-07 16:59:08 +02:00
|
|
|
|
"Get the docid for the header at POINT, or at current (point) if
|
|
|
|
|
nil. Returns the docid, or nil if there is none."
|
|
|
|
|
(save-excursion
|
2012-04-11 01:08:02 +02:00
|
|
|
|
(when point
|
|
|
|
|
(goto-char point))
|
2012-04-07 17:25:22 +02:00
|
|
|
|
(get-text-property (line-beginning-position) 'docid)))
|
2012-04-07 16:59:08 +02:00
|
|
|
|
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(defun mu4e~headers-goto-docid (docid &optional to-mark)
|
2012-04-07 16:59:08 +02:00
|
|
|
|
"Go to the beginning of the line with the header with docid
|
|
|
|
|
DOCID, or nil if it cannot be found. If the optional TO-MARK is
|
|
|
|
|
non-nil, go to the point directly *after* the docid-cookie instead
|
|
|
|
|
of the beginning of the line."
|
|
|
|
|
(let ((oldpoint (point)) (newpoint))
|
|
|
|
|
(goto-char (point-min))
|
|
|
|
|
(setq newpoint
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(search-forward (mu4e~headers-docid-cookie docid) nil t))
|
2012-04-26 21:42:15 +02:00
|
|
|
|
(unless to-mark
|
2012-04-07 16:59:08 +02:00
|
|
|
|
(if (null newpoint)
|
|
|
|
|
(goto-char oldpoint) ;; not found; restore old pos
|
2012-04-08 11:43:37 +02:00
|
|
|
|
(progn
|
2012-04-07 16:59:08 +02:00
|
|
|
|
(beginning-of-line) ;; found, move to beginning of line
|
|
|
|
|
(setq newpoint (point)))))
|
|
|
|
|
newpoint)) ;; return the point, or nil if not found
|
2012-04-08 11:43:37 +02:00
|
|
|
|
|
2012-08-27 17:04:58 +02:00
|
|
|
|
(defsubst mu4e~headers-docid-pos (docid)
|
2012-04-07 16:59:08 +02:00
|
|
|
|
"Return the pos of the beginning of the line with the header with
|
|
|
|
|
docid DOCID, or nil if it cannot be found."
|
|
|
|
|
(let ((pos))
|
|
|
|
|
(save-excursion
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(setq pos (mu4e~headers-goto-docid docid)))
|
2012-04-07 16:59:08 +02:00
|
|
|
|
pos))
|
|
|
|
|
|
2012-08-27 17:04:58 +02:00
|
|
|
|
(defsubst mu4e~headers-field-for-docid (docid field)
|
2012-04-11 01:08:02 +02:00
|
|
|
|
"Get FIELD (a symbol, see `mu4e-headers-names') for the message
|
|
|
|
|
with DOCID which must be present in the headers buffer."
|
|
|
|
|
(save-excursion
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(when (mu4e~headers-goto-docid docid)
|
2012-09-26 16:28:30 +02:00
|
|
|
|
(mu4e-message-field (mu4e-message-at-point) field))))
|
2012-04-11 01:08:02 +02:00
|
|
|
|
|
2012-04-08 11:43:37 +02:00
|
|
|
|
;;;; markers mark headers for
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(defun mu4e~headers-mark (docid mark)
|
2012-04-07 16:59:08 +02:00
|
|
|
|
"(Visually) mark the header for DOCID with character MARK."
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(with-current-buffer mu4e~headers-buffer
|
2012-04-07 16:59:08 +02:00
|
|
|
|
(let ((inhibit-read-only t) (oldpoint (point)))
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(unless (mu4e~headers-goto-docid docid)
|
2012-07-10 11:11:06 +02:00
|
|
|
|
(mu4e-error "Cannot find message with docid %S" docid))
|
2012-04-07 16:59:08 +02:00
|
|
|
|
;; now, we're at the beginning of the header, looking at
|
|
|
|
|
;; <docid>\004
|
2012-04-26 21:42:15 +02:00
|
|
|
|
;; (which is invisible). jump past that…
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(unless (re-search-forward mu4e~headers-docid-post nil t)
|
2012-07-10 11:11:06 +02:00
|
|
|
|
(mu4e-error "Cannot find the `mu4e~headers-docid-post' separator"))
|
2012-04-28 12:47:13 +02:00
|
|
|
|
|
2012-04-07 16:59:08 +02:00
|
|
|
|
;; clear old marks, and add the new ones.
|
2012-04-28 08:08:28 +02:00
|
|
|
|
(let ((msg (get-text-property (point) 'msg)))
|
2012-04-30 16:36:38 +02:00
|
|
|
|
(delete-char mu4e~mark-fringe-len)
|
2012-04-28 08:08:28 +02:00
|
|
|
|
(insert (propertize
|
2012-04-30 16:36:38 +02:00
|
|
|
|
(format mu4e~mark-fringe-format mark)
|
2012-04-28 08:08:28 +02:00
|
|
|
|
'face 'mu4e-header-marks-face
|
|
|
|
|
'docid docid
|
|
|
|
|
'msg msg)))
|
2012-04-07 16:59:08 +02:00
|
|
|
|
(goto-char oldpoint))))
|
2012-04-28 08:08:28 +02:00
|
|
|
|
|
2012-03-25 12:28:06 +02:00
|
|
|
|
|
2012-09-15 20:10:46 +02:00
|
|
|
|
(defsubst mu4e~headers-add-header (str docid point &optional msg)
|
2012-03-25 12:28:06 +02:00
|
|
|
|
"Add header STR with DOCID to the buffer at POINT if non-nil, or
|
2012-09-15 20:10:46 +02:00
|
|
|
|
at (point-max) otherwise. If MSG is not nil, add it as the
|
|
|
|
|
text-property `msg'."
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(when (buffer-live-p mu4e~headers-buffer)
|
|
|
|
|
(with-current-buffer mu4e~headers-buffer
|
2012-04-08 19:28:49 +02:00
|
|
|
|
(let ((inhibit-read-only t)
|
2012-04-11 01:08:02 +02:00
|
|
|
|
(is-first-header (= (point-min) (point-max))))
|
2011-09-20 22:59:20 +02:00
|
|
|
|
(save-excursion
|
2012-04-08 19:28:49 +02:00
|
|
|
|
(goto-char (if point point (point-max)))
|
2012-04-07 16:59:08 +02:00
|
|
|
|
(insert
|
2012-04-08 19:28:49 +02:00
|
|
|
|
(propertize
|
|
|
|
|
(concat
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(mu4e~headers-docid-cookie docid)
|
2012-04-30 16:36:38 +02:00
|
|
|
|
mu4e~mark-fringe
|
2012-04-28 08:08:28 +02:00
|
|
|
|
str "\n")
|
|
|
|
|
'docid docid 'msg msg)))))))
|
2011-12-26 11:18:12 +01:00
|
|
|
|
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(defun mu4e~headers-remove-header (docid &optional ignore-missing)
|
2012-04-24 20:12:15 +02:00
|
|
|
|
"Remove header with DOCID at POINT; when IGNORE-MISSING is
|
|
|
|
|
non-nill, don't raise an error when the docid is not found."
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(with-current-buffer mu4e~headers-buffer
|
|
|
|
|
(if (mu4e~headers-goto-docid docid)
|
2012-04-24 20:12:15 +02:00
|
|
|
|
(let ((inhibit-read-only t))
|
|
|
|
|
(delete-region (line-beginning-position) (line-beginning-position 2)))
|
|
|
|
|
(unless ignore-missing
|
2012-07-10 11:11:06 +02:00
|
|
|
|
(mu4e-error "Cannot find message with docid %S" docid)))))
|
2012-04-24 20:12:15 +02:00
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
2012-08-01 09:48:56 +02:00
|
|
|
|
|
2012-06-10 12:24:41 +02:00
|
|
|
|
(defun mu4e~headers-search-execute (expr ignore-history)
|
2012-05-05 10:07:58 +02:00
|
|
|
|
"Search in the mu database for EXPR, and switch to the output
|
2012-06-10 12:24:41 +02:00
|
|
|
|
buffer for the results. If IGNORE-HISTORY is true, do *not* update
|
|
|
|
|
the query history stack."
|
2012-05-07 09:05:31 +02:00
|
|
|
|
;; note: we don't want to update the history if this query comes from
|
|
|
|
|
;; `mu4e~headers-query-next' or `mu4e~headers-query-prev'.
|
2012-06-11 11:03:37 +02:00
|
|
|
|
(mu4e-hide-other-mu4e-buffers)
|
2012-05-05 10:07:58 +02:00
|
|
|
|
(let ((buf (get-buffer-create mu4e~headers-buffer-name))
|
|
|
|
|
(inhibit-read-only t))
|
|
|
|
|
(with-current-buffer buf
|
|
|
|
|
(mu4e-headers-mode)
|
2012-05-07 09:05:31 +02:00
|
|
|
|
(unless ignore-history
|
|
|
|
|
;; save the old present query to the history list
|
2012-06-10 10:19:51 +02:00
|
|
|
|
(when mu4e~headers-last-query
|
|
|
|
|
(mu4e~headers-push-query mu4e~headers-last-query 'past)))
|
2012-05-05 10:07:58 +02:00
|
|
|
|
(setq
|
|
|
|
|
mu4e~headers-buffer buf
|
2012-05-07 09:05:31 +02:00
|
|
|
|
mode-name "mu4e-headers"
|
2012-07-11 10:36:05 +02:00
|
|
|
|
mu4e~headers-last-query expr
|
2012-08-01 09:48:56 +02:00
|
|
|
|
global-mode-string (propertize mu4e~headers-last-query
|
|
|
|
|
'face 'mu4e-title-face)))
|
2012-05-05 10:07:58 +02:00
|
|
|
|
(switch-to-buffer buf)
|
|
|
|
|
(mu4e~proc-find
|
|
|
|
|
(replace-regexp-in-string "\"" "\\\\\"" expr) ;; escape "\"
|
2012-06-10 10:19:51 +02:00
|
|
|
|
mu4e-headers-show-threads
|
|
|
|
|
mu4e-headers-sortfield
|
|
|
|
|
mu4e-headers-sort-revert
|
2012-06-15 10:46:11 +02:00
|
|
|
|
(unless mu4e-headers-full-search mu4e-search-results-limit))))
|
2012-05-14 09:45:39 +02:00
|
|
|
|
|
|
|
|
|
(defun mu4e~headers-redraw-get-view-window ()
|
|
|
|
|
"Close all windows, redraw the headers buffer based on the value
|
|
|
|
|
of `mu4e-split-view', and return a window for the message view."
|
2012-06-11 11:03:37 +02:00
|
|
|
|
(mu4e-hide-other-mu4e-buffers)
|
2012-05-14 09:45:39 +02:00
|
|
|
|
(unless (buffer-live-p mu4e~headers-buffer)
|
2012-07-10 11:11:06 +02:00
|
|
|
|
(mu4e-error "No headers buffer available"))
|
2012-05-14 09:45:39 +02:00
|
|
|
|
(switch-to-buffer mu4e~headers-buffer)
|
2012-06-23 10:28:56 +02:00
|
|
|
|
;; kill the existing view win
|
|
|
|
|
(when (buffer-live-p mu4e~view-buffer)
|
|
|
|
|
(kill-buffer mu4e~view-buffer))
|
|
|
|
|
;; get a new view window
|
2012-05-20 18:59:57 +02:00
|
|
|
|
(setq mu4e~headers-view-win
|
|
|
|
|
(cond
|
|
|
|
|
((eq mu4e-split-view 'horizontal) ;; split horizontally
|
|
|
|
|
(split-window-vertically mu4e-headers-visible-lines))
|
|
|
|
|
((eq mu4e-split-view 'vertical) ;; split vertically
|
|
|
|
|
(split-window-horizontally mu4e-headers-visible-columns))
|
|
|
|
|
(t ;; no splitting; just use the currently selected one
|
|
|
|
|
(selected-window))))
|
|
|
|
|
mu4e~headers-view-win)
|
2012-05-14 09:45:39 +02:00
|
|
|
|
|
2012-04-24 20:12:15 +02:00
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
;; search-based marking
|
|
|
|
|
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(defun mu4e-headers-for-each (func)
|
2012-04-28 13:39:57 +02:00
|
|
|
|
"Call FUNC for each header, moving point to the header. FUNC
|
|
|
|
|
takes one argument msg, the msg s-expression for the corresponding
|
|
|
|
|
header."
|
2012-04-24 20:12:15 +02:00
|
|
|
|
(save-excursion
|
|
|
|
|
(goto-char (point-min))
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(while (search-forward mu4e~headers-docid-pre nil t)
|
2012-04-26 21:42:15 +02:00
|
|
|
|
;; not really sure why we need to jump to bol; we we need
|
|
|
|
|
;; to, otherwise we miss lines sometimes...
|
|
|
|
|
(let ((msg (get-text-property (line-beginning-position) 'msg)))
|
2012-04-24 20:12:15 +02:00
|
|
|
|
(when msg
|
|
|
|
|
(funcall func msg))))))
|
|
|
|
|
|
2012-10-16 20:43:49 +02:00
|
|
|
|
(defvar mu4e~headers-regexp-hist nil
|
2012-05-02 16:22:45 +02:00
|
|
|
|
"History list of regexps used.")
|
|
|
|
|
|
2012-10-16 20:43:49 +02:00
|
|
|
|
(defun mu4e~headers-mark-for-each-if (markpair mark-pred &optional param)
|
2012-06-14 20:54:24 +02:00
|
|
|
|
"Mark all headers for with predicate function MARK-PRED return
|
|
|
|
|
non-nil with MARKPAIR. MARK-PRED is function that takes two
|
|
|
|
|
arguments, MSG (the message at point) and PARAM (a user-specified
|
|
|
|
|
parameter). MARKPAIR is a cell (MARK . TARGET)."
|
|
|
|
|
(mu4e-headers-for-each
|
|
|
|
|
(lambda (msg)
|
|
|
|
|
(when (funcall mark-pred msg param)
|
2012-06-15 10:46:11 +02:00
|
|
|
|
(mu4e-mark-at-point (car markpair) (cdr markpair))))))
|
2012-06-14 20:54:24 +02:00
|
|
|
|
|
2012-05-10 08:55:28 +02:00
|
|
|
|
(defun mu4e-headers-mark-pattern ()
|
2012-04-24 20:12:15 +02:00
|
|
|
|
"Ask user for a kind of mark (move, delete etc.), a field to
|
|
|
|
|
match and a regular expression to match with. Then, mark all
|
|
|
|
|
matching messages with that mark."
|
|
|
|
|
(interactive)
|
2012-06-14 18:10:02 +02:00
|
|
|
|
(let ((markpair (mu4e~mark-get-markpair "Mark matched messages with: " t))
|
2012-04-26 21:42:15 +02:00
|
|
|
|
(field (mu4e-read-option "Field to match: "
|
2012-06-11 15:40:23 +02:00
|
|
|
|
'( ("subject" . :subject)
|
|
|
|
|
("from" . :from)
|
|
|
|
|
("to" . :to))))
|
2012-05-02 16:21:40 +02:00
|
|
|
|
(pattern (read-string
|
|
|
|
|
(mu4e-format "Regexp:")
|
|
|
|
|
nil 'mu4e~headers-regexp-hist)))
|
2012-06-14 20:54:24 +02:00
|
|
|
|
(mu4e~headers-mark-for-each-if
|
|
|
|
|
markpair
|
|
|
|
|
(lambda (msg param)
|
2012-04-24 20:12:15 +02:00
|
|
|
|
(let* ((do-mark) (value (mu4e-msg-field msg field)))
|
|
|
|
|
(setq do-mark
|
|
|
|
|
(if (member field '(:to :from :cc :bcc :reply-to))
|
|
|
|
|
(find-if (lambda (contact)
|
|
|
|
|
(let ((name (car contact)) (email (cdr contact)))
|
|
|
|
|
(or (and name (string-match pattern name))
|
|
|
|
|
(and email (string-match pattern email))))) value)
|
2012-06-14 20:54:24 +02:00
|
|
|
|
(string-match pattern (or value "")))))))))
|
2012-04-26 21:42:15 +02:00
|
|
|
|
|
2012-06-14 20:54:24 +02:00
|
|
|
|
(defun mu4e-headers-mark-custom ()
|
|
|
|
|
"Mark messages based on a user-provided predicate function."
|
|
|
|
|
(interactive)
|
|
|
|
|
(let* ((pred (mu4e-read-option "Match function: "
|
|
|
|
|
mu4e-headers-custom-markers))
|
|
|
|
|
(param (when (cdr pred) (eval (cdr pred))))
|
|
|
|
|
(markpair (mu4e~mark-get-markpair "Mark matched messages with: " t)))
|
2012-06-15 10:46:11 +02:00
|
|
|
|
(mu4e~headers-mark-for-each-if markpair (car pred) param)))
|
2012-04-26 21:42:15 +02:00
|
|
|
|
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(defun mu4e~headers-get-thread-info (msg what)
|
2012-04-26 21:42:15 +02:00
|
|
|
|
"Get WHAT (a symbol, either path or thread-id) for MSG."
|
2012-09-26 11:25:38 +02:00
|
|
|
|
(let* ((thread (or (mu4e-message-field msg :thread)
|
2012-07-10 11:11:06 +02:00
|
|
|
|
(mu4e-error "No thread info found")))
|
|
|
|
|
(path (or (plist-get thread :path)
|
|
|
|
|
(mu4e-error "No threadpath found"))))
|
2012-04-26 21:42:15 +02:00
|
|
|
|
(case what
|
|
|
|
|
(path path)
|
|
|
|
|
(thread-id
|
|
|
|
|
(save-match-data
|
|
|
|
|
;; the thread id is the first segment of the thread path
|
|
|
|
|
(when (string-match "^\\([[:xdigit:]]+\\):?" path)
|
|
|
|
|
(match-string 1 path))))
|
2012-07-10 11:11:06 +02:00
|
|
|
|
(otherwise (mu4e-error "Not supported")))))
|
2012-04-28 08:08:28 +02:00
|
|
|
|
|
|
|
|
|
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(defun mu4e-headers-mark-thread (&optional subthread)
|
2012-04-26 21:42:15 +02:00
|
|
|
|
"Mark the thread at point, if SUBTHREAD is non-nil, marking is
|
|
|
|
|
limited to the message at point and its descendants."
|
|
|
|
|
;; the tread id is shared by all messages in a thread
|
|
|
|
|
(interactive "P")
|
2012-09-26 16:28:30 +02:00
|
|
|
|
(let* ((msg (mu4e-message-at-point))
|
|
|
|
|
(thread-id (mu4e~headers-get-thread-info msg 'thread-id))
|
|
|
|
|
(path (mu4e~headers-get-thread-info msg 'path))
|
2012-06-14 18:10:02 +02:00
|
|
|
|
(markpair
|
|
|
|
|
(mu4e~mark-get-markpair
|
|
|
|
|
(if subthread "Mark subthread with: " "Mark whole thread with: ")
|
|
|
|
|
t))
|
2012-04-28 13:39:57 +02:00
|
|
|
|
(last-marked-point))
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(mu4e-headers-for-each
|
2012-09-26 16:28:30 +02:00
|
|
|
|
(lambda (mymsg)
|
|
|
|
|
(let ((my-thread-id (mu4e~headers-get-thread-info mymsg 'thread-id)))
|
2012-04-26 21:42:15 +02:00
|
|
|
|
(if subthread
|
2012-09-26 16:28:30 +02:00
|
|
|
|
;; subthread matching; mymsg's thread path should have path as its
|
2012-04-28 08:08:28 +02:00
|
|
|
|
;; prefix
|
2012-04-26 21:42:15 +02:00
|
|
|
|
(when (string-match (concat "^" path)
|
2012-09-26 16:28:30 +02:00
|
|
|
|
(mu4e~headers-get-thread-info mymsg 'path))
|
2012-04-28 13:39:57 +02:00
|
|
|
|
(mu4e-mark-at-point (car markpair) (cdr markpair))
|
|
|
|
|
(setq last-marked-point (point)))
|
2012-04-26 21:42:15 +02:00
|
|
|
|
;; nope; not looking for the subthread; looking for the whole thread
|
|
|
|
|
(when (string= thread-id
|
2012-09-26 16:28:30 +02:00
|
|
|
|
(mu4e~headers-get-thread-info mymsg 'thread-id))
|
2012-04-28 13:39:57 +02:00
|
|
|
|
(mu4e-mark-at-point (car markpair) (cdr markpair))
|
|
|
|
|
(setq last-marked-point (point)))))))
|
|
|
|
|
(when last-marked-point
|
|
|
|
|
(goto-char last-marked-point)
|
2012-05-05 10:07:58 +02:00
|
|
|
|
(mu4e-headers-next))))
|
2012-04-26 21:42:15 +02:00
|
|
|
|
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(defun mu4e-headers-mark-subthread ()
|
2012-04-26 21:42:15 +02:00
|
|
|
|
"Like `mu4e-mark-thread', but only for a sub-thread."
|
|
|
|
|
(interactive)
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(mu4e-headers-mark-thread t))
|
2012-04-26 21:42:15 +02:00
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
2012-04-28 08:08:28 +02:00
|
|
|
|
|
2012-05-07 09:05:31 +02:00
|
|
|
|
|
|
|
|
|
;;; the query past / present / future ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
(defvar mu4e~headers-query-past nil
|
|
|
|
|
"Stack of queries before the present one.")
|
|
|
|
|
(defvar mu4e~headers-query-future nil
|
|
|
|
|
"Stack of queries after the present one.")
|
|
|
|
|
(defvar mu4e~headers-query-stack-size 20
|
|
|
|
|
"Maximum size for the query stacks.")
|
2012-05-12 08:58:29 +02:00
|
|
|
|
|
2012-05-07 09:05:31 +02:00
|
|
|
|
(defun mu4e~headers-push-query (query where)
|
|
|
|
|
"Push QUERY to one of the query stacks; WHERE is a symbol telling
|
|
|
|
|
us where to push; it's a symbol, either 'future or
|
|
|
|
|
'past. Functional also removes duplicats, limits the stack size."
|
|
|
|
|
(let ((stack
|
|
|
|
|
(case where
|
|
|
|
|
(past mu4e~headers-query-past)
|
|
|
|
|
(future mu4e~headers-query-future))))
|
|
|
|
|
;; only add if not the same item
|
|
|
|
|
(unless (and stack (string= (car stack) query))
|
|
|
|
|
(push query stack)
|
|
|
|
|
;; limit the stack to `mu4e~headers-query-stack-size' elements
|
|
|
|
|
(when (> (length stack) mu4e~headers-query-stack-size)
|
|
|
|
|
(setq stack (subseq stack 0 mu4e~headers-query-stack-size)))
|
|
|
|
|
;; remove all duplicates of the new element
|
|
|
|
|
(remove-if (lambda (elm) (string= elm (car stack))) (cdr stack))
|
|
|
|
|
;; update the stacks
|
|
|
|
|
(case where
|
|
|
|
|
(past (setq mu4e~headers-query-past stack))
|
|
|
|
|
(future (setq mu4e~headers-query-future stack))))))
|
|
|
|
|
|
|
|
|
|
(defun mu4e~headers-pop-query (whence)
|
|
|
|
|
"Pop a query from the stack. WHENCE is a symbol telling us where
|
|
|
|
|
to get it from; it's a symbol, either 'future or 'past."
|
|
|
|
|
(case whence
|
|
|
|
|
(past
|
|
|
|
|
(unless mu4e~headers-query-past
|
2012-09-06 09:33:53 +02:00
|
|
|
|
(mu4e-warn "No more previous queries"))
|
2012-05-07 09:05:31 +02:00
|
|
|
|
(pop mu4e~headers-query-past))
|
|
|
|
|
(future
|
|
|
|
|
(unless mu4e~headers-query-future
|
2012-09-06 09:33:53 +02:00
|
|
|
|
(mu4e-warn "No more next queries"))
|
2012-05-07 09:05:31 +02:00
|
|
|
|
(pop mu4e~headers-query-future))))
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
|
2011-09-12 19:52:32 +02:00
|
|
|
|
|
|
|
|
|
;;; interactive functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
2012-05-05 10:07:58 +02:00
|
|
|
|
(defvar mu4e~headers-search-hist nil
|
|
|
|
|
"History list of searches.")
|
|
|
|
|
|
2012-06-10 12:24:41 +02:00
|
|
|
|
(defun mu4e-headers-search (&optional expr prompt edit ignore-history)
|
2012-05-05 10:07:58 +02:00
|
|
|
|
"Search in the mu database for EXPR, and switch to the output
|
2012-06-10 12:24:41 +02:00
|
|
|
|
buffer for the results. This is an interactive function which ask
|
|
|
|
|
user for EXPR. PROMPT, if non-nil, is the prompt used by this
|
|
|
|
|
function (default is \"Search for:\"). If EDIT is non-nil, instead
|
|
|
|
|
of executing the query for EXPR, let the user edit the query before
|
|
|
|
|
executing it. If IGNORE-HISTORY is true, do *not* update the query
|
|
|
|
|
history stack."
|
2012-05-07 09:05:31 +02:00
|
|
|
|
;; note: we don't want to update the history if this query comes from
|
|
|
|
|
;; `mu4e~headers-query-next' or `mu4e~headers-query-prev'."
|
2012-05-05 10:07:58 +02:00
|
|
|
|
(interactive)
|
|
|
|
|
(let* ((prompt (mu4e-format (or prompt "Search for: ")))
|
|
|
|
|
(expr
|
|
|
|
|
(if edit
|
|
|
|
|
(read-string prompt expr)
|
|
|
|
|
(or expr
|
|
|
|
|
(read-string prompt nil 'mu4e~headers-search-hist)))))
|
|
|
|
|
(mu4e-mark-handle-when-leaving)
|
2012-05-07 09:05:31 +02:00
|
|
|
|
(mu4e~headers-search-execute expr
|
|
|
|
|
ignore-history)))
|
2012-03-25 19:33:17 +02:00
|
|
|
|
|
2012-06-10 12:24:41 +02:00
|
|
|
|
(defun mu4e-headers-search-edit ()
|
|
|
|
|
"Edit the last search expression."
|
|
|
|
|
(interactive)
|
|
|
|
|
(mu4e-headers-search mu4e~headers-last-query nil t))
|
2012-04-23 18:07:20 +02:00
|
|
|
|
|
2012-06-10 12:24:41 +02:00
|
|
|
|
(defun mu4e-headers-search-bookmark (&optional expr edit)
|
|
|
|
|
"Search using some bookmarked query EXPR.
|
|
|
|
|
If EDIT is non-nil, let the user edit the bookmark before starting
|
|
|
|
|
the search."
|
2012-05-05 10:07:58 +02:00
|
|
|
|
(interactive)
|
|
|
|
|
(let ((expr
|
|
|
|
|
(or expr
|
|
|
|
|
(mu4e-ask-bookmark (if edit "Select bookmark: " "Bookmark: ")))))
|
2012-06-10 12:24:41 +02:00
|
|
|
|
(mu4e-headers-search expr (when edit "Edit bookmark: ") edit)))
|
2012-05-05 10:07:58 +02:00
|
|
|
|
|
|
|
|
|
(defun mu4e-headers-search-bookmark-edit ()
|
|
|
|
|
"Edit an existing bookmark before executing it."
|
|
|
|
|
(interactive)
|
2012-06-10 12:24:41 +02:00
|
|
|
|
(mu4e-headers-search-bookmark nil t))
|
2012-05-06 10:21:12 +02:00
|
|
|
|
|
|
|
|
|
|
2012-06-10 12:24:41 +02:00
|
|
|
|
(defun mu4e-headers-search-narrow (filter )
|
2012-05-06 15:55:14 +02:00
|
|
|
|
"Narrow the last search by appending search expression FILTER to
|
2012-06-10 12:24:41 +02:00
|
|
|
|
the last search expression."
|
2012-05-06 10:21:12 +02:00
|
|
|
|
(interactive
|
2012-05-06 15:55:14 +02:00
|
|
|
|
(let ((filter
|
2012-05-10 08:55:28 +02:00
|
|
|
|
(read-string (mu4e-format "Narrow down to: ")
|
2012-06-10 12:24:41 +02:00
|
|
|
|
nil 'mu4e~headers-search-hist nil t)))
|
|
|
|
|
(list filter)))
|
2012-06-10 10:19:51 +02:00
|
|
|
|
(unless mu4e~headers-last-query
|
2012-09-06 09:33:53 +02:00
|
|
|
|
(mu4e-warn "There's nothing to filter"))
|
2012-05-06 10:21:12 +02:00
|
|
|
|
(mu4e-headers-search
|
2012-06-10 12:24:41 +02:00
|
|
|
|
(format "(%s) AND %s" mu4e~headers-last-query filter)))
|
2012-06-10 10:19:51 +02:00
|
|
|
|
|
|
|
|
|
|
2012-06-15 10:46:11 +02:00
|
|
|
|
(defun mu4e-headers-change-sorting (&optional dont-refresh)
|
2012-06-10 10:19:51 +02:00
|
|
|
|
"Interactively change the sorting/threading parameters. With prefix-argument,
|
2012-06-15 10:46:11 +02:00
|
|
|
|
do _not_ refresh the last search with the new parameters."
|
2012-06-10 10:19:51 +02:00
|
|
|
|
(interactive "P")
|
|
|
|
|
(let* ((sortfield
|
|
|
|
|
(mu4e-read-option "Sortfield: " mu4e~headers-sortfield-choices))
|
|
|
|
|
(revert
|
|
|
|
|
(mu4e-read-option "Direction: "
|
2012-06-11 15:40:23 +02:00
|
|
|
|
'(("ascending" . nil) ("descending" . t)))))
|
2012-06-10 10:19:51 +02:00
|
|
|
|
(setq
|
|
|
|
|
mu4e-headers-sortfield sortfield
|
2012-06-11 15:53:29 +02:00
|
|
|
|
mu4e-headers-sort-revert revert) ;; "descending" means "revert"
|
2012-06-11 23:34:56 +02:00
|
|
|
|
(mu4e-message "Sorting by %s (%s)%s"
|
|
|
|
|
(symbol-name sortfield)
|
|
|
|
|
(if revert "descending" "ascending")
|
2012-06-15 10:46:11 +02:00
|
|
|
|
(if dont-refresh
|
|
|
|
|
" (press 'g' to refresh)" ""))
|
|
|
|
|
(unless dont-refresh
|
2012-06-10 10:19:51 +02:00
|
|
|
|
(mu4e-headers-rerun-search))))
|
|
|
|
|
|
2012-06-15 10:46:11 +02:00
|
|
|
|
(defun mu4e-headers-toggle-threading (&optional dont-refresh)
|
2012-06-10 10:19:51 +02:00
|
|
|
|
"Toggle threading on/off for the search results. With prefix-argument,
|
2012-06-15 10:46:11 +02:00
|
|
|
|
do _not_ refresh the last search with the new setting for
|
|
|
|
|
threading."
|
2012-06-10 10:19:51 +02:00
|
|
|
|
(interactive "P")
|
|
|
|
|
(setq mu4e-headers-show-threads (not mu4e-headers-show-threads))
|
2012-06-11 23:34:56 +02:00
|
|
|
|
(mu4e-message "Threading turned %s%s"
|
|
|
|
|
(if mu4e-headers-show-threads "on" "off")
|
2012-06-15 10:46:11 +02:00
|
|
|
|
(if dont-refresh
|
|
|
|
|
" (press 'g' to refresh)" ""))
|
|
|
|
|
(unless dont-refresh
|
2012-06-10 10:19:51 +02:00
|
|
|
|
(mu4e-headers-rerun-search)))
|
|
|
|
|
|
2012-06-15 10:46:11 +02:00
|
|
|
|
(defun mu4e-headers-toggle-full-search (&optional dont-refresh)
|
2012-06-10 12:24:41 +02:00
|
|
|
|
"Toggle full-search on/off for the search results. With prefix-argument,
|
2012-06-15 10:46:11 +02:00
|
|
|
|
do _not_ refresh the last search with the new setting for
|
|
|
|
|
threading."
|
2012-06-10 12:24:41 +02:00
|
|
|
|
(interactive "P")
|
|
|
|
|
(setq mu4e-headers-full-search (not mu4e-headers-full-search))
|
2012-06-11 23:34:56 +02:00
|
|
|
|
(mu4e-message "Full search turned %s%s"
|
|
|
|
|
(if mu4e-headers-full-search "on" "off")
|
2012-06-15 10:46:11 +02:00
|
|
|
|
(if dont-refresh
|
|
|
|
|
" (press 'g' to refresh)" ""))
|
|
|
|
|
(unless dont-refresh
|
2012-06-11 23:34:56 +02:00
|
|
|
|
(mu4e-headers-rerun-search)))
|
2012-06-10 12:24:41 +02:00
|
|
|
|
|
2012-06-24 09:38:26 +02:00
|
|
|
|
(defvar mu4e~headers-loading-buf nil
|
|
|
|
|
"A buffer for loading a message view.")
|
|
|
|
|
|
|
|
|
|
(defun mu4e~headers-get-loading-buf ()
|
|
|
|
|
"Get a buffer to give feedback while loading a message view."
|
|
|
|
|
(unless (buffer-live-p mu4e~headers-loading-buf)
|
|
|
|
|
(setq mu4e~headers-loading-buf
|
|
|
|
|
(get-buffer-create " *mu4e-loading*"))
|
|
|
|
|
(with-current-buffer mu4e~headers-loading-buf
|
2012-06-27 18:01:58 +02:00
|
|
|
|
(let ((inhibit-read-only t))
|
|
|
|
|
(erase-buffer)
|
|
|
|
|
(insert (propertize "Waiting for message..."
|
|
|
|
|
'face 'mu4e-system-face 'intangible t)))
|
|
|
|
|
(setq buffer-read-only t)))
|
2012-06-24 09:38:26 +02:00
|
|
|
|
mu4e~headers-loading-buf)
|
2012-06-10 12:24:41 +02:00
|
|
|
|
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(defun mu4e-headers-view-message ()
|
2012-04-23 18:07:20 +02:00
|
|
|
|
"View message at point. If there's an existing window for the
|
|
|
|
|
view, re-use that one. If not, create a new one, depending on the
|
|
|
|
|
value of `mu4e-split-view': if it's a symbol `horizontal' or
|
|
|
|
|
`vertical', split the window accordingly; if it is nil, replace the
|
|
|
|
|
current window. "
|
|
|
|
|
(interactive)
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(unless (eq major-mode 'mu4e-headers-mode)
|
2012-07-10 11:11:06 +02:00
|
|
|
|
(mu4e-error "Must be in mu4e-headers-mode (%S)" major-mode))
|
2012-09-26 16:28:30 +02:00
|
|
|
|
(let* ((msg (mu4e-message-at-point))
|
2012-09-26 15:47:42 +02:00
|
|
|
|
(docid (or (mu4e-message-field msg :docid)
|
2012-10-22 19:27:14 +02:00
|
|
|
|
(mu4e-warn "No message at point")))
|
2012-09-13 20:10:27 +02:00
|
|
|
|
;; decrypt (or not), based on `mu4e-decryption-policy'.
|
|
|
|
|
(decrypt
|
2012-09-26 15:47:42 +02:00
|
|
|
|
(and (member 'encrypted (mu4e-message-field msg :flags))
|
2012-09-13 20:10:27 +02:00
|
|
|
|
(if (eq mu4e-decryption-policy 'ask)
|
|
|
|
|
(yes-or-no-p (mu4e-format "Decrypt message?"))
|
2012-09-16 20:46:47 +02:00
|
|
|
|
mu4e-decryption-policy)))
|
2012-05-14 09:45:39 +02:00
|
|
|
|
(viewwin (mu4e~headers-redraw-get-view-window)))
|
2012-06-27 18:01:58 +02:00
|
|
|
|
(unless (window-live-p viewwin)
|
2012-07-10 11:11:06 +02:00
|
|
|
|
(mu4e-error "Cannot get a message view"))
|
2012-04-23 18:07:20 +02:00
|
|
|
|
(select-window viewwin)
|
2012-06-24 09:38:26 +02:00
|
|
|
|
(switch-to-buffer (mu4e~headers-get-loading-buf))
|
2012-09-13 20:10:27 +02:00
|
|
|
|
(mu4e~proc-view docid mu4e-show-images decrypt)))
|
2012-06-15 10:46:11 +02:00
|
|
|
|
|
2012-06-10 10:19:51 +02:00
|
|
|
|
(defun mu4e-headers-rerun-search ()
|
|
|
|
|
"Rerun the search for the last search expression."
|
|
|
|
|
(interactive)
|
2012-06-10 12:24:41 +02:00
|
|
|
|
(mu4e-headers-search mu4e~headers-last-query))
|
2012-05-07 09:05:31 +02:00
|
|
|
|
|
2012-06-10 12:24:41 +02:00
|
|
|
|
(defun mu4e~headers-query-navigate (whence)
|
2012-05-07 09:05:31 +02:00
|
|
|
|
"Execute the previous query from the query stacks. WHENCE
|
|
|
|
|
determines where the query is taken from and is a symbol, either
|
|
|
|
|
`future' or `past'."
|
|
|
|
|
(let ((query (mu4e~headers-pop-query whence))
|
|
|
|
|
(where (if (eq whence 'future) 'past 'future)))
|
2012-07-18 13:48:28 +02:00
|
|
|
|
(when query
|
|
|
|
|
(mu4e~headers-push-query mu4e~headers-last-query where)
|
|
|
|
|
(mu4e-headers-search query nil nil t))))
|
2012-05-07 09:05:31 +02:00
|
|
|
|
|
2012-06-10 12:24:41 +02:00
|
|
|
|
(defun mu4e-headers-query-next ()
|
2012-05-07 09:05:31 +02:00
|
|
|
|
"Execute the previous query from the query stacks."
|
2012-06-16 08:31:45 +02:00
|
|
|
|
(interactive)
|
2012-06-10 12:24:41 +02:00
|
|
|
|
(mu4e~headers-query-navigate 'future))
|
2012-04-11 01:08:02 +02:00
|
|
|
|
|
2012-06-10 12:24:41 +02:00
|
|
|
|
(defun mu4e-headers-query-prev ()
|
2012-05-07 09:05:31 +02:00
|
|
|
|
"Execute the previous query from the query stacks."
|
2012-06-16 08:31:45 +02:00
|
|
|
|
(interactive)
|
2012-06-10 12:24:41 +02:00
|
|
|
|
(mu4e~headers-query-navigate 'past))
|
2012-05-07 15:30:22 +02:00
|
|
|
|
|
|
|
|
|
;; forget the past so we don't repeat it :/
|
|
|
|
|
(defun mu4e-headers-forget-queries ()
|
|
|
|
|
"Forget all the complete query history."
|
|
|
|
|
(interactive)
|
|
|
|
|
(setq
|
2012-05-10 08:55:28 +02:00
|
|
|
|
;; note: don't forget the present one
|
2012-05-07 15:30:22 +02:00
|
|
|
|
mu4e~headers-query-past nil
|
|
|
|
|
mu4e~headers-query-future nil)
|
|
|
|
|
(mu4e-message "Query history cleared"))
|
|
|
|
|
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(defun mu4e~headers-move (lines)
|
2012-04-08 11:43:37 +02:00
|
|
|
|
"Move point LINES lines forward (if LINES is positive) or
|
|
|
|
|
backward (if LINES is negative). If this succeeds, return the new
|
|
|
|
|
docid. Otherwise, return nil."
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(unless (eq major-mode 'mu4e-headers-mode)
|
2012-07-10 11:11:06 +02:00
|
|
|
|
(mu4e-error "Must be in mu4e-headers-mode (%S)" major-mode))
|
2012-06-11 11:03:37 +02:00
|
|
|
|
(let ((succeeded (zerop (forward-line lines)))
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(docid (mu4e~headers-docid-at-point)))
|
2012-05-20 18:59:57 +02:00
|
|
|
|
;; move point, even if this function is called when this window is not
|
|
|
|
|
;; visible
|
2012-04-23 18:07:20 +02:00
|
|
|
|
(when docid
|
2012-06-11 11:03:37 +02:00
|
|
|
|
;; update all windows showing the headers buffer
|
|
|
|
|
(walk-windows
|
|
|
|
|
(lambda (win)
|
|
|
|
|
(when (eq (window-buffer win) mu4e~headers-buffer)
|
|
|
|
|
(set-window-point win (point))))
|
|
|
|
|
nil t)
|
|
|
|
|
;;(set-window-point (get-buffer-window mu4e~headers-buffer t) (point))
|
2012-04-23 18:07:20 +02:00
|
|
|
|
;; attempt to highlight the new line, display the message
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(mu4e~headers-highlight docid)
|
2012-05-21 14:28:55 +02:00
|
|
|
|
;; update message view if it was already showing
|
2012-05-20 18:59:57 +02:00
|
|
|
|
(when (window-live-p mu4e~headers-view-win)
|
2012-06-10 10:19:51 +02:00
|
|
|
|
(mu4e-headers-view-message))
|
|
|
|
|
docid)))
|
2012-04-11 01:08:02 +02:00
|
|
|
|
|
2012-05-06 10:00:56 +02:00
|
|
|
|
(defun mu4e-headers-next (&optional n)
|
2011-09-18 13:39:36 +02:00
|
|
|
|
"Move point to the next message header. If this succeeds, return
|
2012-05-06 10:00:56 +02:00
|
|
|
|
the new docid. Otherwise, return nil. Optionally, takes an integer
|
|
|
|
|
N (prefix argument), to the Nth next header."
|
|
|
|
|
(interactive "P")
|
|
|
|
|
(mu4e~headers-move (or n 1)))
|
2012-04-11 01:08:02 +02:00
|
|
|
|
|
2012-05-06 10:00:56 +02:00
|
|
|
|
(defun mu4e-headers-prev (&optional n)
|
|
|
|
|
"Move point to the previous message header. If this succeeds, return
|
|
|
|
|
the new docid. Otherwise, return nil. Optionally, takes an integer
|
|
|
|
|
N (prefix argument), to the Nth previous header."
|
|
|
|
|
(interactive "P")
|
|
|
|
|
(mu4e~headers-move (- (or n 1))))
|
2011-09-12 19:52:32 +02:00
|
|
|
|
|
2012-06-10 12:24:41 +02:00
|
|
|
|
(defun mu4e~headers-jump-to-maildir (maildir)
|
2012-03-19 20:45:26 +01:00
|
|
|
|
"Show the messages in maildir (user is prompted to ask what
|
2012-06-10 12:24:41 +02:00
|
|
|
|
maildir)."
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(interactive
|
|
|
|
|
(let ((maildir (mu4e-ask-maildir "Jump to maildir: ")))
|
2012-06-10 12:24:41 +02:00
|
|
|
|
(list maildir)))
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(when maildir
|
|
|
|
|
(mu4e-mark-handle-when-leaving)
|
2012-06-10 12:24:41 +02:00
|
|
|
|
(mu4e-headers-search (concat "\"maildir:" maildir "\""))))
|
2012-05-01 21:45:54 +02:00
|
|
|
|
|
2012-05-14 09:45:39 +02:00
|
|
|
|
(defun mu4e-headers-split-view-resize (n)
|
|
|
|
|
"In horizontal split-view, increase the number of lines shown by
|
|
|
|
|
N; in vertical split-view, increase the number of columns shown by
|
|
|
|
|
N. Otherwise, don't do anything."
|
|
|
|
|
(interactive "P")
|
2012-10-01 20:17:05 +02:00
|
|
|
|
(let ((n (or n 1))
|
|
|
|
|
(hwin (get-buffer-window mu4e~headers-buffer)))
|
|
|
|
|
(when (and (buffer-live-p mu4e~view-buffer) (window-live-p hwin))
|
|
|
|
|
(let ((n (or n 1)))
|
|
|
|
|
(case mu4e-split-view
|
|
|
|
|
;; emacs has weird ideas about what horizontal, vertical means...
|
|
|
|
|
(horizontal
|
|
|
|
|
(window-resize hwin n nil)
|
2012-10-22 19:27:14 +02:00
|
|
|
|
(incf mu4e-headers-visible-lines n))
|
2012-10-01 20:17:05 +02:00
|
|
|
|
(vertical
|
|
|
|
|
(window-resize hwin n t)
|
2012-10-22 19:27:14 +02:00
|
|
|
|
(incf mu4e-headers-visible-columns n)))))))
|
|
|
|
|
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(defun mu4e-headers-action ()
|
2012-04-20 17:23:16 +02:00
|
|
|
|
"Ask user what to do with message-at-point, then do it. The
|
|
|
|
|
actions are specified in `mu4e-headers-actions'."
|
|
|
|
|
(interactive)
|
2012-09-26 16:28:30 +02:00
|
|
|
|
(let ((msg (mu4e-message-at-point))
|
2012-04-26 21:42:15 +02:00
|
|
|
|
(actionfunc (mu4e-read-option "Action: " mu4e-headers-actions)))
|
2012-04-20 17:23:16 +02:00
|
|
|
|
(funcall actionfunc msg)))
|
|
|
|
|
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(defun mu4e-headers-mark-and-next (mark)
|
2012-04-23 18:07:20 +02:00
|
|
|
|
"Set mark MARK on the message at point or on all messages in the
|
|
|
|
|
region if there is a region, then move to the next message."
|
|
|
|
|
(interactive)
|
|
|
|
|
(mu4e-mark-set mark)
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(mu4e-headers-next))
|
2012-10-22 19:27:14 +02:00
|
|
|
|
|
2012-06-15 10:01:40 +02:00
|
|
|
|
(defun mu4e~headers-quit-buffer ()
|
2012-06-16 09:45:51 +02:00
|
|
|
|
"Quit the mu4e-headers buffer. This is a rather complex function,
|
|
|
|
|
to ensure we don't disturb other windows."
|
2012-06-15 10:01:40 +02:00
|
|
|
|
(interactive)
|
|
|
|
|
(unless (eq major-mode 'mu4e-headers-mode)
|
2012-07-10 11:11:06 +02:00
|
|
|
|
(mu4e-error "Must be in mu4e-headers-mode (%S)" major-mode))
|
2012-06-15 10:01:40 +02:00
|
|
|
|
(mu4e-mark-handle-when-leaving)
|
|
|
|
|
(let ((curbuf (current-buffer)) (curwin (selected-window))
|
|
|
|
|
(headers-visible))
|
|
|
|
|
(walk-windows
|
|
|
|
|
(lambda (win)
|
2012-08-11 10:55:34 +02:00
|
|
|
|
(with-selected-window win
|
|
|
|
|
;; if we the view window connected to this one, kill it
|
|
|
|
|
(when (and (not (one-window-p win)) (eq mu4e~headers-view-win win))
|
|
|
|
|
(delete-window win)
|
|
|
|
|
(setq mu4e~headers-view-win nil)))
|
2012-06-15 10:01:40 +02:00
|
|
|
|
;; and kill any _other_ (non-selected) window that shows the current
|
|
|
|
|
;; buffer
|
2012-06-22 08:45:28 +02:00
|
|
|
|
(when (and
|
|
|
|
|
(eq curbuf (window-buffer win)) ;; does win show curbuf?
|
|
|
|
|
(not (eq curwin win)) ;; it's not the curwin?
|
|
|
|
|
(not (one-window-p))) ;; and not the last one?
|
2012-06-15 10:01:40 +02:00
|
|
|
|
(delete-window win)))) ;; delete it!
|
|
|
|
|
;; now, all *other* windows should be gone. kill ourselves, and return
|
|
|
|
|
;; to the main view
|
|
|
|
|
(kill-buffer)
|
|
|
|
|
(mu4e~main-view)))
|
2012-06-15 10:46:11 +02:00
|
|
|
|
|
2011-09-18 13:39:36 +02:00
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
2012-05-01 21:45:54 +02:00
|
|
|
|
(provide 'mu4e-headers)
|