2012-04-07 16:59:08 +02:00
|
|
|
|
;;; mu4e-hdrs.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-03-31 16:20:03 +02:00
|
|
|
|
;; In this file are function related mu4e-hdrs-mode, to creating the list of
|
|
|
|
|
;; 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-04-08 11:43:37 +02:00
|
|
|
|
(require 'hl-line)
|
2012-04-09 15:34:52 +02:00
|
|
|
|
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(require 'mu4e-proc)
|
2012-04-09 10:51:24 +02:00
|
|
|
|
(require 'mu4e-utils) ;; utility functions
|
2012-04-09 15:34:52 +02:00
|
|
|
|
(require 'mu4e-vars)
|
2012-04-23 18:07:20 +02:00
|
|
|
|
(require 'mu4e-mark)
|
2012-04-24 17:13:12 +02:00
|
|
|
|
(require 'mu4e-actions)
|
|
|
|
|
|
|
|
|
|
;; the headers view
|
|
|
|
|
(defgroup mu4e-headers nil
|
|
|
|
|
"Settings for the headers view."
|
|
|
|
|
:group 'mu4e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(defcustom mu4e-headers-fields
|
|
|
|
|
'( (:date . 25)
|
|
|
|
|
(:flags . 6)
|
|
|
|
|
(:from . 22)
|
|
|
|
|
(:subject . nil))
|
|
|
|
|
"A list of header fields to show in the headers buffer, and their
|
|
|
|
|
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
|
|
|
|
|
`mu4e-header-names'"
|
|
|
|
|
:type (list 'symbol)
|
|
|
|
|
:group 'mu4e-headers)
|
|
|
|
|
|
|
|
|
|
(defcustom mu4e-headers-date-format "%x %X"
|
|
|
|
|
"Date format to use in the headers view, in the format of
|
|
|
|
|
`format-time-string'."
|
|
|
|
|
:type 'string
|
|
|
|
|
:group 'mu4e-headers)
|
|
|
|
|
|
|
|
|
|
(defcustom mu4e-headers-leave-behavior 'ask
|
|
|
|
|
"What to do when user leaves the headers view (e.g. quits,
|
|
|
|
|
refreshes or does a new search). Value is one of the following
|
|
|
|
|
symbols:
|
|
|
|
|
- ask (ask the user whether to ignore the marks)
|
|
|
|
|
- apply (automatically apply the marks before doing anything else)
|
|
|
|
|
- ignore (automatically ignore the marks without asking)."
|
|
|
|
|
:type 'symbol
|
|
|
|
|
:group 'mu4e-headers)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(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)
|
|
|
|
|
|
|
|
|
|
(defvar mu4e-headers-actions
|
|
|
|
|
'( ("capture message" ?c mu4e-action-capture-message))
|
|
|
|
|
"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.")
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-09-12 19:52:32 +02:00
|
|
|
|
|
|
|
|
|
;;;; internal variables/constants ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(defconst mu4e~hdrs-fringe " " "*internal* The space on the left of
|
2012-04-01 11:29:24 +02:00
|
|
|
|
message headers to put marks.")
|
2012-01-09 07:24:22 +01:00
|
|
|
|
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(defun mu4e~hdrs-clear ()
|
2012-03-25 12:28:06 +02:00
|
|
|
|
"Clear the header buffer and related data structures."
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(when (buffer-live-p mu4e~hdrs-buffer)
|
2012-03-25 12:28:06 +02:00
|
|
|
|
(let ((inhibit-read-only t))
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(with-current-buffer mu4e~hdrs-buffer
|
2012-03-25 12:28:06 +02:00
|
|
|
|
(erase-buffer)
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(mu4e~mark-clear)))))
|
2012-03-25 12:28:06 +02:00
|
|
|
|
|
|
|
|
|
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(defun mu4e-hdrs-search (expr &optional full-search)
|
2011-09-12 19:52:32 +02:00
|
|
|
|
"Search in the mu database for EXPR, and switch to the output
|
2011-12-07 07:50:03 +01:00
|
|
|
|
buffer for the results. If FULL-SEARCH is non-nil return all
|
|
|
|
|
results, otherwise, limit number of results to
|
2011-12-13 08:07:38 +01:00
|
|
|
|
`mu4e-search-results-limit'."
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(let ((buf (get-buffer-create mu4e~hdrs-buffer-name))
|
2012-04-15 13:21:59 +02:00
|
|
|
|
(inhibit-read-only t))
|
2011-09-18 13:39:36 +02:00
|
|
|
|
(with-current-buffer buf
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(mu4e-hdrs-mode)
|
2011-09-18 13:39:36 +02:00
|
|
|
|
(setq
|
2012-02-06 21:30:07 +01:00
|
|
|
|
global-mode-string (propertize expr 'face 'mu4e-title-face)
|
2011-12-13 08:07:38 +01:00
|
|
|
|
mu4e-last-expr expr
|
2012-04-23 19:35:14 +02:00
|
|
|
|
mu4e~hdrs-buffer buf
|
2012-01-21 10:20:11 +01:00
|
|
|
|
mode-name "mu4e-headers"))
|
2012-03-25 12:28:06 +02:00
|
|
|
|
(switch-to-buffer buf)
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(mu4e~proc-find
|
2012-04-15 13:21:59 +02:00
|
|
|
|
(replace-regexp-in-string "\"" "\\\\\"" expr) ;; escape "\"
|
|
|
|
|
(unless full-search mu4e-search-results-limit))
|
2012-04-08 19:28:49 +02:00
|
|
|
|
;;; when we're starting a new search, we also kill the
|
|
|
|
|
;;; view buffer, if any
|
|
|
|
|
(mu4e-view-kill-buffer-and-window)))
|
2012-04-11 01:08:02 +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-04-23 19:35:14 +02:00
|
|
|
|
(defun mu4e~hdrs-view-handler (msg)
|
2011-09-18 13:39:36 +02:00
|
|
|
|
"Handler function for displaying a message."
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(mu4e-view msg mu4e~hdrs-buffer))
|
2011-09-12 19:52:32 +02:00
|
|
|
|
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(defun mu4e~hdrs-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-04-23 19:35:14 +02:00
|
|
|
|
(when (buffer-live-p mu4e~hdrs-buffer)
|
|
|
|
|
(with-current-buffer mu4e~hdrs-buffer
|
2011-09-18 13:39:36 +02:00
|
|
|
|
(let* ((docid (plist-get msg :docid))
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(point (mu4e~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
|
|
|
|
|
;; *update* message don't have thread info by themselves (unlike
|
|
|
|
|
;; search results)
|
|
|
|
|
;; but since we still have the search results, re-use those
|
|
|
|
|
(plist-put msg :thread
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(mu4e~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-04-23 19:35:14 +02:00
|
|
|
|
(mu4e~hdrs-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
|
|
|
|
|
;; update the `mu4e-current-msg' there as well; that way, the flags can
|
2011-11-20 09:31:38 +01:00
|
|
|
|
;; be updated, as well as the path (which is useful for viewing the
|
|
|
|
|
;; raw message)
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(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
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(when (eq docid (plist-get mu4e-current-msg :docid))
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(mu4e-view msg mu4e~hdrs-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-04-23 19:35:14 +02:00
|
|
|
|
(mu4e~hdrs-header-handler msg point))
|
2012-04-09 22:48:30 +02:00
|
|
|
|
|
|
|
|
|
;; attempt to highlight the corresponding line and make it visible
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(mu4e~hdrs-highlight docid))))))
|
2011-09-30 07:37:47 +02:00
|
|
|
|
|
2011-09-18 13:39:36 +02:00
|
|
|
|
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(defun mu4e~hdrs-remove-handler (docid)
|
2011-09-18 13:39:36 +02:00
|
|
|
|
"Remove handler, will be called when a message has been removed
|
2012-03-25 12:28:06 +02:00
|
|
|
|
from the database. This function will hide the removed message from
|
2011-09-18 13:39:36 +02:00
|
|
|
|
the current list of headers."
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(when (buffer-live-p mu4e~hdrs-buffer)
|
|
|
|
|
(with-current-buffer mu4e~hdrs-buffer
|
|
|
|
|
(mu4e~hdrs-remove-header docid))))
|
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-04-23 19:35:14 +02:00
|
|
|
|
(defun mu4e~hdrs-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 ", "))
|
|
|
|
|
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(defun mu4e-thread-prefix (thread)
|
2011-11-20 00:19:07 +01:00
|
|
|
|
"Calculate the thread prefix based on thread info THREAD."
|
|
|
|
|
(if thread
|
|
|
|
|
(let ( (level (plist-get thread :level))
|
|
|
|
|
(first-child (plist-get thread :first-child))
|
|
|
|
|
(has-child (plist-get thread :has-child))
|
|
|
|
|
(duplicate (plist-get thread :duplicate))
|
|
|
|
|
(empty-parent (plist-get thread :empty-parent)))
|
|
|
|
|
(concat
|
|
|
|
|
(make-string (* (if empty-parent 0 2) level) ?\s)
|
|
|
|
|
(cond
|
|
|
|
|
(has-child "+ ")
|
|
|
|
|
(empty-parent "- ")
|
|
|
|
|
(first-child "\\ ")
|
|
|
|
|
(duplicate "= ")
|
|
|
|
|
(t "| "))))))
|
2011-11-09 07:35:24 +01:00
|
|
|
|
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(defun mu4e~hdrs-header-handler (msg &optional point)
|
2011-09-30 07:37:47 +02:00
|
|
|
|
"Create a one line description of MSG in this buffer, at POINT,
|
|
|
|
|
if provided, or at the end of the buffer otherwise."
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(when (buffer-live-p mu4e~hdrs-buffer)
|
2012-03-25 12:28:06 +02:00
|
|
|
|
(let* ((docid (plist-get msg :docid))
|
2011-11-20 00:19:07 +01:00
|
|
|
|
(line
|
2011-11-13 11:44:54 +01:00
|
|
|
|
(mapconcat
|
|
|
|
|
(lambda (f-w)
|
|
|
|
|
(let* ((field (car f-w)) (width (cdr f-w))
|
|
|
|
|
(val (plist-get msg field))
|
|
|
|
|
(str
|
|
|
|
|
(case field
|
2012-04-11 01:08:02 +02:00
|
|
|
|
(:subject
|
|
|
|
|
(concat ;; prefix subject with a thread indicator
|
|
|
|
|
(mu4e-thread-prefix (plist-get msg :thread))
|
|
|
|
|
val))
|
2011-11-20 00:19:07 +01:00
|
|
|
|
((:maildir :path) val)
|
2012-04-23 19:35:14 +02:00
|
|
|
|
((:to :from :cc :bcc) (mu4e~hdrs-contact-str val))
|
2011-12-07 07:50:03 +01:00
|
|
|
|
;; if we (ie. `user-mail-address' is the 'From', show
|
|
|
|
|
;; 'To', otherwise show From
|
2011-11-13 11:44:54 +01:00
|
|
|
|
(:from-or-to
|
|
|
|
|
(let* ((from-lst (plist-get msg :from))
|
|
|
|
|
(from (and from-lst (cdar from-lst))))
|
2011-12-07 07:50:03 +01:00
|
|
|
|
(if (and from (string-match
|
2011-12-13 08:07:38 +01:00
|
|
|
|
mu4e-user-mail-address-regexp from))
|
2011-11-13 11:44:54 +01:00
|
|
|
|
(concat "To "
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(mu4e~hdrs-contact-str (plist-get msg :to)))
|
|
|
|
|
(mu4e~hdrs-contact-str from-lst))))
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(:date (format-time-string mu4e-headers-date-format val))
|
|
|
|
|
(:flags (mu4e-flags-to-string val))
|
|
|
|
|
(:size (mu4e-display-size val))
|
2011-11-20 00:19:07 +01:00
|
|
|
|
(t (error "Unsupported header field (%S)" field)))))
|
2011-11-13 11:44:54 +01:00
|
|
|
|
(when str
|
|
|
|
|
(if (not width)
|
|
|
|
|
str
|
|
|
|
|
(truncate-string-to-width str width 0 ?\s t)))))
|
2011-12-13 08:07:38 +01:00
|
|
|
|
mu4e-headers-fields " "))
|
2011-09-20 22:59:20 +02:00
|
|
|
|
(flags (plist-get msg :flags))
|
|
|
|
|
(line (cond
|
2011-10-23 23:20:32 +02:00
|
|
|
|
((member 'draft flags)
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(propertize line 'face 'mu4e-draft-face 'draft t))
|
2011-10-23 23:20:32 +02:00
|
|
|
|
((member 'trashed flags)
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(propertize line 'face 'mu4e-trashed-face))
|
2011-10-23 23:20:32 +02:00
|
|
|
|
((member 'unread flags)
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(propertize line 'face 'mu4e-unread-face))
|
2011-10-23 23:20:32 +02:00
|
|
|
|
(t ;; else
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(propertize line 'face 'mu4e-header-face)))))
|
2011-11-20 09:31:38 +01:00
|
|
|
|
|
2012-03-25 12:28:06 +02:00
|
|
|
|
;; now, append the header line
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(mu4e~hdrs-add-header line docid point msg))))
|
2011-10-25 07:43:24 +02:00
|
|
|
|
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(defun mu4e~hdrs-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-04-23 19:35:14 +02:00
|
|
|
|
(when (buffer-live-p mu4e~hdrs-buffer)
|
|
|
|
|
(with-current-buffer mu4e~hdrs-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)
|
|
|
|
|
"No matching messages found"
|
|
|
|
|
"End of search results")))
|
|
|
|
|
(insert (propertize str 'face 'mu4e-system-face 'intangible t))
|
|
|
|
|
(unless (= 0 count)
|
|
|
|
|
(message "Found %d matching message%s"
|
2012-04-09 15:34:52 +02:00
|
|
|
|
count (if (= 1 count) "" "s"))
|
|
|
|
|
;; highlight the first message
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(mu4e~hdrs-highlight (mu4e~docid-at-point (point-min)))))))))
|
2011-09-12 19:52:32 +02:00
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
|
|
|
|
|
|
2012-03-28 23:28:49 +02:00
|
|
|
|
|
2012-04-23 18:07:20 +02:00
|
|
|
|
|
|
|
|
|
|
2011-10-18 11:39:49 +02:00
|
|
|
|
;;; hdrs-mode and mode-map ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(defvar mu4e-hdrs-mode-map nil
|
|
|
|
|
"Keymap for *mu4e-headers* buffers.")
|
|
|
|
|
(unless mu4e-hdrs-mode-map
|
2012-04-23 18:07:20 +02:00
|
|
|
|
;; add some quick funcs so our key descriptions below are shorter
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(defun mu4e~hdrs-mark-trash()(interactive)(mu4e-hdrs-mark-and-next 'trash))
|
|
|
|
|
(defun mu4e~hdrs-mark-delete()(interactive)(mu4e-hdrs-mark-and-next 'delete))
|
|
|
|
|
(defun mu4e~hdrs-mark-unmark()(interactive)(mu4e-hdrs-mark-and-next 'unmark))
|
|
|
|
|
(defun mu4e~hdrs-mark-read()(interactive)(mu4e-hdrs-mark-and-next 'read))
|
|
|
|
|
(defun mu4e~hdrs-mark-unread()(interactive)(mu4e-hdrs-mark-and-next 'unread))
|
2012-04-23 18:07:20 +02:00
|
|
|
|
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(setq mu4e-hdrs-mode-map
|
2011-10-18 11:39:49 +02:00
|
|
|
|
(let ((map (make-sparse-keymap)))
|
|
|
|
|
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(define-key map "s" 'mu4e-search)
|
2011-12-23 18:09:03 +01:00
|
|
|
|
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(define-key map "b" 'mu4e-search-bookmark)
|
2012-03-25 19:33:17 +02:00
|
|
|
|
(define-key map "B" 'mu4e-search-bookmark-edit-first)
|
2012-03-27 20:16:32 +02:00
|
|
|
|
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(define-key map "q" 'mu4e~hdrs-kill-buffer-and-window)
|
|
|
|
|
(define-key map "z" 'mu4e~hdrs-kill-buffer-and-window)
|
2012-04-11 01:08:02 +02:00
|
|
|
|
|
2011-12-15 20:47:01 +01:00
|
|
|
|
(define-key map "r" 'mu4e-rerun-search)
|
2012-01-06 16:23:09 +01:00
|
|
|
|
(define-key map "g" 'mu4e-rerun-search) ;; for compatibility
|
2011-10-25 07:43:24 +02:00
|
|
|
|
|
2011-10-18 11:39:49 +02:00
|
|
|
|
;; navigation
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(define-key map "n" 'mu4e-next-header)
|
|
|
|
|
(define-key map "p" 'mu4e-prev-header)
|
2012-04-09 10:51:24 +02:00
|
|
|
|
;; the same
|
|
|
|
|
(define-key map (kbd "<M-down>") 'mu4e-next-header)
|
|
|
|
|
(define-key map (kbd "<M-up>") 'mu4e-prev-header)
|
2012-04-11 01:08:02 +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-04-23 19:35:14 +02:00
|
|
|
|
(define-key map (kbd "<backspace>") 'mu4e~hdrs-mark-trash)
|
|
|
|
|
(define-key map (kbd "d") 'mu4e~hdrs-mark-trash)
|
2011-10-25 07:43:24 +02:00
|
|
|
|
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(define-key map (kbd "<delete>") 'mu4e~hdrs-mark-delete)
|
|
|
|
|
(define-key map (kbd "<deletechar>") 'mu4e~hdrs-mark-delete)
|
|
|
|
|
(define-key map (kbd "D") 'mu4e~hdrs-mark-delete)
|
2012-04-23 18:07:20 +02:00
|
|
|
|
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(define-key map (kbd "o") 'mu4e~hdrs-mark-unread)
|
|
|
|
|
(define-key map (kbd "r") 'mu4e~hdrs-mark-read)
|
|
|
|
|
(define-key map (kbd "u") 'mu4e~hdrs-mark-unmark)
|
2012-04-23 18:07:20 +02:00
|
|
|
|
|
|
|
|
|
(define-key map "m" 'mu4e-hdrs-mark-for-move-and-next)
|
|
|
|
|
|
|
|
|
|
(define-key map "U" 'mu4e-mark-unmark-all)
|
|
|
|
|
(define-key map "x" 'mu4e-mark-execute-all)
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
|
2012-02-09 20:10:33 +01:00
|
|
|
|
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(define-key map "j" 'mu4e-jump-to-maildir)
|
2012-04-20 17:23:16 +02:00
|
|
|
|
(define-key map "a" 'mu4e-hdrs-action)
|
|
|
|
|
|
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
|
|
|
|
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(define-key map (kbd "RET") 'mu4e-view-message)
|
2011-12-26 11:18:12 +01:00
|
|
|
|
(define-key map [mouse-2] 'mu4e-view-message)
|
|
|
|
|
|
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-04-23 19:35:14 +02:00
|
|
|
|
(define-key menumap [mu4e~hdrs-kill-buffer-and-window]
|
|
|
|
|
'("Quit view" . mu4e~hdrs-kill-buffer-and-window))
|
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-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-04-23 19:35:14 +02:00
|
|
|
|
(define-key menumap [unmark] '("Unmark" . mu4e~hdrs-mark-unmark))
|
2011-10-18 11:39:49 +02:00
|
|
|
|
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(define-key menumap [mark-as-read] '("Mark as read" . mu4e~hdrs-mark-read))
|
2012-02-27 22:41:11 +01:00
|
|
|
|
(define-key menumap [mark-as-unread]
|
2012-04-23 19:35:14 +02:00
|
|
|
|
'("Mark as unread" . mu4e~hdrs-mark-unread))
|
2012-02-09 20:10:33 +01:00
|
|
|
|
|
2012-02-27 22:41:11 +01:00
|
|
|
|
(define-key menumap [mark-delete]
|
2012-04-23 19:35:14 +02:00
|
|
|
|
'("Mark for deletion" . mu4e~hdrs-mark-delete))
|
2012-04-23 18:07:20 +02:00
|
|
|
|
(define-key menumap [mark-trash]
|
2012-04-23 19:35:14 +02:00
|
|
|
|
'("Mark for trash" . mu4e~hdrs-mark-trash))
|
2012-04-23 18:07:20 +02:00
|
|
|
|
(define-key menumap [mark-move]
|
|
|
|
|
'("Mark for move" . mu4e-hdrs-mark-for-move-and-next))
|
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] '("--"))
|
|
|
|
|
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(define-key menumap [refresh] '("Refresh" . mu4e-rerun-search))
|
2011-12-15 07:51:39 +01:00
|
|
|
|
(define-key menumap [search] '("Search" . mu4e-search))
|
|
|
|
|
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(define-key menumap [jump] '("Jump to maildir" . mu4e-jump-to-maildir))
|
2011-10-18 11:39:49 +02:00
|
|
|
|
(define-key menumap [sepa3] '("--"))
|
2011-10-25 07:43:24 +02:00
|
|
|
|
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(define-key menumap [view] '("View" . mu4e-view-message))
|
|
|
|
|
(define-key menumap [next] '("Next" . mu4e-next-header))
|
|
|
|
|
(define-key menumap [previous] '("Previous" . mu4e-prev-header))
|
2011-10-18 11:39:49 +02:00
|
|
|
|
(define-key menumap [sepa4] '("--")))
|
|
|
|
|
map)))
|
|
|
|
|
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(fset 'mu4e-hdrs-mode-map mu4e-hdrs-mode-map)
|
2011-09-12 19:52:32 +02:00
|
|
|
|
|
2011-10-18 11:39:49 +02:00
|
|
|
|
|
2012-03-27 20:16:32 +02:00
|
|
|
|
(define-derived-mode mu4e-hdrs-mode special-mode
|
|
|
|
|
"mu4e:headers"
|
2012-01-14 10:05:23 +01:00
|
|
|
|
"Major mode for displaying mu4e search results.
|
|
|
|
|
\\{mu4e-hdrs-mode-map}."
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(use-local-map mu4e-hdrs-mode-map)
|
|
|
|
|
|
|
|
|
|
(make-local-variable 'mu4e-last-expr)
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(make-local-variable 'mu4e~hdrs-proc)
|
|
|
|
|
(make-local-variable 'mu4e~highlighted-docid)
|
2012-04-11 01:08:02 +02:00
|
|
|
|
|
2012-04-08 11:43:37 +02:00
|
|
|
|
(make-local-variable 'global-mode-string)
|
|
|
|
|
(make-local-variable 'hl-line-face)
|
2012-04-11 01:08:02 +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
|
|
|
|
|
hl-line-face 'mu4e-header-highlight-face)
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(mu4e~mark-initialize) ;; initialize the marking subsystem
|
2012-04-08 11:43:37 +02:00
|
|
|
|
(hl-line-mode 1)
|
2012-04-11 01:08:02 +02:00
|
|
|
|
|
2012-03-27 20:16:32 +02:00
|
|
|
|
(setq header-line-format
|
|
|
|
|
(cons
|
|
|
|
|
(make-string
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(+ (length mu4e~hdrs-fringe) (floor (fringe-columns 'left t))) ?\s)
|
2012-03-27 20:16:32 +02:00
|
|
|
|
(map 'list
|
|
|
|
|
(lambda (item)
|
|
|
|
|
(let ((field (cdr (assoc (car item) mu4e-header-names)))
|
|
|
|
|
(width (cdr item)))
|
|
|
|
|
(concat
|
|
|
|
|
(propertize
|
|
|
|
|
(if width
|
|
|
|
|
(truncate-string-to-width field width 0 ?\s t)
|
|
|
|
|
field)
|
2012-04-01 11:29:24 +02:00
|
|
|
|
'face 'mu4e-header-title-face) " ")))
|
2012-03-27 20:16:32 +02:00
|
|
|
|
mu4e-headers-fields))))
|
2011-12-29 09:39:30 +01: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-04-09 15:34:52 +02:00
|
|
|
|
"*internal* The highlighted docid")
|
|
|
|
|
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(defun mu4e~hdrs-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-04-23 19:35:14 +02:00
|
|
|
|
(with-current-buffer mu4e~hdrs-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
|
|
|
|
|
(mu4e~goto-docid mu4e~highlighted-docid))
|
2012-04-09 15:34:52 +02:00
|
|
|
|
(hl-line-unhighlight))
|
|
|
|
|
;; now, highlight the new one
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(when (mu4e~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
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
(defun mu4e-select-headers-window-if-visible ()
|
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-04-23 19:35:14 +02:00
|
|
|
|
(let ((win (get-buffer-window mu4e~hdrs-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-04-23 19:35:14 +02:00
|
|
|
|
(defun mu4e~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."
|
|
|
|
|
(propertize (format "%d\004" docid) 'docid docid 'invisible t))
|
|
|
|
|
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(defun mu4e~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-04-23 19:35:14 +02:00
|
|
|
|
(defun mu4e~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
|
|
|
|
|
(search-forward (format "%d\004" docid) nil t))
|
|
|
|
|
(when (null to-mark)
|
|
|
|
|
(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-04-23 19:35:14 +02:00
|
|
|
|
(defun mu4e~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-04-23 19:35:14 +02:00
|
|
|
|
(setq pos (mu4e~goto-docid docid)))
|
2012-04-07 16:59:08 +02:00
|
|
|
|
pos))
|
|
|
|
|
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(defun mu4e~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-04-23 19:35:14 +02:00
|
|
|
|
(when (mu4e~goto-docid docid)
|
2012-04-11 21:31:52 +02:00
|
|
|
|
(mu4e-field-at-point field))))
|
2012-04-11 01:08:02 +02:00
|
|
|
|
|
2012-04-08 11:43:37 +02:00
|
|
|
|
;;;; markers mark headers for
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(defun mu4e~mark-header (docid mark)
|
2012-04-07 16:59:08 +02:00
|
|
|
|
"(Visually) mark the header for DOCID with character MARK."
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(with-current-buffer mu4e~hdrs-buffer
|
2012-04-07 16:59:08 +02:00
|
|
|
|
(let ((inhibit-read-only t) (oldpoint (point)))
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(unless (mu4e~goto-docid docid)
|
2012-04-07 16:59:08 +02:00
|
|
|
|
(error "Cannot find message with docid %S" docid))
|
|
|
|
|
;; now, we're at the beginning of the header, looking at
|
|
|
|
|
;; <docid>\004
|
|
|
|
|
;; (which is invisible). jumpp past that…
|
|
|
|
|
(unless (re-search-forward "\004" nil t)
|
|
|
|
|
(error "Cannot find \004 separator"))
|
|
|
|
|
;; we found the \004; we move point one to the right for the
|
|
|
|
|
;; the area to write the marker.
|
|
|
|
|
;;(forward-char)
|
|
|
|
|
;; clear old marks, and add the new ones.
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(delete-char (length mu4e~hdrs-fringe))
|
2012-04-07 16:59:08 +02:00
|
|
|
|
(insert (propertize mark 'face 'mu4e-hdrs-marks-face) " ")
|
|
|
|
|
(goto-char oldpoint))))
|
2012-03-25 12:28:06 +02:00
|
|
|
|
|
|
|
|
|
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(defun mu4e~hdrs-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-04-08 19:28:49 +02:00
|
|
|
|
at (point-max) otherwise. If MSG is not nil, add it as the text-property `msg'."
|
2011-09-20 22:59:20 +02:00
|
|
|
|
(unless docid (error "Invalid message"))
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(when (buffer-live-p mu4e~hdrs-buffer)
|
|
|
|
|
(with-current-buffer mu4e~hdrs-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-04-23 19:35:14 +02:00
|
|
|
|
(mu4e~docid-cookie docid)
|
|
|
|
|
mu4e~hdrs-fringe str "\n") 'docid docid 'msg msg)))))))
|
2011-12-26 11:18:12 +01:00
|
|
|
|
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(defun mu4e~hdrs-remove-header (docid)
|
2011-09-22 20:01:35 +02:00
|
|
|
|
"Remove header with DOCID at POINT."
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(with-current-buffer mu4e~hdrs-buffer
|
|
|
|
|
(unless (mu4e~goto-docid docid)
|
2012-04-07 16:59:08 +02:00
|
|
|
|
(error "Cannot find message with docid %S" docid))
|
2011-09-30 07:37:47 +02:00
|
|
|
|
(let ((inhibit-read-only t))
|
2012-04-07 16:59:08 +02:00
|
|
|
|
(delete-region (line-beginning-position) (line-beginning-position 2)))))
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
2011-09-12 19:52:32 +02:00
|
|
|
|
|
2011-11-20 00:19:07 +01:00
|
|
|
|
|
2011-09-12 19:52:32 +02:00
|
|
|
|
|
|
|
|
|
;;; interactive functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(defun mu4e-search (expr)
|
2012-02-27 22:41:11 +01:00
|
|
|
|
"Start a new mu search. If prefix ARG is nil, limit the number of
|
2011-12-17 10:32:43 +01:00
|
|
|
|
results to `mu4e-search-results-limit', otherwise show all. In
|
|
|
|
|
other words, use the C-u prefix to get /all/ results, otherwise get
|
|
|
|
|
up to `mu4e-search-results-limit' much quicker."
|
2012-02-27 22:41:11 +01:00
|
|
|
|
(interactive "s[mu] search for: ")
|
2012-04-23 18:07:20 +02:00
|
|
|
|
(when (mu4e-mark-handle-when-leaving)
|
2012-02-27 22:41:11 +01:00
|
|
|
|
(mu4e-hdrs-search expr current-prefix-arg)))
|
2011-09-12 19:52:32 +02:00
|
|
|
|
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(defun mu4e-search-bookmark ()
|
2012-03-25 12:28:06 +02:00
|
|
|
|
"Search using some bookmarked query. With C-u prefix, show /all/ results,
|
|
|
|
|
otherwise, limit to up to `mu4e-search-results-limit'."
|
2011-12-03 13:22:30 +01:00
|
|
|
|
(interactive)
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(let ((query (mu4e-ask-bookmark "Bookmark: ")))
|
2012-04-23 18:07:20 +02:00
|
|
|
|
(when (and query (mu4e-mark-handle-when-leaving))
|
2011-12-17 10:32:43 +01:00
|
|
|
|
(mu4e-hdrs-search query current-prefix-arg))))
|
2011-12-07 07:50:03 +01:00
|
|
|
|
|
2012-03-25 19:33:17 +02:00
|
|
|
|
(defun mu4e-search-bookmark-edit-first (expr)
|
|
|
|
|
"Search using some bookmarked query, but allow for editing the
|
|
|
|
|
bookmark before submitting it. With C-u prefix, show /all/ results,
|
|
|
|
|
otherwise, limit to up to `mu4e-search-results-limit'."
|
|
|
|
|
(interactive
|
|
|
|
|
(list (read-string "[mu] search for: "
|
|
|
|
|
(concat (or (mu4e-ask-bookmark "Edit bookmark: ") "") " "))))
|
2012-04-23 18:07:20 +02:00
|
|
|
|
(when (and expr (mu4e-mark-handle-when-leaving))
|
2012-03-25 19:33:17 +02:00
|
|
|
|
(mu4e-hdrs-search expr current-prefix-arg)))
|
|
|
|
|
|
2012-04-23 18:07:20 +02:00
|
|
|
|
|
|
|
|
|
(defun mu4e-view-message ()
|
|
|
|
|
"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)
|
|
|
|
|
(unless (eq major-mode 'mu4e-hdrs-mode)
|
|
|
|
|
(error "Must be in mu4e-hdrs-mode (%S)" major-mode))
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(let* ((docid (mu4e~docid-at-point))
|
2012-04-23 18:07:20 +02:00
|
|
|
|
(viewwin (and mu4e-view-buffer
|
|
|
|
|
(get-buffer-window mu4e-view-buffer))))
|
|
|
|
|
(unless docid (error "No message at point."))
|
|
|
|
|
;; is there a window already for the message view?
|
|
|
|
|
(unless (window-live-p viewwin)
|
|
|
|
|
;; no view window yet; create one, based on the split settings etc.
|
|
|
|
|
;; emacs' use of the terms "horizontally" and "vertically"
|
|
|
|
|
;; are... suprising. There's a clearer `split-window' in emacs24, but
|
|
|
|
|
;; it's not compatible with emacs 23
|
|
|
|
|
(setq viewwin
|
|
|
|
|
(cond ;; is there are live window for the message view?
|
|
|
|
|
((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)))))
|
|
|
|
|
;; okay, now we should have a window for the message view
|
|
|
|
|
;; we select it, and show the messages there.
|
|
|
|
|
(select-window viewwin)
|
|
|
|
|
(switch-to-buffer (get-buffer-create mu4e-view-buffer-name))
|
|
|
|
|
(let ((inhibit-read-only t))
|
|
|
|
|
(erase-buffer)
|
|
|
|
|
(insert (propertize "Waiting for message..."
|
|
|
|
|
'face 'mu4e-system-face 'intangible t)))
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(mu4e~proc-view docid)))
|
2012-04-23 18:07:20 +02:00
|
|
|
|
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(defun mu4e~hdrs-kill-buffer-and-window ()
|
2012-04-08 19:28:49 +02:00
|
|
|
|
"Quit the message view and return to the main view."
|
2011-09-12 19:52:32 +02:00
|
|
|
|
(interactive)
|
2012-04-23 18:07:20 +02:00
|
|
|
|
(when (mu4e-mark-handle-when-leaving)
|
2012-04-24 08:08:15 +02:00
|
|
|
|
(let ((buf mu4e~hdrs-buffer))
|
|
|
|
|
(when (buffer-live-p buf)
|
|
|
|
|
(bury-buffer)
|
|
|
|
|
(delete-windows-on buf) ;; destroy all windows for this buffer
|
|
|
|
|
(kill-buffer buf)))
|
2012-04-12 08:01:28 +02:00
|
|
|
|
(mu4e-main-view)))
|
2012-04-24 08:08:15 +02:00
|
|
|
|
|
2011-09-12 19:52:32 +02:00
|
|
|
|
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(defun mu4e-rerun-search ()
|
2011-09-12 19:52:32 +02:00
|
|
|
|
"Rerun the search for the last search expression; if none exists,
|
|
|
|
|
do a new search."
|
|
|
|
|
(interactive)
|
2012-04-23 18:07:20 +02:00
|
|
|
|
(when (mu4e-mark-handle-when-leaving)
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(if mu4e-last-expr
|
|
|
|
|
(mu4e-hdrs-search mu4e-last-expr)
|
2012-04-09 15:34:52 +02:00
|
|
|
|
(call-interactively 'mu4e-search))))
|
2012-04-11 01:08:02 +02:00
|
|
|
|
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(defun mu4e~hdrs-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-04-23 18:07:20 +02:00
|
|
|
|
(unless (eq major-mode 'mu4e-hdrs-mode)
|
|
|
|
|
(error "Must be in mu4e-hdrs-mode (%S)" major-mode))
|
|
|
|
|
(let ((succeeded (= 0 (forward-line lines)))
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(docid (mu4e~docid-at-point)))
|
2012-04-23 18:07:20 +02:00
|
|
|
|
;; trick to move point, even if this function is called when this window
|
|
|
|
|
;; is not visible
|
|
|
|
|
(when docid
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(set-window-point (get-buffer-window mu4e~hdrs-buffer) (point))
|
2012-04-23 18:07:20 +02:00
|
|
|
|
;; attempt to highlight the new line, display the message
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(mu4e~hdrs-highlight docid)
|
2012-04-23 18:07:20 +02:00
|
|
|
|
;; if there already is a visible message view, show the message
|
|
|
|
|
(when (and (buffer-live-p mu4e-view-buffer)
|
|
|
|
|
(window-live-p (get-buffer-window mu4e-view-buffer)))
|
|
|
|
|
(mu4e-view-message)))
|
|
|
|
|
;; return the docid only if the move succeeded
|
|
|
|
|
(when succeeded docid)))
|
2012-04-11 01:08:02 +02:00
|
|
|
|
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(defun mu4e-next-header ()
|
2011-09-18 13:39:36 +02:00
|
|
|
|
"Move point to the next message header. If this succeeds, return
|
|
|
|
|
the new docid. Otherwise, return nil."
|
2011-09-12 19:52:32 +02:00
|
|
|
|
(interactive)
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(mu4e~hdrs-move 1))
|
2012-04-11 01:08:02 +02:00
|
|
|
|
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(defun mu4e-prev-header ()
|
2011-09-18 13:39:36 +02:00
|
|
|
|
"Move point to the previous message header. If this succeeds,
|
|
|
|
|
return the new docid. Otherwise, return nil."
|
2011-09-12 19:52:32 +02:00
|
|
|
|
(interactive)
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(mu4e~hdrs-move -1))
|
2011-09-18 13:39:36 +02:00
|
|
|
|
|
2011-09-12 19:52:32 +02:00
|
|
|
|
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(defun mu4e-jump-to-maildir ()
|
2012-03-19 20:45:26 +01:00
|
|
|
|
"Show the messages in maildir (user is prompted to ask what
|
|
|
|
|
maildir). With C-u prefix, show /all/ results, otherwise, limit to
|
|
|
|
|
up to `mu4e-search-results-limit'."
|
2011-09-12 19:52:32 +02:00
|
|
|
|
(interactive)
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(let ((fld (mu4e-ask-maildir "Jump to maildir: ")))
|
2012-04-23 18:07:20 +02:00
|
|
|
|
(when (and fld (mu4e-mark-handle-when-leaving))
|
2012-01-21 10:20:11 +01:00
|
|
|
|
(mu4e-hdrs-search (concat "\"maildir:" fld "\"")
|
|
|
|
|
current-prefix-arg))))
|
2011-09-12 19:52:32 +02:00
|
|
|
|
|
2012-03-25 12:28:06 +02:00
|
|
|
|
|
2012-04-15 13:21:59 +02:00
|
|
|
|
(defun mu4e-compose (compose-type)
|
2012-03-25 12:28:06 +02:00
|
|
|
|
"Start composing a message of COMPOSE-TYPE, where COMPOSE-TYPE is
|
|
|
|
|
a symbol, one of `reply', `forward', `edit', `new'. All but `new'
|
|
|
|
|
take the message at point as input. Symbol `edit' is only allowed
|
|
|
|
|
for draft messages."
|
2011-09-18 13:39:36 +02:00
|
|
|
|
(interactive)
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(let ((mu4e~hdrs-buffer (get-buffer-create mu4e~hdrs-buffer-name))
|
2012-03-27 20:16:32 +02:00
|
|
|
|
(compose-type
|
|
|
|
|
(or compose-type
|
|
|
|
|
(intern (ido-completing-read "Compose type: "
|
|
|
|
|
'("reply" "forward" "edit" "new"))))))
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(with-current-buffer mu4e~hdrs-buffer
|
2012-03-25 12:28:06 +02:00
|
|
|
|
;; 'new is special, since it takes no existing message as arg therefore,
|
|
|
|
|
;; we don't need to call thec backend, and call the handler *directly*
|
|
|
|
|
(if (eq compose-type 'new)
|
2012-04-23 20:16:20 +02:00
|
|
|
|
(mu4e~compose-handler 'new)
|
2012-03-25 12:28:06 +02:00
|
|
|
|
;; otherwise, we need the doc-id
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(let ((docid (mu4e~docid-at-point)))
|
2012-03-25 12:28:06 +02:00
|
|
|
|
(unless docid (error "No message at point."))
|
|
|
|
|
;; note, the first two chars of the line (the mark margin) does *not*
|
|
|
|
|
;; have the 'draft property; thus, we check one char before the end of
|
|
|
|
|
;; the current line instead
|
2012-03-27 20:16:32 +02:00
|
|
|
|
(unless (or (not (eq compose-type 'edit))
|
|
|
|
|
(get-text-property (- (line-end-position) 1) 'draft))
|
|
|
|
|
(error "Editing is only allowed for draft messages"))
|
2012-04-16 19:42:56 +02:00
|
|
|
|
;; if there's a visible view window, select that before starting
|
|
|
|
|
;; composing a new message, so that one will be replaced by the
|
|
|
|
|
;; compose window. The 10-or-so line headers buffer is not a good way
|
|
|
|
|
;; to write it...
|
|
|
|
|
(let ((viewwin (get-buffer-window mu4e-view-buffer)))
|
|
|
|
|
(when (window-live-p viewwin)
|
|
|
|
|
(select-window viewwin)))
|
|
|
|
|
|
2012-03-25 12:28:06 +02:00
|
|
|
|
;; talk to the backend
|
2012-04-23 19:35:14 +02:00
|
|
|
|
(mu4e~proc-compose compose-type docid))))))
|
2012-04-11 01:08:02 +02:00
|
|
|
|
|
2012-03-25 12:28:06 +02:00
|
|
|
|
(defun mu4e-compose-reply ()
|
|
|
|
|
"Reply to the current message."
|
|
|
|
|
(interactive) (mu4e-compose 'reply))
|
2011-09-18 13:39:36 +02:00
|
|
|
|
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(defun mu4e-compose-forward ()
|
2012-03-25 12:28:06 +02:00
|
|
|
|
"Forward the current message."
|
|
|
|
|
(interactive) (mu4e-compose 'forward))
|
2011-09-12 19:52:32 +02:00
|
|
|
|
|
2012-03-25 12:28:06 +02:00
|
|
|
|
(defun mu4e-compose-edit ()
|
|
|
|
|
"Edit the draft message."
|
|
|
|
|
(interactive) (mu4e-compose 'edit))
|
2011-10-02 20:35:03 +02:00
|
|
|
|
|
2012-03-25 12:28:06 +02:00
|
|
|
|
(defun mu4e-compose-new ()
|
|
|
|
|
"Compose a new message."
|
|
|
|
|
(interactive) (mu4e-compose 'new))
|
2012-04-20 17:23:16 +02:00
|
|
|
|
|
|
|
|
|
(defun mu4e-hdrs-action ()
|
|
|
|
|
"Ask user what to do with message-at-point, then do it. The
|
|
|
|
|
actions are specified in `mu4e-headers-actions'."
|
|
|
|
|
(interactive)
|
|
|
|
|
(let ((msg (mu4e-message-at-point t))
|
|
|
|
|
(actionfunc (mu4e-choose-action "Action: " mu4e-headers-actions)))
|
|
|
|
|
(funcall actionfunc msg)))
|
|
|
|
|
|
2012-04-23 18:07:20 +02:00
|
|
|
|
(defun mu4e-hdrs-mark-and-next (mark)
|
|
|
|
|
"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)
|
|
|
|
|
(mu4e-next-header))
|
|
|
|
|
|
|
|
|
|
(defun mu4e-hdrs-mark-for-move-and-next ()
|
|
|
|
|
"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-for-move-set)
|
|
|
|
|
(mu4e-next-header))
|
|
|
|
|
|
|
|
|
|
|
2011-09-18 13:39:36 +02:00
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
2011-09-12 19:52:32 +02:00
|
|
|
|
|
2011-12-13 08:07:38 +01:00
|
|
|
|
(provide 'mu4e-hdrs)
|