From 37df936cc1c9e3f630a060c8347a4aeba46fc7d0 Mon Sep 17 00:00:00 2001 From: Adam Porter Date: Thu, 31 Dec 2020 12:56:25 -0600 Subject: [PATCH] * lisp/subr.el (with-file-buffer): New macro. * lisp/subr.el (with-file-buffer): New macro. * doc/lispref/files.texi (Writing to Files): Document it. * etc/NEWS: Add news entry. --- doc/lispref/files.texi | 48 ++++++++++++++++++++++++++++++++++++++++++ etc/NEWS | 6 ++++++ lisp/subr.el | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+) diff --git a/doc/lispref/files.texi b/doc/lispref/files.texi index 6949ca2..1617bbf 100644 --- a/doc/lispref/files.texi +++ b/doc/lispref/files.texi @@ -708,6 +708,54 @@ Writing to Files (@pxref{Buffer List}). @end defmac +@defmac with-file-buffer file options body@dots{} +@anchor{Definition of with-file-buffer} +Like the @code{with-temp-file} macro (which see), the +@code{with-file-buffer} macro evaluates the @var{body} forms with a +temporary buffer as the current buffer and then returns the value of +the last form in @var{body}. The @var{options} offer control over +various aspects of the operations: + +@table @code +@item :insert +When non-nil (the default, when unspecified), insert @var{file}'s contents +before evaluating @var{body}, leaving point before the contents. + +@item :must-exist +When non-nil, signal an error if @var{file} does not exist. + +@item :write +When non-nil, write the contents of the buffer to @var{file} after +evaluating @var{body}. + +@item :overwrite +When nil (the default, when unspecified), signal an error instead of +overwriting an existing file. If @code{ask}, ask for confirmation +before overwriting an existing file. If @code{t}, overwrite +@var{file} unconditionally. + +@item :visit +Passed to function @code{write-region}, which see. + +@item :lockname +Passed to function @code{write-region}, which see. + +@item :append +Passed to function @code{write-region}, which see. (When using this +option, you will probably want to specify @code{:insert nil} as well, +otherwise the file's contents would be duplicated.) + +@item :fsync +When non-nil (the default, when unspecified), bind +@var{write-region-inhibit-fsync} (which see) to this value. + +@item :precious +Bind @var{file-precious-flag} (which see) to this +value (when unspecified, nil). +@end table + +@end defmac + @node File Locks @section File Locks @cindex file locks diff --git a/etc/NEWS b/etc/NEWS index 62907a6..9b8288f 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -2311,6 +2311,12 @@ locales. They are also available as aliases 'ebcdic-cp-*' (e.g., 'cp278' for 'ibm278'). There are also new charsets 'ibm2xx' to support these coding-systems. +--- +** New macro 'with-file-buffer'. +The new macro 'with-file-buffer' simplifies operating on the contents +of files and/or writing to them, compared to using 'with-temp-buffer', +'insert-file-contents', 'write-region', and various options +separately. * Changes in Emacs 28.1 on Non-Free Operating Systems diff --git a/lisp/subr.el b/lisp/subr.el index 77b142c..0f6da02 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -3992,6 +3992,63 @@ with-temp-buffer (and (buffer-name ,temp-buffer) (kill-buffer ,temp-buffer))))))) +(defmacro with-file-buffer (file options &rest body) + "Evaluate BODY and return its value in a temp buffer for FILE. +OPTIONS is a plist of the following options: + +`:insert': When non-nil (the default, when unspecified), insert +file's contents before evaluating BODY, leaving point before the +contents. + +`:must-exist': When non-nil, signal an error if no file exists at +FILE. + +`:write': When non-nil, write the contents of the buffer to FILE +after evaluating BODY. + +`:overwrite': When nil (the default, when unspecified), signal an +error instead of overwriting an existing file at FILE. If `ask', +ask for confirmation before overwriting an existing file. If t, +overwrite a file at FILE unconditionally. + +`:visit': Passed to function `write-region', which see. + +`:lockname:' Passed to function `write-region', which see. + +`:append': Passed to function `write-region', which see. (When +using this option, you will probably want to specify `:insert +nil' as well.) + +`:fsync': When non-nil (the default, when unspecified), bind +`write-region-inhibit-fsync' (which see) to this value. + +`:precious': Bind `file-precious-flag' (which see) to this +value (when unspecified, nil)." + (declare (indent 2) (debug (stringp form body))) + `(let ((write-region-inhibit-fsync ,(when (plist-member options :fsync) + (not (plist-get options :fsync)))) + (file-precious-flag ,(plist-get options :precious))) + (with-temp-buffer + ,(when (or (not (plist-member options :insert)) + (plist-get options :insert)) + `(if (file-readable-p ,file) + (save-excursion + (insert-file-contents ,file)) + (when ,(plist-get options :must-exist) + (error "File not readable: %s" ,file)))) + (prog1 + (progn + ,@body) + ,(when (plist-get options :write) + `(write-region nil nil ,file + ,(plist-get options :append) + ,(plist-get options :visit) + ,(plist-get options :lockname) + ,(pcase-exhaustive (plist-get options :overwrite) + ('nil ''excl) + ((or 'ask ''ask) ''ask) + ('t nil)))))))) + (defmacro with-silent-modifications (&rest body) "Execute BODY, pretending it does not modify the buffer. This macro is typically used around modifications of -- 2.7.4