2

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)
      (barf-if-buffer-read-only)
      (erase-buffer)
      (save-excursion
        (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)
      (barf-if-buffer-read-only)
      (erase-buffer)
      (insert-buffer-substring oldbuf start end))))
Tobias
  • 32,569
  • 1
  • 34
  • 75
nalzok
  • 665
  • 6
  • 18
  • 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 09: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

1 Answers1

3

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))
  `(save-current-buffer
     (set-buffer ,buffer-or-name)
     ,@body))

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

Drew
  • 75,699
  • 9
  • 109
  • 225
  • 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 06: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 09:06