projectile icon indicating copy to clipboard operation
projectile copied to clipboard

Projects remain open after running `projectile-kill-buffers`

Open jtherrmann opened this issue 6 years ago • 2 comments

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)

jtherrmann avatar Dec 17 '19 01:12 jtherrmann

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!

stale[bot] avatar Jun 14 '20 01:06 stale[bot]

This is still reproducible with the latest version

azzamsa avatar Aug 26 '20 01:08 azzamsa