mu4e: contacts: use mu4e--contacts-set

We use to have mu4e--contacts-hash, with name mapping to rank; that was
needlessly complicated since most completion engine sort alphabetically, making
the rank totally irrelevant (in practice, it doesn't matter much from the
end-user pov).

Anyway, simplify that part, maintain a set of contacts without any rank (which
what the server delivers now).

Also update the _default_ mu4e-contact-process-function to filter out anything
with 'reply' since it's not very useful for autocompletion.
This commit is contained in:
Dirk-Jan C. Binnema 2022-05-09 21:22:17 +03:00
parent 81689f0af3
commit db86e7b5ee
4 changed files with 35 additions and 51 deletions

View File

@ -224,9 +224,9 @@ Message-ID."
"Complete address STR with predication PRED for ACTION."
(cond
((eq action nil)
(try-completion str mu4e--contacts-hash pred))
(try-completion str mu4e--contacts-set pred))
((eq action t)
(all-completions str mu4e--contacts-hash pred))
(all-completions str mu4e--contacts-set pred))
((eq action 'metadata)
;; our contacts are already sorted - just need to tell the
;; completion machinery not to try to undo that...
@ -357,7 +357,7 @@ buffers; lets remap its faces so it uses the ones for mu4e."
(mu4e~compose-register-message-save-hooks)
;; offer completion for e-mail addresses
(when mu4e-compose-complete-addresses
(unless mu4e--contacts-hash
(unless mu4e--contacts-set
;; work-around for https://github.com/djcb/mu/issues/1016
(mu4e--request-contacts-maybe))
(mu4e~compose-setup-completion))

View File

@ -87,14 +87,18 @@ their canonical counterpart; useful as an example."
"mu4e 1.3.2")
(defcustom mu4e-contact-process-function
(lambda(addr) ;; filter-out no-reply addresses
(unless (string-match-p "no[t]?[-\\.]?repl\\(y\\|ies\\)" addr)
addr))
(lambda(addr)
(cond
((string-match-p "reply" addr)
;; no-reply adresses are not useful of course, but neither are are
;; reply-xxxx addresses since they're autogenerated only useful for direct
;; replies.
nil)
(t addr)))
"Function for processing contact information for use in auto-completion.
The function receives the contact as a string, e.g
\"Foo Bar <foo.bar@example.com>\"
\"cuux@example.com\"
The function receives the contact as a string, e.g \"Foo Bar
<foo.bar@example.com>\" \"cuux@example.com\"
The function should return either:
- nil: do not use this contact for completion
@ -121,11 +125,8 @@ predicate function. A value of nil keeps all the addresses."
(defvar mu4e--contacts-tstamp "0"
"Timestamp for the most recent contacts update." )
(defvar mu4e--contacts-hash nil
"Hash that maps contacts (ie. 'name <e-mail>') to an integer for sorting.
We need to keep this information around to quickly re-sort
subsets of the contacts in the completions function in
mu4e-compose.")
(defvar mu4e--contacts-set nil
"Set with the full contact addresses for autocompletion.")
;;; user mail address
(defun mu4e-personal-addresses(&optional no-regexp)
@ -236,36 +237,24 @@ case a phrase contains a quote, it will be escaped."
(defun mu4e--update-contacts (contacts &optional tstamp)
"Receive a sorted list of CONTACTS newer than TSTAMP.
Each of the contacts has the form
(FULL_EMAIL_ADDRESS . RANK) and fill `mu4e--contacts-hash' with
it, with each contact mapped to an integer for their ranking.
Update an internal set with it.
This is used by the completion function in mu4e-compose."
;; We have our nicely sorted list, map them to a list
;; of increasing integers. We use that map in the composer
;; to sort them there. It would have been so much easier if emacs
;; allowed us to use the sorted-list as-is, but no such luck.
(let ((n 0))
(unless mu4e--contacts-hash
(setq mu4e--contacts-hash (make-hash-table :test 'equal :weakness nil
(unless mu4e--contacts-set
(setq mu4e--contacts-set (make-hash-table :test 'equal :weakness nil
:size (length contacts))))
(dolist (contact contacts)
(cl-incf n)
(let* ((address (plist-get contact :address))
(address
(if (functionp mu4e-contact-process-function)
(funcall mu4e-contact-process-function address)
address)))
(when address ;; note the explicit deccode; the strings we get are
(when (functionp mu4e-contact-process-function)
(setq contact (funcall mu4e-contact-process-function contact)))
(when contact ;; note the explicit deccode; the strings we get are
;; utf-8, but emacs doesn't know yet.
(puthash (decode-coding-string address 'utf-8)
(plist-get contact :rank) mu4e--contacts-hash))))
(puthash (decode-coding-string contact 'utf-8) t mu4e--contacts-set)))
(setq mu4e--contacts-tstamp (or tstamp "0"))
(unless (zerop n)
(mu4e-index-message "Contacts updated: %d; total %d"
n (hash-table-count mu4e--contacts-hash)))))
n (hash-table-count mu4e--contacts-set)))))
(defun mu4e-contacts-info ()
"Display information about the contacts-cache.
@ -274,31 +263,26 @@ For testing/debugging."
(with-current-buffer (get-buffer-create "*mu4e-contacts-info*")
(erase-buffer)
(insert (format "complete addresses: %s\n"
(if mu4e-compose-complete-addresses "yes" "no")))
(if mu4e-compose-complete-addresses "yes" "no")))
(insert (format "only personal addresses: %s\n"
(if mu4e-compose-complete-only-personal "yes" "no")))
(insert (format "only addresses seen after: %s\n"
(or mu4e-compose-complete-only-after "no restrictions")))
(when mu4e--contacts-hash
(when mu4e--contacts-set
(insert (format "number of contacts cached: %d\n\n"
(hash-table-count mu4e--contacts-hash)))
(let ((contacts))
(maphash (lambda (addr rank)
(setq contacts (cons (cons rank addr) contacts)))
mu4e--contacts-hash)
(setq contacts (sort contacts
(lambda(cell1 cell2) (< (car cell1) (car cell2)))))
(dolist (contact contacts)
(insert (format "%s\n" (cdr contact))))))
(hash-table-count mu4e--contacts-set)))
(maphash (lambda (contact _)
(insert (format "%s\n" contact))) mu4e--contacts-set))
(pop-to-buffer "*mu4e-contacts-info*")))
(declare-function mu4e--server-contacts "mu4e-server")
(defun mu4e--request-contacts-maybe ()
"If `mu4e-compose-complete-addresses' is non-nil, get/update
the list of contacts we use for autocompletion; otherwise, do
"Maybe update the set of contacts for autocompletion.
If `mu4e-compose-complete-addresses' is non-nil, get/update the
list of contacts we use for autocompletion; otherwise, do
nothing."
(when mu4e-compose-complete-addresses
(mu4e--server-contacts

View File

@ -441,7 +441,7 @@ status, STATUS."
((looking-back "\\(from\\|to\\|cc\\|bcc\\|contact\\|recip\\):\\([a-zA-Z0-9/.@]*\\)" nil)
(list (match-beginning 2)
(match-end 2)
mu4e--contacts-hash
mu4e--contacts-set
:exit-function
#'mu4e--search-completion-contacts-action))
((looking-back "list:\\([a-zA-Z0-9/.@]*\\)" nil)

View File

@ -151,7 +151,7 @@ invoke
(mu4e--maildirs-with-query)))))
;; maybe request the list of contacts, automatically refreshed after
;; reindexing
(unless mu4e--contacts-hash (mu4e--request-contacts-maybe)))
(unless mu4e--contacts-set (mu4e--request-contacts-maybe)))
(defun mu4e--stop ()
"Stop mu4e."
@ -251,7 +251,7 @@ chance."
"Clear any cached resources."
(setq
mu4e-maildir-list nil
mu4e--contacts-hash nil
mu4e--contacts-set nil
mu4e--contacts-tstamp "0"))
;;; _
(provide 'mu4e)