I am trying to write an idle-timer to export my markdown file whenever I am idle. (I have the output loaded in a Chrome tab which is auto-reloading.)
I tried to do the following:
(defvar my--markdown-idle-timer nil)
(defvar my--markdown-idle-buffers nil)
(defun my-markdown-export-when-idle ()
"Export the file whenever emacs is idle."
(interactive)
(unless my--markdown-idle-timer
(setq my--markdown-idle-timer (run-with-idle-timer 2 'repeat 'my--markdown-idle-export)))
(add-to-list 'my--markdown-idle-buffers (current-buffer)))
(defun my--markdown-idle-export ()
"Export markdown buffers when idle."
(loop for buffer in my--markdown-idle-buffers
if (buffer-live-p buffer)
do (save-excursion
(message "3 Point in %s: %s" (current-buffer) (point))
(with-current-buffer buffer
(message "2 Point in %s: %s" (current-buffer) (point))
(save-excursion
(message "1 Point in %s: %s" (current-buffer) (point))
(markdown-export)
(message "1 - After Point in %s: %s" (current-buffer) (point))
)
(message "2 - After Point in %s: %s" (current-buffer) (point))
)
(message "3 - After Point in %s: %s" (current-buffer) (point))
)
)
)
This works if there are no changes to save. However, if the buffer has changes, the point jumps to the beginning of the buffer. The content of the *Messages*
buffer is
3 Point in partial-matching.md: 1404
2 Point in partial-matching.md: 1404
1 Point in partial-matching.md: 1404
Saving file /Users/me/partial-matching.html...
Wrote /Users/me/partial-matching.html
Saving file /Users/me/partial-matching-components/partial-matching.md...
Wrote /Users/me/partial-matching.md
1 - After Point in partial-matching.md: 1404
2 - After Point in partial-matching.md: 1
3 - After Point in partial-matching.md: 1
So it appears that (save-excursion (markdown-export))
is moving the point in the current buffer. My understanding is that (save-excursion -anything-)
should leave the current buffer and the point in that buffer unchanged.
This behavior happens regardless of whether the current buffer is the markdown buffer or some other buffer when the timer runs.
I'm fairly confident that the outer save-excursion
is unnecessary, but I added it in case having the timer run while in the markdown buffer was causing problems.
I have looked at the source for the function, and the only questionable thing that it seems to do is save-window-excursion
, whose documentation warns that its use usually leads to bugs.
I am running this in my standard configuration, which has a lot of other packages installed, so it is possible that some other package is interfering. However, I am not aware of anything that is trying to interfere with save-excursion
. C-h f save-excursion
claims that save-excursion
is a special in C source code, and does not list any advice.
There is a similar question: save-excursion doesn't restore the currently visible buffer?. However, it addresses the visible buffer and not the location of point in the buffer.
There is another similar question: Why save-excursion doesn't save point position?. However, it refers to a case where the point is inside deleted text. In my case, the text containing the point is not being deleted.
Any idea what is going wrong here?
point
andwindow-point
. This can occur if a function triggers a redisplay. Maybe you could try to track it as well. (I'm just grasping at straws here, the behaviour you describe looks strange.)save-excursion
saves and restores the buffer point.save-window-excursion
saves and restores the window point. Selecting a window sets the buffer point to the window point. It's likely that a window selection is happening at an inopportune time, such as recalculating frame titles after timer operation.(window-point)
to my output, but it's not showing anything that makes sense to me.save-excursion
is written in C, I assume there's no easy way to see the data that it is using or exactly what it is doing. (I consider building emacs from source or attaching a debugger not an "easy way".)