aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Eglen1998-02-15 16:45:52 +0000
committerStephen Eglen1998-02-15 16:45:52 +0000
commit3cfa0ee92f8a92958334f79f2dcba4ed35e5cc34 (patch)
tree298aaebd85026f650d5b3e3e4702e57f8854bd83
parent4d7ce99c2f1b855e3ea9f7f828ac1d7ceaaa46b4 (diff)
downloademacs-3cfa0ee92f8a92958334f79f2dcba4ed35e5cc34.tar.gz
emacs-3cfa0ee92f8a92958334f79f2dcba4ed35e5cc34.zip
File customized.
(msb-modes-key): New variable. (msb--mode-menu-cond, msb--aggregate-alist): New functions. (msb--split-menus): Check if msb-max-file-menu-items is nil. (msb--format-title): Remove extra / after ~. (msb--choose-file-menu): Prevent looping when examining ange-ftp directory paths. Redundant (function ...) forms around lambda functions removed. Update copyright year.
-rw-r--r--lisp/msb.el499
1 files changed, 311 insertions, 188 deletions
diff --git a/lisp/msb.el b/lisp/msb.el
index d70a5f46c8f..6c4e472ec9e 100644
--- a/lisp/msb.el
+++ b/lisp/msb.el
@@ -1,10 +1,10 @@
1;;; msb.el --- Customizable buffer-selection with multiple menus. 1;;; msb.el --- Customizable buffer-selection with multiple menus.
2 2
3;; Copyright (C) 1993, 1994, 1995, 1997 Free Software Foundation, Inc. 3;; Copyright (C) 1993, 1994, 1995, 1997, 1998 Free Software Foundation, Inc.
4 4
5;; Author: Lars Lindberg <Lars.G.Lindberg@capgemini.se> 5;; Author: Lars Lindberg <Lars.G.Lindberg@capgemini.se>
6;; Created: 8 Oct 1993 6;; Created: 8 Oct 1993
7;; Lindberg's last update version: 3.33 7;; Lindberg's last update version: 3.34
8;; Keywords: mouse buffer menu 8;; Keywords: mouse buffer menu
9 9
10;; This file is part of GNU Emacs. 10;; This file is part of GNU Emacs.
@@ -48,7 +48,7 @@
48;; There are some constants for you to try here: 48;; There are some constants for you to try here:
49;; msb--few-menus 49;; msb--few-menus
50;; msb--very-many-menus (default) 50;; msb--very-many-menus (default)
51;; 51;;
52;; Look at the variable `msb-item-handling-function' for customization 52;; Look at the variable `msb-item-handling-function' for customization
53;; of the appearance of every menu item. Try for instance setting 53;; of the appearance of every menu item. Try for instance setting
54;; it to `msb-alon-item-handler'. 54;; it to `msb-alon-item-handler'.
@@ -62,7 +62,7 @@
62;; Known bugs: 62;; Known bugs:
63;; - Files-by-directory 63;; - Files-by-directory
64;; + No possibility to show client/changed buffers separately. 64;; + No possibility to show client/changed buffers separately.
65;; + All file buffers only appear in in a file sub-menu, they will 65;; + All file buffers only appear in a file sub-menu, they will
66;; for instance not appear in the Mail sub-menu. 66;; for instance not appear in the Mail sub-menu.
67 67
68;; Future enhancements: 68;; Future enhancements:
@@ -164,10 +164,10 @@
164 ;; Also note this item-sorter 164 ;; Also note this item-sorter
165 msb-sort-by-directory) 165 msb-sort-by-directory)
166 ((eq major-mode 'Man-mode) 166 ((eq major-mode 'Man-mode)
167 4030 167 5030
168 "Manuals (%d)") 168 "Manuals (%d)")
169 ((eq major-mode 'w3-mode) 169 ((eq major-mode 'w3-mode)
170 4020 170 5020
171 "WWW (%d)") 171 "WWW (%d)")
172 ((or (memq major-mode '(rmail-mode rmail-edit-mode vm-summary-mode vm-mode mail-mode)) 172 ((or (memq major-mode '(rmail-mode rmail-edit-mode vm-summary-mode vm-mode mail-mode))
173 (memq major-mode '(mh-letter-mode 173 (memq major-mode '(mh-letter-mode
@@ -179,12 +179,12 @@
179 gnus-article-mode 179 gnus-article-mode
180 gnus-kill-file-mode 180 gnus-kill-file-mode
181 gnus-browse-killed-mode))) 181 gnus-browse-killed-mode)))
182 4010 182 5010
183 "Mail (%d)") 183 "Mail (%d)")
184 ;; Catchup for all non-file buffers 184 ;; Catchup for all non-file buffers
185 ((and (not buffer-file-name) 185 ((and (not buffer-file-name)
186 'no-multi) 186 'no-multi)
187 4099 187 5099
188 "Other non-file buffers (%d)") 188 "Other non-file buffers (%d)")
189 ((and (string-match "/\\.[^/]*$" buffer-file-name) 189 ((and (string-match "/\\.[^/]*$" buffer-file-name)
190 'multi) 190 'multi)
@@ -210,20 +210,96 @@
210;;; Customizable variables 210;;; Customizable variables
211;;; 211;;;
212 212
213(defvar msb-separator-diff 100 213(defgroup msb nil
214 "Customizable buffer-selection with multiple menus."
215 :prefix "msb-"
216 :group 'mouse)
217
218(defun msb-custom-set (symbol value)
219 "Set the value of custom variables for msb."
220 (set symbol value)
221 (if (featurep 'msb)
222 ;; wait until package has been loaded before bothering to update
223 ;; the buffer lists.
224 (menu-bar-update-buffers t))
225)
226
227(defcustom msb-menu-cond msb--very-many-menus
228 "*List of criteria for splitting the mouse buffer menu.
229The elements in the list should be of this type:
230 (CONDITION MENU-SORT-KEY MENU-TITLE ITEM-HANDLING-FN ITEM-SORT-FN).
231
232When making the split, the buffers are tested one by one against the
233CONDITION, just like a lisp cond: When hitting a true condition, the
234other criteria are *not* tested and the buffer name will appear in the
235menu with the menu-title corresponding to the true condition.
236
237If the condition returns the symbol `multi', then the buffer will be
238added to this menu *and* tested for other menus too. If it returns
239`no-multi', then the buffer will only be added if it hasn't been added
240to any other menu.
241
242During this test, the buffer in question is the current buffer, and
243the test is surrounded by calls to `save-excursion' and
244`save-match-data'.
245
246The categories are sorted by MENU-SORT-KEY. Smaller keys are on top.
247nil means don't display this menu.
248
249MENU-TITLE is really a format. If you add %d in it, the %d is
250replaced with the number of items in that menu.
251
252ITEM-HANDLING-FN, is optional. If it is supplied and is a function,
253than it is used for displaying the items in that particular buffer
254menu, otherwise the function pointed out by
255`msb-item-handling-function' is used.
256
257ITEM-SORT-FN, is also optional.
258If it is not supplied, the function pointed out by
259`msb-item-sort-function' is used.
260If it is nil, then no sort takes place and the buffers are presented
261in least-recently-used order.
262If it is t, then no sort takes place and the buffers are presented in
263most-recently-used order.
264If it is supplied and non-nil and not t than it is used for sorting
265the items in that particular buffer menu.
266
267Note1: There should always be a `catch-all' as last element, in this
268list. That is an element like (t TITLE ITEM-HANDLING-FUNCTION).
269Note2: A buffer menu appears only if it has at least one buffer in it.
270Note3: If you have a CONDITION that can't be evaluated you will get an
271error every time you do \\[msb]."
272 :type `(choice (const :tag "long" :value ,msb--very-many-menus)
273 (const :tag "short" :value ,msb--few-menus))
274 :set 'msb-custom-set
275 :group 'msb)
276
277(defcustom msb-modes-key 4000
278 "The sort key for files sorted by mode."
279 :type 'integer
280 :set 'msb-custom-set
281 :group 'msb)
282
283(defcustom msb-separator-diff 100
214 "*Non-nil means use separators. 284 "*Non-nil means use separators.
215The separators will appear between all menus that have a sorting key 285The separators will appear between all menus that have a sorting key
216that differs by this value or more.") 286that differs by this value or more."
287 :type '(choice integer (const nil))
288 :set 'msb-custom-set
289 :group 'msb)
217 290
218(defvar msb-files-by-directory-sort-key 0 291(defvar msb-files-by-directory-sort-key 0
219 "*The sort key for files sorted by directory.") 292 "*The sort key for files sorted by directory.")
220 293
221(defvar msb-max-menu-items 15 294(defcustom msb-max-menu-items 15
222 "*The maximum number of items in a menu. 295 "*The maximum number of items in a menu.
223If this variable is set to 15 for instance, then the submenu will be 296If this variable is set to 15 for instance, then the submenu will be
224split up in minor parts, 15 items each. If nil, there is no limit.") 297split up in minor parts, 15 items each. Nil means no limit."
298 :type '(choice integer (const nil))
299 :set 'msb-custom-set
300 :group 'msb)
225 301
226(defvar msb-max-file-menu-items 10 302(defcustom msb-max-file-menu-items 10
227 "*The maximum number of items from different directories. 303 "*The maximum number of items from different directories.
228 304
229When the menu is of type `file by directory', this is the maximum 305When the menu is of type `file by directory', this is the maximum
@@ -233,25 +309,40 @@ directories.
233Set this to 1 if you want one menu per directory instead of clumping 309Set this to 1 if you want one menu per directory instead of clumping
234them together. 310them together.
235 311
236If the value is not a number, then the value 10 is used.") 312If the value is not a number, then the value 10 is used."
313 :type 'integer
314 :set 'msb-custom-set
315 :group 'msb)
237 316
238(defvar msb-most-recently-used-sort-key -1010 317(defcustom msb-most-recently-used-sort-key -1010
239 "*Where should the menu with the most recently used buffers be placed?") 318 "*Where should the menu with the most recently used buffers be placed?"
319 :type 'integer
320 :set 'msb-custom-set
321 :group 'msb)
240 322
241(defvar msb-display-most-recently-used 15 323(defcustom msb-display-most-recently-used 15
242 "*How many buffers should be in the most-recently-used menu. 324 "*How many buffers should be in the most-recently-used menu.
243 No buffers at all if less than 1 or nil (or any non-number).") 325No buffers at all if less than 1 or nil (or any non-number)."
244 326 :type 'integer
245(defvar msb-most-recently-used-title "Most recently used (%d)" 327 :set 'msb-custom-set
246 "*The title for the most-recently-used menu.") 328 :group 'msb)
329
330(defcustom msb-most-recently-used-title "Most recently used (%d)"
331 "*The title for the most-recently-used menu."
332 :type 'string
333 :set 'msb-custom-set
334 :group 'msb)
247 335
248(defvar msb-horizontal-shift-function '(lambda () 0) 336(defvar msb-horizontal-shift-function '(lambda () 0)
249 "*Function that specifies how many pixels to shift the top menu leftwards.") 337 "*Function that specifies how many pixels to shift the top menu leftwards.")
250 338
251(defvar msb-display-invisible-buffers-p nil 339(defcustom msb-display-invisible-buffers-p nil
252 "*Show invisible buffers or not. 340 "*Show invisible buffers or not.
253Non-nil means that the buffer menu should include buffers that have 341Non-nil means that the buffer menu should include buffers that have
254names that starts with a space character.") 342names that starts with a space character."
343 :type 'boolean
344 :set 'msb-custom-set
345 :group 'msb)
255 346
256(defvar msb-item-handling-function 'msb-item-handler 347(defvar msb-item-handling-function 'msb-item-handler
257 "*The appearance of a buffer menu. 348 "*The appearance of a buffer menu.
@@ -267,7 +358,7 @@ function is called for items in the variable `msb-menu-cond' that have
267nil as ITEM-HANDLING-FUNCTION. See `msb-menu-cond' for more 358nil as ITEM-HANDLING-FUNCTION. See `msb-menu-cond' for more
268information.") 359information.")
269 360
270(defvar msb-item-sort-function 'msb-sort-by-name 361(defcustom msb-item-sort-function 'msb-sort-by-name
271 "*The order of items in a buffer menu. 362 "*The order of items in a buffer menu.
272 363
273The default function to call for handling the order of items in a menu 364The default function to call for handling the order of items in a menu
@@ -277,67 +368,33 @@ like (ITEM-NAME . BUFFER).
277ITEM-NAME is the name of the item that will appear in the menu. 368ITEM-NAME is the name of the item that will appear in the menu.
278BUFFER is the buffer, this is not necessarily the current buffer. 369BUFFER is the buffer, this is not necessarily the current buffer.
279 370
280Set this to nil or t if you don't want any sorting (faster).") 371Set this to nil or t if you don't want any sorting (faster)."
281 372 :type '(choice (const msb-sort-by-name)
282(defvar msb-files-by-directory nil 373 (const :tag "Newest first" t)
374 (const :tag "Oldest first" nil))
375 :set 'msb-custom-set
376 :group 'msb
377)
378
379(defcustom msb-files-by-directory nil
283 "*Non-nil means that files should be sorted by directory instead of 380 "*Non-nil means that files should be sorted by directory instead of
284the groups in msb-menu-cond.") 381the groups in msb-menu-cond."
382 :type 'boolean
383 :set 'msb-custom-set
384 :group 'msb)
285 385
286(defvar msb-menu-cond msb--very-many-menus 386(defcustom msb-after-load-hooks nil
287 "*List of criteria for splitting the mouse buffer menu. 387 "Hooks to be run after the msb package has been loaded."
288The elements in the list should be of this type: 388 :type 'hook
289 (CONDITION MENU-SORT-KEY MENU-TITLE ITEM-HANDLING-FN ITEM-SORT-FN). 389 :set 'msb-custom-set
290 390 :group 'msb)
291When making the split, the buffers are tested one by one against the
292CONDITION, just like a lisp cond: When hitting a true condition, the
293other criteria are *not* tested and the buffer name will appear in the
294menu with the menu-title corresponding to the true condition.
295
296If the condition returns the symbol `multi', then the buffer will be
297added to this menu *and* tested for other menus too. If it returns
298`no-multi', then the buffer will only be added if it hasn't been added
299to any other menu.
300
301During this test, the buffer in question is the current buffer, and
302the test is surrounded by calls to `save-excursion' and
303`save-match-data'.
304
305The categories are sorted by MENU-SORT-KEY. Smaller keys are on top.
306nil means don't display this menu.
307
308MENU-TITLE is really a format. If you add %d in it, the %d is
309replaced with the number of items in that menu.
310
311ITEM-HANDLING-FN, is optional. If it is supplied and is a function,
312than it is used for displaying the items in that particular buffer
313menu, otherwise the function pointed out by
314`msb-item-handling-function' is used.
315
316ITEM-SORT-FN, is also optional.
317If it is not supplied, the function pointed out by
318`msb-item-sort-function' is used.
319If it is nil, then no sort takes place and the buffers are presented
320in least-recently-used order.
321If it is t, then no sort takes place and the buffers are presented in
322most-recently-used order.
323If it is supplied and non-nil and not t than it is used for sorting
324the items in that particular buffer menu.
325
326Note1: There should always be a `catch-all' as last element, in this
327list. That is an element like (t TITLE ITEM-HANDLING-FUNCTION).
328Note2: A buffer menu appears only if it has at least one buffer in it.
329Note3: If you have a CONDITION that can't be evaluated you will get an
330error every time you do \\[msb].")
331
332(defvar msb-after-load-hooks nil
333 "Hooks to be run after the msb package has been loaded.")
334 391
335;;; 392;;;
336;;; Internal variables 393;;; Internal variables
337;;; 394;;;
338 395
339;; Home directory for the current user 396;; Home directory for the current user
340(defvar msb--home-dir 397(defconst msb--home-dir
341 (condition-case nil 398 (condition-case nil
342 (substitute-in-file-name "$HOME") 399 (substitute-in-file-name "$HOME")
343 ;; If $HOME isn't defined, use nil 400 ;; If $HOME isn't defined, use nil
@@ -467,37 +524,35 @@ If the argument is left out or nil, then the current buffer is considered."
467 ;; ((PATH-1 BUFFER-1) (PATH-2 BUFFER-2) ...) 524 ;; ((PATH-1 BUFFER-1) (PATH-2 BUFFER-2) ...)
468 ;; sorted on PATH-x 525 ;; sorted on PATH-x
469 (sort (mapcan 526 (sort (mapcan
470 (function 527 (lambda (buffer)
471 (lambda (buffer) 528 (let ((file-name (expand-file-name (buffer-file-name buffer))))
472 (let ((file-name (expand-file-name (buffer-file-name buffer)))) 529 (when file-name
473 (when file-name 530 (list (cons (msb--strip-dir file-name) buffer)))))
474 (list (cons (msb--strip-dir file-name) buffer))))))
475 list) 531 list)
476 (function (lambda (item1 item2) 532 (lambda (item1 item2)
477 (string< (car item1) (car item2))))))) 533 (string< (car item1) (car item2))))))
478 ;; Now clump buffers together that have the same path 534 ;; Now clump buffers together that have the same path
479 ;; Make alist that looks like 535 ;; Make alist that looks like
480 ;; ((PATH1 . (BUFFER-1 BUFFER-2 ...)) (PATH2 . (BUFFER-K)) ...) 536 ;; ((PATH1 . (BUFFER-1 BUFFER-2 ...)) (PATH2 . (BUFFER-K)) ...)
481 (let ((path nil) 537 (let ((path nil)
482 (buffers nil)) 538 (buffers nil))
483 (nconc 539 (nconc
484 (mapcan (function 540 (mapcan (lambda (item)
485 (lambda (item) 541 (cond
486 (cond 542 ((and path
487 ((and path 543 (string= path (car item)))
488 (string= path (car item))) 544 ;; The same path as earlier: Add to current list of
489 ;; The same path as earlier: Add to current list of 545 ;; buffers.
490 ;; buffers. 546 (push (cdr item) buffers)
491 (push (cdr item) buffers) 547 ;; This item should not be added to list
492 ;; This item should not be added to list 548 nil)
493 nil) 549 (t
494 (t 550 ;; New path
495 ;; New path 551 (let ((result (and path (cons path buffers))))
496 (let ((result (and path (cons path buffers)))) 552 (setq path (car item))
497 (setq path (car item)) 553 (setq buffers (list (cdr item)))
498 (setq buffers (list (cdr item))) 554 ;; Add the last result the list.
499 ;; Add the last result the list. 555 (and result (list result))))))
500 (and result (list result)))))))
501 buffer-alist) 556 buffer-alist)
502 ;; Add the last result to the list 557 ;; Add the last result to the list
503 (list (cons path buffers)))))) 558 (list (cons path buffers))))))
@@ -507,7 +562,7 @@ If the argument is left out or nil, then the current buffer is considered."
507 (let ((new-path path)) 562 (let ((new-path path))
508 (when (and msb--home-dir 563 (when (and msb--home-dir
509 (string-match (concat "^" msb--home-dir) path)) 564 (string-match (concat "^" msb--home-dir) path))
510 (setq new-path (concat "~/" 565 (setq new-path (concat "~"
511 (substring path (match-end 0))))) 566 (substring path (match-end 0)))))
512 (format (if top-found-p "%s... (%d)" "%s (%d)") 567 (format (if top-found-p "%s... (%d)" "%s (%d)")
513 new-path number-of-items))) 568 new-path number-of-items)))
@@ -526,7 +581,7 @@ If the argument is left out or nil, then the current buffer is considered."
526 10)) 581 10))
527 (top-found-p nil) 582 (top-found-p nil)
528 (last-path nil) 583 (last-path nil)
529 first rest path buffers) 584 first rest path buffers old-path)
530 ;; Prepare for looping over all items in buffer-alist 585 ;; Prepare for looping over all items in buffer-alist
531 (setq first (car buffer-alist) 586 (setq first (car buffer-alist)
532 rest (cdr buffer-alist) 587 rest (cdr buffer-alist)
@@ -576,8 +631,13 @@ If the argument is left out or nil, then the current buffer is considered."
576 rest tmp-rest)) 631 rest tmp-rest))
577 ;; Now see if we can clump more buffers together if we go up 632 ;; Now see if we can clump more buffers together if we go up
578 ;; one step in the file hierarchy. 633 ;; one step in the file hierarchy.
634 ;; If path isn't changed by msb--strip-dir, we are looking
635 ;; at the machine name component of an ange-ftp filename.
636 (setq old-path path)
579 (setq path (msb--strip-dir path) 637 (setq path (msb--strip-dir path)
580 buffers (cdr first)) 638 buffers (cdr first))
639 (if (equal old-path path)
640 (setq last-path path))
581 (when (and last-path 641 (when (and last-path
582 (or (and (>= (length path) (length last-path)) 642 (or (and (>= (length path) (length last-path))
583 (string= last-path 643 (string= last-path
@@ -599,11 +659,12 @@ If the argument is left out or nil, then the current buffer is considered."
599 path (car first) 659 path (car first)
600 buffers (cdr first))))))) 660 buffers (cdr first)))))))
601 ;; Now take care of the last item. 661 ;; Now take care of the last item.
602 (push (cons (msb--format-title top-found-p 662 (when first
603 (car first) 663 (push (cons (msb--format-title top-found-p
604 (length (cdr first))) 664 (car first)
605 (cdr first)) 665 (length (cdr first)))
606 final-list) 666 (cdr first))
667 final-list))
607 (setq top-found-p nil) 668 (setq top-found-p nil)
608 (nreverse final-list))) 669 (nreverse final-list)))
609 670
@@ -646,7 +707,7 @@ If the argument is left out or nil, then the current buffer is considered."
646 )) 707 ))
647 708
648;; This defsubst is only used in `msb--choose-menu' below. It was 709;; This defsubst is only used in `msb--choose-menu' below. It was
649;; pulled out merely to make the code somewhat clearer. The indention 710;; pulled out merely to make the code somewhat clearer. The indentation
650;; level was too big. 711;; level was too big.
651(defsubst msb--collect (function-info-vector) 712(defsubst msb--collect (function-info-vector)
652 (let ((result nil) 713 (let ((result nil)
@@ -693,9 +754,8 @@ If the argument is left out or nil, then the current buffer is considered."
693 (save-excursion 754 (save-excursion
694 (set-buffer buffer) 755 (set-buffer buffer)
695 ;; Menu found. Add to this menu 756 ;; Menu found. Add to this menu
696 (mapc (function 757 (mapc (lambda (function-info)
697 (lambda (function-info) 758 (msb--add-to-menu buffer function-info max-buffer-name-length))
698 (msb--add-to-menu buffer function-info max-buffer-name-length)))
699 (msb--collect function-info-vector))) 759 (msb--collect function-info-vector)))
700 (error (unless msb--error 760 (error (unless msb--error
701 (setq msb--error 761 (setq msb--error
@@ -723,6 +783,68 @@ If the argument is left out or nil, then the current buffer is considered."
723 (t 783 (t
724 (sort buffer-list sorter)))))))))) 784 (sort buffer-list sorter))))))))))
725 785
786;; Return ALIST as a sorted, aggregated alist, where all items with
787;; the same car element (according to SAME-PREDICATE) are aggregated
788;; together. The alist is first sorted by SORT-PREDICATE.
789;; Example:
790;; (msb--aggregate-alist
791;; '((a . a1) (a . a2) (b . b1) (c . c3) (a . a4) (a . a3) (b . b3) (b . b2))
792;; (function string=)
793;; (lambda (item1 item2)
794;; (string< (symbol-name item1) (symbol-name item2))))
795;; results in
796;; ((a a1 a2 a4 a3) (b b1 b3 b2) (c c3))
797(defun msb--aggregate-alist (alist same-predicate sort-predicate)
798 (when (not (null alist))
799 (let (result
800 same
801 tmp-old-car
802 tmp-same
803 (first-time-p t)
804 old-car)
805 (nconc
806 (mapcan (lambda (item)
807 (cond
808 (first-time-p
809 (push (cdr item) same)
810 (setq first-time-p nil)
811 (setq old-car (car item))
812 nil)
813 ((funcall same-predicate (car item) old-car)
814 (push (cdr item) same)
815 nil)
816 (t
817 (setq tmp-same same
818 tmp-old-car old-car)
819 (setq same (list (cdr item))
820 old-car (car item))
821 (list (cons tmp-old-car (nreverse tmp-same))))))
822 (sort alist (lambda (item1 item2)
823 (funcall sort-predicate (car item1) (car item2)))))
824 (list (cons old-car (nreverse same)))))))
825
826
827(defun msb--mode-menu-cond ()
828 (let ((key msb-modes-key))
829 (mapcar (lambda (item)
830 (incf key)
831 (list `( eq major-mode (quote ,(car item)))
832 key
833 (concat (cdr item) " (%d)")))
834 (sort
835 (let ((mode-list nil))
836 (mapc (lambda (buffer)
837 (save-excursion
838 (set-buffer buffer)
839 (when (and (not (msb-invisible-buffer-p))
840 (not (assq major-mode mode-list))
841 (push (cons major-mode mode-name)
842 mode-list)))))
843 (cdr (buffer-list)))
844 mode-list)
845 (lambda (item1 item2)
846 (string< (cdr item1) (cdr item2)))))))
847
726;; Returns a list on the form ((TITLE . BUFFER-LIST)) for 848;; Returns a list on the form ((TITLE . BUFFER-LIST)) for
727;; the most recently used buffers. 849;; the most recently used buffers.
728(defun msb--most-recently-used-menu (max-buffer-name-length) 850(defun msb--most-recently-used-menu (max-buffer-name-length)
@@ -756,13 +878,12 @@ If the argument is left out or nil, then the current buffer is considered."
756 function-info-vector) 878 function-info-vector)
757 ;; Calculate the longest buffer name. 879 ;; Calculate the longest buffer name.
758 (mapc 880 (mapc
759 (function 881 (lambda (buffer)
760 (lambda (buffer) 882 (if (or msb-display-invisible-buffers-p
761 (if (or msb-display-invisible-buffers-p 883 (not (msb-invisible-buffer-p)))
762 (not (msb-invisible-buffer-p))) 884 (setq max-buffer-name-length
763 (setq max-buffer-name-length 885 (max max-buffer-name-length
764 (max max-buffer-name-length 886 (length (buffer-name buffer))))))
765 (length (buffer-name buffer)))))))
766 (buffer-list)) 887 (buffer-list))
767 ;; Make a list with elements of type 888 ;; Make a list with elements of type
768 ;; (BUFFER-LIST-VARIABLE 889 ;; (BUFFER-LIST-VARIABLE
@@ -776,37 +897,40 @@ If the argument is left out or nil, then the current buffer is considered."
776 (setq function-info-vector 897 (setq function-info-vector
777 (apply (function vector) 898 (apply (function vector)
778 (mapcar (function msb--create-function-info) 899 (mapcar (function msb--create-function-info)
779 msb-menu-cond))) 900 (append msb-menu-cond (msb--mode-menu-cond)))))
780 ;; Split the buffer-list into several lists; one list for each 901 ;; Split the buffer-list into several lists; one list for each
781 ;; criteria. This is the most critical part with respect to time. 902 ;; criteria. This is the most critical part with respect to time.
782 (mapc (function (lambda (buffer) 903 (mapc (lambda (buffer)
783 (cond ((and msb-files-by-directory 904 (cond ((and msb-files-by-directory
784 (buffer-file-name buffer)) 905 (buffer-file-name buffer)
785 (push buffer file-buffers)) 906 ;; exclude ange-ftp buffers
786 (t 907 ;;(not (string-match "\\/[^/:]+:"
787 (msb--choose-menu buffer 908 ;; (buffer-file-name buffer)))
788 function-info-vector 909 )
789 max-buffer-name-length))))) 910 (push buffer file-buffers))
911 (t
912 (msb--choose-menu buffer
913 function-info-vector
914 max-buffer-name-length))))
790 (buffer-list)) 915 (buffer-list))
791 (when file-buffers 916 (when file-buffers
792 (setq file-buffers 917 (setq file-buffers
793 (mapcar (function 918 (mapcar (lambda (buffer-list)
794 (lambda (buffer-list) 919 (cons msb-files-by-directory-sort-key
795 (cons msb-files-by-directory-sort-key 920 (cons (car buffer-list)
796 (cons (car buffer-list) 921 (sort
797 (sort 922 (mapcar (function
798 (mapcar (function 923 (lambda (buffer)
799 (lambda (buffer) 924 (cons (save-excursion
800 (cons (save-excursion 925 (set-buffer buffer)
801 (set-buffer buffer) 926 (funcall msb-item-handling-function
802 (funcall msb-item-handling-function 927 buffer
803 buffer 928 max-buffer-name-length))
804 max-buffer-name-length)) 929 buffer)))
805 buffer))) 930 (cdr buffer-list))
806 (cdr buffer-list)) 931 (function
807 (function 932 (lambda (item1 item2)
808 (lambda (item1 item2) 933 (string< (car item1) (car item2))))))))
809 (string< (car item1) (car item2)))))))))
810 (msb--choose-file-menu file-buffers)))) 934 (msb--choose-file-menu file-buffers))))
811 ;; Now make the menu - a list of (TITLE . BUFFER-LIST) 935 ;; Now make the menu - a list of (TITLE . BUFFER-LIST)
812 (let* (menu 936 (let* (menu
@@ -831,8 +955,8 @@ If the argument is left out or nil, then the current buffer is considered."
831 most-recently-used) 955 most-recently-used)
832 others) 956 others)
833 others) 957 others)
834 (function (lambda (elt1 elt2) 958 (lambda (elt1 elt2)
835 (< (car elt1) (car elt2)))))))) 959 (< (car elt1) (car elt2)))))))
836 ;; Now make it a keymap menu 960 ;; Now make it a keymap menu
837 (append 961 (append
838 '(keymap "Select Buffer") 962 '(keymap "Select Buffer")
@@ -907,7 +1031,7 @@ variable `msb-menu-cond'."
907 choice) 1031 choice)
908 (t 1032 (t
909 (error "Unknown form for buffer: %s" choice))))) 1033 (error "Unknown form for buffer: %s" choice)))))
910 1034
911;; Add separators 1035;; Add separators
912(defun msb--add-separators (sorted-list) 1036(defun msb--add-separators (sorted-list)
913 (cond 1037 (cond
@@ -917,19 +1041,18 @@ variable `msb-menu-cond'."
917 (t 1041 (t
918 (let ((last-key nil)) 1042 (let ((last-key nil))
919 (mapcan 1043 (mapcan
920 (function 1044 (lambda (item)
921 (lambda (item) 1045 (cond
922 (cond 1046 ((and msb-separator-diff
923 ((and msb-separator-diff 1047 last-key
924 last-key 1048 (> (- (car item) last-key)
925 (> (- (car item) last-key) 1049 msb-separator-diff))
926 msb-separator-diff)) 1050 (setq last-key (car item))
927 (setq last-key (car item)) 1051 (list (cons last-key 'separator)
928 (list (cons last-key 'separator) 1052 item))
929 item)) 1053 (t
930 (t 1054 (setq last-key (car item))
931 (setq last-key (car item)) 1055 (list item))))
932 (list item)))))
933 sorted-list))))) 1056 sorted-list)))))
934 1057
935(defun msb--split-menus-2 (list mcount result) 1058(defun msb--split-menus-2 (list mcount result)
@@ -958,31 +1081,32 @@ variable `msb-menu-cond'."
958 list) 1081 list)
959 result)) 1082 result))
960 (nreverse result)))) 1083 (nreverse result))))
961
962(defun msb--split-menus (list)
963 (msb--split-menus-2 list 0 nil))
964 1084
1085(defun msb--split-menus (list)
1086 (if (and (integerp msb-max-menu-items)
1087 (> msb-max-menu-items 0))
1088 (msb--split-menus-2 list 0 nil)
1089 list))
965 1090
966(defun msb--make-keymap-menu (raw-menu) 1091(defun msb--make-keymap-menu (raw-menu)
967 (let ((end (cons '(nil) 'menu-bar-select-buffer)) 1092 (let ((end (cons '(nil) 'menu-bar-select-buffer))
968 (mcount 0)) 1093 (mcount 0))
969 (mapcar 1094 (mapcar
970 (function 1095 (lambda (sub-menu)
971 (lambda (sub-menu) 1096 (cond
972 (cond 1097 ((eq 'separator sub-menu)
973 ((eq 'separator sub-menu) 1098 (list 'separator "--"))
974 (list 'separator "--")) 1099 (t
975 (t 1100 (let ((buffers (mapcar (function
976 (let ((buffers (mapcar (function 1101 (lambda (item)
977 (lambda (item) 1102 (let ((string (car item))
978 (let ((string (car item)) 1103 (buffer (cdr item)))
979 (buffer (cdr item))) 1104 (cons (buffer-name buffer)
980 (cons (buffer-name buffer) 1105 (cons string end)))))
981 (cons string end))))) 1106 (cdr sub-menu))))
982 (cdr sub-menu)))) 1107 (nconc (list (incf mcount) (car sub-menu)
983 (nconc (list (incf mcount) (car sub-menu) 1108 'keymap (car sub-menu))
984 'keymap (car sub-menu)) 1109 (msb--split-menus buffers))))))
985 (msb--split-menus buffers)))))))
986 raw-menu))) 1110 raw-menu)))
987 1111
988(defun menu-bar-update-buffers (&optional arg) 1112(defun menu-bar-update-buffers (&optional arg)
@@ -1009,14 +1133,13 @@ variable `msb-menu-cond'."
1009 (nconc 1133 (nconc
1010 (list 'frame f-title '(nil) 'keymap f-title) 1134 (list 'frame f-title '(nil) 'keymap f-title)
1011 (mapcar 1135 (mapcar
1012 (function 1136 (lambda (frame)
1013 (lambda (frame) 1137 (nconc
1014 (nconc 1138 (list frame
1015 (list frame 1139 (cdr (assq 'name
1016 (cdr (assq 'name 1140 (frame-parameters frame)))
1017 (frame-parameters frame))) 1141 (cons nil nil))
1018 (cons nil nil)) 1142 'menu-bar-select-frame))
1019 'menu-bar-select-frame)))
1020 frames))))) 1143 frames)))))
1021 (define-key (current-global-map) [menu-bar buffer] 1144 (define-key (current-global-map) [menu-bar buffer]
1022 (cons "Buffers" 1145 (cons "Buffers"