Abbrev suggestions helps users remember to use defined abbrevs
* 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.
This commit is contained in:
parent
e7012148c0
commit
f43d9d94aa
3 changed files with 181 additions and 1 deletions
|
@ -28,6 +28,7 @@ Automatic Typing}.
|
|||
* 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 @@ changing this function you can make arbitrary changes to
|
|||
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 area 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
|
||||
|
||||
|
|
10
etc/NEWS
10
etc/NEWS
|
@ -1271,6 +1271,16 @@ This value customizes Emacs to use the style recommended in Damian
|
|||
Conway's book "Perl Best Practices" for indentation and formatting
|
||||
of conditionals.
|
||||
|
||||
** 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.
|
||||
|
||||
|
||||
* New Modes and Packages in Emacs 28.1
|
||||
|
||||
|
|
140
lisp/abbrev.el
140
lisp/abbrev.el
|
@ -824,6 +824,142 @@ see `define-abbrev' for details."
|
|||
"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 @@ Calls the value of `abbrev-expand-function' with no argument to do
|
|||
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'.
|
||||
|
|
Loading…
Add table
Reference in a new issue