EUDC: Add completion-at-point support

* lisp/net/eudc-capf.el: New file.
* lisp/gnus/message.el (message-mode): Add `eudc-capf-complete' to
`completion-at-point-functions' when a `message-mode' buffer is
created.
* doc/misc/eudc.texi (Inline Query Expansion): Add a new subsection,
describing the new `completion-at-point' mechanism in `message-mode'.
* etc/NEWS (EUDC): Describe the new `completion-at-point' method.
This commit is contained in:
Alexander Adolf 2022-05-02 23:01:11 +02:00 committed by Thomas Fitzsimmons
parent b186d5063d
commit 620ac67355
4 changed files with 167 additions and 3 deletions

View file

@ -713,6 +713,7 @@ be passed to the program.
@node Inline Query Expansion
@section Inline Query Expansion
@subsection Inline Query Expansion Using a Key Binding
Inline query expansion is a powerful method to get completion from
your directory servers. The most common usage is for expanding names
@ -885,6 +886,29 @@ An error is signaled. The expansion aborts.
Default is @code{select}
@end defvar
@subsection Inline Query Expansion Using completion-at-point
In addition to providing a dedicated EUDC function for binding to a
key shortcut (@pxref{Inline Query Expansion}), EUDC also provides a
function to contribute search results to the Emacs in-buffer
completion system available via the function
@code{completion-at-point} (@pxref{Identifier
Inquiries,,,maintaining}) in @code{message-mode} buffers
(@pxref{Top,Message,, message, Message}). When using this mechanism,
queries are made in the multi-server query mode of operation
(@pxref{Multi-server Queries}).
When a buffer in @code{message-mode} is created, EUDC's inline
expansion function is automatically added to the variable
@code{completion-at-point-functions}. As a result, whenever
@code{completion-at-point} is invoked in a @code{message-mode} buffer,
EUDC will be queried for email addresses matching the words before
point. Since this will be useful only when editing specific message
header fields that require specifying one or more email addresses, an
additional check is performed whether point is actually in one of
those header fields. Thus, any matching email addresses will be
offered for completion in suitable message header fields only, and not
in other places, like for example the body of the message.
@node The Server Hotlist

View file

@ -1073,6 +1073,12 @@ is called, and the returned values are used to populate the phrase and
comment parts (see RFC 5322 for definitions). In both cases, the
phrase part will be automatically quoted if necessary.
+++
*** New function 'eudc-capf-complete' with message-mode integration
EUDC can now contribute email addresses to 'completion-at-point' by
adding the new function 'eudc-capf-complete' to
'completion-at-point-functions' in message-mode.
** eww/shr
+++

View file

@ -51,6 +51,7 @@
(require 'yank-media)
(require 'mailcap)
(require 'sendmail)
(require 'eudc-capf)
(autoload 'mailclient-send-it "mailclient")
@ -3180,8 +3181,7 @@ Like `text-mode', but with these additional commands:
(mail-abbrevs-setup))
((message-mail-alias-type-p 'ecomplete)
(ecomplete-setup)))
;; FIXME: merge the completion tables from ecomplete/bbdb/...?
;;(add-hook 'completion-at-point-functions #'message-ecomplete-capf nil t)
(add-hook 'completion-at-point-functions #'eudc-capf-complete -1 t)
(add-hook 'completion-at-point-functions #'message-completion-function nil t)
(unless buffer-file-name
(message-set-auto-save-file-name))
@ -8364,7 +8364,8 @@ set to nil."
(t
(expand-abbrev))))
(add-to-list 'completion-category-defaults '(email (styles substring)))
(add-to-list 'completion-category-defaults '(email (styles substring
partial-completion)))
(defun message--bbdb-query-with-words (words)
;; FIXME: This (or something like this) should live on the BBDB side.

133
lisp/net/eudc-capf.el Normal file
View file

@ -0,0 +1,133 @@
;;; eudc-capf.el --- EUDC - completion-at-point bindings -*- lexical-binding:t -*-
;; Copyright (C) 2022 Free Software Foundation, Inc.
;;
;; Author: Alexander Adolf
;;
;; This file is 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 <https://www.gnu.org/licenses/>.
;;; Commentary:
;; This library provides functions to deliver email addresses from
;; EUDC search results to `completion-at-point'.
;;
;; Email address completion will likely be desirable only in
;; situations where designating email recipients plays a role, such
;; as when composing or replying to email messages, or when posting
;; to newsgroups, possibly with copies of the post being emailed.
;; Hence, modes relevant in such contexts, such as for example
;; `message-mode' and `mail-mode', often at least to some extent
;; provide infrastructure for different functions to be called when
;; completing in certain message header fields, or in the body of
;; the message. In other modes for editing email messages or
;; newsgroup posts, which do not provide such infrastructure, any
;; completion function providing email addresses will need to check
;; whether the completion attempt occurs in an appropriate context
;; (that is, in a relevant message header field) before providing
;; completion candidates. Two mechanisms are thus provided by this
;; library.
;;
;; The first mechanism is intended for use by the modes listed in
;; `eudc-capf-modes', and relies on these modes adding
;; `eudc-capf-complete' to `completion-at-point-functions', as
;; would be usually done for any general-purpose completion
;; function. In this mode of operation, and in order to offer
;; email addresses only in contexts where the user would expect
;; them, a check is performed whether point is on a line that is a
;; message header field suitable for email addresses, such as for
;; example "To:", "Cc:", etc.
;;
;; The second mechanism is intended for when the user modifies
;; `message-completion-alist' to replace `message-expand-name' with
;; the function `eudc-capf-message-expand-name'. As a result,
;; minibuffer completion (`completing-read') for email addresses
;; would no longer enabled in `message-mode', but
;; `completion-at-point' (in-buffer completion) only.
;;; Usage:
;; In a major mode, or context where you want email address
;; completion, you would do something along the lines of:
;;
;; (require 'eudc-capf)
;; (add-hook 'completion-at-point-functions #'eudc-capf-complete -1 t)
;;
;; The minus one argument puts it at the front of the list so it is
;; called first, and the t value for the LOCAL parameter causes the
;; setting to be buffer local, so as to avoid modifying any global
;; setting.
;;
;; The value of the variable `eudc-capf-modes' indicates which
;; major modes do such a setup as part of their initialisation
;; code.
;;; Code:
(require 'eudc)
(defvar message-email-recipient-header-regexp)
(defvar mail-abbrev-mode-regexp)
(declare-function mail-abbrev-in-expansion-header-p "mailabbrev" ())
(defconst eudc-capf-modes '(message-mode)
"List of modes in which email address completion is to be attempted.")
;; completion functions
;;;###autoload
(defun eudc-capf-complete ()
"Email address completion function for `completion-at-point-functions'.
This function checks whether the current major mode is one of the
modes listed in `eudc-capf-modes', and whether point is on a line
with a message header listing email recipients, that is, a line
whose beginning matches `message-email-recipient-header-regexp',
and, if the check succeeds, searches for records matching the
words before point.
The return value is either nil when no match is found, or a
completion table as required for functions listed in
`completion-at-point-functions'."
(if (and (seq-some #'derived-mode-p eudc-capf-modes)
(let ((mail-abbrev-mode-regexp message-email-recipient-header-regexp))
(mail-abbrev-in-expansion-header-p)))
(eudc-capf-message-expand-name)))
;;;###autoload
(defun eudc-capf-message-expand-name ()
"Email address completion function for `message-completion-alist'.
When this function is added to `message-completion-alist',
replacing any existing entry for `message-expand-name' there,
with an appropriate regular expression such as for example
`message-email-recipient-header-regexp', then EUDC will be
queried for email addresses, and the results delivered to
`completion-at-point'."
(if (or eudc-server eudc-server-hotlist)
(progn
(let* ((beg (save-excursion
(re-search-backward "\\([:,]\\|^\\)[ \t]*")
(match-end 0)))
(end (point))
(prefix (save-excursion (buffer-substring-no-properties beg end))))
(list beg end
(completion-table-with-cache
(lambda (_)
(eudc-query-with-words (split-string prefix "[ \t]+") t))
t))))))
(provide 'eudc-capf)
;;; eudc-capf.el ends here