Projects remain open after running `projectile-kill-buffers`
Expected behavior
After running projectile-kill-buffers on a project, with projectile-kill-buffers-filter set to kill-all, I should no longer see the project when I run projectile-switch-open-project, and the list returned by projectile-open-projects should no longer include the project.
For context, here are the docs for projectile-open-projects:
Return a list of all open projects. An open project is a project with any open buffers.
Therefore, if we kill all of a project's buffers, the project should no longer be considered open.
Actual behavior
Often, after running projectile-kill-buffers, the project still appears when running projectile-switch-open-project and is included in the list returned by projectile-open-projects.
From reviewing the source code, I believe this happens for the following reasons:
projectile-open-projects returns a list of open projects, where an open project is a project with at least one buffer in (buffer-list). See https://github.com/bbatsov/projectile/blob/master/projectile.el#L3994 for exactly how projectile-open-projects builds a list of open projects from (buffer-list). It does not appear to do any filtering on the buffer list.
projectile-kill-buffers kills the current project's buffers, using the buffer list given by (projectile-project-buffers). But (projectile-project-buffers) doesn't necessarily contain all of the project's buffers from (buffer-list), because it filters the buffers according to projectile-project-buffer-p.
For example, I often see projects that are considered to be open because of the existence of a single #<buffer *which-key*> associated with the project. Buffer names with a leading space are filtered out by projectile-project-buffer-p, so are not killed by projectile-kill-buffers, but they are not filtered out when projectile-open-projects builds a list of open projects from (buffer-list).
This is my current workaround:
(defun projectile-open-projects-wrapper (orig-fun &rest args)
(-filter (lambda (project-root)
(projectile-project-buffers (expand-file-name project-root)))
(apply orig-fun args)))
(advice-add 'projectile-open-projects
:around #'projectile-open-projects-wrapper)
which simply takes the list of projects returned by projectile-open-projects and filters out the ones that don't have any buffers according to projectile-project-buffers.
I considered implementing a better solution and making a PR, but when I started really digging through the source code, I started to realize that the more fundamental problem is that there are so many different ways to tell if a buffer is in a project. projectile-project-root, projectile-project-buffer-p, projectile-project-buffers, projectile-open-projects, etc. all treat this differently. As far as I can tell, there is no single, authoritative function for determining whether a given buffer really belongs to a particular project. So I am going to continue using my workaround for now, and hopefully open this issue up for discussion so that people more familiar with the project can decide what the best solution is.
Steps to reproduce the problem
Open a project with projectile-switch-project. Then within the project, evaluate some expressions in the minibuffer and run some key sequences to trigger which-key (if installed). Then run projectile-kill-buffers and then confirm that the project still appears when running projectile-switch-open-project.
I believe this function that I wrote will return the complete list of buffers associated with a project, using a similar method to the one used by projectile-open-projects:
(defun all-buffers-for-project (project-path)
(-filter (lambda (buffer)
(string-equal
(with-current-buffer buffer (projectile-project-root))
project-path))
(buffer-list)))
After running projectile-kill-buffers, the above function can be used to determine which buffers were not killed because they were filtered by projectile-project-buffer-p, including globally ignored buffers and buffers whose names have a leading space.
Environment & Version information
Projectile version information
Projectile 2.1.0snapshot
Using the latest commit https://github.com/bbatsov/projectile/commit/0f5018fd7e7b3a1d224d3aa96edff0b40306e79f
Emacs version
26.1 (built from source)
Operating system
Debian 9 (stretch)
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contribution and understanding!
This is still reproducible with the latest version