8

From the save-excursion docstring:

Save point, mark, and current buffer; execute BODY; restore those things.

My understanding was that the restored buffer would again be visible following the evaluation of the body, but that appears not to be the case. A basic function demonstrating the behavior that I find surprising:

(defun test-excursion ()
  (interactive)
  (save-excursion
    (find-file "just-a-test"))
  (insert "blah"))

On my system (using emacs -q; running Debian version 24.5.1) interactively running this function using M-x test-excursion I get most of the behavior I expect. A new empty file buffer is created (there is no such file on disk) named "just-a-test" and "blah" is inserted in the scratch buffer that I happened to have open at the time. However; the buffer that remains visible is "just-a-test" and not "*scratch*" which was (current-buffer) at the time the command was invoked. No additional windows were created. It is only apparent by switching back to "*scratch*" that the string was inserted as expected.

My memory may be inaccurate on this, but I recall using save-excursion when writing a function and observing the alternate behavior (the restored buffer restored as visible). Is there any chance that this behavior has changed or that there has been a regression in 24.5.1? I know that the definition has changed in 25. I checked on another system (also 24.5.1) and observed the same behavior as my system. Evaluation non-interactively (via eval-last-sexp) yields the same. switch-buffer and save-current-buffer also yield the same.

My understanding is that each window (in the emacs sense) has a current buffer (edit: perhaps appropriately referred to simply as the "displayed buffer" and is returned by current-buffer when the window has focus) which necessarily is visible and there are no other conceptions of a "visible buffer". If save-excursion restores the current buffer then shouldn't it be visible?

I've been scratching my head at this one for a while. I hope someone can help me out.

2 Answers 2

9

The current buffer need not be visible in a window.

You're looking for save-window-excursion (or quite possibly a combination of the two).

n.b. C-uC-ha ^save- will point out all of the following:

save-current-buffer
  Function: Record which buffer is current; execute BODY; make that
            buffer current.

save-excursion
  Function: Save point, mark, and current buffer; execute BODY;
            restore those things.

save-match-data
  Macro: Execute the BODY forms, restoring the global value of the
         match data.

save-restriction
  Function: Execute BODY, saving and restoring current buffer's
            restrictions.

save-selected-window
  Macro: Execute BODY, then select the previously selected window.

save-window-excursion
  Macro: Execute BODY, then restore previous window configuration.
3
  • Do all windows necessarily lack focus when current-buffer is not visible? I don't ever recall observing emacs in such a state, but it would be a rare condition in the first place.
    – ebpa
    Commented Jun 22, 2016 at 23:22
  • 2
    The documentation for set-buffer suggests that the command loop restores the current buffer to the selected window's buffer at the end of each command, in which case that wouldn't be a state that Emacs could get into.
    – phils
    Commented Jun 23, 2016 at 0:40
  • Confirmed by (elisp) Current Buffer which states "When an editing command returns to the editor command loop, Emacs automatically calls ‘set-buffer’ on the buffer shown in the selected window."
    – phils
    Commented Jun 23, 2016 at 1:26
4

Facing a similar problem, I realize this behavior is due to find-file in particular. I didn't try using save-window-excursion instead of save-excursion. What I used instead was

(with-current-buffer (find-file-noselect "just-a-test")
 (insert "blah"))

That way, just-a-test is loaded or switched to if it already visited in the background. It remains open. As far as I can see, for this simple example the two methods (this and the one by phils) is a matter of taste.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.