aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChong Yidong2011-04-06 16:33:30 -0400
committerChong Yidong2011-04-06 16:33:30 -0400
commite91a96fefdc732b857532bfa827439efe520c47f (patch)
tree5aee0ed310810e9aa46a1ccb62c27f6493f4f1e6
parenta83ec3c99a6536a248c4806fbbafbc47c2047bc6 (diff)
downloademacs-e91a96fefdc732b857532bfa827439efe520c47f.tar.gz
emacs-e91a96fefdc732b857532bfa827439efe520c47f.zip
Make Package Menu a child of Tabulated List mode.
* emacs-lisp/package.el: Use Tabulated List mode. (package-menu-mode-map): Inherit from tabulated-list-mode-map. (package-menu-mode): Derive from tabulated-list-mode. Set up the table format using Tabulated List mode variables. (package--push): New macro, replacing package-list-maybe-add. (package-menu--generate): Use package--push. Renamed from package--generate-package-list. (package-menu-refresh, list-packages): Use it. (package-menu--print-info): Renamed from package-print-package. Return insertion data instead of inserting it directly. (package-menu-describe-package, package-menu-execute): Use tabulated-list-get-id. (package-menu-mark-delete, package-menu-mark-install) (package-menu-mark-unmark, package-menu-backup-unmark) (package-menu-mark-obsolete-for-deletion): Use tabulated-list-put-tag. (package--list-packages, package-menu-revert) (package-menu-get-package, package-menu-get-version) (package-menu-sort-by-column): Functions deleted. (package-menu-package-list, package-menu-sort-key): Vars deleted. (package-menu--status-predicate, package-menu--version-predicate) (package-menu--name-predicate) (package-menu--description-predicate): Handle arguments in the Tabulated List format. (package-list-packages-no-fetch): Call list-packages.
-rw-r--r--lisp/ChangeLog26
-rw-r--r--lisp/emacs-lisp/package.el460
2 files changed, 190 insertions, 296 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 133bf70d482..313b2e94a30 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -2,6 +2,32 @@
2 2
3 * emacs-lisp/tabulated-list.el: New file. 3 * emacs-lisp/tabulated-list.el: New file.
4 4
5 * emacs-lisp/package.el: Use Tabulated List mode.
6 (package-menu-mode-map): Inherit from tabulated-list-mode-map.
7 (package-menu-mode): Derive from tabulated-list-mode. Set up the
8 table format using Tabulated List mode variables.
9 (package--push): New macro, replacing package-list-maybe-add.
10 (package-menu--generate): Use package--push. Renamed from
11 package--generate-package-list.
12 (package-menu-refresh, list-packages): Use it.
13 (package-menu--print-info): Renamed from package-print-package.
14 Return insertion data instead of inserting it directly.
15 (package-menu-describe-package, package-menu-execute): Use
16 tabulated-list-get-id.
17 (package-menu-mark-delete, package-menu-mark-install)
18 (package-menu-mark-unmark, package-menu-backup-unmark)
19 (package-menu-mark-obsolete-for-deletion): Use
20 tabulated-list-put-tag.
21 (package--list-packages, package-menu-revert)
22 (package-menu-get-package, package-menu-get-version)
23 (package-menu-sort-by-column): Functions deleted.
24 (package-menu-package-list, package-menu-sort-key): Vars deleted.
25 (package-menu--status-predicate, package-menu--version-predicate)
26 (package-menu--name-predicate)
27 (package-menu--description-predicate): Handle arguments in the
28 Tabulated List format.
29 (package-list-packages-no-fetch): Call list-packages.
30
52011-04-06 Juanma Barranquero <lekktu@gmail.com> 312011-04-06 Juanma Barranquero <lekktu@gmail.com>
6 32
7 * files.el (after-find-file-from-revert-buffer): Remove variable. 33 * files.el (after-find-file-from-revert-buffer): Remove variable.
diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
index 6aecc3615f3..4ce71b29d70 100644
--- a/lisp/emacs-lisp/package.el
+++ b/lisp/emacs-lisp/package.el
@@ -173,6 +173,8 @@
173 173
174;;; Code: 174;;; Code:
175 175
176(require 'tabulated-list)
177
176(defgroup package nil 178(defgroup package nil
177 "Manager for Emacs Lisp packages." 179 "Manager for Emacs Lisp packages."
178 :group 'applications 180 :group 'applications
@@ -1249,12 +1251,10 @@ If optional arg NO-ACTIVATE is non-nil, don't activate packages."
1249;;;; Package menu mode. 1251;;;; Package menu mode.
1250 1252
1251(defvar package-menu-mode-map 1253(defvar package-menu-mode-map
1252 (let ((map (copy-keymap special-mode-map)) 1254 (let ((map (make-sparse-keymap))
1253 (menu-map (make-sparse-keymap "Package"))) 1255 (menu-map (make-sparse-keymap "Package")))
1254 (set-keymap-parent map button-buffer-map) 1256 (set-keymap-parent map tabulated-list-mode-map)
1255 (define-key map "\C-m" 'package-menu-describe-package) 1257 (define-key map "\C-m" 'package-menu-describe-package)
1256 (define-key map "n" 'next-line)
1257 (define-key map "p" 'previous-line)
1258 (define-key map "u" 'package-menu-mark-unmark) 1258 (define-key map "u" 'package-menu-mark-unmark)
1259 (define-key map "\177" 'package-menu-backup-unmark) 1259 (define-key map "\177" 'package-menu-backup-unmark)
1260 (define-key map "d" 'package-menu-mark-delete) 1260 (define-key map "d" 'package-menu-mark-delete)
@@ -1264,8 +1264,6 @@ If optional arg NO-ACTIVATE is non-nil, don't activate packages."
1264 (define-key map "x" 'package-menu-execute) 1264 (define-key map "x" 'package-menu-execute)
1265 (define-key map "h" 'package-menu-quick-help) 1265 (define-key map "h" 'package-menu-quick-help)
1266 (define-key map "?" 'package-menu-describe-package) 1266 (define-key map "?" 'package-menu-describe-package)
1267 (define-key map [follow-link] 'mouse-face)
1268 (define-key map [mouse-2] 'mouse-select-window)
1269 (define-key map [menu-bar package-menu] (cons "Package" menu-map)) 1267 (define-key map [menu-bar package-menu] (cons "Package" menu-map))
1270 (define-key menu-map [mq] 1268 (define-key menu-map [mq]
1271 '(menu-item "Quit" quit-window 1269 '(menu-item "Quit" quit-window
@@ -1314,49 +1312,93 @@ If optional arg NO-ACTIVATE is non-nil, don't activate packages."
1314 map) 1312 map)
1315 "Local keymap for `package-menu-mode' buffers.") 1313 "Local keymap for `package-menu-mode' buffers.")
1316 1314
1317(defvar package-menu-sort-button-map 1315(define-derived-mode package-menu-mode tabulated-list-mode "Package Menu"
1318 (let ((map (make-sparse-keymap)))
1319 (define-key map [header-line mouse-1] 'package-menu-sort-by-column)
1320 (define-key map [header-line mouse-2] 'package-menu-sort-by-column)
1321 (define-key map [follow-link] 'mouse-face)
1322 map)
1323 "Local keymap for package menu sort buttons.")
1324
1325(put 'package-menu-mode 'mode-class 'special)
1326
1327(define-derived-mode package-menu-mode special-mode "Package Menu"
1328 "Major mode for browsing a list of packages. 1316 "Major mode for browsing a list of packages.
1329Letters do not insert themselves; instead, they are commands. 1317Letters do not insert themselves; instead, they are commands.
1330\\<package-menu-mode-map> 1318\\<package-menu-mode-map>
1331\\{package-menu-mode-map}" 1319\\{package-menu-mode-map}"
1332 (setq truncate-lines t) 1320 (setq tabulated-list-format [("Package" 18 package-menu--name-predicate)
1333 (setq buffer-read-only t) 1321 ("Version" 12 nil)
1334 (set (make-local-variable 'revert-buffer-function) 'package-menu-revert) 1322 ("Status" 10 package-menu--status-predicate)
1335 (setq header-line-format 1323 ("Description" 0 nil)])
1336 (mapconcat 1324 (setq tabulated-list-padding 2)
1337 (lambda (pair) 1325 (setq tabulated-list-sort-key (cons "Status" nil))
1338 (let ((column (car pair)) 1326 (tabulated-list-init-header))
1339 (name (cdr pair))) 1327
1340 (concat 1328(defmacro package--push (package desc status listname)
1341 ;; Insert a space that aligns the button properly. 1329 "Convenience macro for `package-menu--generate'.
1342 (propertize " " 'display (list 'space :align-to column) 1330If the alist stored in the symbol LISTNAME lacks an entry for a
1343 'face 'fixed-pitch) 1331package PACKAGE with descriptor DESC, add one. The alist is
1344 ;; Set up the column button. 1332keyed with cons cells (PACKAGE . VERSION), where PACKAGE is a
1345 (propertize name 1333symbol and VERSION is a version list."
1346 'column-name name 1334 `(let* ((version (package-desc-vers ,desc))
1347 'help-echo "mouse-1: sort by column" 1335 (key (cons ,package version)))
1348 'mouse-face 'highlight 1336 (unless (assoc key ,listname)
1349 'keymap package-menu-sort-button-map)))) 1337 (push (list key ,status (package-desc-doc ,desc)) ,listname))))
1350 ;; We take a trick from buff-menu and have a dummy leading 1338
1351 ;; space to align the header line with the beginning of the 1339(defun package-menu--generate (&optional remember-pos)
1352 ;; text. This doesn't really work properly on Emacs 21, but 1340 "Populate the Package Menu.
1353 ;; it is close enough. 1341Optional argument REMEMBER-POS, if non-nil, means to move point
1354 '((0 . "") 1342to the entry as before."
1355 (2 . "Package") 1343 ;; Construct list of ((PACKAGE . VERSION) STATUS DESCRIPTION).
1356 (20 . "Version") 1344 (let (info-list name builtin)
1357 (32 . "Status") 1345 ;; Installed packages:
1358 (43 . "Description")) 1346 (dolist (elt package-alist)
1359 ""))) 1347 (setq name (car elt))
1348 (package--push name (cdr elt)
1349 (if (stringp (cadr (assq name package-load-list)))
1350 "held" "installed")
1351 info-list))
1352
1353 ;; Built-in packages:
1354 (dolist (elt package--builtins)
1355 (setq name (car elt))
1356 (unless (eq name 'emacs) ; Hide the `emacs' package.
1357 (package--push name (cdr elt) "built-in" info-list)))
1358
1359 ;; Available and disabled packages:
1360 (dolist (elt package-archive-contents)
1361 (setq name (car elt))
1362 (let ((hold (assq name package-load-list)))
1363 (package--push name (cdr elt)
1364 (if (and hold (null (cadr hold))) "disabled" "available")
1365 info-list)))
1366
1367 ;; Obsolete packages:
1368 (dolist (elt package-obsolete-alist)
1369 (dolist (inner-elt (cdr elt))
1370 (package--push (car elt) (cdr inner-elt) "obsolete" info-list)))
1371
1372 ;; Print the result.
1373 (setq tabulated-list-entries (mapcar 'package-menu--print-info info-list))
1374 (tabulated-list-print remember-pos)))
1375
1376(defun package-menu--print-info (pkg)
1377 "Return a package entry suitable for `tabulated-list-entries'.
1378PKG has the form ((PACKAGE . VERSION) STATUS DOC).
1379Return (KEY [NAME VERSION STATUS DOC]), where KEY is the
1380identifier (NAME . VERSION-LIST)."
1381 (let* ((package (caar pkg))
1382 (version (cdr (car pkg)))
1383 (status (nth 1 pkg))
1384 (doc (or (nth 2 pkg) ""))
1385 (face (cond
1386 ((string= status "built-in") 'font-lock-builtin-face)
1387 ((string= status "available") 'default)
1388 ((string= status "held") 'font-lock-constant-face)
1389 ((string= status "disabled") 'font-lock-warning-face)
1390 ((string= status "installed") 'font-lock-comment-face)
1391 (t 'font-lock-warning-face)))) ; obsolete.
1392 (list (cons package version)
1393 (vector (list (symbol-name package)
1394 'face 'link
1395 'follow-link t
1396 'package-symbol package
1397 'action 'package-menu-describe-package)
1398 (propertize (package-version-join version)
1399 'font-lock-face face)
1400 (propertize status 'font-lock-face face)
1401 (propertize doc 'font-lock-face face)))))
1360 1402
1361(defun package-menu-refresh () 1403(defun package-menu-refresh ()
1362 "Download the Emacs Lisp package archive. 1404 "Download the Emacs Lisp package archive.
@@ -1366,59 +1408,42 @@ This fetches the contents of each archive specified in
1366 (unless (eq major-mode 'package-menu-mode) 1408 (unless (eq major-mode 'package-menu-mode)
1367 (error "The current buffer is not a Package Menu")) 1409 (error "The current buffer is not a Package Menu"))
1368 (package-refresh-contents) 1410 (package-refresh-contents)
1369 (package--generate-package-list)) 1411 (package-menu--generate t))
1370 1412
1371(defun package-menu-revert (&optional arg noconfirm) 1413(defun package-menu-describe-package (&optional button)
1372 "Update the list of packages. 1414 "Describe the current package.
1373This function is the `revert-buffer-function' for Package Menu 1415If optional arg BUTTON is non-nil, describe its associated package."
1374buffers. The arguments are ignored."
1375 (interactive) 1416 (interactive)
1376 (unless (eq major-mode 'package-menu-mode) 1417 (let ((package (if button (button-get button 'package-symbol)
1377 (error "The current buffer is not a Package Menu")) 1418 (car (tabulated-list-get-id)))))
1378 (package--generate-package-list)) 1419 (if package
1379 1420 (describe-package package))))
1380(defun package-menu-describe-package ()
1381 "Describe the package in the current line."
1382 (interactive)
1383 (let ((name (package-menu-get-package)))
1384 (if name
1385 (describe-package (intern name))
1386 (message "No package on this line"))))
1387
1388(defun package-menu-mark-internal (what)
1389 (unless (eobp)
1390 (let ((buffer-read-only nil))
1391 (beginning-of-line)
1392 (delete-char 1)
1393 (insert what)
1394 (forward-line))))
1395 1421
1396;; fixme numeric argument 1422;; fixme numeric argument
1397(defun package-menu-mark-delete (num) 1423(defun package-menu-mark-delete (num)
1398 "Mark a package for deletion and move to the next line." 1424 "Mark a package for deletion and move to the next line."
1399 (interactive "p") 1425 (interactive "p")
1400 (if (string-equal (package-menu-get-status) "installed") 1426 (if (string-equal (package-menu-get-status) "installed")
1401 (package-menu-mark-internal "D") 1427 (tabulated-list-put-tag "D" t)
1402 (forward-line))) 1428 (forward-line)))
1403 1429
1404(defun package-menu-mark-install (num) 1430(defun package-menu-mark-install (num)
1405 "Mark a package for installation and move to the next line." 1431 "Mark a package for installation and move to the next line."
1406 (interactive "p") 1432 (interactive "p")
1407 (if (string-equal (package-menu-get-status) "available") 1433 (if (string-equal (package-menu-get-status) "available")
1408 (package-menu-mark-internal "I") 1434 (tabulated-list-put-tag "I" t)
1409 (forward-line))) 1435 (forward-line)))
1410 1436
1411(defun package-menu-mark-unmark (num) 1437(defun package-menu-mark-unmark (num)
1412 "Clear any marks on a package and move to the next line." 1438 "Clear any marks on a package and move to the next line."
1413 (interactive "p") 1439 (interactive "p")
1414 (package-menu-mark-internal " ")) 1440 (tabulated-list-put-tag " " t))
1415 1441
1416(defun package-menu-backup-unmark () 1442(defun package-menu-backup-unmark ()
1417 "Back up one line and clear any marks on that package." 1443 "Back up one line and clear any marks on that package."
1418 (interactive) 1444 (interactive)
1419 (forward-line -1) 1445 (forward-line -1)
1420 (package-menu-mark-internal " ") 1446 (tabulated-list-put-tag " "))
1421 (forward-line -1))
1422 1447
1423(defun package-menu-mark-obsolete-for-deletion () 1448(defun package-menu-mark-obsolete-for-deletion ()
1424 "Mark all obsolete packages for deletion." 1449 "Mark all obsolete packages for deletion."
@@ -1428,7 +1453,7 @@ buffers. The arguments are ignored."
1428 (forward-line 2) 1453 (forward-line 2)
1429 (while (not (eobp)) 1454 (while (not (eobp))
1430 (if (looking-at ".*\\s obsolete\\s ") 1455 (if (looking-at ".*\\s obsolete\\s ")
1431 (package-menu-mark-internal "D") 1456 (tabulated-list-put-tag "D" t)
1432 (forward-line 1))))) 1457 (forward-line 1)))))
1433 1458
1434(defun package-menu-quick-help () 1459(defun package-menu-quick-help ()
@@ -1439,20 +1464,6 @@ buffers. The arguments are ignored."
1439(define-obsolete-function-alias 1464(define-obsolete-function-alias
1440 'package-menu-view-commentary 'package-menu-describe-package "24.1") 1465 'package-menu-view-commentary 'package-menu-describe-package "24.1")
1441 1466
1442;; Return the name of the package on the current line.
1443(defun package-menu-get-package ()
1444 (save-excursion
1445 (beginning-of-line)
1446 (if (looking-at ". \\([^ \t]*\\)")
1447 (match-string-no-properties 1))))
1448
1449;; Return the version of the package on the current line.
1450(defun package-menu-get-version ()
1451 (save-excursion
1452 (beginning-of-line)
1453 (if (looking-at ". [^ \t]*[ \t]*\\([0-9.]*\\)")
1454 (match-string 1))))
1455
1456(defun package-menu-get-status () 1467(defun package-menu-get-status ()
1457 (save-excursion 1468 (save-excursion
1458 (if (looking-at ". [^ \t]*[ \t]*[^ \t]*[ \t]*\\([^ \t]*\\)") 1469 (if (looking-at ". [^ \t]*[ \t]*[^ \t]*[ \t]*\\([^ \t]*\\)")
@@ -1464,19 +1475,22 @@ buffers. The arguments are ignored."
1464Packages marked for installation are downloaded and installed; 1475Packages marked for installation are downloaded and installed;
1465packages marked for deletion are removed." 1476packages marked for deletion are removed."
1466 (interactive) 1477 (interactive)
1467 (let (install-list delete-list cmd) 1478 (unless (eq major-mode 'package-menu-mode)
1479 (error "The current buffer is not in Package Menu mode"))
1480 (let (install-list delete-list cmd id)
1468 (save-excursion 1481 (save-excursion
1469 (goto-char (point-min)) 1482 (goto-char (point-min))
1470 (while (not (eobp)) 1483 (while (not (eobp))
1471 (setq cmd (char-after)) 1484 (setq cmd (char-after))
1472 (cond 1485 (unless (eq cmd ?\s)
1473 ((eq cmd ?\s) t) 1486 ;; This is the key (PACKAGE . VERSION-LIST).
1474 ((eq cmd ?D) 1487 (setq id (tabulated-list-get-id))
1475 (push (cons (package-menu-get-package) 1488 (cond ((eq cmd ?D)
1476 (package-menu-get-version)) 1489 (push (cons (symbol-name (car id))
1477 delete-list)) 1490 (package-version-join (cdr id)))
1478 ((eq cmd ?I) 1491 delete-list))
1479 (push (package-menu-get-package) install-list))) 1492 ((eq cmd ?I)
1493 (push (car id) install-list))))
1480 (forward-line))) 1494 (forward-line)))
1481 ;; Delete packages, prompting if necessary. 1495 ;; Delete packages, prompting if necessary.
1482 (when delete-list 1496 (when delete-list
@@ -1502,217 +1516,71 @@ packages marked for deletion are removed."
1502 (format "Install package `%s'? " (car install-list)) 1516 (format "Install package `%s'? " (car install-list))
1503 (format "Install these %d packages (%s)? " 1517 (format "Install these %d packages (%s)? "
1504 (length install-list) 1518 (length install-list)
1505 (mapconcat 'identity install-list ", ")))) 1519 (mapconcat 'symbol-name install-list ", "))))
1506 (dolist (elt install-list) 1520 (mapc 'package-install install-list)))
1507 (package-install (intern elt)))))
1508 ;; If we deleted anything, regenerate `package-alist'. This is done 1521 ;; If we deleted anything, regenerate `package-alist'. This is done
1509 ;; automatically if we installed a package. 1522 ;; automatically if we installed a package.
1510 (and delete-list (null install-list) 1523 (and delete-list (null install-list)
1511 (package-initialize)) 1524 (package-initialize))
1512 (if (or delete-list install-list) 1525 (if (or delete-list install-list)
1513 (package-menu-revert) 1526 (package-menu--generate t)
1514 (message "No operations specified.")))) 1527 (message "No operations specified."))))
1515 1528
1516(defun package-print-package (package version key desc) 1529(defun package-menu--version-predicate (A B)
1517 (let ((face 1530 (let ((vA (or (aref (cadr A) 1) '(0)))
1518 (cond ((string= key "built-in") 'font-lock-builtin-face) 1531 (vB (or (aref (cadr B) 1) '(0))))
1519 ((string= key "available") 'default) 1532 (if (version-list-= vA vB)
1520 ((string= key "held") 'font-lock-constant-face) 1533 (package-menu--name-predicate A B)
1521 ((string= key "disabled") 'font-lock-warning-face) 1534 (version-list-< vA vB))))
1522 ((string= key "installed") 'font-lock-comment-face) 1535
1523 (t ; obsolete, but also the default. 1536(defun package-menu--status-predicate (A B)
1524 'font-lock-warning-face)))) 1537 (let ((sA (aref (cadr A) 2))
1525 (insert (propertize " " 'font-lock-face face)) 1538 (sB (aref (cadr B) 2)))
1526 (insert-text-button (symbol-name package) 1539 (cond ((string= sA sB)
1527 'face 'link 1540 (package-menu--name-predicate A B))
1528 'follow-link t 1541 ((string= sA "available") t)
1529 'package-symbol package 1542 ((string= sB "available") nil)
1530 'action (lambda (button) 1543 ((string= sA "installed") t)
1531 (describe-package 1544 ((string= sB "installed") nil)
1532 (button-get button 'package-symbol)))) 1545 ((string= sA "held") t)
1533 (indent-to 20 1) 1546 ((string= sB "held") nil)
1534 (insert (propertize (package-version-join version) 'font-lock-face face)) 1547 ((string= sA "built-in") t)
1535 (indent-to 32 1) 1548 ((string= sB "built-in") nil)
1536 (insert (propertize key 'font-lock-face face)) 1549 ((string= sA "obsolete") t)
1537 ;; FIXME: this 'when' is bogus... 1550 ((string= sB "obsolete") nil)
1538 (when desc 1551 (t (string< sA sB)))))
1539 (indent-to 43 1) 1552
1540 (let ((opoint (point))) 1553(defun package-menu--description-predicate (A B)
1541 (insert (propertize desc 'font-lock-face face)) 1554 (let ((dA (aref (cadr A) 3))
1542 (upcase-region opoint (min (point) (1+ opoint))))) 1555 (dB (aref (cadr B) 3)))
1543 (insert "\n"))) 1556 (if (string= dA dB)
1544 1557 (package-menu--name-predicate A B)
1545(defun package-list-maybe-add (package version status description result) 1558 (string< dA dB))))
1546 (unless (assoc (cons package version) result) 1559
1547 (push (list (cons package version) status description) result)) 1560(defun package-menu--name-predicate (A B)
1548 result) 1561 (string< (symbol-name (caar A))
1549 1562 (symbol-name (caar B))))
1550(defvar package-menu-package-list nil
1551 "List of packages to display in the Package Menu buffer.
1552A value of nil means to display all packages.")
1553
1554(defvar package-menu-sort-key nil
1555 "Sort key for the current Package Menu buffer.")
1556
1557(defun package--generate-package-list ()
1558 "Populate the current Package Menu buffer."
1559 (let ((inhibit-read-only t)
1560 info-list name desc hold builtin)
1561 (erase-buffer)
1562 ;; List installed packages
1563 (dolist (elt package-alist)
1564 (setq name (car elt))
1565 (when (or (null package-menu-package-list)
1566 (memq name package-menu-package-list))
1567 (setq desc (cdr elt)
1568 hold (cadr (assq name package-load-list)))
1569 (setq info-list
1570 (package-list-maybe-add
1571 name (package-desc-vers desc)
1572 ;; FIXME: it turns out to be tricky to see if this
1573 ;; package is presently activated.
1574 (if (stringp hold) "held" "installed")
1575 (package-desc-doc desc)
1576 info-list))))
1577
1578 ;; List built-in packages
1579 (dolist (elt package--builtins)
1580 (setq name (car elt))
1581 (when (and (not (eq name 'emacs)) ; Hide the `emacs' package.
1582 (or (null package-menu-package-list)
1583 (memq name package-menu-package-list)))
1584 (setq desc (cdr elt))
1585 (setq info-list
1586 (package-list-maybe-add
1587 name (package-desc-vers desc)
1588 "built-in"
1589 (package-desc-doc desc)
1590 info-list))))
1591
1592 ;; List available and disabled packages
1593 (dolist (elt package-archive-contents)
1594 (setq name (car elt)
1595 desc (cdr elt)
1596 hold (assq name package-load-list))
1597 (when (or (null package-menu-package-list)
1598 (memq name package-menu-package-list))
1599 (setq info-list
1600 (package-list-maybe-add name
1601 (package-desc-vers desc)
1602 (if (and hold (null (cadr hold)))
1603 "disabled"
1604 "available")
1605 (package-desc-doc (cdr elt))
1606 info-list))))
1607 ;; List obsolete packages
1608 (mapc (lambda (elt)
1609 (mapc (lambda (inner-elt)
1610 (setq info-list
1611 (package-list-maybe-add (car elt)
1612 (package-desc-vers
1613 (cdr inner-elt))
1614 "obsolete"
1615 (package-desc-doc
1616 (cdr inner-elt))
1617 info-list)))
1618 (cdr elt)))
1619 package-obsolete-alist)
1620
1621 (setq info-list
1622 (sort info-list
1623 (cond ((string= package-menu-sort-key "Package")
1624 'package-menu--name-predicate)
1625 ((string= package-menu-sort-key "Version")
1626 'package-menu--version-predicate)
1627 ((string= package-menu-sort-key "Description")
1628 'package-menu--description-predicate)
1629 (t ; By default, sort by package status
1630 'package-menu--status-predicate))))
1631
1632 (dolist (elt info-list)
1633 (package-print-package (car (car elt))
1634 (cdr (car elt))
1635 (car (cdr elt))
1636 (car (cdr (cdr elt)))))
1637 (goto-char (point-min))
1638 (set-buffer-modified-p nil)
1639 (current-buffer)))
1640
1641(defun package-menu--version-predicate (left right)
1642 (let ((vleft (or (cdr (car left)) '(0)))
1643 (vright (or (cdr (car right)) '(0))))
1644 (if (version-list-= vleft vright)
1645 (package-menu--name-predicate left right)
1646 (version-list-< vleft vright))))
1647
1648(defun package-menu--status-predicate (left right)
1649 (let ((sleft (cadr left))
1650 (sright (cadr right)))
1651 (cond ((string= sleft sright)
1652 (package-menu--name-predicate left right))
1653 ((string= sleft "available") t)
1654 ((string= sright "available") nil)
1655 ((string= sleft "installed") t)
1656 ((string= sright "installed") nil)
1657 ((string= sleft "held") t)
1658 ((string= sright "held") nil)
1659 ((string= sleft "built-in") t)
1660 ((string= sright "built-in") nil)
1661 ((string= sleft "obsolete") t)
1662 ((string= sright "obsolete") nil)
1663 (t (string< sleft sright)))))
1664
1665(defun package-menu--description-predicate (left right)
1666 (let ((sleft (car (cddr left)))
1667 (sright (car (cddr right))))
1668 (if (string= sleft sright)
1669 (package-menu--name-predicate left right)
1670 (string< sleft sright))))
1671
1672(defun package-menu--name-predicate (left right)
1673 (string< (symbol-name (caar left))
1674 (symbol-name (caar right))))
1675
1676(defun package-menu-sort-by-column (&optional e)
1677 "Sort the package menu by the column of the mouse click E."
1678 (interactive "e")
1679 (let* ((pos (event-start e))
1680 (obj (posn-object pos))
1681 (col (if obj
1682 (get-text-property (cdr obj) 'column-name (car obj))
1683 (get-text-property (posn-point pos) 'column-name)))
1684 (buf (window-buffer (posn-window (event-start e)))))
1685 (with-current-buffer buf
1686 (when (eq major-mode 'package-menu-mode)
1687 (setq package-menu-sort-key col)
1688 (package--generate-package-list)))))
1689
1690(defun package--list-packages (&optional packages)
1691 "Generate and pop to the *Packages* buffer.
1692Optional PACKAGES is a list of names of packages (symbols) to
1693list; the default is to display everything in `package-alist'."
1694 (require 'finder-inf nil t)
1695 (let ((buf (get-buffer-create "*Packages*")))
1696 (with-current-buffer buf
1697 (package-menu-mode)
1698 (set (make-local-variable 'package-menu-package-list) packages)
1699 (set (make-local-variable 'package-menu-sort-key) nil)
1700 (package--generate-package-list))
1701 ;; The package menu buffer has keybindings. If the user types
1702 ;; `M-x list-packages', that suggests it should become current.
1703 (switch-to-buffer buf)))
1704 1563
1705;;;###autoload 1564;;;###autoload
1706(defun list-packages () 1565(defun list-packages (&optional no-fetch)
1707 "Display a list of packages. 1566 "Display a list of packages.
1708Fetches the updated list of packages before displaying. 1567This first fetches the updated list of packages before
1568displaying, unless a prefix argument NO-FETCH is specified.
1709The list is displayed in a buffer named `*Packages*'." 1569The list is displayed in a buffer named `*Packages*'."
1710 (interactive) 1570 (interactive "P")
1571 (require 'finder-inf nil t)
1711 ;; Initialize the package system if necessary. 1572 ;; Initialize the package system if necessary.
1712 (unless package--initialized 1573 (unless package--initialized
1713 (package-initialize t)) 1574 (package-initialize t))
1714 (package-refresh-contents) 1575 (unless no-fetch
1715 (package--list-packages)) 1576 (package-refresh-contents))
1577 (let ((buf (get-buffer-create "*Packages*")))
1578 (with-current-buffer buf
1579 (package-menu-mode)
1580 (package-menu--generate))
1581 ;; The package menu buffer has keybindings. If the user types
1582 ;; `M-x list-packages', that suggests it should become current.
1583 (switch-to-buffer buf)))
1716 1584
1717;;;###autoload 1585;;;###autoload
1718(defalias 'package-list-packages 'list-packages) 1586(defalias 'package-list-packages 'list-packages)
@@ -1722,7 +1590,7 @@ The list is displayed in a buffer named `*Packages*'."
1722Does not fetch the updated list of packages before displaying. 1590Does not fetch the updated list of packages before displaying.
1723The list is displayed in a buffer named `*Packages*'." 1591The list is displayed in a buffer named `*Packages*'."
1724 (interactive) 1592 (interactive)
1725 (package--list-packages)) 1593 (list-packages t))
1726 1594
1727(provide 'package) 1595(provide 'package)
1728 1596