From a28bf9c778dadab1b3f93e90b0706a6e6f2da657 Mon Sep 17 00:00:00 2001 From: Bozhidar Batsov Date: Sat, 14 Feb 2026 17:06:31 +0200 Subject: Fix grep hook, replace-regexp on missing files, and corrupt bookmarks - Pass unique=t to rename-buffer in projectile-grep so subsequent greps don't fail with "buffer name in use", which prevented projectile-grep-finished-hook from running (#1687) - Filter nonexistent files from projectile-replace-regexp file list to avoid stopping on deleted files (#1456) - Validate that deserialized known-projects data is a proper list, gracefully handling corrupted bookmarks files (#1939) --- CHANGELOG.md | 3 +++ projectile.el | 21 +++++++++++++-------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7cf4b69..efddfbc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,9 @@ * [#1823](https://github.com/bbatsov/projectile/issues/1823): Update the mode-line via `window-configuration-change-hook` so non-file buffers (e.g. Magit) display the correct project info. * [#1886](https://github.com/bbatsov/projectile/issues/1886): Fix `(wrong-type-argument stringp nil)` error when running project commands in a newly created project by using `projectile-acquire-root` instead of `projectile-project-root` in `projectile--run-project-cmd`. +* [#1456](https://github.com/bbatsov/projectile/issues/1456): Fix `projectile-replace-regexp` stopping when encountering a missing file by filtering nonexistent files from the replacement file list. +* [#1687](https://github.com/bbatsov/projectile/issues/1687): Fix `projectile-grep-finished-hook` not running on subsequent grep calls due to buffer rename collision. +* [#1939](https://github.com/bbatsov/projectile/issues/1939): Handle corrupted `projectile-known-projects-file` gracefully instead of crashing with `(wrong-type-argument listp ...)`. * [#1748](https://github.com/bbatsov/projectile/issues/1748): Fix `projectile-replace` falling back to the legacy Emacs 25/26 code path on Emacs 27+ because `fileloop` was not loaded. * [#1741](https://github.com/bbatsov/projectile/issues/1741): Fix `projectile-replace` treating the search string as a regexp instead of a literal string on Emacs 27+. * [#1729](https://github.com/bbatsov/projectile/issues/1729): Fix `projectile-root-top-down` to actually return the topmost matching project root instead of the bottommost. diff --git a/projectile.el b/projectile.el index 6692cff..5791b51 100644 --- a/projectile.el +++ b/projectile.el @@ -4513,7 +4513,7 @@ With REGEXP given, don't query the user for a regexp." ;; scoped to the current root to allow multiple concurrent grep ;; operations, one per root (with-current-buffer "*grep*" - (rename-buffer (concat "*grep <" root-dir ">*")))))))) + (rename-buffer (concat "*grep <" root-dir ">*") t))))))) (run-hooks 'projectile-grep-finished-hook))) ;;;###autoload @@ -5036,12 +5036,13 @@ to run the replacement." (format "Replace regexp %s with: " old-text)))) (files ;; We have to reject directories as a workaround to work with git submodules. + ;; We also reject nonexistent files to avoid errors during replacement. ;; ;; We can't narrow the list of files with ;; `projectile-files-with-string' because those regexp tools ;; don't support Emacs regular expressions. (cl-remove-if - #'file-directory-p + (lambda (f) (or (file-directory-p f) (not (file-exists-p f)))) (mapcar #'(lambda (file) (expand-file-name file directory)) (projectile-dir-files directory))))) ;; FIXME: Probably would fail on Emacs 27+, fourth argument is gone. @@ -5930,11 +5931,14 @@ Return a list of projects removed." (defun projectile-load-known-projects () "Load saved projects from `projectile-known-projects-file'. Also set `projectile-known-projects'." - (setq projectile-known-projects - (projectile-unserialize projectile-known-projects-file)) - (setq projectile-known-projects-on-file - (and (sequencep projectile-known-projects) - (copy-sequence projectile-known-projects)))) + (let ((data (projectile-unserialize projectile-known-projects-file))) + (setq projectile-known-projects + (if (and (listp data) (null (cdr (last data)))) data nil)) + (unless (equal data projectile-known-projects) + (message "Warning: Projectile known projects file was corrupted, ignoring saved data")) + (setq projectile-known-projects-on-file + (and (sequencep projectile-known-projects) + (copy-sequence projectile-known-projects))))) (defun projectile-save-known-projects () "Save PROJECTILE-KNOWN-PROJECTS to PROJECTILE-KNOWN-PROJECTS-FILE." @@ -5952,7 +5956,8 @@ overwriting each other's changes." (let* ((known-now projectile-known-projects) (known-on-last-sync projectile-known-projects-on-file) (known-on-file - (projectile-unserialize projectile-known-projects-file)) + (let ((data (projectile-unserialize projectile-known-projects-file))) + (if (and (listp data) (null (cdr (last data)))) data nil))) (removed-after-sync (projectile-difference known-on-last-sync known-now)) (removed-in-other-process (projectile-difference known-on-last-sync known-on-file)) -- cgit v1.0