diff --git a/doc/emacs/package.texi b/doc/emacs/package.texi index fdb0822e85c..485ad601c3c 100644 --- a/doc/emacs/package.texi +++ b/doc/emacs/package.texi @@ -454,16 +454,22 @@ case, Emacs retrieves packages from this archive via ordinary file access. Such local archives are mainly useful for testing. @end defopt -@cindex suggestions +@cindex automatic suggestions for installing Emacs packages +@cindex packages, automatic suggestions for installing @findex package-autosuggest @findex package-autosuggest-mode - Emacs has a built-in database of suggested packages for certain file -types. If Emacs opens a file with no specific mode, you can use the -@code{package-autosuggest} command to install the recommended packages -from ELPA. After enabling @code{package-autosuggest-mode}, Emacs will -display a clickable hint in the mode-line if it there is a suggested -package. Using the @code{package-autosuggest-style} user option, you -can adjust how Emacs presents the hint to install a package. +@vindex package-autosuggest-style + Emacs can suggest installing packages when you visit certain kinds of +files. When you visit a file with no specific mode available, you can +use the @code{package-autosuggest} command to find and install add-on +ELPA packages recommended for this file type. If you enable +@code{package-autosuggest-mode}, Emacs will automatically notify you if +it there is a suggested add-on package for the file visited by the +buffer. The default is for these notifications to display a button in +the buffer window's mode-line suggesting you to upgrade the major mode +by installing add-on packages, but you can control how Emacs presents +these notifications by customizing the @code{package-autosuggest-style} +user option. @anchor{Package Signing} @cindex package security diff --git a/etc/NEWS b/etc/NEWS index 243feba3c0e..09481189558 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -2990,14 +2990,18 @@ installation or displaying a ChangeLog. +++ *** New command 'package-autosuggest' -Using a built-in database of package suggestions from ELPA, this command -will install viable packages if no specific major mode is available. +Using a built-in database of ELPA package suggestions, this command will +install viable packages if no specific major mode is available for the +contents of the current buffer. +++ *** New minor mode 'package-autosuggest-mode' -When enabled, this displays a hint in the mode line indicating the -availability of a suggested package. You can customise the presentation -of these hints using 'package-autosuggest-style'. +When enabled, this displays indications about the availability of add-on +ELPA packages for the current buffer and suggestions for installing +those packages. The default is to show a button on the mode line that +can be used to install such packages, but you can customise the +presentation style of these suggestions using +'package-autosuggest-style'. ** Rcirc diff --git a/lisp/emacs-lisp/package-activate.el b/lisp/emacs-lisp/package-activate.el index 1689d985c28..bee4fc1fb7e 100644 --- a/lisp/emacs-lisp/package-activate.el +++ b/lisp/emacs-lisp/package-activate.el @@ -544,23 +544,35 @@ the `Version:' header." ;; on package suggestions is to be found in package.el. (defcustom package-autosuggest-style 'mode-line - "How to draw attention to `package-autosuggest-mode' suggestions. -You can set this value to `mode-line' (default) to indicate the -availability of a package suggestion in the minor mode, `always' to -prompt the user in the minibuffer every time a suggestion is available -in a `fundamental-mode' buffer, or `message' to just display a message -hinting at the existence of a suggestion. If you only wish to be -reminded of package suggestions once every session, consider customizing -the `package-autosuggest-once' user option." + "Style of showing suggestions of `package-autosuggest-mode'. +If the value is `mode-line' (default), Emacs indicates the availability +of suggested packages as a button on the mode line. The value `always' +means prompt the user in the minibuffer every time a suggestion is available. +The value `message' means display an echo-area message about the existence +of a package and how to install it. + +This variable has effect only if `package-autosuggest-mode' is turned on. + +If you wish to be shown a suggestion of each package only once every +session, consider customizing the `package-autosuggest-once' user option." :type '(choice (const :tag "Indicate in mode line" mode-line) - (const :tag "Always prompt" always) - (const :tag "Indicate with message" message)) - :group 'package) + (const :tag "Prompt in minibuffer" always) + (const :tag "Show echo-area message" message)) + :group 'package + :version "31.1") (defcustom package-autosuggest-once nil - "Non-nil means not to repeat package suggestions." + "Non-nil means show automatic suggestion for each package only once. +If this variable is non-nil, Emacs will show an automatic suggestion +to install a certain package only once per session, and will not repeat +the suggestion to install the same package until you restart Emacs. +The default value is nil, which means show the suggestions as many times +as the criteria for suggesting it are fulfilled. + +This variable has effect only if `package-autosuggest-mode' is turned on." :type 'boolean - :group 'package) + :group 'package + :version "31.1") (defvar package--autosuggest-database 'unset "A list of package suggestions. @@ -578,15 +590,15 @@ the mode line).") (defun package--suggestion-applies-p (sug) "Check if a suggestion SUG is applicable to the current buffer. -Each suggestion has the form (PACKAGE TYPE DATA), where PACKAGE is a -symbol denoting the package and major-mode the suggestion applies to, -TYPE is one of `auto-mode-alist', `magic-mode-alist' or -`interpreter-mode-alist' indicating the type of check to be made and -DATA is the value to check against TYPE in the intuitive way (e.g. for -`auto-mode-alist' DATA is a regular expression matching a file name that -PACKAGE should be suggested for). If the package name and the major -mode name differ, then an optional forth element MAJOR-MODE can indicate -what command to invoke to enable the package." +Each suggestion has the form (PACKAGE TYPE DATA [MAJOR-MODE]), where +PACKAGE is a symbol denoting the package and major-mode to which the +suggestion applies, TYPE is one of `auto-mode-alist', `magic-mode-alist' +or `interpreter-mode-alist', indicating the type of check to be made, +and DATA is the value to check against TYPE in the intuitive way (e.g., +for `auto-mode-alist' DATA is a regular expression matching a file name +for which PACKAGE should be suggested). If the package name and the +major mode name differ, then an optional fourth element MAJOR-MODE can +be used to indicate what command to invoke to enable the package." (pcase sug ((or (guard (not (eq major-mode 'fundamental-mode))) (guard (and package-autosuggest-once @@ -610,9 +622,9 @@ what command to invoke to enable the package." intr))))))) (defun package--autosuggest-find-candidates () - "Return a list of suggestions that might be interesting the current buffer. -The elements of the returned list will have the form described in -`package--suggestion-applies-p'." + "Return a list of suggestions that might be interesting for the current buffer. +The elements of the returned list will have the form described +in `package--suggestion-applies-p'." (and (eq major-mode 'fundamental-mode) (let ((suggetions '())) (when (eq package--autosuggest-database 'unset) @@ -632,7 +644,7 @@ The elements of the returned list will have the form described in (put 'package--autosugest-line-format 'risky-local-variable t) (defun package--autosugest-line-format () - "Generate a mode-line string to indicate a suggested package." + "Generate a mode-line button to indicate a suggested package." `(,@(and-let* (((not (null package-autosuggest-mode))) ((eq package-autosuggest-style 'mode-line)) (avail (package--autosuggest-find-candidates))) @@ -642,14 +654,16 @@ The elements of the returned list will have the form described in 'mouse-face 'mode-line-highlight 'help-echo "Click to install suggested package." 'keymap (let ((map (make-sparse-keymap))) - (define-key map [mode-line down-mouse-1] #'package-autosuggest) + (define-key map + [mode-line down-mouse-1] + #'package-autosuggest) map))))) (declare-function package-autosuggest "package" (&optional candidates)) (defun package--autosuggest-after-change-mode () "Display package suggestions for the current buffer. -This function should be added to `after-change-major-mode-hook'." +This function is intended for addition to `after-change-major-mode-hook'." (when-let* ((avail (package--autosuggest-find-candidates)) (pkgs (mapconcat #'symbol-name (delete-dups (mapcar #'car avail)) @@ -672,7 +686,15 @@ This function should be added to `after-change-major-mode-hook'." ;;;###autoload (define-minor-mode package-autosuggest-mode - "Enable the automatic suggestion and installation of packages." + "Enable automatic suggestions for installing add-on packages. +When this minor mode is turned on, Emacs will suggest installing +add-on packages from ELPA whenever it determines that the buffer's +contents and editing could benefit from a better major mode. + +See the variable `package-autosuggest-style' for controlling the style +of showing these suggestions. +Customize the variable `package-autosuggest-once' to control repetitive +suggestions." :global t :group 'package ;; :initialize #'custom-initialize-delay (funcall (if package-autosuggest-mode #'add-hook #'remove-hook) diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el index e2d35f20eb5..fa8c5cb4599 100644 --- a/lisp/emacs-lisp/package.el +++ b/lisp/emacs-lisp/package.el @@ -4533,7 +4533,7 @@ The list is displayed in a buffer named `*Packages*'." ;;;; Package Suggestions (defun package--autosuggest-install-and-enable (sug) - "Install and enable a package suggestion PKG-ENT. + "Install and enable a package suggestion SUG. SUG should be of the form as described in `package--suggestion-applies-p'." (let ((buffers-to-update '())) (dolist (buf (buffer-list)) @@ -4550,9 +4550,9 @@ SUG should be of the form as described in `package--suggestion-applies-p'." (defun package--autosugest-prompt (packages) "Query the user whether to install PACKAGES or not. -PACKAGES is a list of package suggestions in the form as described in +PACKAGES is a list of package suggestions in the form described in `package--suggestion-applies-p'. The function returns a non-nil value -if affirmative, otherwise nil" +if the user confirms installation, otherwise nil." (let* ((inhibit-read-only t) (use-hard-newlines t) (nl (propertize "\n" 'hard t)) (nlnl (concat nl nl)) (buf (current-buffer))) @@ -4627,9 +4627,9 @@ so you have to select which to install!)" nl)) ;;;###autoload (defun package-autosuggest (&optional candidates) "Prompt the user to install the suggested packages. -The optional argument CANDIDATES may be a list of packages that match -for form described in `package--suggestion-applies-p'. If omitted, the -list of candidates will be computed from the database." +The optional argument CANDIDATES may be a list of package suggestions +in the form described in `package--suggestion-applies-p'. If omitted +or nil, the list of candidates will be computed from the database." (interactive) (package--autosugest-prompt (or candidates