In my org-mode setup, initially I used to preview the whole buffer all the time. However, as my files grew bigger the waiting time for this has become prohibitively expensive. Since then I have set it up to continuously recompile the file in the background each time the file is saved. It works pretty well since instead of spawning a new async process on each save, I have a single background process which recomiles in sync and thus needs not reload all the emacs on each recompile. Overall, it takes a couple of seconds to see the updated pdf after each save.
Recently however, I updated to org-mode 9.3 and I noticed that the image creation has gotten significantly faster, and the caching has gotten better - to the point of loading instantly the images from previous sessions. This has led me searching again for a way to toggle the images whenever the cursor falls on them, like in auctex. I wanted this feature for a long while now, bug never bothered to write it myself.
This time however, I found the solution premade by John Kitchin. It essentially worked quite well but had a few bugs that irritated me. I took it upon me to fix them, and attached below is the version with the fixes, as well as a bit of refactoring.
The major points: - Before deleting an overlay, make sure that there is still a latex fragment at the current location. - Don’t move the point (cursor) when entering a fragment. - Refactoring of the latex fragment test and surroungins (I know there is also org-inside-LaTeX-fragment-p, but it doesn’t detect when located on the first character of a fragment, and this one does).
To use, add the following to your
(add-hook 'post-command-hook 'kk/org-latex-fragment-toggle t)
And add the following code somewhere in
(defvar kk/org-latex-fragment-last nil "Holds last fragment/environment you were on.") (defun kk/org-in-latex-fragment-p () "Return the point where the latex fragment begins, if inside a latex fragment. Else return false" (let* ((el (org-element-context)) (el-type (car el))) (and (or (eq 'latex-fragment el-type) (eq 'latex-environment el-type)) (org-element-property :begin el)))) (defun kk/org-latex-fragment-toggle () "Toggle a latex fragment image " (and (eq 'org-mode major-mode) (let ((begin (kk/org-in-latex-fragment-p))) (cond ;; were on a fragment and now on a new fragment ((and ;; fragment we were on kk/org-latex-fragment-last ;; and are on a fragment now begin ;; but not on the last one this is a little tricky. as you edit the ;; fragment, it is not equal to the last one. We use the begin ;; property which is less likely to change for the comparison. (not (and kk/org-latex-fragment-last (= begin kk/org-latex-fragment-last)))) ;; go back to last one and put image back, provided there is still a fragment there (save-excursion (goto-char kk/org-latex-fragment-last) (when (kk/org-in-latex-fragment-p) (org-preview-latex-fragment)) ;; now remove current image (goto-char begin) (let ((ov (loop for ov in (org--list-latex-overlays) if (and (<= (overlay-start ov) (point)) (>= (overlay-end ov) (point))) return ov))) (when ov (delete-overlay ov))) ;; and save new fragment (setq kk/org-latex-fragment-last begin))) ;; were on a fragment and now are not on a fragment ((and ;; not on a fragment now (not begin) ;; but we were on one kk/org-latex-fragment-last) ;; put image back on, provided that there is still a fragment here. (save-excursion (goto-char kk/org-latex-fragment-last) (when (kk/org-in-latex-fragment-p) (org-preview-latex-fragment))) ;; unset last fragment (setq kk/org-latex-fragment-last nil)) ;; were not on a fragment, and now are ((and ;; we were not one one (not kk/org-latex-fragment-last) ;; but now we are begin) ;; remove image (save-excursion (goto-char begin) (let ((ov (loop for ov in (org--list-latex-overlays) if (and (<= (overlay-start ov) (point)) (>= (overlay-end ov) (point))) return ov))) (when ov (delete-overlay ov)))) (setq kk/org-latex-fragment-last begin))))))