* clear up the mu4e headers updating mechanism, so it's more robust (i.e..,

when another window is selected, such as in the case when using the
  speedbar).

  Also, some cleanup in message composition (that would deserve a separate
  commit, but it's too late now...)
This commit is contained in:
djcb 2012-03-25 13:28:06 +03:00
parent 67261b614d
commit 1d5640fde2
1 changed files with 90 additions and 60 deletions

View File

@ -45,6 +45,17 @@
(defconst mu4e-hdrs-fringe " " (defconst mu4e-hdrs-fringe " "
"*internal* The space on the left of message headers to put marks.") "*internal* The space on the left of message headers to put marks.")
(defun mu4e-hdrs-clear ()
"Clear the header buffer and related data structures."
(when (buffer-live-p mu4e-hdrs-buffer)
(let ((inhibit-read-only t))
(with-current-buffer mu4e-hdrs-buffer
(erase-buffer)
(when mu4e-marks-map (clrhash mu4e-marks-map))
(when mu4e-msg-map (clrhash mu4e-msg-map))
(when mu4e-thread-info-map (clrhash mu4e-thread-info-map))))))
(defun mu4e-hdrs-search (expr &optional full-search) (defun mu4e-hdrs-search (expr &optional full-search)
"Search in the mu database for EXPR, and switch to the output "Search in the mu database for EXPR, and switch to the output
buffer for the results. If FULL-SEARCH is non-nil return all buffer for the results. If FULL-SEARCH is non-nil return all
@ -54,14 +65,14 @@ results, otherwise, limit number of results to
(inhibit-read-only t) (inhibit-read-only t)
(esc (replace-regexp-in-string "\"" "\\\\\"" expr))) ;; escape "\" (esc (replace-regexp-in-string "\"" "\\\\\"" expr))) ;; escape "\"
(with-current-buffer buf (with-current-buffer buf
(erase-buffer)
(mu4e-hdrs-mode) (mu4e-hdrs-mode)
(setq (setq
global-mode-string (propertize expr 'face 'mu4e-title-face) global-mode-string (propertize expr 'face 'mu4e-title-face)
mu4e-last-expr expr mu4e-last-expr expr
mu4e-hdrs-buffer buf mu4e-hdrs-buffer buf
mode-name "mu4e-headers")) mode-name "mu4e-headers"))
(switch-to-buffer mu4e-hdrs-buffer)
(switch-to-buffer buf)
(mu4e-proc-find esc ;; '-1' means 'unlimited search' (mu4e-proc-find esc ;; '-1' means 'unlimited search'
(if full-search -1 mu4e-search-results-limit)))) (if full-search -1 mu4e-search-results-limit))))
@ -95,8 +106,9 @@ headers."
(point (when marker (marker-position marker)))) (point (when marker (marker-position marker))))
(when point ;; is the message present in this list? (when point ;; is the message present in this list?
;; if it's marked, unmark it now ;; if it's marked, unmark it now
(when (mu4e-hdrs-docid-is-marked docid) (mu4e-hdrs-mark 'unmark)) (when (mu4e-hdrs-docid-is-marked docid)
;; first, remove the old one (otherwise, we'd have to headers with (mu4e-hdrs-mark 'unmark))
;; first, remove the old one (otherwise, we'd have two headers with
;; the same docid... ;; the same docid...
(mu4e-hdrs-remove-handler docid) (mu4e-hdrs-remove-handler docid)
@ -120,7 +132,7 @@ headers."
(defun mu4e-hdrs-remove-handler (docid) (defun mu4e-hdrs-remove-handler (docid)
"Remove handler, will be called when a message has been removed "Remove handler, will be called when a message has been removed
from the database. This function will hide the remove message in from the database. This function will hide the removed message from
the current list of headers." the current list of headers."
(with-current-buffer mu4e-hdrs-buffer (with-current-buffer mu4e-hdrs-buffer
(let* ((marker (gethash docid mu4e-msg-map)) (let* ((marker (gethash docid mu4e-msg-map))
@ -128,7 +140,7 @@ the current list of headers."
(docid-at-pos (and pos (mu4e-hdrs-get-docid pos)))) (docid-at-pos (and pos (mu4e-hdrs-get-docid pos))))
(unless marker (error "Message %d not found" docid)) (unless marker (error "Message %d not found" docid))
(unless (eq docid docid-at-pos) (unless (eq docid docid-at-pos)
(error "At point %d, expected docid %d, but got %d" (error "At point %d, expected docid %d, but got %S"
pos docid docid-at-pos)) pos docid docid-at-pos))
(mu4e-hdrs-remove-header docid pos)))) (mu4e-hdrs-remove-header docid pos))))
@ -164,7 +176,7 @@ into a string."
(defun mu4e-hdrs-header-handler (msg &optional point) (defun mu4e-hdrs-header-handler (msg &optional point)
"Create a one line description of MSG in this buffer, at POINT, "Create a one line description of MSG in this buffer, at POINT,
if provided, or at the end of the buffer otherwise." if provided, or at the end of the buffer otherwise."
(let* ( (docid (plist-get msg :docid)) (let* ((docid (plist-get msg :docid))
(thread-info (thread-info
(or (plist-get msg :thread) (gethash docid mu4e-thread-info-map))) (or (plist-get msg :thread) (gethash docid mu4e-thread-info-map)))
(line (line
@ -210,9 +222,8 @@ if provided, or at the end of the buffer otherwise."
;; store the thread info, so we can use it when updating the message ;; store the thread info, so we can use it when updating the message
(when (and thread-info mu4e-thread-info-map) (when (and thread-info mu4e-thread-info-map)
(puthash docid thread-info mu4e-thread-info-map)) (puthash docid thread-info mu4e-thread-info-map))
(mu4e-hdrs-add-header line (plist-get msg :docid) ;; now, append the header line
(if point point (point-max))))) (mu4e-hdrs-add-header line docid point)))
(defun mu4e-hdrs-found-handler (count) (defun mu4e-hdrs-found-handler (count)
"Create a one line description of the number of headers found "Create a one line description of the number of headers found
@ -278,7 +289,7 @@ after the end of the search results."
(define-key map "R" 'mu4e-compose-reply) (define-key map "R" 'mu4e-compose-reply)
(define-key map "F" 'mu4e-compose-forward) (define-key map "F" 'mu4e-compose-forward)
(define-key map "C" 'mu4e-compose-new) (define-key map "C" 'mu4e-compose-new)
(define-key map "E" 'mu4e-edit-draft) (define-key map "E" 'mu4e-compose-edit)
(define-key map (kbd "RET") 'mu4e-view-message) (define-key map (kbd "RET") 'mu4e-view-message)
(define-key map [mouse-2] 'mu4e-view-message) (define-key map [mouse-2] 'mu4e-view-message)
@ -325,7 +336,6 @@ after the end of the search results."
(define-key menumap [previous] '("Previous" . mu4e-prev-header)) (define-key menumap [previous] '("Previous" . mu4e-prev-header))
(define-key menumap [sepa4] '("--"))) (define-key menumap [sepa4] '("--")))
;;(define-key menumap [draft] '("Edit draft" . mu4e-compose-new))
map))) map)))
(fset 'mu4e-hdrs-mode-map mu4e-hdrs-mode-map) (fset 'mu4e-hdrs-mode-map mu4e-hdrs-mode-map)
@ -337,6 +347,8 @@ after the end of the search results."
(setq mu4e-proc-found-func 'mu4e-hdrs-found-handler) (setq mu4e-proc-found-func 'mu4e-hdrs-found-handler)
(setq mu4e-proc-view-func 'mu4e-hdrs-view-handler) (setq mu4e-proc-view-func 'mu4e-hdrs-view-handler)
(setq mu4e-proc-remove-func 'mu4e-hdrs-remove-handler) (setq mu4e-proc-remove-func 'mu4e-hdrs-remove-handler)
(setq mu4e-proc-erase-func 'mu4e-hdrs-clear)
;; this last one is defined in mu4e-send.el ;; this last one is defined in mu4e-send.el
(setq mu4e-proc-compose-func 'mu4e-send-compose-handler) (setq mu4e-proc-compose-func 'mu4e-send-compose-handler)
@ -391,23 +403,40 @@ after the end of the search results."
(defvar mu4e-msg-map nil (defvar mu4e-msg-map nil
"*internal* A map (hashtable) which maps a database (Xapian) "*internal* A map (hashtable) which maps a database (Xapian)
docid (which uniquely identifies a message to a marker. where docid (which uniquely identifies a message to a marker. where
marker points to the buffer position for the message. marker points to the buffer position for the message
Using this map, we can update message headers which are currently Using this map, we can update message headers which are currently
on the screen, when we receive (:update ) notices from the mu on the screen, when we receive (:update ) notices from the mu
server.") server.")
(defun mu4e-select-headers-window-if-visible ()
"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."
(let ((win (get-buffer-window mu4e-hdrs-buffer)))
(when win (select-window win)
)))
(defun mu4e-hdrs-add-header (str docid point) (defun mu4e-hdrs-add-header (str docid point)
"Add header STR with DOCID to the buffer at POINT." "Add header STR with DOCID to the buffer at POINT if non-nil, or
at (point-max) otherwise."
(unless docid (error "Invalid message")) (unless docid (error "Invalid message"))
(when (buffer-live-p mu4e-hdrs-buffer) (when (buffer-live-p mu4e-hdrs-buffer)
(with-current-buffer mu4e-hdrs-buffer (with-current-buffer mu4e-hdrs-buffer
(let ((inhibit-read-only t)) (let ((inhibit-read-only t) (point (if point point (point-max))))
;;(mu4e-select-headers-window-if-visible)
(save-excursion (save-excursion
(goto-char point) (goto-char point)
;; make sure the output window is selected, which it wouldn't be if called
;; from e.g. speedbar (output looks choppy when another window is
;; selected). We use switch-to-buffer for its window-selecting side-effect -
;; but only if the window is visible
(insert (propertize (concat mu4e-hdrs-fringe str "\n") 'docid docid))
;; Update `mu4e-msg-map' with MSG, and MARKER pointing to the buffer ;; Update `mu4e-msg-map' with MSG, and MARKER pointing to the buffer
;; position for the message header." ;; position for the message header."
(insert (propertize (concat mu4e-hdrs-fringe str "\n") 'docid docid))
;; note: this maintaining the hash with the markers makes things slow ;; note: this maintaining the hash with the markers makes things slow
;; when there are many (say > 1000) headers. this seems to be mostly ;; when there are many (say > 1000) headers. this seems to be mostly
;; in the use of markers. we use those to find messages when they need ;; in the use of markers. we use those to find messages when they need
@ -436,7 +465,8 @@ server.")
(when marker (when marker
(with-current-buffer mu4e-hdrs-buffer (with-current-buffer mu4e-hdrs-buffer
(save-excursion (save-excursion
(let ((inhibit-read-only t) (pos (marker-position marker))) (let ((inhibit-read-only t)
(pos (marker-position marker)))
(goto-char pos) (goto-char pos)
(delete-char 2) (delete-char 2)
(insert (propertize mark 'face 'mu4e-hdrs-marks-face) " ") (insert (propertize mark 'face 'mu4e-hdrs-marks-face) " ")
@ -598,30 +628,6 @@ work well."
(unless docid (error "No message at point.")) (unless docid (error "No message at point."))
(mu4e-proc-view-msg docid))) (mu4e-proc-view-msg docid)))
(defun mu4e-hdrs-compose (compose-type)
"Compose either a reply/forward based on the message at point. or
start editing it. COMPOSE-TYPE is either `reply', `forward', `edit'
or `new'."
(if (eq compose-type 'new)
(mu4e-send-compose-handler 'new)
(let ((docid (mu4e-hdrs-get-docid))
;; 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
(is-draft (get-text-property (- (line-end-position) 1) 'draft)))
(unless docid
(error "No message at point."))
(cond
((member compose-type '(reply forward))
(mu4e-proc-compose compose-type docid))
((eq compose-type 'edit)
(unless is-draft
(error "Cannot edit a non-draft message"))
(mu4e-proc-compose 'edit docid))
(t (error "invalid compose type %S" compose-type))))))
(defun mu4e-hdrs-docid-is-marked (docid) (defun mu4e-hdrs-docid-is-marked (docid)
"Is the given docid marked?" "Is the given docid marked?"
(when (gethash docid mu4e-marks-map) t)) (when (gethash docid mu4e-marks-map) t))
@ -671,8 +677,8 @@ up to `mu4e-search-results-limit' much quicker."
(mu4e-hdrs-search expr current-prefix-arg))) (mu4e-hdrs-search expr current-prefix-arg)))
(defun mu4e-search-bookmark () (defun mu4e-search-bookmark ()
"Search using some bookmarked query. With C-u prefix, show /all/ results, otherwise, "Search using some bookmarked query. With C-u prefix, show /all/ results,
limit to up to `mu4e-search-results-limit'." otherwise, limit to up to `mu4e-search-results-limit'."
(interactive) (interactive)
(let ((query (mu4e-ask-bookmark "Bookmark: "))) (let ((query (mu4e-ask-bookmark "Bookmark: ")))
(when query (when query
@ -808,28 +814,52 @@ parameter NO-CONFIRMATION is is t, don't ask for confirmation."
(mu4e-hdrs-marks-execute) (mu4e-hdrs-marks-execute)
(message nil))))) (message nil)))))
(defun mu4e-compose-reply ()
"Start composing a reply to the current message." (defun mu4e-compose (&optional compose-type)
"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."
(interactive) (interactive)
(with-current-buffer mu4e-hdrs-buffer (let ((compose-type
(mu4e-hdrs-compose 'reply))) (or compose-type
(intern (ido-completing-read "Compose type: "
'("reply" "forward" "edit" "new"))))))
(with-current-buffer mu4e-hdrs-buffer
;; '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)
(mu4e-send-compose-handler 'new)
;; otherwise, we need the doc-id
(let ((docid (mu4e-hdrs-get-docid))
(is-draft ))
(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
(when (and (eq compose-type 'edit)
(get-text-property (- (line-end-position) 1) 'draft))
(error "Editing only allowed for draft messages"))
;; talk to the backend
(mu4e-proc-compose compose-type docid))))))
(defun mu4e-compose-reply ()
"Reply to the current message."
(interactive) (mu4e-compose 'reply))
(defun mu4e-compose-forward () (defun mu4e-compose-forward ()
"Start composing a forward to the current message." "Forward the current message."
(interactive) (interactive) (mu4e-compose 'forward))
(with-current-buffer mu4e-hdrs-buffer
(mu4e-hdrs-compose 'forward))) (defun mu4e-compose-edit ()
"Edit the draft message."
(interactive) (mu4e-compose 'edit))
(defun mu4e-compose-new () (defun mu4e-compose-new ()
"Compose a new, empty message." "Compose a new message."
(interactive) (interactive) (mu4e-compose 'new))
(mu4e-hdrs-compose 'new))
(defun mu4e-edit-draft ()
"Start editing the existing draft message at point."
(interactive)
(with-current-buffer mu4e-hdrs-buffer
(mu4e-hdrs-compose 'edit)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;