diff options
| -rw-r--r-- | lisp/ibuf-ext.el | 156 | ||||
| -rw-r--r-- | test/lisp/ibuffer-tests.el | 29 |
2 files changed, 150 insertions, 35 deletions
diff --git a/lisp/ibuf-ext.el b/lisp/ibuf-ext.el index 5ef07469772..d1bf5769d8c 100644 --- a/lisp/ibuf-ext.el +++ b/lisp/ibuf-ext.el | |||
| @@ -35,7 +35,8 @@ | |||
| 35 | 35 | ||
| 36 | (eval-when-compile | 36 | (eval-when-compile |
| 37 | (require 'ibuf-macs) | 37 | (require 'ibuf-macs) |
| 38 | (require 'cl-lib)) | 38 | (require 'cl-lib) |
| 39 | (require 'subr-x)) | ||
| 39 | 40 | ||
| 40 | ;;; Utility functions | 41 | ;;; Utility functions |
| 41 | (defun ibuffer-delete-alist (key alist) | 42 | (defun ibuffer-delete-alist (key alist) |
| @@ -119,32 +120,100 @@ Buffers whose major mode is in this list, are not searched." | |||
| 119 | 120 | ||
| 120 | (defvar ibuffer-auto-buffers-changed nil) | 121 | (defvar ibuffer-auto-buffers-changed nil) |
| 121 | 122 | ||
| 122 | (defcustom ibuffer-saved-filters '(("gnus" | 123 | (defun ibuffer-update-saved-filters-format (filters) |
| 123 | ((or (mode . message-mode) | 124 | "Transforms alist from old to new `ibuffer-saved-filters' format. |
| 124 | (mode . mail-mode) | 125 | |
| 125 | (mode . gnus-group-mode) | 126 | Specifically, converts old-format alist with values of the |
| 126 | (mode . gnus-summary-mode) | 127 | form (STRING (FILTER-SPECS...)) to alist with values of the |
| 127 | (mode . gnus-article-mode)))) | 128 | form (STRING FILTER-SPECS...), where each filter spec should be a |
| 128 | ("programming" | 129 | cons cell with a symbol in the car. Any elements in the latter |
| 129 | ((or (mode . emacs-lisp-mode) | 130 | form are kept as is. |
| 130 | (mode . cperl-mode) | 131 | |
| 131 | (mode . c-mode) | 132 | Returns (OLD-FORMAT-DETECTED . UPDATED-SAVED-FILTERS-LIST)." |
| 132 | (mode . java-mode) | 133 | (when filters |
| 133 | (mode . idl-mode) | 134 | (let* ((old-format-detected nil) |
| 134 | (mode . lisp-mode))))) | 135 | (fix-filter (lambda (filter-spec) |
| 135 | 136 | (if (symbolp (car (cadr filter-spec))) | |
| 136 | "An alist of filter qualifiers to switch between. | 137 | filter-spec |
| 138 | (setq old-format-detected t) ; side-effect | ||
| 139 | (cons (car filter-spec) (cadr filter-spec))))) | ||
| 140 | (fixed (mapcar fix-filter filters))) | ||
| 141 | (cons old-format-detected fixed)))) | ||
| 137 | 142 | ||
| 138 | This variable should look like ((\"STRING\" QUALIFIERS) | 143 | (defcustom ibuffer-saved-filters '(("gnus" |
| 139 | (\"STRING\" QUALIFIERS) ...), where | 144 | (or (mode . message-mode) |
| 140 | QUALIFIERS is a list of the same form as | 145 | (mode . mail-mode) |
| 141 | `ibuffer-filtering-qualifiers'. | 146 | (mode . gnus-group-mode) |
| 142 | See also the variables `ibuffer-filtering-qualifiers', | 147 | (mode . gnus-summary-mode) |
| 143 | `ibuffer-filtering-alist', and the functions | 148 | (mode . gnus-article-mode))) |
| 144 | `ibuffer-switch-to-saved-filters', `ibuffer-save-filters'." | 149 | ("programming" |
| 145 | :type '(repeat sexp) | 150 | (or (mode . emacs-lisp-mode) |
| 151 | (mode . cperl-mode) | ||
| 152 | (mode . c-mode) | ||
| 153 | (mode . java-mode) | ||
| 154 | (mode . idl-mode) | ||
| 155 | (mode . lisp-mode)))) | ||
| 156 | |||
| 157 | "An alist mapping saved filter names to filter specifications. | ||
| 158 | |||
| 159 | Each element should look like (\"NAME\" . FILTER-LIST), where | ||
| 160 | FILTER-LIST has the same structure as the variable | ||
| 161 | `ibuffer-filtering-qualifiers', which see. The filters defined | ||
| 162 | here are joined with an implicit logical `and' and associated | ||
| 163 | with NAME. The combined specification can be used by name in | ||
| 164 | other filter specifications via the `saved' qualifier (again, see | ||
| 165 | `ibuffer-filtering-qualifiers'). They can also be switched to by | ||
| 166 | name (see the functions `ibuffer-switch-to-saved-filters' and | ||
| 167 | `ibuffer-save-filters'). The variable `ibuffer-save-with-custom' | ||
| 168 | affects how this information is saved for future sessions. This | ||
| 169 | variable can be set directly from lisp code." | ||
| 170 | :version "26.1" | ||
| 171 | :type '(alist :key-type (string :tag "Filter name") | ||
| 172 | :value-type (repeat :tag "Filter specification" sexp)) | ||
| 173 | :set (lambda (symbol value) | ||
| 174 | ;; Just set-default but update legacy old-style format | ||
| 175 | (set-default symbol (cdr (ibuffer-update-saved-filters-format value)))) | ||
| 146 | :group 'ibuffer) | 176 | :group 'ibuffer) |
| 147 | 177 | ||
| 178 | (defvar ibuffer-old-saved-filters-warning | ||
| 179 | (concat "Deprecated format detected for variable `ibuffer-saved-filters'. | ||
| 180 | |||
| 181 | The format has been repaired and the variable modified accordingly. | ||
| 182 | You can save the current value through the customize system by | ||
| 183 | either clicking or hitting return " | ||
| 184 | (make-text-button | ||
| 185 | "here" nil | ||
| 186 | 'face '(:weight bold :inherit button) | ||
| 187 | 'mouse-face '(:weight normal :background "gray50" :inherit button) | ||
| 188 | 'follow-link t | ||
| 189 | 'help-echo "Click or RET: save new value in customize" | ||
| 190 | 'action (lambda (_) | ||
| 191 | (if (not (fboundp 'customize-save-variable)) | ||
| 192 | (message "Customize not available; value not saved") | ||
| 193 | (customize-save-variable 'ibuffer-saved-filters | ||
| 194 | ibuffer-saved-filters) | ||
| 195 | (message "Saved updated ibuffer-saved-filters.")))) | ||
| 196 | ". See below for | ||
| 197 | an explanation and alternative ways to save the repaired value. | ||
| 198 | |||
| 199 | Explanation: For the list variable `ibuffer-saved-filters', | ||
| 200 | elements of the form (STRING (FILTER-SPECS...)) are deprecated | ||
| 201 | and should instead have the form (STRING FILTER-SPECS...), where | ||
| 202 | each filter spec is a cons cell with a symbol in the car. See | ||
| 203 | `ibuffer-saved-filters' for details. The repaired value fixes | ||
| 204 | this format without changing the meaning of the saved filters. | ||
| 205 | |||
| 206 | Alternative ways to save the repaired value: | ||
| 207 | |||
| 208 | 1. Do M-x customize-variable and entering `ibuffer-saved-filters' | ||
| 209 | when prompted. | ||
| 210 | |||
| 211 | 2. Set the updated value manually by copying the | ||
| 212 | following emacs-lisp form to your emacs init file. | ||
| 213 | |||
| 214 | %s | ||
| 215 | ")) | ||
| 216 | |||
| 148 | (defvar ibuffer-filtering-qualifiers nil | 217 | (defvar ibuffer-filtering-qualifiers nil |
| 149 | "A list like (SYMBOL . QUALIFIER) which filters the current buffer list. | 218 | "A list like (SYMBOL . QUALIFIER) which filters the current buffer list. |
| 150 | See also `ibuffer-filtering-alist'.") | 219 | See also `ibuffer-filtering-alist'.") |
| @@ -224,6 +293,28 @@ Currently, this only applies to `ibuffer-saved-filters' and | |||
| 224 | :type 'boolean | 293 | :type 'boolean |
| 225 | :group 'ibuffer) | 294 | :group 'ibuffer) |
| 226 | 295 | ||
| 296 | (defun ibuffer-repair-saved-filters () | ||
| 297 | "Updates `ibuffer-saved-filters' to its new-style format, if needed. | ||
| 298 | |||
| 299 | If this list has any elements of the old-style format, a | ||
| 300 | deprecation warning is raised, with a button allowing persistent | ||
| 301 | update. Any updated filters retain their meaning in the new | ||
| 302 | format. See `ibuffer-update-saved-filters-format' and | ||
| 303 | `ibuffer-saved-filters' for details of the old and new formats." | ||
| 304 | (interactive) | ||
| 305 | (when (and (boundp 'ibuffer-saved-filters) ibuffer-saved-filters) | ||
| 306 | (let ((fixed (ibuffer-update-saved-filters-format ibuffer-saved-filters))) | ||
| 307 | (prog1 | ||
| 308 | (setq ibuffer-saved-filters (cdr fixed)) | ||
| 309 | (when-let (old-format-detected (car fixed)) | ||
| 310 | (let ((warning-series t) | ||
| 311 | (updated-form | ||
| 312 | (with-output-to-string | ||
| 313 | (pp `(setq ibuffer-saved-filters ',ibuffer-saved-filters))))) | ||
| 314 | (display-warning | ||
| 315 | 'ibuffer | ||
| 316 | (format ibuffer-old-saved-filters-warning updated-form)))))))) | ||
| 317 | |||
| 227 | (defun ibuffer-ext-visible-p (buf all &optional ibuffer-buf) | 318 | (defun ibuffer-ext-visible-p (buf all &optional ibuffer-buf) |
| 228 | (or | 319 | (or |
| 229 | (ibuffer-buf-matches-predicates buf ibuffer-tmp-show-regexps) | 320 | (ibuffer-buf-matches-predicates buf ibuffer-tmp-show-regexps) |
| @@ -535,13 +626,11 @@ To evaluate a form without viewing the buffer, see `ibuffer-do-eval'." | |||
| 535 | (ibuffer-included-in-filter-p buf x)) | 626 | (ibuffer-included-in-filter-p buf x)) |
| 536 | (cdr filter)))) | 627 | (cdr filter)))) |
| 537 | (`saved | 628 | (`saved |
| 538 | (let ((data | 629 | (let ((data (assoc (cdr filter) ibuffer-saved-filters))) |
| 539 | (assoc (cdr filter) | ||
| 540 | ibuffer-saved-filters))) | ||
| 541 | (unless data | 630 | (unless data |
| 542 | (ibuffer-filter-disable t) | 631 | (ibuffer-filter-disable t) |
| 543 | (error "Unknown saved filter %s" (cdr filter))) | 632 | (error "Unknown saved filter %s" (cdr filter))) |
| 544 | (ibuffer-included-in-filters-p buf (cadr data)))) | 633 | (ibuffer-included-in-filters-p buf (cdr data)))) |
| 545 | (_ | 634 | (_ |
| 546 | (pcase-let ((`(,_type ,_desc ,func) | 635 | (pcase-let ((`(,_type ,_desc ,func) |
| 547 | (assq (car filter) ibuffer-filtering-alist))) | 636 | (assq (car filter) ibuffer-filtering-alist))) |
| @@ -849,15 +938,12 @@ turned into two separate filters [name: foo] and [mode: bar-mode]." | |||
| 849 | (cdr lim) | 938 | (cdr lim) |
| 850 | ibuffer-filtering-qualifiers))) | 939 | ibuffer-filtering-qualifiers))) |
| 851 | (`saved | 940 | (`saved |
| 852 | (let ((data | 941 | (let ((data (assoc (cdr lim) ibuffer-saved-filters))) |
| 853 | (assoc (cdr lim) | ||
| 854 | ibuffer-saved-filters))) | ||
| 855 | (unless data | 942 | (unless data |
| 856 | (ibuffer-filter-disable) | 943 | (ibuffer-filter-disable) |
| 857 | (error "Unknown saved filter %s" (cdr lim))) | 944 | (error "Unknown saved filter %s" (cdr lim))) |
| 858 | (setq ibuffer-filtering-qualifiers (append | 945 | (setq ibuffer-filtering-qualifiers |
| 859 | (cadr data) | 946 | (append (cdr data) ibuffer-filtering-qualifiers)))) |
| 860 | ibuffer-filtering-qualifiers)))) | ||
| 861 | (`not | 947 | (`not |
| 862 | (push (cdr lim) | 948 | (push (cdr lim) |
| 863 | ibuffer-filtering-qualifiers)) | 949 | ibuffer-filtering-qualifiers)) |
| @@ -936,7 +1022,7 @@ Interactively, prompt for NAME, and use the current filters." | |||
| 936 | ibuffer-filtering-qualifiers))) | 1022 | ibuffer-filtering-qualifiers))) |
| 937 | (ibuffer-aif (assoc name ibuffer-saved-filters) | 1023 | (ibuffer-aif (assoc name ibuffer-saved-filters) |
| 938 | (setcdr it filters) | 1024 | (setcdr it filters) |
| 939 | (push (list name filters) ibuffer-saved-filters)) | 1025 | (push (cons name filters) ibuffer-saved-filters)) |
| 940 | (ibuffer-maybe-save-stuff)) | 1026 | (ibuffer-maybe-save-stuff)) |
| 941 | 1027 | ||
| 942 | ;;;###autoload | 1028 | ;;;###autoload |
diff --git a/test/lisp/ibuffer-tests.el b/test/lisp/ibuffer-tests.el index 3a4def3a2b0..6d5187a2b77 100644 --- a/test/lisp/ibuffer-tests.el +++ b/test/lisp/ibuffer-tests.el | |||
| @@ -66,5 +66,34 @@ | |||
| 66 | (mapc (lambda (buf) (when (buffer-live-p buf) | 66 | (mapc (lambda (buf) (when (buffer-live-p buf) |
| 67 | (kill-buffer buf))) (list buf1 buf2))))) | 67 | (kill-buffer buf))) (list buf1 buf2))))) |
| 68 | 68 | ||
| 69 | (ert-deftest ibuffer-save-filters () | ||
| 70 | "Tests that `ibuffer-save-filters' saves in the proper format." | ||
| 71 | (skip-unless (featurep 'ibuf-ext)) | ||
| 72 | (let ((ibuffer-save-with-custom nil) | ||
| 73 | (ibuffer-saved-filters nil) | ||
| 74 | (test1 '((mode . org-mode) | ||
| 75 | (or (size-gt . 10000) | ||
| 76 | (and (not (starred-name)) | ||
| 77 | (directory . "\<org\>"))))) | ||
| 78 | (test2 '((or (mode . emacs-lisp-mode) (file-extension . "elc?") | ||
| 79 | (and (starred-name) (name . "elisp")) | ||
| 80 | (mode . lisp-interaction-mode)))) | ||
| 81 | (test3 '((size-lt . 100) (derived-mode . prog-mode) | ||
| 82 | (or (filename . "scratch") | ||
| 83 | (filename . "bonz") | ||
| 84 | (filename . "temp"))))) | ||
| 85 | (ibuffer-save-filters "test1" test1) | ||
| 86 | (should (equal (car ibuffer-saved-filters) (cons "test1" test1))) | ||
| 87 | (ibuffer-save-filters "test2" test2) | ||
| 88 | (should (equal (car ibuffer-saved-filters) (cons "test2" test2))) | ||
| 89 | (should (equal (cadr ibuffer-saved-filters) (cons "test1" test1))) | ||
| 90 | (ibuffer-save-filters "test3" test3) | ||
| 91 | (should (equal (car ibuffer-saved-filters) (cons "test3" test3))) | ||
| 92 | (should (equal (cadr ibuffer-saved-filters) (cons "test2" test2))) | ||
| 93 | (should (equal (car (cddr ibuffer-saved-filters)) (cons "test1" test1))) | ||
| 94 | (should (equal (cdr (assoc "test1" ibuffer-saved-filters)) test1)) | ||
| 95 | (should (equal (cdr (assoc "test2" ibuffer-saved-filters)) test2)) | ||
| 96 | (should (equal (cdr (assoc "test3" ibuffer-saved-filters)) test3)))) | ||
| 97 | |||
| 69 | (provide 'ibuffer-tests) | 98 | (provide 'ibuffer-tests) |
| 70 | ;; ibuffer-tests.el ends here | 99 | ;; ibuffer-tests.el ends here |