mu4e: improve sorting of contacts for completion

set up the extra machinery for making sure emacs does not try to re-sort
our already-sorted contacts.... Also try to improve the sorting strategy
itself.
This commit is contained in:
djcb 2015-12-29 18:53:57 +02:00
parent 7dff782c58
commit f645a12075
3 changed files with 38 additions and 34 deletions

View File

@ -250,12 +250,22 @@ appear on disk."
(mu4e-message "Saved (%d lines)" (count-lines (point-min) (point-max)))
;; update the file on disk -- ie., without the separator
(mu4e~proc-add (buffer-file-name) mu4e~draft-drafts-folder)) nil t))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; address completion; inspired by org-contacts.el and
;; https://github.com/nordlow/elisp/blob/master/mine/completion-styles-cycle.el
(defun mu4e~compose-complete-handler (str pred action)
(cond
((eq action nil)
(try-completion str mu4e~contacts-for-completion pred))
((eq action t)
(all-completions str mu4e~contacts-for-completion pred))
((eq action 'metadata)
;; our contacts are already sorted - just need to tell the
;; completion machinery not to try to undo that...
'(metadata
(display-sort-function . identity) ;; i.e., alphabetically
(cycle-sort-function . identity)))))
(defun mu4e~compose-complete-contact (&optional start)
"Complete the text at START with a contact.
@ -276,8 +286,8 @@ Ie. either 'name <email>' or 'email')."
(re-search-backward "\\(\\`\\|[\n:,]\\)[ \t]*")
(goto-char (match-end 0))
(point)))))
(list start end mu4e~contacts-for-completion)))))
(list start end 'mu4e~compose-complete-handler)))))
(defun mu4e~compose-setup-completion ()
"Set up auto-completion of addresses."
(set (make-local-variable 'completion-ignore-case) t)
@ -311,8 +321,8 @@ message-thread by removing the In-Reply-To header."
(progn
(use-local-map mu4e-compose-mode-map)
(set (make-local-variable 'global-mode-string) '(:eval (mu4e-context-label)))
(set (make-local-variable 'global-mode-string) '(:eval (mu4e-context-label)))
(set (make-local-variable 'message-signature) mu4e-compose-signature)
;; set this to allow mu4e to work when gnus-agent is unplugged in gnus
(set (make-local-variable 'message-send-mail-real-function) nil)

View File

@ -638,16 +638,32 @@ process."
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defsubst mu4e~process-contact (contact)
"Process CONTACT, possibly rewriting it, or return nil if
should be removed."
"Process CONTACT, and either return nil when it should not be included,
or (rfc822-string . CONTACT) otherwise."
(when mu4e-contact-rewrite-function
(setq contact (funcall mu4e-contact-rewrite-function contact)))
(when contact
(let ((name (plist-get contact :name))
(mail (plist-get contact :mail)))
(unless (and mail (string-match mu4e-compose-complete-ignore-address-regexp mail))
(if name (format "%s <%s>" (mu4e~rfc822-quoteit name) mail) mail)))))
(cons
(if name (format "%s <%s>" (mu4e~rfc822-quoteit name) mail) mail)
contact)))))
(defun mu4e~sort-contacts (contacts)
"Sort the contacts (only for cycling). Sort by last-use when
that is at most 10 days old. Otherwise, sort by frequency."
(let ((recent (- (float-time) (* 10 24 3600))))
(sort contacts
(lambda (c1 c2)
(let* ((freq1 (plist-get c1 :freq))
(freq2 (plist-get c2 :freq))
(tstamp1 (plist-get c1 :tstamp))
(tstamp2 (plist-get c2 :tstamp)))
(if (or (> tstamp1 recent) (> tstamp2 recent))
(< tstamp1 tstamp2)
(< freq1 freq2)))))))
;; start and stopping
(defun mu4e~fill-contacts (contacts)
"We receive a list of contacts, which each contact of the form
@ -656,25 +672,8 @@ and fill the list `mu4e~contacts-for-completion' with it, with
each element looking like
name <email>
This is used by the completion function in mu4e-compose."
(setq
mu4e~contact-list contacts
mu4e~contacts-for-completion nil)
(let ((lst)
;; sort by the frequency (ascending), then timestamp (ascending)
;; note -- this the opposite order we'd want, but the
;; `push' below reverses the order
;; FIXME: sadly, the emacs completion subsystem re-sorts the list
;; before showing candidates, so this doesn't do anything useful yet.
(contacts (sort contacts
(lambda (c1 c2)
(let ((freq1 (plist-get c1 :freq))
(tstamp1 (plist-get c1 :tstamp))
(freq2 (plist-get c2 :freq))
(tstamp2 (plist-get c2 :tstamp)))
(if (equal freq1 freq2)
(< tstamp1 tstamp2)
(< freq1 freq2)))))))
(let ((contacts (mu4e~sort-contacts contacts)))
(setq mu4e~contacts-for-completion nil)
(dolist (contact contacts)
(let ((contact (mu4e~process-contact contact)))
(when contact (push contact mu4e~contacts-for-completion))))
@ -1173,6 +1172,5 @@ the view and compose modes."
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(provide 'mu4e-utils)
;;; End of mu4e-utils.el

View File

@ -771,10 +771,6 @@ for an example.")
This is used by the completion functions in mu4e-compose, filled
when mu4e starts.")
(defvar mu4e~contact-list nil
"List of contacts, where each contact is a plist
(:name NAME :mail EMAIL :tstamp TIMESTAMP :freq FREQUENCY).")
(defvar mu4e~server-props nil
"Properties we receive from the mu4e server process.
\(in the 'pong-handler').")