I'm trying to write a command that allows me to search for an org-mode entry and inserts a link to it at point (using its id). Here's the code:

  (defun org-link-to-entry ()
    (let (link description)
        (setq link (org-id-complete-link))
        (org-id-goto (string-remove-prefix "id:" link))
        (setq description (org-get-heading t t t t)))
      (insert (format "[[%s][%s]]" link description))

As far as I understand it, the only form that changes point is org-id-goto, and that is inside a save-excursion. In my setup, the code actually inserts the link at the proper place, but leaves me at the start of the heading with the given id.

This question seems related, but no enough: Why save-excursion doesn't save point position?

I've also tried using save-current-buffer (as in https://emacs.stackexchange.com/a/17577/27223) both around save-excursion and the let binding, but both also leave me at the buffer where the entry with id is.

I'm on Spacemacs, if that's relevant.

Note that this is what I get when I pull-up the documentation for save-excursion:

save-excursion is a special form in ‘C source code’.

(save-excursion &rest BODY)

Probably introduced at or before Emacs version 20.

Save point, and current buffer; execute BODY; restore those things. Executes BODY just like ‘progn’. The values of point and the current buffer are restored even in case of abnormal exit (throw or error).

If you only want to save the current buffer but not point, then just use ‘save-current-buffer’, or even ‘with-current-buffer’.

Before Emacs 25.1, ‘save-excursion’ used to save the mark state. To save the mark state as well as point and the current buffer, use ‘save-mark-and-excursion’.

What am I doing wrong? How to make this function leave me at the point and buffer I was before calling it?

  • Yes, actually. Don't know how I didn't come across it. Thanks. – Juan Meleiro Sep 26 '20 at 13:16

You're probably looking for save-window-excursion.

Note the docstring warnings; but as org-id-goto uses pop-to-buffer-same-window which will use the current window unless called from a minibuffer or the current window is dedicated, you would be ok in most situations.

save-excursion just ensures that elisp code acting on a buffer will be able to continue acting afterwards on the same buffer at the same point. Whether or not the window configuration changed in the interim is not relevant to that use-case -- the buffer being acted on needn't even be visible (and frequently isn't).

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