org-latex-preview: Dynamic throttle for live previews

* lisp/org-latex-preview.el (org-latex-preview-live--throttle,
org-latex-preview-live-throttle,
org-latex-preview-live--preview-times,
org-latex-preview-live--update-times,
org-latex-preview-live--record-hook,
org-latex-preview-live--regenerate,
org-latex-preview-live--update-props,
org-latex-preview-live--src-buffer-setup,
org-latex-preview-live--setup, org-latex-preview-live--teardown,
org-latex-preview--create-image-async): Find the optimal throttle
time for live preview updates dynamically.  The variable
`org-latex-preview-live--preview-times' records the last three
process run times, and `org-latex-preview-live-throttle' is set to
the average of these.  This ensures that there are never more than
two concurrent processes live-previewing a single fragment.  Start
another preview run process the end of the throttle period if the
preview image is out of date to ensure that the state of the
preview is eventually consistent with the contents of the
fragment.
This commit is contained in:
Karthik Chikmagalur 2024-01-18 23:59:30 -08:00 committed by TEC
parent 36178651d4
commit 2ca8200554
Signed by: tec
SSH Key Fingerprint: SHA256:eobz41Mnm0/iYWBvWThftS0ElEs1ftBr6jamutnXc/A
1 changed files with 52 additions and 23 deletions

View File

@ -873,8 +873,8 @@ customize the variable `org-latex-preview-live'."
;; - When the preview is regenerated, the `after-string' property of ;; - When the preview is regenerated, the `after-string' property of
;; the preview overlay is updated to show the new image. This ;; the preview overlay is updated to show the new image. This
;; regeneration is modulated with a debounce ;; regeneration is modulated with a debounce
;; `org-latex-preview-live-debounce' and a throttle ;; `org-latex-preview-live-debounce' and a dynamically updated
;; `org-latex-preview-live-throttle'. ;; throttle `org-latex-preview-live-throttle'.
;; ;;
;; - When the cursor exits the boundaries of the fragment, the ;; - When the cursor exits the boundaries of the fragment, the
;; `after-string' property of the preview overlay is removed. ;; `after-string' property of the preview overlay is removed.
@ -938,15 +938,36 @@ environment for at least this much time."
:package-version '(Org . "9.7") :package-version '(Org . "9.7")
:type 'number) :type 'number)
(defcustom org-latex-preview-live-throttle 1.0 (defvar org-latex-preview-live-throttle 1.0
"Throttle time for live LaTeX previews. "Throttle time for live LaTeX previews.
When `org-latex-preview-live' is non-nil and When `org-latex-preview-live' is non-nil and
`org-latex-preview-auto-mode' is active, live previews are `org-latex-preview-auto-mode' is active, live previews are
updated no more than once in this interval of time." updated no more than once in this interval of time.
:group 'org-latex-preview
:package-version '(Org . "9.7") Its value is updated dynamically based on the average fragment
:type 'number) preview time.")
(defvar-local org-latex-preview-live--preview-times
(make-vector 3 1.0)
"Vector containing the last three preview run times in this buffer")
(defvar-local org-latex-preview-live--preview-times-index 0)
(defun org-latex-preview-live--update-times (latest-duration)
"Update preview times given the last preview took LATEST-DURATION seconds."
(aset org-latex-preview-live--preview-times
(% (cl-incf org-latex-preview-live--preview-times-index) 3)
latest-duration)
(setq-local org-latex-preview-live-throttle
(/ (apply #'+ (append org-latex-preview-live--preview-times nil))
3)))
(defun org-latex-preview-live--record-hook (exit-code _buf extended-info)
"A hook for `org-latex-preview-process-finish-functions' to track preview time.
Called with EXIT-CODE and EXTENDED-INFO from the async process."
(when (= exit-code 0)
(org-latex-preview-live--update-times
(- (float-time) (plist-get extended-info :start-time)))))
(defconst org-latex-preview-live-display-type 'buffer (defconst org-latex-preview-live-display-type 'buffer
"How to display live-updating previews of LaTeX snippets. "How to display live-updating previews of LaTeX snippets.
@ -973,22 +994,27 @@ The only currently supported option is the symbol buffer, to
(setq debounce-timer nil) (setq debounce-timer nil)
(apply func args)))))))) (apply func args))))))))
(defun org-latex-preview-live--throttle (func timeout) (defun org-latex-preview-live--throttle (func)
"Return a throttled FUNC with TIMEOUT applied." "Return a throttled FUNC.
Ensures that FUNC runs at the end of the throttle duration."
(let ((waiting)) (let ((waiting))
(lambda (&rest args) (lambda (&rest args)
(unless waiting (unless waiting
(apply func args) (apply func args)
(setq waiting t) (setq waiting t)
(run-at-time timeout nil (run-at-time
(lambda () (setq waiting nil))))))) org-latex-preview-live-throttle nil
(lambda ()
(setq waiting nil)
(apply func args)))))))
(defun org-latex-preview-live--clearout (ov) (defun org-latex-preview-live--clearout (ov)
"Clear out the live LaTeX preview for the preview overlay OV." "Clear out the live LaTeX preview for the preview overlay OV."
(setq org-latex-preview-live--element-type nil) (setq org-latex-preview-live--element-type nil)
(overlay-put ov 'after-string nil)) (overlay-put ov 'after-string nil))
(defun org-latex-preview-live--regenerate (beg end _) (defun org-latex-preview-live--regenerate (&rest _)
"Regenerate the LaTeX preview overlay that overlaps BEG and END. "Regenerate the LaTeX preview overlay that overlaps BEG and END.
This is meant to be run via the `after-change-functions' hook in This is meant to be run via the `after-change-functions' hook in
@ -996,10 +1022,13 @@ Org buffers when using live-updating LaTeX previews."
(pcase-let ((`(,type . ,ov) (pcase-let ((`(,type . ,ov)
(get-char-property-and-overlay (point) 'org-overlay-type))) (get-char-property-and-overlay (point) 'org-overlay-type)))
(when (and ov (eq type 'org-latex-overlay) (when (and ov (eq type 'org-latex-overlay)
(<= (overlay-start ov) beg) ;; The following checks are redundant and can make
(>= (overlay-end ov) end)) ;; throttling inconsistent:
(org-latex-preview-auto--regenerate-overlay ov) ;; (<= (overlay-start ov) beg)
(unless (overlay-buffer ov) ;; (>= (overlay-end ov) end)
(overlay-get ov 'preview-state))
(org-latex-preview-auto--regenerate-overlay ov t)
(unless (and (overlay-buffer ov) (overlay-get ov 'preview-image))
(org-latex-preview-live--clearout ov))))) (org-latex-preview-live--clearout ov)))))
(defun org-latex-preview-live--update-props (image-spec &optional box-face) (defun org-latex-preview-live--update-props (image-spec &optional box-face)
@ -1141,8 +1170,7 @@ This is meant to be called via `org-src-mode-hook'."
(overlay-end orig-ov) (overlay-end orig-ov)
content)) content))
numbering-offsets)))) numbering-offsets))))
(org-latex-preview-live--throttle (org-latex-preview-live--throttle)
org-latex-preview-live-throttle)
(org-latex-preview-live--debounce (org-latex-preview-live--debounce
org-latex-preview-live-debounce))) org-latex-preview-live-debounce)))
(add-hook 'after-change-functions org-latex-preview-live--generator 90 'local)) (add-hook 'after-change-functions org-latex-preview-live--generator 90 'local))
@ -1174,8 +1202,7 @@ This is meant to be called via `org-src-mode-hook'."
(skip-chars-backward "\n \t\r") (skip-chars-backward "\n \t\r")
(point)))) (point))))
numbering-offsets preamble)) numbering-offsets preamble))
(org-latex-preview-live--throttle (org-latex-preview-live--throttle)
org-latex-preview-live-throttle)
(org-latex-preview-live--debounce (org-latex-preview-live--debounce
org-latex-preview-live-debounce))) org-latex-preview-live-debounce)))
(add-hook 'org-latex-preview-overlay-open-functions #'org-latex-preview-live--ensure-overlay nil 'local) (add-hook 'org-latex-preview-overlay-open-functions #'org-latex-preview-live--ensure-overlay nil 'local)
@ -1207,8 +1234,7 @@ See `org-latex-preview-live' for details."
(setq org-latex-preview-live--docstring " ") (setq org-latex-preview-live--docstring " ")
(setq-local org-latex-preview-live--generator (setq-local org-latex-preview-live--generator
(thread-first #'org-latex-preview-live--regenerate (thread-first #'org-latex-preview-live--regenerate
(org-latex-preview-live--throttle (org-latex-preview-live--throttle)
org-latex-preview-live-throttle)
(org-latex-preview-live--debounce (org-latex-preview-live--debounce
org-latex-preview-live-debounce))) org-latex-preview-live-debounce)))
(when (eq org-latex-preview-live-display-type 'eldoc) (when (eq org-latex-preview-live-display-type 'eldoc)
@ -1218,6 +1244,7 @@ See `org-latex-preview-live' for details."
(add-hook 'org-latex-preview-overlay-close-functions #'org-latex-preview-live--clearout nil 'local) (add-hook 'org-latex-preview-overlay-close-functions #'org-latex-preview-live--clearout nil 'local)
(add-hook 'org-latex-preview-overlay-open-functions #'org-latex-preview-live--ensure-overlay nil 'local) (add-hook 'org-latex-preview-overlay-open-functions #'org-latex-preview-live--ensure-overlay nil 'local)
(add-hook 'after-change-functions org-latex-preview-live--generator 90 'local) (add-hook 'after-change-functions org-latex-preview-live--generator 90 'local)
(add-hook 'org-latex-preview-process-finish-functions #'org-latex-preview-live--record-hook nil 'local)
(add-hook 'org-latex-preview-overlay-update-functions #'org-latex-preview-live--update-overlay nil 'local)) (add-hook 'org-latex-preview-overlay-update-functions #'org-latex-preview-live--update-overlay nil 'local))
(defun org-latex-preview-live--teardown () (defun org-latex-preview-live--teardown ()
@ -1235,6 +1262,7 @@ See `org-latex-preview-live' for details."
(remove-hook 'org-latex-preview-overlay-open-functions #'org-latex-preview-live--ensure-overlay 'local) (remove-hook 'org-latex-preview-overlay-open-functions #'org-latex-preview-live--ensure-overlay 'local)
(remove-hook 'after-change-functions org-latex-preview-live--generator 'local) (remove-hook 'after-change-functions org-latex-preview-live--generator 'local)
(remove-hook 'org-latex-preview-overlay-update-functions #'org-latex-preview-live--update-overlay 'local) (remove-hook 'org-latex-preview-overlay-update-functions #'org-latex-preview-live--update-overlay 'local)
(remove-hook 'org-latex-preview-process-finish-functions #'org-latex-preview-live--record-hook 'local)
(setq-local org-latex-preview-live--generator nil)) (setq-local org-latex-preview-live--generator nil))
(defun org-latex-preview-clear-overlays (&optional beg end) (defun org-latex-preview-clear-overlays (&optional beg end)
@ -1861,7 +1889,8 @@ Returns a list of async tasks started."
:texfile (org-latex-preview--create-tex-file :texfile (org-latex-preview--create-tex-file
processing-info fragments-info appearance-options) processing-info fragments-info appearance-options)
:appearance-options appearance-options :appearance-options appearance-options
:place-preview-p place-preview-p))) :place-preview-p place-preview-p
:start-time (float-time))))
(tex-compile-async (tex-compile-async
(org-latex-preview--tex-compile-async extended-info)) (org-latex-preview--tex-compile-async extended-info))
(img-extract-async (img-extract-async