Here is the official definition of copy-to-buffer in Emacs 26.1 (the doc string part is omitted for brevity)

(defun copy-to-buffer (buffer start end)
  (interactive "BCopy to buffer: \nr")
  (let ((oldbuf (current-buffer)))
    (with-current-buffer (get-buffer-create buffer)
        (insert-buffer-substring oldbuf start end)))))

I don't understand why it's necessary to use save-excursion in conjoint with with-current-buffer? As far as I'm concerned, the former is equivalent to a combination of save-excursion and set-buffer, so the current point would be saved and restored anyway.

In other words, I'm wondering why don't the Emacs implementers use the following piece of code, which after some experiments appears to be functionally identical to the current one.

(defun my-copy-to-buffer (buffer start end)
  (interactive "BCopy to buffer: \nr")
  (let ((oldbuf (current-buffer)))
    (with-current-buffer (get-buffer-create buffer)
      (insert-buffer-substring oldbuf start end))))
  • 2
    I agree with you that save-excursion does not make much sense there. The content of BUFFER is replaced anyway. Maybe the reason for save-excursion is of historical nature. One would have to trace the log back in time. Even so I expected a slight difference between the two implementations.. I thought point should end up at the end of buffer with your impementation and stay at the beginning of buffer with the original implementation. But, insert-buffer-substring does unexpectedly not move point to the end of the insertion?! – Tobias Feb 22 '19 at 9:03
  • @Tobias hmm, yeah, though if I do M-: (insert-buffer-substring "*scratch*" 1 10) point does go to the end. Maybe something in the command loop/post command hook is resetting things? – npostavs Feb 22 '19 at 12:55
  • 1
    @npostavs You are right. Point is moved within the context of current-buffer but this movement is not shown in any window since the scope of current-buffer is not associated with any window as long as one does not use functions like display-buffer. I did now (with-current-buffer "*work*" (insert-buffer-substring "*Help*" 1 10) (point)) which gave 10. Point did not move in any visible window. – Tobias Feb 22 '19 at 19:33

Why do you think so? with-current-buffer does not do a save-excursion. Its purpose is just to temporarily change the current buffer (i.e., set it to some buffer and at the end restore what was the current buffer beforehand as the current buffer once again).

This is all that macro with-current-buffer does:

(defmacro with-current-buffer (buffer-or-name &rest body)
  "Execute the forms in BODY with BUFFER-OR-NAME temporarily current.
BUFFER-OR-NAME must be a buffer or the name of an existing buffer.
The value returned is the value of the last form in BODY.  See
also `with-temp-buffer'."
  (declare (indent 1) (debug t))
     (set-buffer ,buffer-or-name)

The purpose of save-excursion is instead to save and restore point and which buffer is current.

  • But save-excursion is evaluated within with-current-buffer, where the "current buffer" being saved (and to be restored later) by save-excursion is the buffer to which I am copying. This doesn't seem to be right, because after executing copy-to-buffer, I remain in the old buffer. – nalzok Feb 22 '19 at 6:25
  • The paragraph where the OP speaks about with-current-buffer is wrong. But I think that that is not really the point of the question. The actual point is that save-excursion does not really make sense in the original implementation. – Tobias Feb 22 '19 at 9:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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