Subject: bug#25058: closed (Re: bug#25058: 26.0.50; ibuffer-decompose-filter-group: unwanted side effects)

From: [email-masked] (GNU bug Tracking System)
Date: Wed, 07 Dec 2016 12:56:02 +0000

Your bug report

#25058: 26.0.50; ibuffer-decompose-filter-group: unwanted side effects

which was filed against the emacs package, has been closed.

The explanation is attached below, along with your original report.
If you require more details, please reply to [email-masked].

-- 
25058: http://debbugs.gnu.org/cgi/bugreport.cgi?bug=25058
GNU Bug Tracking System
Contact [email-masked] with problems

Subject: Re: bug#25058: 26.0.50; ibuffer-decompose-filter-group: unwanted side effects
From: Tino Calancha <[email-masked]>
To: [email-masked]
Date: Wed, 07 Dec 2016 21:55:06 +0900
List-Id: <debbugs-submit.debbugs.gnu.org>

Tino Calancha <[email-masked]> writes:

> `ibuffer-decompose-filter-group' has unwanted side effects: it might
> modify `ibuffer-saved-filter-groups'.
Pushed fix to master branch as commit 53fefb5.

Subject: 26.0.50; ibuffer-decompose-filter-group: unwanted side effects
From: Tino Calancha <[email-masked]>
To: [email-masked]
Date: Tue, 29 Nov 2016 18:28:07 +0900
List-Id: <debbugs-submit.debbugs.gnu.org>

`ibuffer-decompose-filter-group' has unwanted side effects: it might
modify `ibuffer-saved-filter-groups'.

emacs -Q -eval "(dired (expand-file-name source-directory))"
;; Evaluate following form:
(progn
  (ibuffer)
  (setq ibuffer-show-empty-filter-groups nil
        ibuffer-saved-filter-groups
        '(("saved-filters"
           ("Shell"
            (used-mode . shell-mode))
           ("Elisp"
            (or
             (used-mode . emacs-lisp-mode)
             (used-mode . lisp-interaction-mode)))
           ("Dired"
            (used-mode . dired-mode))
           ("Info"
            (or
             (used-mode . help-mode)
             (used-mode . debugger-mode)
             (used-mode . Custom-mode)
             (used-mode . completion-list-mode)
             (name . "\\`[*]Messages[*]\\'"))))))
  (ibuffer-switch-to-saved-filter-groups "saved-filters"))
;; Now we call `ibuffer-decompose-filter-group' followed by
;; `ibuffer-filter-disable' and `ibuffer-switch-to-saved-filter-groups'.
;; These commands should bring us back to the initial Ibuffer status:
/D Elisp RET
//
/R
;; Elisp group is missing without calling `ibuffer-delete-saved-filter-groups'
M-: (assoc "Elisp" (cdar ibuffer-saved-filter-groups)) RET
=> nil

The reason seems to be that `ibuffer-saved-filter-groups' and
`ibuffer-filter-groups' share elements.
(eq (cdar ibuffer-saved-filter-groups) ibuffer-filter-groups)
=> t

Then, the destructive
function `ibuffer-delete-alist' applied on `ibuffer-filter-groups' will
modify the other list as well.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
>From 45f95151de799fc1acd19353a40b22d6783ad1a6 Mon Sep 17 00:00:00 2001
From: Tino Calancha <[email-masked]>
Date: Tue, 29 Nov 2016 18:14:32 +0900
Subject: [PATCH] ibuffer-decompose-filter-group avoid unwanted side effects

* lisp/ibuf-ext.el (ibuffer-delete-alist): Remove it.
(ibuffer-remove-alist): New defun; it supersedes 'ibuffer-delete-alist'.
All callers changed (Bug#25058).
* test/lisp/ibuffer-tests.el (ibuffer-test-Bug25058): Add test.
---
 lisp/ibuf-ext.el           | 23 +++++++++++------------
 test/lisp/ibuffer-tests.el | 33 +++++++++++++++++++++++++++++++++
 2 files changed, 44 insertions(+), 12 deletions(-)

diff --git a/lisp/ibuf-ext.el b/lisp/ibuf-ext.el
index 5ef0746..7f35ce6 100644
--- a/lisp/ibuf-ext.el
+++ b/lisp/ibuf-ext.el
@@ -38,12 +38,11 @@
   (require 'cl-lib))
 
 ;;; Utility functions
-(defun ibuffer-delete-alist (key alist)
-  "Delete all entries in ALIST that have a key equal to KEY."
-  (let (entry)
-    (while (setq entry (assoc key alist))
-      (setq alist (delete entry alist)))
-    alist))
+(defun ibuffer-remove-alist (key alist)
+  "Remove all entries in ALIST that have a key equal to KEY."
+  (while (ibuffer-awhen (assoc key alist)
+           (setq alist (remove it alist)) it))
+  alist)
 
 ;; borrowed from Gnus
 (defun ibuffer-remove-duplicates (list)
@@ -281,7 +280,7 @@ ibuffer-interactive-filter-by-mode
   (let ((buf (ibuffer-current-buffer)))
     (if (assq 'mode ibuffer-filtering-qualifiers)
 	(setq ibuffer-filtering-qualifiers
-	      (ibuffer-delete-alist 'mode ibuffer-filtering-qualifiers))
+	      (ibuffer-remove-alist 'mode ibuffer-filtering-qualifiers))
       (ibuffer-push-filter (cons 'mode (buffer-local-value 'major-mode buf)))))
   (ibuffer-update nil t))
 
@@ -556,7 +555,7 @@ ibuffer-generate-filter-groups
 			      (append ibuffer-filter-groups
 				      (list (cons "Default" nil))))))
     ;; (dolist (hidden ibuffer-hidden-filter-groups)
-    ;;   (setq filter-group-alist (ibuffer-delete-alist
+    ;;   (setq filter-group-alist (ibuffer-remove-alist
     ;;     			   hidden filter-group-alist)))
     (let ((vec (make-vector (length filter-group-alist) nil))
 	  (i 0))
@@ -640,7 +639,7 @@ ibuffer-decompose-filter-group
   (interactive
    (list (ibuffer-read-filter-group-name "Decompose filter group: " t)))
   (let ((data (cdr (assoc group ibuffer-filter-groups))))
-    (setq ibuffer-filter-groups (ibuffer-delete-alist
+    (setq ibuffer-filter-groups (ibuffer-remove-alist
 				 group ibuffer-filter-groups)
 	  ibuffer-filtering-qualifiers data))
   (ibuffer-update nil t))
@@ -688,7 +687,7 @@ ibuffer-kill-filter-group
   (ibuffer-aif (assoc name ibuffer-filter-groups)
       (progn
 	(push (copy-tree it) ibuffer-filter-group-kill-ring)
-	(setq ibuffer-filter-groups (ibuffer-delete-alist
+	(setq ibuffer-filter-groups (ibuffer-remove-alist
 				     name ibuffer-filter-groups))
 	(setq ibuffer-hidden-filter-groups
 	      (delete name ibuffer-hidden-filter-groups)))
@@ -778,7 +777,7 @@ ibuffer-delete-saved-filter-groups
       (completing-read "Delete saved filter group: "
 		       ibuffer-saved-filter-groups nil t))))
   (setq ibuffer-saved-filter-groups
-	(ibuffer-delete-alist name ibuffer-saved-filter-groups))
+	(ibuffer-remove-alist name ibuffer-saved-filter-groups))
   (ibuffer-maybe-save-stuff)
   (ibuffer-update nil t))
 
@@ -949,7 +948,7 @@ ibuffer-delete-saved-filters
       (completing-read "Delete saved filters: "
 		       ibuffer-saved-filters nil t))))
   (setq ibuffer-saved-filters
-	(ibuffer-delete-alist name ibuffer-saved-filters))
+	(ibuffer-remove-alist name ibuffer-saved-filters))
   (ibuffer-maybe-save-stuff)
   (ibuffer-update nil t))
 
diff --git a/test/lisp/ibuffer-tests.el b/test/lisp/ibuffer-tests.el
index 3a4def3..260469e 100644
--- a/test/lisp/ibuffer-tests.el
+++ b/test/lisp/ibuffer-tests.el
@@ -66,5 +66,38 @@
       (mapc (lambda (buf) (when (buffer-live-p buf)
                             (kill-buffer buf))) (list buf1 buf2)))))
 
+(ert-deftest ibuffer-test-Bug25058 ()
+  "Test for http://debbugs.gnu.org/25058 ."
+  (ibuffer)
+  (let ((orig-filters ibuffer-saved-filter-groups)
+        (tmp-filters '(("saved-filters"
+                        ("Shell"
+                         (used-mode . shell-mode))
+                        ("Elisp"
+                         (or
+                          (used-mode . emacs-lisp-mode)
+                          (used-mode . lisp-interaction-mode)))
+                        ("Dired"
+                         (used-mode . dired-mode))
+                        ("Info"
+                         (or
+                          (used-mode . help-mode)
+                          (used-mode . debugger-mode)
+                          (used-mode . Custom-mode)
+                          (used-mode . completion-list-mode)
+                          (name . "\\`[*]Messages[*]\\'")))))))
+    (unwind-protect
+        (progn
+          (setq ibuffer-saved-filter-groups tmp-filters)
+	  (ibuffer-switch-to-saved-filter-groups "saved-filters")
+          (ibuffer-decompose-filter-group "Elisp")
+          (ibuffer-filter-disable)
+          (ibuffer-switch-to-saved-filter-groups "saved-filters")
+          (should (assoc "Elisp" (cdar ibuffer-saved-filter-groups))))
+      (setq ibuffer-saved-filter-groups orig-filters)
+      (ibuffer-awhen (get-buffer "*Ibuffer*")
+        (and (buffer-live-p it) (kill-buffer it))))))
+
+
 (provide 'ibuffer-tests)
 ;; ibuffer-tests.el ends here
-- 
2.10.2

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
In GNU Emacs 26.0.50.1 (x86_64-pc-linux-gnu, GTK+ Version 3.22.4)
 of 2016-11-28
Repository revision: 2c8a7e50d24daf19ea7d86f1cfeaa98a41c56085