aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFederico Tedin2019-09-26 19:18:58 +0200
committerStefan Kangas2019-10-08 19:24:12 +0200
commitf96b8fd27c382a941c52c2938544b9b0e3a2fb0e (patch)
tree22708a866bce395e64ce5c883ac349e415dc2570
parentba57f1a4273cabb53cbae86ad34b0a4bf01e1513 (diff)
downloademacs-f96b8fd27c382a941c52c2938544b9b0e3a2fb0e.tar.gz
emacs-f96b8fd27c382a941c52c2938544b9b0e3a2fb0e.zip
Filter packages by name in list-packages. (Bug#36981)
* lisp/emacs-lisp/package.el (package-menu-filter-by-name): New function to filter packages by name. (package-menu-clear-filter): New function to clear applied filters. (package-menu-filter-by-keyword): Rename function from package-menu-filter. (package-menu--generate): Don't change 'q' binding anymore. (package-menu-mode-map): Bind '/ n' to package-menu-filter-by-name, '/ k' to package-menu-filter-by-keyword and '/ /' to package-menu-clear-filter. (package-menu-mode-menu): Update menu entries for the three functions. * test/lisp/emacs-lisp/package-tests.el (package-test-list-filter-by-name) (package-test-list-clear-filter): New tests. * doc/emacs/package.texi: Document usage of package-menu-filter-by-name, package-menu-clear-filter and update reference to package-menu-filter-by-keyword. * etc/NEWS: Announce changes.
-rw-r--r--doc/emacs/package.texi19
-rw-r--r--etc/NEWS10
-rw-r--r--lisp/emacs-lisp/package.el47
-rw-r--r--test/lisp/emacs-lisp/package-tests.el22
4 files changed, 81 insertions, 17 deletions
diff --git a/doc/emacs/package.texi b/doc/emacs/package.texi
index 2c09ca89024..d97648af1bb 100644
--- a/doc/emacs/package.texi
+++ b/doc/emacs/package.texi
@@ -136,11 +136,20 @@ Refresh the package list (@code{package-menu-refresh}). This fetches
136the list of available packages from the package archive again, and 136the list of available packages from the package archive again, and
137recomputes the package list. 137recomputes the package list.
138 138
139@item f 139@item / k
140Filter the package list (@code{package-menu-filter}). This prompts 140Filter the package list by keyword
141for a keyword (e.g., @samp{games}), then shows only the packages 141(@code{package-menu-filter-by-keyword}). This prompts for a keyword
142that relate to that keyword. To restore the full package list, 142(e.g., @samp{games}), then shows only the packages that relate to that
143type @kbd{q}. 143keyword.
144
145@item / n
146Filter the package list by name (@code{package-menu-filter-by-name}).
147This prompts for a string, then shows only the packages whose names
148match a regexp with that value.
149
150@item / /
151Clear filter currently applied to the package list
152(@code{package-menu-clear-filter}).
144 153
145@item H 154@item H
146Permanently hide packages that match a regexp 155Permanently hide packages that match a regexp
diff --git a/etc/NEWS b/etc/NEWS
index 906dc912d6d..2ca681ff9b9 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1006,6 +1006,16 @@ early init file.
1006 1006
1007*** New function 'package-activate-all'. 1007*** New function 'package-activate-all'.
1008 1008
1009+++
1010*** New functions for filtering packages list.
1011A new function has been added which allows users to filter the
1012packages list by name: 'package-menu-filter-by-name'. By default, it
1013is bound to '/ n'. Additionally, the function
1014'package-menu-fiter-by-keyword' has been renamed from
1015'package-menu-filter'. Its keybinding has also been changed to '/ k'
1016(from 'f'). To clear any of the two filters, the user can now call
1017the 'package-menu-clear-filter' function, bound to '/ /' by default.
1018
1009--- 1019---
1010*** Imenu support has been added to 'package-menu-mode'. 1020*** Imenu support has been added to 'package-menu-mode'.
1011 1021
diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
index 0b2dc24ebb9..20462064afd 100644
--- a/lisp/emacs-lisp/package.el
+++ b/lisp/emacs-lisp/package.el
@@ -2685,7 +2685,9 @@ either a full name or nil, and EMAIL is a valid email address."
2685 (define-key map "i" 'package-menu-mark-install) 2685 (define-key map "i" 'package-menu-mark-install)
2686 (define-key map "U" 'package-menu-mark-upgrades) 2686 (define-key map "U" 'package-menu-mark-upgrades)
2687 (define-key map "r" 'package-menu-refresh) 2687 (define-key map "r" 'package-menu-refresh)
2688 (define-key map "f" 'package-menu-filter) 2688 (define-key map (kbd "/ k") 'package-menu-filter-by-keyword)
2689 (define-key map (kbd "/ n") 'package-menu-filter-by-name)
2690 (define-key map (kbd "/ /") 'package-menu-clear-filter)
2689 (define-key map "~" 'package-menu-mark-obsolete-for-deletion) 2691 (define-key map "~" 'package-menu-mark-obsolete-for-deletion)
2690 (define-key map "x" 'package-menu-execute) 2692 (define-key map "x" 'package-menu-execute)
2691 (define-key map "h" 'package-menu-quick-help) 2693 (define-key map "h" 'package-menu-quick-help)
@@ -2717,7 +2719,11 @@ either a full name or nil, and EMAIL is a valid email address."
2717 ["Unmark" package-menu-mark-unmark :help "Clear any marks on a package and move to the next line"] 2719 ["Unmark" package-menu-mark-unmark :help "Clear any marks on a package and move to the next line"]
2718 2720
2719 "--" 2721 "--"
2720 ["Filter Package List" package-menu-filter :help "Filter package selection (q to go back)"] 2722 ("Filter Packages"
2723 ["Filter by Keyword" package-menu-filter-by-keyword :help "Filter packages by keyword"]
2724 ["Filter by Name" package-menu-filter-by-name :help "Filter packages by name"]
2725 ["Clear Filter" package-menu-clear-filter :help "Clear package list filter"])
2726
2721 ["Hide by Regexp" package-menu-hide-package :help "Permanently hide all packages matching a regexp"] 2727 ["Hide by Regexp" package-menu-hide-package :help "Permanently hide all packages matching a regexp"]
2722 ["Display Older Versions" package-menu-toggle-hiding 2728 ["Display Older Versions" package-menu-toggle-hiding
2723 :style toggle :selected (not package-menu--hide-packages) 2729 :style toggle :selected (not package-menu--hide-packages)
@@ -3028,9 +3034,6 @@ shown."
3028 (let ((filters (mapconcat #'identity keywords ","))) 3034 (let ((filters (mapconcat #'identity keywords ",")))
3029 (concat "Package[" filters "]")) 3035 (concat "Package[" filters "]"))
3030 "Package")) 3036 "Package"))
3031 (if keywords
3032 (define-key package-menu-mode-map "q" 'package-show-package-list)
3033 (define-key package-menu-mode-map "q" 'quit-window))
3034 (tabulated-list-init-header) 3037 (tabulated-list-init-header)
3035 (tabulated-list-print remember-pos)) 3038 (tabulated-list-print remember-pos))
3036 3039
@@ -3660,10 +3663,8 @@ shown."
3660 (select-window win) 3663 (select-window win)
3661 (switch-to-buffer buf)))) 3664 (switch-to-buffer buf))))
3662 3665
3663;; package-menu--generate rebinds "q" on the fly, so we have to 3666(defun package-menu-filter-by-keyword (keyword)
3664;; hard-code the binding in the doc-string here. 3667 "Filter the \"*Packages*\" buffer by KEYWORD.
3665(defun package-menu-filter (keyword)
3666 "Filter the *Packages* buffer.
3667Show only those items that relate to the specified KEYWORD. 3668Show only those items that relate to the specified KEYWORD.
3668 3669
3669KEYWORD can be a string or a list of strings. If it is a list, a 3670KEYWORD can be a string or a list of strings. If it is a list, a
@@ -3673,9 +3674,7 @@ Interactively, it is a list of strings separated by commas.
3673KEYWORD can also be used to filter by status or archive name by 3674KEYWORD can also be used to filter by status or archive name by
3674using keywords like \"arc:gnu\" and \"status:available\". 3675using keywords like \"arc:gnu\" and \"status:available\".
3675Statuses available include \"incompat\", \"available\", 3676Statuses available include \"incompat\", \"available\",
3676\"built-in\" and \"installed\". 3677\"built-in\" and \"installed\"."
3677
3678To restore the full package list, type `q'."
3679 (interactive 3678 (interactive
3680 (list (completing-read-multiple 3679 (list (completing-read-multiple
3681 "Keywords (comma separated): " (package-all-keywords)))) 3680 "Keywords (comma separated): " (package-all-keywords))))
@@ -3683,6 +3682,30 @@ To restore the full package list, type `q'."
3683 (list keyword) 3682 (list keyword)
3684 keyword))) 3683 keyword)))
3685 3684
3685(defun package-menu-filter-by-name (name)
3686 "Filter the \"*Packages*\" buffer by NAME.
3687Show only those items whose name matches the regular expression
3688NAME. If NAME is nil or the empty string, show all packages."
3689 (interactive (list (read-from-minibuffer "Filter by name (regexp): ")))
3690 (if (or (not name) (string-empty-p name))
3691 (package-show-package-list t nil)
3692 ;; Update `tabulated-list-entries' so that it contains all
3693 ;; packages before searching.
3694 (package-menu--refresh t nil)
3695 (let (matched)
3696 (dolist (entry tabulated-list-entries)
3697 (let* ((pkg-name (package-desc-name (car entry))))
3698 (when (string-match name (symbol-name pkg-name))
3699 (push pkg-name matched))))
3700 (if matched
3701 (package-show-package-list matched nil)
3702 (user-error "No packages found")))))
3703
3704(defun package-menu-clear-filter ()
3705 "Clear any filter currently applied to the \"*Packages*\" buffer."
3706 (interactive)
3707 (package-menu--generate t t))
3708
3686(defun package-list-packages-no-fetch () 3709(defun package-list-packages-no-fetch ()
3687 "Display a list of packages. 3710 "Display a list of packages.
3688Does not fetch the updated list of packages before displaying. 3711Does not fetch the updated list of packages before displaying.
diff --git a/test/lisp/emacs-lisp/package-tests.el b/test/lisp/emacs-lisp/package-tests.el
index 0edb81d6a11..8670e6f3fac 100644
--- a/test/lisp/emacs-lisp/package-tests.el
+++ b/test/lisp/emacs-lisp/package-tests.el
@@ -365,6 +365,28 @@ Must called from within a `tar-mode' buffer."
365 (should-not (re-search-forward "^\\s-+simple-single\\s-+1.3\\s-+\\(available\\|new\\)" nil t)) 365 (should-not (re-search-forward "^\\s-+simple-single\\s-+1.3\\s-+\\(available\\|new\\)" nil t))
366 (kill-buffer buf)))) 366 (kill-buffer buf))))
367 367
368(ert-deftest package-test-list-filter-by-name ()
369 "Ensure package list is filtered correctly by package name."
370 (with-package-test ()
371 (let ((buf (package-list-packages)))
372 (package-menu-filter-by-name "tetris")
373 (goto-char (point-min))
374 (should (re-search-forward "^\\s-+tetris" nil t))
375 (should (= (count-lines (point-min) (point-max)) 1))
376 (kill-buffer buf))))
377
378(ert-deftest package-test-list-clear-filter ()
379 "Ensure package list filter is cleared correctly."
380 (with-package-test ()
381 (let ((buf (package-list-packages)))
382 (let ((num-packages (count-lines (point-min) (point-max))))
383 (should (> num-packages 1))
384 (package-menu-filter-by-name "tetris")
385 (should (= (count-lines (point-min) (point-max)) 1))
386 (package-menu-clear-filter)
387 (should (= (count-lines (point-min) (point-max)) num-packages)))
388 (kill-buffer buf))))
389
368(ert-deftest package-test-update-archives () 390(ert-deftest package-test-update-archives ()
369 "Test updating package archives." 391 "Test updating package archives."
370 (with-package-test () 392 (with-package-test ()