From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Alexander Adolf Newsgroups: gmane.emacs.devel Subject: Re: [PATCH] EUDC email addresses via completion-at-point in message-mode Date: Mon, 02 May 2022 23:38:43 +0200 Message-ID: <15b3bbf610c12c046aff8cdea3f5e592@condition-alpha.com> References: Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="25204"; mail-complaints-to="usenet@ciao.gmane.io" Cc: emacs-devel@gnu.org To: Filipp Gunbin Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Mon May 02 23:39:43 2022 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1nldlf-0006P3-7U for ged-emacs-devel@m.gmane-mx.org; Mon, 02 May 2022 23:39:43 +0200 Original-Received: from localhost ([::1]:42590 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nldld-0003BV-Fm for ged-emacs-devel@m.gmane-mx.org; Mon, 02 May 2022 17:39:41 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:39654) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nldko-0001wD-Q9 for emacs-devel@gnu.org; Mon, 02 May 2022 17:38:50 -0400 Original-Received: from smtprelay02.ispgateway.de ([80.67.18.44]:55023) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nldkm-0002bz-8P for emacs-devel@gnu.org; Mon, 02 May 2022 17:38:50 -0400 Original-Received: from [46.244.206.150] (helo=condition-alpha.com) by smtprelay02.ispgateway.de with esmtpsa (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1nldkh-0004hI-Mz; Mon, 02 May 2022 23:38:43 +0200 In-Reply-To: X-Df-Sender: YWxleGFuZGVyLmFkb2xmQGNvbmRpdGlvbi1hbHBoYS5jb20= Received-SPF: pass client-ip=80.67.18.44; envelope-from=alexander.adolf@condition-alpha.com; helo=smtprelay02.ispgateway.de X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.io gmane.emacs.devel:289091 Archived-At: --=-=-= Content-Type: text/plain Hello Filipp, Filipp Gunbin writes: >> [...] >> This reads as if t ("do nothing") vs. 'move ("move to the limit of >> search") should make a difference? A few quick experiments seem to >> indicate that in practice both seem to behave the same though. In this >> light, I'm fine with changing 'move to t. > > Well honestly I was fooled by save-excursion, and didn't notice the > return value of (point), with which the value we're talking about _may_ > matter. However, your regexp will always match, due to \\|^ branch > which will find bol, so you can just do: > > (save-excursion > (re-search-backward "\\([:,]\\|^\\)[ \t]*") > (match-end 0)) I tried without the surrounding save-excursion, and even then I didn't notice any difference in behaviour between t and 'move for NOERROR. Your suggested simplification works just as well, of course. Thanks for pointing out! Updated patch below. >> [...] >> That said, it would probably be desirable for message mode to have >> different values for both, completion-at-point-functions and >> completion-styles, depending on where point is (email header, newsgroup >> header, message body, etc.). But this seems like a wider discussion >> about the architecture of message.el rather than this patch. > > Yes, sounds like another use case for completion-category-overrides. Hadn't come across that one yet; thanks for the pointer. Message.el does this: (add-to-list 'completion-category-defaults '(email (styles substring))) It seems to me you suggest amending that line in message.el, rather than having the setq-local in my capf function? I have included this in the below patch, too. Many thanks and looking forward to your thoughts, --alexander --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=0001-EUDC-email-addresses-via-completion-at-point-in-mess.patch >From 7da38d56d7dddf4f60f4e8055634a64ef6709870 Mon Sep 17 00:00:00 2001 From: Alexander Adolf Date: Mon, 2 May 2022 23:01:11 +0200 Subject: [PATCH] EUDC email addresses via completion-at-point in message-mode * lisp/net/eudc-capf.el (new file): Add new 'eudc-capf-complete' function. * lisp/gnus/message.el (message-mode): Add 'eudc-capf-complete' to 'completion-at-point-functions' when a 'message-mode' buffer is created, removing the FIXME. * 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. --- doc/misc/eudc.texi | 23 ++++++++ etc/NEWS | 6 ++ lisp/gnus/message.el | 7 ++- lisp/net/eudc-capf.el | 133 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 166 insertions(+), 3 deletions(-) create mode 100644 lisp/net/eudc-capf.el diff --git a/doc/misc/eudc.texi b/doc/misc/eudc.texi index d2850282fe..d2a1efeed0 100644 --- a/doc/misc/eudc.texi +++ b/doc/misc/eudc.texi @@ -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,28 @@ 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 Using a Key Binding}), +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{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 diff --git a/etc/NEWS b/etc/NEWS index f897158afd..9df23ee326 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -951,6 +951,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 +++ diff --git a/lisp/gnus/message.el b/lisp/gnus/message.el index e7dc089a3c..3cef247522 100644 --- a/lisp/gnus/message.el +++ b/lisp/gnus/message.el @@ -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. diff --git a/lisp/net/eudc-capf.el b/lisp/net/eudc-capf.el new file mode 100644 index 0000000000..68cbfd93ff --- /dev/null +++ b/lisp/net/eudc-capf.el @@ -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 . + +;;; 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 -- 2.36.0 --=-=-=--