diff options
| author | Stephen Eglen | 1998-02-15 16:45:52 +0000 |
|---|---|---|
| committer | Stephen Eglen | 1998-02-15 16:45:52 +0000 |
| commit | 3cfa0ee92f8a92958334f79f2dcba4ed35e5cc34 (patch) | |
| tree | 298aaebd85026f650d5b3e3e4702e57f8854bd83 | |
| parent | 4d7ce99c2f1b855e3ea9f7f828ac1d7ceaaa46b4 (diff) | |
| download | emacs-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.el | 499 |
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. | ||
| 229 | The elements in the list should be of this type: | ||
| 230 | (CONDITION MENU-SORT-KEY MENU-TITLE ITEM-HANDLING-FN ITEM-SORT-FN). | ||
| 231 | |||
| 232 | When making the split, the buffers are tested one by one against the | ||
| 233 | CONDITION, just like a lisp cond: When hitting a true condition, the | ||
| 234 | other criteria are *not* tested and the buffer name will appear in the | ||
| 235 | menu with the menu-title corresponding to the true condition. | ||
| 236 | |||
| 237 | If the condition returns the symbol `multi', then the buffer will be | ||
| 238 | added 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 | ||
| 240 | to any other menu. | ||
| 241 | |||
| 242 | During this test, the buffer in question is the current buffer, and | ||
| 243 | the test is surrounded by calls to `save-excursion' and | ||
| 244 | `save-match-data'. | ||
| 245 | |||
| 246 | The categories are sorted by MENU-SORT-KEY. Smaller keys are on top. | ||
| 247 | nil means don't display this menu. | ||
| 248 | |||
| 249 | MENU-TITLE is really a format. If you add %d in it, the %d is | ||
| 250 | replaced with the number of items in that menu. | ||
| 251 | |||
| 252 | ITEM-HANDLING-FN, is optional. If it is supplied and is a function, | ||
| 253 | than it is used for displaying the items in that particular buffer | ||
| 254 | menu, otherwise the function pointed out by | ||
| 255 | `msb-item-handling-function' is used. | ||
| 256 | |||
| 257 | ITEM-SORT-FN, is also optional. | ||
| 258 | If it is not supplied, the function pointed out by | ||
| 259 | `msb-item-sort-function' is used. | ||
| 260 | If it is nil, then no sort takes place and the buffers are presented | ||
| 261 | in least-recently-used order. | ||
| 262 | If it is t, then no sort takes place and the buffers are presented in | ||
| 263 | most-recently-used order. | ||
| 264 | If it is supplied and non-nil and not t than it is used for sorting | ||
| 265 | the items in that particular buffer menu. | ||
| 266 | |||
| 267 | Note1: There should always be a `catch-all' as last element, in this | ||
| 268 | list. That is an element like (t TITLE ITEM-HANDLING-FUNCTION). | ||
| 269 | Note2: A buffer menu appears only if it has at least one buffer in it. | ||
| 270 | Note3: If you have a CONDITION that can't be evaluated you will get an | ||
| 271 | error 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. |
| 215 | The separators will appear between all menus that have a sorting key | 285 | The separators will appear between all menus that have a sorting key |
| 216 | that differs by this value or more.") | 286 | that 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. |
| 223 | If this variable is set to 15 for instance, then the submenu will be | 296 | If this variable is set to 15 for instance, then the submenu will be |
| 224 | split up in minor parts, 15 items each. If nil, there is no limit.") | 297 | split 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 | ||
| 229 | When the menu is of type `file by directory', this is the maximum | 305 | When the menu is of type `file by directory', this is the maximum |
| @@ -233,25 +309,40 @@ directories. | |||
| 233 | Set this to 1 if you want one menu per directory instead of clumping | 309 | Set this to 1 if you want one menu per directory instead of clumping |
| 234 | them together. | 310 | them together. |
| 235 | 311 | ||
| 236 | If the value is not a number, then the value 10 is used.") | 312 | If 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).") | 325 | No 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. |
| 253 | Non-nil means that the buffer menu should include buffers that have | 341 | Non-nil means that the buffer menu should include buffers that have |
| 254 | names that starts with a space character.") | 342 | names 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 | |||
| 267 | nil as ITEM-HANDLING-FUNCTION. See `msb-menu-cond' for more | 358 | nil as ITEM-HANDLING-FUNCTION. See `msb-menu-cond' for more |
| 268 | information.") | 359 | information.") |
| 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 | ||
| 273 | The default function to call for handling the order of items in a menu | 364 | The default function to call for handling the order of items in a menu |
| @@ -277,67 +368,33 @@ like (ITEM-NAME . BUFFER). | |||
| 277 | ITEM-NAME is the name of the item that will appear in the menu. | 368 | ITEM-NAME is the name of the item that will appear in the menu. |
| 278 | BUFFER is the buffer, this is not necessarily the current buffer. | 369 | BUFFER is the buffer, this is not necessarily the current buffer. |
| 279 | 370 | ||
| 280 | Set this to nil or t if you don't want any sorting (faster).") | 371 | Set 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 |
| 284 | the groups in msb-menu-cond.") | 381 | the 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." |
| 288 | The 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) | |
| 291 | When making the split, the buffers are tested one by one against the | ||
| 292 | CONDITION, just like a lisp cond: When hitting a true condition, the | ||
| 293 | other criteria are *not* tested and the buffer name will appear in the | ||
| 294 | menu with the menu-title corresponding to the true condition. | ||
| 295 | |||
| 296 | If the condition returns the symbol `multi', then the buffer will be | ||
| 297 | added 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 | ||
| 299 | to any other menu. | ||
| 300 | |||
| 301 | During this test, the buffer in question is the current buffer, and | ||
| 302 | the test is surrounded by calls to `save-excursion' and | ||
| 303 | `save-match-data'. | ||
| 304 | |||
| 305 | The categories are sorted by MENU-SORT-KEY. Smaller keys are on top. | ||
| 306 | nil means don't display this menu. | ||
| 307 | |||
| 308 | MENU-TITLE is really a format. If you add %d in it, the %d is | ||
| 309 | replaced with the number of items in that menu. | ||
| 310 | |||
| 311 | ITEM-HANDLING-FN, is optional. If it is supplied and is a function, | ||
| 312 | than it is used for displaying the items in that particular buffer | ||
| 313 | menu, otherwise the function pointed out by | ||
| 314 | `msb-item-handling-function' is used. | ||
| 315 | |||
| 316 | ITEM-SORT-FN, is also optional. | ||
| 317 | If it is not supplied, the function pointed out by | ||
| 318 | `msb-item-sort-function' is used. | ||
| 319 | If it is nil, then no sort takes place and the buffers are presented | ||
| 320 | in least-recently-used order. | ||
| 321 | If it is t, then no sort takes place and the buffers are presented in | ||
| 322 | most-recently-used order. | ||
| 323 | If it is supplied and non-nil and not t than it is used for sorting | ||
| 324 | the items in that particular buffer menu. | ||
| 325 | |||
| 326 | Note1: There should always be a `catch-all' as last element, in this | ||
| 327 | list. That is an element like (t TITLE ITEM-HANDLING-FUNCTION). | ||
| 328 | Note2: A buffer menu appears only if it has at least one buffer in it. | ||
| 329 | Note3: If you have a CONDITION that can't be evaluated you will get an | ||
| 330 | error 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" |