Subject: [PATCH] Add option for automatically delete non-existent projects.

From: Elijah Gabe Pérez <[email-masked]>
Date: Sat, 05 Apr 2025 17:50:56 -0600

Tags: patch

This feature automatically remove from project list projects that were
deleted, only when `project-switch-project' is being used.

This acts similar to `projectile-auto-cleanup-known-projects' from
projectile.el

>From d426ab218feb1b2ce8c203991374a9e987f2a379 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?El=C3=ADas=20Gabriel=20P=C3=A9rez?= <[email-masked]>
Date: Sat, 5 Apr 2025 16:18:27 -0600
Subject: [PATCH] Add option for automatically delete non-existent projects. 
 (bug#)

* etc/NEWS: Announce changes.
* lisp/progmodes/project.el
(project-auto-forget-zombie-projects):
New user option.
(project--remove-from-project-list, project-forget-project)
(project-forget-zombie-projects): Allow not to show forgotten
projects.
(project-switch-project): Call `project-forget-zombie-projects'
only if `project-auto-forget-zombie-projects' is non-nil.
---
 etc/NEWS                  |  5 +++++
 lisp/progmodes/project.el | 26 ++++++++++++++++++--------
 2 files changed, 23 insertions(+), 8 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index cc63d03eafe..37e7a32f09a 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -362,6 +362,11 @@ invoked standalone or from the 'project-switch-commands' dispatch menu.
 This user option describes projects that should always be skipped by
 'project-remember-project'.
 
++++
+*** New user option 'project-auto-forget-zombie-projects'.
+This user option automatically remove projects from 'project-list-file'
+that have been deleted when switching projects.
+
 ---
 *** New command 'project-save-some-buffers' bound to 'C-x p C-x s'.
 This is like 'C-x s', but only for this project's buffers.
diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el
index e2cd5bfa231..6a38f49978b 100644
--- a/lisp/progmodes/project.el
+++ b/lisp/progmodes/project.el
@@ -1551,6 +1551,14 @@ project-ignore-buffer-conditions
   :group 'project
   :package-version '(project . "0.8.2"))
 
+(defcustom project-auto-forget-zombie-projects nil
+  "Automatically remove projects that doesn't exist anymore.
+If non-nil, remove automatically projects that doesn't exist anymore
+when switching projects."
+  :type 'boolean
+  :version "31.1"
+  :group 'project)
+
 (defun project--read-project-buffer ()
   (let* ((pr (project-current t))
          (current-buffer (current-buffer))
@@ -1936,23 +1944,24 @@ project-remember-project
 (defun project--remove-from-project-list (project-root report-message)
   "Remove directory PROJECT-ROOT of a missing project from the project list.
 If the directory was in the list before the removal, save the
-result in `project-list-file'.  Announce the project's removal
-from the list using REPORT-MESSAGE, which is a format string
-passed to `message' as its first argument."
+result in `project-list-file'.  If REPORT-MESSAGE is non-nil,
+Announce the project's removal from the list using REPORT-MESSAGE,
+which is a format string passed to `message' as its first argument."
   (project--ensure-read-project-list)
   (when-let* ((ent (assoc (abbreviate-file-name project-root) project--list)))
     (setq project--list (delq ent project--list))
-    (message report-message project-root)
+    (when report-message (message report-message project-root))
     (project--write-project-list)))
 
 ;;;###autoload
-(defun project-forget-project (project-root)
+(defun project-forget-project (project-root &optional no-message)
   "Remove directory PROJECT-ROOT from the project list.
 PROJECT-ROOT is the root directory of a known project listed in
-the project list."
+the project list.
+If NO-MESSAGE is non-nil, don't display a message about project removed."
   (interactive (list (funcall project-prompter)))
   (project--remove-from-project-list
-   project-root "Project `%s' removed from known projects"))
+   project-root (unless no-message "Project `%s' removed from known projects")))
 
 (defvar project--dir-history)
 
@@ -2122,7 +2131,7 @@ project-forget-zombie-projects
   (interactive)
   (dolist (proj (project-known-project-roots))
     (unless (file-exists-p proj)
-      (project-forget-project proj))))
+      (project-forget-project proj 'no-message))))
 
 (defun project-forget-projects-under (dir &optional recursive)
   "Forget all known projects below a directory DIR.
@@ -2302,6 +2311,7 @@ project-switch-project
 to directory DIR."
   (interactive (list (funcall project-prompter)))
   (project-remember-project (project-current nil dir))
+  (if project-auto-forget-zombie-projects (project-forget-zombie-projects))
   (let ((command (if (symbolp project-switch-commands)
                      project-switch-commands
                    (project--switch-project-command dir)))
-- 
2.49.0

-- 
                                          - E.G via GNU Emacs and Org.