Subject: Re: bug#46374: 28.0.50; Ask me to save buffers only if they are under callers dir

From: Tino Calancha <[email-masked]>
Date: Sun, 21 Mar 2021 18:59:04 +0100

Juri Linkov <[email-masked]> writes:

>> How 'bout using something like `isearch-search-fun-function`:
>> i.e. *compute* the predicate by calling
>> save-some-buffers-predicate-function, so this function can return
>> a predicate that remembers the default-dir of the original buffer (or
>> any other aspect relevant to the state from which we started the
>> save-some-buffers).
>
> This should work.  Then in save-some-buffers it's possible
> to add after the existing 2 lines:
>
>   (unless pred
>     (setq pred save-some-buffers-default-predicate))
>
> only 3 additional lines:
>
>   (let ((pred-fun (and (functionp pred) (funcall pred))))
>     (when (functionp pred-fun)
>       (setq pred pred-fun)))
>
> Then a pred function could contain something like:
>
>   (lambda ()
>     (let ((project-dir (or (project-root (project-current)) default-directory)))
>       (lambda () (file-in-directory-p default-directory project-dir))))

Thanks Juri and Stefan; it looks more general now.

I have noticed that I haven't enabled lexical-binding in my .emacs file,
which it is crucial for my use case.
To avoid surprises, I have mentioned this issue in the docstring.

--8<-----------------------------cut here---------------start------------->8---
diff --git a/lisp/files.el b/lisp/files.el
index dada69c145..e87fbe9599 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -5520,6 +5520,28 @@ save-some-buffers-default-predicate
   :type '(choice (const :tag "Default" nil) function)
   :version "26.1")
 
+(defvar save-some-buffers-fun-function (lambda () save-some-buffers-default-predicate)
+  "Overrides the behavior of `save-some-buffers-default-predicate'.
+This variable's value should be a function, which will be called
+by `save-some-buffers' with no arguments to override the default predicate.
+This allow you to capture variables in the environment of `save-some-buffers',
+and use them to decide which buffers must be saved.
+For instance, the following expression restricts to save only buffers inside
+the project from where `save-some-buffers' is invoked, or under the
+caller's `default-directory' if no project is found:
+
+\(lambda ()
+  (let ((project-dir
+         (or (and (project-current) (project-root (project-current)))
+             default-directory)))
+    (lambda () (file-in-directory-p default-directory project-dir))))
+
+Note that, the example above requires that you evaluate this expression
+in a file or buffer with lexical binding enabled.")
+
+(defun save-some-buffers-fun ()
+  (funcall save-some-buffers-fun-function))
+
 (defun save-some-buffers (&optional arg pred)
   "Save some modified file-visiting buffers.  Asks user about each one.
 You can answer `y' or SPC to save, `n' or DEL not to save, `C-r'
@@ -5547,8 +5569,17 @@ save-some-buffers
 change the additional actions you can take on files."
   (interactive "P")
   (unless pred
-    (setq pred save-some-buffers-default-predicate))
+    (setq pred (save-some-buffers-fun)))
+

--8<-----------------------------cut here---------------end--------------->8---