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: Fri, 15 Apr 2022 23:58:40 +0200 Message-ID: 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="38888"; mail-complaints-to="usenet@ciao.gmane.io" Cc: Thomas Fitzsimmons , emacs-devel@gnu.org To: Stefan Monnier Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Fri Apr 15 23:59:22 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 1nfTyL-0009tc-SC for ged-emacs-devel@m.gmane-mx.org; Fri, 15 Apr 2022 23:59:21 +0200 Original-Received: from localhost ([::1]:53700 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nfTyK-0001AK-JO for ged-emacs-devel@m.gmane-mx.org; Fri, 15 Apr 2022 17:59:20 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:43144) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nfTxn-0000Vj-BS for emacs-devel@gnu.org; Fri, 15 Apr 2022 17:58:47 -0400 Original-Received: from smtprelay05.ispgateway.de ([80.67.18.28]:61483) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nfTxl-0006M9-9L for emacs-devel@gnu.org; Fri, 15 Apr 2022 17:58:46 -0400 Original-Received: from [46.244.203.213] (helo=condition-alpha.com) by smtprelay05.ispgateway.de with esmtpsa (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1nfTy8-0007HZ-UA; Fri, 15 Apr 2022 23:59:09 +0200 In-Reply-To: X-Df-Sender: YWxleGFuZGVyLmFkb2xmQGNvbmRpdGlvbi1hbHBoYS5jb20= Received-SPF: pass client-ip=80.67.18.28; envelope-from=alexander.adolf@condition-alpha.com; helo=smtprelay05.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:288465 Archived-At: 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... --alexander