branch: externals/bufferlo
commit 140c6a951e5cf6ad753ad2827fc1e1a0648f47f8
Author: shipmints <shipmi...@gmail.com>
Commit: shipmints <shipmi...@gmail.com>

    Fix bufferlo-delete-frame-kill-buffers, add 
bufferlo-kill-modified-buffers-policy
    
    bufferlo-delete-frame-kill-buffers was erroneously deleting the
    current frame after kill-buffer had already killed the target frame as
    a side effect of it calling replace-buffer-in-windows.
    
    The option bufferlo-kill-modified-buffers-policy gives people control
    over default Emacs buffer killing prompts, ignoring modified buffers,
    or indiscriminately killing changed buffers and those with active
    processes such as *shell* buffers.
---
 bufferlo.el | 82 ++++++++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 60 insertions(+), 22 deletions(-)

diff --git a/bufferlo.el b/bufferlo.el
index 25d6dc5c7a..363d7ccc98 100644
--- a/bufferlo.el
+++ b/bufferlo.el
@@ -126,6 +126,25 @@ This is a list of regular expressions that match buffer 
names."
   "If non-nil, confirm before killing local or orphan buffers."
   :type 'boolean)
 
+(defcustom bufferlo-kill-modified-buffers-policy 'kill-modified
+  "Bufferlo behavior when killing modified or process buffers.
+
+This policy is useful when `shell-mode' or `eshell-mode' buffers
+are active in a bufferlo-controlled frame or tab.
+
+nil means default Emacs behavior which may prompt. This may have
+side effects when killing frames.
+
+\\='ignore-modified means bufferlo will leave modified buffers as
+is.
+
+\\='kill-modified instructs bufferlo to kill modified buffers
+without remorse including those with running processes such as
+`shell-mode' buffers."
+  :type '(radio (const :tag "Do not kill modified buffers" ignore-modified)
+                (const :tag "Kill modified buffers without prompting" 
kill-modified)
+                (const :tag "Default Emacs behavior (will prompt)" nil)))
+
 (defcustom bufferlo-bookmark-prefer-saveplace-point nil
   "If non-nil, and `save-place-mode' mode is on, inhibit point in bookmarks."
   :type 'boolean)
@@ -1193,6 +1212,19 @@ If INVERT is non-nil, return the non-exclusive buffers 
instead."
                   (lambda (b) (not (memq b other-bufs))))
                 this-bufs)))
 
+(defun bufferlo--kill-buffer (buffer)
+  "Kill BUFFER respecting `bufferlo-kill-modified-buffers-policy'."
+  (pcase bufferlo-kill-modified-buffers-policy
+    ('ignore-modified
+     (unless (buffer-modified-p buffer)
+       (kill-buffer buffer)))
+    ('kill-modified
+     (let ((kill-buffer-query-functions nil))
+       (with-current-buffer buffer
+       (set-buffer-modified-p nil)
+       (kill-buffer))))
+    (_ (kill-buffer buffer))))
+
 (defun bufferlo-kill-buffers (&optional killall frame tabnum internal-too)
   "Kill the buffers of the frame/tab-local buffer list.
 By default, this will only kill buffers that are exclusive to the frame/tab.
@@ -1223,7 +1255,7 @@ argument INTERNAL-TOO is non-nil."
                                (string-match-p exclude (buffer-name b)))))
                        kill-list)))
         (dolist (b buffers)
-          (kill-buffer b))))))
+          (bufferlo--kill-buffer b))))))
 
 (defun bufferlo-kill-orphan-buffers (&optional internal-too)
   "Kill all buffers that are not in any local list of a frame or tab.
@@ -1246,7 +1278,7 @@ Buffers matching `bufferlo-kill-buffers-exclude-filters' 
are never killed."
                                (string-match-p exclude (buffer-name b)))))
                        (bufferlo--get-orphan-buffers))))
         (dolist (b buffers)
-          (kill-buffer b))))))
+          (bufferlo--kill-buffer b))))))
 
 (defun bufferlo-delete-frame-kill-buffers (&optional frame internal-too)
   "Delete a frame and kill the local buffers of its tabs.
@@ -1256,25 +1288,31 @@ argument INTERNAL-TOO is non-nil."
   (interactive)
   (bufferlo--warn)
   (let ((kill t)
-        (fbm (frame-parameter nil 'bufferlo-bookmark-frame-name)))
-    (when (and fbm
-               bufferlo-delete-frame-kill-buffers-save-bookmark-prompt)
-      (when (y-or-n-p
-             (concat "Save frame bookmark \"" fbm "\"? "))
-        (bufferlo-bookmark-frame-save-current)))
-    (when bufferlo-delete-frame-kill-buffers-prompt
-      (setq kill (y-or-n-p "Kill frame and its buffers? ")))
-    (when kill
-      (raise-frame frame) ; if called in a batch, raise frame in case of 
prompts for buffers that need saving
-      (bufferlo-kill-buffers nil frame 'all internal-too)
-      ;; TODO: Emacs 30 frame-deletable-p
-      ;; account for top-level, non-child frames
-      (setq frame (or frame (selected-frame)))
-      (when (= 1 (length (seq-filter
-                          (lambda (x) (null (frame-parameter x 'parent-frame)))
-                          (frame-list))))
-        (make-frame)) ; leave one for the user
-      (delete-frame frame))))
+        (frame (or frame (selected-frame))))
+    (let ((fbm (frame-parameter frame 'bufferlo-bookmark-frame-name)))
+      (when (and fbm
+                 bufferlo-delete-frame-kill-buffers-save-bookmark-prompt)
+        (when (y-or-n-p
+               (concat "Save frame bookmark \"" fbm "\"? "))
+          (with-selected-frame frame ; needed if called in a batch
+            (bufferlo-bookmark-frame-save-current))))
+      (when bufferlo-delete-frame-kill-buffers-prompt
+        (setq kill (y-or-n-p "Kill frame and its buffers? ")))
+      (when kill
+        ;; If batch, raise frame in case of prompts for buffers that need 
saving.
+        (raise-frame frame)
+        ;; kill-buffer calls replace-buffer-in-windows which will
+        ;; delete windows *and* their frame so we have to test if
+        ;; the frame in question is still live.
+        (bufferlo-kill-buffers nil frame 'all internal-too)
+        (when (frame-live-p frame)
+          ;; TODO: Emacs 30 frame-deletable-p
+          ;; account for top-level, non-child frames
+          (when (= 1 (length (seq-filter
+                              (lambda (x) (null (frame-parameter x 
'parent-frame)))
+                              (frame-list))))
+            (make-frame)) ; leave one for the user
+          (delete-frame frame))))))
 
 (defun bufferlo-tab-close-kill-buffers (&optional killall internal-too)
   "Close the current tab and kill the local buffers.
@@ -1817,7 +1855,7 @@ this bookmark is embedded in a frame bookmark."
              (unless (consp current-prefix-arg) ; user new tab suppression
                (tab-bar-new-tab-to))))))
       (let* ((ws (copy-tree (alist-get 'window bookmark)))
-             (dummy (generate-new-buffer " *bufferlo dummy buffer*")) ; TODO: 
needs unwind-protect or make-finalizer?
+             (dummy (generate-new-buffer " *bufferlo dummy buffer*")) ; TODO: 
needs unwind-protect or make-finalizer or with-temp-buffer?
              (renamed
               (mapcar
                (lambda (bm)

Reply via email to