diff --git a/CHANGELOG.md b/CHANGELOG.md index de67a8ab..5d573bc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ * [#1877](https://github.com/bbatsov/projectile/pull/1877): Add custom variable `projectile-cmd-hist-ignoredups`. * Add support for Eask projects. * [#1892](https://github.com/bbatsov/projectile/pull/1892): Add category metadata to `completing-read`. (it's used by packages like `marginalia` and `embark`) +* [#1895](https://github.com/bbatsov/projectile/pull/1895): Modify projectile-mode to add a hook to `buffer-list-update-hook` such that any change in the buffer list will update the selected project. ### Bugs fixed diff --git a/projectile.el b/projectile.el index f581fc6c..31a970d3 100644 --- a/projectile.el +++ b/projectile.el @@ -6284,14 +6284,24 @@ Otherwise behave as if called interactively. (projectile-discover-projects-in-search-path)) (add-hook 'project-find-functions #'project-projectile) (add-hook 'find-file-hook 'projectile-find-file-hook-function) - (add-hook 'projectile-find-dir-hook #'projectile-track-known-projects-find-file-hook t) - (add-hook 'dired-before-readin-hook #'projectile-track-known-projects-find-file-hook t t) + ;; Add hooks to track which buffer is currently active. + ;; Note - In Emacs 28.1 `buffer-list-update-hook' was modified to no + ;; longer run on temporary buffers, this allows us to use it to track + ;; changes to the active buffer instead of relying on more specific hooks + ;; such as `dired-before-readin-hook'. + (if (version<= "28.1" emacs-version) + (add-hook 'buffer-list-update-hook #'projectile-track-known-projects-find-file-hook t) + (add-hook 'projectile-find-dir-hook #'projectile-track-known-projects-find-file-hook t) + (add-hook 'dired-before-readin-hook #'projectile-track-known-projects-find-file-hook t t)) + (advice-add 'compilation-find-file :around #'compilation-find-file-projectile-find-compilation-buffer) (advice-add 'delete-file :before #'delete-file-projectile-remove-from-cache)) (t (remove-hook 'project-find-functions #'project-projectile) (remove-hook 'find-file-hook #'projectile-find-file-hook-function) - (remove-hook 'dired-before-readin-hook #'projectile-track-known-projects-find-file-hook t) + (if (version<= "28.1" emacs-version) + (remove-hook 'buffer-list-update-hook #'projectile-track-known-projects-find-file-hook) + (remove-hook 'dired-before-readin-hook #'projectile-track-known-projects-find-file-hook t)) (advice-remove 'compilation-find-file #'compilation-find-file-projectile-find-compilation-buffer) (advice-remove 'delete-file #'delete-file-projectile-remove-from-cache)))) diff --git a/test/projectile-test.el b/test/projectile-test.el index 1ae331d6..c1084135 100644 --- a/test/projectile-test.el +++ b/test/projectile-test.el @@ -1957,6 +1957,40 @@ projectile-process-current-project-buffers-current to have similar behaviour" (with-current-buffer (find-file-noselect "foo" t)) (expect (length (projectile-project-buffers)) :to-equal 1))))) +(describe "projectile-mode buffer-list-update-hook" + (it "check that the hooks properly update the known projects when changing files or windows" + (projectile-test-with-sandbox + (projectile-test-with-files + ("project1/" + "project1/.projectile" + "project1/foo" + "project2/" + "project2/.projectile" + "project2/bar") + (find-file "project1/") + (projectile-mode 1) + + ;; Check that opening a file leads to the known-projects being updated + (find-file "project1/foo") + (expect (mapcar (lambda (x) (file-name-base (directory-file-name x))) projectile-known-projects) + :to-equal '("project1")) + + ;; Check that opening a file in a different project leads to the known-projects being updated + (find-file-other-window "../../project2/bar") + (expect (mapcar (lambda (x) (file-name-base (directory-file-name x))) projectile-known-projects) + :to-equal '("project2" "project1")) + + ;; Check that selecting a different buffer also updates the known-projects + (other-window 1) + (expect (mapcar (lambda (x) (file-name-base (directory-file-name x))) projectile-known-projects) + ;; Sadly this behavior is contigent on the existance of + ;; `buffer-list-update-hook' so it will behave + ;; differently on older versions of Emacs that do not + ;; have this variable. + :to-equal (if (version<= "28.1" emacs-version) + '("project1" "project2") + '("project2" "project1"))))))) + (describe "projectile--impl-name-for-test-name" :var ((mock-projectile-project-types '((foo test-suffix "Test")