* bug#46374: 28.0.50; Ask me to save buffers only if they are under callers dir
@ 2021-02-07 22:32 Tino Calancha
2021-02-08 15:07 ` Eli Zaretskii
` (3 more replies)
0 siblings, 4 replies; 44+ messages in thread
From: Tino Calancha @ 2021-02-07 22:32 UTC (permalink / raw)
To: 46374; +Cc: stefan monnier, uyennhi.qm
X-Debbugs-Cc: Stefan Monnier <monnier@iro.umontreal.ca>, <uyennhi.qm@gmail.com>
Severity: wishlist
Severity: patch
I wish, by default, to only been prompted for buffers whose default-directory
is under the caller dir (except when closing Emacs).
## Description
Everyday I connect via Tramp with machines at each of my properties (Hawaii,
Maldives, Palawan, and a very large etc.)
Then, in the same Emacs session, I connect to a host in Wall Street to see
how my stock grows, making me richer.
Often, a compilation buffer at New York city prompts me to save a buffer
at Waikiki beach. Quite distracting! Cannot focus on my money!
I found some people with related issues:
https://emacs.stackexchange.com/questions/7268/package-el-asks-whether-i-want-to-save-modified-files-before-package-installatio
https://emacs.stackexchange.com/questions/40593/automatically-dont-save-buffers-before-compiling
## How to reproduce
Sure, I understand not all of you can possibly reproduce the above conditions.
Maybe you can try the following poor man's recipe:
emacs -Q ~/foo.txt
;; write something and do not save
foo
;; now visit another, for instance, the Emacs source dir
C-x d EMACS-SRC-DIR RET
;; call rgrep with whatever string
M-x rgrep money RET *.el RET RET
;; You will be prompted to save ~/foo.txt
I am aware of `grep-save-buffers', `compilation-save-buffers-predicate' and the solutions
proposed in the links above.
My proposal adds a new option `save-some-buffers-restrict-to-caller-subdirs'.
I am already using it for a while with joy (10 bagger at GameStop using it!).
--8<-----------------------------cut here---------------start------------->8---
commit 85e5399f035fb698fcfbb50ca01980fbbc68707c
Author: Tino Calancha <ccalancha@suse.com>
Date: Thu Feb 4 21:39:37 2021 +0100
save-some-buffers: Add option restricting to files in a caller's subdir
Restrict the action to buffers with `default-directory' lying in a
subdir of the `default-directory' from where the command is invoked.
* lisp/files.el (save-some-buffers-restrict-to-caller-subdirs): New option.
(save-some-buffers)
(save-buffers-kill-emacs): Use it.
* doc/emacs/files.texi (Save Commands)
* doc/lispref/files.texi (Saving Buffers): Document it.
* etc/NEWS (Editing Changes in Emacs 28.1): Announce this change.
* lisp/progmodes/grep.el (grep-save-buffers)
* lisp/progmodes/compile.el (compilation-save-buffers-predicate):
Mention it in the docstring.
* test/lisp/files-tests.el (files-tests--save-some-buffers): Helper function.
(files-tests-with-all-permutations)
(files-tests--with-buffer-offer-save): Helper macros.
(files-tests-save-some-buffers)
(files-tests-buffer-offer-save)
(files-tests-save-buffers-kill-emacs--asks-to-save-buffers): New tests.
diff --git a/doc/emacs/files.texi b/doc/emacs/files.texi
index 6b3bc430d9..36d38218e9 100644
--- a/doc/emacs/files.texi
+++ b/doc/emacs/files.texi
@@ -433,9 +433,11 @@ Save Commands
@noindent
@vindex save-some-buffers-default-predicate
+@vindex save-some-buffers-restrict-to-caller-subdirs
You can customize the value of
-@code{save-some-buffers-default-predicate} to control which buffers
-Emacs will ask about.
+@code{save-some-buffers-default-predicate} and
+@code{save-some-buffers-restrict-to-caller-subdirs} to control which
+buffers Emacs will ask about.
@kbd{C-x C-c}, the key sequence to exit Emacs, invokes
@code{save-some-buffers} and therefore asks the same questions.
diff --git a/doc/lispref/files.texi b/doc/lispref/files.texi
index 4110c51099..a9855fef2b 100644
--- a/doc/lispref/files.texi
+++ b/doc/lispref/files.texi
@@ -371,6 +371,7 @@ Saving Buffers
querying the user.
@vindex save-some-buffers-default-predicate
+@vindex save-some-buffers-restrict-to-caller-subdirs
The optional @var{pred} argument provides a predicate that controls
which buffers to ask about (or to save silently if
@var{save-silently-p} is non-@code{nil}). If @var{pred} is
@@ -381,8 +382,12 @@ Saving Buffers
other non-file buffers---those that have a non-@code{nil} buffer-local
value of @code{buffer-offer-save} (@pxref{Killing Buffers}). A user
who says @samp{yes} to saving a non-file buffer is asked to specify
-the file name to use. The @code{save-buffers-kill-emacs} function
-passes the value @code{t} for @var{pred}.
+the file name to use. The option
+@code{save-some-buffers-restrict-to-caller-subdirs} restricts the
+action of this command to buffers with @code{default-directory} in a
+subdirectory of the caller's @code{default-directory}. The
+@code{save-buffers-kill-emacs} function ignores this option and passes
+the value @code{t} for @var{pred}.
If the predicate is neither @code{t} nor @code{nil}, then it should be
a function of no arguments. It will be called in each buffer to decide
diff --git a/etc/NEWS b/etc/NEWS
index b3d53bf73c..f1bd21f26a 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -247,6 +247,11 @@ commands. The new keystrokes are 'C-x x g' ('revert-buffer'),
\f
* Editing Changes in Emacs 28.1
++++
+** The new option 'save-some-buffers-restrict-to-caller-subdirs'
+restricts the action of 'same-some-buffers' to buffers with
+'default-directory' in a subdir of the callers 'default-directory'.
+
---
** 'eval-expression' now no longer signals an error on incomplete expressions.
Previously, typing 'M-: ( RET' would result in Emacs saying "End of
diff --git a/lisp/files.el b/lisp/files.el
index dada69c145..d51cd58217 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -5520,6 +5520,19 @@ save-some-buffers-default-predicate
:type '(choice (const :tag "Default" nil) function)
:version "26.1")
+(defcustom save-some-buffers-restrict-to-caller-subdirs nil
+ "Only save buffers under caller's default directory.
+I.e., only prompt for modified buffers whose `default-directory' is in
+in a subdir of the directory from where `save-some-buffers' is
+invoked.
+Note that `save-buffers-kill-emacs' ignores this value and prompts for
+any unsaved buffer."
+ :group 'auto-save
+ :type '(choice
+ (const :tag "All buffers" nil)
+ (const :tag "Buffers under caller's default directory" t))
+ :version "28.1")
+
(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'
@@ -5543,12 +5556,35 @@ save-some-buffers
to consider it or not when called with that buffer current.
PRED defaults to the value of `save-some-buffers-default-predicate'.
+You can restrict to modified buffers with `default-directory' under
+the caller's `default-directory' with
+`save-some-buffers-restrict-to-caller-subdirs'.
+
See `save-some-buffers-action-alist' if you want to
change the additional actions you can take on files."
(interactive "P")
- (unless pred
- (setq pred save-some-buffers-default-predicate))
- (let* ((switched-buffer nil)
+ (let* ((caller-dir default-directory)
+ (maybe-save-buffer-p
+ (lambda (buffer)
+ (or (not save-some-buffers-restrict-to-caller-subdirs)
+ (file-in-directory-p (buffer-local-value 'default-directory buffer)
+ caller-dir))))
+ (effective-pred
+ (unless (eq t pred)
+ (let ((def-pred save-some-buffers-default-predicate))
+ (lambda () (and (funcall maybe-save-buffer-p (current-buffer))
+ (if (functionp pred) (funcall pred)
+ (or (not (functionp def-pred))
+ (funcall def-pred))))))))
+ (switched-buffer nil)
+ (non-visiting-buffers-ok (not (null pred)))
+ (buffer-name-matches-filename-p
+ (lambda (buffer)
+ "Return non-nil if BUFFER name is similar to its file name."
+ (let ((file-basename (file-name-nondirectory (buffer-file-name buffer))))
+ (or (equal (buffer-name buffer) file-basename)
+ (string-match-p (format "\\<%s<[^>]*>\\'" (regexp-quote file-basename))
+ (buffer-name buffer))))))
(save-some-buffers--switch-window-callback
(lambda (buffer)
(setq switched-buffer buffer)))
@@ -5578,36 +5614,20 @@ save-some-buffers
(buffer-file-name buffer)
(with-current-buffer buffer
(or (eq buffer-offer-save 'always)
- (and pred buffer-offer-save
- (> (buffer-size) 0)))))
- (or (not (functionp pred))
- (with-current-buffer buffer (funcall pred)))
+ (and non-visiting-buffers-ok buffer-offer-save (> (buffer-size) 0)))))
+ (or (not (functionp effective-pred))
+ (with-current-buffer buffer (funcall effective-pred)))
(if arg
- t
+ (funcall maybe-save-buffer-p buffer)
(setq queried t)
- (if (buffer-file-name buffer)
- (if (or
- (equal (buffer-name buffer)
- (file-name-nondirectory
- (buffer-file-name buffer)))
- (string-match
- (concat "\\<"
- (regexp-quote
- (file-name-nondirectory
- (buffer-file-name buffer)))
- "<[^>]*>\\'")
- (buffer-name buffer)))
- ;; The buffer name is similar to the
- ;; file name.
- (format "Save file %s? "
- (buffer-file-name buffer))
- ;; The buffer and file names are
- ;; dissimilar; display both.
- (format "Save file %s (buffer %s)? "
- (buffer-file-name buffer)
- (buffer-name buffer)))
- ;; No file name
- (format "Save buffer %s? " (buffer-name buffer))))))
+ (when (funcall maybe-save-buffer-p buffer)
+ (cond ((null (buffer-file-name buffer))
+ (format "Save buffer %s? " (buffer-name buffer)))
+ ((funcall buffer-name-matches-filename-p buffer)
+ (format "Save file %s? " (buffer-file-name buffer)))
+ (t (format "Save file %s (buffer %s)? "
+ (buffer-file-name buffer)
+ (buffer-name buffer))))))))
(lambda (buffer)
(with-current-buffer buffer
(save-buffer)))
@@ -7362,7 +7382,8 @@ save-buffers-kill-emacs
(interactive "P")
;; Don't use save-some-buffers-default-predicate, because we want
;; to ask about all the buffers before killing Emacs.
- (save-some-buffers arg t)
+ (let ((save-some-buffers-restrict-to-caller-subdirs nil))
+ (save-some-buffers arg t))
(let ((confirm confirm-kill-emacs))
(and
(or (not (memq t (mapcar (lambda (buf)
diff --git a/lisp/progmodes/compile.el b/lisp/progmodes/compile.el
index 48b5ee9973..d3d3849c83 100644
--- a/lisp/progmodes/compile.el
+++ b/lisp/progmodes/compile.el
@@ -790,7 +790,10 @@ compilation-save-buffers-predicate
(string-prefix-p my-compilation-root (file-truename (buffer-file-name))))
to limit saving to files located under `my-compilation-root'.
Note, that, in general, `compilation-directory' cannot be used instead
-of `my-compilation-root' here."
+of `my-compilation-root' here.
+
+See `save-some-buffers-restrict-to-caller-subdirs' for a consistent
+way to achieve this."
:type '(choice
(const :tag "Default (save all file-visiting buffers)" nil)
(const :tag "Save all buffers" t)
diff --git a/lisp/progmodes/grep.el b/lisp/progmodes/grep.el
index d6ee8bb423..5454d47211 100644
--- a/lisp/progmodes/grep.el
+++ b/lisp/progmodes/grep.el
@@ -246,7 +246,11 @@ grep-save-buffers
buffer should be saved or not. E.g., one can set this to
(lambda ()
(string-prefix-p my-grep-root (file-truename (buffer-file-name))))
-to limit saving to files located under `my-grep-root'."
+to limit saving to files located under `my-grep-root'.
+
+Note that `my-grep-root' is only known at runtime. See
+`save-some-buffers-restrict-to-caller-subdirs' for a consistent way to
+achieve the same goal."
:version "26.1"
:type '(choice
(const :tag "Ask before saving" ask)
diff --git a/test/lisp/files-tests.el b/test/lisp/files-tests.el
index 149cc689ae..14d6bc099d 100644
--- a/test/lisp/files-tests.el
+++ b/test/lisp/files-tests.el
@@ -1432,5 +1432,206 @@ files-tests-revert-buffer-with-fine-grain
(buffer-substring (point-min) (point-max))
nil nil)))))
-(provide 'files-tests)
+(defun files-tests--save-some-buffers (pred caller-subdirs-only exp-1 exp-2)
+ "Helper function to test `save-some-buffers'.
+
+This function creates two visiting-file buffers, BUF-1, BUF-2 in
+ different directories at the same level, i.e., none of them is a
+ subdir of the other; then, it modifies both buffers; finally it calls
+ `save-some-buffers' from BUF-1 with first arg t and second arg PRED
+ and `save-some-buffers-restrict-to-caller-subdirs' let-bound to
+ CALLER-SUBDIRS-ONLY.
+
+EXP-1 and EXP-1 are the expected values of the modified flags of BUF-1
+and BUF-2 after the `save-some-buffers' call.
+
+The test is repeated with `save-some-buffers-default-predicate'
+let-bound to PRED and passing nil as second arg of
+`save-some-buffers'."
+ (let* ((dir (make-temp-file "testdir" 'dir))
+ (file-1 (expand-file-name "subdir-1/file.foo" dir))
+ (file-2 (expand-file-name "subdir-2/file.bar" dir))
+ (inhibit-message t)
+ buf-1 buf-2)
+ (unwind-protect
+ (progn
+ (make-empty-file file-1 'parens)
+ (make-empty-file file-2 'parens)
+ (setq buf-1 (find-file file-1)
+ buf-2 (find-file file-2))
+ (dolist (buf (list buf-1 buf-2))
+ (with-current-buffer buf (insert "foobar\n")))
+ ;; buf-2 is ignored if `save-some-buffers-restrict-to-caller-subdirs' is non-nil.
+ (with-current-buffer buf-1
+ (let ((save-some-buffers-restrict-to-caller-subdirs caller-subdirs-only))
+ (save-some-buffers t pred))
+ (should (eq exp-1 (buffer-modified-p buf-1)))
+ (should (eq exp-2 (buffer-modified-p buf-2))))
+
+ ;; Set both buffers as modified to repeat the test.
+ (dolist (buf (list buf-1 buf-2))
+ (with-current-buffer buf (set-buffer-modified-p t)))
+ ;; Same result with: `save-some-buffers-default-predicate' -> pred, pred -> nil.
+ (with-current-buffer buf-1
+ (let ((save-some-buffers-restrict-to-caller-subdirs caller-subdirs-only)
+ (save-some-buffers-default-predicate (and (functionp pred) pred)))
+ (save-some-buffers t nil))
+ (should (eq exp-1 (buffer-modified-p buf-1)))
+ (should (eq exp-2 (buffer-modified-p buf-2)))))
+ ;; Clean up.
+ (dolist (buf (list buf-1 buf-2))
+ (with-current-buffer buf
+ (set-buffer-modified-p nil)
+ (kill-buffer buf)))
+ (delete-directory dir 'recursive))))
+
+(ert-deftest files-tests-save-some-buffers ()
+ "Test `save-some-buffers'.
+Test the 3 cases for the second argument PRED, i.e., `nil', `t' or
+predicate."
+ (let* ((foo-file-p (lambda () (string-suffix-p ".foo" buffer-file-name)))
+ (bar-file-p (lambda () (string-suffix-p ".bar" buffer-file-name)))
+ (args-results `((nil nil nil nil)
+ (nil t nil t)
+ (,foo-file-p nil nil t)
+ (,bar-file-p nil t nil)
+ (,foo-file-p t nil t)
+ (,bar-file-p t t t)
+ (t nil nil nil)
+ (t t nil t))))
+ (pcase-dolist (`(,pred ,caller-subdirs-only ,exp-1 ,exp-2) args-results)
+ (files-tests--save-some-buffers pred caller-subdirs-only exp-1 exp-2))))
+
+(defmacro files-tests--with-buffer-offer-save (buffers-offer fn-test fn-binders args-results)
+ "Helper macro to test `save-some-buffers' and `save-buffers-kill-emacs'.
+
+This macro creates several non-visiting-file buffers in different
+ directories at the same level, i.e., none of them is a subdir of the
+ other; then, it modifies the buffers and sets `buffer-offer-save' per
+ each buffer as specified by BUFFERS-OFFER, a list of elements
+ (BUFFER OFFER-SAVE). Finally it calls FN-TEST from the first
+ buffer.
+
+FN-TEST is the function to test: either `save-some-buffers' or
+`save-buffers-kill-emacs'. This function is called with
+`save-some-buffers-restrict-to-caller-subdirs' let-bound to a value
+specified inside ARGS-RESULTS.
+
+FN-BINDERS is a list of elements (FUNCTION . BINDING), where FUNCTION
+is a function symbol that this macro temporary binds to BINDING during
+the FN-TEST call.
+ARGS-RESULTS is a list of elements (FN-ARGS CALLERS-DIR RESULTS), where
+ FN-ARGS are the arguments for FN-TEST;
+ CALLERS-DIR specify the value to let-bind
+`save-some-buffers-restrict-to-caller-subdirs';
+ RESULTS are the expected results of the test."
+ (declare (debug (form symbol form form)))
+ (let ((dir (gensym "dir"))
+ (buffers (gensym "buffers")))
+ `(let* ((,dir (make-temp-file "testdir" 'dir))
+ (inhibit-message t)
+ (use-dialog-box nil)
+ ,buffers)
+ (pcase-dolist (`(,bufsym ,offer-save) ,buffers-offer)
+ (let* ((buf (generate-new-buffer (symbol-name bufsym)))
+ (subdir (expand-file-name
+ (format "subdir-%s" (buffer-name buf))
+ ,dir)))
+ (make-directory subdir 'parens)
+ (push buf ,buffers)
+ (with-current-buffer buf
+ (cd subdir)
+ (setq buffer-offer-save offer-save)
+ (insert "foobar\n"))))
+ (setq ,buffers (nreverse ,buffers))
+
+ (let ((nb-saved-buffers 0))
+ (unwind-protect
+ (pcase-dolist (`(,fn-test-args ,callers-dir ,expected)
+ ,args-results)
+ (setq nb-saved-buffers 0)
+ (with-current-buffer (car ,buffers)
+ (cl-letf
+ (,@(mapcar (lambda (pair) `((symbol-function ,(car pair)) ,(cdr pair)))
+ fn-binders)
+ (save-some-buffers-restrict-to-caller-subdirs callers-dir))
+ (apply #',fn-test fn-test-args)
+ (should (equal nb-saved-buffers expected)))))
+ ;; Clean up.
+ (dolist (buf ,buffers)
+ (with-current-buffer buf
+ (set-buffer-modified-p nil)
+ (kill-buffer buf)))
+ (delete-directory ,dir 'recursive))))))
+
+(defmacro files-tests-with-all-permutations (permutation list &rest body)
+ "Execute BODY forms for all permutation of LIST.
+Execute the forms with the symbol PERMUTATION bound to the current
+permutation."
+ (declare (indent 2) (debug (symbol form body)))
+ (let ((vec (gensym "vec")))
+ `(let ((,vec (vconcat ,list)))
+ (cl-labels ((swap (,vec i j)
+ (let ((tmp (aref ,vec j)))
+ (aset ,vec j (aref ,vec i))
+ (aset ,vec i tmp)))
+ (permute (,vec l r)
+ (if (= l r)
+ (let ((,permutation (append ,vec nil)))
+ ,@body)
+ (cl-loop for idx from l below (1+ r) do
+ (swap ,vec idx l)
+ (permute ,vec (1+ l) r)
+ (swap ,vec idx l)))))
+ (permute ,vec 0 (1- (length ,vec)))))))
+
+(ert-deftest files-tests-buffer-offer-save ()
+ "Test `save-some-buffers'.
+Check the expected behavior for non-visiting-file buffers with
+a non-nil value of `buffer-offer-save'."
+ (let* ((buffers-offer-init '((buf-1 t) (buf-2 always) (buf-3 nil)))
+ (nb-might-save
+ (length
+ (cl-remove-if (lambda (l) (null (cadr l))) buffers-offer-init)))
+ (nb-always-save
+ (length
+ (cl-remove-if-not (lambda (l) (eq 'always (cadr l))) buffers-offer-init))))
+ (files-tests-with-all-permutations
+ buffers-offer
+ buffers-offer-init
+ (dolist (must-save `(nil t))
+ (dolist (callers-dir `(nil t))
+ (let* ((head-offer (cadar buffers-offer))
+ (res (if must-save
+ (if callers-dir (or (and head-offer 1) 0)
+ nb-might-save)
+ (if callers-dir (or (and (eq 'always head-offer) 1) 0)
+ nb-always-save)))
+ (args-res `(((nil ,must-save) ,callers-dir ,res))))
+ (files-tests--with-buffer-offer-save
+ buffers-offer
+ save-some-buffers
+ ;; Increase counter and answer 'n' when prompted to save a buffer.
+ (('read-event . (lambda () (cl-incf nb-saved-buffers) ?n)))
+ args-res)))))))
+
+(ert-deftest files-tests-save-buffers-kill-emacs--asks-to-save-buffers ()
+ "Test that `save-buffers-kill-emacs' asks to save buffers as expected."
+ (let* ((buffers-offer-init '((buf-1 t) (buf-2 always) (buf-3 nil)))
+ (nb-might-save
+ (length
+ (cl-remove-if (lambda (l) (null (cadr l))) buffers-offer-init))))
+ (files-tests-with-all-permutations
+ buffers-offer
+ buffers-offer-init
+ ;; Order doesn't matter: ask to save any buffer with non-nil `buffer-offer-save'.
+ (files-tests--with-buffer-offer-save
+ buffers-offer
+ save-buffers-kill-emacs
+ ;; Increase counter and answer 'n' when prompted to save a buffer.
+ (('read-event . (lambda () (cl-incf nb-saved-buffers) ?n))
+ ('kill-emacs . #'ignore)) ; Do not kill Emacs.
+ `((nil nil ,nb-might-save) (nil t ,nb-might-save))))))
+
+
;;; files-tests.el ends here
--8<-----------------------------cut here---------------end--------------->8---
In GNU Emacs 28.0.50 (build 2, x86_64-pc-linux-gnu, X toolkit, cairo version 1.16.0, Xaw scroll bars)
of 2021-02-07 built on localhost.example.com
Repository revision: 7c5938ad7d8884d03471e2395937e11611faadb9
Repository branch: master
Windowing system distributor 'The X.Org Foundation', version 11.0.12010000
System Description: openSUSE Tumbleweed
Configured using:
'configure --with-x-toolkit=lucid'
Configured features:
CAIRO DBUS FREETYPE GIF GLIB GMP GNUTLS GSETTINGS HARFBUZZ JPEG
LIBSELINUX LIBXML2 MODULES NOTIFY INOTIFY PDUMPER PNG SOUND THREADS TIFF
TOOLKIT_SCROLL_BARS X11 XDBE XIM XPM LUCID ZLIB
Important settings:
value of $LANG: en_US.UTF-8
value of $XMODIFIERS: @im=ibus
locale-coding-system: utf-8-unix
Major mode: Lisp Interaction
Minor modes in effect:
tooltip-mode: t
global-eldoc-mode: t
eldoc-mode: t
electric-indent-mode: t
mouse-wheel-mode: t
tool-bar-mode: t
menu-bar-mode: t
file-name-shadow-mode: t
global-font-lock-mode: t
font-lock-mode: t
blink-cursor-mode: t
auto-composition-mode: t
auto-encryption-mode: t
auto-compression-mode: t
line-number-mode: t
transient-mark-mode: t
Load-path shadows:
None found.
Features:
(shadow sort mail-extr emacsbug message rmc puny dired dired-loaddefs
rfc822 mml easymenu mml-sec epa derived epg epg-config gnus-util rmail
rmail-loaddefs auth-source cl-seq eieio eieio-core cl-macs
eieio-loaddefs password-cache json map text-property-search time-date
subr-x seq byte-opt gv bytecomp byte-compile cconv mm-decode mm-bodies
mm-encode mail-parse rfc2231 mailabbrev gmm-utils mailheader cl-loaddefs
cl-lib sendmail rfc2047 rfc2045 ietf-drums mm-util mail-prsvr mail-utils
iso-transl tooltip eldoc electric uniquify ediff-hook vc-hooks
lisp-float-type mwheel term/x-win x-win term/common-win x-dnd tool-bar
dnd fontset image regexp-opt fringe tabulated-list replace newcomment
text-mode elisp-mode lisp-mode prog-mode register page tab-bar menu-bar
rfn-eshadow isearch timer select scroll-bar mouse jit-lock font-lock
syntax facemenu font-core term/tty-colors frame minibuffer cl-generic
cham georgian utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao
korean japanese eucjp-ms cp51932 hebrew greek romanian slovak czech
european ethiopic indian cyrillic chinese composite charscript charprop
case-table epa-hook jka-cmpr-hook help simple abbrev obarray
cl-preloaded nadvice button loaddefs faces cus-face macroexp files
window text-properties overlay sha1 md5 base64 format env code-pages
mule custom widget hashtable-print-readable backquote threads dbusbind
inotify dynamic-setting system-font-setting font-render-setting cairo
x-toolkit x multi-tty make-network-process emacs)
Memory information:
((conses 16 52136 5739)
(symbols 48 6583 1)
(strings 32 19227 1884)
(string-bytes 1 625859)
(vectors 16 12486)
(vector-slots 8 169553 9399)
(floats 8 23 41)
(intervals 56 211 0)
(buffers 984 10))
^ permalink raw reply related [flat|nested] 44+ messages in thread
* bug#46374: 28.0.50; Ask me to save buffers only if they are under callers dir
2021-02-07 22:32 bug#46374: 28.0.50; Ask me to save buffers only if they are under callers dir Tino Calancha
@ 2021-02-08 15:07 ` Eli Zaretskii
2021-02-08 15:47 ` Stefan Monnier
` (2 subsequent siblings)
3 siblings, 0 replies; 44+ messages in thread
From: Eli Zaretskii @ 2021-02-08 15:07 UTC (permalink / raw)
To: Tino Calancha; +Cc: 46374, monnier, uyennhi.qm
> From: Tino Calancha <tino.calancha@gmail.com>
> Date: Sun, 07 Feb 2021 23:32:07 +0100
> Cc: stefan monnier <monnier@iro.umontreal.ca>, uyennhi.qm@gmail.com
>
>
> I wish, by default, to only been prompted for buffers whose default-directory
> is under the caller dir (except when closing Emacs).
>
> ## Description
> Everyday I connect via Tramp with machines at each of my properties (Hawaii,
> Maldives, Palawan, and a very large etc.)
> Then, in the same Emacs session, I connect to a host in Wall Street to see
> how my stock grows, making me richer.
> Often, a compilation buffer at New York city prompts me to save a buffer
> at Waikiki beach. Quite distracting! Cannot focus on my money!
>
> I found some people with related issues:
> https://emacs.stackexchange.com/questions/7268/package-el-asks-whether-i-want-to-save-modified-files-before-package-installatio
> https://emacs.stackexchange.com/questions/40593/automatically-dont-save-buffers-before-compiling
>
> ## How to reproduce
> Sure, I understand not all of you can possibly reproduce the above conditions.
> Maybe you can try the following poor man's recipe:
>
> emacs -Q ~/foo.txt
> ;; write something and do not save
> foo
> ;; now visit another, for instance, the Emacs source dir
> C-x d EMACS-SRC-DIR RET
> ;; call rgrep with whatever string
> M-x rgrep money RET *.el RET RET
> ;; You will be prompted to save ~/foo.txt
You are assuming that when save-some-buffers runs, the default
directory is the same as when you issued whatever command triggered
the call to save-some-buffers? Is that assumption really accurate?
^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#46374: 28.0.50; Ask me to save buffers only if they are under callers dir
2021-02-07 22:32 bug#46374: 28.0.50; Ask me to save buffers only if they are under callers dir Tino Calancha
2021-02-08 15:07 ` Eli Zaretskii
@ 2021-02-08 15:47 ` Stefan Monnier
2021-02-09 17:50 ` Juri Linkov
2021-08-28 16:25 ` bug#46374: Regression: erronous calls to PRED switch major-mode of unrelated modified buffers Hauke Rehfeld
3 siblings, 0 replies; 44+ messages in thread
From: Stefan Monnier @ 2021-02-08 15:47 UTC (permalink / raw)
To: Tino Calancha; +Cc: 46374, uyennhi.qm
> I wish, by default, to only been prompted for buffers whose default-directory
> is under the caller dir (except when closing Emacs).
If we want to have such a behavior and make it optional, it's fine by me.
But if we want to make it a default behavior, then I think
`project-root` would be much a much better choice (when available) than
`default-directory`.
Stefan
^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#46374: 28.0.50; Ask me to save buffers only if they are under callers dir
2021-02-07 22:32 bug#46374: 28.0.50; Ask me to save buffers only if they are under callers dir Tino Calancha
2021-02-08 15:07 ` Eli Zaretskii
2021-02-08 15:47 ` Stefan Monnier
@ 2021-02-09 17:50 ` Juri Linkov
2021-03-07 20:34 ` Tino Calancha
2021-08-28 16:25 ` bug#46374: Regression: erronous calls to PRED switch major-mode of unrelated modified buffers Hauke Rehfeld
3 siblings, 1 reply; 44+ messages in thread
From: Juri Linkov @ 2021-02-09 17:50 UTC (permalink / raw)
To: Tino Calancha; +Cc: 46374, stefan monnier, uyennhi.qm
> @vindex save-some-buffers-default-predicate
> +@vindex save-some-buffers-restrict-to-caller-subdirs
> You can customize the value of
> -@code{save-some-buffers-default-predicate} to control which buffers
> -Emacs will ask about.
> +@code{save-some-buffers-default-predicate} and
> +@code{save-some-buffers-restrict-to-caller-subdirs} to control which
> +buffers Emacs will ask about.
Why not simply add a new option to the existing variable
save-some-buffers-default-predicate? For example:
(defcustom save-some-buffers-default-predicate nil
"Default predicate for `save-some-buffers'."
:group 'auto-save
;; FIXME nil should not be a valid option, let alone the default,
;; eg so that add-function can be used.
:type '(choice (const :tag "Default" nil)
(const :tag "Subdirs of default directory" default-directory)
(const :tag "Project root" project-root)
function)
^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#46374: 28.0.50; Ask me to save buffers only if they are under callers dir
2021-02-09 17:50 ` Juri Linkov
@ 2021-03-07 20:34 ` Tino Calancha
2021-03-07 21:08 ` Juri Linkov
0 siblings, 1 reply; 44+ messages in thread
From: Tino Calancha @ 2021-03-07 20:34 UTC (permalink / raw)
To: Juri Linkov; +Cc: 46374, stefan monnier, uyennhi.qm
Sorry for the late response: many meetings with investors.
Then I went on a vacation to my castle in Seychelles.
Eli Zaretskii <eliz@gnu.org> writes:
>> You are assuming that when save-some-buffers runs, the default
>> directory is the same as when you issued whatever command triggered
>> the call to save-some-buffers? Is that assumption really accurate?
I don't know if there are some corner cases.
In my experience, I am hit by this (very often) when using packages
that call `compilation-start`. Prominent examples are `rgrep` or
when downloading ELPA updates (they will trigger a compilation as well).
The patch is serving me very well so far.
Juri Linkov <juri@linkov.net> writes:
>> @vindex save-some-buffers-default-predicategn
>> +@vindex save-some-buffers-restrict-to-caller-subdirs
>> You can customize the value of
>> -@code{save-some-buffers-default-predicate} to control which buffers
>> -Emacs will ask about.
>> +@code{save-some-buffers-default-predicate} and
>> +@code{save-some-buffers-restrict-to-caller-subdirs} to control which
>> +buffers Emacs will ask about.
>
> Why not simply add a new option to the existing variable
> save-some-buffers-default-predicate? For example:
>
> (defcustom save-some-buffers-default-predicate nil
> "Default predicate for `save-some-buffers'."
> :group 'auto-save
> ;; FIXME nil should not be a valid option, let alone the default,
> ;; eg so that add-function can be used.
> :type '(choice (const :tag "Default" nil)
> (const :tag "Subdirs of default directory" default-directory)
> (const :tag "Project root" project-root)
> function)
Indeed, this was my initial implemention.
Then I moved to the one I shared here; I found my second version
superior for the following reason:
1. Users can restrict the buffer default directory AND still pass a
predicate to filter by any other thing they wish;
i.e. you don't need to chose either one of the other.
2. I find it cleaner having it in a separated option.
Stefan Monnier <monnier@iro.umontreal.ca>
>> If we want to have such a behavior and make it optional, it's fine by me.
It's optional in my patch; some people might like the current situation:
been prompted about any modified buffer.
>> But if we want to make it a default behavior, then I think
>> `project-root` would be much a much better choice (when available) than
>> `default-directory`.
Would this `project-root` feature work for `rgrep`?
I mean, I can call `rgrep` in my local computer, out of any project, for
instance to search for information in some plain text notes. In this
case, `default-directory` works quite well.
^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#46374: 28.0.50; Ask me to save buffers only if they are under callers dir
2021-03-07 20:34 ` Tino Calancha
@ 2021-03-07 21:08 ` Juri Linkov
[not found] ` <1952f2d9-51b6-a4ba-6c9e-98594222f017@gmail.com>
0 siblings, 1 reply; 44+ messages in thread
From: Juri Linkov @ 2021-03-07 21:08 UTC (permalink / raw)
To: Tino Calancha; +Cc: 46374, stefan monnier, uyennhi.qm
> Sorry for the late response: many meetings with investors.
> Then I went on a vacation to my castle in Seychelles.
Oh, I thought you were busy running for President.
>> Why not simply add a new option to the existing variable
>> save-some-buffers-default-predicate? For example:
>>
>> (defcustom save-some-buffers-default-predicate nil
>> "Default predicate for `save-some-buffers'."
>> :group 'auto-save
>> ;; FIXME nil should not be a valid option, let alone the default,
>> ;; eg so that add-function can be used.
>> :type '(choice (const :tag "Default" nil)
>> (const :tag "Subdirs of default directory" default-directory)
>> (const :tag "Project root" project-root)
>> function)
>
> Indeed, this was my initial implemention.
> Then I moved to the one I shared here; I found my second version
> superior for the following reason:
>
> 1. Users can restrict the buffer default directory AND still pass a
> predicate to filter by any other thing they wish;
> i.e. you don't need to chose either one of the other.
>
> 2. I find it cleaner having it in a separated option.
I'm not sure if there is a need for adding
another dimension with another option.
But if yes, then still shouldn't a new option
provide a wider choice of restricting predicates
like above?
^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#46374: Regression: erronous calls to PRED switch major-mode of unrelated modified buffers
2021-02-07 22:32 bug#46374: 28.0.50; Ask me to save buffers only if they are under callers dir Tino Calancha
` (2 preceding siblings ...)
2021-02-09 17:50 ` Juri Linkov
@ 2021-08-28 16:25 ` Hauke Rehfeld
2021-08-29 16:38 ` Juri Linkov
3 siblings, 1 reply; 44+ messages in thread
From: Hauke Rehfeld @ 2021-08-28 16:25 UTC (permalink / raw)
To: 46374
Hmmm, I'm pretty sure the changes to `save-some-buffers` here
regarding the predicate indirection caused a regression and/or
very unexpected behavior that causes bugs in previously working
code.
Consider
`(save-some-buffers t (lambda () (derived-mode-p 'org-mode)))'
called from an org-mode buffer. It runs through the part of
`save-some-buffers' that is trying to resolve the PRED
indirection:
https://github.com/emacs-mirror/emacs/blob/692da8c6a82f8de376a2eec9304773b3e85205f3/lisp/files.el#L5792
``` emacs-lisp
;; Allow `pred' to be a function that returns a predicate
;; with lexical bindings in its original environment
(bug#46374).
(let ((pred-fun (and (functionp pred) (funcall pred))))
(when (functionp pred-fun)
(setq pred pred-fun)))
```
which evaluates the predicate to check if it returns a function --
which `(derived-mode-p)' does, as it simply returns the major-mode
symbol on success! In this case, it would be `#'org-mode'. So then
`org-mode' is called on any unsaved buffers as a PREDICATE,
switching those buffers to org-mode.
Compare this usage in org-mode, org.el:15357:
``` emacs-lisp
(defun org-save-all-org-buffers ()
"Save all Org buffers without user confirmation."
(interactive)
(message "Saving all Org buffers...")
(save-some-buffers t (lambda () (derived-mode-p 'org-mode)))
(when (featurep 'org-id) (org-id-locations-save))
(message "Saving all Org buffers... done"))
```
^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#46374: Regression: erronous calls to PRED switch major-mode of unrelated modified buffers
2021-08-28 16:25 ` bug#46374: Regression: erronous calls to PRED switch major-mode of unrelated modified buffers Hauke Rehfeld
@ 2021-08-29 16:38 ` Juri Linkov
2021-08-30 7:28 ` Juri Linkov
[not found] ` <jwv5yqwrgru.fsf-monnier+emacs@gnu.org>
0 siblings, 2 replies; 44+ messages in thread
From: Juri Linkov @ 2021-08-29 16:38 UTC (permalink / raw)
To: Hauke Rehfeld; +Cc: 46374, Stefan Monnier, Tino Calancha
> Hmmm, I'm pretty sure the changes to `save-some-buffers` here
> regarding the predicate indirection caused a regression and/or
> very unexpected behavior that causes bugs in previously working
> code.
Thanks, this is a very interesting case, so Cc'ing Stefan and Tino.
> Consider
>
> `(save-some-buffers t (lambda () (derived-mode-p 'org-mode)))'
>
> called from an org-mode buffer. It runs through the part of
> `save-some-buffers' that is trying to resolve the PRED
> indirection:
>
> ``` emacs-lisp
> ;; Allow `pred' to be a function that returns a predicate
> ;; with lexical bindings in its original environment
> (bug#46374).
> (let ((pred-fun (and (functionp pred) (funcall pred))))
> (when (functionp pred-fun)
> (setq pred pred-fun)))
> ```
> which evaluates the predicate to check if it returns a function --
> which `(derived-mode-p)' does, as it simply returns the major-mode
> symbol on success! In this case, it would be `#'org-mode'. So then
> `org-mode' is called on any unsaved buffers as a PREDICATE,
> switching those buffers to org-mode.
Indeed, the predicate returns a function, just to add more fun:
(funcall (lambda () (derived-mode-p 'lisp-interaction-mode)))
=> lisp-interaction-mode
This means we need to invent some ad-hoc format to distinguish between
these cases. For example, to create a lexically-bound predicate
at the beginning, it could be called with e.g.
(save-some-buffers t '(eval . save-some-buffers-root))
and defcustom will look like:
(defcustom save-some-buffers-default-predicate nil
:type '(choice (const :tag "Default" nil)
(function :tag "Only in subdirs of root"
(eval . save-some-buffers-root))
(function :tag "Custom function"))
Quite ugly, but I see no more natural way.
^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#46374: Regression: erronous calls to PRED switch major-mode of unrelated modified buffers
2021-08-29 16:38 ` Juri Linkov
@ 2021-08-30 7:28 ` Juri Linkov
2021-08-30 11:43 ` Hauke Rehfeld
2021-09-05 10:09 ` bug#46374: 28.0.50; Ask me to save buffers only if they are under callers dir Tino Calancha
[not found] ` <jwv5yqwrgru.fsf-monnier+emacs@gnu.org>
1 sibling, 2 replies; 44+ messages in thread
From: Juri Linkov @ 2021-08-30 7:28 UTC (permalink / raw)
To: Hauke Rehfeld; +Cc: 46374, Stefan Monnier, Tino Calancha
> This means we need to invent some ad-hoc format to distinguish between
> these cases. For example, to create a lexically-bound predicate
> at the beginning, it could be called with e.g.
>
> (save-some-buffers t '(eval . save-some-buffers-root))
>
> and defcustom will look like:
>
> (defcustom save-some-buffers-default-predicate nil
> :type '(choice (const :tag "Default" nil)
> (function :tag "Only in subdirs of root"
> (eval . save-some-buffers-root))
> (function :tag "Custom function"))
Or maybe simply '(save-some-buffers-root):
(defcustom save-some-buffers-default-predicate nil
:type '(choice (const :tag "Default" nil)
(function :tag "Only in subdirs of root"
(save-some-buffers-root))
Then the following two calls both will have exactly the same effect:
(save-some-buffers t '(save-some-buffers-root))
(save-some-buffers t (save-some-buffers-root))
^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#46374: Regression: erronous calls to PRED switch major-mode of unrelated modified buffers
2021-08-30 7:28 ` Juri Linkov
@ 2021-08-30 11:43 ` Hauke Rehfeld
2021-08-30 16:04 ` Hauke Rehfeld
2021-08-31 7:02 ` Juri Linkov
2021-09-05 10:09 ` bug#46374: 28.0.50; Ask me to save buffers only if they are under callers dir Tino Calancha
1 sibling, 2 replies; 44+ messages in thread
From: Hauke Rehfeld @ 2021-08-30 11:43 UTC (permalink / raw)
To: Juri Linkov; +Cc: 46374, Stefan Monnier, Tino Calancha
I'm way not deep enough into this issue, but how about using a
temp buffer and checking for major mode equivalent (can pred ever
reasonably be fundamental-mode?):
;; Allow `pred' to be a function that returns a predicate
;; with lexical bindings in its original environment
(bug#46374).
(let ((pred-fun (and (functionp pred))))
;; don't use the result of `pred' if it returns the current
buffer major-mode
(with-temp-buffer
(let ((pred-fun (funcall pred)))
(when (and (functionp pred-fun) (not (eq major-mode
pred-fun)))
(setq pred pred-fun)))))
Juri Linkov <juri@linkov.net> writes:
>> This means we need to invent some ad-hoc format to distinguish
>> between
>> these cases. For example, to create a lexically-bound
>> predicate
>> at the beginning, it could be called with e.g.
>>
>> (save-some-buffers t '(eval . save-some-buffers-root))
>>
>> and defcustom will look like:
>>
>> (defcustom save-some-buffers-default-predicate nil
>> :type '(choice (const :tag "Default" nil)
>> (function :tag "Only in subdirs of root"
>> (eval . save-some-buffers-root))
>> (function :tag "Custom function"))
>
> Or maybe simply '(save-some-buffers-root):
>
> (defcustom save-some-buffers-default-predicate nil
> :type '(choice (const :tag "Default" nil)
> (function :tag "Only in subdirs of root"
> (save-some-buffers-root))
>
> Then the following two calls both will have exactly the same
> effect:
>
> (save-some-buffers t '(save-some-buffers-root))
> (save-some-buffers t (save-some-buffers-root))
^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#46374: Regression: erronous calls to PRED switch major-mode of unrelated modified buffers
2021-08-30 11:43 ` Hauke Rehfeld
@ 2021-08-30 16:04 ` Hauke Rehfeld
2021-08-31 7:02 ` Juri Linkov
1 sibling, 0 replies; 44+ messages in thread
From: Hauke Rehfeld @ 2021-08-30 16:04 UTC (permalink / raw)
To: Juri Linkov; +Cc: 46374, Stefan Monnier, Tino Calancha
Sorry, that was broken when called with an empty `pred' argument.
This should work (but testing all code paths is indeed not a
simple task):
;; Allow `pred' to be a function that returns a predicate
;; with lexical bindings in its original environment
(bug#46374).
(when (functionp pred)
;; don't use the result of `pred' if it returns the current
buffer major-mode
(with-temp-buffer
(let ((pred-fun (funcall pred)))
(when (and (functionp pred-fun) (not (eq major-mode
pred-fun)))
(setq pred pred-fun)))))
Hauke Rehfeld <hauke@haukerehfeld.de> writes:
> I'm way not deep enough into this issue, but how about using a
> temp buffer and checking for major mode equivalent (can pred
> ever
> reasonably be fundamental-mode?):
>
> ;; Allow `pred' to be a function that returns a predicate
> ;; with lexical bindings in its original environment
> (bug#46374).
> (let ((pred-fun (and (functionp pred))))
> ;; don't use the result of `pred' if it returns the current
> buffer major-mode
> (with-temp-buffer
> (let ((pred-fun (funcall pred)))
> (when (and (functionp pred-fun) (not (eq major-mode
> pred-fun)))
> (setq pred pred-fun)))))
>
>
> Juri Linkov <juri@linkov.net> writes:
>
>>> This means we need to invent some ad-hoc format to distinguish
>>> between
>>> these cases. For example, to create a lexically-bound
>>> predicate
>>> at the beginning, it could be called with e.g.
>>>
>>> (save-some-buffers t '(eval . save-some-buffers-root))
>>>
>>> and defcustom will look like:
>>>
>>> (defcustom save-some-buffers-default-predicate nil
>>> :type '(choice (const :tag "Default" nil)
>>> (function :tag "Only in subdirs of root"
>>> (eval . save-some-buffers-root))
>>> (function :tag "Custom function"))
>>
>> Or maybe simply '(save-some-buffers-root):
>>
>> (defcustom save-some-buffers-default-predicate nil
>> :type '(choice (const :tag "Default" nil)
>> (function :tag "Only in subdirs of root"
>> (save-some-buffers-root))
>>
>> Then the following two calls both will have exactly the same
>> effect:
>>
>> (save-some-buffers t '(save-some-buffers-root))
>> (save-some-buffers t (save-some-buffers-root))
^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#46374: Regression: erronous calls to PRED switch major-mode of unrelated modified buffers
2021-08-30 11:43 ` Hauke Rehfeld
2021-08-30 16:04 ` Hauke Rehfeld
@ 2021-08-31 7:02 ` Juri Linkov
1 sibling, 0 replies; 44+ messages in thread
From: Juri Linkov @ 2021-08-31 7:02 UTC (permalink / raw)
To: Hauke Rehfeld; +Cc: 46374, Stefan Monnier, Tino Calancha
> I'm way not deep enough into this issue, but how about using a
> temp buffer and checking for major mode equivalent (can pred ever
> reasonably be fundamental-mode?):
This assumes that only derived-mode-p can be used as the predicate,
so it will fix only this particular case until some other code
will find a more clever way to circumvent this assumption
by returning some other arbitrary function that does
more nasty things than changing the major mode.
^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#46374: 28.0.50; Ask me to save buffers only if they are under callers dir
2021-08-30 7:28 ` Juri Linkov
2021-08-30 11:43 ` Hauke Rehfeld
@ 2021-09-05 10:09 ` Tino Calancha
2021-09-05 16:21 ` Juri Linkov
1 sibling, 1 reply; 44+ messages in thread
From: Tino Calancha @ 2021-09-05 10:09 UTC (permalink / raw)
To: Juri Linkov; +Cc: 46374, Hauke Rehfeld, Stefan Monnier
Juri Linkov <juri@linkov.net> writes:
>> This means we need to invent some ad-hoc format to distinguish between
>> these cases. For example, to create a lexically-bound predicate
>> at the beginning, it could be called with e.g.
>>
>> (save-some-buffers t '(eval . save-some-buffers-root))
>>
>> and defcustom will look like:
>>
>> (defcustom save-some-buffers-default-predicate nil
>> :type '(choice (const :tag "Default" nil)
>> (function :tag "Only in subdirs of root"
>> (eval . save-some-buffers-root))
>> (function :tag "Custom function"))
>
> Or maybe simply '(save-some-buffers-root):
Hi Juri!
Being able to set `save-some-buffers-root' as the value of
`save-some-buffers-default-predicate' is easy for users.
The problem I see is that it hides the real nature of `save-some-buffers-root':
- it's not a predicate (as the docstring of `save-some-buffers-default-predicate' suggests).
- it's a function generating the default predicate.
We can make the distinction (default predicate <-> func generating a default predicate)
more clear if we put the generating functions in a list.
Then, we can restrict the allowed pred-fun to the elements inside such a list.
I have played today with this quick-and-dirty patch:
How do you think?
--8<-----------------------------cut here---------------start------------->8---
diff --git a/lisp/files.el b/lisp/files.el
index 7e4bdab507..91582ec9b0 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -5731,6 +5731,13 @@ save-some-buffers-action-alist
(defvar-local buffer-save-without-query nil
"Non-nil means `save-some-buffers' should save this buffer without asking.")
+(defvar save-some-buffers-fn-generating-pred '(save-some-buffers-root)
+ "List of supported functions to generate a default predicate for `save-some-buffers'.
+Each element is a function with no arguments that returns a predicate
+suitable for `save-some-buffers'.
+You can use any of these functions as the value of
+`save-some-buffers-default-predicate'.")
+
(defcustom save-some-buffers-default-predicate nil
"Default predicate for `save-some-buffers'.
@@ -5789,7 +5796,8 @@ save-some-buffers
(setq pred save-some-buffers-default-predicate))
;; Allow `pred' to be a function that returns a predicate
;; with lexical bindings in its original environment (bug#46374).
- (let ((pred-fun (and (functionp pred) (funcall pred))))
+ (let ((pred-fun (and (memq pred save-some-buffers-fn-generating-pred)
+ (funcall pred))))
(when (functionp pred-fun)
(setq pred pred-fun)))
(let* ((switched-buffer nil)
--8<-----------------------------cut here---------------end--------------->8---
^ permalink raw reply related [flat|nested] 44+ messages in thread
* bug#46374: 28.0.50; Ask me to save buffers only if they are under callers dir
2021-09-05 10:09 ` bug#46374: 28.0.50; Ask me to save buffers only if they are under callers dir Tino Calancha
@ 2021-09-05 16:21 ` Juri Linkov
2021-10-10 17:38 ` Juri Linkov
0 siblings, 1 reply; 44+ messages in thread
From: Juri Linkov @ 2021-09-05 16:21 UTC (permalink / raw)
To: Tino Calancha; +Cc: 46374, Hauke Rehfeld, Stefan Monnier
> Being able to set `save-some-buffers-root' as the value of
> `save-some-buffers-default-predicate' is easy for users.
>
> The problem I see is that it hides the real nature of `save-some-buffers-root':
> - it's not a predicate (as the docstring of `save-some-buffers-default-predicate' suggests).
> - it's a function generating the default predicate.
>
> We can make the distinction (default predicate <-> func generating a default predicate)
> more clear if we put the generating functions in a list.
>
> Then, we can restrict the allowed pred-fun to the elements inside such a list.
>
> I have played today with this quick-and-dirty patch:
> How do you think?
Nice idea, and it's better than what I proposed.
The only change that I suggest is instead of a list,
to put a special symbol on the symbol property,
for example:
(put 'save-some-buffers-root 'higher-order-function t)
or simply
(put 'save-some-buffers-root 'hof t)
A better name is appreciated.
^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#46374: 28.0.50; Ask me to save buffers only if they are under callers dir
2021-09-05 16:21 ` Juri Linkov
@ 2021-10-10 17:38 ` Juri Linkov
0 siblings, 0 replies; 44+ messages in thread
From: Juri Linkov @ 2021-10-10 17:38 UTC (permalink / raw)
To: Tino Calancha; +Cc: 46374, Hauke Rehfeld, Stefan Monnier
close 46374 28.0.60
thanks
>> Being able to set `save-some-buffers-root' as the value of
>> `save-some-buffers-default-predicate' is easy for users.
>>
>> The problem I see is that it hides the real nature of `save-some-buffers-root':
>> - it's not a predicate (as the docstring of `save-some-buffers-default-predicate' suggests).
>> - it's a function generating the default predicate.
>>
>> We can make the distinction (default predicate <-> func generating a default predicate)
>> more clear if we put the generating functions in a list.
>>
>> Then, we can restrict the allowed pred-fun to the elements inside such a list.
>>
>> I have played today with this quick-and-dirty patch:
>> How do you think?
>
> Nice idea, and it's better than what I proposed.
> The only change that I suggest is instead of a list,
> to put a special symbol on the symbol property,
> for example:
>
> (put 'save-some-buffers-root 'higher-order-function t)
> or simply
> (put 'save-some-buffers-root 'hof t)
>
> A better name is appreciated.
I can't invent a better name than 'save-some-buffers-function'.
So now pushed with this property name.
^ permalink raw reply [flat|nested] 44+ messages in thread
[parent not found: <jwv5yqwrgru.fsf-monnier+emacs@gnu.org>]
* bug#46374: Regression: erronous calls to PRED switch major-mode of unrelated modified buffers
[not found] ` <jwv5yqwrgru.fsf-monnier+emacs@gnu.org>
@ 2022-01-06 19:09 ` Juri Linkov
2022-01-06 20:17 ` Eli Zaretskii
0 siblings, 1 reply; 44+ messages in thread
From: Juri Linkov @ 2022-01-06 19:09 UTC (permalink / raw)
To: Stefan Monnier; +Cc: 46374, Hauke Rehfeld, Tino Calancha
> It's actually easy to distinguish this specific case: when the pred is
> passed directly to `save-some-buffers` we don't need to do the "call
> PRED to get the actual predicate" dance, since the caller could just as
> well do that dance before calling us if that's what they want.
>
> IOW, the test for `save-some-buffers-function` is only needed for those
> functions that come from `save-some-buffers-default-predicate`.
>
> Any objection to the patch below (which also aligns the code closer
> with the doc since the doc of `save-some-buffers` doesn't mention the
> use of the `save-some-buffers-function` property on its `pred`
> argument).
Then this change needs to be in the release branch, so users won't start
relying on the unintended case of using of the `save-some-buffers-function`
property on the `pred` argument.
^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#46374: Regression: erronous calls to PRED switch major-mode of unrelated modified buffers
2022-01-06 19:09 ` bug#46374: Regression: erronous calls to PRED switch major-mode of unrelated modified buffers Juri Linkov
@ 2022-01-06 20:17 ` Eli Zaretskii
2022-01-06 20:28 ` Juri Linkov
0 siblings, 1 reply; 44+ messages in thread
From: Eli Zaretskii @ 2022-01-06 20:17 UTC (permalink / raw)
To: Juri Linkov; +Cc: 46374, hauke, monnier, tino.calancha
> From: Juri Linkov <juri@linkov.net>
> Date: Thu, 06 Jan 2022 21:09:47 +0200
> Cc: 46374@debbugs.gnu.org, Hauke Rehfeld <hauke@haukerehfeld.de>,
> Tino Calancha <tino.calancha@gmail.com>
>
> > It's actually easy to distinguish this specific case: when the pred is
> > passed directly to `save-some-buffers` we don't need to do the "call
> > PRED to get the actual predicate" dance, since the caller could just as
> > well do that dance before calling us if that's what they want.
> >
> > IOW, the test for `save-some-buffers-function` is only needed for those
> > functions that come from `save-some-buffers-default-predicate`.
> >
> > Any objection to the patch below (which also aligns the code closer
> > with the doc since the doc of `save-some-buffers` doesn't mention the
> > use of the `save-some-buffers-function` property on its `pred`
> > argument).
>
> Then this change needs to be in the release branch, so users won't start
> relying on the unintended case of using of the `save-some-buffers-function`
> property on the `pred` argument.
I don't see the message to which you are responding, so I cannot tell
whether the patch you have in mind is appropriate for the release
branch.
^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#46374: Regression: erronous calls to PRED switch major-mode of unrelated modified buffers
2022-01-06 20:17 ` Eli Zaretskii
@ 2022-01-06 20:28 ` Juri Linkov
2022-01-07 14:45 ` Eli Zaretskii
0 siblings, 1 reply; 44+ messages in thread
From: Juri Linkov @ 2022-01-06 20:28 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: 46374, hauke, monnier, tino.calancha
>> Then this change needs to be in the release branch, so users won't start
>> relying on the unintended case of using of the `save-some-buffers-function`
>> property on the `pred` argument.
>
> I don't see the message to which you are responding, so I cannot tell
> whether the patch you have in mind is appropriate for the release
> branch.
Oh, it was archived, so here is a copy:
> It's actually easy to distinguish this specific case: when the pred is
> passed directly to `save-some-buffers` we don't need to do the "call
> PRED to get the actual predicate" dance, since the caller could just as
> well do that dance before calling us if that's what they want.
>
> IOW, the test for `save-some-buffers-function` is only needed for those
> functions that come from `save-some-buffers-default-predicate`.
>
> Any objection to the patch below (which also aligns the code closer
> with the doc since the doc of `save-some-buffers` doesn't mention the
> use of the `save-some-buffers-function` property on its `pred`
> argument).
>
>
> Stefan
>
>
> diff --git a/lisp/files.el b/lisp/files.el
> index a11786fca2c..cd43b94622e 100644
> --- a/lisp/files.el
> +++ b/lisp/files.el
> @@ -5799,7 +5799,7 @@ save-some-buffers-default-predicate
> ;; FIXME nil should not be a valid option, let alone the default,
> ;; eg so that add-function can be used.
> :type '(choice (const :tag "Default" nil)
> - (function :tag "Only in subdirs of root"
> + (function :tag "Only in subdirs of current project"
> save-some-buffers-root)
> (function :tag "Custom function"))
> :version "26.1")
> @@ -5835,21 +5835,22 @@ save-some-buffers
> Optional second argument PRED determines which buffers are considered:
> If PRED is nil, all the file-visiting buffers are considered.
> If PRED is t, then certain non-file buffers will also be considered.
> -If PRED is a zero-argument function, it indicates for each buffer whether
> -to consider it or not when called with that buffer current.
> +If PRED is a function, it is called with no argument in each buffer and
> +should return non-nil if that buffer should be considered.
> PRED defaults to the value of `save-some-buffers-default-predicate'.
>
> See `save-some-buffers-action-alist' if you want to
> change the additional actions you can take on files."
> (interactive "P")
> (unless pred
> - (setq pred save-some-buffers-default-predicate))
> - ;; Allow `pred' to be a function that returns a predicate
> - ;; with lexical bindings in its original environment (bug#46374).
> - (when (and (symbolp pred) (get pred 'save-some-buffers-function))
> - (let ((pred-fun (and (functionp pred) (funcall pred))))
> - (when (functionp pred-fun)
> - (setq pred pred-fun))))
> + (setq pred
> + ;; Allow `pred' to be a function that returns a predicate
> + ;; with lexical bindings in its original environment (bug#46374).
> + (if (and (symbolp save-some-buffers-default-predicate)
> + (get save-some-buffers-default-predicate
> + 'save-some-buffers-function))
> + (funcall save-some-buffers-default-predicate)
> + save-some-buffers-default-predicate)))
> (let* ((switched-buffer nil)
> (save-some-buffers--switch-window-callback
> (lambda (buffer)
^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#46374: Regression: erronous calls to PRED switch major-mode of unrelated modified buffers
2022-01-06 20:28 ` Juri Linkov
@ 2022-01-07 14:45 ` Eli Zaretskii
2022-01-10 3:18 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
0 siblings, 1 reply; 44+ messages in thread
From: Eli Zaretskii @ 2022-01-07 14:45 UTC (permalink / raw)
To: Juri Linkov; +Cc: 46374, hauke, monnier, tino.calancha
> From: Juri Linkov <juri@linkov.net>
> Cc: monnier@iro.umontreal.ca, 46374@debbugs.gnu.org,
> hauke@haukerehfeld.de, tino.calancha@gmail.com
> Date: Thu, 06 Jan 2022 22:28:02 +0200
>
> >> Then this change needs to be in the release branch, so users won't start
> >> relying on the unintended case of using of the `save-some-buffers-function`
> >> property on the `pred` argument.
> >
> > I don't see the message to which you are responding, so I cannot tell
> > whether the patch you have in mind is appropriate for the release
> > branch.
>
> Oh, it was archived, so here is a copy:
Thanks. This is okay for the release branch.
^ permalink raw reply [flat|nested] 44+ messages in thread
end of thread, other threads:[~2022-01-10 3:18 UTC | newest]
Thread overview: 44+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-02-07 22:32 bug#46374: 28.0.50; Ask me to save buffers only if they are under callers dir Tino Calancha
2021-02-08 15:07 ` Eli Zaretskii
2021-02-08 15:47 ` Stefan Monnier
2021-02-09 17:50 ` Juri Linkov
2021-03-07 20:34 ` Tino Calancha
2021-03-07 21:08 ` Juri Linkov
[not found] ` <1952f2d9-51b6-a4ba-6c9e-98594222f017@gmail.com>
2021-03-08 17:28 ` Juri Linkov
2021-03-14 12:17 ` Tino Calancha
2021-03-15 17:10 ` Juri Linkov
2021-03-16 17:49 ` Juri Linkov
2021-03-16 22:54 ` Stefan Monnier
2021-03-16 23:37 ` bug#46374: [External] : " Drew Adams
2021-03-17 17:12 ` Juri Linkov
2021-03-17 17:10 ` Juri Linkov
2021-03-21 17:59 ` Tino Calancha
2021-03-21 20:10 ` Juri Linkov
2021-04-18 14:27 ` Tino Calancha
2021-04-24 22:13 ` Juri Linkov
2021-04-28 19:31 ` Tino Calancha
2021-04-28 19:51 ` Juri Linkov
2021-04-28 20:35 ` Tino Calancha
2021-04-29 9:17 ` Eli Zaretskii
2021-05-18 17:46 ` Tino Calancha
2021-04-29 16:04 ` Juri Linkov
[not found] ` <82abe5b9-7d42-b05d-26a5-fd63e1f59e3a@gmail.com>
2021-08-13 7:11 ` Juri Linkov
[not found] ` <3c7dc42a-e484-8068-d28d-49677f0b4a7@gmail.com>
2021-08-13 16:08 ` Juri Linkov
2021-04-29 9:16 ` Eli Zaretskii
2021-05-18 18:04 ` Tino Calancha
2021-05-18 18:23 ` Eli Zaretskii
2021-05-18 18:47 ` Tino Calancha
2021-08-28 16:25 ` bug#46374: Regression: erronous calls to PRED switch major-mode of unrelated modified buffers Hauke Rehfeld
2021-08-29 16:38 ` Juri Linkov
2021-08-30 7:28 ` Juri Linkov
2021-08-30 11:43 ` Hauke Rehfeld
2021-08-30 16:04 ` Hauke Rehfeld
2021-08-31 7:02 ` Juri Linkov
2021-09-05 10:09 ` bug#46374: 28.0.50; Ask me to save buffers only if they are under callers dir Tino Calancha
2021-09-05 16:21 ` Juri Linkov
2021-10-10 17:38 ` Juri Linkov
[not found] ` <jwv5yqwrgru.fsf-monnier+emacs@gnu.org>
2022-01-06 19:09 ` bug#46374: Regression: erronous calls to PRED switch major-mode of unrelated modified buffers Juri Linkov
2022-01-06 20:17 ` Eli Zaretskii
2022-01-06 20:28 ` Juri Linkov
2022-01-07 14:45 ` Eli Zaretskii
2022-01-10 3:18 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).