Subject: Re: bug#76587: 31.0.50; [FR] project.el should have a way to exclude certain projects from being saved

From: Visuwesh <[email-masked]>
Date: Sun, 02 Mar 2025 10:01:58 +0530

[ஞாயிறு மார்ச் 02, 2025] Dmitry Gutov wrote:

> On 28/02/2025 05:48, Visuwesh wrote:
>> I see one caller of project--remember-dir, project-switch-project, that
>> does not have the project object handy.  Maybe we could do
>>      (project--remember-dir dir nil (project-current nil dir))
>> in place of the current call in project-switch-project?
>
> Hm yeah, I suppose that would be okay: project-switch-project is not
> required to be very fast, and project search often uses cache.
>
> And when the project value is available, the call to be made to
> project-remember-project instead - this one could do the filtering as
> well. So no need to add new arg to project--remember-dir.

OK, sounds good to me.  WDYT about the patch below?  It doesn't exclude
projects at the time of saving, but whenever project-remember-project is
called.

diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el
index 35bf66c9ffb..9904a734e07 100644
--- a/lisp/progmodes/project.el
+++ b/lisp/progmodes/project.el
@@ -1837,6 +1837,14 @@ project-list-file
   :version "28.1"
   :group 'project)
 
+(defcustom project-list-exclude nil
+  "List of regexps and predicates for project root and objects to ignore.
+The predicate should take one argument, the projet object, and should
+return non-nil if the project should not be saved."
+  :type '(repeat (choice regexp function))
+  :version "31.1"
+  :group 'project)
+
 (defvar project--list 'unset
   "List structure containing root directories of known projects.
 With some possible metadata (to be decided).")
@@ -1902,9 +1910,16 @@ project--remember-dir
 ;;;###autoload
 (defun project-remember-project (pr &optional no-write)
   "Add project PR to the front of the project list.
+If project PR satisfies `project-list-exclude', then nothing is done.
 Save the result in `project-list-file' if the list of projects
 has changed, and NO-WRITE is nil."
-  (project--remember-dir (project-root pr) no-write))
+  (let ((root (project-root pr)))
+    (when (or (null project-list-exclude)
+              (null (seq-some (lambda (r)
+                                (if (functionp r) (funcall r pr)
+                                  (string-match-p r root)))
+                              project-list-exclude)))
+      (project--remember-dir root no-write))))
 
 (defun project--remove-from-project-list (project-root report-message)
   "Remove directory PROJECT-ROOT of a missing project from the project list.
@@ -2274,7 +2289,7 @@ project-switch-project
 When called in a program, it will use the project corresponding
 to directory DIR."
   (interactive (list (funcall project-prompter)))
-  (project--remember-dir dir)
+  (project-remember-project (project-current nil dir))
   (let ((command (if (symbolp project-switch-commands)
                      project-switch-commands
                    (project--switch-project-command dir)))