aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Mendler <mail@daniel-mendler.de>2025-03-07 16:58:10 +0100
committerDaniel Mendler <mail@daniel-mendler.de>2025-03-07 17:13:26 +0100
commite5204b0807c987d4a7b1a9441158b80a3407b675 (patch)
treee295ccb1c9494af403b26f91d56844b1a10813e1
parentc833f2edcb68466bef53a6ea104371a26d6bc0c8 (diff)
compat-31: New macro with-work-buffer
-rw-r--r--NEWS.org1
-rw-r--r--compat-31.el54
-rw-r--r--compat-tests.el9
-rw-r--r--compat.texi7
4 files changed, 71 insertions, 0 deletions
diff --git a/NEWS.org b/NEWS.org
index 31b180e..10f4563 100644
--- a/NEWS.org
+++ b/NEWS.org
@@ -9,6 +9,7 @@
- compat-31: New macros =incf= and =decf=.
- compat-31: New function =color-blend=.
- compat-31: New function =completion-table-with-metadata=.
+- compat-31: New macro =with-work-buffer=.
- Drop support for Emacs 24.x. Emacs 25.1 is required now. In case
Emacs 24.x support is still needed, Compat 30 can be used.
diff --git a/compat-31.el b/compat-31.el
index 59ea412..6b23b4c 100644
--- a/compat-31.el
+++ b/compat-31.el
@@ -94,5 +94,59 @@ METADATA should be an alist of completion metadata. See
`(metadata . ,metadata)
(complete-with-action action table string pred))))
+;;;; Defined in subr-x.el
+
+(compat-defvar work-buffer--list nil ;; <compat-tests:with-work-buffer>
+ "List of work buffers.")
+
+(compat-defvar work-buffer-limit 10 ;; <compat-tests:with-work-buffer>
+ "Maximum number of reusable work buffers.
+When this limit is exceeded, newly allocated work buffers are
+automatically killed, which means that in a such case
+`with-work-buffer' becomes equivalent to `with-temp-buffer'.")
+
+(compat-defun work-buffer--get () ;; <compat-tests:with-work-buffer>
+ "Get a work buffer."
+ (let ((buffer (pop work-buffer--list)))
+ (if (buffer-live-p buffer)
+ buffer
+ ;; `generate-new-buffer' and `get-buffer-create' accept an
+ ;; INHIBIT-BUFFER-HOOKS argument on Emacs 28 and newer.
+ ;; Unfortunately it is hard or not possible to port this back. See
+ ;; issue <compat-gh:42>.
+ (static-if (>= emacs-major-version 28)
+ (generate-new-buffer " *work*" t)
+ (generate-new-buffer " *work*")))))
+
+(compat-defun work-buffer--release (buffer) ;; <compat-tests:with-work-buffer>
+ "Release work BUFFER."
+ (if (buffer-live-p buffer)
+ (with-current-buffer buffer
+ (let ((inhibit-read-only t) deactivate-mark)
+ (erase-buffer))
+ (delete-all-overlays)
+ (let (change-major-mode-hook)
+ ;; TODO Port back the KILL-PERMANENT argument from Emacs 29
+ ;; Right now permanent variables are not killed.
+ (static-if (>= emacs-major-version 29)
+ (kill-all-local-variables t)
+ (kill-all-local-variables)))
+ (push buffer work-buffer--list)))
+ (when (> (length work-buffer--list) work-buffer-limit)
+ (mapc #'kill-buffer (nthcdr work-buffer-limit work-buffer--list))
+ (setq work-buffer--list (ntake work-buffer-limit work-buffer--list))))
+
+(compat-defmacro with-work-buffer (&rest body) ;; <compat-tests:with-work-buffer>
+ "Create a work buffer, and evaluate BODY there like `progn'.
+Like `with-temp-buffer', but reuse an already created temporary
+buffer when possible, instead of creating a new one on each call."
+ (declare (indent 0) (debug t))
+ (let ((work-buffer (make-symbol "work-buffer")))
+ `(let ((,work-buffer (work-buffer--get)))
+ (with-current-buffer ,work-buffer
+ (unwind-protect
+ (progn ,@body)
+ (work-buffer--release ,work-buffer))))))
+
(provide 'compat-31)
;;; compat-31.el ends here
diff --git a/compat-tests.el b/compat-tests.el
index 5b12baf..6705620 100644
--- a/compat-tests.el
+++ b/compat-tests.el
@@ -1088,6 +1088,15 @@
(with-current-buffer inner
(should-not (buffer-modified-p))))))))
+(ert-deftest compat-with-work-buffer ()
+ (with-work-buffer
+ (should (string-match-p "\\` \\*work\\*" (buffer-name)))
+ (let ((outer (current-buffer)))
+ (with-work-buffer
+ (should (string-match-p "\\` \\*work\\*" (buffer-name)))
+ (let ((inner (current-buffer)))
+ (should-not (eq outer inner)))))))
+
(ert-deftest compat-insert-into-buffer ()
;; Without optional compat--arguments
(with-temp-buffer
diff --git a/compat.texi b/compat.texi
index 16ae3a9..c1b7701 100644
--- a/compat.texi
+++ b/compat.texi
@@ -3427,6 +3427,13 @@ older than 31.1. Note that due to upstream changes, it might happen
that there will be the need for changes, so use these functions with
care.
+@c based on lisp/emacs-lisp/subr-x.el
+@defmac with-work-buffer &rest body
+Create a work buffer, and evaluate @var{body} there like @code{progn}.
+Like @code{with-temp-buffer}, but reuse an already created temporary
+buffer when possible, instead of creating a new one on each call.
+@end defmac
+
@c copied from lispref/numbers.texi
@defun plusp number
This predicate tests whether its argument is positive, and returns