xemacs-21.4 / lisp / package-ui.el

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
;;; package-ui.el ---

;; Copyright (C) 1998 by Darryl Okahata

;; Author: Darryl Okahata <darrylo@sr.hp.com>
;; Keywords: internal

;; This file is part of XEmacs.

;; XEmacs is free software; you can redistribute it and/or modify it
;; under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.

;; XEmacs is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;; General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with XEmacs; see the file COPYING.  If not, write to the Free
;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
;; 02111-1307, USA.

;;; Synched up with: Not in FSF

(require 'package-get)		;; which, in turn, requires 'package-admin

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; User-changeable variables:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defgroup pui nil
  "Conventient interface to the package system."
  :group 'package-tools
  :tag "Package User interface"
  :prefix "pui-")

(defcustom pui-package-install-dest-dir nil
  "*If non-nil (Automatic) path to package tree to install packages in.
Otherwise, use old path for installed packages and make a guess for
new ones."
  :group 'pui
  :tag "Install Location"
  :type '(choice (const :tag "Automatic" nil)
		 (directory)))
		 
(defcustom pui-list-verbose t
  "*If non-nil, display verbose info in the package list buffer."
  :group 'pui
  :tag "Verbose Listing"
  :type 'boolean)

(defcustom pui-up-to-date-package-face nil
  "*The face to use for packages that are up-to-date."
  :group 'pui
  :type 'face)

(defcustom pui-selected-package-face 'bold
  "*The face to use for selected packages.
Set this to `nil' to use the `default' face."
  :group 'pui
  :type 'face)

(defcustom pui-deleted-package-face 'blue
  "*The face to use for packages marked for removal.
Set this to `nil' to use the `default' face."
  :group 'pui
  :type 'face)

(defcustom pui-outdated-package-face 'red
  "*The face to use for outdated packages.
Set this to `nil' to use the `default' face."
  :group 'pui
  :type 'face)

(defcustom pui-uninstalled-package-face 'italic
  "*The face to use for uninstalled packages.
Set this to `nil' to use the `default' face."
   :group 'pui
   :type 'face)
   



(defvar pui-info-buffer "*Packages*"
  "Buffer to use for displaying package information.")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; End of user-changeable variables.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defvar pui-selected-packages nil
  "The list of user-selected packages to install.")

(defvar pui-deleted-packages nil
  "The list of user-selected packages to remove.")

(defvar pui-actual-package "")

(defvar pui-display-keymap
  (let ((m (make-keymap)))
    (suppress-keymap m)
    (set-keymap-name m 'pui-display-keymap)
    (define-key m "q" 'pui-quit)
    (define-key m "g" 'pui-list-packages)
    (define-key m "i" 'pui-display-info)
    (define-key m "?" 'describe-mode)
    (define-key m "v" 'pui-toggle-verbosity-redisplay)
    (define-key m "d" 'pui-toggle-package-delete-key)
    (define-key m "D" 'pui-toggle-package-delete-key)
    (define-key m [return] 'pui-toggle-package-key)
    (define-key m "x" 'pui-install-selected-packages)
    (define-key m "I" 'pui-install-selected-packages)
    (define-key m "r" 'pui-add-required-packages)
    (define-key m "n" 'next-line)
    (define-key m "+" 'pui-toggle-package-key)
    (define-key m "p" 'previous-line)
    (define-key m " " 'scroll-up-command)
    (define-key m [delete] 'scroll-down-command)
    m)
  "Keymap to use in the `pui-info-buffer' buffer")

(defvar pui-package-keymap
  (let ((m (make-sparse-keymap)))
    (set-keymap-name m 'pui-package-keymap)
    (define-key m 'button2 'pui-toggle-package-event)
;; We use a popup menu    
    (define-key m 'button3 'pui-popup-context-sensitive)
    m)
  "Keymap to use over package names/descriptions.")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; End of variables


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Configuration routines

(defun pui-directory-exists (dir)
  "Check to see if DIR exists in `package-get-remote'."
  (let (found)
    (mapcar #'(lambda (item)
		(if (and (null (car item))
			 (string-equal (file-name-as-directory (car (cdr item)))
				       (file-name-as-directory dir)))
		    (setq found t)))
	    package-get-remote)
    found
    ))

(defun pui-package-dir-list (buffer)
  "In BUFFER, format the list of package binary paths."
  (let ( (count 1) paths sys dir)
    (set-buffer buffer)
    (buffer-disable-undo buffer)
    (erase-buffer buffer)
    (insert "Existing package binary paths:\n\n")
    (setq paths package-get-remote)
    (while paths
      (setq sys (car (car paths))
	    dir (car (cdr (car paths))))
      (insert (format "%2s. " count))
      (if (null sys)
	  (insert dir)
	(insert sys ":" dir))
      (insert "\n")
      (setq count (1+ count))
      (setq paths (cdr paths))
      )
    (insert "\nThese are the places that will be searched for package binaries.\n")
    (goto-char (point-min))
    ))

;;;###autoload
(defun package-ui-add-site (site)
  "Add site to package-get-remote and possibly offer to update package list."
  (let ((had-none (null package-get-remote)))
    (push site package-get-remote)    
    (when (and had-none package-get-was-current
	       (y-or-n-p "Update Package list?"))
      (setq package-get-was-current nil)
      (package-get-require-base t)
      (if (get-buffer pui-info-buffer)
	  (save-window-excursion
	    (pui-list-packages))))
    (set-menubar-dirty-flag)))
    

;;;###autoload
(defun pui-add-install-directory (dir)
  "Add a new package binary directory to the head of `package-get-remote'.
Note that no provision is made for saving any changes made by this function.
It exists mainly as a convenience for one-time package installations from
disk."
  (interactive (let ( (tmpbuf (get-buffer-create
			       "*Existing Package Binary Paths*"))
		      dir)
		 (save-window-excursion
		   (save-excursion
		     (unwind-protect
			 (progn
			   (pui-package-dir-list tmpbuf)
			   (display-buffer tmpbuf)
			   (setq dir (read-directory-name
				      "New package binary directory to add? "
				      nil nil t))
			   )
		       (kill-buffer tmpbuf)
		       )))
		 (list dir)
		 ))
  (progn
    (if (not (pui-directory-exists dir))
	(progn
	  (setq package-get-remote (cons (list nil dir) package-get-remote))
	  (message "Package directory \"%s\" added." dir)
	  )
      (message "Directory \"%s\" already exists in `package-get-remote'." dir))
    ))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Package list/installer routines

(defun pui-quit ()
  (interactive)
  (kill-buffer nil))

(defun pui-package-symbol-char (pkg-sym version)
  (progn
    (if (package-get-info-find-package packages-package-list pkg-sym)
        (let ((installed (package-get-key pkg-sym :version)))
          (if (>= (if (stringp installed)
                      (string-to-number installed)
                    installed)
                  (if (stringp version)
                      (string-to-number version)
                    version))
              (list " " pui-up-to-date-package-face)
            (list "*" pui-outdated-package-face)))
      (list "-" pui-uninstalled-package-face))
    ))

(defun pui-update-package-display (extent &optional pkg-sym version)
  "Update the package status for EXTENT.
If PKG-SYM or VERSION are not given, they are read from the extent.
These are used to determine whether or not the package is installed,
and whether or not it is up-to-date."
  (let (buffer-read-only disp sym-char)
    (if (not pkg-sym)
	(setq pkg-sym (extent-property extent 'pui-package)))
    (if (not version)
	(setq version (package-get-info-prop (extent-property extent 'pui-info)
					     'version)))
    (cond ((member pkg-sym pui-selected-packages)
	     (if pui-selected-package-face
		 (set-extent-face extent (get-face pui-selected-package-face))
	       (set-extent-face extent (get-face 'default)))
	     (setq sym-char "+"))
	  ((member pkg-sym pui-deleted-packages)
	   (if pui-deleted-package-face
		 (set-extent-face extent (get-face pui-deleted-package-face))
	       (set-extent-face extent (get-face 'default)))
	     (setq sym-char "D"))
	  (t
	   (setq disp (pui-package-symbol-char pkg-sym version))
	   (setq sym-char (car disp))
	   (if (car (cdr disp))
	       (set-extent-face extent (get-face (car (cdr disp))))
	     (set-extent-face extent (get-face 'default)))))
    (save-excursion
      (goto-char (extent-start-position extent))
      (delete-char 1)
      (insert sym-char)
      (set-buffer-modified-p nil)
      )
    ))

(defun pui-toggle-package (extent)
  (let (pkg-sym)
    (setq pkg-sym (extent-property extent 'pui-package))
    (if (member pkg-sym pui-selected-packages)
	(setq pui-selected-packages
	      (delete pkg-sym pui-selected-packages))
      (setq pui-selected-packages
	    (cons pkg-sym pui-selected-packages))
      (setq pui-deleted-packages
	    (delete pkg-sym pui-deleted-packages)))
    (pui-update-package-display extent pkg-sym)
    ))

(defun pui-toggle-package-key ()
  "Select/unselect package for installation, using the keyboard."
  (interactive)
  (let (extent)
    (if (setq extent (extent-at (point) (current-buffer) 'pui))
	(progn
	  (pui-toggle-package extent)
	  (forward-line 1)
	  )
      (error "No package under cursor!"))
    ))

(defun pui-toggle-package-delete (extent)
  (let (pkg-sym)
    (setq pkg-sym (extent-property extent 'pui-package))
    (if (member pkg-sym pui-deleted-packages)
	(setq pui-deleted-packages
	      (delete pkg-sym pui-deleted-packages))
      (setq pui-deleted-packages
	    (cons pkg-sym pui-deleted-packages))
      (setq pui-seleted-packages
	    (delete pkg-sym pui-selected-packages)))
    (pui-update-package-display extent pkg-sym)
    ))
  

(defun pui-toggle-package-delete-key ()
  "Select/unselect package for removal, using the keyboard."
  (interactive)
  (let (extent)
    (if (setq extent (extent-at (point) (current-buffer) 'pui))
	(progn
	  (pui-toggle-package-delete extent)
	  (forward-line 1)
	  )
      (error "No package under cursor!"))
    ))

(defun pui-current-package ()
  (let ((extent (extent-at (point) (current-buffer) 'pui)))
    (if extent
	(extent-property extent 'pui-package))))

(defun pui-toggle-package-event (event)
  "Select/unselect package for installation, using the mouse."
  (interactive "e")
  (let* ( (ep (event-point event))
          (buffer (window-buffer (event-window event)))
          (extent (extent-at ep buffer 'pui-package))
          )
    (pui-toggle-package extent)
    ))

(defun pui-toggle-verbosity-redisplay ()
  "Toggle verbose package info."
  (interactive)
  (progn
    (setq pui-list-verbose (not pui-list-verbose))
    (pui-list-packages)
    ))

(defun pui-install-selected-packages ()
  "Install selected packages."
  (interactive)
  (let ( (tmpbuf "*Packages-To-Remove*") do-delete)
    (when pui-deleted-packages
      (save-window-excursion
	(with-output-to-temp-buffer tmpbuf
	  (display-completion-list (sort
				    (mapcar #'symbol-name pui-deleted-packages)
				    #'string<)
				   :activate-callback nil
				   :help-string "Packages selected for removal:\n"
				   :completion-string t
				   ))
	(setq tmpbuf (get-buffer-create tmpbuf))
	(display-buffer tmpbuf)
	(setq do-delete (yes-or-no-p "Remove these packages? "))
	(kill-buffer tmpbuf))	    
      (when do-delete
	(message "Deleting selected packages ...") (sit-for 0)
	(mapcar (lambda (pkg)
		  (package-admin-delete-binary-package
		   pkg (package-admin-get-install-dir pkg nil)))
		pui-deleted-packages)
	(message "Packages deleted"))))
	 
  (let ( (tmpbuf "*Packages-To-Install*") do-install)
    (if pui-selected-packages
	(progn
	  ;; Don't change window config when asking the user if he really
	  ;; wants to install the packages.  We do this to avoid messing up
	  ;; the window configuration if errors occur (we don't want to
	  ;; display random buffers in addition to the error buffer, if
	  ;; errors occur, which would normally be caused by display-buffer).
	  (save-window-excursion
	    (with-output-to-temp-buffer tmpbuf
	      (display-completion-list
	       (sort (mapcar #'symbol-name pui-selected-packages) #'string<)
	       :activate-callback nil
	       :help-string "Packages selected for installation:\n"
	       :completion-string t
	       ))
	    (setq tmpbuf (get-buffer-create tmpbuf))
	    (display-buffer tmpbuf)
	    (setq do-install (y-or-n-p "Install these packages? "))
	    (kill-buffer tmpbuf)
	    )
	  (if do-install
	      (progn
		(save-excursion
		  ;; Clear old temp buffer history
		  (set-buffer (get-buffer-create package-admin-temp-buffer))
		  (buffer-disable-undo package-admin-temp-buffer)
		  (erase-buffer package-admin-temp-buffer)
		  )
		(message "Installing selected packages ...") (sit-for 0)
		(if (catch 'done
		      (mapcar (lambda (pkg)
				(if (not (package-get pkg nil nil
                                                      pui-package-install-dest-dir))
				    (throw 'done nil)))
			      pui-selected-packages)
		      t)
		    (progn
		      (pui-list-packages)
		      (message "Packages installed")
		      ))
		)
	    (clear-message)
	    )
	  )
      (if pui-deleted-packages
	  (pui-list-packages)
	(error "No packages have been selected!")))
    ))

(defun pui-add-required-packages ()
  "Select packages required by those already selected for installation."
  (interactive)
  (let ((tmpbuf "*Required-Packages*") do-select)
    (if pui-selected-packages
	(let ((dependencies
               (delq nil (mapcar
                          (lambda (pkg)
                            (let ((installed
                                   (package-get-key pkg :version))
                                  (current
                                   (package-get-info-prop
                                    (package-get-info-version
                                     (package-get-info-find-package
                                      package-get-base pkg) nil)
                                    'version)))
                              (if (or (null installed)
                                     (< (if (stringp installed)
                                         (string-to-number installed)
                                       installed)
                                     (if (stringp current)
                                         (string-to-number current)
                                       current)))
                                  pkg
                                nil)))
                          (package-get-dependencies pui-selected-packages)))))
	  ;; Don't change window config when asking the user if he really
	  ;; wants to add the packages.  We do this to avoid messing up
	  ;; the window configuration if errors occur (we don't want to
	  ;; display random buffers in addition to the error buffer, if
	  ;; errors occur, which would normally be caused by display-buffer).
	  (save-window-excursion
	    (with-output-to-temp-buffer tmpbuf
	      (display-completion-list (sort
					(mapcar #'(lambda (pkg)
                                                    (symbol-name pkg))
						dependencies)
					'string<)
				       :activate-callback nil
				       :help-string "Required packages:\n"
				       :completion-string t))
	    (setq tmpbuf (get-buffer-create tmpbuf))
	    (display-buffer tmpbuf)
	    (setq do-select (y-or-n-p "Select these packages? "))
	    (kill-buffer tmpbuf))
	  (if do-select
              (progn
                (setq pui-selected-packages
                      (union pui-selected-packages dependencies))
                (map-extents #'(lambda (extent maparg)
                                 (pui-update-package-display extent))
                             nil nil nil nil nil 'pui)
                (message "added dependencies"))
	      (clear-message)))
      (error "No packages have been selected!"))))

(defun pui-help-echo (extent &optional force-update)
  "Display additional package info in the modeline.
EXTENT determines the package to display (the package information is
attached to the extent as properties)."
  (let (pkg-sym info inst-ver auth-ver date maintainer)
    (if (or force-update (not (current-message))
	    (string-match ".*: .*: " (current-message))
	    )
	(progn
	  (setq pkg-sym (extent-property extent 'pui-package)
		info (extent-property extent 'pui-info)
		inst-ver (package-get-key pkg-sym :version)
		auth-ver (package-get-info-prop info 'author-version)
		date (package-get-info-prop info 'date)
		maintainer (package-get-info-prop info 'maintainer))
	  (if (not inst-ver)
	      (setq inst-ver ""))
	  (if pui-list-verbose
	      (format "Author version: %-8s %11s: %s"
		      auth-ver date maintainer)
	    (format "%-6s: %-8s %11s: %s"
		    inst-ver auth-ver date maintainer))
	  ))
    ))

(defun pui-display-info (&optional no-error event)
  "Display additional package info in the modeline.
Designed to be called interactively (from a keypress)."
  (interactive)
  (let (extent)
    (save-excursion
      (beginning-of-line)
      (if (setq extent 	(extent-at (point) (current-buffer) 'pui))
	  (message (pui-help-echo extent t))
	(if no-error
	    (clear-message nil)
	  (error "No package under cursor!")))
      )))

;;; "Why is there no standard function to do this?"
(defun pui-popup-context-sensitive (event)
  (interactive "e")
  (save-excursion
    (set-buffer (event-buffer event))
    (goto-char (event-point event))
    (popup-menu pui-menu event)
    ;; I agree with dired.el - this is seriously bogus.
    (while (popup-menu-up-p)
      (dispatch-event (next-event)))))

(defvar pui-menu
  '("Packages"
    ["Toggle install " pui-toggle-package-key :active (pui-current-package) :suffix (format "`%s'" (or (pui-current-package) "..."))]
    ["Toggle delete " pui-toggle-package-delete-key :active (pui-current-package) :suffix (format "`%s'" (or (pui-current-package) "..."))]
    ["Info on" pui-display-info  :active (pui-current-package) :suffix (format "`%s'" (or (pui-current-package) "..."))]
    "---"
    ["Add Required" pui-add-required-packages t]
    ["Install/Remove Selected" pui-install-selected-packages t]
    "---"
    ["Verbose" pui-toggle-verbosity-redisplay
     :active t :style toggle :selected pui-list-verbose]
    ["Refresh" pui-list-packages t]
    ["Help" pui-help t]
    ["Quit" pui-quit t]))


(defun list-packages-mode ()
    "Symbols in the leftmost column:

  +	The package is marked for installation.
  -     The package has not been installed.
  D     The package has been marked for deletion.
  *     The currently installed package is old, and a newer version is
	available.

Useful keys:

  `\\[pui-toggle-package-key]' to select/unselect the current package for installation.
  `\\[pui-toggle-package-delete-key]' to select/unselect the current package for removal.
  `\\[pui-add-required-packages]' to add any packages required by those selected.
  `\\[pui-install-selected-packages]' to install/delete selected packages.
  `\\[pui-display-info]' to display additional information about the package in the modeline.
  `\\[pui-list-packages]' to refresh the package list.
  `\\[pui-toggle-verbosity-redisplay]' to toggle between a verbose and non-verbose display.
  `\\[pui-quit]' to kill this buffer.
"
  (error "You cannot enter this mode directly. Use `pui-list-packages'"))

(put 'list-packages-mode 'mode-class 'special)

;;;###autoload
(defun pui-list-packages ()
  "List all packages and package information.
The package name, version, and description are displayed.  From the displayed
buffer, the user can see which packages are installed, which are not, and
which are out-of-date (a newer version is available).  The user can then
select packages for installation via the keyboard or mouse."
  (interactive)
  (package-get-require-base t)
  (let ( (outbuf (get-buffer-create pui-info-buffer))
	 (sep-string "===============================================================================\n")
	 start )
    (message "Creating package list ...") (sit-for 0)
    (set-buffer outbuf)
    (setq buffer-read-only nil)
    (buffer-disable-undo outbuf)
    (erase-buffer outbuf)
    (kill-all-local-variables)
    (use-local-map pui-display-keymap)
    (setq major-mode 'list-packages-mode)
    (setq mode-name "Packages")
    (setq truncate-lines t)

    (unless package-get-remote
      (insert "
Warning: No download sites specified.  Package index may be out of date.
         If you intend to install packages, specify download sites first.

"))
    
    (if pui-list-verbose
	(insert "                 Latest Installed
  Package name   Vers.  Vers.   Description
")
      (insert "                 Latest
  Package name   Vers.  Description
"))
    (insert sep-string)
    (setq start (point))
    (mapcar
     #'(lambda (pkg)
	 (let (pkg-sym info version desc
		       b e extent current-vers disp)
	   (setq pkg-sym (car pkg)
		 info (package-get-info-version (cdr pkg) nil))
	   (setq version (package-get-info-prop info 'version)
		 desc (package-get-info-prop info 'description))

	   (setq disp (pui-package-symbol-char pkg-sym
					       version))
	   (setq b (point))
	   (if pui-list-verbose
	       (progn
		 (setq current-vers (package-get-key pkg-sym :version))
		 (cond
		  ( (not current-vers)
		    (setq current-vers "-----") )
		  ( (stringp current-vers)
		    (setq current-vers
			  (format "%.2f"
				  (string-to-number current-vers))) )
		  ( (numberp current-vers)
		    (setq current-vers (format "%.2f" current-vers)) )
		  )
		 (insert
		  (format "%s %-15s %-5.2f  %-5s  %s\n"
			  (car disp) pkg-sym 
			  (if (stringp version)
			      (string-to-number version)
			    version)
			  current-vers desc))
		 ;; (insert
		 ;;  (format "\t\t  %-12s  %s\n"
		 ;;    (package-get-info-prop info 'author-version)
		 ;;    (package-get-info-prop info 'date)))
		 )
	     (insert (format "%s %-15s %-5s %s\n"
			     (car disp)
			     pkg-sym version desc)))
	   (save-excursion
	     (setq e (progn
		       (forward-line -1)
		       (end-of-line)
		       (point))))
	   (setq extent (make-extent b e))
	   (if (car (cdr disp))
	       (set-extent-face extent (get-face (car (cdr disp))))
	     (set-extent-face extent (get-face 'default)))
	   (set-extent-property extent 'highlight t)
	   (set-extent-property extent 'pui t)
	   (set-extent-property extent 'pui-package pkg-sym)
	   (set-extent-property extent 'pui-info info)
	   (set-extent-property extent 'help-echo 'pui-help-echo)
	   (set-extent-property extent 'keymap pui-package-keymap)
	   ))
     (sort (copy-sequence package-get-base)
	   #'(lambda (a b)
	       (string< (symbol-name (car a))
			(symbol-name (car b))))))
    (insert sep-string)
    (insert (documentation 'list-packages-mode))
    (set-buffer-modified-p nil)
    (setq buffer-read-only t)
    (pop-to-buffer outbuf)
    (delete-other-windows)
    (goto-char start)
    (setq pui-selected-packages nil)	; Reset list
    (setq pui-deleted-packages nil)	; Reset list
    (when (featurep 'menubar)
      (set-buffer-menubar current-menubar)
      (add-submenu '() pui-menu)
      (setq mode-popup-menu pui-menu))
    (clear-message)
    ;;    (message (substitute-command-keys "Press `\\[pui-help]' for help."))
    ))

;;;###autoload
(defalias 'list-packages 'pui-list-packages)

(provide 'package-ui)

;;; package-ui.el ends here
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.