]> git.eshelyaron.com Git - emacs.git/commitdiff
Allow automatically delete non-existent projects. (Bug#77566)
authorElías Gabriel Pérez <eg642616@gmail.com>
Wed, 9 Apr 2025 04:30:28 +0000 (22:30 -0600)
committerEshel Yaron <me@eshelyaron.com>
Wed, 23 Jul 2025 19:18:00 +0000 (21:18 +0200)
* etc/NEWS: Announce changes.
* lisp/progmodes/project.el (project-prune-zombie-projects): New
user option.
(project-prune-zombies-default): New function.
(project-forget-zombie-projects): Rework.
(project--ensure-read-project-list, project-prompt-project-dir)
(project-prompt-project-name): Call
'project-forget-zombie-projects' but inhibit its message.

(cherry picked from commit 6b078013f19e9e2ee4e7ac8bf5d22fb0b8989035)

lisp/progmodes/project.el

index 61694c3ec6a77043d17d47037d5acf6953845b47..2d57579513db662dc683c424b1b6a621130dc286 100644 (file)
@@ -1476,6 +1476,24 @@ general form of conditions."
   :group 'project
   :package-version '(project . "0.8.2"))
 
+(defcustom project-prune-zombie-projects #'project-prune-zombies-default
+  "Remove automatically from project list all the projects that were removed.
+The value can be a predicate function which takes one argument, and
+should return non-nil if the project should be removed.
+If set to nil, all the inaccessible projects will not be removed automatically."
+  :type '(choice (const :tag "Default (remove non-remote projects)"
+                        project-prune-zombies-default)
+                 (const :tag "Remove any project" identity)
+                 (function :tag "Custom function")
+                 (const :tag "Disable auto-deletion" nil))
+  :version "31.1"
+  :group 'project)
+
+(defun project-prune-zombies-default (project)
+  "Default function used in `project-prune-zombie-projects'.
+Return non-nil if PROJECT is not a remote project."
+  (not (file-remote-p project)))
+
 (defun project--read-project-buffer ()
   (let* ((pr (project-current t))
          (current-buffer (current-buffer))
@@ -1839,7 +1857,11 @@ With some possible metadata (to be decided).")
 (defun project--ensure-read-project-list ()
   "Initialize `project--list' if it isn't already initialized."
   (when (eq project--list 'unset)
-    (project--read-project-list)))
+    (project--read-project-list)
+    (if-let* (project-prune-zombie-projects
+              ((consp project--list))
+              (inhibit-message t))
+        (project-forget-zombie-projects))))
 
 (defun project--write-project-list ()
   "Save `project--list' in `project-list-file'."
@@ -1939,6 +1961,9 @@ see `project-list-file'.
 It's also possible to enter an arbitrary directory not in the list.
 When PROMPT is non-nil, use it as the prompt string."
   (project--ensure-read-project-list)
+  (if-let* (project-prune-zombie-projects
+            (inhibit-message t))
+      (project-forget-zombie-projects))
   (let* ((dir-choice "... (choose a dir)")
          (choices
           ;; XXX: Just using this for the category (for the substring
@@ -2012,6 +2037,9 @@ The project is chosen among projects known from the project list,
 see `project-list-file'.
 It's also possible to enter an arbitrary directory not in the list.
 When PROMPT is non-nil, use it as the prompt string."
+  (if-let* (project-prune-zombie-projects
+            (inhibit-message t))
+      (project-forget-zombie-projects))
   (let* ((dir-choice "... (choose a dir)")
          project--name-history
          (choices
@@ -2140,7 +2168,10 @@ Return the number of detected projects."
   "Forget all known projects that don't exist any more."
   (interactive)
   (dolist (proj (project-known-project-roots))
-    (unless (file-exists-p proj)
+    (when (and (if project-prune-zombie-projects
+                   (funcall project-prune-zombie-projects proj)
+                 t)
+               (not (file-exists-p proj)))
       (project-forget-project proj))))
 
 (defun project-read-ancestor-directory (prompt)