This is another follow-up bug-report/patch from: https://lists.gnu.org/archive/html/auctex-devel/2025-08/msg00026.html
and continuing the discussion from bug#79708 (Thanks Paul, Arash and Ikumi for your help, support and comments on this feature-set). This patch implements an extensible automatic preview mode based on ideas by Paul in preview-auto. I wasn't sure what to call it, since I didn't want it to clash with Paul's package. I thought of preview-automatic or preview-live and went with the first one for now. Let me know your thoughts. Out of the box, enabling preview-automatic-mode would cause the previews to be auto-updated when modified. Setting `preview-automatic-function` to #'texmathp would further cause newly written math expressions to be previewed as well. preview-automatic-delay can be customized to reduce the frequency of previewing through debouncing. I am using the new timeout package when available, and implementing the debouncing of previewing manually otherwise. Any comments on the design, approach or lisp-fu or welcome. One potential point for discussion is when to call the previewing function. I am currently doing that on modification rather than post-command-hook to reduce unnecessary calls. This does mean that if the user continuously types on a preview, then quickly (before the debouncing delay passes) moves to another preview and continues typing there before updating the first one. The first preview is not auto-updated. I find this a good compromise to reduce the overhead, but I am happy to change it back to post-command-hook if there is disagreement (I do think the overhead is minimal). On 31/03/2026, Arash Esbati wrote: > Can you please also make a suggestion for NEWS.org? I'd then release > AUCTeX 14.2.0. TIA. @Arash, can we hold off releasing 14.2.0 until this patch is considered? It would complete the basic feature set of the previewing workflow that I am currently using and I think many people would find useful. There is one more improvement I am planning to propose (changing the preview face when disabled -- mostly relevant for svg previews), but it can be postponed after releasing 14.2.0 if needed. -- Al
>From 6052b60bfb95d0c2f734ad2070060cf11adec440 Mon Sep 17 00:00:00 2001 From: Al Haji-Ali <[email protected]> Date: Tue, 31 Mar 2026 14:13:50 +0100 Subject: [PATCH] New feature: preview-automatic Code derived from preview-auto.el (Copyright 2024 FSF, by Paul D. Nelson), adapted and integrated here. * doc/preview-latex.texi: Add docs for preview-automatic * preview.el (preview-silent-errors): New local variable. (preview-log-error, preview-reraise-error): Silence errors conditionally. (preview-automatic-function, preview-automatic-delay): New user options (preview-handle-modification): Update previews automatically. (preview-automatic-mode): New mode. (preview-automatic--update-1, preview-automatic-update, preview-automatic--after-change): New function. --- doc/preview-latex.texi | 3 + preview.el | 129 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 128 insertions(+), 4 deletions(-) diff --git a/doc/preview-latex.texi b/doc/preview-latex.texi index 0f3c63b1..a38d030d 100644 --- a/doc/preview-latex.texi +++ b/doc/preview-latex.texi @@ -481,6 +481,9 @@ math (@code{$@dots{}$}), or if your usage of @code{$} conflicts with @samp{Preview Latex} group, remove @code{textmath} from @code{preview-default-option-list} by customizing this variable. +See also @code{preview-automatic-mode} to enable automatic updating or +generation of previews. + @item Customize where previews are shown Set @code{preview-visibility-style} to control when previews appear: diff --git a/preview.el b/preview.el index 37da8f1d..43ad9a6e 100644 --- a/preview.el +++ b/preview.el @@ -372,6 +372,10 @@ See also `preview-gs-command'." "List of overlays to convert using gs. Buffer-local to the appropriate TeX process buffer.") +(defvar-local preview-silent-errors nil + "When non-nil, do not signal preview errors nor display output buffer. +This variable should be set in the process buffer.") + (defvar-local preview-gs-outstanding nil "Overlays currently processed.") @@ -699,7 +703,8 @@ is to be used." (insert-before-markers (format "%s: %s\n" context (error-message-string err))) - (display-buffer (current-buffer))))) + (unless preview-silent-errors + (display-buffer (current-buffer)))))) (setq preview-error-condition err)) (defun preview-reraise-error (&optional process) @@ -708,7 +713,11 @@ Makes sure that PROCESS is removed from the \"Compilation\" tag in the mode line." (when preview-error-condition (unwind-protect - (signal (car preview-error-condition) (cdr preview-error-condition)) + (unless (buffer-local-value 'preview-silent-errors + (or (process-buffer process) + (current-buffer))) + (signal (car preview-error-condition) + (cdr preview-error-condition))) (setq preview-error-condition nil compilation-in-progress (delq process compilation-in-progress))))) @@ -2173,11 +2182,15 @@ for definition of OV, AFTER-CHANGE, BEG, END and LENGTH." (preview-register-change ov))) (defun preview-handle-modification - (ov after-change _beg _end &optional _length) + (ov after-change _beg _end &optional _length) "Hook function for `modification-hooks' property. See info node `(elisp) Overlay Properties' for definition of OV, AFTER-CHANGE, BEG, END and LENGTH." - (unless after-change + (if after-change + (when (buffer-local-value 'preview-automatic-mode + (overlay-buffer ov)) + (preview-automatic-update (overlay-buffer ov) + (overlay-start ov))) (preview-register-change ov))) (defun preview--string (ov use-icon helpstring &optional click1) @@ -4675,6 +4688,114 @@ See `preview-at-point-placement'.")))) (set-frame-parameter old-frame 'auctex-preview nil) (buframe-disable old-frame))))) +;;; preview-automatic -- Auto-preview + +(defcustom preview-automatic-function nil + "Function to determine if a preview should be created at point. + +When `preview-automatic-mode' is enabled and this variable is non-nil, +it should be a function that is is called with no arguments at (point) +when there is not a preview already. If the function returns a non-nil +value, `preview-at-point' will be called. + +If the function returns a cons, it should be the (BEGIN . END), which +will be used as arguments for `preview-region'." + :type 'symbol + :group 'preview-latex + :package-version '(auctex . "14.2.0")) + +;;;###autoload +(define-minor-mode preview-automatic-mode + "Enable automatic refreshing and generation of previews. +When enabled, existing previews are automatically updated when their +text is changed. Moreover, previews are automatically created whenever +`preview-automatic-function' returns a non-nil value at point." + :group 'preview-latex + :init-value nil + (if preview-automatic-mode + (progn + (add-hook 'after-change-functions + #'preview-automatic--after-change nil t) + (preview-automatic-update (current-buffer) (point))) + (remove-hook 'after-change-functions + #'preview-automatic--after-change t))) + +(defcustom preview-automatic-delay 0.1 + "Delay in seconds for automatic preview timer." + :type 'number + :group 'preview-latex + :package-version '(auctex . "14.2.0")) + +(defun preview-automatic--update-1 (buffer pt &optional new-only) + "Update preview at PT in BUFFER." + (when (buffer-live-p buffer) + (with-current-buffer buffer + (if-let* ((cur-process + (or (get-buffer-process (TeX-process-buffer-name + (TeX-region-file))) + (get-buffer-process (TeX-process-buffer-name + (TeX-master-file)))))) + (progn + (when (and preview-current-region (not preview-abort-flag)) + (progn + (ignore-errors (TeX-kill-job)) + (setq preview-abort-flag t))) + (with-local-quit (accept-process-output cur-process)) + ;; Assume that `preview-automatic-update' is debounced, + ;; otherwise this call may cause an infinite loop. + (preview-automatic-update buffer pt new-only)) + (when-let* ((region + (save-excursion + (goto-char pt) + (let* ((cur (cl-find-if + (lambda (ov) + (eq (overlay-get ov 'cateogry) + 'preview-overlay)) + (overlays-at (point)))) + (region (or + (and (not new-only) cur) + (and (not cur) + preview-automatic-function + (funcall + preview-automatic-function))))) + (when region + (if (consp region) + region + (cons (preview-next-border t) + (preview-next-border nil)))))))) + (let ((TeX-suppress-compilation-message t) + (save-silently t) + (noninteractive t) + (inhibit-message t) + message-log-max) + (let* ((process (preview-region (car region) (cdr region)))) + (with-current-buffer (process-buffer process) + (setq-local preview-silent-errors t))))))))) + +(if (require 'timeout nil t) + (defalias 'preview-automatic-update + (timeout-debounced-func 'preview-automatic--update-1 + 'preview-automatic-delay)) + ;; `timeout' is not available, define debounced + ;; `preview-automatic-update' manually. + (defvar preview-automatic--update-timer nil + "Timer used for debouncing preview-automatic-update.") + (defun preview-automatic-update (buffer pt &optional new-only) + (:documentation (documentation 'preview-automatic--update-1)) + (when preview-automatic--update-timer + (cancel-timer preview-automatic--update-timer) + (setq preview-automatic--update-timer nil)) + + (setq preview-automatic--update-timer + (run-with-idle-timer + preview-automatic-delay nil + #'preview-automatic--update-1 + buffer pt new-only)))) + +(defun preview-automatic--after-change (&rest _) + "Ensure a preview is created after change, if needed." + (preview-automatic-update (current-buffer) (point) t)) + ;;;###autoload (defun preview-report-bug () "Report a bug in the preview-latex package." (interactive) -- 2.50.1 (Apple Git-155)
_______________________________________________ bug-auctex mailing list [email protected] https://lists.gnu.org/mailman/listinfo/bug-auctex
