From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Eric Abrahamsen Newsgroups: gmane.emacs.devel Subject: Re: [PATCH] EUDC email addresses via completion-at-point in message-mode Date: Fri, 15 Apr 2022 15:57:18 -0700 Message-ID: <87a6cmymy9.fsf@ericabrahamsen.net> References: <4c3f728f989e832d224be1503808a682@condition-alpha.com> Mime-Version: 1.0 Content-Type: text/plain Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="999"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (gnu/linux) To: emacs-devel@gnu.org Cancel-Lock: sha1:3828deKiAmckZuuiIP9Je7ZOV3I= Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Sat Apr 16 00:58:45 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 1nfUto-00005g-CQ for ged-emacs-devel@m.gmane-mx.org; Sat, 16 Apr 2022 00:58:44 +0200 Original-Received: from localhost ([::1]:39658 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nfUtm-0005kI-RT for ged-emacs-devel@m.gmane-mx.org; Fri, 15 Apr 2022 18:58:42 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:51322) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nfUsd-00052S-74 for emacs-devel@gnu.org; Fri, 15 Apr 2022 18:57:31 -0400 Original-Received: from ciao.gmane.io ([116.202.254.214]:44082) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nfUsb-00065d-8e for emacs-devel@gnu.org; Fri, 15 Apr 2022 18:57:30 -0400 Original-Received: from list by ciao.gmane.io with local (Exim 4.92) (envelope-from ) id 1nfUsZ-00092X-He for emacs-devel@gnu.org; Sat, 16 Apr 2022 00:57:27 +0200 X-Injected-Via-Gmane: http://gmane.org/ Received-SPF: pass client-ip=116.202.254.214; envelope-from=ged-emacs-devel@m.gmane-mx.org; helo=ciao.gmane.io X-Spam_score_int: -16 X-Spam_score: -1.7 X-Spam_bar: - X-Spam_report: (-1.7 / 5.0 requ) BAYES_00=-1.9, HEADER_FROM_DIFFERENT_DOMAINS=0.249, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=no 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:288468 Archived-At: Alexander Adolf writes: > Hello Stefan, > > Stefan Monnier writes: > >> [...] >> Maybe EUDC shouldn't be in charge of providing a CAPF function. > > I'd tend to disagree. > >> The CAPF function needs to understand the current document's syntax to >> know where an email address is expected, but that part is completely >> unrelated to EUDC itself (and related to the major mode instead). >> [...] > > Fully agree. > > I think there may be a middle ground. I appreciate you seem to share the > idea of following "separation of concerns", some also call it > "one-thing-well mantra" (doe one thing only, do it well), as it > typically helps keeping code simpler. > > A couple of thoughts on completion in message mode: > > ---------------------------- Begin Quote ----------------------------- > Variable: completion-at-point-functions > > The value of this abnormal hook should be a list of functions, > which are used to compute a completion table (see Basic Completion) > for completing the text at point. It can be used by major modes to > provide mode-specific completion tables (see Major Mode > Conventions). > ----------------------------- End Quote ------------------------------ > > But I think there may be a "catch 22" here, though. If the major mode > provides the completion table(s) itself, fine. But what about completion > tables contributed by 3rd party packages? I don't think a major mode > could, or should have an, inevitably incomplete, list of 3rd party > packages to query for completion tables. IMO it would seem much more > sensible to reverse responsibilities: any package that is capable of > providing additional completion tables for certain major modes, should > register itself with those modes (e.g. by adding itself to > completion-at-point-functions). > > In message-mode (there may be others, too), the in-buffer completion > will additionally need to figure out the context where completion is > attempted, i.e. some function will need to be called to determine the > semantic context of the stuff around point in order to choose one or > more suitable functions for delivering completion candidates. For > instance in a programming language buffer, do I need candidates for a > function, or for a variable? For instance in a message buffer, do I need > candidates for an email address, or text snippets for the message body? > > In the current architecture for completion-at-point, such checks for > context have to be performed by the functions registered in > completion-at-point-functions. This seems wasteful, as it means a lot of > very similar code all over (possibly with subtly different bugs in each > copy), and an unnecessary runtime burden as completion-at-point may be > called often (for every keystroke in some situations). > > mail-mode and message-mode are sort of half way there by providing > mail-complete-alist and message-completion-alist, respectively. Both > variables allow for registering a _single_ function to be called for > buffer lines matching a regex. This already takes the burden of figuring > out the completion context away from the function being called, and > together with the try-all-servers feature recently added to EUDC it > would already suffice to aggregate email address candidates from more > than one source in message-mode. > > A more generic mechanism could look like this: > > 1) Each 3rd party package that wants to provide general purpose > completion tables for a given major mode, adds a function to the > respective *-mode-hook that adds that package's completion function > to completion-at-point-functions (this is current good practice). > > 2) Each major mode that wants to allow users to have different > completion tables based on the context where the completion happens, > offers a *-mode-context-completion-functions-alist variable. The keys > in this alist should be symbols describing the completion context or > purpose (for example 'email, 'newsgroup, etc.). The values are > symbols representing abnormal hook variables. (This is where > mail-mode and message-mode are half way there.) > > 3) Users (or init code of 3rd party packages) call add-hook to add > completion functions to the values of entries in > *-mode-context-completion-functions-alist variable(s) as they deem > fit. These functions must be "cooperative" in the sense that they > should add ":exclusive 'no" to the completion table they return, > unless there is a particular reason for claiming exclusive completion > "rights". > > 4) Each major mode that wants to allow users to have different > completion tables based on the context where the completion happens, > does the following: > > 4.1) After all mode hooks have been run, sample the current value of > completion-at-point-functions, and store it in a variable. > > 4.2) Next, set completion-at-point-functions to a single function, > which is the mode's completion function. > > 4.3) When completion-at-point is called, and hence in the mode's > completion function: > > 4.3.1) Check whether point is in any of specific completion > context. > > 4.3.2) If point is in a specific context, consult the > *-mode-context-completion-functions-alist variable to > determine the list of functions to call. If that is not > the case, use the previously sampled value of > completion-at-point-functions. > > 4.3.3) Do a let-binding setting completion-at-point-functions to > the value determined in the previous step, and then call > completion-at-point (recursive) within the let context, > and return whatever completion-at-point returned. (Can > completion-at-point be called recursively? I haven't > tried.) > > 5) Job done. > > > Apologies for the lengthy explanation... Hi Alexander, I'll respond here, though I've read your other replies in other subthreads. First of all, my apologies for an attempted hijacking of the thread! But you're right this is something that has irked me for a long time, I just haven't gotten around to writing code, and it's easier to yell about it on this thread than go write my own patch :) While I don't object to EUDC at all (and have a half-written patch somewhere to adapt EBDB to EUDC, as well), I don't think it's necessary to funnel all email completion through it. The mechanism already exists in the completion-at-point code, and if that doesn't work the way we want it to, I think it should be tweaked until it does, because this is a common use case. We already have `message-expand-name-databases', and it is merely a bit of historical perversity that only two values are allowed in there. It should accept any appropriate function. `message-tab' will always be necessary for checking where in the message buffer we are, and feeding the correct string to the completion tables. `completion-table-merge' is the only missing piece. It collections all potential completions from all tables and, as the name suggests, merges them. I think that's all we need. Users should certainly be free to only use EUDC if they want, but then all they have to do is funnel their various functions into EUDC, and set `message-expand-name-databases' to '(eudc). I don't see any need to enforce the use of EUDC, and think that message.el should not (and should not need to) make any mention of specific contact-management packages at all. That's my point of view! Thanks, Eric