Subject: bug#59842: closed (Re: bug#59842: [PATCH] Make proced-update Preserve Refinements)

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

Your bug report

#59842: [PATCH] Make proced-update Preserve Refinements

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].

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

Subject: Re: bug#59842: [PATCH] Make proced-update Preserve Refinements
From: Eli Zaretskii <[email-masked]>
To: Laurence Warne <[email-masked]>
Cc: [email-masked]
Date: Wed, 14 Dec 2022 16:55:05 +0200
List-Id: <debbugs-submit.debbugs.gnu.org>

> From: Laurence Warne <[email-masked]>
> Date: Thu, 8 Dec 2022 19:06:35 +0000
> Cc: [email-masked]
> 
> If it's helpful, I've attached a (seperate) patch containing a test suite (or at least the start of) for proced.el
> (though some parts are somewhat awkward - mainly testing the proced buffer contains strings we would
> expect - of course comments on the approach welcome), the last test there: 'proced-refine-with-update-test'
> fails without the original patch.  I didn't want to conflate the original patch with it, I can open a new report with it
> if you prefer.

I installed both on the master branch, and modified the tests so that
they could be run on more systems.

I'm therefore closing this bug.

Subject: [PATCH] Make proced-update Preserve Refinements
From: Laurence Warne <[email-masked]>
To: [email-masked]
Date: Mon, 5 Dec 2022 20:26:26 +0000
List-Id: <debbugs-submit.debbugs.gnu.org>

Hi,

Currently proced-update will clear any active refinements in proced-buffers
(see proced-refine for information on refinements), which can be annoying
when proced-auto-update-flag is non-nil as this will result in you only
being able to see the refinement for a few seconds before the buffer
updates and you're back to all processes.  To reproduce this:

(require 'proced)
(setq-default proced-auto-update-flag t)
(setq-default proced-auto-update-interval 1)

M-x proced, then create a new refinement by <ENTER> on the PID of any
process.  You should see your refinement vanish after the next update.

The patch fixes aims to fix this by introducing a new buffer local variable
"proced-refinements" which stores information about the current
refinements, and is used by proced-update to further refine
proced-process-alist in the case it is non-nil.

proced-revert will get rid of any existing refinements (bound to "g"), so
the existing behaviour of refinements with proced-auto-update-flag set to
nil should stay the same.

Thanks, Laurence
From 1d71022e6359d017d08a424cb2c04077c804e8a4 Mon Sep 17 00:00:00 2001
From: Laurence Warne <[email-masked]>
Date: Sat, 3 Dec 2022 21:41:57 +0000
Subject: [PATCH] Make proced-update preserve refinements

Make proced-update preserve refinements by creating a new buffer local
variable proced-refinements which stores information about the current
refinements and is used by proced-update to further refine
proced-process-alist in the case it is non-nil.  The result is that
refinements are not immediately cleared when a proced buffer is
updated with proced-auto-update-flag non-nil.  proced-revert
maintains its current behaviour of clearing any active refinements.

* lisp/proced.el (proced-refinements): New buffer local variable
which tracks the current refinements.
(proced-refine): Set proced-refinements variable and defer setting of
proced-process-alist to proced-update.
(proced-update): Take into account proced-refinements when setting
proced-process-alist.
(proced-revert): Set proced-refinements to nil prior to calling proced-update.
---
 lisp/proced.el | 51 ++++++++++++++++++++++++++++++++------------------
 1 file changed, 33 insertions(+), 18 deletions(-)

diff --git a/lisp/proced.el b/lisp/proced.el
index c7419288ed..e13a804468 100644
--- a/lisp/proced.el
+++ b/lisp/proced.el
@@ -656,6 +656,14 @@ proced-mode-map
   )
 (put 'proced-mark :advertised-binding "m")
 
+(defvar-local proced-refinements nil
+  "Information about the current buffer refinements.
+
+It should be a list of elements of the form (REFINER PID KEY GRAMMAR), where
+REFINER and GRAMMAR are as described in `proced-grammar-alist', PID is the
+process ID of the process used to create the refinement, and KEY the attribute
+of the process.  A value of nil indicates that there are no active refinements.")
+
 (easy-menu-define proced-menu proced-mode-map
   "Proced Menu."
   `("Proced"
@@ -1337,20 +1345,7 @@ proced-refine
         (let* ((grammar (assq key proced-grammar-alist))
                (refiner (nth 7 grammar)))
           (when refiner
-            (cond ((functionp (car refiner))
-                   (setq proced-process-alist (funcall (car refiner) pid)))
-                  ((consp refiner)
-                   (let ((predicate (nth 4 grammar))
-                         (ref (cdr (assq key (cdr (assq pid proced-process-alist)))))
-                         val new-alist)
-                     (dolist (process proced-process-alist)
-                       (setq val (funcall predicate (cdr (assq key (cdr process))) ref))
-                       (if (cond ((not val) (nth 2 refiner))
-                                 ((eq val 'equal) (nth 1 refiner))
-                                 (val (car refiner)))
-                           (push process new-alist)))
-                     (setq proced-process-alist new-alist))))
-            ;; Do not revert listing.
+            (add-to-list 'proced-refinements (list refiner pid key grammar) t)
             (proced-update)))
       (message "No refiner defined here."))))
 
@@ -1859,10 +1854,29 @@ proced-update
                        "Updating process display...")))
   (if revert ;; evaluate all processes
       (setq proced-process-alist (proced-process-attributes)))
-  ;; filtering and sorting
+  ;; filtering
+  (setq proced-process-alist (proced-filter proced-process-alist proced-filter))
+  ;; refinements
+  (pcase-dolist (`(,refiner ,pid ,key ,grammar) proced-refinements)
+    ;; It's possible the process has exited since the refinement was made
+    (when (assq pid proced-process-alist)
+      (cond ((functionp (car refiner))
+             (setq proced-process-alist (funcall (car refiner) pid)))
+            ((consp refiner)
+             (let ((predicate (nth 4 grammar))
+                   (ref (cdr (assq key (cdr (assq pid proced-process-alist)))))
+                   val new-alist)
+               (dolist (process proced-process-alist)
+                 (setq val (funcall predicate (cdr (assq key (cdr process))) ref))
+                 (when (cond ((not val) (nth 2 refiner))
+                             ((eq val 'equal) (nth 1 refiner))
+                             (val (car refiner)))
+                   (push process new-alist)))
+               (setq proced-process-alist new-alist))))))
+
+  ;; sorting
   (setq proced-process-alist
-        (proced-sort (proced-filter proced-process-alist proced-filter)
-                     proced-sort proced-descend))
+        (proced-sort proced-process-alist proced-sort proced-descend))
 
   ;; display as process tree?
   (setq proced-process-alist
@@ -1976,7 +1990,8 @@ proced-update
 
 (defun proced-revert (&rest _args)
   "Reevaluate the process listing based on the currently running processes.
-Preserves point and marks."
+Preserves point and marks, but not refinements."
+  (setq proced-refinements nil)
   (proced-update t))
 
 (defun proced-marked-processes ()
-- 
2.30.2