Subject: bug#58839: [Patch] Re: bug#58839: 29.0.50; project-kill-buffer fails when Eglot is running

From: Dmitry Gutov <[email-masked]>
Date: Mon, 31 Oct 2022 19:24:02 +0200

On 31.10.2022 11:53, João Távora wrote:
> Dmitry Gutov <[email-masked]> writes:
> 
>> Anyway, if we do decide to flip the switch, it should be through
>> project-kill-buffer-conditions, so the user can make a different
>> choice through customization.
> 
> project-kill-buffer-conditions doesn't work, I've tried it, it has this
> fundamental-mode thing there that makes it impossible.  Supposedly it is
> there to serve some purpose that no-one seems to be able to find a
> argumentative basis for.

What have you tried?

This should take care of the specific complaint about unknown 
"invisible" buffers:

diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el
index ac278edd40..1e7573c740 100644
--- a/lisp/progmodes/project.el
+++ b/lisp/progmodes/project.el
@@ -1223,7 +1223,9 @@ project-display-buffer-other-frame
  (defcustom project-kill-buffer-conditions
    '(buffer-file-name    ; All file-visiting buffers are included.
      ;; Most of the temp buffers in the background:
-    (major-mode . fundamental-mode)
+    (and
+     (major-mode . fundamental-mode)
+     (not "\\` "))
      ;; non-text buffer such as xref, occur, vc, log, ...
      (and (derived-mode . special-mode)
           (not (major-mode . help-mode)))

> It's quite clear that _some_ non-file-visiting buffers can be considered
> as belonging to a project's working set.  But it's very very easy to
> come up with many that cannot be considered so.
> 
> Because "killing buffers" is a destructive operation, being greedy here
> is a really bad design decision, as it catches an arbitrary number of
> unsuspecting extensions off-guard, which have been using earmuffed
> buffers for many years.
> 
> All in all, it's like you're making a gun that only backfires 5% of the
> time.

Yours is the first instance so far.

> In the little time I've used this feature since the start of this
> discussion I have discovered it backfires no small number of occasions:
> Eglot, CIDER, *scratch*, *ielm*, *sly-scratch*, *Completions*,...  Heck
> even *ibuffer* itself is targeted by this.

Of course it is targeted: we want ibuffer buffers to be killed just as 
well when killing a project. And sly-scratch, and etc.

> Project-kill-buffers is off. Its intention pretty useful, but its
> implementation is a blunder.  The root cause is this overgreedy
> project-buffers.  When "killing a project" the echo area asks me if I
> want to kill a number of buffers that I didn't even know I had, because
> of hidden buffers.  This cannot be logical and the only way the
> "argument can be made both ways" is out of stubborness.
> 
> JSONRPC's buffers are hidden implementation details: the argument that
> they are somehow under the responsibility of project.el just because it
> can see them through (buffer-list) is blind tiranny.
> 
> The mini-languages invented in project-kill-buffers-conditions and
> project-ignore-buffer-conditions are abominations.

This is the point where I'd normally blacklist you again.

> diff --git a/lisp/vc/vc-dispatcher.el b/lisp/vc/vc-dispatcher.el
> index dc3ed52650..718bebc7cd 100644
> --- a/lisp/vc/vc-dispatcher.el
> +++ b/lisp/vc/vc-dispatcher.el
> @@ -179,6 +179,7 @@ vc-setup-buffer
>     (let ((camefrom (current-buffer))
>   	(olddir default-directory))
>       (set-buffer (get-buffer-create buf))
> +    (setq-local project-owned t)
>       (let ((oldproc (get-buffer-process (current-buffer))))
>         ;; If we wanted to wait for oldproc to finish before doing
>         ;; something, we'd have used vc-eval-after.
> 
> To name one.  The above is just the converse of the solution proposed by
> Philip before.
> 
> Anyway, I've now suggested and presented 2 actually tested, actually
> working patches to project.el.  I don't have anything more to add.

They are not much better than the "patch" I showed for Eglot, 
correctness-wise.

And mine would make it safe against any kill-buffer calls, including 
ones issued by the user.