diff options
| author | Ted Zlatanov | 2013-12-14 14:55:19 -0500 |
|---|---|---|
| committer | Ted Zlatanov | 2013-12-14 14:55:19 -0500 |
| commit | 5ae811ddef14ea1989088c259a9ed2d14d5332b4 (patch) | |
| tree | cbe7a4ec4c082f4f8d1e9f0a959632b28d9e0ca5 | |
| parent | 2897da4d7be9f0082e88140ef2de2c463d62fea7 (diff) | |
| download | emacs-5ae811ddef14ea1989088c259a9ed2d14d5332b4.tar.gz emacs-5ae811ddef14ea1989088c259a9ed2d14d5332b4.zip | |
Support filtering by keywords in package listings.
* emacs-lisp/package.el (package-built-in-p): Support both
built-in and the package.el converted package descriptions.
(package-show-package-list): Allow keywords.
(package-keyword-button-action): Use it instead of
`finder-list-matches'.
(package-menu-filter-interactive): Interactive filtering (by
keyword) function.
(package-menu--generate): Support keywords and change keymappings
and headers when they are given.
(package--has-keyword-p): Helper function.
(package-menu--refresh): Use it.
(package--mapc): Helper function.
(package-all-keywords): Use it.
(package-menu-mode-map): Set up menu items and keybindings to
provide a filtering UI.
| -rw-r--r-- | lisp/ChangeLog | 18 | ||||
| -rw-r--r-- | lisp/emacs-lisp/package.el | 126 |
2 files changed, 124 insertions, 20 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 246b7ae5b5f..0eabdf86ffa 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,5 +1,23 @@ | |||
| 1 | 2013-12-14 Teodor Zlatanov <tzz@lifelogs.com> | 1 | 2013-12-14 Teodor Zlatanov <tzz@lifelogs.com> |
| 2 | 2 | ||
| 3 | * emacs-lisp/package.el (package-built-in-p): Support both | ||
| 4 | built-in and the package.el converted package descriptions. | ||
| 5 | (package-show-package-list): Allow keywords. | ||
| 6 | (package-keyword-button-action): Use it instead of | ||
| 7 | `finder-list-matches'. | ||
| 8 | (package-menu-filter-interactive): Interactive filtering (by | ||
| 9 | keyword) function. | ||
| 10 | (package-menu--generate): Support keywords and change keymappings | ||
| 11 | and headers when they are given. | ||
| 12 | (package--has-keyword-p): Helper function. | ||
| 13 | (package-menu--refresh): Use it. | ||
| 14 | (package--mapc): Helper function. | ||
| 15 | (package-all-keywords): Use it. | ||
| 16 | (package-menu-mode-map): Set up menu items and keybindings to | ||
| 17 | provide a filtering UI. | ||
| 18 | |||
| 19 | 2013-12-14 Teodor Zlatanov <tzz@lifelogs.com> | ||
| 20 | |||
| 3 | * net/gnutls.el (gnutls-verify-error): New defcustom to control | 21 | * net/gnutls.el (gnutls-verify-error): New defcustom to control |
| 4 | the behavior when a certificate fails validation. Defaults to | 22 | the behavior when a certificate fails validation. Defaults to |
| 5 | old behavior: never abort, just warn. | 23 | old behavior: never abort, just warn. |
diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el index b8c21e0386b..407b277fa9f 100644 --- a/lisp/emacs-lisp/package.el +++ b/lisp/emacs-lisp/package.el | |||
| @@ -524,13 +524,15 @@ Return the max version (as a string) if the package is held at a lower version." | |||
| 524 | "Return true if PACKAGE is built-in to Emacs. | 524 | "Return true if PACKAGE is built-in to Emacs. |
| 525 | Optional arg MIN-VERSION, if non-nil, should be a version list | 525 | Optional arg MIN-VERSION, if non-nil, should be a version list |
| 526 | specifying the minimum acceptable version." | 526 | specifying the minimum acceptable version." |
| 527 | (let ((bi (assq package package--builtin-versions))) | 527 | (if (package-desc-p package) ;; was built-in and then was converted |
| 528 | (cond | 528 | (eq 'builtin (package-desc-dir package)) |
| 529 | (bi (version-list-<= min-version (cdr bi))) | 529 | (let ((bi (assq package package--builtin-versions))) |
| 530 | (min-version nil) | 530 | (cond |
| 531 | (t | 531 | (bi (version-list-<= min-version (cdr bi))) |
| 532 | (require 'finder-inf nil t) ; For `package--builtins'. | 532 | (min-version nil) |
| 533 | (assq package package--builtins))))) | 533 | (t |
| 534 | (require 'finder-inf nil t) ; For `package--builtins'. | ||
| 535 | (assq package package--builtins)))))) | ||
| 534 | 536 | ||
| 535 | (defun package--from-builtin (bi-desc) | 537 | (defun package--from-builtin (bi-desc) |
| 536 | (package-desc-create :name (pop bi-desc) | 538 | (package-desc-create :name (pop bi-desc) |
| @@ -1528,10 +1530,9 @@ If optional arg NO-ACTIVATE is non-nil, don't activate packages." | |||
| 1528 | (revert-buffer nil t) | 1530 | (revert-buffer nil t) |
| 1529 | (goto-char (point-min))))) | 1531 | (goto-char (point-min))))) |
| 1530 | 1532 | ||
| 1531 | (autoload 'finder-list-matches "finder") | ||
| 1532 | (defun package-keyword-button-action (button) | 1533 | (defun package-keyword-button-action (button) |
| 1533 | (let ((pkg-keyword (button-get button 'package-keyword))) | 1534 | (let ((pkg-keyword (button-get button 'package-keyword))) |
| 1534 | (finder-list-matches pkg-keyword))) | 1535 | (package-show-package-list t (list pkg-keyword)))) |
| 1535 | 1536 | ||
| 1536 | (defun package-make-button (text &rest props) | 1537 | (defun package-make-button (text &rest props) |
| 1537 | (let ((button-text (if (display-graphic-p) text (concat "[" text "]"))) | 1538 | (let ((button-text (if (display-graphic-p) text (concat "[" text "]"))) |
| @@ -1557,6 +1558,7 @@ If optional arg NO-ACTIVATE is non-nil, don't activate packages." | |||
| 1557 | (define-key map "i" 'package-menu-mark-install) | 1558 | (define-key map "i" 'package-menu-mark-install) |
| 1558 | (define-key map "U" 'package-menu-mark-upgrades) | 1559 | (define-key map "U" 'package-menu-mark-upgrades) |
| 1559 | (define-key map "r" 'package-menu-refresh) | 1560 | (define-key map "r" 'package-menu-refresh) |
| 1561 | (define-key map "f" 'package-menu-filter-interactive) | ||
| 1560 | (define-key map "~" 'package-menu-mark-obsolete-for-deletion) | 1562 | (define-key map "~" 'package-menu-mark-obsolete-for-deletion) |
| 1561 | (define-key map "x" 'package-menu-execute) | 1563 | (define-key map "x" 'package-menu-execute) |
| 1562 | (define-key map "h" 'package-menu-quick-help) | 1564 | (define-key map "h" 'package-menu-quick-help) |
| @@ -1565,6 +1567,9 @@ If optional arg NO-ACTIVATE is non-nil, don't activate packages." | |||
| 1565 | (define-key menu-map [mq] | 1567 | (define-key menu-map [mq] |
| 1566 | '(menu-item "Quit" quit-window | 1568 | '(menu-item "Quit" quit-window |
| 1567 | :help "Quit package selection")) | 1569 | :help "Quit package selection")) |
| 1570 | (define-key menu-map [mf] | ||
| 1571 | '(menu-item "Filter" package-menu-filter-interactive | ||
| 1572 | :help "Filter package selection (q to go back)")) | ||
| 1568 | (define-key menu-map [s1] '("--")) | 1573 | (define-key menu-map [s1] '("--")) |
| 1569 | (define-key menu-map [mn] | 1574 | (define-key menu-map [mn] |
| 1570 | '(menu-item "Next" next-line | 1575 | '(menu-item "Next" next-line |
| @@ -1677,9 +1682,10 @@ package PKG-DESC, add one. The alist is keyed with PKG-DESC." | |||
| 1677 | "installed" | 1682 | "installed" |
| 1678 | "unsigned")))))))) | 1683 | "unsigned")))))))) |
| 1679 | 1684 | ||
| 1680 | (defun package-menu--refresh (&optional packages) | 1685 | (defun package-menu--refresh (&optional packages keywords) |
| 1681 | "Re-populate the `tabulated-list-entries'. | 1686 | "Re-populate the `tabulated-list-entries'. |
| 1682 | PACKAGES should be nil or t, which means to display all known packages." | 1687 | PACKAGES should be nil or t, which means to display all known packages. |
| 1688 | KEYWORDS should be nil or a list of keywords." | ||
| 1683 | ;; Construct list of (PKG-DESC . STATUS). | 1689 | ;; Construct list of (PKG-DESC . STATUS). |
| 1684 | (unless packages (setq packages t)) | 1690 | (unless packages (setq packages t)) |
| 1685 | (let (info-list name) | 1691 | (let (info-list name) |
| @@ -1688,12 +1694,14 @@ PACKAGES should be nil or t, which means to display all known packages." | |||
| 1688 | (setq name (car elt)) | 1694 | (setq name (car elt)) |
| 1689 | (when (or (eq packages t) (memq name packages)) | 1695 | (when (or (eq packages t) (memq name packages)) |
| 1690 | (dolist (pkg (cdr elt)) | 1696 | (dolist (pkg (cdr elt)) |
| 1691 | (package--push pkg (package-desc-status pkg) info-list)))) | 1697 | (when (package--has-keyword-p pkg keywords) |
| 1698 | (package--push pkg (package-desc-status pkg) info-list))))) | ||
| 1692 | 1699 | ||
| 1693 | ;; Built-in packages: | 1700 | ;; Built-in packages: |
| 1694 | (dolist (elt package--builtins) | 1701 | (dolist (elt package--builtins) |
| 1695 | (setq name (car elt)) | 1702 | (setq name (car elt)) |
| 1696 | (when (and (not (eq name 'emacs)) ; Hide the `emacs' package. | 1703 | (when (and (not (eq name 'emacs)) ; Hide the `emacs' package. |
| 1704 | (package--has-keyword-p (package--from-builtin elt) keywords) | ||
| 1697 | (or package-list-unversioned | 1705 | (or package-list-unversioned |
| 1698 | (package--bi-desc-version (cdr elt))) | 1706 | (package--bi-desc-version (cdr elt))) |
| 1699 | (or (eq packages t) (memq name packages))) | 1707 | (or (eq packages t) (memq name packages))) |
| @@ -1705,20 +1713,89 @@ PACKAGES should be nil or t, which means to display all known packages." | |||
| 1705 | (when (or (eq packages t) (memq name packages)) | 1713 | (when (or (eq packages t) (memq name packages)) |
| 1706 | (dolist (pkg (cdr elt)) | 1714 | (dolist (pkg (cdr elt)) |
| 1707 | ;; Hide obsolete packages. | 1715 | ;; Hide obsolete packages. |
| 1708 | (unless (package-installed-p (package-desc-name pkg) | 1716 | (when (and (not (package-installed-p (package-desc-name pkg) |
| 1709 | (package-desc-version pkg)) | 1717 | (package-desc-version pkg))) |
| 1718 | (package--has-keyword-p pkg keywords)) | ||
| 1710 | (package--push pkg (package-desc-status pkg) info-list))))) | 1719 | (package--push pkg (package-desc-status pkg) info-list))))) |
| 1711 | 1720 | ||
| 1712 | ;; Print the result. | 1721 | ;; Print the result. |
| 1713 | (setq tabulated-list-entries | 1722 | (setq tabulated-list-entries |
| 1714 | (mapcar #'package-menu--print-info info-list)))) | 1723 | (mapcar #'package-menu--print-info info-list)))) |
| 1715 | 1724 | ||
| 1716 | (defun package-menu--generate (remember-pos packages) | 1725 | (defun package-all-keywords () |
| 1726 | "Collect all package keywords" | ||
| 1727 | (let (keywords) | ||
| 1728 | (package--mapc (lambda (desc) | ||
| 1729 | (let* ((extras (and desc (package-desc-extras desc))) | ||
| 1730 | (desc-keywords (cdr (assoc :keywords extras)))) | ||
| 1731 | (setq keywords (append keywords desc-keywords))))) | ||
| 1732 | keywords)) | ||
| 1733 | |||
| 1734 | (defun package--mapc (function &optional packages) | ||
| 1735 | "Call FUNCTION for all known PACKAGES. | ||
| 1736 | PACKAGES can be nil or t, which means to display all known | ||
| 1737 | packages, or a list of packages. | ||
| 1738 | |||
| 1739 | Built-in packages are converted with `package--from-builtin'." | ||
| 1740 | (unless packages (setq packages t)) | ||
| 1741 | (let (name) | ||
| 1742 | ;; Installed packages: | ||
| 1743 | (dolist (elt package-alist) | ||
| 1744 | (setq name (car elt)) | ||
| 1745 | (when (or (eq packages t) (memq name packages)) | ||
| 1746 | (mapc function (cdr elt)))) | ||
| 1747 | |||
| 1748 | ;; Built-in packages: | ||
| 1749 | (dolist (elt package--builtins) | ||
| 1750 | (setq name (car elt)) | ||
| 1751 | (when (and (not (eq name 'emacs)) ; Hide the `emacs' package. | ||
| 1752 | (or package-list-unversioned | ||
| 1753 | (package--bi-desc-version (cdr elt))) | ||
| 1754 | (or (eq packages t) (memq name packages))) | ||
| 1755 | (funcall function (package--from-builtin elt)))) | ||
| 1756 | |||
| 1757 | ;; Available and disabled packages: | ||
| 1758 | (dolist (elt package-archive-contents) | ||
| 1759 | (setq name (car elt)) | ||
| 1760 | (when (or (eq packages t) (memq name packages)) | ||
| 1761 | (dolist (pkg (cdr elt)) | ||
| 1762 | ;; Hide obsolete packages. | ||
| 1763 | (unless (package-installed-p (package-desc-name pkg) | ||
| 1764 | (package-desc-version pkg)) | ||
| 1765 | (funcall function pkg))))))) | ||
| 1766 | |||
| 1767 | (defun package--has-keyword-p (desc &optional keywords) | ||
| 1768 | "Test if package DESC has any of the given KEYWORDS. | ||
| 1769 | When none are given, the package matches." | ||
| 1770 | (if keywords | ||
| 1771 | (let* ((extras (and desc (package-desc-extras desc))) | ||
| 1772 | (desc-keywords (cdr (assoc :keywords extras))) | ||
| 1773 | found) | ||
| 1774 | (dolist (k keywords) | ||
| 1775 | (when (and (not found) | ||
| 1776 | (member k desc-keywords)) | ||
| 1777 | (setq found t))) | ||
| 1778 | found) | ||
| 1779 | t)) | ||
| 1780 | |||
| 1781 | (defun package-menu--generate (remember-pos packages &optional keywords) | ||
| 1717 | "Populate the Package Menu. | 1782 | "Populate the Package Menu. |
| 1718 | If REMEMBER-POS is non-nil, keep point on the same entry. | 1783 | If REMEMBER-POS is non-nil, keep point on the same entry. |
| 1719 | PACKAGES should be t, which means to display all known packages, | 1784 | PACKAGES should be t, which means to display all known packages, |
| 1720 | or a list of package names (symbols) to display." | 1785 | or a list of package names (symbols) to display. |
| 1721 | (package-menu--refresh packages) | 1786 | |
| 1787 | With KEYWORDS given, only packages with those keywords are | ||
| 1788 | shown." | ||
| 1789 | (package-menu--refresh packages keywords) | ||
| 1790 | (setf (car (aref tabulated-list-format 0)) | ||
| 1791 | (if keywords | ||
| 1792 | (let ((filters (mapconcat 'identity keywords ","))) | ||
| 1793 | (concat "Package[" filters "]")) | ||
| 1794 | "Package")) | ||
| 1795 | (if keywords | ||
| 1796 | (define-key package-menu-mode-map "q" 'package-show-package-list) | ||
| 1797 | (define-key package-menu-mode-map "q" 'quit-window)) | ||
| 1798 | (tabulated-list-init-header) | ||
| 1722 | (tabulated-list-print remember-pos)) | 1799 | (tabulated-list-print remember-pos)) |
| 1723 | 1800 | ||
| 1724 | (defun package-menu--print-info (pkg) | 1801 | (defun package-menu--print-info (pkg) |
| @@ -2014,18 +2091,27 @@ The list is displayed in a buffer named `*Packages*'." | |||
| 2014 | (defalias 'package-list-packages 'list-packages) | 2091 | (defalias 'package-list-packages 'list-packages) |
| 2015 | 2092 | ||
| 2016 | ;; Used in finder.el | 2093 | ;; Used in finder.el |
| 2017 | (defun package-show-package-list (packages) | 2094 | (defun package-show-package-list (&optional packages keywords) |
| 2018 | "Display PACKAGES in a *Packages* buffer. | 2095 | "Display PACKAGES in a *Packages* buffer. |
| 2019 | This is similar to `list-packages', but it does not fetch the | 2096 | This is similar to `list-packages', but it does not fetch the |
| 2020 | updated list of packages, and it only displays packages with | 2097 | updated list of packages, and it only displays packages with |
| 2021 | names in PACKAGES (which should be a list of symbols)." | 2098 | names in PACKAGES (which should be a list of symbols). |
| 2099 | |||
| 2100 | When KEYWORDS are given, only packages with those KEYWORDS are | ||
| 2101 | shown." | ||
| 2102 | (interactive) | ||
| 2022 | (require 'finder-inf nil t) | 2103 | (require 'finder-inf nil t) |
| 2023 | (let ((buf (get-buffer-create "*Packages*"))) | 2104 | (let ((buf (get-buffer-create "*Packages*"))) |
| 2024 | (with-current-buffer buf | 2105 | (with-current-buffer buf |
| 2025 | (package-menu-mode) | 2106 | (package-menu-mode) |
| 2026 | (package-menu--generate nil packages)) | 2107 | (package-menu--generate nil packages keywords)) |
| 2027 | (switch-to-buffer buf))) | 2108 | (switch-to-buffer buf))) |
| 2028 | 2109 | ||
| 2110 | (defun package-menu-filter-interactive (keyword) | ||
| 2111 | "Filter the *Packages* buffer." | ||
| 2112 | (interactive (list (completing-read "Keyword: " (package-all-keywords)))) | ||
| 2113 | (package-show-package-list t (list keyword))) | ||
| 2114 | |||
| 2029 | (defun package-list-packages-no-fetch () | 2115 | (defun package-list-packages-no-fetch () |
| 2030 | "Display a list of packages. | 2116 | "Display a list of packages. |
| 2031 | Does not fetch the updated list of packages before displaying. | 2117 | Does not fetch the updated list of packages before displaying. |