From 8384289762b41b26e75d2e80c37ec84bcc552d32 Mon Sep 17 00:00:00 2001 From: Karthik Chikmagalur Date: Thu, 18 Jan 2024 23:59:30 -0800 Subject: [PATCH] org-latex-preview: WIP live-previews adaptive throttle * lisp/org-latex-preview.el (org-latex-preview-live--throttle, org-latex-preview-live-throttle): --- lisp/org-latex-preview.el | 73 +++++++++++++++++++++++++++------------ 1 file changed, 50 insertions(+), 23 deletions(-) diff --git a/lisp/org-latex-preview.el b/lisp/org-latex-preview.el index 328e291a1..afd197650 100644 --- a/lisp/org-latex-preview.el +++ b/lisp/org-latex-preview.el @@ -927,8 +927,8 @@ customize the variable `org-latex-preview-live'." ;; - When the preview is regenerated, the `after-string' property of ;; the preview overlay is updated to show the new image. This ;; regeneration is modulated with a debounce -;; `org-latex-preview-live-debounce' and a throttle -;; `org-latex-preview-live-throttle'. +;; `org-latex-preview-live-debounce' and a dynamically updated +;; throttle `org-latex-preview-live-throttle'. ;; ;; - When the cursor exits the boundaries of the fragment, the ;; `after-string' property of the preview overlay is removed. @@ -992,15 +992,36 @@ environment for at least this much time." :package-version '(Org . "9.7") :type 'number) -(defcustom org-latex-preview-live-throttle 1.0 +(defvar org-latex-preview-live-throttle 1.0 "Throttle time for live LaTeX previews. When `org-latex-preview-live' is non-nil and `org-latex-preview-auto-mode' is active, live previews are -updated no more than once in this interval of time." - :group 'org-latex-preview - :package-version '(Org . "9.7") - :type 'number) +updated no more than once in this interval of time. + +Its value is updated dynamically based on the average fragment +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))))) (defun org-latex-preview-live--debounce (func duration) "Return a debounced FUNC with DURATION applied." @@ -1016,22 +1037,27 @@ updated no more than once in this interval of time." (setq debounce-timer nil) (apply func args)))))))) -(defun org-latex-preview-live--throttle (func timeout) - "Return a throttled FUNC with TIMEOUT applied." +(defun org-latex-preview-live--throttle (func) + "Return a throttled FUNC. + +Ensures that FUNC runs at the end of the throttle duration." (let ((waiting)) (lambda (&rest args) (unless waiting (apply func args) (setq waiting t) - (run-at-time timeout nil - (lambda () (setq waiting nil))))))) + (run-at-time + org-latex-preview-live-throttle nil + (lambda () + (setq waiting nil) + (apply func args))))))) (defun org-latex-preview-live--clearout (ov) "Clear out the live LaTeX preview for the preview overlay OV." (setq org-latex-preview-live--element-type 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. This is meant to be run via the `after-change-functions' hook in @@ -1039,8 +1065,11 @@ Org buffers when using live-updating LaTeX previews." (pcase-let ((`(,type . ,ov) (get-char-property-and-overlay (point) 'org-overlay-type))) (when (and ov (eq type 'org-latex-overlay) - (<= (overlay-start ov) beg) - (>= (overlay-end ov) end)) + ;; The following checks are redundant and can make + ;; throttling inconsistent: + ;; (<= (overlay-start ov) beg) + ;; (>= (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))))) @@ -1210,8 +1239,7 @@ This is meant to be called via `org-src-mode-hook'." (overlay-end orig-ov) content)) 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))) (add-hook 'after-change-functions org-latex-preview-live--generator 90 'local)) @@ -1233,8 +1261,7 @@ This is meant to be called via `org-src-mode-hook'." (skip-chars-backward "\n \t\r") (point)))) 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))) (add-hook 'org-latex-preview-open-functions #'org-latex-preview-live--ensure-overlay nil 'local) @@ -1266,8 +1293,7 @@ See `org-latex-preview-live' for details." (setq org-latex-preview-live--docstring " ") (setq-local org-latex-preview-live--generator (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))) (when (eq org-latex-preview-live-display-type 'eldoc) @@ -1277,7 +1303,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-open-functions #'org-latex-preview-live--ensure-overlay nil '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--update-overlay-run nil '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)) (defun org-latex-preview-live--teardown () @@ -1295,7 +1321,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 '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-process-finish-functions #'org-latex-preview-live--update-overlay-run 'local) + (remove-hook 'org-latex-preview-process-finish-functions #'org-latex-preview--live-record-hook 'local) (setq-local org-latex-preview-live--generator nil)) (defun org-latex-preview-clear-overlays (&optional beg end) @@ -1936,7 +1962,8 @@ Returns a list of async tasks started." :texfile (org-latex-preview--create-tex-file processing-info fragments-info 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 (org-latex-preview--tex-compile-async extended-info)) (img-extract-async