unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* [PATCH] Add abbrev suggestions
@ 2020-07-05 23:40 Mathias Dahl
  2020-07-19 17:40 ` Mathias Dahl
  0 siblings, 1 reply; 19+ messages in thread
From: Mathias Dahl @ 2020-07-05 23:40 UTC (permalink / raw)
  To: emacs-devel


[-- Attachment #1.1: Type: text/plain, Size: 1008 bytes --]

Hi,

After some time I decided to try to send a patch for this.

As for what it is, check the source :)

Or read this short documentation string for the new abbrev-suggest option:

*    Non-nil means we should suggest abbrevs to the user.*
*By enabling this option, if abbrev mode is enabled and if the*
*user has typed some text that exists as an abbrev, suggest to the*
*user to use the abbrev instead."*


You can also read this thread to get the background:

https://lists.gnu.org/archive/html/emacs-devel/2017-09/msg00449.html

The recent discussions can be found here:

https://lists.gnu.org/archive/html/emacs-devel/2020-05/msg01605.html

If this patch looks good (a lot of changes has been done as per the
discussions with Eli, Stefan and others in the threads above, and I hope I
also managed to use the correct format for the patch), I'd be glad if
someone could commit this, and I will get started on the changes to the
Emacs documentation as well. I have signed papers before.

Thanks!

/Mathias

[-- Attachment #1.2: Type: text/html, Size: 1627 bytes --]

[-- Attachment #2: 0001-Add-abbrev-suggestions.patch --]
[-- Type: application/octet-stream, Size: 6610 bytes --]

From 32161858a4b34ec1f36fe0225dcd0b84ca8d43bc Mon Sep 17 00:00:00 2001
From: Mathias Dahl <mathias.dahl@gmail.com>
Date: Sun, 5 Jul 2020 18:44:57 -0400
Subject: [PATCH] Add abbrev suggestions

---
 lisp/abbrev.el | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 139 insertions(+), 2 deletions(-)

diff --git a/lisp/abbrev.el b/lisp/abbrev.el
index 2d61a96..9690dac 100644
--- a/lisp/abbrev.el
+++ b/lisp/abbrev.el
@@ -830,9 +830,144 @@ abbrev-expand-functions
 (make-obsolete-variable 'abbrev-expand-functions 'abbrev-expand-function "24.4")
 
 (defvar abbrev-expand-function #'abbrev--default-expand
-  "Function that `expand-abbrev' uses to perform abbrev expansion.
+    "Function that `expand-abbrev' uses to perform abbrev expansion.
 Takes no argument and should return the abbrev symbol if expansion took place.")
 
+(defcustom abbrev-suggest t
+    "Non-nil means we should suggest abbrevs to the user.
+By enabling this option, if abbrev mode is enabled and if the
+user has typed some text that exists as an abbrev, suggest to the
+user to use the abbrev instead."
+    :type 'boolean
+    :group 'abbrev-mode)
+
+(defcustom abbrev-suggest-hint-threshold 3
+    "Threshold for when to inform the user that there is an abbrev.
+The threshold is the number of characters that differs between
+the length of the abbrev and the length of the expansion.  The
+thinking is that if the expansion is only one or a few characters
+longer than the abbrev, the benefit of informing the user is not
+that big.  If you always want to be informed, set this value to
+`0' or less."
+    :type 'number
+    :group 'abbrev-mode)
+
+(defun abbrev--suggest-get-active-tables-including-parents ()
+  "Return a list of all active abbrev tables, including parent tables."
+  (let* ((tables (abbrev--active-tables))
+	 (all tables))
+    (dolist (table tables)
+      (setq all (append (abbrev-table-get table :parents) all)))
+    all))
+
+(defun abbrev--suggest-get-active-abbrev-expansions ()
+    "Return a list of all the active abbrev expansions.
+Includes expansions from parent abbrev tables."
+    (let (expansions)
+      (dolist (table (abbrev--suggest-get-active-tables-including-parents))
+	(mapatoms (lambda (e)
+		    (let ((value (symbol-value (abbrev--symbol e table))))
+		      (when value
+                        (push (cons value (symbol-name e)) expansions))))
+		  table))
+      expansions))
+
+(defun abbrev--suggest-count-words (expansion)
+    "Return the number of words in EXPANSION.
+Expansion is a string of one or more words."
+    (length (split-string expansion " " t)))
+
+(defun abbrev--suggest-get-previous-words (n)
+    "Return the previous N words, spaces included.
+Changes newlines into spaces."
+    (let ((end (point)))
+      (save-excursion
+	(backward-word n)
+	(replace-regexp-in-string
+	 "\\s " " "
+	 (buffer-substring-no-properties (point) end)))))
+
+(defun abbrev--suggest-above-threshold (expansion)
+    "Return t if we are above the threshold.
+EXPANSION is a cons cell where the car is the expansion and the
+cdr is the abbrev."
+    (>= (- (length (car expansion))
+	   (length (cdr expansion)))
+	abbrev-suggest-hint-threshold))
+
+(defvar abbrev--suggest-saved-recommendations nil
+    "Keeps a list of expansions that have abbrevs defined.
+The user can show this list by calling
+`abbrev-suggest-show-report'.")
+
+(defun abbrev--suggest-inform-user (expansion)
+    "Display a message to the user about the existing abbrev.
+EXPANSION is a cons cell where the `car' is the expansion and the
+`cdr' is the abbrev."
+    (run-with-idle-timer
+     1 nil
+     (lambda ()
+       (message "You can write `%s' using the abbrev `%s'."
+                                   (car expansion) (cdr expansion))))
+    (push expansion abbrev--suggest-saved-recommendations))
+
+(defun abbrev--suggest-shortest-abbrev (new current)
+    "Return the shortest abbrev.
+NEW and CURRENT are cons cells where the `car' is the expansion
+and the `cdr' is the abbrev."
+    (if (not current)
+	new
+      (if (< (length (cdr new))
+	     (length (cdr current)))
+	  new
+	current)))
+
+(defun abbrev--suggest-maybe-suggest ()
+    "Suggest an abbrev to the user based on the word(s) before point.
+Uses `abbrev-suggest-hint-threshold' to find out if the user should be
+informed about the existing abbrev."
+    (let (words abbrev-found word-count)
+      (dolist (expansion (abbrev--suggest-get-active-abbrev-expansions))
+	(setq word-count (abbrev--suggest-count-words (car expansion))
+	      words (abbrev--suggest-get-previous-words word-count))
+	(let ((case-fold-search t))
+	  (when (and (> word-count 0)
+		     (string-match (car expansion) words)
+		     (abbrev--suggest-above-threshold expansion))
+	    (setq abbrev-found (abbrev--suggest-shortest-abbrev
+				expansion abbrev-found)))))
+      (when abbrev-found
+	(abbrev--suggest-inform-user abbrev-found))))
+
+(defun abbrev--suggest-get-totals ()
+    "Return a list of all expansions and their usage.
+Each expansion is a cons cell where the `car' is the expansion
+and the `cdr' is the number of times the expansion has been
+typed."
+    (let (total cell)
+      (dolist (expansion abbrev--suggest-saved-recommendations)
+	(if (not (assoc (car expansion) total))
+	    (push (cons (car expansion) 1) total)
+	  (setq cell (assoc (car expansion) total))
+	  (setcdr cell (1+ (cdr cell)))))
+      total))
+
+(defun abbrev-suggest-show-report ()
+  "Show the user a report of abbrevs he could have used."
+  (interactive)
+  (let ((totals (abbrev--suggest-get-totals))
+	(buf (get-buffer-create "*abbrev-suggest*")))
+    (set-buffer buf)
+    (erase-buffer)
+        (insert "** Abbrev expansion usage **
+
+Below is a list of expansions for which abbrevs are defined, and
+the number of times the expansion was typed manually. To display
+and edit all abbrevs, type `M-x edit-abbrevs RET'\n\n")
+	(dolist (expansion totals)
+	  (insert (format " %s: %d\n" (car expansion) (cdr expansion))))
+	(display-buffer buf)))
+
 (defun expand-abbrev ()
   "Expand the abbrev before point, if there is an abbrev there.
 Effective when explicitly called even when `abbrev-mode' is nil.
@@ -842,7 +977,9 @@ expand-abbrev
 be the abbrev symbol if expansion occurred, else nil.)"
   (interactive)
   (run-hooks 'pre-abbrev-expand-hook)
-  (funcall abbrev-expand-function))
+  (or (funcall abbrev-expand-function)
+      (if abbrev-suggest
+          (abbrev--suggest-maybe-suggest))))
 
 (defun abbrev--default-expand ()
   "Default function to use for `abbrev-expand-function'.
-- 
1.9.1


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

* Re: [PATCH] Add abbrev suggestions
  2020-07-05 23:40 [PATCH] Add abbrev suggestions Mathias Dahl
@ 2020-07-19 17:40 ` Mathias Dahl
  2020-07-19 19:01   ` Eli Zaretskii
  0 siblings, 1 reply; 19+ messages in thread
From: Mathias Dahl @ 2020-07-19 17:40 UTC (permalink / raw)
  To: emacs-devel

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

Hi,

Could someone help out with the below?

Alternatively, what is needed for me to merge this into Emacs myself (how
do I get access, which branch to I work on, etc)? I have basic knowledge of
Git branching and merging.

Thanks!

/Mathias

On Mon, Jul 6, 2020 at 1:40 AM Mathias Dahl <mathias.dahl@gmail.com> wrote:

> Hi,
>
> After some time I decided to try to send a patch for this.
>
> As for what it is, check the source :)
>
> Or read this short documentation string for the new abbrev-suggest option:
>
> *    Non-nil means we should suggest abbrevs to the user.*
> *By enabling this option, if abbrev mode is enabled and if the*
> *user has typed some text that exists as an abbrev, suggest to the*
> *user to use the abbrev instead."*
>
>
> You can also read this thread to get the background:
>
> https://lists.gnu.org/archive/html/emacs-devel/2017-09/msg00449.html
>
> The recent discussions can be found here:
>
> https://lists.gnu.org/archive/html/emacs-devel/2020-05/msg01605.html
>
> If this patch looks good (a lot of changes has been done as per the
> discussions with Eli, Stefan and others in the threads above, and I hope I
> also managed to use the correct format for the patch), I'd be glad if
> someone could commit this, and I will get started on the changes to the
> Emacs documentation as well. I have signed papers before.
>
> Thanks!
>
> /Mathias
>
>

[-- Attachment #2: Type: text/html, Size: 2366 bytes --]

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

* Re: [PATCH] Add abbrev suggestions
  2020-07-19 17:40 ` Mathias Dahl
@ 2020-07-19 19:01   ` Eli Zaretskii
  2020-07-25  8:12     ` Eli Zaretskii
  0 siblings, 1 reply; 19+ messages in thread
From: Eli Zaretskii @ 2020-07-19 19:01 UTC (permalink / raw)
  To: Mathias Dahl; +Cc: emacs-devel

> From: Mathias Dahl <mathias.dahl@gmail.com>
> Date: Sun, 19 Jul 2020 19:40:17 +0200
> 
> Could someone help out with the below?

Sorry your patch was forgotten.  If no one beats me to it, I will take
care of it in a few days.  Stay tuned.

Thanks.



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

* Re: [PATCH] Add abbrev suggestions
  2020-07-19 19:01   ` Eli Zaretskii
@ 2020-07-25  8:12     ` Eli Zaretskii
  2020-08-11 22:16       ` Mathias Dahl
  0 siblings, 1 reply; 19+ messages in thread
From: Eli Zaretskii @ 2020-07-25  8:12 UTC (permalink / raw)
  To: mathias.dahl; +Cc: emacs-devel

> Date: Sun, 19 Jul 2020 22:01:00 +0300
> From: Eli Zaretskii <eliz@gnu.org>
> Cc: emacs-devel@gnu.org
> 
> > From: Mathias Dahl <mathias.dahl@gmail.com>
> > Date: Sun, 19 Jul 2020 19:40:17 +0200
> > 
> > Could someone help out with the below?
> 
> Sorry your patch was forgotten.  If no one beats me to it, I will take
> care of it in a few days.  Stay tuned.

I have a few comments to your patch, mostly about the documentation
parts:

First, please accompany the patch with a ChangeLog-style commit log
message which describes the individual changes.  See CONTRIBUTE for
the style guidance.

>  (defvar abbrev-expand-function #'abbrev--default-expand
> -  "Function that `expand-abbrev' uses to perform abbrev expansion.
> +    "Function that `expand-abbrev' uses to perform abbrev expansion.

What is this whitespace change about?

> +(defcustom abbrev-suggest t
> +    "Non-nil means we should suggest abbrevs to the user.

Our style is "Non-nil means suggest abbrevs ..."

> +By enabling this option, if abbrev mode is enabled and if the
> +user has typed some text that exists as an abbrev, suggest to the
> +user to use the abbrev instead."
> +    :type 'boolean
> +    :group 'abbrev-mode)

Please always specify a :version tag in new and modified defcustoms
(here and elsewhere in your patch).

Are you sure it is a good idea to make this non-nil by default?
Wouldn't some users consider these suggestions an annoyance?

> +(defcustom abbrev-suggest-hint-threshold 3
> +    "Threshold for when to inform the user that there is an abbrev.
> +The threshold is the number of characters that differs between
                                                  ^^^^^^^
"differ", in plural.  I think.

> +the length of the abbrev and the length of the expansion.  The
> +thinking is that if the expansion is only one or a few characters
> +longer than the abbrev, the benefit of informing the user is not
> +that big.  If you always want to be informed, set this value to
> +`0' or less."

This doc string should mention abbrev-suggest, since it only has
effect if that is non-nil.

> +(defun abbrev--suggest-get-previous-words (n)
> +    "Return the previous N words, spaces included.

"Previous" as in "before point", I presume?  If so, please say that.

> +Changes newlines into spaces."
> +    (let ((end (point)))
> +      (save-excursion
> +	(backward-word n)
> +	(replace-regexp-in-string
> +	 "\\s " " "
> +	 (buffer-substring-no-properties (point) end)))))
> +
> +(defun abbrev--suggest-above-threshold (expansion)
> +    "Return t if we are above the threshold.

Who is "we" in this context?  This should be explained.

> +EXPANSION is a cons cell where the car is the expansion and the
> +cdr is the abbrev."

Our style is to include the arguments in the first sentence of the doc
string.

> +(defun abbrev--suggest-shortest-abbrev (new current)
> +    "Return the shortest abbrev.
> +NEW and CURRENT are cons cells where the `car' is the expansion

Same here.

> +(defun abbrev--suggest-get-totals ()
> +    "Return a list of all expansions and their usage.
> +Each expansion is a cons cell where the `car' is the expansion
> +and the `cdr' is the number of times the expansion has been
> +typed."

This doc string doesn't explain the meaning of "usage" in this case.

> +Below is a list of expansions for which abbrevs are defined, and
> +the number of times the expansion was typed manually. To display
                                                       ^^
Two spaces between sentences, please.

Finally, I think these new features should be in NEWS and probably
also in the user manual.

Thank you for working on this.



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

* Re: [PATCH] Add abbrev suggestions
  2020-07-25  8:12     ` Eli Zaretskii
@ 2020-08-11 22:16       ` Mathias Dahl
  2020-08-13 13:59         ` Eli Zaretskii
  0 siblings, 1 reply; 19+ messages in thread
From: Mathias Dahl @ 2020-08-11 22:16 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

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

Hi Eli,

> I have a few comments to your patch, mostly about the documentation
> parts:

Thanks for taking the time to review this.

> First, please accompany the patch with a ChangeLog-style commit log
> message which describes the individual changes.  See CONTRIBUTE for
> the style guidance.

Will do.

> >  (defvar abbrev-expand-function #'abbrev--default-expand
> > -  "Function that `expand-abbrev' uses to perform abbrev expansion.
> > +    "Function that `expand-abbrev' uses to perform abbrev expansion.
>
> What is this whitespace change about?

No idea :), will fix it.

> > +(defcustom abbrev-suggest t
> > +    "Non-nil means we should suggest abbrevs to the user.
>
> Our style is "Non-nil means suggest abbrevs ..."

Got it!

> Please always specify a :version tag in new and modified defcustoms
> (here and elsewhere in your patch).

Sure.

> Are you sure it is a good idea to make this non-nil by default?
> Wouldn't some users consider these suggestions an annoyance?

No, I'm not. In fact, it was not the default when I started working on
this, but Stefan suggested that it might be a good default. Now we're
me and you against him, I guess... :)

> > +(defcustom abbrev-suggest-hint-threshold 3
> > +    "Threshold for when to inform the user that there is an abbrev.
> > +The threshold is the number of characters that differs between
>                                                   ^^^^^^^
> "differ", in plural.  I think.

I trust you.

> > +the length of the abbrev and the length of the expansion.  The
> > +thinking is that if the expansion is only one or a few characters
> > +longer than the abbrev, the benefit of informing the user is not
> > +that big.  If you always want to be informed, set this value to
> > +`0' or less."
>
> This doc string should mention abbrev-suggest, since it only has
> effect if that is non-nil.

I'll rework it.

> > +(defun abbrev--suggest-get-previous-words (n)
> > +    "Return the previous N words, spaces included.
>
> "Previous" as in "before point", I presume?  If so, please say that.

Yes.

> > +Changes newlines into spaces."
> > +    (let ((end (point)))
> > +      (save-excursion
> > +     (backward-word n)
> > +     (replace-regexp-in-string
> > +      "\\s " " "
> > +      (buffer-substring-no-properties (point) end)))))
> > +
> > +(defun abbrev--suggest-above-threshold (expansion)
> > +    "Return t if we are above the threshold.
>
> Who is "we" in this context?  This should be explained.

I know, I was not happy when I wrote that. "we", here, is something
like "the difference in length between what the user typed and the
abbrev that we found." I guess I could not find a good way to keep the
first sentence of the docstring short, so I opted for the fuzzy "we"
expression...

> > +EXPANSION is a cons cell where the car is the expansion and the
> > +cdr is the abbrev."
>
> Our style is to include the arguments in the first sentence of the doc
> string.

I know. Frankly I don't know if I can come up with a suggestion that
combines that together with having a relatively short first
sentence...

> > +(defun abbrev--suggest-shortest-abbrev (new current)
> > +    "Return the shortest abbrev.
> > +NEW and CURRENT are cons cells where the `car' is the expansion
>
> Same here.

Should be easy to fix.

> > +(defun abbrev--suggest-get-totals ()
> > +    "Return a list of all expansions and their usage.
> > +Each expansion is a cons cell where the `car' is the expansion
> > +and the `cdr' is the number of times the expansion has been
> > +typed."
>
> This doc string doesn't explain the meaning of "usage" in this case.

I'll fix it.

> > +Below is a list of expansions for which abbrevs are defined, and
> > +the number of times the expansion was typed manually. To display
>                                                        ^^
> Two spaces between sentences, please.

Of course :)

> Finally, I think these new features should be in NEWS and probably
> also in the user manual.

Agree. Should I include those changes in the same patch and resend
that when done?

> Thank you for working on this.

Welcome. I think this would be a useful addition, for me and others,
and that makes it fun.

Thank you for doing what you do best, and keep on top of all the Emacs
things :)

/Mathias


On Sat, Jul 25, 2020 at 10:13 AM Eli Zaretskii <eliz@gnu.org> wrote:

> > Date: Sun, 19 Jul 2020 22:01:00 +0300
> > From: Eli Zaretskii <eliz@gnu.org>
> > Cc: emacs-devel@gnu.org
> >
> > > From: Mathias Dahl <mathias.dahl@gmail.com>
> > > Date: Sun, 19 Jul 2020 19:40:17 +0200
> > >
> > > Could someone help out with the below?
> >
> > Sorry your patch was forgotten.  If no one beats me to it, I will take
> > care of it in a few days.  Stay tuned.
>
> I have a few comments to your patch, mostly about the documentation
> parts:
>
> First, please accompany the patch with a ChangeLog-style commit log
> message which describes the individual changes.  See CONTRIBUTE for
> the style guidance.
>
> >  (defvar abbrev-expand-function #'abbrev--default-expand
> > -  "Function that `expand-abbrev' uses to perform abbrev expansion.
> > +    "Function that `expand-abbrev' uses to perform abbrev expansion.
>
> What is this whitespace change about?
>
> > +(defcustom abbrev-suggest t
> > +    "Non-nil means we should suggest abbrevs to the user.
>
> Our style is "Non-nil means suggest abbrevs ..."
>
> > +By enabling this option, if abbrev mode is enabled and if the
> > +user has typed some text that exists as an abbrev, suggest to the
> > +user to use the abbrev instead."
> > +    :type 'boolean
> > +    :group 'abbrev-mode)
>
> Please always specify a :version tag in new and modified defcustoms
> (here and elsewhere in your patch).
>
> Are you sure it is a good idea to make this non-nil by default?
> Wouldn't some users consider these suggestions an annoyance?
>
> > +(defcustom abbrev-suggest-hint-threshold 3
> > +    "Threshold for when to inform the user that there is an abbrev.
> > +The threshold is the number of characters that differs between
>                                                   ^^^^^^^
> "differ", in plural.  I think.
>
> > +the length of the abbrev and the length of the expansion.  The
> > +thinking is that if the expansion is only one or a few characters
> > +longer than the abbrev, the benefit of informing the user is not
> > +that big.  If you always want to be informed, set this value to
> > +`0' or less."
>
> This doc string should mention abbrev-suggest, since it only has
> effect if that is non-nil.
>
> > +(defun abbrev--suggest-get-previous-words (n)
> > +    "Return the previous N words, spaces included.
>
> "Previous" as in "before point", I presume?  If so, please say that.
>
> > +Changes newlines into spaces."
> > +    (let ((end (point)))
> > +      (save-excursion
> > +     (backward-word n)
> > +     (replace-regexp-in-string
> > +      "\\s " " "
> > +      (buffer-substring-no-properties (point) end)))))
> > +
> > +(defun abbrev--suggest-above-threshold (expansion)
> > +    "Return t if we are above the threshold.
>
> Who is "we" in this context?  This should be explained.
>
> > +EXPANSION is a cons cell where the car is the expansion and the
> > +cdr is the abbrev."
>
> Our style is to include the arguments in the first sentence of the doc
> string.
>
> > +(defun abbrev--suggest-shortest-abbrev (new current)
> > +    "Return the shortest abbrev.
> > +NEW and CURRENT are cons cells where the `car' is the expansion
>
> Same here.
>
> > +(defun abbrev--suggest-get-totals ()
> > +    "Return a list of all expansions and their usage.
> > +Each expansion is a cons cell where the `car' is the expansion
> > +and the `cdr' is the number of times the expansion has been
> > +typed."
>
> This doc string doesn't explain the meaning of "usage" in this case.
>
> > +Below is a list of expansions for which abbrevs are defined, and
> > +the number of times the expansion was typed manually. To display
>                                                        ^^
> Two spaces between sentences, please.
>
> Finally, I think these new features should be in NEWS and probably
> also in the user manual.
>
> Thank you for working on this.
>

[-- Attachment #2: Type: text/html, Size: 10496 bytes --]

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

* Re: [PATCH] Add abbrev suggestions
  2020-08-11 22:16       ` Mathias Dahl
@ 2020-08-13 13:59         ` Eli Zaretskii
  2020-08-13 14:29           ` Mathias Dahl
  0 siblings, 1 reply; 19+ messages in thread
From: Eli Zaretskii @ 2020-08-13 13:59 UTC (permalink / raw)
  To: Mathias Dahl; +Cc: emacs-devel

> From: Mathias Dahl <mathias.dahl@gmail.com>
> Date: Wed, 12 Aug 2020 00:16:33 +0200
> Cc: emacs-devel@gnu.org
> 
> > Are you sure it is a good idea to make this non-nil by default?
> > Wouldn't some users consider these suggestions an annoyance?
> 
> No, I'm not. In fact, it was not the default when I started working on
> this, but Stefan suggested that it might be a good default. Now we're
> me and you against him, I guess... :)

Let's start with having it opt-in.  We can later see if it is popular
enough to become the default.

> > > +(defun abbrev--suggest-above-threshold (expansion)
> > > +    "Return t if we are above the threshold.
> > 
> > Who is "we" in this context?  This should be explained.
> 
> I know, I was not happy when I wrote that. "we", here, is something
> like "the difference in length between what the user typed and the
> abbrev that we found." I guess I could not find a good way to keep the
> first sentence of the docstring short, so I opted for the fuzzy "we"
> expression...

How about the below?

  Return non-nil if an abbrev in EXPANSION provides significant savings.

> > > +EXPANSION is a cons cell where the car is the expansion and the
> > > +cdr is the abbrev."
> > 
> > Our style is to include the arguments in the first sentence of the doc
> > string.
> 
> I know. Frankly I don't know if I can come up with a suggestion that
> combines that together with having a relatively short first
> sentence...

See above.

> Should I include those changes in the same patch and resend
> that when done?

Yes, please.



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

* Re: [PATCH] Add abbrev suggestions
  2020-08-13 13:59         ` Eli Zaretskii
@ 2020-08-13 14:29           ` Mathias Dahl
  2020-09-14 22:04             ` Mathias Dahl
  0 siblings, 1 reply; 19+ messages in thread
From: Mathias Dahl @ 2020-08-13 14:29 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

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

> > No, I'm not. In fact, it was not the default when I started
> > working on this, but Stefan suggested that it might be a good
> > default. Now we're me and you against him, I guess... :)

> Let's start with having it opt-in.  We can later see if it is
> popular enough to become the default.

Fine by me.

> How about the below?

> Return non-nil if an abbrev in EXPANSION provides significant
> savings.

Hey, that's cheating! :)

I prepared a new version myself too. Will see which one I select when
I send a new patch...

> > Should I include those changes in the same patch and resend
> > that when done?

> Yes, please.

Alrighty then!

Thanks!

/Mathias


On Thu, Aug 13, 2020 at 3:59 PM Eli Zaretskii <eliz@gnu.org> wrote:

> > From: Mathias Dahl <mathias.dahl@gmail.com>
> > Date: Wed, 12 Aug 2020 00:16:33 +0200
> > Cc: emacs-devel@gnu.org
> >
> > > Are you sure it is a good idea to make this non-nil by default?
> > > Wouldn't some users consider these suggestions an annoyance?
> >
> > No, I'm not. In fact, it was not the default when I started working on
> > this, but Stefan suggested that it might be a good default. Now we're
> > me and you against him, I guess... :)
>
> Let's start with having it opt-in.  We can later see if it is popular
> enough to become the default.
>
> > > > +(defun abbrev--suggest-above-threshold (expansion)
> > > > +    "Return t if we are above the threshold.
> > >
> > > Who is "we" in this context?  This should be explained.
> >
> > I know, I was not happy when I wrote that. "we", here, is something
> > like "the difference in length between what the user typed and the
> > abbrev that we found." I guess I could not find a good way to keep the
> > first sentence of the docstring short, so I opted for the fuzzy "we"
> > expression...
>
> How about the below?
>
>   Return non-nil if an abbrev in EXPANSION provides significant savings.
>
> > > > +EXPANSION is a cons cell where the car is the expansion and the
> > > > +cdr is the abbrev."
> > >
> > > Our style is to include the arguments in the first sentence of the doc
> > > string.
> >
> > I know. Frankly I don't know if I can come up with a suggestion that
> > combines that together with having a relatively short first
> > sentence...
>
> See above.
>
> > Should I include those changes in the same patch and resend
> > that when done?
>
> Yes, please.
>

[-- Attachment #2: Type: text/html, Size: 3294 bytes --]

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

* Re: [PATCH] Add abbrev suggestions
  2020-08-13 14:29           ` Mathias Dahl
@ 2020-09-14 22:04             ` Mathias Dahl
  2020-09-15  6:20               ` Andreas Röhler
  2020-09-15  8:16               ` Robert Pluim
  0 siblings, 2 replies; 19+ messages in thread
From: Mathias Dahl @ 2020-09-14 22:04 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel


[-- Attachment #1.1: Type: text/plain, Size: 2767 bytes --]

Hi Eli,

Finally! I sat down and documented this, updated NEWS as well as tried
to format the commit message in the correct manner. Let me know how
the new patch looks like.

Keeping my fingers crossed...

/Mathias


On Thu, Aug 13, 2020 at 4:29 PM Mathias Dahl <mathias.dahl@gmail.com> wrote:

> > > No, I'm not. In fact, it was not the default when I started
> > > working on this, but Stefan suggested that it might be a good
> > > default. Now we're me and you against him, I guess... :)
>
> > Let's start with having it opt-in.  We can later see if it is
> > popular enough to become the default.
>
> Fine by me.
>
> > How about the below?
>
> > Return non-nil if an abbrev in EXPANSION provides significant
> > savings.
>
> Hey, that's cheating! :)
>
> I prepared a new version myself too. Will see which one I select when
> I send a new patch...
>
> > > Should I include those changes in the same patch and resend
> > > that when done?
>
> > Yes, please.
>
> Alrighty then!
>
> Thanks!
>
> /Mathias
>
>
> On Thu, Aug 13, 2020 at 3:59 PM Eli Zaretskii <eliz@gnu.org> wrote:
>
>> > From: Mathias Dahl <mathias.dahl@gmail.com>
>> > Date: Wed, 12 Aug 2020 00:16:33 +0200
>> > Cc: emacs-devel@gnu.org
>> >
>> > > Are you sure it is a good idea to make this non-nil by default?
>> > > Wouldn't some users consider these suggestions an annoyance?
>> >
>> > No, I'm not. In fact, it was not the default when I started working on
>> > this, but Stefan suggested that it might be a good default. Now we're
>> > me and you against him, I guess... :)
>>
>> Let's start with having it opt-in.  We can later see if it is popular
>> enough to become the default.
>>
>> > > > +(defun abbrev--suggest-above-threshold (expansion)
>> > > > +    "Return t if we are above the threshold.
>> > >
>> > > Who is "we" in this context?  This should be explained.
>> >
>> > I know, I was not happy when I wrote that. "we", here, is something
>> > like "the difference in length between what the user typed and the
>> > abbrev that we found." I guess I could not find a good way to keep the
>> > first sentence of the docstring short, so I opted for the fuzzy "we"
>> > expression...
>>
>> How about the below?
>>
>>   Return non-nil if an abbrev in EXPANSION provides significant savings.
>>
>> > > > +EXPANSION is a cons cell where the car is the expansion and the
>> > > > +cdr is the abbrev."
>> > >
>> > > Our style is to include the arguments in the first sentence of the doc
>> > > string.
>> >
>> > I know. Frankly I don't know if I can come up with a suggestion that
>> > combines that together with having a relatively short first
>> > sentence...
>>
>> See above.
>>
>> > Should I include those changes in the same patch and resend
>> > that when done?
>>
>> Yes, please.
>>
>

[-- Attachment #1.2: Type: text/html, Size: 3994 bytes --]

[-- Attachment #2: 0001-Add-abbrev-suggestions-take-two.patch --]
[-- Type: application/octet-stream, Size: 10710 bytes --]

From b0b1bb04098a11e7f6c5fffbcbf7cd30be4679e0 Mon Sep 17 00:00:00 2001
From: Mathias Dahl <mathias.dahl@gmail.com>
Date: Mon, 14 Sep 2020 17:05:11 -0400
Subject: [PATCH] Add abbrev suggestions

    Add abbrev suggestions

    * lisp/abbrev.el (abbrev-suggest): New defcustom.
    (abbrev-suggest-hint-threshold): New defcustom.
    (abbrev--suggest-get-active-tables-including-parents): New defun.
    (abbrev--suggest-get-active-abbrev-expansions): New defun.
    (abbrev--suggest-count-words): New defun.
    (abbrev--suggest-get-previous-words): New defun.
    (abbrev--suggest-above-threshold): New defun.
    (abbrev--suggest-saved-recommendations): New defvar.
    (abbrev--suggest-inform-user): New defun.
    (abbrev--suggest-shortest-abbrev): New defun.
    (abbrev--suggest-maybe-suggest): New defun.
    (abbrev--suggest-get-totals): New defun.
    (abbrev-suggest-show-report): New defun.
    (expand-abbrev): If the previous word was not an abbrev, maybe
    suggest an abbrev to the user.
    * doc/emacs/abbrevs.texi (Abbrev suggestions): New section.
    * etc/NEWS: Announce abbrev suggestions.
---
 doc/emacs/abbrevs.texi |  33 ++++++++++++
 etc/NEWS               |   8 +++
 lisp/abbrev.el         | 143 ++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 183 insertions(+), 1 deletion(-)

diff --git a/doc/emacs/abbrevs.texi b/doc/emacs/abbrevs.texi
index 21bf8c5..fbe7117 100644
--- a/doc/emacs/abbrevs.texi
+++ b/doc/emacs/abbrevs.texi
@@ -28,6 +28,7 @@ Abbrevs
 * Abbrev Concepts::   Fundamentals of defined abbrevs.
 * Defining Abbrevs::  Defining an abbrev, so it will expand when typed.
 * Expanding Abbrevs:: Controlling expansion: prefixes, canceling expansion.
+* Abbrevs Suggestions:: Get suggestions about defined abbrevs.
 * Editing Abbrevs::   Viewing or editing the entire list of defined abbrevs.
 * Saving Abbrevs::    Saving the entire list of abbrevs for another session.
 * Dynamic Abbrevs::   Abbreviations for words already in the buffer.
@@ -223,6 +224,38 @@ Expanding Abbrevs
 the abbrev expansion.  @xref{Abbrev Expansion,,, elisp, The Emacs Lisp
 Reference Manual}.
 
+@node Abbrev Suggestions
+@section Abbrev Suggestions
+
+  You can get abbrev suggestions when you manually type text for which
+there is currently an active defined abbrev.  For example, if there is
+an abbrev @samp{foo} with the expansion @samp{find outer otter}, and
+you manually type @samp{find outer otter}, the abbrev suggestion
+feature will notice this and show a hint in the echo when you have
+stop typing.
+
+@vindex abbrev-suggest
+  Enable the abbrev suggestion feature by setting the variable
+@code{abbrev-suggest} to @code{t}.
+
+@vindex abbrev-suggest-hint-threshold
+  The variable @code{abbrev-suggest-hint-threshold} controls when to
+suggest an abbrev to the user.  The variable defines the number of
+characters that the user must save in order to get a suggestion.  For
+example, if the user types @samp{foo bar} (seven characters) and there
+is an abbrev @samp{fubar} defined (five characters), the user will not
+get any suggestion unless the threshold is set to the number 2 or
+lower.  With the default value 3, the user would not get any
+suggestion, because the savings in using the abbrev are too small, not
+above the threshold.  If you always want to get abbrev suggestions,
+set this variable to 0.
+
+@findex abbrev-suggest-show-report
+  The command @code{abbrev-suggest-show-report} can be used to show a
+buffer with all abbrev suggestions from the current editing session.
+This can be useful if you get several abbrev suggestions and don't
+remember them all.
+
 @node Editing Abbrevs
 @section Examining and Editing Abbrevs
 
diff --git a/etc/NEWS b/etc/NEWS
index 4076630..b4dc52a 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1158,6 +1158,14 @@ messages, contain the error name of that message now.  They can be
 made visible by setting user variable 'dbus-show-dbus-errors' to
 non-nil, even if protected by 'dbus-ignore-errors' otherwise.
 
+** Abbrev mode
+
++++
+*** A new user option, 'abbrev-suggest', enables the new abbrev
+suggestion feature.  When enabled, if a user manually type a piece of
+text that could have been written by using an abbrev, a hint will be
+displayed mentioning the abbrev that could have been used instead.
+
 \f
 * New Modes and Packages in Emacs 28.1
 
diff --git a/lisp/abbrev.el b/lisp/abbrev.el
index be6f9ee..a249dc0 100644
--- a/lisp/abbrev.el
+++ b/lisp/abbrev.el
@@ -824,6 +824,145 @@ abbrev-expand-function
   "Function that `expand-abbrev' uses to perform abbrev expansion.
 Takes no argument and should return the abbrev symbol if expansion took place.")
 
+(defcustom abbrev-suggest nil
+  "Non-nil means suggest abbrevs to the user.
+By enabling this option, if abbrev mode is enabled and if the
+user has typed some text that exists as an abbrev, suggest to the
+user to use the abbrev instead."
+    :type 'boolean
+    :group 'abbrev-mode
+    :version "28.0")
+
+(defcustom abbrev-suggest-hint-threshold 3
+  "Threshold for when to inform the user that there is an abbrev.
+The threshold is the number of characters that differ between the
+length of the abbrev and the length of the expansion.  The
+thinking is that if the expansion is only one or a few characters
+longer than the abbrev, the benefit of informing the user is not
+that big.  If you always want to be informed, set this value to
+`0' or less.  This setting only applies if `abbrev-suggest' is
+non-nil."
+    :type 'number
+    :group 'abbrev-mode
+    :version "28.0")
+
+(defun abbrev--suggest-get-active-tables-including-parents ()
+  "Return a list of all active abbrev tables, including parent tables."
+  (let* ((tables (abbrev--active-tables))
+	 (all tables))
+    (dolist (table tables)
+      (setq all (append (abbrev-table-get table :parents) all)))
+    all))
+
+(defun abbrev--suggest-get-active-abbrev-expansions ()
+  "Return a list of all the active abbrev expansions.
+Includes expansions from parent abbrev tables."
+    (let (expansions)
+      (dolist (table (abbrev--suggest-get-active-tables-including-parents))
+	(mapatoms (lambda (e)
+		    (let ((value (symbol-value (abbrev--symbol e table))))
+		      (when value
+                        (push (cons value (symbol-name e)) expansions))))
+		  table))
+      expansions))
+
+(defun abbrev--suggest-count-words (expansion)
+  "Return the number of words in EXPANSION.
+Expansion is a string of one or more words."
+    (length (split-string expansion " " t)))
+
+(defun abbrev--suggest-get-previous-words (n)
+  "Return the N words before point, spaces included.
+Changes newlines into spaces."
+    (let ((end (point)))
+      (save-excursion
+	(backward-word n)
+	(replace-regexp-in-string
+	 "\\s " " "
+	 (buffer-substring-no-properties (point) end)))))
+
+(defun abbrev--suggest-above-threshold (expansion)
+  "Return non-nil if an abbrev in EXPANSION provides significant savings.
+A significant saving, here, is the difference in length between
+the abbrev and the abbrev expansion.  EXPANSION is a cons cell
+where the car is the expansion and the cdr is the abbrev."
+    (>= (- (length (car expansion))
+	   (length (cdr expansion)))
+	abbrev-suggest-hint-threshold))
+
+(defvar abbrev--suggest-saved-recommendations nil
+    "Keeps a list of expansions that have abbrevs defined.
+The user can show this list by calling
+`abbrev-suggest-show-report'.")
+
+(defun abbrev--suggest-inform-user (expansion)
+    "Display a message to the user about the existing abbrev.
+EXPANSION is a cons cell where the `car' is the expansion and the
+`cdr' is the abbrev."
+    (run-with-idle-timer
+     1 nil
+     (lambda ()
+       (message "You can write `%s' using the abbrev `%s'."
+                                   (car expansion) (cdr expansion))))
+    (push expansion abbrev--suggest-saved-recommendations))
+
+(defun abbrev--suggest-shortest-abbrev (new current)
+    "Return the shortest abbrev of NEW and CURRENT.
+NEW and CURRENT are cons cells where the `car' is the expansion
+and the `cdr' is the abbrev."
+    (if (not current)
+	new
+      (if (< (length (cdr new))
+	     (length (cdr current)))
+	  new
+	current)))
+
+(defun abbrev--suggest-maybe-suggest ()
+    "Suggest an abbrev to the user based on the word(s) before point.
+Uses `abbrev-suggest-hint-threshold' to find out if the user should be
+informed about the existing abbrev."
+    (let (words abbrev-found word-count)
+      (dolist (expansion (abbrev--suggest-get-active-abbrev-expansions))
+	(setq word-count (abbrev--suggest-count-words (car expansion))
+	      words (abbrev--suggest-get-previous-words word-count))
+	(let ((case-fold-search t))
+	  (when (and (> word-count 0)
+		     (string-match (car expansion) words)
+		     (abbrev--suggest-above-threshold expansion))
+	    (setq abbrev-found (abbrev--suggest-shortest-abbrev
+				expansion abbrev-found)))))
+      (when abbrev-found
+	(abbrev--suggest-inform-user abbrev-found))))
+
+(defun abbrev--suggest-get-totals ()
+    "Return a list of all expansions and how many times they were used.
+Each expansion is a cons cell where the `car' is the expansion
+and the `cdr' is the number of times the expansion has been
+typed."
+    (let (total cell)
+      (dolist (expansion abbrev--suggest-saved-recommendations)
+	(if (not (assoc (car expansion) total))
+	    (push (cons (car expansion) 1) total)
+	  (setq cell (assoc (car expansion) total))
+	  (setcdr cell (1+ (cdr cell)))))
+      total))
+
+(defun abbrev-suggest-show-report ()
+  "Show the user a report of abbrevs he could have used."
+  (interactive)
+  (let ((totals (abbrev--suggest-get-totals))
+	(buf (get-buffer-create "*abbrev-suggest*")))
+    (set-buffer buf)
+    (erase-buffer)
+        (insert "** Abbrev expansion usage **
+
+Below is a list of expansions for which abbrevs are defined, and
+the number of times the expansion was typed manually.  To display
+and edit all abbrevs, type `M-x edit-abbrevs RET'\n\n")
+	(dolist (expansion totals)
+	  (insert (format " %s: %d\n" (car expansion) (cdr expansion))))
+	(display-buffer buf)))
+
 (defun expand-abbrev ()
   "Expand the abbrev before point, if there is an abbrev there.
 Effective when explicitly called even when `abbrev-mode' is nil.
@@ -831,7 +970,9 @@ expand-abbrev
 the work, and returns whatever it does.  (That return value should
 be the abbrev symbol if expansion occurred, else nil.)"
   (interactive)
-  (funcall abbrev-expand-function))
+  (or (funcall abbrev-expand-function)
+      (if abbrev-suggest
+          (abbrev--suggest-maybe-suggest))))
 
 (defun abbrev--default-expand ()
   "Default function to use for `abbrev-expand-function'.
-- 
1.9.1


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

* Re: [PATCH] Add abbrev suggestions
  2020-09-14 22:04             ` Mathias Dahl
@ 2020-09-15  6:20               ` Andreas Röhler
  2020-09-18  8:39                 ` Mathias Dahl
  2020-09-15  8:16               ` Robert Pluim
  1 sibling, 1 reply; 19+ messages in thread
From: Andreas Röhler @ 2020-09-15  6:20 UTC (permalink / raw)
  To: emacs-devel


On 15.09.20 00:04, Mathias Dahl wrote:


FWIW wrote such a thing years ago but finally don't use it. The reason: 
in case an abbrev is forgotten, rather store a new one easier the 
remember than learning the old one.

No need to learn abbrevs...

OTOH in daily use is a suggestion of abbrevs to define:


(defun mode-abbrev-propose (arg)
   "Defines mode-specific abbrev for last word(s) before point.
Argument is how many words before point form the expansion;
...

Cheers,

Andreas




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

* Re: [PATCH] Add abbrev suggestions
  2020-09-14 22:04             ` Mathias Dahl
  2020-09-15  6:20               ` Andreas Röhler
@ 2020-09-15  8:16               ` Robert Pluim
  2020-09-18  8:40                 ` Mathias Dahl
  1 sibling, 1 reply; 19+ messages in thread
From: Robert Pluim @ 2020-09-15  8:16 UTC (permalink / raw)
  To: Mathias Dahl; +Cc: Eli Zaretskii, emacs-devel

>>>>> On Tue, 15 Sep 2020 00:04:05 +0200, Mathias Dahl <mathias.dahl@gmail.com> said:

    Mathias> Hi Eli,
    Mathias> Finally! I sat down and documented this, updated NEWS as well as tried
    Mathias> to format the commit message in the correct manner. Let me know how
    Mathias> the new patch looks like.

    Mathias> Keeping my fingers crossed...

Nitpicking below. Nothing major, it looks to be a useful feature.

    Mathias> From b0b1bb04098a11e7f6c5fffbcbf7cd30be4679e0 Mon Sep 17 00:00:00 2001
    Mathias> From: Mathias Dahl <mathias.dahl@gmail.com>
    Mathias> Date: Mon, 14 Sep 2020 17:05:11 -0400
    Mathias> Subject: [PATCH] Add abbrev suggestions

    Mathias>     Add abbrev suggestions

Youʼre allowed to be a little bit more verbose in the commit messages
:-) Tell us briefly what this does.

    Mathias>     * lisp/abbrev.el (abbrev-suggest): New defcustom.
    Mathias>     (abbrev-suggest-hint-threshold): New defcustom.
    Mathias>     (abbrev--suggest-get-active-tables-including-parents): New defun.
    Mathias>     (abbrev--suggest-get-active-abbrev-expansions): New defun.
    Mathias>     (abbrev--suggest-count-words): New defun.
    Mathias>     (abbrev--suggest-get-previous-words): New defun.
    Mathias>     (abbrev--suggest-above-threshold): New defun.
    Mathias>     (abbrev--suggest-saved-recommendations): New defvar.
    Mathias>     (abbrev--suggest-inform-user): New defun.
    Mathias>     (abbrev--suggest-shortest-abbrev): New defun.
    Mathias>     (abbrev--suggest-maybe-suggest): New defun.
    Mathias>     (abbrev--suggest-get-totals): New defun.
    Mathias>     (abbrev-suggest-show-report): New defun.
    Mathias>     (expand-abbrev): If the previous word was not an abbrev, maybe
    Mathias>     suggest an abbrev to the user.
    Mathias>     * doc/emacs/abbrevs.texi (Abbrev suggestions): New section.
    Mathias>     * etc/NEWS: Announce abbrev suggestions.
    Mathias> ---
    Mathias>  doc/emacs/abbrevs.texi |  33 ++++++++++++
    Mathias>  etc/NEWS               |   8 +++
    Mathias>  lisp/abbrev.el         | 143 ++++++++++++++++++++++++++++++++++++++++++++++++-
    Mathias>  3 files changed, 183 insertions(+), 1 deletion(-)

    Mathias> diff --git a/doc/emacs/abbrevs.texi b/doc/emacs/abbrevs.texi
    Mathias> index 21bf8c5..fbe7117 100644
    Mathias> --- a/doc/emacs/abbrevs.texi
    Mathias> +++ b/doc/emacs/abbrevs.texi
    Mathias> @@ -28,6 +28,7 @@ Abbrevs
    Mathias>  * Abbrev Concepts::   Fundamentals of defined abbrevs.
    Mathias>  * Defining Abbrevs::  Defining an abbrev, so it will expand when typed.
    Mathias>  * Expanding Abbrevs:: Controlling expansion: prefixes, canceling expansion.
    Mathias> +* Abbrevs Suggestions:: Get suggestions about defined abbrevs.
    Mathias>  * Editing Abbrevs::   Viewing or editing the entire list of defined abbrevs.
    Mathias>  * Saving Abbrevs::    Saving the entire list of abbrevs for another session.
    Mathias>  * Dynamic Abbrevs::   Abbreviations for words already in the buffer.
    Mathias> @@ -223,6 +224,38 @@ Expanding Abbrevs
    Mathias>  the abbrev expansion.  @xref{Abbrev Expansion,,, elisp, The Emacs Lisp
    Mathias>  Reference Manual}.
 
    Mathias> +@node Abbrev Suggestions
    Mathias> +@section Abbrev Suggestions
    Mathias> +
    Mathias> +  You can get abbrev suggestions when you manually type text for which
    Mathias> +there is currently an active defined abbrev.  For example, if there is
    Mathias> +an abbrev @samp{foo} with the expansion @samp{find outer otter}, and
    Mathias> +you manually type @samp{find outer otter}, the abbrev suggestion
    Mathias> +feature will notice this and show a hint in the echo when you have
    Mathias> +stop typing.

Either "when you stop" or "when you have stopped"

    Mathias> +
    Mathias> +@vindex abbrev-suggest
    Mathias> +  Enable the abbrev suggestion feature by setting the variable

You donʼt need "the variable" here.

    Mathias> +@code{abbrev-suggest} to @code{t}.
    Mathias> +
    Mathias> +@vindex abbrev-suggest-hint-threshold
    Mathias> +  The variable @code{abbrev-suggest-hint-threshold} controls when to

Nor here. Or call it a "user option" (I assume itʼs customizable)

    Mathias> +suggest an abbrev to the user.  The variable defines the number of
    Mathias> +characters that the user must save in order to get a suggestion.  For
    Mathias> +example, if the user types @samp{foo bar} (seven characters) and there
    Mathias> +is an abbrev @samp{fubar} defined (five characters), the user will not
    Mathias> +get any suggestion unless the threshold is set to the number 2 or
    Mathias> +lower.  With the default value 3, the user would not get any
    Mathias> +suggestion, because the savings in using the abbrev are too small, not

Iʼd drop the "too small,"

    Mathias> +above the threshold.  If you always want to get abbrev suggestions,
    Mathias> +set this variable to 0.
    Mathias> +
    Mathias> +@findex abbrev-suggest-show-report
    Mathias> +  The command @code{abbrev-suggest-show-report} can be used to show a
    Mathias> +buffer with all abbrev suggestions from the current editing session.
    Mathias> +This can be useful if you get several abbrev suggestions and don't
    Mathias> +remember them all.
    Mathias> +
    Mathias>  @node Editing Abbrevs
    Mathias>  @section Examining and Editing Abbrevs
 
    Mathias> diff --git a/etc/NEWS b/etc/NEWS
    Mathias> index 4076630..b4dc52a 100644
    Mathias> --- a/etc/NEWS
    Mathias> +++ b/etc/NEWS
    Mathias> @@ -1158,6 +1158,14 @@ messages, contain the error name of that message now.  They can be
    Mathias>  made visible by setting user variable 'dbus-show-dbus-errors' to
    Mathias>  non-nil, even if protected by 'dbus-ignore-errors' otherwise.
 
    Mathias> +** Abbrev mode
    Mathias> +
    Mathias> ++++
    Mathias> +*** A new user option, 'abbrev-suggest', enables the new abbrev
    Mathias> +suggestion feature.  When enabled, if a user manually type a piece of
    Mathias> +text that could have been written by using an abbrev, a hint will be
    Mathias> +displayed mentioning the abbrev that could have been used instead.
    Mathias> +

The first line should be a complete sentence, with details below, so:

"Abbrev can now suggest pre-existing abbreviations based on typed text."

    Mathias>  \f
    Mathias>  * New Modes and Packages in Emacs 28.1
 
    Mathias> diff --git a/lisp/abbrev.el b/lisp/abbrev.el
    Mathias> index be6f9ee..a249dc0 100644
    Mathias> --- a/lisp/abbrev.el
    Mathias> +++ b/lisp/abbrev.el
    Mathias> @@ -824,6 +824,145 @@ abbrev-expand-function
    Mathias>    "Function that `expand-abbrev' uses to perform abbrev expansion.
    Mathias>  Takes no argument and should return the abbrev symbol if expansion took place.")
 
    Mathias> +(defcustom abbrev-suggest nil
    Mathias> +  "Non-nil means suggest abbrevs to the user.
    Mathias> +By enabling this option, if abbrev mode is enabled and if the
    Mathias> +user has typed some text that exists as an abbrev, suggest to the
    Mathias> +user to use the abbrev instead."

How is the suggestion displayed? Echo area, popup frame....?

    Mathias> +    :type 'boolean
    Mathias> +    :group 'abbrev-mode
    Mathias> +    :version "28.0")

"28.1"

    Mathias> +
    Mathias> +(defcustom abbrev-suggest-hint-threshold 3
    Mathias> +  "Threshold for when to inform the user that there is an abbrev.
    Mathias> +The threshold is the number of characters that differ between the
    Mathias> +length of the abbrev and the length of the expansion.  The
    Mathias> +thinking is that if the expansion is only one or a few characters
    Mathias> +longer than the abbrev, the benefit of informing the user is not
    Mathias> +that big.  If you always want to be informed, set this value to
    Mathias> +`0' or less.  This setting only applies if `abbrev-suggest' is
    Mathias> +non-nil."
    Mathias> +    :type 'number
    Mathias> +    :group 'abbrev-mode
    Mathias> +    :version "28.0")

And again. Plus the :group is derived from the last seen 'defgroup',
so itʼs optional here.

    Mathias> +
    Mathias> +(defun abbrev--suggest-get-active-tables-including-parents ()
    Mathias> +  "Return a list of all active abbrev tables, including parent tables."
    Mathias> +  (let* ((tables (abbrev--active-tables))
    Mathias> +	 (all tables))

You've got indent-tabs-mode set to t, even though our .dir-locals.el
sets it to nil for elisp.

    Mathias> +    (dolist (table tables)
    Mathias> +      (setq all (append (abbrev-table-get table :parents) all)))
    Mathias> +    all))
    Mathias> +
    Mathias> +(defun abbrev--suggest-get-active-abbrev-expansions ()
    Mathias> +  "Return a list of all the active abbrev expansions.
    Mathias> +Includes expansions from parent abbrev tables."
    Mathias> +    (let (expansions)
    Mathias> +      (dolist (table (abbrev--suggest-get-active-tables-including-parents))
    Mathias> +	(mapatoms (lambda (e)
    Mathias> +		    (let ((value (symbol-value (abbrev--symbol e table))))
    Mathias> +		      (when value
    Mathias> +                        (push (cons value (symbol-name e)) expansions))))
    Mathias> +		  table))
    Mathias> +      expansions))
    Mathias> +
    Mathias> +(defun abbrev--suggest-count-words (expansion)
    Mathias> +  "Return the number of words in EXPANSION.
    Mathias> +Expansion is a string of one or more words."
    Mathias> +    (length (split-string expansion " " t)))
    Mathias> +
    Mathias> +(defun abbrev--suggest-get-previous-words (n)
    Mathias> +  "Return the N words before point, spaces included.
    Mathias> +Changes newlines into spaces."

Well, anything with whitespace syntax. Iʼm not sure you need to
mention that.

    Mathias> +    (let ((end (point)))
    Mathias> +      (save-excursion
    Mathias> +	(backward-word n)
    Mathias> +	(replace-regexp-in-string
    Mathias> +	 "\\s " " "
    Mathias> +	 (buffer-substring-no-properties (point) end)))))
    Mathias> +
    Mathias> +(defun abbrev--suggest-above-threshold (expansion)
    Mathias> +  "Return non-nil if an abbrev in EXPANSION provides significant savings.

"the abbrev", no? I think EXPANSION only contains one abbrev.

    Mathias> +A significant saving, here, is the difference in length between
    Mathias> +the abbrev and the abbrev expansion.  EXPANSION is a cons cell
    Mathias> +where the car is the expansion and the cdr is the abbrev."
    Mathias> +    (>= (- (length (car expansion))
    Mathias> +	   (length (cdr expansion)))
    Mathias> +	abbrev-suggest-hint-threshold))
    Mathias> +
    Mathias> +(defvar abbrev--suggest-saved-recommendations nil
    Mathias> +    "Keeps a list of expansions that have abbrevs defined.
    Mathias> +The user can show this list by calling
    Mathias> +`abbrev-suggest-show-report'.")
    Mathias> +
    Mathias> +(defun abbrev--suggest-inform-user (expansion)
    Mathias> +    "Display a message to the user about the existing abbrev.
    Mathias> +EXPANSION is a cons cell where the `car' is the expansion and the
    Mathias> +`cdr' is the abbrev."
    Mathias> +    (run-with-idle-timer
    Mathias> +     1 nil
    Mathias> +     (lambda ()
    Mathias> +       (message "You can write `%s' using the abbrev `%s'."
    Mathias> +                                   (car expansion) (cdr expansion))))

Iʼd put the abbrev first, and the expansion second. "abbrev `%s' can
be used to write `%s'."

    Mathias> +    (push expansion abbrev--suggest-saved-recommendations))
    Mathias> +
    Mathias> +(defun abbrev--suggest-shortest-abbrev (new current)
    Mathias> +    "Return the shortest abbrev of NEW and CURRENT.
    Mathias> +NEW and CURRENT are cons cells where the `car' is the expansion
    Mathias> +and the `cdr' is the abbrev."
    Mathias> +    (if (not current)
    Mathias> +	new
    Mathias> +      (if (< (length (cdr new))
    Mathias> +	     (length (cdr current)))
    Mathias> +	  new
    Mathias> +	current)))
    Mathias> +
    Mathias> +(defun abbrev--suggest-maybe-suggest ()
    Mathias> +    "Suggest an abbrev to the user based on the word(s) before point.
    Mathias> +Uses `abbrev-suggest-hint-threshold' to find out if the user should be
    Mathias> +informed about the existing abbrev."
    Mathias> +    (let (words abbrev-found word-count)
    Mathias> +      (dolist (expansion (abbrev--suggest-get-active-abbrev-expansions))
    Mathias> +	(setq word-count (abbrev--suggest-count-words (car expansion))
    Mathias> +	      words (abbrev--suggest-get-previous-words word-count))
    Mathias> +	(let ((case-fold-search t))
    Mathias> +	  (when (and (> word-count 0)

Personally Iʼm allergic to "(when (and", but opinions differ :-)

    Mathias> +		     (string-match (car expansion) words)
    Mathias> +		     (abbrev--suggest-above-threshold expansion))
    Mathias> +	    (setq abbrev-found (abbrev--suggest-shortest-abbrev
    Mathias> +				expansion abbrev-found)))))
    Mathias> +      (when abbrev-found
    Mathias> +	(abbrev--suggest-inform-user abbrev-found))))
    Mathias> +
    Mathias> +(defun abbrev--suggest-get-totals ()
    Mathias> +    "Return a list of all expansions and how many times they were used.
    Mathias> +Each expansion is a cons cell where the `car' is the expansion
    Mathias> +and the `cdr' is the number of times the expansion has been
    Mathias> +typed."
    Mathias> +    (let (total cell)
    Mathias> +      (dolist (expansion abbrev--suggest-saved-recommendations)
    Mathias> +	(if (not (assoc (car expansion) total))
    Mathias> +	    (push (cons (car expansion) 1) total)
    Mathias> +	  (setq cell (assoc (car expansion) total))
    Mathias> +	  (setcdr cell (1+ (cdr cell)))))
    Mathias> +      total))
    Mathias> +
    Mathias> +(defun abbrev-suggest-show-report ()
    Mathias> +  "Show the user a report of abbrevs he could have used."
    Mathias> +  (interactive)
    Mathias> +  (let ((totals (abbrev--suggest-get-totals))
    Mathias> +	(buf (get-buffer-create "*abbrev-suggest*")))
    Mathias> +    (set-buffer buf)
    Mathias> +    (erase-buffer)
    Mathias> +        (insert "** Abbrev expansion usage **
    Mathias> +
    Mathias> +Below is a list of expansions for which abbrevs are defined, and
    Mathias> +the number of times the expansion was typed manually.  To display
    Mathias> +and edit all abbrevs, type `M-x edit-abbrevs RET'\n\n")
    Mathias> +	(dolist (expansion totals)
    Mathias> +	  (insert (format " %s: %d\n" (car expansion) (cdr expansion))))
    Mathias> +	(display-buffer buf)))

`pop-to-buffer' rather than `set-buffer' + `display-buffer'?

    Mathias> +
    Mathias>  (defun expand-abbrev ()
    Mathias>    "Expand the abbrev before point, if there is an abbrev there.
    Mathias>  Effective when explicitly called even when `abbrev-mode' is nil.
    Mathias> @@ -831,7 +970,9 @@ expand-abbrev
    Mathias>  the work, and returns whatever it does.  (That return value should
    Mathias>  be the abbrev symbol if expansion occurred, else nil.)"
    Mathias>    (interactive)
    Mathias> -  (funcall abbrev-expand-function))
    Mathias> +  (or (funcall abbrev-expand-function)
    Mathias> +      (if abbrev-suggest
    Mathias> +          (abbrev--suggest-maybe-suggest))))
 
    Mathias>  (defun abbrev--default-expand ()
    Mathias>    "Default function to use for `abbrev-expand-function'.
    Mathias> -- 
    Mathias> 1.9.1





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

* Re: [PATCH] Add abbrev suggestions
  2020-09-15  6:20               ` Andreas Röhler
@ 2020-09-18  8:39                 ` Mathias Dahl
  0 siblings, 0 replies; 19+ messages in thread
From: Mathias Dahl @ 2020-09-18  8:39 UTC (permalink / raw)
  To: Andreas Röhler; +Cc: emacs-devel

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

On Tue, Sep 15, 2020 at 8:21 AM Andreas Röhler <andreas.roehler@online.de>
wrote:

>
> FWIW wrote such a thing years ago but finally don't use it. The reason:
> in case an abbrev is forgotten, rather store a new one easier the
> remember than learning the old one.
>

The problem I have is that I forget that I have abbrevs defined in the
first place, for things I type. My problem is not (primarily) that I
forget exactly what a specific abbrev is. Abbrev suggestions would
simply remind me to use the ones I have. Like every habit that you try
to create, it takes time and effort. This feature would help me with
that, I think.

[-- Attachment #2: Type: text/html, Size: 1027 bytes --]

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

* Re: [PATCH] Add abbrev suggestions
  2020-09-15  8:16               ` Robert Pluim
@ 2020-09-18  8:40                 ` Mathias Dahl
  2020-09-24 20:02                   ` Mathias Dahl
  0 siblings, 1 reply; 19+ messages in thread
From: Mathias Dahl @ 2020-09-18  8:40 UTC (permalink / raw)
  To: Robert Pluim; +Cc: Eli Zaretskii, emacs-devel

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

On Tue, Sep 15, 2020 at 10:16 AM Robert Pluim <rpluim@gmail.com> wrote:

> >>>>> On Tue, 15 Sep 2020 00:04:05 +0200, Mathias Dahl <
> mathias.dahl@gmail.com> said:
>
> Nitpicking below. Nothing major, it looks to be a useful feature.
>

Hi Robert, thanks for this! I will review your suggestions and incorporate
the ones I like :)

[-- Attachment #2: Type: text/html, Size: 766 bytes --]

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

* Re: [PATCH] Add abbrev suggestions
  2020-09-18  8:40                 ` Mathias Dahl
@ 2020-09-24 20:02                   ` Mathias Dahl
  2020-09-25  8:09                     ` Robert Pluim
  0 siblings, 1 reply; 19+ messages in thread
From: Mathias Dahl @ 2020-09-24 20:02 UTC (permalink / raw)
  To: Robert Pluim; +Cc: Eli Zaretskii, emacs-devel


[-- Attachment #1.1: Type: text/plain, Size: 808 bytes --]

On Fri, Sep 18, 2020 at 10:40 AM Mathias Dahl <mathias.dahl@gmail.com>
wrote:

>
> On Tue, Sep 15, 2020 at 10:16 AM Robert Pluim <rpluim@gmail.com> wrote:
>
>> >>>>> On Tue, 15 Sep 2020 00:04:05 +0200, Mathias Dahl <
>> mathias.dahl@gmail.com> said:
>>
>> Nitpicking below. Nothing major, it looks to be a useful feature.
>>
>
> Hi Robert, thanks for this! I will review your suggestions and incorporate
> the ones I like :)
>

Okay, so I finally got around doing this. I incorporated some of the
changes but not others. Since
it's mostly nitpicking, as you said Robert, it should be fine I think.

Eli, if this looks good, can we get this added to Emacs Git repo? If we
need small tweaks I
would rather want to add those separately instead of trying to get this
first patch 100%
correct.

Thanks!

/Mathias

[-- Attachment #1.2: Type: text/html, Size: 1633 bytes --]

[-- Attachment #2: 0001-Abbrev-suggestions.patch --]
[-- Type: application/octet-stream, Size: 10757 bytes --]

From 8adb089dfc52561dba703036c698c6e063976872 Mon Sep 17 00:00:00 2001
From: Mathias Dahl <mathias.dahl@gmail.com>
Date: Thu, 24 Sep 2020 15:06:23 -0400
Subject: [PATCH] Abbrev suggestions

    Add abbrev suggestions - Suggest to the user to use defined
    abbrevs instead of typing their expansion.

    * lisp/abbrev.el (abbrev-suggest): New defcustom.
    (abbrev-suggest-hint-threshold): New defcustom.
    (abbrev--suggest-get-active-tables-including-parents): New defun.
    (abbrev--suggest-get-active-abbrev-expansions): New defun.
    (abbrev--suggest-count-words): New defun.
    (abbrev--suggest-get-previous-words): New defun.
    (abbrev--suggest-above-threshold): New defun.
    (abbrev--suggest-saved-recommendations): New defvar.
    (abbrev--suggest-inform-user): New defun.
    (abbrev--suggest-shortest-abbrev): New defun.
    (abbrev--suggest-maybe-suggest): New defun.
    (abbrev--suggest-get-totals): New defun.
    (abbrev-suggest-show-report): New defun.
    (expand-abbrev): If the previous word was not an abbrev, maybe
    suggest an abbrev to the user.
    * doc/emacs/abbrevs.texi (Abbrev suggestions): New section.
    * etc/NEWS: Announce abbrev suggestions.

---
 doc/emacs/abbrevs.texi |  32 +++++++++++
 etc/NEWS               |  10 ++++
 lisp/abbrev.el         | 140 ++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 181 insertions(+), 1 deletion(-)

diff --git a/doc/emacs/abbrevs.texi b/doc/emacs/abbrevs.texi
index 21bf8c5..dfced88 100644
--- a/doc/emacs/abbrevs.texi
+++ b/doc/emacs/abbrevs.texi
@@ -28,6 +28,7 @@ Abbrevs
 * Abbrev Concepts::   Fundamentals of defined abbrevs.
 * Defining Abbrevs::  Defining an abbrev, so it will expand when typed.
 * Expanding Abbrevs:: Controlling expansion: prefixes, canceling expansion.
+* Abbrevs Suggestions:: Get suggestions about defined abbrevs.
 * Editing Abbrevs::   Viewing or editing the entire list of defined abbrevs.
 * Saving Abbrevs::    Saving the entire list of abbrevs for another session.
 * Dynamic Abbrevs::   Abbreviations for words already in the buffer.
@@ -223,6 +224,37 @@ Expanding Abbrevs
 the abbrev expansion.  @xref{Abbrev Expansion,,, elisp, The Emacs Lisp
 Reference Manual}.
 
+@node Abbrev Suggestions
+@section Abbrev Suggestions
+
+  You can get abbrev suggestions when you manually type text for which
+there is currently an active defined abbrev.  For example, if there is
+an abbrev @samp{foo} with the expansion @samp{find outer otter}, and
+you manually type @samp{find outer otter}, the abbrev suggestion
+feature will notice this and show a hint in the echo when you have
+stopped typing.
+
+@vindex abbrev-suggest
+  Enable the abbrev suggestion feature by setting
+@code{abbrev-suggest} to @code{t}.
+
+@vindex abbrev-suggest-hint-threshold
+  Controls when to suggest an abbrev to the user.  The variable
+defines the number of characters that the user must save in order to
+get a suggestion.  For example, if the user types @samp{foo bar}
+(seven characters) and there is an abbrev @samp{fubar} defined (five
+characters), the user will not get any suggestion unless the threshold
+is set to the number 2 or lower.  With the default value 3, the user
+would not get any suggestion, because the savings in using the abbrev
+are not above the threshold.  If you always want to get abbrev
+suggestions, set this variable to 0.
+
+@findex abbrev-suggest-show-report
+  The command @code{abbrev-suggest-show-report} can be used to show a
+buffer with all abbrev suggestions from the current editing session.
+This can be useful if you get several abbrev suggestions and don't
+remember them all.
+
 @node Editing Abbrevs
 @section Examining and Editing Abbrevs
 
diff --git a/etc/NEWS b/etc/NEWS
index 4076630..3e404c0 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1158,6 +1158,16 @@ messages, contain the error name of that message now.  They can be
 made visible by setting user variable 'dbus-show-dbus-errors' to
 non-nil, even if protected by 'dbus-ignore-errors' otherwise.
 
+** Abbrev mode
+
++++
+*** Abbrev can now suggest pre-existing abbrevs based on typed text.
+A new user option, 'abbrev-suggest', enables the new abbrev suggestion
+feature.  When enabled, if a user manually type a piece of text that
+could have been written by using an abbrev, a hint will be displayed
+in the echo area, mentioning the abbrev that could have been used
+instead.
+
 \f
 * New Modes and Packages in Emacs 28.1
 
diff --git a/lisp/abbrev.el b/lisp/abbrev.el
index be6f9ee..75cc439 100644
--- a/lisp/abbrev.el
+++ b/lisp/abbrev.el
@@ -824,6 +824,142 @@ abbrev-expand-function
   "Function that `expand-abbrev' uses to perform abbrev expansion.
 Takes no argument and should return the abbrev symbol if expansion took place.")
 
+(defcustom abbrev-suggest nil
+  "Non-nil means suggest abbrevs to the user.
+By enabling this option, if abbrev mode is enabled and if the
+user has typed some text that exists as an abbrev, suggest to the
+user to use the abbrev by displaying a message in the echo area."
+    :type 'boolean
+    :version "28.1")
+
+(defcustom abbrev-suggest-hint-threshold 3
+  "Threshold for when to inform the user that there is an abbrev.
+The threshold is the number of characters that differ between the
+length of the abbrev and the length of the expansion.  The
+thinking is that if the expansion is only one or a few characters
+longer than the abbrev, the benefit of informing the user is not
+that big.  If you always want to be informed, set this value to
+`0' or less.  This setting only applies if `abbrev-suggest' is
+non-nil."
+    :type 'number
+    :version "28.1")
+
+(defun abbrev--suggest-get-active-tables-including-parents ()
+  "Return a list of all active abbrev tables, including parent tables."
+  (let* ((tables (abbrev--active-tables))
+	 (all tables))
+    (dolist (table tables)
+      (setq all (append (abbrev-table-get table :parents) all)))
+    all))
+
+(defun abbrev--suggest-get-active-abbrev-expansions ()
+  "Return a list of all the active abbrev expansions.
+Includes expansions from parent abbrev tables."
+    (let (expansions)
+      (dolist (table (abbrev--suggest-get-active-tables-including-parents))
+	(mapatoms (lambda (e)
+		    (let ((value (symbol-value (abbrev--symbol e table))))
+		      (when value
+                        (push (cons value (symbol-name e)) expansions))))
+		  table))
+      expansions))
+
+(defun abbrev--suggest-count-words (expansion)
+  "Return the number of words in EXPANSION.
+Expansion is a string of one or more words."
+    (length (split-string expansion " " t)))
+
+(defun abbrev--suggest-get-previous-words (n)
+  "Return the N words before point, spaces included."
+    (let ((end (point)))
+      (save-excursion
+	(backward-word n)
+	(replace-regexp-in-string
+	 "\\s " " "
+	 (buffer-substring-no-properties (point) end)))))
+
+(defun abbrev--suggest-above-threshold (expansion)
+  "Return non-nil if the abbrev in EXPANSION provides significant savings.
+A significant saving, here, is the difference in length between
+the abbrev and the abbrev expansion.  EXPANSION is a cons cell
+where the car is the expansion and the cdr is the abbrev."
+    (>= (- (length (car expansion))
+	   (length (cdr expansion)))
+	abbrev-suggest-hint-threshold))
+
+(defvar abbrev--suggest-saved-recommendations nil
+    "Keeps a list of expansions that have abbrevs defined.
+The user can show this list by calling
+`abbrev-suggest-show-report'.")
+
+(defun abbrev--suggest-inform-user (expansion)
+    "Display a message to the user about the existing abbrev.
+EXPANSION is a cons cell where the `car' is the expansion and the
+`cdr' is the abbrev."
+    (run-with-idle-timer
+     1 nil
+     (lambda ()
+       (message "You can write `%s' using the abbrev `%s'."
+                                   (car expansion) (cdr expansion))))
+    (push expansion abbrev--suggest-saved-recommendations))
+
+(defun abbrev--suggest-shortest-abbrev (new current)
+    "Return the shortest abbrev of NEW and CURRENT.
+NEW and CURRENT are cons cells where the `car' is the expansion
+and the `cdr' is the abbrev."
+    (if (not current)
+	new
+      (if (< (length (cdr new))
+	     (length (cdr current)))
+	  new
+	current)))
+
+(defun abbrev--suggest-maybe-suggest ()
+    "Suggest an abbrev to the user based on the word(s) before point.
+Uses `abbrev-suggest-hint-threshold' to find out if the user should be
+informed about the existing abbrev."
+    (let (words abbrev-found word-count)
+      (dolist (expansion (abbrev--suggest-get-active-abbrev-expansions))
+	(setq word-count (abbrev--suggest-count-words (car expansion))
+	      words (abbrev--suggest-get-previous-words word-count))
+	(let ((case-fold-search t))
+	  (when (and (> word-count 0)
+		     (string-match (car expansion) words)
+		     (abbrev--suggest-above-threshold expansion))
+	    (setq abbrev-found (abbrev--suggest-shortest-abbrev
+				expansion abbrev-found)))))
+      (when abbrev-found
+	(abbrev--suggest-inform-user abbrev-found))))
+
+(defun abbrev--suggest-get-totals ()
+    "Return a list of all expansions and how many times they were used.
+Each expansion is a cons cell where the `car' is the expansion
+and the `cdr' is the number of times the expansion has been
+typed."
+    (let (total cell)
+      (dolist (expansion abbrev--suggest-saved-recommendations)
+	(if (not (assoc (car expansion) total))
+	    (push (cons (car expansion) 1) total)
+	  (setq cell (assoc (car expansion) total))
+	  (setcdr cell (1+ (cdr cell)))))
+      total))
+
+(defun abbrev-suggest-show-report ()
+  "Show the user a report of abbrevs he could have used."
+  (interactive)
+  (let ((totals (abbrev--suggest-get-totals))
+	(buf (get-buffer-create "*abbrev-suggest*")))
+    (set-buffer buf)
+    (erase-buffer)
+        (insert "** Abbrev expansion usage **
+
+Below is a list of expansions for which abbrevs are defined, and
+the number of times the expansion was typed manually.  To display
+and edit all abbrevs, type `M-x edit-abbrevs RET'\n\n")
+	(dolist (expansion totals)
+	  (insert (format " %s: %d\n" (car expansion) (cdr expansion))))
+	(display-buffer buf)))
+
 (defun expand-abbrev ()
   "Expand the abbrev before point, if there is an abbrev there.
 Effective when explicitly called even when `abbrev-mode' is nil.
@@ -831,7 +967,9 @@ expand-abbrev
 the work, and returns whatever it does.  (That return value should
 be the abbrev symbol if expansion occurred, else nil.)"
   (interactive)
-  (funcall abbrev-expand-function))
+  (or (funcall abbrev-expand-function)
+      (if abbrev-suggest
+          (abbrev--suggest-maybe-suggest))))
 
 (defun abbrev--default-expand ()
   "Default function to use for `abbrev-expand-function'.
-- 
1.9.1


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

* Re: [PATCH] Add abbrev suggestions
  2020-09-24 20:02                   ` Mathias Dahl
@ 2020-09-25  8:09                     ` Robert Pluim
  2020-09-25 20:42                       ` Mathias Dahl
  0 siblings, 1 reply; 19+ messages in thread
From: Robert Pluim @ 2020-09-25  8:09 UTC (permalink / raw)
  To: Mathias Dahl; +Cc: Eli Zaretskii, emacs-devel

>>>>> On Thu, 24 Sep 2020 22:02:08 +0200, Mathias Dahl <mathias.dahl@gmail.com> said:

    Mathias> Okay, so I finally got around doing this. I incorporated some of the
    Mathias> changes but not others. Since it's mostly nitpicking, as you said
    Mathias> Robert, it should be fine I think.

I have one more :-)

    Mathias> Eli, if this looks good, can we get this added to Emacs Git repo? If
    Mathias> we need small tweaks I would rather want to add those separately
    Mathias> instead of trying to get this first patch 100% correct.

If you have push access you can commit these changes yourself.

    Mathias> +@node Abbrev Suggestions
    Mathias> +@section Abbrev Suggestions
    Mathias> +
    Mathias> +  You can get abbrev suggestions when you manually type text for which
    Mathias> +there is currently an active defined abbrev.  For example, if there is
    Mathias> +an abbrev @samp{foo} with the expansion @samp{find outer otter}, and
    Mathias> +you manually type @samp{find outer otter}, the abbrev suggestion
    Mathias> +feature will notice this and show a hint in the echo when you have

"echo area"

Robert



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

* Re: [PATCH] Add abbrev suggestions
  2020-09-25  8:09                     ` Robert Pluim
@ 2020-09-25 20:42                       ` Mathias Dahl
  2020-09-26 14:19                         ` Robert Pluim
  0 siblings, 1 reply; 19+ messages in thread
From: Mathias Dahl @ 2020-09-25 20:42 UTC (permalink / raw)
  To: Robert Pluim; +Cc: Eli Zaretskii, emacs-devel

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

>
> I have one more :-)
>

There's always more, isn't there... :-)

If you have push access you can commit these changes yourself.
>

I thought about it initially, but I felt I might do more harm than good,
despite
having at least a decent understanding of Git nowadays. Seems I have an
account
with Savannah since, I have no idea when, perhaps I should give it a try. I
need to
read up on if there is any Emacs-specific Git flow though...


>     Mathias> +you manually type @samp{find outer otter}, the abbrev
> suggestion
>     Mathias> +feature will notice this and show a hint in the echo when
> you have
>
> "echo area"
>

:-)

Thanks!

/Mathias

[-- Attachment #2: Type: text/html, Size: 1331 bytes --]

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

* Re: [PATCH] Add abbrev suggestions
  2020-09-25 20:42                       ` Mathias Dahl
@ 2020-09-26 14:19                         ` Robert Pluim
  2020-09-26 20:56                           ` Mathias Dahl
  0 siblings, 1 reply; 19+ messages in thread
From: Robert Pluim @ 2020-09-26 14:19 UTC (permalink / raw)
  To: Mathias Dahl; +Cc: Eli Zaretskii, emacs-devel

>>>>> On Fri, 25 Sep 2020 22:42:55 +0200, Mathias Dahl <mathias.dahl@gmail.com> said:

    >> 
    >> I have one more :-)
    >> 

    Mathias> There's always more, isn't there... :-)

    Mathias> If you have push access you can commit these changes yourself.
    >> 

    Mathias> I thought about it initially, but I felt I might do more
    Mathias> harm than good, despite having at least a decent
    Mathias> understanding of Git nowadays. Seems I have an account
    Mathias> with Savannah since, I have no idea when, perhaps I
    Mathias> should give it a try. I need to read up on if there is
    Mathias> any Emacs-specific Git flow though...

'CONTRIBUTE' discusses how to generate a patch with git that will be
easy to apply for an emacs committer without having to change
it. 'admin/notes/git-workflow' goes over the details of what to do if
youʼre committing yourself.

Robert



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

* Re: [PATCH] Add abbrev suggestions
  2020-09-26 14:19                         ` Robert Pluim
@ 2020-09-26 20:56                           ` Mathias Dahl
  2020-09-26 22:21                             ` Stefan Monnier
  2020-09-27  6:12                             ` Eli Zaretskii
  0 siblings, 2 replies; 19+ messages in thread
From: Mathias Dahl @ 2020-09-26 20:56 UTC (permalink / raw)
  To: Robert Pluim; +Cc: Eli Zaretskii, emacs-devel

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

>
> 'CONTRIBUTE' discusses how to generate a patch with git that will be
> easy to apply for an emacs committer without having to change
> it. 'admin/notes/git-workflow' goes over the details of what to do if
> youʼre committing yourself.
>

Thanks! I found the guide about Emacs+Git for developers and tried to
follow that, especially this part:

https://www.emacswiki.org/emacs/GitForEmacsDevs#toc16

(I also had to play around with merging and rebasing to get a clean git log
without merge commit
messages - as a side note, Git is really starting to grow on me, seems you
can handle all kinds of
scenarios in a good way, once you know how to do it)

Long story short, I think I have now pushed my changes to the remote master
at gnu.org - Yay! :)

If someone could verify that it looks correct, it would be nice.

Thanks!

/Mathias

[-- Attachment #2: Type: text/html, Size: 1352 bytes --]

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

* Re: [PATCH] Add abbrev suggestions
  2020-09-26 20:56                           ` Mathias Dahl
@ 2020-09-26 22:21                             ` Stefan Monnier
  2020-09-27  6:12                             ` Eli Zaretskii
  1 sibling, 0 replies; 19+ messages in thread
From: Stefan Monnier @ 2020-09-26 22:21 UTC (permalink / raw)
  To: Mathias Dahl; +Cc: Robert Pluim, Eli Zaretskii, emacs-devel

> If someone could verify that it looks correct, it would be nice.

Looks good here, thank you!


        Stefan




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

* Re: [PATCH] Add abbrev suggestions
  2020-09-26 20:56                           ` Mathias Dahl
  2020-09-26 22:21                             ` Stefan Monnier
@ 2020-09-27  6:12                             ` Eli Zaretskii
  1 sibling, 0 replies; 19+ messages in thread
From: Eli Zaretskii @ 2020-09-27  6:12 UTC (permalink / raw)
  To: Mathias Dahl; +Cc: rpluim, emacs-devel

> From: Mathias Dahl <mathias.dahl@gmail.com>
> Date: Sat, 26 Sep 2020 22:56:52 +0200
> Cc: Eli Zaretskii <eliz@gnu.org>, emacs-devel@gnu.org
> 
> Thanks! I found the guide about Emacs+Git for developers and tried to follow that, especially this part:
> 
> https://www.emacswiki.org/emacs/GitForEmacsDevs#toc16

Beware: that guide is outdated, and no longer corresponds 100% to what
we practice nowadays in Emacs development.  CONTRIBUTE and
git-workflow are better suited for that role.



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

end of thread, other threads:[~2020-09-27  6:12 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-05 23:40 [PATCH] Add abbrev suggestions Mathias Dahl
2020-07-19 17:40 ` Mathias Dahl
2020-07-19 19:01   ` Eli Zaretskii
2020-07-25  8:12     ` Eli Zaretskii
2020-08-11 22:16       ` Mathias Dahl
2020-08-13 13:59         ` Eli Zaretskii
2020-08-13 14:29           ` Mathias Dahl
2020-09-14 22:04             ` Mathias Dahl
2020-09-15  6:20               ` Andreas Röhler
2020-09-18  8:39                 ` Mathias Dahl
2020-09-15  8:16               ` Robert Pluim
2020-09-18  8:40                 ` Mathias Dahl
2020-09-24 20:02                   ` Mathias Dahl
2020-09-25  8:09                     ` Robert Pluim
2020-09-25 20:42                       ` Mathias Dahl
2020-09-26 14:19                         ` Robert Pluim
2020-09-26 20:56                           ` Mathias Dahl
2020-09-26 22:21                             ` Stefan Monnier
2020-09-27  6:12                             ` Eli Zaretskii

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).