From f645a12075e1ef46a067533a0b213505d46bb752 Mon Sep 17 00:00:00 2001 From: djcb Date: Tue, 29 Dec 2015 18:53:57 +0200 Subject: [PATCH] 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. --- mu4e/mu4e-compose.el | 22 +++++++++++++++------ mu4e/mu4e-utils.el | 46 +++++++++++++++++++++----------------------- mu4e/mu4e-vars.el | 4 ---- 3 files changed, 38 insertions(+), 34 deletions(-) diff --git a/mu4e/mu4e-compose.el b/mu4e/mu4e-compose.el index 3ec1b743..741df3e6 100644 --- a/mu4e/mu4e-compose.el +++ b/mu4e/mu4e-compose.el @@ -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 ' 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) diff --git a/mu4e/mu4e-utils.el b/mu4e/mu4e-utils.el index 527db205..cc9c0547 100644 --- a/mu4e/mu4e-utils.el +++ b/mu4e/mu4e-utils.el @@ -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 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 diff --git a/mu4e/mu4e-vars.el b/mu4e/mu4e-vars.el index d42a8d32..a603fc88 100644 --- a/mu4e/mu4e-vars.el +++ b/mu4e/mu4e-vars.el @@ -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').")