unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#32731: 26.1.50; Ibuffer filter by mode: Handle >1 mode names
@ 2018-09-13 18:19 Tino Calancha
  2018-09-13 19:09 ` Noam Postavsky
  0 siblings, 1 reply; 28+ messages in thread
From: Tino Calancha @ 2018-09-13 18:19 UTC (permalink / raw)
  To: 32731


Severity: wishlist

Ibuffer filtering is a great feature.
If you just want to filter by 1 major, then it's quite straight.

/m [mode1-name] RET

Filtering by >1 major mode is still possible; you must
combine the individuals filters with `ibuffer-or-filter':

/m [mode1-name] RET
/m [mode2-name] RET
/|
/m [mode3-name] RET
/|
.
.
.
/m [modeN-name] RET
/|

This become a bit cumbersome with > 2 mode names; you also need to
remember how to combine filters, which I usually forget :-|

Following patch adds a new command `ibuffer-filter-by-used-modes',
similar as `ibuffer-filter-by-used-mode', to simplify this filtering.

The new command accepts a list of mode names, and it takes care
internally of the filter composition.

Interactively, it preserves the interface of `ibuffer-filter-by-used-mode',
with the only difference that the user might input a comma separated
list of mode names.  For instance,

;; Following produces identical result as the original command
M-x ibuffer-filter-by-used-modes RET mode1-mode RET

;; This is equivalent to create the N filters + OR-compose them
M-x ibuffer-filter-by-used-modes RET mode1-mode,mode2-mode,...,modeN-mode RET

--8<-----------------------------cut here---------------start------------->8---
commit e36ff5779764e531cc149e4342e93cb6e37c30ee
Author: Tino Calancha <tino.calancha@gmail.com>
Date:   Fri Sep 14 03:10:11 2018 +0900

    Ibuffer filter by mode: Handle >1 mode names
    
    Extend used mode filtering so that we can input >1 mode.
    For instance, if we want to filter all buffers in
    C or C++ mode, then we can call the filter interactively
    with input: 'c-mode,c++-mode'.
    
    * lisp/ibuf-ext.el (ibuffer-filter-by-used-modes):
    New command.  Accept a list of mode names (symbols).
    Interactively, accept a comma separated list of mode names.
    * lisp/ibuffer.el(ibuffer-mode-map): Rebind '/ m' to
    the new command.
    * etc/NEWS(Ibuffer): Announce this change.

diff --git a/etc/NEWS b/etc/NEWS
index a54ac2db43..6ef6f20b05 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -48,6 +48,11 @@ often cause crashes.  Set it to nil if you really need those fonts.
 ** Ibuffer
 
 ---
+*** The new command 'ibuffer-filter-by-used-modes', bound
+to '/ m', extends 'ibuffer-filter-by-used-mode'; it makes easy
+filtering buffers by a list of major modes.
+
+---
 *** New toggle 'ibuffer-do-toggle-lock', bound to 'L'.
 
 ** Imenu
diff --git a/lisp/ibuf-ext.el b/lisp/ibuf-ext.el
index a3143e5e29..b7c3ae8030 100644
--- a/lisp/ibuf-ext.el
+++ b/lisp/ibuf-ext.el
@@ -1265,6 +1265,34 @@ used-mode
        (ibuffer-list-buffer-modes) nil t nil nil default))))
   (eq qualifier (buffer-local-value 'major-mode buf)))
 
+;;;###autoload
+(defun ibuffer-filter-by-used-modes(modes)
+  "Limit current view to buffers with major mode in MODES.
+MODES is a list of mode names (symbols).
+When called interactively, accept the mode names separated by commas."
+  (interactive
+   (let* ((buf (ibuffer-current-buffer))
+          (default (if (and buf (buffer-live-p buf))
+                       (symbol-name (buffer-local-value
+                                     'major-mode buf)))))
+     (list
+      (mapcar #'intern
+              (split-string
+               (completing-read
+                (if default
+                    (format "Filter by major mode (default %s): " default)
+                  "Filter by major mode: ")
+                (ibuffer-list-buffer-modes)
+                nil nil nil nil default)
+               "\\s-*,\\s-*" t)))))
+  (setq modes (delete-dups modes))
+  (mapc #'ibuffer-filter-by-used-mode modes)
+  (let ((nb_modes (length modes)))
+    (when (>= nb_modes 2)
+      (cl-loop repeat (- nb_modes 2) do (ibuffer-or-filter))
+      (message nil)
+      (ibuffer-or-filter))))
+
 ;;;###autoload (autoload 'ibuffer-filter-by-derived-mode "ibuf-ext")
 (define-ibuffer-filter derived-mode
     "Limit current view to buffers whose major mode inherits from QUALIFIER."
diff --git a/lisp/ibuffer.el b/lisp/ibuffer.el
index 08b0801cb5..f7c20d0da3 100644
--- a/lisp/ibuffer.el
+++ b/lisp/ibuffer.el
@@ -519,7 +519,7 @@ ibuffer-mode-map
     (define-key map (kbd "s m") 'ibuffer-do-sort-by-major-mode)
 
     (define-key map (kbd "/ RET") 'ibuffer-filter-by-mode)
-    (define-key map (kbd "/ m") 'ibuffer-filter-by-used-mode)
+    (define-key map (kbd "/ m") 'ibuffer-filter-by-used-modes)
     (define-key map (kbd "/ M") 'ibuffer-filter-by-derived-mode)
     (define-key map (kbd "/ n") 'ibuffer-filter-by-name)
     (define-key map (kbd "/ *") 'ibuffer-filter-by-starred-name)
--8<-----------------------------cut here---------------end--------------->8---
In GNU Emacs 26.1.50 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.22.11)
 of 2018-09-14 built
Repository revision: 41cdda22c78eb0b00612ce25cdb356dd64322fcc





^ permalink raw reply related	[flat|nested] 28+ messages in thread

* bug#32731: 26.1.50; Ibuffer filter by mode: Handle >1 mode names
  2018-09-13 18:19 bug#32731: 26.1.50; Ibuffer filter by mode: Handle >1 mode names Tino Calancha
@ 2018-09-13 19:09 ` Noam Postavsky
  2018-09-13 20:04   ` Tino Calancha
  2018-09-13 20:38   ` Tino Calancha
  0 siblings, 2 replies; 28+ messages in thread
From: Noam Postavsky @ 2018-09-13 19:09 UTC (permalink / raw)
  To: Tino Calancha; +Cc: 32731

On 13 September 2018 at 14:19, Tino Calancha <tino.calancha@gmail.com> wrote:

> +;;;###autoload
> +(defun ibuffer-filter-by-used-modes(modes)
> +  "Limit current view to buffers with major mode in MODES.
> +MODES is a list of mode names (symbols).
> +When called interactively, accept the mode names separated by commas."
> +  (interactive
> +   (let* ((buf (ibuffer-current-buffer))
> +          (default (if (and buf (buffer-live-p buf))
> +                       (symbol-name (buffer-local-value
> +                                     'major-mode buf)))))
> +     (list
> +      (mapcar #'intern
> +              (split-string
> +               (completing-read
> +                (if default
> +                    (format "Filter by major mode (default %s): " default)
> +                  "Filter by major mode: ")
> +                (ibuffer-list-buffer-modes)
> +                nil nil nil nil default)
> +               "\\s-*,\\s-*" t)))))

This will use completion only for the first mode, right? Perhaps
completing-read-multiple would make more sense here.

> +  (setq modes (delete-dups modes))
> +  (mapc #'ibuffer-filter-by-used-mode modes)
> +  (let ((nb_modes (length modes)))
> +    (when (>= nb_modes 2)
> +      (cl-loop repeat (- nb_modes 2) do (ibuffer-or-filter))
> +      (message nil)

What's this `message' call for?

> +      (ibuffer-or-filter))))

Maybe it's simpler to construct the filter directly? As in:

  (push `(or ,@(mapcar (lambda (m) `(used-mode . ,m)) modes))
        ibuffer-filtering-qualifiers)
  (ibuffer-update nil t)





^ permalink raw reply	[flat|nested] 28+ messages in thread

* bug#32731: 26.1.50; Ibuffer filter by mode: Handle >1 mode names
  2018-09-13 19:09 ` Noam Postavsky
@ 2018-09-13 20:04   ` Tino Calancha
  2018-09-13 20:38   ` Tino Calancha
  1 sibling, 0 replies; 28+ messages in thread
From: Tino Calancha @ 2018-09-13 20:04 UTC (permalink / raw)
  To: Noam Postavsky; +Cc: 32731, Tino Calancha



On Thu, 13 Sep 2018, Noam Postavsky wrote:

> On 13 September 2018 at 14:19, Tino Calancha <tino.calancha@gmail.com> wrote:
>
>> +;;;###autoload
>> +(defun ibuffer-filter-by-used-modes(modes)
>> +  "Limit current view to buffers with major mode in MODES.
>> +MODES is a list of mode names (symbols).
>> +When called interactively, accept the mode names separated by commas."
>> +  (interactive
>> +   (let* ((buf (ibuffer-current-buffer))
>> +          (default (if (and buf (buffer-live-p buf))
>> +                       (symbol-name (buffer-local-value
>> +                                     'major-mode buf)))))
>> +     (list
>> +      (mapcar #'intern
>> +              (split-string
>> +               (completing-read
>> +                (if default
>> +                    (format "Filter by major mode (default %s): " default)
>> +                  "Filter by major mode: ")
>> +                (ibuffer-list-buffer-modes)
>> +                nil nil nil nil default)
>> +               "\\s-*,\\s-*" t)))))
>
> This will use completion only for the first mode, right?
Yeah, that's right.
> Perhaps completing-read-multiple would make more sense here.
Hummmm, it sounds like a good idea.  I will look on it.

>> +  (setq modes (delete-dups modes))
>> +  (mapc #'ibuffer-filter-by-used-mode modes)
>> +  (let ((nb_modes (length modes)))
>> +    (when (>= nb_modes 2)
>> +      (cl-loop repeat (- nb_modes 2) do (ibuffer-or-filter))
>> +      (message nil)
>
> What's this `message' call for?
To clean the minibuffer after the second filter fails;
before you do the composition, you have an implicit AND, so
you are requiring:
(and (eq major-mode mode1-mode) (eq major-mode mode2-mode))
;; This fails
;; after  `ibuffer-or-filter' previous line is changed to:
(or (eq major-mode mode1-mode) (eq major-mode mode2-mode))

>> +      (ibuffer-or-filter))))
>
> Maybe it's simpler to construct the filter directly? As in:
>
>  (push `(or ,@(mapcar (lambda (m) `(used-mode . ,m)) modes))
>        ibuffer-filtering-qualifiers)
>  (ibuffer-update nil t)
Right, much more elegant.  Thank you!
I will update the patch accordingly





^ permalink raw reply	[flat|nested] 28+ messages in thread

* bug#32731: 26.1.50; Ibuffer filter by mode: Handle >1 mode names
  2018-09-13 19:09 ` Noam Postavsky
  2018-09-13 20:04   ` Tino Calancha
@ 2018-09-13 20:38   ` Tino Calancha
  2018-09-13 23:39     ` Noam Postavsky
  1 sibling, 1 reply; 28+ messages in thread
From: Tino Calancha @ 2018-09-13 20:38 UTC (permalink / raw)
  To: Noam Postavsky; +Cc: 32731

Noam Postavsky <npostavs@gmail.com> writes:

> This will use completion only for the first mode, right? Perhaps
> completing-read-multiple would make more sense here.
This is very nice suggestion!  I never used this nice defun before!
(`completing-read-multiple')

> Maybe it's simpler to construct the filter directly? As in:
>
>   (push `(or ,@(mapcar (lambda (m) `(used-mode . ,m)) modes))
>         ibuffer-filtering-qualifiers)
>   (ibuffer-update nil t)
I tried this way and I see 2 nits:
1) With just one mode you still get superflous `or'
   [OR [major mode in use: mode1]]

2) Also, with just one mode, we miss the printout message
   with the description:
"Filter by major mode in use added:  mode1"

Less important but `define-ibuffer-filter' performs some checks
(there is a `condition-case').

Following is a patch on top of previous patch with all your suggestions:
--8<-----------------------------cut here---------------start------------->8---
commit 5a0657d2d06dd495090d49fae477dbc624b1c85b
Author: Tino Calancha <tino.calancha@gmail.com>
Date:   Fri Sep 14 05:22:32 2018 +0900

    Use completing-read-multiple
    
    * lisp/ibuf-ext.el (ibuffer-filter-by-used-modes): Construct
    teh filter by hand, instead of callig `completing-read-multiple'.

diff --git a/lisp/ibuf-ext.el b/lisp/ibuf-ext.el
index b7c3ae8030..f2f9ce8bce 100644
--- a/lisp/ibuf-ext.el
+++ b/lisp/ibuf-ext.el
@@ -1277,21 +1277,16 @@ ibuffer-filter-by-used-modes
                                      'major-mode buf)))))
      (list
       (mapcar #'intern
-              (split-string
-               (completing-read
-                (if default
-                    (format "Filter by major mode (default %s): " default)
-                  "Filter by major mode: ")
-                (ibuffer-list-buffer-modes)
-                nil nil nil nil default)
-               "\\s-*,\\s-*" t)))))
+              (completing-read-multiple
+               (if default
+                   (format "Filter by major mode (default %s): " default)
+                 "Filter by major mode: ")
+               (ibuffer-list-buffer-modes)
+               nil t nil nil nil default)))))
   (setq modes (delete-dups modes))
-  (mapc #'ibuffer-filter-by-used-mode modes)
-  (let ((nb_modes (length modes)))
-    (when (>= nb_modes 2)
-      (cl-loop repeat (- nb_modes 2) do (ibuffer-or-filter))
-      (message nil)
-      (ibuffer-or-filter))))
+  (push `(or ,@(mapcar (lambda (m) `(used-mode . ,m)) modes))
+        ibuffer-filtering-qualifiers)
+  (ibuffer-update nil t))
 
 ;;;###autoload (autoload 'ibuffer-filter-by-derived-mode "ibuf-ext")
 (define-ibuffer-filter derived-mode
--8<-----------------------------cut here---------------end--------------->8---

Next one just use `completing-read-multiple' (keeps calling
`'ibuffer-filter-by-used-mode'); I prefer this one:
--8<-----------------------------cut here---------------start------------->8---
commit af9471040740d351208da7bc929219b291674d67
Author: Tino Calancha <tino.calancha@gmail.com>
Date:   Fri Sep 14 05:36:35 2018 +0900

    Ibuffer filter by modes: Accept several mode names
    
    Extend mode filters so that we can input more than 1 mode.
    For instance, if we want to filter all buffers in
    C or C++ mode, then we can call the filter interactively
    with input: 'c-mode,c++-mode'.
    
    * lisp/ibuf-ext.el (ibuffer-filter-by-used-modes):
    New command.  Accept a list of mode names (symbols).
    Interactively, accept a comma separated list of mode names.
    * lisp/ibuffer.el(ibuffer-mode-map): Rebind '/ m' to
    the new command.
    * etc/NEWS(Ibuffer): Announce this change.
    
    Co-authored-by: Noam Postavsky <npostavs@gmail.com>

diff --git a/etc/NEWS b/etc/NEWS
index a54ac2db43..6ef6f20b05 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -48,6 +48,11 @@ often cause crashes.  Set it to nil if you really need those fonts.
 ** Ibuffer
 
 ---
+*** The new command 'ibuffer-filter-by-used-modes', bound
+to '/ m', extends 'ibuffer-filter-by-used-mode'; it makes easy
+filtering buffers by a list of major modes.
+
+---
 *** New toggle 'ibuffer-do-toggle-lock', bound to 'L'.
 
 ** Imenu
diff --git a/lisp/ibuf-ext.el b/lisp/ibuf-ext.el
index a3143e5e29..048d0bc126 100644
--- a/lisp/ibuf-ext.el
+++ b/lisp/ibuf-ext.el
@@ -1265,6 +1265,32 @@ used-mode
        (ibuffer-list-buffer-modes) nil t nil nil default))))
   (eq qualifier (buffer-local-value 'major-mode buf)))
 
+;;;###autoload
+(defun ibuffer-filter-by-used-modes(modes)
+  "Limit current view to buffers with major mode in MODES.
+MODES is a list of mode names (symbols).
+When called interactively, accept the mode names separated by commas."
+  (interactive
+   (let* ((buf (ibuffer-current-buffer))
+          (default (if (and buf (buffer-live-p buf))
+                       (symbol-name (buffer-local-value
+                                     'major-mode buf)))))
+     (list
+      (mapcar #'intern
+              (completing-read-multiple
+               (if default
+                   (format "Filter by major mode (default %s): " default)
+                 "Filter by major mode: ")
+               (ibuffer-list-buffer-modes)
+               nil t nil nil nil default)))))
+  (setq modes (delete-dups modes))
+  (mapc #'ibuffer-filter-by-used-mode modes)
+  (let ((nb_modes (length modes)))
+    (when (>= nb_modes 2)
+      (cl-loop repeat (- nb_modes 2) do (ibuffer-or-filter))
+      (message nil)
+      (ibuffer-or-filter))))
+
 ;;;###autoload (autoload 'ibuffer-filter-by-derived-mode "ibuf-ext")
 (define-ibuffer-filter derived-mode
     "Limit current view to buffers whose major mode inherits from QUALIFIER."
diff --git a/lisp/ibuffer.el b/lisp/ibuffer.el
index 08b0801cb5..f7c20d0da3 100644
--- a/lisp/ibuffer.el
+++ b/lisp/ibuffer.el
@@ -519,7 +519,7 @@ ibuffer-mode-map
     (define-key map (kbd "s m") 'ibuffer-do-sort-by-major-mode)
 
     (define-key map (kbd "/ RET") 'ibuffer-filter-by-mode)
-    (define-key map (kbd "/ m") 'ibuffer-filter-by-used-mode)
+    (define-key map (kbd "/ m") 'ibuffer-filter-by-used-modes)
     (define-key map (kbd "/ M") 'ibuffer-filter-by-derived-mode)
     (define-key map (kbd "/ n") 'ibuffer-filter-by-name)
     (define-key map (kbd "/ *") 'ibuffer-filter-by-starred-name)

--8<-----------------------------cut here---------------end--------------->8---





^ permalink raw reply related	[flat|nested] 28+ messages in thread

* bug#32731: 26.1.50; Ibuffer filter by mode: Handle >1 mode names
  2018-09-13 20:38   ` Tino Calancha
@ 2018-09-13 23:39     ` Noam Postavsky
  2018-09-15  9:15       ` Tino Calancha
  0 siblings, 1 reply; 28+ messages in thread
From: Noam Postavsky @ 2018-09-13 23:39 UTC (permalink / raw)
  To: Tino Calancha; +Cc: 32731

Tino Calancha <tino.calancha@gmail.com> writes:

>> Maybe it's simpler to construct the filter directly? As in:
>>
>>   (push `(or ,@(mapcar (lambda (m) `(used-mode . ,m)) modes))
>>         ibuffer-filtering-qualifiers)
>>   (ibuffer-update nil t)
> I tried this way and I see 2 nits:
> 1) With just one mode you still get superflous `or'
>    [OR [major mode in use: mode1]]
>
> 2) Also, with just one mode, we miss the printout message
>    with the description:
> "Filter by major mode in use added:  mode1"

Yeah, we need special cases for lists of zero and one modes.

> Less important but `define-ibuffer-filter' performs some checks
> (there is a `condition-case').

The condition-case thing is in a lambda form which goes into
ibuffer-filtering-alist, so I don't think there is a need to explicitly
invoke it when constructing a filter of an existing type.

> Next one just use `completing-read-multiple' (keeps calling
> `'ibuffer-filter-by-used-mode'); I prefer this one:

I would be okay if it was just a matter of repeated ibuffer-filter-*
calls, but the fact that it produces error messages which then need to
be hidden makes it unacceptable, IMO.





^ permalink raw reply	[flat|nested] 28+ messages in thread

* bug#32731: 26.1.50; Ibuffer filter by mode: Handle >1 mode names
  2018-09-13 23:39     ` Noam Postavsky
@ 2018-09-15  9:15       ` Tino Calancha
  2018-09-15 12:42         ` Noam Postavsky
  0 siblings, 1 reply; 28+ messages in thread
From: Tino Calancha @ 2018-09-15  9:15 UTC (permalink / raw)
  To: Noam Postavsky; +Cc: 32731

Noam Postavsky <npostavs@gmail.com> writes:

> Tino Calancha <tino.calancha@gmail.com> writes:
>
> Yeah, we need special cases for lists of zero and one modes.
No problem.

>> Less important but `define-ibuffer-filter' performs some checks
>> (there is a `condition-case').
>
> The condition-case thing is in a lambda form which goes into
> ibuffer-filtering-alist, so I don't think there is a need to explicitly
> invoke it when constructing a filter of an existing type.
Absolutely.  Sorry for the noise.

>> Next one just use `completing-read-multiple' (keeps calling
>> `'ibuffer-filter-by-used-mode'); I prefer this one:
>
> I would be okay if it was just a matter of repeated ibuffer-filter-*
> calls, but the fact that it produces error messages which then need to
> be hidden makes it unacceptable, IMO.
I agree with you: those messages must not be produced.

BTW, I've noticed following commit is missing in the release branch:
'Make ibuffer filters idempotent'
(ee6fe8378a28444cb4913abca4af742f736e9b45)

I suggest we backport it.
Then, I am OK with the next patch (which uses that commit):
--8<-----------------------------cut here---------------start------------->8---
commit c60a9bb36d4d4092866f36d1d8b246b79c1a2fd8
Author: Tino Calancha <tino.calancha@gmail.com>
Date:   Sat Sep 15 18:01:14 2018 +0900

    Ibuffer filter by modes: Accept several mode names
    
    Extend mode filters so that we can input more than 1 mode.
    For instance, if we want to filter all buffers in
    C or C++ mode, then we can call the filter interactively
    with input: 'c-mode,c++-mode'.
    
    * lisp/ibuf-ext.el (ibuffer-filter-by-used-modes):
    New command.  Accept a list of mode names (symbols).
    Interactively, accept a comma separated list of mode names.
    * lisp/ibuffer.el(ibuffer-mode-map): Rebind '/ m' to
    the new command.
    * etc/NEWS(Ibuffer): Announce this change.
    
    Co-authored-by: Noam Postavsky <npostavs@gmail.com>

diff --git a/etc/NEWS b/etc/NEWS
index a54ac2db43..6ef6f20b05 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -48,6 +48,11 @@ often cause crashes.  Set it to nil if you really need those fonts.
 ** Ibuffer
 
 ---
+*** The new command 'ibuffer-filter-by-used-modes', bound
+to '/ m', extends 'ibuffer-filter-by-used-mode'; it makes easy
+filtering buffers by a list of major modes.
+
+---
 *** New toggle 'ibuffer-do-toggle-lock', bound to 'L'.
 
 ** Imenu
diff --git a/lisp/ibuf-ext.el b/lisp/ibuf-ext.el
index a3143e5e29..7094ae2674 100644
--- a/lisp/ibuf-ext.el
+++ b/lisp/ibuf-ext.el
@@ -1265,6 +1265,35 @@ used-mode
        (ibuffer-list-buffer-modes) nil t nil nil default))))
   (eq qualifier (buffer-local-value 'major-mode buf)))
 
+;;;###autoload
+(defun ibuffer-filter-by-used-modes(modes)
+  "Limit current view to buffers with major mode in MODES.
+MODES is a list of mode names (symbols).
+When called interactively, accept the mode names separated by commas."
+  (interactive
+   (let* ((buf (ibuffer-current-buffer))
+          (default (if (and buf (buffer-live-p buf))
+                       (symbol-name (buffer-local-value
+                                     'major-mode buf)))))
+     (list
+      (mapcar #'intern
+              (completing-read-multiple
+               (if default
+                   (format "Filter by major mode (default %s): " default)
+                 "Filter by major mode: ")
+               (ibuffer-list-buffer-modes)
+               nil t nil nil default)))))
+  ;; Sort to avoid adding filter (or mode2 mode1) once we have (or mode1 mode2)
+  (setq modes (sort (delete-dups modes) #'string-lessp))
+  (cond ((null (cdr modes)) (ibuffer-filter-by-used-mode (car modes)))
+        (t (let ((composed-filter
+                  `(or ,@(mapcar (lambda (m) `(used-mode . ,m)) modes)))
+                 (mode-names (mapconcat #'symbol-name modes ",")))
+             (if (null (ibuffer-push-filter composed-filter))
+                 (message "Filter by mode in use already applied: %s" mode-names)
+               (message "Filter by mode in use added: %s" mode-names)
+               (ibuffer-update nil t))))))
+
 ;;;###autoload (autoload 'ibuffer-filter-by-derived-mode "ibuf-ext")
 (define-ibuffer-filter derived-mode
     "Limit current view to buffers whose major mode inherits from QUALIFIER."
diff --git a/lisp/ibuffer.el b/lisp/ibuffer.el
index 08b0801cb5..f7c20d0da3 100644
--- a/lisp/ibuffer.el
+++ b/lisp/ibuffer.el
@@ -519,7 +519,7 @@ ibuffer-mode-map
     (define-key map (kbd "s m") 'ibuffer-do-sort-by-major-mode)
 
     (define-key map (kbd "/ RET") 'ibuffer-filter-by-mode)
-    (define-key map (kbd "/ m") 'ibuffer-filter-by-used-mode)
+    (define-key map (kbd "/ m") 'ibuffer-filter-by-used-modes)
     (define-key map (kbd "/ M") 'ibuffer-filter-by-derived-mode)
     (define-key map (kbd "/ n") 'ibuffer-filter-by-name)
     (define-key map (kbd "/ *") 'ibuffer-filter-by-starred-name)

--8<-----------------------------cut here---------------end--------------->8---
In GNU Emacs 26.0.50 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.22.11)
Repository revision: 41cdda22c78eb0b00612ce25cdb356dd64322fcc





^ permalink raw reply related	[flat|nested] 28+ messages in thread

* bug#32731: 26.1.50; Ibuffer filter by mode: Handle >1 mode names
  2018-09-15  9:15       ` Tino Calancha
@ 2018-09-15 12:42         ` Noam Postavsky
  2018-09-17 17:44           ` Tino Calancha
  0 siblings, 1 reply; 28+ messages in thread
From: Noam Postavsky @ 2018-09-15 12:42 UTC (permalink / raw)
  To: Tino Calancha; +Cc: 32731

Tino Calancha <tino.calancha@gmail.com> writes:

> BTW, I've noticed following commit is missing in the release branch:
> 'Make ibuffer filters idempotent'
> (ee6fe8378a28444cb4913abca4af742f736e9b45)
>
> I suggest we backport it.
> Then, I am OK with the next patch (which uses that commit):

Shouldn't this patch be going into master anyway (since it's adding a
new feature)?

> +  (cond ((null (cdr modes)) (ibuffer-filter-by-used-mode (car modes)))
> +        (t (let ((composed-filter

We should handle the (null modes) case too, but otherwise looks good to
me.





^ permalink raw reply	[flat|nested] 28+ messages in thread

* bug#32731: 26.1.50; Ibuffer filter by mode: Handle >1 mode names
  2018-09-15 12:42         ` Noam Postavsky
@ 2018-09-17 17:44           ` Tino Calancha
  2018-09-17 18:27             ` Eli Zaretskii
  2018-09-18 23:19             ` Noam Postavsky
  0 siblings, 2 replies; 28+ messages in thread
From: Tino Calancha @ 2018-09-17 17:44 UTC (permalink / raw)
  To: Noam Postavsky; +Cc: 32731

Noam Postavsky <npostavs@gmail.com> writes:

>Shouldn't this patch be going into master anyway (since it's adding a
>new feature)?
I think is pretty tiny and safe new feature.  We can ask Eli anyway
[probably he is reading this right now :-)]

>> +  (cond ((null (cdr modes)) (ibuffer-filter-by-used-mode (car modes)))
>> +        (t (let ((composed-filter
>
> We should handle the (null modes) case too, but otherwise looks good to
> me.
Yeah, that's right.

* I don't like much such new function
`ibuffer-filter-by-used-modes': isn't it better that
`ibuffer-filter-by-used-mode' handles both inputs?

* Why just 'used modes' and not the other 2
  mode filters benefit from this feature?  
Because I just use that filter, i.e. '/ m'.  A bit selfish.

Please take a look in following patch.
* It allows filtering by >1 mode with the 3 mode filters.
* It moves most of the code inside the macro `define-ibuffer-filter'; no
  need to add new functions.


--8<-----------------------------cut here---------------start------------->8---
commit 2079d7b656cef1e1d2c03f3c7e0c93ec135f348d
Author: Tino Calancha <tino.calancha@gmail.com>
Date:   Tue Sep 18 02:19:54 2018 +0900

    Ibuffer filter by modes: Accept several mode names
    
    Extend all mode filters so that they handle >1 mode.
    For instance, if the user wants to filter all buffers in
    C or C++ mode, then s?he can call the filter interactively
    with input: 'c-mode,c++-mode'.
    
    * lisp/ibuf-ext.el (ibuffer-filter-by-used-mode)
    (ibuffer-filter-by-mode, ibuffer-filter-by-derived-mode)
    Accept a mode name or a list of mode names.
    Interactively, accept a comma separated list of mode names.
    * lisp/ibuf-macs.el(define-ibuffer-filter): Adjust it to
    handle QUALIFIER been a list of symbols.
    * etc/NEWS(Ibuffer): Announce this change.
    
    Co-authored-by: Noam Postavsky <npostavs@gmail.com>

diff --git a/etc/NEWS b/etc/NEWS
index fa93112c91..43d9a38b91 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -62,6 +62,10 @@ to reduce differences between developer and production builds.
 ** Ibuffer
 
 ---
+*** All mode filters accept a symbol or a list of symbols, i.e., you
+can filter several major modes with easy.
+
+---
 *** New toggle 'ibuffer-do-toggle-lock', bound to 'L'.
 
 ** Gnus
diff --git a/lisp/ibuf-ext.el b/lisp/ibuf-ext.el
index d9949d2835..2b0292f2de 100644
--- a/lisp/ibuf-ext.el
+++ b/lisp/ibuf-ext.el
@@ -1228,28 +1228,33 @@ ibuffer-list-buffer-modes
 
 ;;;###autoload (autoload 'ibuffer-filter-by-mode "ibuf-ext")
 (define-ibuffer-filter mode
-  "Limit current view to buffers with major mode QUALIFIER."
+  "Limit current view to buffers with major mode in QUALIFIER.
+QUALIFIER is the mode name as a symbol or a list of symbols.
+Called interactively, accept a comma separated list of mode names."
   (:description "major mode"
    :reader
    (let* ((buf (ibuffer-current-buffer))
           (default (if (and buf (buffer-live-p buf))
                        (symbol-name (buffer-local-value
                                      'major-mode buf)))))
-     (intern
-      (completing-read
+     (mapcar #'intern
+      (completing-read-multiple
        (if default
            (format "Filter by major mode (default %s): " default)
          "Filter by major mode: ")
        obarray
-       #'(lambda (e)
-           (string-match "-mode\\'" (symbol-name e)))
+       (lambda (e)
+           (string-match "-mode\\'" (if (symbolp e) (symbol-name e) e)))
        t nil nil default))))
   (eq qualifier (buffer-local-value 'major-mode buf)))
 
 ;;;###autoload (autoload 'ibuffer-filter-by-used-mode "ibuf-ext")
 (define-ibuffer-filter used-mode
-  "Limit current view to buffers with major mode QUALIFIER.
-Called interactively, this function allows selection of modes
+  "Limit current view to buffers with major mode in QUALIFIER.
+QUALIFIER is the mode name as a symbol or a list of symbols.
+
+Called interactively, accept a comma separated list of mode names.
+When called interactively, this function allows selection of modes
 currently used by buffers."
   (:description "major mode in use"
    :reader
@@ -1257,8 +1262,8 @@ used-mode
           (default (if (and buf (buffer-live-p buf))
                        (symbol-name (buffer-local-value
                                      'major-mode buf)))))
-     (intern
-      (completing-read
+     (mapcar #'intern
+      (completing-read-multiple
        (if default
            (format "Filter by major mode (default %s): " default)
          "Filter by major mode: ")
@@ -1267,11 +1272,13 @@ used-mode
 
 ;;;###autoload (autoload 'ibuffer-filter-by-derived-mode "ibuf-ext")
 (define-ibuffer-filter derived-mode
-    "Limit current view to buffers whose major mode inherits from QUALIFIER."
+    "Limit current view to buffers whose major mode inherits from QUALIFIER.
+QUALIFIER is the mode name as a symbol or a list of symbols.
+Called interactively, accept a comma separated list of mode names."
   (:description "derived mode"
 		:reader
-		(intern
-		 (completing-read "Filter by derived mode: "
+                (mapcar #'intern
+		 (completing-read-multiple "Filter by derived mode: "
 				  (ibuffer-list-buffer-modes t)
                                   nil t)))
   (with-current-buffer buf (derived-mode-p qualifier)))
diff --git a/lisp/ibuf-macs.el b/lisp/ibuf-macs.el
index 6a70a8341a..7893ec9cae 100644
--- a/lisp/ibuf-macs.el
+++ b/lisp/ibuf-macs.el
@@ -296,21 +296,34 @@ ibuffer-save-marks
 
 \(fn NAME DOCUMENTATION (&key READER DESCRIPTION) &rest BODY)"
   (declare (indent 2) (doc-string 2))
-  (let ((fn-name (intern (concat "ibuffer-filter-by-" (symbol-name name)))))
+  (let ((fn-name (intern (concat "ibuffer-filter-by-" (symbol-name name))))
+        (filter (make-symbol "ibuffer-filter"))
+        (qualifier-str (make-symbol "ibuffer-qualifier-str")))
     `(progn
        (defun ,fn-name (qualifier)
 	 ,(or documentation "This filter is not documented.")
 	 (interactive (list ,reader))
-	 (if (null (ibuffer-push-filter (cons ',name qualifier)))
-	     (message "%s"
-		      (format ,(concat (format "Filter by %s already applied: " description)
-				       " %s")
-			      qualifier))
-           (message "%s"
-		    (format ,(concat (format "Filter by %s added: " description)
-				     " %s")
-			    qualifier))
-	   (ibuffer-update nil t)))
+         (let ((,filter (cons ',name qualifier))
+               (,qualifier-str qualifier))
+           ;; The mode filters accept one symbol or a list of symbols; if the
+           ;; user inputs >1 mode, compose the individual filters with `or'.
+           ,(when (memq name (list 'mode 'used-mode 'derived-mode))
+              `(progn
+                 (unless (listp qualifier) (setq qualifier (list qualifier)))
+                 ;; Reject equivalent filters: (or m1 m2) is same as (or m2 m1).
+                 (setq qualifier (sort (delete-dups qualifier) #'string-lessp))
+                 (setq ,filter (cons ',name (car qualifier)))
+                 (setq ,qualifier-str
+                       (mapconcat (lambda (m) (if (symbolp m) (symbol-name m) m))
+                                  qualifier ","))
+                 (when (cdr qualifier)
+                   (setq ,filter `(or ,@(mapcar (lambda (m) (cons ',name m)) qualifier))))))
+	   (if (null (ibuffer-push-filter ,filter))
+	       (message ,(format "Filter by %s already applied:  %%s" description)
+		        ,qualifier-str)
+	     (message ,(format "Filter by %s added:  %%s" description)
+                      ,qualifier-str)
+	     (ibuffer-update nil t))))
        (push (list ',name ,description
 		   (lambda (buf qualifier)
                      (condition-case nil

--8<-----------------------------cut here---------------end--------------->8---





^ permalink raw reply related	[flat|nested] 28+ messages in thread

* bug#32731: 26.1.50; Ibuffer filter by mode: Handle >1 mode names
  2018-09-17 17:44           ` Tino Calancha
@ 2018-09-17 18:27             ` Eli Zaretskii
  2018-09-17 19:53               ` Tino Calancha
  2018-09-18 23:19             ` Noam Postavsky
  1 sibling, 1 reply; 28+ messages in thread
From: Eli Zaretskii @ 2018-09-17 18:27 UTC (permalink / raw)
  To: Tino Calancha; +Cc: npostavs, 32731

> From: Tino Calancha <tino.calancha@gmail.com>
> Date: Tue, 18 Sep 2018 02:44:28 +0900
> Cc: 32731@debbugs.gnu.org
> 
> Noam Postavsky <npostavs@gmail.com> writes:
> 
> >Shouldn't this patch be going into master anyway (since it's adding a
> >new feature)?
> I think is pretty tiny and safe new feature.

"Tiny and safe feature" doesn't necessarily cut it.  It has to be
something important.  Is it?





^ permalink raw reply	[flat|nested] 28+ messages in thread

* bug#32731: 26.1.50; Ibuffer filter by mode: Handle >1 mode names
  2018-09-17 18:27             ` Eli Zaretskii
@ 2018-09-17 19:53               ` Tino Calancha
  2018-09-18  7:14                 ` Eli Zaretskii
  0 siblings, 1 reply; 28+ messages in thread
From: Tino Calancha @ 2018-09-17 19:53 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Tino Calancha, 32731, npostavs



On Mon, 17 Sep 2018, Eli Zaretskii wrote:

>> From: Tino Calancha <tino.calancha@gmail.com>
>> Date: Tue, 18 Sep 2018 02:44:28 +0900
>> Cc: 32731@debbugs.gnu.org
>>
>> Noam Postavsky <npostavs@gmail.com> writes:
>>
>>> Shouldn't this patch be going into master anyway (since it's adding a
>>> new feature)?
>> I think is pretty tiny and safe new feature.
>
> "Tiny and safe feature" doesn't necessarily cut it.  It has to be
> something important.  Is it?
It's not important; just for convenience.
It doesn't bring anything new: you can get the same result just typing
more keys.





^ permalink raw reply	[flat|nested] 28+ messages in thread

* bug#32731: 26.1.50; Ibuffer filter by mode: Handle >1 mode names
  2018-09-17 19:53               ` Tino Calancha
@ 2018-09-18  7:14                 ` Eli Zaretskii
  0 siblings, 0 replies; 28+ messages in thread
From: Eli Zaretskii @ 2018-09-18  7:14 UTC (permalink / raw)
  To: Tino Calancha; +Cc: npostavs, 32731

> From: Tino Calancha <tino.calancha@gmail.com>
> Date: Tue, 18 Sep 2018 04:53:56 +0900 (JST)
> cc: Tino Calancha <tino.calancha@gmail.com>, npostavs@gmail.com, 
>     32731@debbugs.gnu.org
> 
> >> Noam Postavsky <npostavs@gmail.com> writes:
> >>
> >>> Shouldn't this patch be going into master anyway (since it's adding a
> >>> new feature)?
> >> I think is pretty tiny and safe new feature.
> >
> > "Tiny and safe feature" doesn't necessarily cut it.  It has to be
> > something important.  Is it?
> It's not important; just for convenience.
> It doesn't bring anything new: you can get the same result just typing
> more keys.

Then I think we had better put it on master.

Thanks.





^ permalink raw reply	[flat|nested] 28+ messages in thread

* bug#32731: 26.1.50; Ibuffer filter by mode: Handle >1 mode names
  2018-09-17 17:44           ` Tino Calancha
  2018-09-17 18:27             ` Eli Zaretskii
@ 2018-09-18 23:19             ` Noam Postavsky
  2018-09-19  9:23               ` Tino Calancha
  1 sibling, 1 reply; 28+ messages in thread
From: Noam Postavsky @ 2018-09-18 23:19 UTC (permalink / raw)
  To: Tino Calancha; +Cc: 32731

Tino Calancha <tino.calancha@gmail.com> writes:

> * I don't like much such new function
> `ibuffer-filter-by-used-modes': isn't it better that
> `ibuffer-filter-by-used-mode' handles both inputs?

In principle, I agree with this, but there is a drawback to be aware of:
fancier completion modes (e.g., icomplete, ido, etc) don't support
completing-read-multiple.  So users of those modes could see this as a
regression.

> * It moves most of the code inside the macro `define-ibuffer-filter'; no
>   need to add new functions.

I don't like that define-ibuffer-filter has special code for certain
filter types.





^ permalink raw reply	[flat|nested] 28+ messages in thread

* bug#32731: 26.1.50; Ibuffer filter by mode: Handle >1 mode names
  2018-09-18 23:19             ` Noam Postavsky
@ 2018-09-19  9:23               ` Tino Calancha
  2018-09-19  9:42                 ` Eli Zaretskii
  0 siblings, 1 reply; 28+ messages in thread
From: Tino Calancha @ 2018-09-19  9:23 UTC (permalink / raw)
  To: Noam Postavsky; +Cc: 32731

Noam Postavsky <npostavs@gmail.com> writes:

> Tino Calancha <tino.calancha@gmail.com> writes:
>
>> * I don't like much such new function
>> `ibuffer-filter-by-used-modes': isn't it better that
>> `ibuffer-filter-by-used-mode' handles both inputs?
>
> In principle, I agree with this, but there is a drawback to be aware of:
> fancier completion modes (e.g., icomplete, ido, etc) don't support
> completing-read-multiple.  So users of those modes could see this as a
> regression.
OK.  Annotaded here for the records.

>> * It moves most of the code inside the macro `define-ibuffer-filter'; no
>>   need to add new functions.
>
> I don't like that define-ibuffer-filter has special code for certain
> filter types.
Me either, but I don't like code duplication either:  Macros are a
convenient way to avoid that.  Unless you have something sound in mind...

Following patch adds a key :composable, which also serves as
documentation.
--8<-----------------------------cut here---------------start------------->8---
commit 5c6092b172209cb0261f36f423f508bddc4d0dcd
Author: Tino Calancha <tino.calancha@gmail.com>
Date:   Wed Sep 19 18:08:35 2018 +0900

    Ibuffer filter by modes: Accept several mode names
    
    Extend all mode filters so that they handle >1 mode.
    For instance, if the user wants to filter all buffers in
    C or C++ mode, then s?he can call the filter interactively
    with input: 'c-mode,c++-mode'.
    
    * lisp/ibuf-macs.el(define-ibuffer-filter): Add key :composable.
    If the value of this key is non-nil, then the filter accepts
    a single qualifier or a list of them; in the latter case, the
    resultant filter is the `or' composition of the individual ones.
    
    * lisp/ibuf-ext.el (ibuffer-filter-by-used-mode)
    (ibuffer-filter-by-mode, ibuffer-filter-by-derived-mode)
    Accept a mode name or a list of mode names.
    Interactively, accept a comma separated list of mode names.
    Set :composable value non-nil.
    
    * etc/NEWS(Ibuffer): Announce this change.
    
    Co-authored-by: Noam Postavsky <npostavs@gmail.com>

diff --git a/etc/NEWS b/etc/NEWS
index fa93112c91..43d9a38b91 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -62,6 +62,10 @@ to reduce differences between developer and production builds.
 ** Ibuffer
 
 ---
+*** All mode filters accept a symbol or a list of symbols, i.e., you
+can filter several major modes with easy.
+
+---
 *** New toggle 'ibuffer-do-toggle-lock', bound to 'L'.
 
 ** Gnus
diff --git a/lisp/ibuf-ext.el b/lisp/ibuf-ext.el
index d9949d2835..fc2e21a77f 100644
--- a/lisp/ibuf-ext.el
+++ b/lisp/ibuf-ext.el
@@ -1228,28 +1228,34 @@ ibuffer-list-buffer-modes
 
 ;;;###autoload (autoload 'ibuffer-filter-by-mode "ibuf-ext")
 (define-ibuffer-filter mode
-  "Limit current view to buffers with major mode QUALIFIER."
+  "Limit current view to buffers with major mode in QUALIFIER.
+QUALIFIER is the mode name as a symbol or a list of symbols.
+Called interactively, accept a comma separated list of mode names."
   (:description "major mode"
    :reader
    (let* ((buf (ibuffer-current-buffer))
           (default (if (and buf (buffer-live-p buf))
                        (symbol-name (buffer-local-value
                                      'major-mode buf)))))
-     (intern
-      (completing-read
+     (mapcar #'intern
+      (completing-read-multiple
        (if default
            (format "Filter by major mode (default %s): " default)
          "Filter by major mode: ")
        obarray
-       #'(lambda (e)
-           (string-match "-mode\\'" (symbol-name e)))
-       t nil nil default))))
+       (lambda (e)
+           (string-match "-mode\\'" (if (symbolp e) (symbol-name e) e)))
+       t nil nil default)))
+   :composable t)
   (eq qualifier (buffer-local-value 'major-mode buf)))
 
 ;;;###autoload (autoload 'ibuffer-filter-by-used-mode "ibuf-ext")
 (define-ibuffer-filter used-mode
-  "Limit current view to buffers with major mode QUALIFIER.
-Called interactively, this function allows selection of modes
+  "Limit current view to buffers with major mode in QUALIFIER.
+QUALIFIER is the mode name as a symbol or a list of symbols.
+
+Called interactively, accept a comma separated list of mode names.
+When called interactively, this function allows selection of modes
 currently used by buffers."
   (:description "major mode in use"
    :reader
@@ -1257,23 +1263,27 @@ used-mode
           (default (if (and buf (buffer-live-p buf))
                        (symbol-name (buffer-local-value
                                      'major-mode buf)))))
-     (intern
-      (completing-read
+     (mapcar #'intern
+      (completing-read-multiple
        (if default
            (format "Filter by major mode (default %s): " default)
          "Filter by major mode: ")
-       (ibuffer-list-buffer-modes) nil t nil nil default))))
+       (ibuffer-list-buffer-modes) nil t nil nil default)))
+   :composable t)
   (eq qualifier (buffer-local-value 'major-mode buf)))
 
 ;;;###autoload (autoload 'ibuffer-filter-by-derived-mode "ibuf-ext")
 (define-ibuffer-filter derived-mode
-    "Limit current view to buffers whose major mode inherits from QUALIFIER."
+    "Limit current view to buffers whose major mode inherits from QUALIFIER.
+QUALIFIER is the mode name as a symbol or a list of symbols.
+Called interactively, accept a comma separated list of mode names."
   (:description "derived mode"
 		:reader
-		(intern
-		 (completing-read "Filter by derived mode: "
+                (mapcar #'intern
+		 (completing-read-multiple "Filter by derived mode: "
 				  (ibuffer-list-buffer-modes t)
-                                  nil t)))
+                                  nil t))
+                :composable t)
   (with-current-buffer buf (derived-mode-p qualifier)))
 
 ;;;###autoload (autoload 'ibuffer-filter-by-name "ibuf-ext")
diff --git a/lisp/ibuf-macs.el b/lisp/ibuf-macs.el
index 6a70a8341a..1030096ec1 100644
--- a/lisp/ibuf-macs.el
+++ b/lisp/ibuf-macs.el
@@ -282,12 +282,16 @@ ibuffer-save-marks
 (cl-defmacro define-ibuffer-filter (name documentation
 				       (&key
 					reader
-					description)
+					description
+                                        composable)
 				       &rest body)
   "Define a filter named NAME.
 DOCUMENTATION is the documentation of the function.
 READER is a form which should read a qualifier from the user.
 DESCRIPTION is a short string describing the filter.
+COMPOSABLE is a boolean; if non-nil, the filter accepts both,
+a single condition or a list of them; in the latter
+case the filter is the `or' composition of the conditions.
 
 BODY should contain forms which will be evaluated to test whether or
 not a particular buffer should be displayed or not.  The forms in BODY
@@ -296,21 +300,32 @@ ibuffer-save-marks
 
 \(fn NAME DOCUMENTATION (&key READER DESCRIPTION) &rest BODY)"
   (declare (indent 2) (doc-string 2))
-  (let ((fn-name (intern (concat "ibuffer-filter-by-" (symbol-name name)))))
+  (let ((fn-name (intern (concat "ibuffer-filter-by-" (symbol-name name))))
+        (filter (make-symbol "ibuffer-filter"))
+        (qualifier-str (make-symbol "ibuffer-qualifier-str")))
     `(progn
        (defun ,fn-name (qualifier)
 	 ,(or documentation "This filter is not documented.")
 	 (interactive (list ,reader))
-	 (if (null (ibuffer-push-filter (cons ',name qualifier)))
-	     (message "%s"
-		      (format ,(concat (format "Filter by %s already applied: " description)
-				       " %s")
-			      qualifier))
-           (message "%s"
-		    (format ,(concat (format "Filter by %s added: " description)
-				     " %s")
-			    qualifier))
-	   (ibuffer-update nil t)))
+         (let ((,filter (cons ',name qualifier))
+               (,qualifier-str qualifier))
+           ,(when composable
+              `(progn
+                 (unless (listp qualifier) (setq qualifier (list qualifier)))
+                 ;; Reject equivalent filters: (or f1 f2) is same as (or f2 f1).
+                 (setq qualifier (sort (delete-dups qualifier) #'string-lessp))
+                 (setq ,filter (cons ',name (car qualifier)))
+                 (setq ,qualifier-str
+                       (mapconcat (lambda (m) (if (symbolp m) (symbol-name m) m))
+                                  qualifier ","))
+                 (when (cdr qualifier) ; Compose individual filters with `or'.
+                   (setq ,filter `(or ,@(mapcar (lambda (m) (cons ',name m)) qualifier))))))
+	   (if (null (ibuffer-push-filter ,filter))
+	       (message ,(format "Filter by %s already applied:  %%s" description)
+		        ,qualifier-str)
+	     (message ,(format "Filter by %s added:  %%s" description)
+                      ,qualifier-str)
+	     (ibuffer-update nil t))))
        (push (list ',name ,description
 		   (lambda (buf qualifier)
                      (condition-case nil

--8<-----------------------------cut here---------------end--------------->8---





^ permalink raw reply related	[flat|nested] 28+ messages in thread

* bug#32731: 26.1.50; Ibuffer filter by mode: Handle >1 mode names
  2018-09-19  9:23               ` Tino Calancha
@ 2018-09-19  9:42                 ` Eli Zaretskii
  2018-09-21  8:37                   ` Tino Calancha
  0 siblings, 1 reply; 28+ messages in thread
From: Eli Zaretskii @ 2018-09-19  9:42 UTC (permalink / raw)
  To: Tino Calancha; +Cc: npostavs, 32731

> From: Tino Calancha <tino.calancha@gmail.com>
> Date: Wed, 19 Sep 2018 18:23:52 +0900
> Cc: 32731@debbugs.gnu.org
> 
> Following patch adds a key :composable, which also serves as
> documentation.

Thanks, a few nits to the documentation parts:

>  ---
> +*** All mode filters accept a symbol or a list of symbols, i.e., you
> +can filter several major modes with easy.

Please try to keep the first line in a NEWS item a single complete
sentence, as much as possible: that allows for more convenient
browsing in Outline mode.  In this case, I would break this into two
sentences: a short announcement and followup details:

   *** All mode filters can now accept a list of symbols.
   This means you can now easily filter several major modes, as well
   as a single mode.

>  ;;;###autoload (autoload 'ibuffer-filter-by-mode "ibuf-ext")
>  (define-ibuffer-filter mode
> -  "Limit current view to buffers with major mode QUALIFIER."
> +  "Limit current view to buffers with major mode in QUALIFIER.
> +QUALIFIER is the mode name as a symbol or a list of symbols.

In the first sentence, I'd suggest to rephrase:

  Limit current view to buffers with major mode(s) specified by QUALIFIER.

because "in QUALIFIER" only covers the case of a list.

Similarly in other doc strings you modified the same way.

> +Called interactively, accept a comma separated list of mode names.
> +When called interactively, this function allows selection of modes
>  currently used by buffers."

These two sentences seem to be in contradiction, so they probably need
to be merged or rephrased.

>  (cl-defmacro define-ibuffer-filter (name documentation
>  				       (&key
>  					reader
> -					description)
> +					description
> +                                        composable)
>  				       &rest body)
>    "Define a filter named NAME.
>  DOCUMENTATION is the documentation of the function.
>  READER is a form which should read a qualifier from the user.
>  DESCRIPTION is a short string describing the filter.
> +COMPOSABLE is a boolean; if non-nil, the filter accepts both,
                                                               ^
That comma should be deleted, it gets in the way of understanding what
you mean.  And I would actually rephrase

  if non-nil, the filter accepts either a single condition or a list
  of them

because "both" might be interpreted as meaning "and", not "or".

I also wonder whether "COMPOSABLE" is a good name for this argument;
how about ACCEPT-LIST instead?

Thanks for working on this.





^ permalink raw reply	[flat|nested] 28+ messages in thread

* bug#32731: 26.1.50; Ibuffer filter by mode: Handle >1 mode names
  2018-09-19  9:42                 ` Eli Zaretskii
@ 2018-09-21  8:37                   ` Tino Calancha
  2018-09-22  9:14                     ` Eli Zaretskii
  2018-09-22 13:00                     ` Noam Postavsky
  0 siblings, 2 replies; 28+ messages in thread
From: Tino Calancha @ 2018-09-21  8:37 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: npostavs, 32731

Eli Zaretskii <eliz@gnu.org> writes:

>> From: Tino Calancha <tino.calancha@gmail.com>
>> Date: Wed, 19 Sep 2018 18:23:52 +0900
>> Cc: 32731@debbugs.gnu.org
>> 
>> Following patch adds a key :composable, which also serves as
>> documentation.
>
> Thanks, a few nits to the documentation parts:
Thank you.
I've amended the patch to address all the nits:
--8<-----------------------------cut here---------------start------------->8---
commit 72e332c986304775e91020c88ded1ba9d7226023
Author: Tino Calancha <tino.calancha@gmail.com>
Date:   Fri Sep 21 17:32:57 2018 +0900

    Ibuffer filter by modes: Accept several mode names
    
    Extend all mode filters so that they handle >1 mode.
    For instance, if the user wants to filter all buffers in
    C or C++ mode, then s?he can call the filter interactively
    with input: 'c-mode,c++-mode' (Bug#32731).
    
    * lisp/ibuf-macs.el(define-ibuffer-filter): Add key :accept-list.
    If the value of this key is non-nil, then the filter accepts
    either a single qualifier or a list of them; in the latter case,
    the resultant filter is the `or' composition of the individual ones.
    
    * lisp/ibuf-ext.el (ibuffer-filter-by-used-mode)
    (ibuffer-filter-by-mode, ibuffer-filter-by-derived-mode)
    Set :accept-list value non-nil.
    Interactively, accept a comma separated list of mode names.
    
    * etc/NEWS(Ibuffer): Announce this change.
    
    Co-authored-by: Noam Postavsky <npostavs@gmail.com>

diff --git a/etc/NEWS b/etc/NEWS
index 736955be0c..9f7e0544d5 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -62,6 +62,11 @@ to reduce differences between developer and production builds.
 ** Ibuffer
 
 ---
+*** All mode filters can now accept a list of symbols.
+This means you can now easily filter several major modes, as well
+as a single mode.
+
+---
 *** New toggle 'ibuffer-do-toggle-lock', bound to 'L'.
 
 ** Gnus
diff --git a/lisp/ibuf-ext.el b/lisp/ibuf-ext.el
index d9949d2835..e3e0d0b578 100644
--- a/lisp/ibuf-ext.el
+++ b/lisp/ibuf-ext.el
@@ -1228,28 +1228,33 @@ ibuffer-list-buffer-modes
 
 ;;;###autoload (autoload 'ibuffer-filter-by-mode "ibuf-ext")
 (define-ibuffer-filter mode
-  "Limit current view to buffers with major mode QUALIFIER."
+    "Limit current view to buffers with major mode(s) specified by QUALIFIER.
+QUALIFIER is the mode name as a symbol or a list of symbols.
+Called interactively, accept a comma separated list of mode names."
   (:description "major mode"
    :reader
    (let* ((buf (ibuffer-current-buffer))
           (default (if (and buf (buffer-live-p buf))
                        (symbol-name (buffer-local-value
                                      'major-mode buf)))))
-     (intern
-      (completing-read
+     (mapcar #'intern
+      (completing-read-multiple
        (if default
            (format "Filter by major mode (default %s): " default)
          "Filter by major mode: ")
        obarray
-       #'(lambda (e)
-           (string-match "-mode\\'" (symbol-name e)))
-       t nil nil default))))
+       (lambda (e)
+           (string-match "-mode\\'" (if (symbolp e) (symbol-name e) e)))
+       t nil nil default)))
+   :accept-list t)
   (eq qualifier (buffer-local-value 'major-mode buf)))
 
 ;;;###autoload (autoload 'ibuffer-filter-by-used-mode "ibuf-ext")
 (define-ibuffer-filter used-mode
-  "Limit current view to buffers with major mode QUALIFIER.
-Called interactively, this function allows selection of modes
+    "Limit current view to buffers with major mode(s) specified by QUALIFIER.
+QUALIFIER is the mode name as a symbol or a list of symbols.
+
+Called interactively, accept a comma separated list of mode names
 currently used by buffers."
   (:description "major mode in use"
    :reader
@@ -1257,23 +1262,29 @@ used-mode
           (default (if (and buf (buffer-live-p buf))
                        (symbol-name (buffer-local-value
                                      'major-mode buf)))))
-     (intern
-      (completing-read
+     (mapcar #'intern
+      (completing-read-multiple
        (if default
            (format "Filter by major mode (default %s): " default)
          "Filter by major mode: ")
-       (ibuffer-list-buffer-modes) nil t nil nil default))))
+       (ibuffer-list-buffer-modes) nil t nil nil default)))
+   :accept-list t)
   (eq qualifier (buffer-local-value 'major-mode buf)))
 
 ;;;###autoload (autoload 'ibuffer-filter-by-derived-mode "ibuf-ext")
 (define-ibuffer-filter derived-mode
-    "Limit current view to buffers whose major mode inherits from QUALIFIER."
+    "Limit current view to buffers with major mode(s) specified by QUALIFIER.
+QUALIFIER is the mode name as a symbol or a list of symbols.
+ Restrict the view to buffers whose major mode derivates
+ from modes specified by QUALIFIER.
+Called interactively, accept a comma separated list of mode names."
   (:description "derived mode"
 		:reader
-		(intern
-		 (completing-read "Filter by derived mode: "
-				  (ibuffer-list-buffer-modes t)
-                                  nil t)))
+		(mapcar #'intern
+		 (completing-read-multiple "Filter by derived mode: "
+					   (ibuffer-list-buffer-modes t)
+					   nil t))
+		:accept-list t)
   (with-current-buffer buf (derived-mode-p qualifier)))
 
 ;;;###autoload (autoload 'ibuffer-filter-by-name "ibuf-ext")
diff --git a/lisp/ibuf-macs.el b/lisp/ibuf-macs.el
index 6a70a8341a..066d9ac2d9 100644
--- a/lisp/ibuf-macs.el
+++ b/lisp/ibuf-macs.el
@@ -282,12 +282,16 @@ ibuffer-save-marks
 (cl-defmacro define-ibuffer-filter (name documentation
 				       (&key
 					reader
-					description)
+					description
+					accept-list)
 				       &rest body)
   "Define a filter named NAME.
 DOCUMENTATION is the documentation of the function.
 READER is a form which should read a qualifier from the user.
 DESCRIPTION is a short string describing the filter.
+ACCEPT-LIST is a boolean; if non-nil, the filter accepts either
+a single condition or a list of them; in the latter
+case the filter is the `or' composition of the conditions.
 
 BODY should contain forms which will be evaluated to test whether or
 not a particular buffer should be displayed or not.  The forms in BODY
@@ -296,29 +300,40 @@ ibuffer-save-marks
 
 \(fn NAME DOCUMENTATION (&key READER DESCRIPTION) &rest BODY)"
   (declare (indent 2) (doc-string 2))
-  (let ((fn-name (intern (concat "ibuffer-filter-by-" (symbol-name name)))))
+  (let ((fn-name (intern (concat "ibuffer-filter-by-" (symbol-name name))))
+        (filter (make-symbol "ibuffer-filter"))
+        (qualifier-str (make-symbol "ibuffer-qualifier-str")))
     `(progn
        (defun ,fn-name (qualifier)
 	 ,(or documentation "This filter is not documented.")
 	 (interactive (list ,reader))
-	 (if (null (ibuffer-push-filter (cons ',name qualifier)))
-	     (message "%s"
-		      (format ,(concat (format "Filter by %s already applied: " description)
-				       " %s")
-			      qualifier))
-           (message "%s"
-		    (format ,(concat (format "Filter by %s added: " description)
-				     " %s")
-			    qualifier))
-	   (ibuffer-update nil t)))
+	 (let ((,filter (cons ',name qualifier))
+	       (,qualifier-str qualifier))
+	   ,(when accept-list
+	      `(progn
+		 (unless (listp qualifier) (setq qualifier (list qualifier)))
+		 ;; Reject equivalent filters: (or f1 f2) is same as (or f2 f1).
+		 (setq qualifier (sort (delete-dups qualifier) #'string-lessp))
+		 (setq ,filter (cons ',name (car qualifier)))
+		 (setq ,qualifier-str
+		       (mapconcat (lambda (m) (if (symbolp m) (symbol-name m) m))
+				  qualifier ","))
+		 (when (cdr qualifier) ; Compose individual filters with `or'.
+		   (setq ,filter `(or ,@(mapcar (lambda (m) (cons ',name m)) qualifier))))))
+	   (if (null (ibuffer-push-filter ,filter))
+	       (message ,(format "Filter by %s already applied:  %%s" description)
+		        ,qualifier-str)
+	     (message ,(format "Filter by %s added:  %%s" description)
+		      ,qualifier-str)
+	     (ibuffer-update nil t))))
        (push (list ',name ,description
 		   (lambda (buf qualifier)
-                     (condition-case nil
-                         (progn ,@body)
-                       (error (ibuffer-pop-filter)
-                              (when (eq ',name 'predicate)
-                                (error "Wrong filter predicate: %S"
-                                       qualifier))))))
+		     (condition-case nil
+			 (progn ,@body)
+		       (error (ibuffer-pop-filter)
+			      (when (eq ',name 'predicate)
+				(error "Wrong filter predicate: %S"
+				       qualifier))))))
 	     ibuffer-filtering-alist)
        :autoload-end)))
 
--8<-----------------------------cut here---------------end--------------->8---
In GNU Emacs 27.0.50 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.22.11)
Repository revision: 7f3877e83405a089b580fe9d0342dc0b6c08cbfc





^ permalink raw reply related	[flat|nested] 28+ messages in thread

* bug#32731: 26.1.50; Ibuffer filter by mode: Handle >1 mode names
  2018-09-21  8:37                   ` Tino Calancha
@ 2018-09-22  9:14                     ` Eli Zaretskii
  2018-09-22 13:00                     ` Noam Postavsky
  1 sibling, 0 replies; 28+ messages in thread
From: Eli Zaretskii @ 2018-09-22  9:14 UTC (permalink / raw)
  To: Tino Calancha; +Cc: npostavs, 32731

> From: Tino Calancha <tino.calancha@gmail.com>
> Cc: npostavs@gmail.com,  32731@debbugs.gnu.org
> Date: Fri, 21 Sep 2018 17:37:39 +0900
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> >> From: Tino Calancha <tino.calancha@gmail.com>
> >> Date: Wed, 19 Sep 2018 18:23:52 +0900
> >> Cc: 32731@debbugs.gnu.org
> >> 
> >> Following patch adds a key :composable, which also serves as
> >> documentation.
> >
> > Thanks, a few nits to the documentation parts:
> Thank you.
> I've amended the patch to address all the nits:

Thanks, this LGTM.





^ permalink raw reply	[flat|nested] 28+ messages in thread

* bug#32731: 26.1.50; Ibuffer filter by mode: Handle >1 mode names
  2018-09-21  8:37                   ` Tino Calancha
  2018-09-22  9:14                     ` Eli Zaretskii
@ 2018-09-22 13:00                     ` Noam Postavsky
  2018-09-23  1:37                       ` Richard Stallman
  2018-09-24  8:36                       ` Tino Calancha
  1 sibling, 2 replies; 28+ messages in thread
From: Noam Postavsky @ 2018-09-22 13:00 UTC (permalink / raw)
  To: Tino Calancha; +Cc: 32731

Tino Calancha <tino.calancha@gmail.com> writes:

> commit 72e332c986304775e91020c88ded1ba9d7226023
> Author: Tino Calancha <tino.calancha@gmail.com>
> Date:   Fri Sep 21 17:32:57 2018 +0900
>
>     Ibuffer filter by modes: Accept several mode names
>     
>     Extend all mode filters so that they handle >1 mode.
>     For instance, if the user wants to filter all buffers in
>     C or C++ mode, then s?he can call the filter interactively

If you'll pardon another nit, I suggest using "they" instead of "s?he"
which has the advantage of being a pronounceable English word.

> +	 (let ((,filter (cons ',name qualifier))
> +	       (,qualifier-str qualifier))
> +	   ,(when accept-list
> +	      `(progn
> +		 (unless (listp qualifier) (setq qualifier (list qualifier)))
> +		 ;; Reject equivalent filters: (or f1 f2) is same as (or f2 f1).
> +		 (setq qualifier (sort (delete-dups qualifier) #'string-lessp))
> +		 (setq ,filter (cons ',name (car qualifier)))
> +		 (setq ,qualifier-str
> +		       (mapconcat (lambda (m) (if (symbolp m) (symbol-name m) m))
> +				  qualifier ","))
> +		 (when (cdr qualifier) ; Compose individual filters with `or'.
> +		   (setq ,filter `(or ,@(mapcar (lambda (m) (cons ',name m)) qualifier))))))
> +	   (if (null (ibuffer-push-filter ,filter))
> +	       (message ,(format "Filter by %s already applied:  %%s" description)
> +		        ,qualifier-str)
> +	     (message ,(format "Filter by %s added:  %%s" description)
> +		      ,qualifier-str)
> +	     (ibuffer-update nil t))))

Since I'm here nitting anyway, I would tweak this code a bit:

    (let ((,filter (cons ',name qualifier))
          (,qualifier-desc qualifier))
      ,(when accept-list
         `(when (listp qualifier)
            (setq ,qualifier-desc
                  (mapconcat (lambda (m) (if (symbolp m) (symbol-name m) m))
                             qualifier ","))
            (if (null (cdr qualifier))
                (setf (cdr ,filter) (car qualifier)) ; Singleton list.
              ;; Reject equivalent filters: (or f1 f2) is same as (or f2 f1).
              (setq qualifier (delete-consecutive-dups
                               (sort qualifier #'string-lessp)))
              ;; Compose individual filters with `or'.
              (setq ,filter `(or ,@(mapcar (lambda (m) (cons ',name m))
                                           qualifier))))))
      (if (null (ibuffer-push-filter ,filter))
          (message ,(format "Filter by %s already applied:  %%s" description)
                   ,qualifier-desc)
        (message ,(format "Filter by %s added:  %%s" description)
                 ,qualifier-desc)
        (ibuffer-update nil t)))

>         (push (list ',name ,description
>  		   (lambda (buf qualifier)
> -                     (condition-case nil
> -                         (progn ,@body)
> -                       (error (ibuffer-pop-filter)
> -                              (when (eq ',name 'predicate)
> -                                (error "Wrong filter predicate: %S"
> -                                       qualifier))))))
> +		     (condition-case nil
> +			 (progn ,@body)
> +		       (error (ibuffer-pop-filter)
> +			      (when (eq ',name 'predicate)
> +				(error "Wrong filter predicate: %S"
> +				       qualifier))))))
>  	     ibuffer-filtering-alist)
>         :autoload-end)))

I think this hunk is just changing spaces to tabs (shouldn't .dir-locals
be setting indent-tabs-mode to nil though?).






^ permalink raw reply	[flat|nested] 28+ messages in thread

* bug#32731: 26.1.50; Ibuffer filter by mode: Handle >1 mode names
  2018-09-22 13:00                     ` Noam Postavsky
@ 2018-09-23  1:37                       ` Richard Stallman
  2018-09-23 12:01                         ` Noam Postavsky
  2018-09-24  8:27                         ` Tino Calancha
  2018-09-24  8:36                       ` Tino Calancha
  1 sibling, 2 replies; 28+ messages in thread
From: Richard Stallman @ 2018-09-23  1:37 UTC (permalink / raw)
  To: Noam Postavsky; +Cc: 32731, tino.calancha

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > If you'll pardon another nit, I suggest using "they" instead of "s?he"
  > which has the advantage of being a pronounceable English word.

Using "they" for a singular antecedent is confusing, and I always find
it jarring.  I won't make a rule against, but I make a point of never
using that construction.  "S?he" avoids the confusion because it is
clearly singular.

I use a different set of gender-neutral singular pronouns, which I
think fit better into English.  See
https://stallman.org/articles/genderless-pronouns.html.

-- 
Dr Richard Stallman
President, Free Software Foundation (https://gnu.org, https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)







^ permalink raw reply	[flat|nested] 28+ messages in thread

* bug#32731: 26.1.50; Ibuffer filter by mode: Handle >1 mode names
  2018-09-23  1:37                       ` Richard Stallman
@ 2018-09-23 12:01                         ` Noam Postavsky
  2018-09-24  8:27                         ` Tino Calancha
  1 sibling, 0 replies; 28+ messages in thread
From: Noam Postavsky @ 2018-09-23 12:01 UTC (permalink / raw)
  To: Richard Stallman; +Cc: 32731, tino.calancha

Richard Stallman <rms@gnu.org> writes:

> [[[ To any NSA and FBI agents reading my email: please consider    ]]]
> [[[ whether defending the US Constitution against all enemies,     ]]]
> [[[ foreign or domestic, requires you to follow Snowden's example. ]]]
>
>   > If you'll pardon another nit, I suggest using "they" instead of "s?he"
>   > which has the advantage of being a pronounceable English word.
>
> Using "they" for a singular antecedent is confusing, and I always find
> it jarring.  I won't make a rule against, but I make a point of never
> using that construction.  "S?he" avoids the confusion because it is
> clearly singular.
>
> I use a different set of gender-neutral singular pronouns, which I
> think fit better into English.  See
> https://stallman.org/articles/genderless-pronouns.html.

I find "s?he" jarring due to its non-wordness and "per" confusing
because it's already a word which means something else (I end up having
to read the sentence from the beginning again to parse it right).  I
expect it's mostly a matter of practice though.






^ permalink raw reply	[flat|nested] 28+ messages in thread

* bug#32731: 26.1.50; Ibuffer filter by mode: Handle >1 mode names
  2018-09-23  1:37                       ` Richard Stallman
  2018-09-23 12:01                         ` Noam Postavsky
@ 2018-09-24  8:27                         ` Tino Calancha
  2018-09-24 19:58                           ` Richard Stallman
  1 sibling, 1 reply; 28+ messages in thread
From: Tino Calancha @ 2018-09-24  8:27 UTC (permalink / raw)
  To: Richard Stallman; +Cc: Tino Calancha, 32731, Noam Postavsky



On Sat, 22 Sep 2018, Richard Stallman wrote:

> [[[ To any NSA and FBI agents reading my email: please consider    ]]]
> [[[ whether defending the US Constitution against all enemies,     ]]]
> [[[ foreign or domestic, requires you to follow Snowden's example. ]]]
>
>  > If you'll pardon another nit, I suggest using "they" instead of "s?he"
>  > which has the advantage of being a pronounceable English word.
>
> Using "they" for a singular antecedent is confusing, and I always find
> it jarring.  I won't make a rule against, but I make a point of never
> using that construction.  "S?he" avoids the confusion because it is
> clearly singular.
>
> I use a different set of gender-neutral singular pronouns, which I
> think fit better into English.  See
> https://stallman.org/articles/genderless-pronouns.html.
How about 'it'?  This way we include robots: we shouldn't
discriminate them ;-)

I saw in your site 'he/she'.  I rewrote as 'she/he',
otherwise, someone picky might complain about 
males been prioritized.





^ permalink raw reply	[flat|nested] 28+ messages in thread

* bug#32731: 26.1.50; Ibuffer filter by mode: Handle >1 mode names
  2018-09-22 13:00                     ` Noam Postavsky
  2018-09-23  1:37                       ` Richard Stallman
@ 2018-09-24  8:36                       ` Tino Calancha
  1 sibling, 0 replies; 28+ messages in thread
From: Tino Calancha @ 2018-09-24  8:36 UTC (permalink / raw)
  To: Noam Postavsky; +Cc: 32731

Noam Postavsky <npostavs@gmail.com> writes:

> Tino Calancha <tino.calancha@gmail.com> writes:
>
>> commit 72e332c986304775e91020c88ded1ba9d7226023
>> Author: Tino Calancha <tino.calancha@gmail.com>
>> Date:   Fri Sep 21 17:32:57 2018 +0900
>>
>>     Ibuffer filter by modes: Accept several mode names
>>     
>>     Extend all mode filters so that they handle >1 mode.
>>     For instance, if the user wants to filter all buffers in
>>     C or C++ mode, then s?he can call the filter interactively
>
> If you'll pardon another nit, I suggest using "they" instead of "s?he"
> which has the advantage of being a pronounceable English word.
I changed to she/he.


> I think this hunk is just changing spaces to tabs (shouldn't .dir-locals
> be setting indent-tabs-mode to nil though?).
I droped my hand-added tabs (also those I added in ibuf-ext.el).
Actually I don't like tabs in source code (just added as a sign of
respect to the library author).
--8<-----------------------------cut here---------------start------------->8---
commit d385f8077ffed38046231bb29448598484352543
Author: Tino Calancha <tino.calancha@gmail.com>
Date:   Mon Sep 24 17:29:48 2018 +0900

    Ibuffer filter by modes: Accept several mode names
    
    Extend all mode filters so that they handle >1 mode.
    For instance, if the user wants to filter all buffers in
    C or C++ mode, then she/he can call the filter interactively
    with input: 'c-mode,c++-mode' (Bug#32731).
    
    * lisp/ibuf-macs.el(define-ibuffer-filter): Add key :accept-list.
    If the value of this key is non-nil, then the filter accepts
    either a single qualifier or a list of them; in the latter case,
    the resultant filter is the `or' composition of the individual ones.
    
    * lisp/ibuf-ext.el (ibuffer-filter-by-used-mode)
    (ibuffer-filter-by-mode, ibuffer-filter-by-derived-mode)
    Set :accept-list value non-nil.
    Interactively, accept a comma separated list of mode names.
    
    * etc/NEWS(Ibuffer): Announce this change.
    
    Co-authored-by: Noam Postavsky <npostavs@gmail.com>

diff --git a/etc/NEWS b/etc/NEWS
index bc6791b05b..8126354ab8 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -62,6 +62,11 @@ to reduce differences between developer and production builds.
 ** Ibuffer
 
 ---
+*** All mode filters can now accept a list of symbols.
+This means you can now easily filter several major modes, as well
+as a single mode.
+
+---
 *** New toggle 'ibuffer-do-toggle-lock', bound to 'L'.
 
 ** Gnus
diff --git a/lisp/ibuf-ext.el b/lisp/ibuf-ext.el
index d9949d2835..32ec91db97 100644
--- a/lisp/ibuf-ext.el
+++ b/lisp/ibuf-ext.el
@@ -1228,28 +1228,33 @@ ibuffer-list-buffer-modes
 
 ;;;###autoload (autoload 'ibuffer-filter-by-mode "ibuf-ext")
 (define-ibuffer-filter mode
-  "Limit current view to buffers with major mode QUALIFIER."
+    "Limit current view to buffers with major mode(s) specified by QUALIFIER.
+QUALIFIER is the mode name as a symbol or a list of symbols.
+Called interactively, accept a comma separated list of mode names."
   (:description "major mode"
    :reader
    (let* ((buf (ibuffer-current-buffer))
           (default (if (and buf (buffer-live-p buf))
                        (symbol-name (buffer-local-value
                                      'major-mode buf)))))
-     (intern
-      (completing-read
+     (mapcar #'intern
+      (completing-read-multiple
        (if default
            (format "Filter by major mode (default %s): " default)
          "Filter by major mode: ")
        obarray
-       #'(lambda (e)
-           (string-match "-mode\\'" (symbol-name e)))
-       t nil nil default))))
+       (lambda (e)
+           (string-match "-mode\\'" (if (symbolp e) (symbol-name e) e)))
+       t nil nil default)))
+   :accept-list t)
   (eq qualifier (buffer-local-value 'major-mode buf)))
 
 ;;;###autoload (autoload 'ibuffer-filter-by-used-mode "ibuf-ext")
 (define-ibuffer-filter used-mode
-  "Limit current view to buffers with major mode QUALIFIER.
-Called interactively, this function allows selection of modes
+    "Limit current view to buffers with major mode(s) specified by QUALIFIER.
+QUALIFIER is the mode name as a symbol or a list of symbols.
+
+Called interactively, accept a comma separated list of mode names
 currently used by buffers."
   (:description "major mode in use"
    :reader
@@ -1257,23 +1262,29 @@ used-mode
           (default (if (and buf (buffer-live-p buf))
                        (symbol-name (buffer-local-value
                                      'major-mode buf)))))
-     (intern
-      (completing-read
+     (mapcar #'intern
+      (completing-read-multiple
        (if default
            (format "Filter by major mode (default %s): " default)
          "Filter by major mode: ")
-       (ibuffer-list-buffer-modes) nil t nil nil default))))
+       (ibuffer-list-buffer-modes) nil t nil nil default)))
+   :accept-list t)
   (eq qualifier (buffer-local-value 'major-mode buf)))
 
 ;;;###autoload (autoload 'ibuffer-filter-by-derived-mode "ibuf-ext")
 (define-ibuffer-filter derived-mode
-    "Limit current view to buffers whose major mode inherits from QUALIFIER."
+    "Limit current view to buffers with major mode(s) specified by QUALIFIER.
+QUALIFIER is the mode name as a symbol or a list of symbols.
+ Restrict the view to buffers whose major mode derivates
+ from modes specified by QUALIFIER.
+Called interactively, accept a comma separated list of mode names."
   (:description "derived mode"
-		:reader
-		(intern
-		 (completing-read "Filter by derived mode: "
-				  (ibuffer-list-buffer-modes t)
-                                  nil t)))
+        :reader
+        (mapcar #'intern
+         (completing-read-multiple "Filter by derived mode: "
+                       (ibuffer-list-buffer-modes t)
+                       nil t))
+        :accept-list t)
   (with-current-buffer buf (derived-mode-p qualifier)))
 
 ;;;###autoload (autoload 'ibuffer-filter-by-name "ibuf-ext")
diff --git a/lisp/ibuf-macs.el b/lisp/ibuf-macs.el
index 6a70a8341a..72a35a5331 100644
--- a/lisp/ibuf-macs.el
+++ b/lisp/ibuf-macs.el
@@ -280,14 +280,18 @@ ibuffer-save-marks
 
 ;;;###autoload
 (cl-defmacro define-ibuffer-filter (name documentation
-				       (&key
-					reader
-					description)
-				       &rest body)
+                                         (&key
+                                          reader
+                                          description
+                                          accept-list)
+                                         &rest body)
   "Define a filter named NAME.
 DOCUMENTATION is the documentation of the function.
 READER is a form which should read a qualifier from the user.
 DESCRIPTION is a short string describing the filter.
+ACCEPT-LIST is a boolean; if non-nil, the filter accepts either
+a single condition or a list of them; in the latter
+case the filter is the `or' composition of the conditions.
 
 BODY should contain forms which will be evaluated to test whether or
 not a particular buffer should be displayed or not.  The forms in BODY
@@ -296,30 +300,41 @@ ibuffer-save-marks
 
 \(fn NAME DOCUMENTATION (&key READER DESCRIPTION) &rest BODY)"
   (declare (indent 2) (doc-string 2))
-  (let ((fn-name (intern (concat "ibuffer-filter-by-" (symbol-name name)))))
+  (let ((fn-name (intern (concat "ibuffer-filter-by-" (symbol-name name))))
+        (filter (make-symbol "ibuffer-filter"))
+        (qualifier-str (make-symbol "ibuffer-qualifier-str")))
     `(progn
        (defun ,fn-name (qualifier)
-	 ,(or documentation "This filter is not documented.")
-	 (interactive (list ,reader))
-	 (if (null (ibuffer-push-filter (cons ',name qualifier)))
-	     (message "%s"
-		      (format ,(concat (format "Filter by %s already applied: " description)
-				       " %s")
-			      qualifier))
-           (message "%s"
-		    (format ,(concat (format "Filter by %s added: " description)
-				     " %s")
-			    qualifier))
-	   (ibuffer-update nil t)))
+     ,(or documentation "This filter is not documented.")
+     (interactive (list ,reader))
+     (let ((,filter (cons ',name qualifier))
+           (,qualifier-str qualifier))
+       ,(when accept-list
+          `(progn
+         (unless (listp qualifier) (setq qualifier (list qualifier)))
+         ;; Reject equivalent filters: (or f1 f2) is same as (or f2 f1).
+         (setq qualifier (sort (delete-dups qualifier) #'string-lessp))
+         (setq ,filter (cons ',name (car qualifier)))
+         (setq ,qualifier-str
+               (mapconcat (lambda (m) (if (symbolp m) (symbol-name m) m))
+                  qualifier ","))
+         (when (cdr qualifier) ; Compose individual filters with `or'.
+           (setq ,filter `(or ,@(mapcar (lambda (m) (cons ',name m)) qualifier))))))
+       (if (null (ibuffer-push-filter ,filter))
+           (message ,(format "Filter by %s already applied:  %%s" description)
+                ,qualifier-str)
+         (message ,(format "Filter by %s added:  %%s" description)
+              ,qualifier-str)
+         (ibuffer-update nil t))))
        (push (list ',name ,description
-		   (lambda (buf qualifier)
-                     (condition-case nil
-                         (progn ,@body)
-                       (error (ibuffer-pop-filter)
-                              (when (eq ',name 'predicate)
-                                (error "Wrong filter predicate: %S"
-                                       qualifier))))))
-	     ibuffer-filtering-alist)
+           (lambda (buf qualifier)
+                  (condition-case nil
+                      (progn ,@body)
+                    (error (ibuffer-pop-filter)
+                           (when (eq ',name 'predicate)
+                             (error "Wrong filter predicate: %S"
+                                    qualifier))))))
+         ibuffer-filtering-alist)
        :autoload-end)))
 
 (provide 'ibuf-macs)

--8<-----------------------------cut here---------------end--------------->8---





^ permalink raw reply related	[flat|nested] 28+ messages in thread

* bug#32731: 26.1.50; Ibuffer filter by mode: Handle >1 mode names
  2018-09-24  8:27                         ` Tino Calancha
@ 2018-09-24 19:58                           ` Richard Stallman
  2018-09-24 20:48                             ` Tino Calancha
  0 siblings, 1 reply; 28+ messages in thread
From: Richard Stallman @ 2018-09-24 19:58 UTC (permalink / raw)
  To: Tino Calancha; +Cc: tino.calancha, 32731, npostavs

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

"She/he" seems to exclude nonbinary genders.
"S?he" does not HAVE to mean "only she or he".

-- 
Dr Richard Stallman
President, Free Software Foundation (https://gnu.org, https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)







^ permalink raw reply	[flat|nested] 28+ messages in thread

* bug#32731: 26.1.50; Ibuffer filter by mode: Handle >1 mode names
  2018-09-24 19:58                           ` Richard Stallman
@ 2018-09-24 20:48                             ` Tino Calancha
  2018-09-24 21:14                               ` Eli Zaretskii
  0 siblings, 1 reply; 28+ messages in thread
From: Tino Calancha @ 2018-09-24 20:48 UTC (permalink / raw)
  To: Richard Stallman; +Cc: Tino Calancha, 32731, npostavs



On Mon, 24 Sep 2018, Richard Stallman wrote:

> [[[ To any NSA and FBI agents reading my email: please consider    ]]]
> [[[ whether defending the US Constitution against all enemies,     ]]]
> [[[ foreign or domestic, requires you to follow Snowden's example. ]]]
>
> "She/he" seems to exclude nonbinary genders.
> "S?he" does not HAVE to mean "only she or he".
I don't feel excluded if I read "she".  Maybe I have enough 
self-confidence or I know the difference between
sex and gramatical genre.
Anyway, whatever Eli likes is fine for me.





^ permalink raw reply	[flat|nested] 28+ messages in thread

* bug#32731: 26.1.50; Ibuffer filter by mode: Handle >1 mode names
  2018-09-24 20:48                             ` Tino Calancha
@ 2018-09-24 21:14                               ` Eli Zaretskii
  2018-09-25  8:14                                 ` Robert Pluim
  0 siblings, 1 reply; 28+ messages in thread
From: Eli Zaretskii @ 2018-09-24 21:14 UTC (permalink / raw)
  To: Tino Calancha; +Cc: 32731, npostavs, rms

> From: Tino Calancha <tino.calancha@gmail.com>
> Date: Tue, 25 Sep 2018 05:48:43 +0900 (JST)
> Cc: Tino Calancha <tino.calancha@gmail.com>, 32731@debbugs.gnu.org,
> 	npostavs@gmail.com
> 
> > "She/he" seems to exclude nonbinary genders.
> > "S?he" does not HAVE to mean "only she or he".
> I don't feel excluded if I read "she".  Maybe I have enough 
> self-confidence or I know the difference between
> sex and gramatical genre.
> Anyway, whatever Eli likes is fine for me.

I usually just rewrite the text to be in plural, like "the users"
instead of "the user".  Then "they" is correct English.





^ permalink raw reply	[flat|nested] 28+ messages in thread

* bug#32731: 26.1.50; Ibuffer filter by mode: Handle >1 mode names
  2018-09-24 21:14                               ` Eli Zaretskii
@ 2018-09-25  8:14                                 ` Robert Pluim
  2018-09-25  9:24                                   ` Eli Zaretskii
  2018-09-29  9:49                                   ` Tino Calancha
  0 siblings, 2 replies; 28+ messages in thread
From: Robert Pluim @ 2018-09-25  8:14 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Tino Calancha, npostavs, rms, 32731

Eli Zaretskii <eliz@gnu.org> writes:

>> From: Tino Calancha <tino.calancha@gmail.com>
>> Date: Tue, 25 Sep 2018 05:48:43 +0900 (JST)
>> Cc: Tino Calancha <tino.calancha@gmail.com>, 32731@debbugs.gnu.org,
>> 	npostavs@gmail.com
>> 
>> > "She/he" seems to exclude nonbinary genders.
>> > "S?he" does not HAVE to mean "only she or he".
>> I don't feel excluded if I read "she".  Maybe I have enough 
>> self-confidence or I know the difference between
>> sex and gramatical genre.
>> Anyway, whatever Eli likes is fine for me.
>
> I usually just rewrite the text to be in plural, like "the users"
> instead of "the user".  Then "they" is correct English.

Point of order: singular they has been correct English for the last
700 years. Some people donʼt like it, but that doesnʼt make it wrong.

Robert





^ permalink raw reply	[flat|nested] 28+ messages in thread

* bug#32731: 26.1.50; Ibuffer filter by mode: Handle >1 mode names
  2018-09-25  8:14                                 ` Robert Pluim
@ 2018-09-25  9:24                                   ` Eli Zaretskii
  2018-09-25 23:03                                     ` Richard Stallman
  2018-09-29  9:49                                   ` Tino Calancha
  1 sibling, 1 reply; 28+ messages in thread
From: Eli Zaretskii @ 2018-09-25  9:24 UTC (permalink / raw)
  To: Robert Pluim; +Cc: tino.calancha, npostavs, rms, 32731

> From: Robert Pluim <rpluim@gmail.com>
> Cc: Tino Calancha <tino.calancha@gmail.com>,  32731@debbugs.gnu.org,  npostavs@gmail.com,  rms@gnu.org
> Date: Tue, 25 Sep 2018 10:14:11 +0200
> 
> > I usually just rewrite the text to be in plural, like "the users"
> > instead of "the user".  Then "they" is correct English.
> 
> Point of order: singular they has been correct English for the last
> 700 years. Some people donʼt like it, but that doesnʼt make it wrong.

"Some people" seem to include Richard, who said a few messages ago:

> Using "they" for a singular antecedent is confusing, and I always find
> it jarring.  I won't make a rule against, but I make a point of never
> using that construction.

Thus my preference to rewrite in plural.





^ permalink raw reply	[flat|nested] 28+ messages in thread

* bug#32731: 26.1.50; Ibuffer filter by mode: Handle >1 mode names
  2018-09-25  9:24                                   ` Eli Zaretskii
@ 2018-09-25 23:03                                     ` Richard Stallman
  0 siblings, 0 replies; 28+ messages in thread
From: Richard Stallman @ 2018-09-25 23:03 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: rpluim, tino.calancha, 32731, npostavs

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > Thus my preference to rewrite in plural.

Please do that,

-- 
Dr Richard Stallman
President, Free Software Foundation (https://gnu.org, https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)







^ permalink raw reply	[flat|nested] 28+ messages in thread

* bug#32731: 26.1.50; Ibuffer filter by mode: Handle >1 mode names
  2018-09-25  8:14                                 ` Robert Pluim
  2018-09-25  9:24                                   ` Eli Zaretskii
@ 2018-09-29  9:49                                   ` Tino Calancha
  1 sibling, 0 replies; 28+ messages in thread
From: Tino Calancha @ 2018-09-29  9:49 UTC (permalink / raw)
  To: 32731-done

Robert Pluim <rpluim@gmail.com> writes:

> Eli Zaretskii <eliz@gnu.org> writes:
>
>>> From: Tino Calancha <tino.calancha@gmail.com>
>>> Date: Tue, 25 Sep 2018 05:48:43 +0900 (JST)
>>> Cc: Tino Calancha <tino.calancha@gmail.com>, 32731@debbugs.gnu.org,
>>> 	npostavs@gmail.com
>>> 
>>> > "She/he" seems to exclude nonbinary genders.
>>> > "S?he" does not HAVE to mean "only she or he".
>>> I don't feel excluded if I read "she".  Maybe I have enough 
>>> self-confidence or I know the difference between
>>> sex and gramatical genre.
>>> Anyway, whatever Eli likes is fine for me.
>>
>> I usually just rewrite the text to be in plural, like "the users"
>> instead of "the user".  Then "they" is correct English.
>
> Point of order: singular they has been correct English for the last
> 700 years. Some people donʼt like it, but that doesnʼt make it wrong.
My grandmother used to say:
"You'll never go to bed without learning a new thing"

[I know, every grandmother says that; same as the best
food is the one prepared by the mother of the person you are asking.]

I will write it in plural.  Thank you all for the feedback!

Implemented at master branch as commit
'Ibuffer filter by modes: Accept several mode names'
(2296bf188fc99d66306e71e6decd3d2e176b7ae6)





^ permalink raw reply	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2018-09-29  9:49 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-09-13 18:19 bug#32731: 26.1.50; Ibuffer filter by mode: Handle >1 mode names Tino Calancha
2018-09-13 19:09 ` Noam Postavsky
2018-09-13 20:04   ` Tino Calancha
2018-09-13 20:38   ` Tino Calancha
2018-09-13 23:39     ` Noam Postavsky
2018-09-15  9:15       ` Tino Calancha
2018-09-15 12:42         ` Noam Postavsky
2018-09-17 17:44           ` Tino Calancha
2018-09-17 18:27             ` Eli Zaretskii
2018-09-17 19:53               ` Tino Calancha
2018-09-18  7:14                 ` Eli Zaretskii
2018-09-18 23:19             ` Noam Postavsky
2018-09-19  9:23               ` Tino Calancha
2018-09-19  9:42                 ` Eli Zaretskii
2018-09-21  8:37                   ` Tino Calancha
2018-09-22  9:14                     ` Eli Zaretskii
2018-09-22 13:00                     ` Noam Postavsky
2018-09-23  1:37                       ` Richard Stallman
2018-09-23 12:01                         ` Noam Postavsky
2018-09-24  8:27                         ` Tino Calancha
2018-09-24 19:58                           ` Richard Stallman
2018-09-24 20:48                             ` Tino Calancha
2018-09-24 21:14                               ` Eli Zaretskii
2018-09-25  8:14                                 ` Robert Pluim
2018-09-25  9:24                                   ` Eli Zaretskii
2018-09-25 23:03                                     ` Richard Stallman
2018-09-29  9:49                                   ` Tino Calancha
2018-09-24  8:36                       ` Tino Calancha

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).