diff --git a/lisp/buff-menu.el b/lisp/buff-menu.el index 91bc038..18264f2 100644 --- a/lisp/buff-menu.el +++ b/lisp/buff-menu.el @@ -96,6 +96,9 @@ This is set by the prefix argument to `buffer-menu' and related commands.") (make-variable-buffer-local 'Buffer-menu-files-only) +(defvar Buffer-menu--regexp-history nil + "History list for buffer name regular expressions.") + (defvar Info-current-file) ; from info.el (defvar Info-current-node) ; from info.el @@ -130,6 +133,9 @@ commands.") (define-key map (kbd "M-s a C-s") 'Buffer-menu-isearch-buffers) (define-key map (kbd "M-s a M-C-s") 'Buffer-menu-isearch-buffers-regexp) (define-key map (kbd "M-s a C-o") 'Buffer-menu-multi-occur) + (define-key map (kbd "D m") 'Buffer-menu-delete-by-major-mode) + (define-key map (kbd "D b") 'Buffer-menu-delete-by-buffer-name-regexp) + (define-key map (kbd "D f") 'Buffer-menu-delete-by-file-name-regexp) (define-key map [mouse-2] 'Buffer-menu-mouse-select) (define-key map [follow-link] 'mouse-face) @@ -243,7 +249,13 @@ In Buffer Menu mode, the following commands are defined: \\[Buffer-menu-toggle-read-only] Toggle read-only status of buffer on this line. \\[revert-buffer] Update the list of buffers. \\[Buffer-menu-toggle-files-only] Toggle whether the menu displays only file buffers. -\\[Buffer-menu-bury] Bury the buffer listed on this line." +\\[Buffer-menu-bury] Bury the buffer listed on this line. +\\[Buffer-menu-delete-by-major-mode] Prompt for major mode name and + delete all buffers in that mode. +\\[Buffer-menu-delete-by-buffer-name-regexp] Prompt for regexp and + mark for deletion all buffers with matching names. +\\[Buffer-menu-delete-by-file-name-regexp] Prompt for regexp and + mark for deletion all buffers with mathing file names." (set (make-local-variable 'buffer-stale-function) (lambda (&optional _noconfirm) 'fast)) (add-hook 'tabulated-list-revert-hook 'list-buffers--refresh nil t)) @@ -270,7 +282,7 @@ Menu." (interactive "P") (switch-to-buffer (list-buffers-noselect arg)) (message - "Commands: d, s, x, u; f, o, 1, 2, m, v; ~, %%; q to quit; ? for help.")) + "Commands: d, s, x, u; f, o, 1, 2, m, v; ~, %%; D m, D b, D f; q to quit; ? for help.")) (defun buffer-menu-other-window (&optional arg) "Display the Buffer Menu in another window. @@ -282,7 +294,7 @@ ARG, show only buffers that are visiting files." (interactive "P") (switch-to-buffer-other-window (list-buffers-noselect arg)) (message - "Commands: d, s, x, u; f, o, 1, 2, m, v; ~, %%; q to quit; ? for help.")) + "Commands: d, s, x, u; f, o, 1, 2, m, v; ~, %%; D m, D b, D f; q to quit; ? for help.")) ;;;###autoload (defun list-buffers (&optional arg) @@ -651,6 +663,70 @@ means list those buffers and no others." (setq tabulated-list-entries (nreverse entries))) (tabulated-list-init-header)) +(defun Buffer-menu--delete-by-predicate (pred) + (let ((count 0)) + (save-excursion + (Buffer-menu-beginning) + (while (not (eobp)) + (let ((buffer (tabulated-list-get-id)) + (entry (tabulated-list-get-entry))) + (if (funcall pred buffer entry) + (progn + (Buffer-menu-delete 1) + (setq count (1+ count))) + (forward-line 1))))) + (message "Marked %d buffers" count))) + +(defun Buffer-menu-delete-by-major-mode (mode) + "Mark for deletion all buffers whose mode symbol's name is MODE. Interactively, +ask for the MODE, providing completion." + (interactive + (list + (let ((this-line-buffer (tabulated-list-get-id)) + modes) + (save-excursion + (Buffer-menu-beginning) + (while (not (eobp)) + (let ((buffer (tabulated-list-get-id))) + (add-to-list 'modes (with-current-buffer buffer + (symbol-name major-mode)))) + (forward-line 1))) + (completing-read + "Buffer major mode: " (sort modes (function string<)) + nil t nil nil + (when this-line-buffer + (with-current-buffer this-line-buffer + (symbol-name major-mode))))))) + (or mode (error "MODE is nil")) + (Buffer-menu--delete-by-predicate + (lambda (buf entry) + (string= (with-current-buffer buf + (symbol-name major-mode)) + mode)))) + +(defun Buffer-menu-delete-by-buffer-name-regexp (regexp) + "Mark for deletion all buffers whose buffer name matches REGEXP" + (interactive + (list + (read-regexp "Buffer name regexp: " 'regexp-history-last + Buffer-menu--regexp-history))) + (or regexp (error "REGEXP is nil")) + (Buffer-menu--delete-by-predicate + (lambda (buf entry) + (string-match regexp (buffer-name buf))))) + +(defun Buffer-menu-delete-by-file-name-regexp (regexp) + "Mark for deletion all buffers whose file name matches REGEXP" + (interactive + (list + (read-regexp "File name regexp: " 'regexp-history-last + Buffer-menu--regexp-history))) + (or regexp (error "REGEXP is nil")) + (Buffer-menu--delete-by-predicate + (lambda (buf entry) + (and (buffer-file-name buf) + (string-match regexp (buffer-file-name buf)))))) + (defun tabulated-list-entry-size-> (entry1 entry2) (> (string-to-number (aref (cadr entry1) 4)) (string-to-number (aref (cadr entry2) 4))))