[This question is related to, but not a duplicate of, the question copy contents of current buffer in a temp buffer and operate on that. Besides other incidental things (e.g., the question itself is different), none of the solutions offered both (1) execute the elisp in the same context as the original buffer, AND (2) maintain the state of the original buffer. Indeed, the purpose of the macro offered as a possible solution (with-indirect-buffer-in-foo-mode
) in that question seems to be to actually edit the original text in a different mode. The macro also doesn't maintain the buffer-undo-list
, of course (nor any other 'state' that may change when the text of a buffer changes).]
I'd like to be able to write
(save-complete-buffer-state
(edit-the-buffer-arbitrarily)
(condition-p))
and have everything (or as much as is practical) be preserved from the original emacs buffer state before the call, including, for example, point, kill ring, undo list, etc. Does such a macro already exist? If not, how difficult would it be to implement? (What needs to be saved?)
(I've found c-save-buffer-state
at
Emacs: How to intelligently handle buffer-modified when setting text properties?
but I don't know enough about what needs to be done to understand how close this is to doing what I'm asking.)
EDIT: Using lawlist's and @phils' suggestions, I was able to come up with this solution. Please note that this macro works on a few simple test cases but has not been tested extensively.
(defmacro with-cloned-buffer (&rest body)
"Executes BODY just like `progn' but maintains original buffer state."
(declare (indent 0))
(let ((return-value (make-symbol "return-value")))
`(let (buffer-undo-list) ; maintain original buffer-undo-list
(clone-indirect-buffer nil t)
(let ((,return-value (progn ,@body)))
(primitive-undo 1 buffer-undo-list)
(kill-buffer-and-window)
,return-value))))
Here are two simple tests (first returns t
, second returns nil
):
(with-cloned-buffer
(insert "A")
(left-char 1)
(looking-at-p "A"))
(with-cloned-buffer
(insert "A")
(left-char 1)
(looking-at-p "B"))
(with-cloned-buffer ...)
macro makes slightly more sense than a(save-complete-buffer-state ...)
macro -- if you are not touching the original buffer, there's also nothing to fix if things go horribly wrong. – phils Mar 27 '17 at 00:49clone-indirect-buffer
is very different toclone-buffer
! I do note thatclone-buffer
throws an error for file-visiting buffers, but you can let-bindbuffer-file-name
to nil around the function call. "A buffer whose major mode symbol has a non-nilno-clone
property" is a different matter. That may or may not be something you care about in practice. – phils Mar 28 '17 at 23:06clone-buffer
last night but didn't realize that one could trick it by settingbuffer-file-name
tonil
. – Carl Mar 29 '17 at 02:13Info-mode
is the only standard major mode with any kind ofno-clone
property (in this case beingno-clone-indirect
). It wouldn't surprise me if the properties were created for that specific purpose and that nothing else uses them. – phils Mar 29 '17 at 03:06