From 4779aae9d1c18cd2dc2b8f54322b48b0e11ac5fb Mon Sep 17 00:00:00 2001 From: Philip Kaludercic Date: Tue, 31 Aug 2021 14:12:13 +0200 Subject: [PATCH] Add aggregate project discovery and maintenance functions * project.el (project-remember-project): Add optional no-write argument (project-remember-projects-under): Add command (project-forget-zombie-projects): Add command (project-forget-known-projects): Add command --- lisp/progmodes/project.el | 72 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 3 deletions(-) diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index ebd21d4b60..977b1ae185 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el @@ -1290,9 +1290,10 @@ project--write-project-list (write-region nil nil filename nil 'silent)))) ;;;###autoload -(defun project-remember-project (pr) +(defun project-remember-project (pr &optional no-write) "Add project PR to the front of the project list. -Save the result in `project-list-file' if the list of projects has changed." +Save the result in `project-list-file' if the list of projects +has changed, and NO-WRITE is nil." (project--ensure-read-project-list) (let ((dir (project-root pr))) (unless (equal (caar project--list) dir) @@ -1300,7 +1301,8 @@ project-remember-project (when (equal dir (car ent)) (setq project--list (delq ent project--list)))) (push (list dir) project--list) - (project--write-project-list)))) + (unless no-write + (project--write-project-list))))) (defun project--remove-from-project-list (project-root report-message) "Remove directory PROJECT-ROOT of a missing project from the project list. @@ -1357,6 +1359,70 @@ project-execute-extended-command (let ((default-directory (project-root (project-current t)))) (call-interactively #'execute-extended-command))) +(defun project-remember-projects-under (dir &optional recursive) + "Index all projects below a directory DIR. +If RECURSIVE is non-nil, recurse into all subdirectories to find +more projects. After finishing, a message is printed summarizing +the progress. The function returns the number of detected +projects." + (interactive "DDirectory: \nP") + (project--ensure-read-project-list) + (let ((queue (directory-files dir t nil t)) (count 0) + (known (make-hash-table + :size (* 2 (length project--list)) + :test #'equal ))) + (dolist (project (mapcar #'car project--list)) + (puthash project t known)) + (while queue + (when-let ((subdir (pop queue)) + ((file-directory-p subdir)) + ((not (gethash subdir known)))) + (when-let (pr (project--find-in-directory subdir)) + (project-remember-project pr t) + (message "Found %s..." (project-root pr)) + (setq count (1+ count))) + (when (and recursive (file-symlink-p subdir)) + (setq queue (nconc (directory-files subdir t nil t) queue)) + (puthash subdir t known)))) + (unless (eq recursive 'in-progress) + (if (zerop count) + (message "No projects were found") + (project--write-project-list) + (message "%d project%s were found" + count (if (= count 1) "" "s")))) + count)) + +(defun project-forget-zombie-projects () + "Forget all known projects that don't exist any more." + (interactive) + (dolist (proj (project-known-project-roots)) + (unless (file-exists-p proj) + (project-remove-known-project proj)))) + +(defun project-forget-known-projects (dir &optional recursive) + "Forget all known projects below a directory DIR. +If RECURSIVE is non-nil, recurse into all subdirectories to +remove all known projects. After finishing, a message is printed +summarizing the progress. The function returns the number of +forgotten projects." + (interactive "DDirectory: \nP") + (let ((count 0)) + (if recursive + (dolist (proj (project-known-project-roots)) + (when (file-in-directory-p proj dir) + (project-remove-known-project proj) + (setq count (1+ count)))) + (dolist (proj (project-known-project-roots)) + (when (file-equal-p (file-name-directory proj) dir) + (project-remove-known-project proj) + (setq count (1+ count))))) + (if (zerop count) + (message "No projects were forgotten") + (project--write-project-list) + (message "%d project%s were forgotten" + count (if (= count 1) "" "s"))) + count)) + ;;; Project switching -- 2.30.2