unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Re: [elpa] externals/ebdb 9e7a96f: Add experimental ebdb-completion-at-point-function
       [not found] ` <20180323044823.1A70C20BDE@vcs0.savannah.gnu.org>
@ 2018-03-23  5:18   ` Stefan Monnier
  2018-03-23  5:50     ` Eric Abrahamsen
  0 siblings, 1 reply; 14+ messages in thread
From: Stefan Monnier @ 2018-03-23  5:18 UTC (permalink / raw)
  To: emacs-devel; +Cc: Eric Abrahamsen

> +;; Experimental completion-at-point function.  I'm not sure this is a
> +;; good idea yet -- with a large enough EBDB database, nearly any
> +;; string is completable, meaning the other completion-at-point
> +;; functions will rarely get a chance.
> +(defun ebdb-completion-at-point-function ()
[...]
> +    (when completions
> +      (list start (point)
> +	    (mapcar
> +	     (lambda (str)
> +	       ;; Gross.
> +	       (if (string-match-p "@" str)
> +		   str
> +		 (capitalize str)))
> +	     completions)
> +	    '(:exclusive no)))))

Completion-at-point-functions are expected to be cheap/fast (it's normal
to call it in post-command-hook) and in order to work correctly the
completion table it returns should ideally not depend on the text
between START and END (i.e. it's OK to look at the text between
START..END in order to choose between an email completion table and
a file completion table, but it shouldn't throw away emails just
because they don't seem to match the text between START..END).

Also in order to be effective, you want them to be selective, e.g. only
match when we're pretty sure that the completion-table we return is
relevant (e.g. we're on a "To:" line in a message-mode buffer), so it
usually depends on the major mode in which it's used.

EBDB might elect not to provide a completion-at-point-function but
instead to provide only a completion-table (or a bunch of completion
tables).  Then message-mode could use that completion-table when it
determines that we're completing an email address.


        Stefan



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [elpa] externals/ebdb 9e7a96f: Add experimental ebdb-completion-at-point-function
  2018-03-23  5:18   ` [elpa] externals/ebdb 9e7a96f: Add experimental ebdb-completion-at-point-function Stefan Monnier
@ 2018-03-23  5:50     ` Eric Abrahamsen
  2018-03-23 10:54       ` Thomas Fitzsimmons
                         ` (2 more replies)
  0 siblings, 3 replies; 14+ messages in thread
From: Eric Abrahamsen @ 2018-03-23  5:50 UTC (permalink / raw)
  To: emacs-devel

Stefan Monnier <monnier@IRO.UMontreal.CA> writes:

>> +;; Experimental completion-at-point function.  I'm not sure this is a
>> +;; good idea yet -- with a large enough EBDB database, nearly any
>> +;; string is completable, meaning the other completion-at-point
>> +;; functions will rarely get a chance.
>> +(defun ebdb-completion-at-point-function ()
> [...]
>> +    (when completions
>> +      (list start (point)
>> +	    (mapcar
>> +	     (lambda (str)
>> +	       ;; Gross.
>> +	       (if (string-match-p "@" str)
>> +		   str
>> +		 (capitalize str)))
>> +	     completions)
>> +	    '(:exclusive no)))))
> Completion-at-point-functions are expected to be cheap/fast (it's normal
> to call it in post-command-hook) and in order to work correctly the
> completion table it returns should ideally not depend on the text
> between START and END (i.e. it's OK to look at the text between
> START..END in order to choose between an email completion table and
> a file completion table, but it shouldn't throw away emails just
> because they don't seem to match the text between START..END).
>
> Also in order to be effective, you want them to be selective, e.g. only
> match when we're pretty sure that the completion-table we return is
> relevant (e.g. we're on a "To:" line in a message-mode buffer), so it
> usually depends on the major mode in which it's used.
>
> EBDB might elect not to provide a completion-at-point-function but
> instead to provide only a completion-table (or a bunch of completion
> tables).  Then message-mode could use that completion-table when it
> determines that we're completing an email address.

Thanks for these notes!

In part I was wondering if it would be useful to provide completion on
contact names in other contexts besides message headers, but I suppose
the right thing to do is just add contact names to the user's personal
spelling dictionary, and allow them to complete names as part of
spell-checking/ispell-complete-word. EBDB provides other tools for
inserting contact information in random contexts.

So this completion function should be targeted specifically at
message/mail-mode header lines. I'll no longer override <TAB> in that
message-mode, but instead tie into what's already there.

In message-mode, c-a-p-f contains `message-completion-function', which
consults `message-completion-alist' (which contains a FIXME: "Make it
possible to use the standard completion UI."), which hands off to
`message-expand-name', which is hard-coded to use either eudc, bbdb, or
`expand-abbrev'. There is a user option,
`message-expand-name-databases', but it's mostly useless as putting new
databases in there won't actually let you use them.

Looks like you added that FIXME! If you outline how you think this ought
to look, I can take a stab at patching message.el. At what level should
these functions be intervening?

My only reservation is that BBDB/EBDB mail completion first completes a
contact mail address, and subsequently cycles through that contact's
other addresses. Is this something that the standard mechanisms can
replicate?

Thanks,
Eric




^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [elpa] externals/ebdb 9e7a96f: Add experimental ebdb-completion-at-point-function
  2018-03-23  5:50     ` Eric Abrahamsen
@ 2018-03-23 10:54       ` Thomas Fitzsimmons
  2018-03-23 12:10         ` Eric Abrahamsen
  2018-03-23 12:11       ` Eric Abrahamsen
  2018-03-23 12:23       ` Stefan Monnier
  2 siblings, 1 reply; 14+ messages in thread
From: Thomas Fitzsimmons @ 2018-03-23 10:54 UTC (permalink / raw)
  To: Eric Abrahamsen; +Cc: emacs-devel

Eric Abrahamsen <eric@ericabrahamsen.net> writes:

> Stefan Monnier <monnier@IRO.UMontreal.CA> writes:
>
>>> +;; Experimental completion-at-point function.  I'm not sure this is a
>>> +;; good idea yet -- with a large enough EBDB database, nearly any
>>> +;; string is completable, meaning the other completion-at-point
>>> +;; functions will rarely get a chance.

See also: eudc-expand-inline, which works at point as long as the
to-be-completed string is the only thing between beginning-of-line and
point.  This is what I use for inline BBDB and LDAP completion anywhere
in Emacs, not just in message-mode headers.  It's useful, for example,
when adding someone's email address to an Org-mode entry (type a few
letters of their first name, then M-x eudc-expand-inline).

Maybe we could add an EBDB backend for EUDC.

Thomas



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [elpa] externals/ebdb 9e7a96f: Add experimental ebdb-completion-at-point-function
  2018-03-23 10:54       ` Thomas Fitzsimmons
@ 2018-03-23 12:10         ` Eric Abrahamsen
  0 siblings, 0 replies; 14+ messages in thread
From: Eric Abrahamsen @ 2018-03-23 12:10 UTC (permalink / raw)
  To: Thomas Fitzsimmons; +Cc: emacs-devel

Thomas Fitzsimmons <fitzsim@fitzsim.org> writes:

> Eric Abrahamsen <eric@ericabrahamsen.net> writes:
>
>> Stefan Monnier <monnier@IRO.UMontreal.CA> writes:
>>
>>>> +;; Experimental completion-at-point function.  I'm not sure this is a
>>>> +;; good idea yet -- with a large enough EBDB database, nearly any
>>>> +;; string is completable, meaning the other completion-at-point
>>>> +;; functions will rarely get a chance.
>
> See also: eudc-expand-inline, which works at point as long as the
> to-be-completed string is the only thing between beginning-of-line and
> point.  This is what I use for inline BBDB and LDAP completion anywhere
> in Emacs, not just in message-mode headers.  It's useful, for example,
> when adding someone's email address to an Org-mode entry (type a few
> letters of their first name, then M-x eudc-expand-inline).
>
> Maybe we could add an EBDB backend for EUDC.

To be honest, I never looked at what EUDC actually is. I'd be happy to
add an EBDB backend, I'll put that on the list.

Eric



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [elpa] externals/ebdb 9e7a96f: Add experimental ebdb-completion-at-point-function
  2018-03-23  5:50     ` Eric Abrahamsen
  2018-03-23 10:54       ` Thomas Fitzsimmons
@ 2018-03-23 12:11       ` Eric Abrahamsen
  2018-03-23 12:23       ` Stefan Monnier
  2 siblings, 0 replies; 14+ messages in thread
From: Eric Abrahamsen @ 2018-03-23 12:11 UTC (permalink / raw)
  To: emacs-devel

Eric Abrahamsen <eric@ericabrahamsen.net> writes:

> Stefan Monnier <monnier@IRO.UMontreal.CA> writes:
>
>>> +;; Experimental completion-at-point function.  I'm not sure this is a
>>> +;; good idea yet -- with a large enough EBDB database, nearly any
>>> +;; string is completable, meaning the other completion-at-point
>>> +;; functions will rarely get a chance.
>>> +(defun ebdb-completion-at-point-function ()
>> [...]
>>> +    (when completions
>>> +      (list start (point)
>>> +	    (mapcar
>>> +	     (lambda (str)
>>> +	       ;; Gross.
>>> +	       (if (string-match-p "@" str)
>>> +		   str
>>> +		 (capitalize str)))
>>> +	     completions)
>>> +	    '(:exclusive no)))))
>> Completion-at-point-functions are expected to be cheap/fast (it's normal
>> to call it in post-command-hook) and in order to work correctly the
>> completion table it returns should ideally not depend on the text
>> between START and END (i.e. it's OK to look at the text between
>> START..END in order to choose between an email completion table and
>> a file completion table, but it shouldn't throw away emails just
>> because they don't seem to match the text between START..END).
>>
>> Also in order to be effective, you want them to be selective, e.g. only
>> match when we're pretty sure that the completion-table we return is
>> relevant (e.g. we're on a "To:" line in a message-mode buffer), so it
>> usually depends on the major mode in which it's used.
>>
>> EBDB might elect not to provide a completion-at-point-function but
>> instead to provide only a completion-table (or a bunch of completion
>> tables).  Then message-mode could use that completion-table when it
>> determines that we're completing an email address.

[...]

> My only reservation is that BBDB/EBDB mail completion first completes a
> contact mail address, and subsequently cycles through that contact's
> other addresses. Is this something that the standard mechanisms can
> replicate?

Never mind, obviously the completion functions can do whatever they like
with the string to be completed.




^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [elpa] externals/ebdb 9e7a96f: Add experimental ebdb-completion-at-point-function
  2018-03-23  5:50     ` Eric Abrahamsen
  2018-03-23 10:54       ` Thomas Fitzsimmons
  2018-03-23 12:11       ` Eric Abrahamsen
@ 2018-03-23 12:23       ` Stefan Monnier
  2018-04-14  1:02         ` Completion functions in message-mode (was: [elpa] externals/ebdb 9e7a96f: Add experimental ebdb-completion-at-point-function) Eric Abrahamsen
  2 siblings, 1 reply; 14+ messages in thread
From: Stefan Monnier @ 2018-03-23 12:23 UTC (permalink / raw)
  To: emacs-devel

> Looks like you added that FIXME! If you outline how you think this ought
> to look, I can take a stab at patching message.el. At what level should
> these functions be intervening?

One of the main issue is preserving backward compatibility with existing
functions the user may have set in message-completion-alist.

I have already some local patches to try and do some of that, so see
patch below (I hand-edited it to remove irrelevant other cosmetic
changes, so don't try to pass it to `patch`).

> My only reservation is that BBDB/EBDB mail completion first completes a
> contact mail address, and subsequently cycles through that contact's
> other addresses. Is this something that the standard mechanisms can
> replicate?

You can get cycling via completion-cycle-threshold, yes.


        Stefan


diff --git a/lisp/gnus/message.el b/lisp/gnus/message.el
index e452c80e26..c99708845d 100644
--- a/lisp/gnus/message.el
+++ b/lisp/gnus/message.el
@@ -7930,6 +7936,8 @@ message-tab
 
 (defvar mail-abbrev-mode-regexp)
 
+(defvar message--old-style-completion-functions nil)
+
 (defun message-completion-function ()
   (let ((alist message-completion-alist))
     (while (and alist
@@ -7938,9 +7946,21 @@ message-completion-function
       (setq alist (cdr alist)))
     (when (cdar alist)
       (let ((fun (cdar alist)))
-        ;; Even if completion fails, return a non-nil value, so as to avoid
-        ;; falling back to message-tab-body-function.
-        (lambda () (funcall fun) 'completion-attempted)))))
+        (if (member fun message--old-style-completion-functions)
+            ;; Even if completion fails, return a non-nil value, so as to avoid
+            ;; falling back to message-tab-body-function.
+            (lambda () (funcall fun) 'completion-attempted)
+          (let ((ticks-before (buffer-chars-modified-tick))
+                (data (funcall fun)))
+            (if (and (eq ticks-before (buffer-chars-modified-tick))
+                     (or (null data)
+                         (integerp (car-safe data))))
+                data
+              (push fun message--old-style-completion-functions)
+              ;; Completion was already performed, so just return a dummy
+              ;; function that prevents trying any further.
+              (lambda () 'completion-attempted))))))))
+
 
 (defun message-expand-group ()
   "Expand the group name under point."
@@ -7966,7 +8083,9 @@ message-expand-group
 		 group)
 	       collection))
        gnus-active-hashtb))
-    (completion-in-region b e collection)))
+    ;; FIXME: Add `category' metadata to the collection, so we can use
+    ;; substring matching on it.
+    (list b e collection)))
 
 (defun message-expand-name ()
   (cond ((and (memq 'eudc message-expand-name-databases)




^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Completion functions in message-mode (was: [elpa] externals/ebdb 9e7a96f: Add experimental ebdb-completion-at-point-function)
  2018-03-23 12:23       ` Stefan Monnier
@ 2018-04-14  1:02         ` Eric Abrahamsen
  2018-04-14  1:17           ` Completion functions in message-mode Stefan Monnier
  2018-04-14 12:59           ` Lars Ingebrigtsen
  0 siblings, 2 replies; 14+ messages in thread
From: Eric Abrahamsen @ 2018-04-14  1:02 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Lars Ingebrigtsen, emacs-devel

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>> Looks like you added that FIXME! If you outline how you think this ought
>> to look, I can take a stab at patching message.el. At what level should
>> these functions be intervening?
>
> One of the main issue is preserving backward compatibility with existing
> functions the user may have set in message-completion-alist.
>
> I have already some local patches to try and do some of that, so see
> patch below (I hand-edited it to remove irrelevant other cosmetic
> changes, so don't try to pass it to `patch`).

Okay, I'm finally coming back around to this, and I need a bit more of
an overview to know what to do. Lars seems to have come in from the
cold, so I'm copying him here.

Leaving backward compatibility aside for a second, here's my take on
things:

What we've got is:

message-mode binds TAB to `message-tab', which calls
`completion-at-point' and, if that doesn't work, falls back to other
things. message-mode adds `message-completion-function' to
`completion-functions-at-point', so TAB ends up calling that function
first. If point is in a viable header, the function calls
`message-expand-group' or `message-expand-name' depending on the header,
but either way _always_ returns a value so that it prevents any other
capf functions from running. If point isn't in a viable header, we get
the "falls back to other things" behavior.

`message-expand-name' is the one that hands off to EUDC, BBDB, etc. The
whole issue is that these package functions do their own completion,
rather than interfacing with `completion-at-point'.

What we _want_ is (and I'm partially guessing here): 

message-mode adds message-expand-group and message-tab-body-function to
`completion-at-point-functions'. Both of these functions check if
they're in an appropriate location, and bail if not, allowing other
functions to do their thing.

Packages such as EUDC and BBDB put their own functions in
`completion-at-point-functions' (in the message-mode hook). The first
thing these functions do is test if they're in an appropriate header,
and bail if not. Otherwise they return an appropriate value for c-a-p,
ie (START END COLLECTION), rather than doing their own completion.

Does this seem about right? Backwards compatibility is still an issue,
but that's what Stefan's patch addresses.

Eric



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Completion functions in message-mode
  2018-04-14  1:02         ` Completion functions in message-mode (was: [elpa] externals/ebdb 9e7a96f: Add experimental ebdb-completion-at-point-function) Eric Abrahamsen
@ 2018-04-14  1:17           ` Stefan Monnier
  2018-04-14  2:33             ` Eric Abrahamsen
  2018-04-14 12:59           ` Lars Ingebrigtsen
  1 sibling, 1 reply; 14+ messages in thread
From: Stefan Monnier @ 2018-04-14  1:17 UTC (permalink / raw)
  To: emacs-devel

> message-mode adds message-expand-group and message-tab-body-function to
> `completion-at-point-functions'. Both of these functions check if
> they're in an appropriate location, and bail if not, allowing other
> functions to do their thing.

I think it's OK for Gnus to keep using message-completion-alist, but
message-expand-name should use a completion table which can be extended,
so EUDC, BBDB, ecomplete, and YouNameIt can add themselves to it.

> Packages such as EUDC and BBDB put their own functions in
> `completion-at-point-functions' (in the message-mode hook).

That doesn't sound right: the code which decides if we're inside
a message header, and which header contains email addresses, and how
they're separated (i.e. the code which knows about the format of
messages) should squarely belong to message-mode and not to
BBDB/EUDC/...

Instead these backends should only provide completion tables that
provide user names, email addresses, or such data.

I.e. the completion-at-point-function should come from message.el and
the completion-tables it returns should come from BBDB/EUDC/...


        Stefan




^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Completion functions in message-mode
  2018-04-14  1:17           ` Completion functions in message-mode Stefan Monnier
@ 2018-04-14  2:33             ` Eric Abrahamsen
  2018-04-14 17:37               ` Stefan Monnier
  0 siblings, 1 reply; 14+ messages in thread
From: Eric Abrahamsen @ 2018-04-14  2:33 UTC (permalink / raw)
  To: emacs-devel

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>> message-mode adds message-expand-group and message-tab-body-function to
>> `completion-at-point-functions'. Both of these functions check if
>> they're in an appropriate location, and bail if not, allowing other
>> functions to do their thing.
>
> I think it's OK for Gnus to keep using message-completion-alist, but
> message-expand-name should use a completion table which can be extended,
> so EUDC, BBDB, ecomplete, and YouNameIt can add themselves to it.
>
>> Packages such as EUDC and BBDB put their own functions in
>> `completion-at-point-functions' (in the message-mode hook).
>
> That doesn't sound right: the code which decides if we're inside
> a message header, and which header contains email addresses, and how
> they're separated (i.e. the code which knows about the format of
> messages) should squarely belong to message-mode and not to
> BBDB/EUDC/...
>
> Instead these backends should only provide completion tables that
> provide user names, email addresses, or such data.
>
> I.e. the completion-at-point-function should come from message.el and
> the completion-tables it returns should come from BBDB/EUDC/...

Good! Thanks, that's the direction I needed.

My next question is, how does one "extend" a completion table?
Specifically: if c-a-p expects to receive (START END COLLECTION), should
the message-mode capf function marshal collections from various
backends, and offer them up as part of that one return value?

So say we add a message-name-completion-functions option, each backend
adds its function there, and message-mode calls all those functions,
gathers the results, and returns them to `completion-at-point'?

Almost there,
Eric




^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Completion functions in message-mode
  2018-04-14  1:02         ` Completion functions in message-mode (was: [elpa] externals/ebdb 9e7a96f: Add experimental ebdb-completion-at-point-function) Eric Abrahamsen
  2018-04-14  1:17           ` Completion functions in message-mode Stefan Monnier
@ 2018-04-14 12:59           ` Lars Ingebrigtsen
  2018-04-14 16:17             ` Eric Abrahamsen
  1 sibling, 1 reply; 14+ messages in thread
From: Lars Ingebrigtsen @ 2018-04-14 12:59 UTC (permalink / raw)
  To: Eric Abrahamsen; +Cc: Stefan Monnier, emacs-devel

Eric Abrahamsen <eric@ericabrahamsen.net> writes:

> message-mode adds message-expand-group and message-tab-body-function to
> `completion-at-point-functions'. Both of these functions check if
> they're in an appropriate location, and bail if not, allowing other
> functions to do their thing.

Does this also tie into ecomplete somehow?  :-)

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Completion functions in message-mode
  2018-04-14 12:59           ` Lars Ingebrigtsen
@ 2018-04-14 16:17             ` Eric Abrahamsen
  0 siblings, 0 replies; 14+ messages in thread
From: Eric Abrahamsen @ 2018-04-14 16:17 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: Stefan Monnier, emacs-devel

Lars Ingebrigtsen <larsi@gnus.org> writes:

> Eric Abrahamsen <eric@ericabrahamsen.net> writes:
>
>> message-mode adds message-expand-group and message-tab-body-function to
>> `completion-at-point-functions'. Both of these functions check if
>> they're in an appropriate location, and bail if not, allowing other
>> functions to do their thing.
>
> Does this also tie into ecomplete somehow?  :-)

I think the goal is that ecomplete would be one of the $contact_packages
that can add themselves as sources for completions. But I'm still not
sure of the exact mechanism.



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Completion functions in message-mode
  2018-04-14  2:33             ` Eric Abrahamsen
@ 2018-04-14 17:37               ` Stefan Monnier
  2018-04-25 19:24                 ` Eric Abrahamsen
  0 siblings, 1 reply; 14+ messages in thread
From: Stefan Monnier @ 2018-04-14 17:37 UTC (permalink / raw)
  To: emacs-devel

> My next question is, how does one "extend" a completion table?

Not sure what you mean, but you can combine completion tables for
example by using completion-table-in-turn, or by doing something
similar to what it does.

> Specifically: if c-a-p expects to receive (START END COLLECTION), should
                                                       ^^^^^^^^^^
BTW, this is what I call "completion table".


        Stefan




^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Completion functions in message-mode
  2018-04-14 17:37               ` Stefan Monnier
@ 2018-04-25 19:24                 ` Eric Abrahamsen
  2018-06-06 21:09                   ` Eric Abrahamsen
  0 siblings, 1 reply; 14+ messages in thread
From: Eric Abrahamsen @ 2018-04-25 19:24 UTC (permalink / raw)
  To: emacs-devel; +Cc: Stefan Monnier

[-- Attachment #1: Type: text/plain, Size: 1398 bytes --]

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>> My next question is, how does one "extend" a completion table?
>
> Not sure what you mean, but you can combine completion tables for
> example by using completion-table-in-turn, or by doing something
> similar to what it does.

Yes, that's what I meant.

>> Specifically: if c-a-p expects to receive (START END COLLECTION), should
>                                                        ^^^^^^^^^^
> BTW, this is what I call "completion table".

Right, that much I understood. But otherwise I was very undereducated
about how completion works, and so have gone down some rabbit holes in
the course of writing the attached patch, which is underwhelming for how
long it took me.

I doubt this will be acceptable as-is, but I do hope it will get us (me)
a step closer. What I ended up with was an option,
`message-expand-name-tables', that contact-management/addressbook
packages can add completion tables to. This is very simple, but probably
too simple: it leaves no mechanism for these packages to add extra PROPS
data, like :predicate or :annotation, and also doesn't give them the
opportunity to alter START and END (though maybe it shouldn't?).

Anyway, for what it is, it works. It also add six spurious blank spaces
to the end of any completion, at least in my test setup, but who's
counting!?

Hopefully we can go somewhere from here.



[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: message-completion.diff --]
[-- Type: text/x-patch, Size: 6872 bytes --]

diff --git a/lisp/gnus/message.el b/lisp/gnus/message.el
index 33c5e2cedb..3a8e3f6e0f 100644
--- a/lisp/gnus/message.el
+++ b/lisp/gnus/message.el
@@ -7929,24 +7929,33 @@ message-make-tool-bar
 				    'message-mode-map))))
   message-tool-bar-map)
 
-;;; Group name completion.
+;;; Group and mail name completion.
 
 (defcustom message-newgroups-header-regexp
   "^\\(Newsgroups\\|Followup-To\\|Posted-To\\|Gcc\\):"
-  "Regexp that match headers that lists groups."
+  "Regexp matching headers that list groups."
   :group 'message
   :type 'regexp)
 
+(defcustom message-mail-header-regexp
+  (concat
+   "^"
+   (regexp-opt
+    '("To" "Bcc" "Cc" "Resent-To" "Resent-Bcc" "Resent-Cc"
+      "Reply-To" "From" "Mail-Followup-To" "Mail-Copies-To"
+      "Disposition-Notification-To" "Return-Receipt-To"))
+   ":")
+  "Regexp matching headers that list name/mail addresses."
+  :group 'message
+  :type 'regexp
+  :version "27.1")
+
 (defcustom message-completion-alist
-  ;; FIXME: Make it possible to use the standard completion UI.
-  (list (cons message-newgroups-header-regexp 'message-expand-group)
-	'("^\\(Resent-\\)?\\(To\\|B?Cc\\):" . message-expand-name)
-	'("^\\(Reply-To\\|From\\|Mail-Followup-To\\|Mail-Copies-To\\):"
-	  . message-expand-name)
-	'("^\\(Disposition-Notification-To\\|Return-Receipt-To\\):"
-	  . message-expand-name))
-  "Alist of (RE . FUN).  Use FUN for completion on header lines matching RE."
-  :version "22.1"
+  (list (cons message-newgroups-header-regexp #'message-expand-group)
+	(cons message-mail-header-regexp #'message-expand-name))
+  "Alist of (RE . FUN).
+Use FUN for completion on header lines matching RE."
+  :version "27.1"
   :group 'message
   :type '(alist :key-type regexp :value-type function))
 
@@ -7956,6 +7965,19 @@ message-expand-name-databases
 Each element is a symbol and can be `bbdb' or `eudc'."
   :group 'message
   :type '(set (const bbdb) (const eudc)))
+(make-obsolete-variable
+ 'message-expand-name-databases
+ "Add completion tables to `message-expand-name-tables' instead"
+ "27.1")
+
+(defcustom message-expand-name-tables nil
+  "List of tables that can be used to expand names.
+Each \"table\" is a collection containing potential expansions,
+and can be an alist, a plain list, a hash table, an obarray, or a
+function.  Multiple tables will be merged."
+  :group 'message
+  :version "27.1"
+  :type 'list)
 
 (defcustom message-tab-body-function nil
   "Function to execute when `message-tab' (TAB) is executed in the body.
@@ -7982,24 +8004,16 @@ message-tab
    (message-tab-body-function (funcall message-tab-body-function))
    (t (funcall (or (lookup-key text-mode-map "\t")
                    (lookup-key global-map "\t")
-                   'indent-relative)))))
+                   #'indent-relative)))))
 
 (defvar mail-abbrev-mode-regexp)
 
-(defun message-completion-function ()
-  (let ((alist message-completion-alist))
-    (while (and alist
-		(let ((mail-abbrev-mode-regexp (caar alist)))
-		  (not (mail-abbrev-in-expansion-header-p))))
-      (setq alist (cdr alist)))
-    (when (cdar alist)
-      (let ((fun (cdar alist)))
-        ;; Even if completion fails, return a non-nil value, so as to avoid
-        ;; falling back to message-tab-body-function.
-        (lambda () (funcall fun) 'completion-attempted)))))
+(defvar message--old-style-completion-functions nil)
 
-(defun message-expand-group ()
-  "Expand the group name under point."
+(defsubst message-header-completion-bounds ()
+  "Return the bounds of header input for completion.
+Searches back for either the end of header or the nearest comma,
+and forward for either the nearest comma or EOL."
   (let ((b (save-excursion
 	     (save-restriction
 	       (narrow-to-region
@@ -8009,36 +8023,57 @@ message-expand-group
 		  (1+ (point)))
 		(point))
 	       (skip-chars-backward "^, \t\n") (point))))
-	(completion-ignore-case t)
-	(e (progn (skip-chars-forward "^,\t\n ") (point)))
-	group collection)
-    (when (and (boundp 'gnus-active-hashtb)
-	       gnus-active-hashtb)
-      (mapatoms
-       (lambda (symbol)
-	 (setq group (symbol-name symbol))
-	 (push (if (string-match "[^\000-\177]" group)
-		   (gnus-group-decoded-name group)
-		 group)
-	       collection))
-       gnus-active-hashtb))
-    (completion-in-region b e collection)))
+	(e (progn (skip-chars-forward "^,\t\n ") (point))))
+    (cons b e)))
+
+(defun message-completion-function ()
+  "Possibly complete a group name or mail address.
+Check if point is in an appropriate header for completion,
+otherwise return nil."
+  (let ((alist message-completion-alist))
+    (while (and alist
+		(let ((mail-abbrev-mode-regexp (caar alist)))
+		  (not (mail-abbrev-in-expansion-header-p))))
+      (setq alist (cdr alist)))
+    (when (cdar alist)
+      (let ((fun (cdar alist))
+	    (completion-ignore-case t))
+	(if (member fun message--old-style-completion-functions)
+	    ;; Even if completion fails, return a non-nil value, so as to avoid
+	    ;; falling back to message-tab-body-function.
+	    (lambda () (funcall fun) 'completion-attempted)
+	  (let ((ticks-before (buffer-chars-modified-tick))
+		(data (funcall fun)))
+	    (if (and (eq ticks-before (buffer-chars-modified-tick))
+		     (or (null data)
+			 (integerp (car-safe data))))
+		data
+	      (push fun message--old-style-completion-functions)
+	      ;; Completion was already performed, so just return a dummy
+	      ;; function that prevents trying any further.
+	      (lambda () 'completion-attempted))))))))
+
+(defun message-expand-group ()
+  "Return group completion from `gnus-active-hashtb'."
+  (pcase-let ((`(,b . ,e) (message-header-completion-bounds)))
+    (let (collection group)
+     (when (and (boundp 'gnus-active-hashtb)
+		gnus-active-hashtb)
+       (mapatoms
+	(lambda (symbol)
+	  (setq group (symbol-name symbol))
+	  (push (if (string-match "[^\000-\177]" group)
+		    (gnus-group-decoded-name group)
+		  group)
+		collection))
+	gnus-active-hashtb)
+       (list b e collection)))))
 
 (defun message-expand-name ()
-  (cond ((and (memq 'eudc message-expand-name-databases)
-		    (boundp 'eudc-protocol)
-		    eudc-protocol)
-	 (eudc-expand-inline))
-	((and (memq 'bbdb message-expand-name-databases)
-	      (fboundp 'bbdb-complete-name))
-         (let ((starttick (buffer-modified-tick)))
-           (or (bbdb-complete-name)
-               ;; Apparently, bbdb-complete-name can return nil even when
-               ;; completion took place.  So let's double check the buffer was
-               ;; not modified.
-               (/= starttick (buffer-modified-tick)))))
-	(t
-	 (expand-abbrev))))
+  (pcase-let ((`(,b . ,e) (message-header-completion-bounds)))
+    (when message-expand-name-tables
+      (list b e (apply #'completion-table-in-turn
+		       message-expand-name-tables)))))
 
 ;;; Help stuff.
 

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: Completion functions in message-mode
  2018-04-25 19:24                 ` Eric Abrahamsen
@ 2018-06-06 21:09                   ` Eric Abrahamsen
  0 siblings, 0 replies; 14+ messages in thread
From: Eric Abrahamsen @ 2018-06-06 21:09 UTC (permalink / raw)
  To: emacs-devel; +Cc: Stefan Monnier

Eric Abrahamsen <eric@ericabrahamsen.net> writes:

> Stefan Monnier <monnier@iro.umontreal.ca> writes:
>
>>> My next question is, how does one "extend" a completion table?
>>
>> Not sure what you mean, but you can combine completion tables for
>> example by using completion-table-in-turn, or by doing something
>> similar to what it does.
>
> Yes, that's what I meant.
>
>>> Specifically: if c-a-p expects to receive (START END COLLECTION), should
>>                                                        ^^^^^^^^^^
>> BTW, this is what I call "completion table".
>
> Right, that much I understood. But otherwise I was very undereducated
> about how completion works, and so have gone down some rabbit holes in
> the course of writing the attached patch, which is underwhelming for how
> long it took me.

Was this too off-base? Is there any chance I could bang it into usable shape?




^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2018-06-06 21:09 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20180323044822.32467.63948@vcs0.savannah.gnu.org>
     [not found] ` <20180323044823.1A70C20BDE@vcs0.savannah.gnu.org>
2018-03-23  5:18   ` [elpa] externals/ebdb 9e7a96f: Add experimental ebdb-completion-at-point-function Stefan Monnier
2018-03-23  5:50     ` Eric Abrahamsen
2018-03-23 10:54       ` Thomas Fitzsimmons
2018-03-23 12:10         ` Eric Abrahamsen
2018-03-23 12:11       ` Eric Abrahamsen
2018-03-23 12:23       ` Stefan Monnier
2018-04-14  1:02         ` Completion functions in message-mode (was: [elpa] externals/ebdb 9e7a96f: Add experimental ebdb-completion-at-point-function) Eric Abrahamsen
2018-04-14  1:17           ` Completion functions in message-mode Stefan Monnier
2018-04-14  2:33             ` Eric Abrahamsen
2018-04-14 17:37               ` Stefan Monnier
2018-04-25 19:24                 ` Eric Abrahamsen
2018-06-06 21:09                   ` Eric Abrahamsen
2018-04-14 12:59           ` Lars Ingebrigtsen
2018-04-14 16:17             ` Eric Abrahamsen

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).