Package: auctex;
Reported by: Al Haji-Ali <abdo.haji.ali <at> gmail.com>
Date: Mon, 27 Oct 2025 21:01:01 UTC
Severity: normal
Tags: patch
Found in version 14.1.0
To reply to this bug, email your comments to 79708 AT debbugs.gnu.org.
Toggle the display of automated, internal messages from the tracker.
View this report as an mbox folder, status mbox, maintainer mbox
bug-auctex <at> gnu.org:bug#79708; Package auctex.
(Mon, 27 Oct 2025 21:01:02 GMT) Full text and rfc822 format available.Al Haji-Ali <abdo.haji.ali <at> gmail.com>:bug-auctex <at> gnu.org.
(Mon, 27 Oct 2025 21:01:02 GMT) Full text and rfc822 format available.Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
From: Al Haji-Ali <abdo.haji.ali <at> gmail.com> To: bug-auctex <at> gnu.org Subject: 14.1.0; [PATCH] New feature: preview-point Date: Mon, 27 Oct 2025 20:16:12 +0100
[Message part 1 (text/plain, inline)]
Hello, This is the last follow-up bug-report/patch from: https://lists.gnu.org/archive/html/auctex-devel/2025-08/msg00026.html which includes the main preview-point feature. It can be enabled by setting `preview-point` to `'after-string` for example. To use `buframe`, the package needs to be installed as well (available on ELPA). Any comments/questions are welcome. I realized it's a a lot of code to review. Best regards, -- Al
[New-feature-preview-point.patch (text/x-patch, attachment)]
bug-auctex <at> gnu.org:bug#79708; Package auctex.
(Thu, 30 Oct 2025 06:28:01 GMT) Full text and rfc822 format available.Message #8 received at 79708 <at> debbugs.gnu.org (full text, mbox):
From: "Paul D. Nelson" <ultrono <at> gmail.com> To: Al Haji-Ali <abdo.haji.ali <at> gmail.com> Cc: 79708 <at> debbugs.gnu.org Subject: Re: bug#79708: 14.1.0; [PATCH] New feature: preview-point Date: Thu, 30 Oct 2025 07:26:46 +0100
Hi Al,
I've started taking a look and have several comments.
Thanks, best,
Paul
> +(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.")
(Very good.)
> +;;; preview-point customizations and variables.
> +(defcustom preview-point nil
> + "Specifies where to show the preview.
> +If non-nil, show the preview at point. Can be `before-string',
> +`after-string' to show at before or after the TeX code or `buframe' to
> +show in a separate frame (the `buframe' package must be installed). Can
> +also be \\='(buframe FN-POS FRAME-PARAMETERS BUF-PARAMETERS) where
> +FN-POS is a position function (default is
> +`buframe-position-right-of-overlay') and FRAME-PARAMETERS is an alist of
> +additional frame parameters, default is nil and BUF-PARAMETERS is an
> +alist of buffer local variables and their values.
> +
> +This variable must be set before opening a TeX file. Charging its value
> +while a file is open will lead to previews not being displayed
> +correctly. See `preview-point-toggle-mode'."
> + :type '(choice
> + (const :tag "Before string" before-string)
> + (const :tag "After string (default)" after-string)
> + (const :tag "On frame" buframe)
> + (list :tag "On frame with explicit parameters"
> + (function :tag "Position function")
> + (alist :tag "Frame parameters")
> + (alist :tag "Buffer parameters"))))
I have several unrelated comments:
Documentation: preview-point seems to work fine in non-file buffers, so
perhaps replace "TeX file" with "TeX buffer".
Typo: "Charging its value" -> "Changing its value"
The default is nil, but ':type' doesn't accept nil. Consider adding
(const :tag "Disabled" nil).
It would be much more ergonomic if we could enable preview-point after
visiting a buffer. Is this a hard limitation?
> +(defcustom preview-point-auto-p nil
> + "Set this to enable previewing automatically.
> +When non-nil, it is assumed to be a function that is is called with no
> +arguments at (point) when there is not a preview already. If the
> +function return a non-nil value, a `preview-at-point' will be initiated."
> + :type 'symbol)
The documentation does not indicate any intended value. Also, from what
I understand, this setting controls when new previews are generated, but
does not affect whether existing previews are automatically regenerated;
the docs don't seem to emphasize this distinction.
> +(defun preview-point-toggle-mode (mode)
> + "Set `preview-point' to MODE.
> +If called interactively `preview-point' is toggled and the user is asked
> +for the MODE when it is switch on.
> +
> +This function has an effect only if `preview-point' is non-nil, which
> +should be set before opening a TeX file."
> + (interactive
> + (list (if preview-point
> + (if (not (eq preview-point 'hidden))
> + 'hidden
> + (intern
> + (cadr (read-multiple-choice
> + "Mode :"
> + '((?b "before-string")
> + (?a "after-string")
> + (?f "buframe"))))))
> + (error "Preview-point is not enabled. \
> +Set preview-point before opening the TeX file"))))
> +
> + (unless preview-point
> + (error "Preview-point needs to be enabled first (before opening the tex file)."))
> + ;; Hide current overlay if it is visible.
> + (when preview-point--current-overlay
> + (preview-toggle preview-point--current-overlay nil))
> + (setq preview-point mode)
> + ;; Show the preview if it at point.
> + (preview-point-move-point))
The command ends in "-mode" but does not come from a major/minor mode.
Perhaps instead something like "preview-point-toggle-display"?
It might be cleaner to move the body of this command to a custom setter
for preview-point and then either delete the command altogether, or
rewrite it as a light wrapper around customize-set-variable. That way,
users can tweak preview-point via either the new C-c C-p C-t bind or
customize-set-variable.
> +(defun preview-point-toggle-auto-update (enable &optional silent)
> + "Enable auto refresh of previews.
> +When ENABLE is nil, disable auto-update instead. If called
> +interactively, auto-updating is toggled."
> + (interactive (list 'toggle))
> + (when (eq enable 'toggle)
> + (setq enable (not (memq
> + #'preview-point-buf-change
> + after-change-functions))))
> + (if enable
> + (progn
> + (add-hook 'after-change-functions #'preview-point-buf-change nil t)
> + (add-hook 'post-command-hook #'preview-point-auto nil t)
> + (preview-point-buf-change)
> + (unless silent
> + (message "Auto-updating previews enabled")))
> + (remove-hook 'after-change-functions #'preview-point-buf-change t)
> + (remove-hook 'post-command-hook #'preview-point-auto t)
> + (unless silent
> + (message "Auto-updating previews disabled"))))
This reads like a minor mode. I would suggest introducing a small,
display-agnostic "preview-automatic-mode", bound to C-c C-p C-a, that,
when enabled, automatically regenerates existing previews, for both
preview-point and "traditional" preview. This aligns with an earlier
suggestion [1] to upstream automatic previewing. (It's simpler than
preview-auto, which also *finds* new regions to preview, but that
feature could be added later via a strategy variable or hook.) I'd be
happy to draft that refactor on top of your patch if the idea sounds
reasonable.
[1] https://lists.gnu.org/archive/html/auctex-devel/2024-06/msg00031.html
> +
> +;;; preview-point -- Auto-preview
If we refactor as suggested above, then most of the functions below
should be given agnostic names ("preview-automatic-*"?), reflecting that
they are not specific to the preview-point feature.
> +(defcustom preview-point-auto-delay 0.1
> + "Delay in seconds for automatic preview timer."
> + :type 'number)
> +(defvar preview-point-force-update--debounce-timer nil)
> +
> +(defun preview-point <at> around <at> write-region (orig-fun &rest args)
> + "Advice around `write-region' to suppress messages.
> +ORIG-FUN is the original function. ARGS are its arguments."
> + (let ((noninteractive t)
> + (inhibit-message t)
> + message-log-max)
> + (apply orig-fun args)))
> +
> +(defun preview-point-force-update (pt buffer &optional debounce)
> + "Update preview at PT in BUFFER.
> +
> +When DEBOUNCE is non-nil, the call is debounced using an idle
> +timer. This also happens automatically when there is an ongoing
> +compilation process."
> + (interactive (list (point) (current-buffer)))
> +
> + (when preview-point-force-update--debounce-timer
> + (cancel-timer preview-point-force-update--debounce-timer)
> + (setq preview-point-force-update--debounce-timer nil))
> +
> + (when (buffer-live-p buffer)
> + (unless debounce
> + (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
> + ;; Force de-bouncing
> + (when (and preview-current-region
> + (not preview-abort-flag)
> + ;; (< beg (cdr preview-current-region))
> + )
> + (progn
> + (ignore-errors (TeX-kill-job))
> + (setq preview-abort-flag t)))
> + (with-local-quit (accept-process-output cur-process))
> + (setq debounce t))
> + ;; The code below is adopted from preview-auto
The code above this comment also appears to be derived from preview-auto
(see [2]), so if such a comment is to appear at all, then it should be
higher up (e.g., after ;;; preview-point -- Auto-preview). But my
impression is that attribution is more customarily indicated in commit
messages, so I would propose removing such comments from the code and
instead including in the commit message something like the following:
--8<---------------cut here---------------start------------->8---
Automatic previewing code derived from preview-auto.el (Copyright 2024
FSF, by Paul D. Nelson), adapted and integrated by Al-Haji Ali.
--8<---------------cut here---------------end--------------->8---
[2] https://lists.gnu.org/archive/html/auctex-devel/2025-08/msg00047.html
> + (let ((TeX-suppress-compilation-message t)
> + (save-silently t))
> + (advice-add 'write-region :around
> + #'preview-point <at> around <at> write-region)
> + (unwind-protect
> + ;; If we are working in a file buffer that is not a tex file,
> + ;; then we want preview-region to operate in "non-file" mode,
> + ;; where it passes "<none>" to TeX-region-create.
> + (save-excursion
> + (goto-char pt)
> + ;; TODO: Check if we can rely on the `preview-region'
> + ;; returning the process. It calls
> + ;; `preview-generate-preview' which has this documented
> + ;; behaviour, but not `preview-region'.
> + (let ((process (preview-region (preview-next-border t)
> + (preview-next-border nil))))
> + (with-current-buffer (process-buffer process)
> + (setq-local preview-silent-errors t))))
> + (advice-remove 'write-region
> + #'preview-point <at> around <at> write-region))))))
> +
> + (when debounce
> + (setq preview-point-force-update--debounce-timer
> + (run-with-idle-timer
> + preview-point-auto-delay nil
> + #'preview-point-force-update
> + pt buffer)))))
> +
> +(defun preview-point-has-preview-p (&optional pt)
> + "Return non-nil if PT has a preview overlay."
> + (cl-find-if
> + (lambda (ov) (overlay-get ov 'preview-state))
> + (overlays-at (or pt (point)))))
> +
> +(defun preview-point-buf-change (&rest _)
> + "Run preview at point if there is a preview overlay."
> + (when (and preview-point
> + (not (eq preview-point 'hidden))
> + (or
> + (preview-point-has-preview-p)
> + (and preview-point-auto-p
> + (funcall preview-point-auto-p))))
> + (preview-point-force-update (point) (current-buffer) t)))
> +
> ;;;###autoload
> (defun preview-report-bug () "Report a bug in the preview-latex package."
> (interactive)
As a final comment, thanks for working on this and for your other recent
improvements to preview.el - much appreciated!
bug-auctex <at> gnu.org:bug#79708; Package auctex.
(Thu, 30 Oct 2025 08:31:01 GMT) Full text and rfc822 format available.Message #11 received at 79708 <at> debbugs.gnu.org (full text, mbox):
From: Al Haji-Ali <abdo.haji.ali <at> gmail.com> To: "Paul D. Nelson" <ultrono <at> gmail.com> Cc: 79708 <at> debbugs.gnu.org Subject: Re: bug#79708: 14.1.0; [PATCH] New feature: preview-point Date: Thu, 30 Oct 2025 09:25:55 +0100
Hi Paul,
On 30/10/2025, Paul D. Nelson wrote:
> I've started taking a look and have several comments.
Thank you for taking the time, really appreciate it as well as your
earlier work on preview-auto.
What's the best practice here about updating patches? Should I send an
updated full patch or a new one on top of the current one?
> I have several unrelated comments:
Thanks for those, I agree with all of them and will make those changes.
> It would be much more ergonomic if we could enable preview-point after
> visiting a buffer. Is this a hard limitation?
No, I can make this change. It would simply require modifying a couple
of hooks. Should the logic be in a custom-setter code, or in a
function/mode? Note that the setting has to be global (at least in the
current implementation -- though I might be able to make it buffer-local
if there's a real need for it).
> The documentation does not indicate any intended value. Also, from what
> I understand, this setting controls when new previews are generated, but
> does not affect whether existing previews are automatically regenerated;
> the docs don't seem to emphasize this distinction.
This setting should be for both. Updating existing previews when the
text is changed and for generating new ones whenever
`preview-point-auto-p` returns non-nil on (point). For example, one can
set it to `texmathp` to automatically generate previews for math
expressions. I will see how I can update the documentation to better
reflect this.
> The command ends in "-mode" but does not come from a major/minor mode.
> Perhaps instead something like "preview-point-toggle-display"?
>
> It might be cleaner to move the body of this command to a custom setter
> for preview-point and then either delete the command altogether, or
> rewrite it as a light wrapper around customize-set-variable. That way,
> users can tweak preview-point via either the new C-c C-p C-t bind or
> customize-set-variable.
I'll see how that would look. Just to say, the purpose of this command
is to provide an easy way to hide/show previews, for example if they are
getting in the way of editing text. I wasn't thinking about it as a way
to enable preview-point. I am open to suggestions of improvement
to this interface.
>> +(defun preview-point-toggle-auto-update (enable &optional silent)
>
> This reads like a minor mode. I would suggest introducing a small,
> display-agnostic "preview-automatic-mode", bound to C-c C-p C-a, that,
> when enabled, automatically regenerates existing previews, for both
> preview-point and "traditional" preview. This aligns with an earlier
> suggestion [1] to upstream automatic previewing. (It's simpler than
> preview-auto, which also *finds* new regions to preview, but that
> feature could be added later via a strategy variable or hook.) I'd be
> happy to draft that refactor on top of your patch if the idea sounds
> reasonable.
>
> [1] https://lists.gnu.org/archive/html/auctex-devel/2024-06/msg00031.html
I agree a minor mode is better here and a patch would be appreciated
(once I send the updated one with your suggested changes).
I had actually wanted to ask you if the introduction of
`preview-point-auto-p` could be a clean way to incorporate the logic of
`preview-auto`, since I think one can have the clever code in
preview-auto which detects if a preview should be generated as a
customization of this variable.
My thinking is to have automatic previewing split into two logical
parts: The mechanism of updating previews which should be general
enough, and the detection of when to do it which will be
user-controlled.
In any case, I think it would be good to have the infrastructure of
automatic previewing which is being added here as suitable for the
integration of preview-auto as possible (we might need to modify
`preview-point-auto-p` so that it can return a region).
>> +
>> +;;; preview-point -- Auto-preview
>
> If we refactor as suggested above, then most of the functions below
> should be given agnostic names ("preview-automatic-*"?), reflecting that
> they are not specific to the preview-point feature.
Agreed, though I haven't tested automatic previewing without
preview-point.
> --8<---------------cut here---------------start------------->8---
> Automatic previewing code derived from preview-auto.el (Copyright 2024
> FSF, by Paul D. Nelson), adapted and integrated by Al-Haji Ali.
> --8<---------------cut here---------------end--------------->8---
Will add this comment to the commit message.
Best regards,
-- Al
bug-auctex <at> gnu.org:bug#79708; Package auctex.
(Thu, 30 Oct 2025 10:16:02 GMT) Full text and rfc822 format available.Message #14 received at 79708 <at> debbugs.gnu.org (full text, mbox):
From: "Paul D. Nelson" <ultrono <at> gmail.com> To: Al Haji-Ali <abdo.haji.ali <at> gmail.com> Cc: 79708 <at> debbugs.gnu.org Subject: Re: bug#79708: 14.1.0; [PATCH] New feature: preview-point Date: Thu, 30 Oct 2025 11:15:04 +0100
Hi Al, > What's the best practice here about updating patches? Should I send an > updated full patch or a new one on top of the current one? I think sending a full patch is the custom. >> It would be much more ergonomic if we could enable preview-point after >> visiting a buffer. Is this a hard limitation? > No, I can make this change. It would simply require modifying a couple > of hooks. Should the logic be in a custom-setter code, or in a > function/mode? Note that the setting has to be global (at least in the > current implementation -- though I might be able to make it buffer-local > if there's a real need for it). I guess we could go with either of the following: (A) A defcustom with custom setters that both determines whether the feature is enabled and how the feature is displayed. (B) A minor-mode (ideally buffer-local), say preview-point-mode [1], that determines whether the feature is enabled at all, together with a defcustom preview-point [2] that determines how the feature displays. Based on what you wrote elsewhere regarding the intent of the defcustom: > Just to say, the purpose of this command is to provide an easy way to > hide/show previews, for example if they are getting in the way of > editing text. I wasn't thinking about it as a way to enable > preview-point. I am open to suggestions of improvement to this > interface. I think (B) makes more sense. [1] or maybe preview-at-point-mode? [2] or maybe preview-point-display, preview-point-display-type, preview-point-type, preview-at-point-type, etc? > I had actually wanted to ask you if the introduction of > `preview-point-auto-p` could be a clean way to incorporate the logic of > `preview-auto`, since I think one can have the clever code in > preview-auto which detects if a preview should be generated as a > customization of this variable. > > My thinking is to have automatic previewing split into two logical > parts: The mechanism of updating previews which should be general > enough, and the detection of when to do it which will be > user-controlled. That sounds good to me. I'll take a careful look once you've sent the revised patch. Thanks, best, Paul
bug-auctex <at> gnu.org:bug#79708; Package auctex.
(Thu, 30 Oct 2025 10:48:02 GMT) Full text and rfc822 format available.Message #17 received at 79708 <at> debbugs.gnu.org (full text, mbox):
From: Arash Esbati <arash <at> gnu.org> To: Al Haji-Ali <abdo.haji.ali <at> gmail.com> Cc: 79708 <at> debbugs.gnu.org, "Paul D. Nelson" <ultrono <at> gmail.com> Subject: Re: bug#79708: 14.1.0; [PATCH] New feature: preview-point Date: Thu, 30 Oct 2025 11:47:07 +0100
Hi Al, Al Haji-Ali <abdo.haji.ali <at> gmail.com> writes: > What's the best practice here about updating patches? Should I send an > updated full patch or a new one on top of the current one? I'd prefer an updated full patch for each iteration. > This setting should be for both. Updating existing previews when the > text is changed and for generating new ones whenever > `preview-point-auto-p` returns non-nil on (point). For example, one can > set it to `texmathp` to automatically generate previews for math > expressions. I will see how I can update the documentation to better > reflect this. Can we please find another name for `preview-point-auto-p'? This is a custom variable, right? The '-?p' thing is more for predicate functions. I suggest we follow Emacs conventions here[1] and name it `preview-point-auto-function' or similar. Best, Arash Footnotes: [1] https://www.gnu.org/software/emacs/manual/html_node/elisp/Tips-for-Defining.html
bug-auctex <at> gnu.org:bug#79708; Package auctex.
(Sat, 01 Nov 2025 21:40:03 GMT) Full text and rfc822 format available.Message #20 received at 79708 <at> debbugs.gnu.org (full text, mbox):
From: "Paul D. Nelson" <ultrono <at> gmail.com> To: Al Haji-Ali <abdo.haji.ali <at> gmail.com> Cc: 79708 <at> debbugs.gnu.org Subject: Re: bug#79708: 14.1.0; [PATCH] New feature: preview-point Date: Sat, 01 Nov 2025 22:39:41 +0100
Hi Al, I had another thought about how preview-point could be structured. It currently combines two somewhat orthogonal features: (a) Previews away from point are no longer displayed at all. (b) We gain further flexibility in how we can display the preview at point -- before the TeX source, after the TeX source, or in a buframe. I think (b) makes sense and would be useful, independent of (a). Conceptually, we could view this as a more flexible form of preview-leave-open-previews-visible, which currently only allows the preview to be displayed before the TeX source. One way to decouple (a) and (b) would be to: - Control (a) via a new defcustom, preview-hide-away-from-point. - Control (b) by allowing preview-leave-open-previews-visible to take new values (e.g., 'after, 'buframe). That setting would then play the role currently played by preview-point. To display previews at point with buframe, one would do (setopt preview-leave-open-previews-visible 'buframe) To recover the current preview-point behavior, one would additionally do (setopt preview-hide-away-from-point t) WDYT? Does it reasonable to you to separate these features? Thanks, best, Paul
bug-auctex <at> gnu.org:bug#79708; Package auctex.
(Sun, 02 Nov 2025 12:51:02 GMT) Full text and rfc822 format available.Message #23 received at 79708 <at> debbugs.gnu.org (full text, mbox):
From: Al Haji-Ali <abdo.haji.ali <at> gmail.com> To: "Paul D. Nelson" <ultrono <at> gmail.com> Cc: 79708 <at> debbugs.gnu.org Subject: Re: bug#79708: 14.1.0; [PATCH] New feature: preview-point Date: Sun, 02 Nov 2025 13:47:36 +0100
[Message part 1 (text/plain, inline)]
Hi all, (Paul, I answer below to your point). Attached is an updated patch. Following Paul's suggestions, I added two minor modes: - preview-point-mode: is a global minor mode to enable point preview. Display style is controlled through preview-point-display. - preview-point-auto-mode: is a local minor mode to enable auto updating of existing previews and generation of new ones. Generation is controlled via `preview-point-auto-function`. If the function returns a region, that is used instead of relying on `preview-next-border`. As Paul suggested, auto-previewing can probably can become preview-point agnostic once it is thoroughly tested with classical previews. A couple of points: - Currently, I update all previews in the current buffer when toggling `preview-point-mode` so that the mode can be toggled back and forth. This is problematic because other opened buffers will still have the "wrong" previews with the "wrong" local hooks. The main issue is preview-point-mode is not local while the hooks and the previews are. We can either leave it as is, or loop through all open buffers to do the necessary cleanup. I found making preview-point-mode local a bit cumbersome to implement (I never understood what the best practice is to deal with local variables when a master and included files are involved -- I might take another crack at it later). - One thing I wanted to check: Can we rely on the `preview-region' returning the preview process. It calls `preview-generate-preview' which has this documented behaviour, but `preview-region' does not. Perhaps I can add that to the documentation to make it official? On 01/11/2025, Paul D. Nelson wrote: > (a) Previews away from point are no longer displayed at all. > (b) We gain further flexibility in how we can display the preview at > point -- before the TeX source, after the TeX source, or in a buframe. > [...] > WDYT? Does it reasonable to you to separate these features? I think fundamentally, preview-point and the classical preview are different in what they show by default. preview-point shows the source by default, and then shows the preview when the cursor is inside the source. Classical preview shows the preview by default, but then displays the source when the cursor is "inside" the image. Both do not display the hidden content away from point. We could frame the feature as what's being displayed by default, with display-styles for either mode being after-string, before-string or buframe's. However, I suspect this or having (b) as a feature on its own will be of limited value since buframe only really works with preview-point. Displaying the preview in a buframe means that point cannot get "inside" it to show the source in classical preview mode (plus we would have to track the many displayed buframes). We can't of course show the source in a buframe, since that would prevent editing it. So the only flexibility one gets is being able to show the preview in an `after-string`, as well as the current `before-string`, but I am not sure how desired such a feature is. Best regards, -- Al
[preview-New-feature-preview-point.patch (text/x-patch, inline)]
From e2a5062c3d5e1c266533965ee9acb6ce659036df Mon Sep 17 00:00:00 2001
From: Al Haji-Ali <a.hajiali <at> hw.ac.uk>
Date: Tue, 9 Sep 2025 21:19:43 +0100
Subject: [PATCH] preview: New feature, preview-point
* doc/preview-latex.texi: Add docs for preview-point-mode
* preview.el (preview-silent-errors): New local variable.
(preview-point-mode): New globalized minor mode.
(preview-point-display): New custom variables
(preview-point-disabled-face, preview-point-processing-face): New faces.
(preview-point--frame, preview-point--current-overlay): New variables.
(preview-dvipng-image-type): Update doc.
(preview-log-error,preview-reraise-error): Implement silent mode based
on `preview-silent-errors'.
(preview-gs-sentinel, preview-gs-transact): Call `preview-point-refresh'.
(preview-ascent-from-bb): Return 'center when 'preview-point-mode' is
non-nil.
(preview-toggle): Call preview-point activation function.
(preview-disable): Control behaviour based on preview-point-mode.
(preview-map): Add key-binding for `preview-point-mode'.
(preview-mode-setup): Control preview setup based on `preview-point-mode'.
(preview-parse-messages): Restore point before calling place functions.
(preview-point--buframe, preview-point-inside-overlay-p,
preview-point-activate-maybe, preview-point-move-point,
preview-point-updated, preview-point-mode,
preview-point-toggle-auto-refresh, preview-point <at> around <at> write-region,
preview-point--preview-at-point, preview-point-has-preview-p,
preview-point-buf-change): New functions.
(preview-point-auto-mode): New local minor mode.
(preview-point-auto-delay,preview-point-auto-function): New custom variable.
(preview-point-auto): New functions.
Automatic previewing code derived from preview-auto.el (Copyright 2024
FSF, by Paul D. Nelson), adapted and integrated here.
---
NEWS.org | 2 +
doc/preview-latex.texi | 12 +
preview.el | 522 ++++++++++++++++++++++++++++++++++++-----
3 files changed, 472 insertions(+), 64 deletions(-)
diff --git a/NEWS.org b/NEWS.org
index ddfcd55c..4fb0d60e 100644
--- a/NEWS.org
+++ b/NEWS.org
@@ -21,6 +21,8 @@
- Add new function ~preview-dvisvgm-command~ to generate SVG images in
preview.
+- New feature: ~preview-point-mode~ and ~preview-point-auto-mode~.
+
** Changed
- Change the format of the value stored in ~preview-dumped-alist~. Add
diff --git a/doc/preview-latex.texi b/doc/preview-latex.texi
index 19210a35..a2052427 100644
--- a/doc/preview-latex.texi
+++ b/doc/preview-latex.texi
@@ -480,6 +480,18 @@ math (@code{$@dots{}$}), or if your usage of @code{$} conflicts with
@previewlatex{}'s, you can turn off inline math previews. In the
@samp{Preview Latex} group, remove @code{textmath} from
@code{preview-default-option-list} by customizing this variable.
+
+@item Enable preview at point.
+
+Enabling @code{preview-point-mode} restricts the display of previews to
+when the cursor is within a previewable area. The display behaviour is
+controlled by @code{preview-point-display}, which determines whether the
+preview appears before or after the TeX source, or in a temporary frame
+(requires the @code{buframe} package, available on ELPA).
+
+For automatic preview updates or generation, see
+@code{preview-point-auto-mode} and @code{preview-point-auto-function}.
+
@end itemize
@node Known problems, For advanced users, Simple customization, top
diff --git a/preview.el b/preview.el
index 94812886..8eb5cddb 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.")
@@ -456,6 +460,86 @@ set to `postscript'."
:group 'preview-latex
:type 'boolean)
+;;; preview-point customizations and variables.
+(defcustom preview-point-display 'after-string
+ "Specifies where to show the preview.
+
+Can be `before-string', `after-string' to show at before or after the
+TeX code or `buframe' to show in a separate frame (the `buframe' package
+must be installed). Can also be \\='(buframe FN-POS FRAME-PARAMETERS
+BUF-PARAMETERS) where FN-POS is a position function (default is
+`buframe-position-right-of-overlay') and FRAME-PARAMETERS is an alist of
+additional frame parameters, default is nil and BUF-PARAMETERS is an
+alist of buffer local variables and their values."
+ :type '(choice
+ (const :tag "Before string" before-string)
+ (const :tag "After string (default)" after-string)
+ (const :tag "On frame" buframe)
+ (list :tag "On frame with explicit parameters"
+ (function :tag "Position function")
+ (alist :tag "Frame parameters")
+ (alist :tag "Buffer parameters"))))
+
+(define-minor-mode preview-point-mode
+ "Show the preview at point."
+ :group 'preview
+ :global t
+ :init-value nil
+
+ (if preview-point-mode
+ (when (member #'preview-move-point post-command-hook)
+ (remove-hook 'pre-command-hook #'preview-mark-point t)
+ (remove-hook 'post-command-hook #'preview-move-point t)
+ (add-hook 'post-command-hook #'preview-point-move-point nil t))
+ (when (member #'preview-point-move-point post-command-hook)
+ ;; First hide the current preview, if any
+ (when preview-point--current-overlay
+ (preview-point-activate-maybe preview-point--current-overlay nil))
+ (remove-hook 'post-command-hook #'preview-point-move-point t)
+ (add-hook 'pre-command-hook #'preview-mark-point nil t)
+ (add-hook 'post-command-hook #'preview-move-point nil t)))
+
+ ;; Go through all the preview overlays in the current buffer and reset
+ ;; them to be consistent with the current value of preview-point-mode
+ (dolist (ov (overlays-in (point-min) (point-max)))
+ (and (overlay-get ov 'preview-state)
+ (let ((strings (overlay-get ov 'strings)))
+ (dolist (prop '(display keymap mouse-face help-echo))
+ ;; The overlay inherits the properties of the string
+ (overlay-put ov prop
+ (if preview-point-mode
+ nil
+ (get-text-property 0 prop (car strings)))))
+ (dolist (prop '(before-string after-string face))
+ (overlay-put ov prop nil))
+ ;; CDR of string should be rebuilt based on mode.
+ (setcdr (overlay-get ov 'strings) nil)
+ (when (memq (overlay-get ov 'preview-state) '(active inactive))
+ ;; Reset preview to neutral state of each mode.
+ (overlay-put ov 'preview-state
+ (if preview-point-mode 'inactive 'active)))
+ (when (eq (overlay-get ov 'preview-state) 'disabled)
+ ;; Redisable preview -- starting from a active state.
+ (overlay-put ov 'preview-state 'active)
+ (preview-toggle ov nil)
+ (preview-disable ov))))))
+
+(defface preview-point-disabled-face
+ '((t (:inherit shadow)))
+ "Face used when preview is disabled."
+ :group 'preview)
+
+(defface preview-point-processing-face
+ '((t (:inherit preview-point-disabled-face)))
+ "Face used when preview is processing."
+ :group 'preview)
+
+(defvar preview-point--frame nil
+ "The last active preview popup frame.")
+
+(defvar preview-point--current-overlay nil
+ "The overlay currently shown in the preview popup frame.")
+
(defun preview-string-expand (arg &optional separator)
"Expand ARG as a string.
It can already be a string. Or it can be a list, then it is
@@ -629,7 +713,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)
@@ -638,7 +723,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)))))
@@ -709,6 +798,8 @@ and tries to restart Ghostscript if necessary."
(let* ((err (concat preview-gs-answer "\n"
(process-name process) " " string))
(ov (preview-gs-behead-outstanding err)))
+ (when ov
+ (preview-point-updated ov))
(when (and (null ov) preview-gs-queue)
(save-excursion
(goto-char (if (marker-buffer (process-mark process))
@@ -1430,16 +1521,16 @@ Try \\[ps-run-start] \\[ps-run-buffer] and \
(ps-open
(let ((string
(concat
- (mapconcat #'shell-quote-argument
- (append (list
- preview-gs-command
- outfile)
- preview-gs-command-line)
- " ")
- "\nGS>"
- preview-gs-init-string
- (aref (overlay-get ov 'queued) 1)
- err)))
+ (mapconcat #'shell-quote-argument
+ (append (list
+ preview-gs-command
+ outfile)
+ preview-gs-command-line)
+ " ")
+ "\nGS>"
+ preview-gs-init-string
+ (aref (overlay-get ov 'queued) 1)
+ err)))
(lambda () (interactive "@") (preview-mouse-open-error string))))
(str
(preview-make-clickable
@@ -1494,7 +1585,8 @@ given as ANSWER."
(preview-ascent-from-bb
bbox)
(aref preview-colors 2))))
- (overlay-put ov 'queued nil)))))
+ (overlay-put ov 'queued nil)
+ (preview-point-updated ov)))))
(while (and (< (length preview-gs-outstanding)
preview-gs-outstanding-limit)
(setq ov (pop preview-gs-queue)))
@@ -1706,19 +1798,22 @@ icon is cached in the property list of the SYMBOL."
(defun preview-ascent-from-bb (bb)
"This calculates the image ascent from its bounding box.
The bounding box BB needs to be a 4-component vector of
-numbers (can be float if available)."
+numbers (can be float if available).
+
+If `preview-point-mode' is non-nil, this simply returns \\='center."
;; baseline is at 1in from the top of letter paper (11in), so it is
;; at 10in from the bottom precisely, which is 720 in PostScript
;; coordinates. If our bounding box has its bottom not above this
;; line, and its top above, we can calculate a useful ascent value.
;; If not, something is amiss. We just use 100 in that case.
-
- (let ((bottom (aref bb 1))
- (top (aref bb 3)))
- (if (and (<= bottom 720)
- (> top 720))
- (round (* 100.0 (/ (- top 720.0) (- top bottom))))
- 100)))
+ (if preview-point-mode
+ 'center
+ (let ((bottom (aref bb 1))
+ (top (aref bb 3)))
+ (if (and (<= bottom 720)
+ (> top 720))
+ (round (* 100.0 (/ (- top 720.0) (- top bottom))))
+ 100))))
(defface preview-face '((((background dark))
(:background "dark slate gray"))
@@ -2090,26 +2185,28 @@ purposes."
'active
'inactive))
(strings (overlay-get ov 'strings)))
- (unless (eq (overlay-get ov 'preview-state) 'disabled)
- (overlay-put ov 'preview-state preview-state)
- (if (eq preview-state 'active)
- (progn
- (overlay-put ov 'category 'preview-overlay)
- (if (eq (overlay-start ov) (overlay-end ov))
- (overlay-put ov 'before-string (car strings))
- (dolist (prop '(display keymap mouse-face help-echo))
- (overlay-put ov prop
- (get-text-property 0 prop (car strings))))
- (overlay-put ov 'before-string nil))
- (overlay-put ov 'face nil))
- (dolist (prop '(display keymap mouse-face help-echo))
- (overlay-put ov prop nil))
- (overlay-put ov 'face 'preview-face)
- (unless (cdr strings)
- (setcdr strings (preview-inactive-string ov)))
- (overlay-put ov 'before-string (cdr strings)))
- (if old-urgent
- (apply #'preview-add-urgentization old-urgent))))
+ (if preview-point-mode
+ (preview-point-activate-maybe ov arg)
+ (unless (eq (overlay-get ov 'preview-state) 'disabled)
+ (overlay-put ov 'preview-state preview-state)
+ (if (eq preview-state 'active)
+ (progn
+ (overlay-put ov 'category 'preview-overlay)
+ (if (eq (overlay-start ov) (overlay-end ov))
+ (overlay-put ov 'before-string (car strings))
+ (dolist (prop '(display keymap mouse-face help-echo))
+ (overlay-put ov prop
+ (get-text-property 0 prop (car strings))))
+ (overlay-put ov 'before-string nil))
+ (overlay-put ov 'face nil))
+ (dolist (prop '(display keymap mouse-face help-echo))
+ (overlay-put ov prop nil))
+ (overlay-put ov 'face 'preview-face)
+ (unless (cdr strings)
+ (setcdr strings (preview-inactive-string ov)))
+ (overlay-put ov 'before-string (cdr strings)))
+ (if old-urgent
+ (apply #'preview-add-urgentization old-urgent)))))
(if event
(preview-restore-position
ov
@@ -2340,11 +2437,21 @@ active (`transient-mark-mode'), it is run through `preview-region'."
(unless preview-leave-open-previews-visible
(overlay-put ovr 'preview-image nil))
(overlay-put ovr 'timestamp nil)
- (setcdr (overlay-get ovr 'strings) (preview-disabled-string ovr))
- (unless preview-leave-open-previews-visible
- (preview-toggle ovr))
+
+ (setcdr (overlay-get ovr 'strings)
+ (unless preview-point-mode
+ ;; It will be updated later in `preview-toggle'.
+ (preview-disabled-string ovr)))
+
+ (unless preview-point-mode
+ (unless preview-leave-open-previews-visible
+ (preview-toggle ovr)
+ ;; Only delete the files if we are not using the images
+ (preview--delete-overlay-files ovr)))
(overlay-put ovr 'preview-state 'disabled)
- (preview--delete-overlay-files ovr))
+ (when preview-point-mode
+ ;; Toggle/update preview (maybe) after setting state
+ (preview-toggle ovr t)))
(defun preview--delete-overlay-files (ovr)
"Delete files owned by OVR."
@@ -2618,7 +2725,8 @@ Deletes the dvi file when finished."
(preview-ascent-from-bb
(aref queued 0))
(aref preview-colors 2)))
- (overlay-put ov 'queued nil))
+ (overlay-put ov 'queued nil)
+ (preview-point-updated ov))
(push filename oldfiles)
;; Do note modify `filenames' if we are not replacing
;; it, to avoid orphaning files. The filenames will be
@@ -2964,6 +3072,7 @@ See description of `TeX-command-list' for details."
(defvar preview-map
(let ((map (make-sparse-keymap)))
+ (define-key map "\C-t" #'preview-point-mode)
(define-key map "\C-p" #'preview-at-point)
(define-key map "\C-r" #'preview-region)
(define-key map "\C-b" #'preview-buffer)
@@ -3210,8 +3319,10 @@ pp")
(defun preview-mode-setup ()
"Setup proper buffer hooks and behavior for previews."
(setq-local desktop-save-buffer #'desktop-buffer-preview-misc-data)
- (add-hook 'pre-command-hook #'preview-mark-point nil t)
- (add-hook 'post-command-hook #'preview-move-point nil t)
+ (if preview-point-mode
+ (add-hook 'post-command-hook #'preview-point-move-point nil t)
+ (add-hook 'pre-command-hook #'preview-mark-point nil t)
+ (add-hook 'post-command-hook #'preview-move-point nil t))
(when (TeX-buffer-file-name)
(let* ((filename (expand-file-name (TeX-buffer-file-name)))
format-cons)
@@ -3803,22 +3914,28 @@ name(\\([^)]+\\))\\)\\|\
(funcall preview-find-end-function
region-beg)
(point)))
- (ovl (preview-place-preview
- snippet
- region-beg
- region-end
- (preview-TeX-bb box)
- (cons lcounters counters)
- tempdir
- (cdr open-data))))
- (setq close-data (nconc ovl close-data))
- (when (and preview-protect-point
- (<= region-beg point-current)
- (< point-current region-end))
- ;; Temporarily open the preview if it
- ;; would bump the point.
- (preview-toggle (car ovl))
- (push (car ovl) preview-temporary-opened)))
+ ovl)
+ (save-excursion
+ ;; Restore point to current one before
+ ;; placing preview
+ (goto-char point-current)
+ (setq ovl (preview-place-preview
+ snippet
+ region-beg
+ region-end
+ (preview-TeX-bb box)
+ (cons lcounters counters)
+ tempdir
+ (cdr open-data)))
+ (setq close-data (nconc ovl close-data))
+ (when (and preview-protect-point
+ (<= region-beg point-current)
+ (< point-current region-end)
+ (not preview-point-mode))
+ ;; Temporarily open the preview if it
+ ;; would bump the point.
+ (preview-toggle (car ovl))
+ (push (car ovl) preview-temporary-opened))))
(with-current-buffer run-buffer
(preview-log-error
(list 'error
@@ -4426,6 +4543,283 @@ If not a regular release, the date of the last change.")
(insert "\n")))
(error nil)))
+
+;;; preview-point
+
+;; Buframe functions, it will be assumed that buframe is installed so
+;; that it can be required.
+(declare-function buframe-position-right-of-overlay "ext:buframe"
+ (frame ov &optional location))
+(declare-function buframe-make-buffer "ext:buframe" (name &optional locals))
+(declare-function buframe-make "ext:buframe"
+ (frame-or-name fn-pos buffer &optional
+ parent-buffer parent-frame parameters))
+(declare-function buframe-disable "ext:buframe" (frame-or-name
+ &optional enable))
+
+(defun preview-point--buframe (show ov str)
+ "Show or hide a a buframe popup with STR around overlay OV."
+ (require 'buframe)
+ (if show
+ (let* ((buf (buframe-make-buffer " *preview-point-buffer*"
+ (car-safe
+ (cddr (cdr-safe
+ preview-point-display)))))
+ (max-image-size
+ (if (integerp max-image-size)
+ max-image-size
+ ;; Set the size max-image-size using the current frame
+ ;; since the popup frame will be small to begin with
+ (* max-image-size (frame-width)))))
+ (with-current-buffer buf
+ (let (buffer-read-only)
+ (with-silent-modifications
+ (erase-buffer)
+ (insert (propertize str
+ 'help-echo nil
+ 'keymap nil
+ 'mouse-face nil))
+ (goto-char (point-min)))))
+ (setq preview-point--frame
+ (buframe-make
+ "preview-point"
+ (lambda (frame)
+ (when preview-point--current-overlay
+ (funcall
+ (or (car-safe (cdr-safe preview-point-display))
+ #'buframe-position-right-of-overlay)
+ frame preview-point--current-overlay)))
+ buf
+ (overlay-buffer ov)
+ (window-frame)
+ (car-safe (cdr (cdr-safe preview-point-display))))))
+ (buframe-disable preview-point--frame)))
+
+(defun preview-point-inside-overlay-p (ov &optional pt)
+ "Return PT if inside overlay OV, nil otherwise.
+If PT is nil, use point of OV's buffer."
+ (or pt
+ (setq pt (and
+ (overlay-buffer ov)
+ (with-current-buffer (overlay-buffer ov)
+ (point)))))
+ (and
+ (eq (overlay-buffer ov) (window-buffer))
+ (>= pt (overlay-start ov))
+ (< pt (overlay-end ov))
+ pt))
+
+(defun preview-point-activate-maybe (ov &optional arg)
+ "Toggle visibility of preview overlay OV.
+If ARG is non-nil, deactivate overlay instead.
+
+If (point) is not inside OV, then a call to activate the overlay is
+ignored. If the preview is disabled, the disabled symbol is shown when
+activated, otherwise the preview state is not changed."
+ (let* ((pt (and
+ (overlay-buffer ov)
+ (with-current-buffer (overlay-buffer ov)
+ (point))))
+ (strings (overlay-get ov 'strings))
+ (construct-p (overlay-get ov 'queued))
+ (disabled-p (eq (overlay-get ov 'preview-state) 'disabled))
+ (inside-p (preview-point-inside-overlay-p ov pt))
+ (str (car strings))
+ (show (and arg inside-p)))
+ ;; Update `strings' cdr, if needed
+ (when (or construct-p disabled-p)
+ (unless (cdr (overlay-get ov 'strings))
+ (setcdr (overlay-get ov 'strings)
+ (cond
+ (disabled-p
+ (if preview-leave-open-previews-visible
+ (propertize str
+ 'face
+ 'preview-point-disabled-face)
+ (preview-disabled-string ov)))
+ (construct-p
+ (if preview-leave-open-previews-visible
+ (propertize str
+ 'face
+ 'preview-point-processing-face)
+ (propertize "x" 'display preview-nonready-icon))))))
+ (setq str (cdr (overlay-get ov 'strings))))
+
+ (unless disabled-p
+ (overlay-put ov 'preview-state
+ (if show
+ 'active
+ 'inactive)))
+
+ (when show
+ (overlay-put ov 'category 'preview-overlay))
+
+ (when (or show
+ (eq preview-point--current-overlay ov))
+ (setq preview-point--current-overlay (and show ov))
+ (if (or (eq preview-point-display 'buframe)
+ (eq (car-safe preview-point-display) 'buframe))
+ (preview-point--buframe show ov str)
+ (overlay-put ov preview-point-display (and show str))))))
+
+(defun preview-point-move-point ()
+ "Toggle previews as point enters or leaves overlays."
+ (preview-check-changes)
+ (let* ((pt (point))
+ (lst (overlays-at pt)))
+ ;; Hide any open overlays
+ (when-let* ((ov preview-point--current-overlay))
+ (and (overlay-buffer ov)
+ (overlay-get ov 'preview-state)
+ (not (eq (overlay-get ov 'preview-state) 'inactive))
+ (when (not (preview-point-inside-overlay-p
+ ov pt))
+ (preview-point-activate-maybe ov nil))))
+
+ ;; Show all overlays under point
+ (dolist (ovr lst)
+ (let ((state (overlay-get ovr 'preview-state)))
+ (when ;; (eq (overlay-get ovr 'preview-state) 'inactive)
+ (and (and state (not (eq state 'active)))
+ (not (eq ovr preview-point--current-overlay)))
+ (preview-point-activate-maybe ovr t))))))
+
+(defun preview-point-updated (ov)
+ "Mark preview OV as updated.
+Has effect only if `preview-point-mode' is active."
+ (when preview-point-mode
+ (preview-point-activate-maybe ov t)))
+
+;;; preview-point -- Auto-preview
+(defcustom preview-point-auto-delay 0.1
+ "Delay in seconds for automatic preview timer."
+ :type 'number)
+(defcustom preview-point-auto-function nil
+ "Function to determine if a preview should be created at point.
+
+When `preview-point-auto-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-region' will be called.
+
+If the function returns a cons, it should be of the form (BEGIN . END),
+which will be used as arguments for `preview-region', otherwise the
+region is determined automatically."
+ :type 'symbol)
+(defvar preview-point-force-update--debounce-timer nil)
+
+(define-minor-mode preview-point-auto-mode
+ "Enable automatic refreshing and generation of previews.
+When enabled, existing previews are automatically updated when there
+text is changed. Moreover, previews are automatically created whenever
+`preview-point-auto-function' returns a non-nil value at point."
+ :group 'preview
+ :init-value nil
+ (if preview-point-auto-mode
+ (progn
+ (add-hook 'after-change-functions #'preview-point-buf-change nil t)
+ (add-hook 'post-command-hook #'preview-point-auto nil t)
+ (preview-point-buf-change))
+ (remove-hook 'after-change-functions #'preview-point-buf-change t)
+ (remove-hook 'post-command-hook #'preview-point-auto t)))
+
+(defun preview-point-auto ()
+ "Mark current region for preview, if not already there."
+ (when (and
+ preview-point-mode
+ (not (preview-point-has-preview-p))
+ preview-point-auto-function
+ (funcall preview-point-auto-function))
+ (preview-point-force-update (point) (current-buffer) t)))
+
+(defun preview-point <at> around <at> write-region (orig-fun &rest args)
+ "Advice around `write-region' to suppress messages.
+ORIG-FUN is the original function. ARGS are its arguments."
+ (let ((noninteractive t)
+ (inhibit-message t)
+ message-log-max)
+ (apply orig-fun args)))
+
+(defun preview-point-force-update (pos-region buffer &optional debounce)
+ "Update preview at POS-REGION in BUFFER.
+
+POS-REGION can be a position, or a cons (BEGIN . END) signifying the
+region for which the previous should be updated. When DEBOUNCE is
+non-nil, the call is debounced using an idle timer. This also happens
+automatically when there is an ongoing compilation process."
+ (interactive (list (point) (current-buffer)))
+
+ (when preview-point-force-update--debounce-timer
+ (cancel-timer preview-point-force-update--debounce-timer)
+ (setq preview-point-force-update--debounce-timer nil))
+
+ (when (buffer-live-p buffer)
+ (unless debounce
+ (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
+ ;; Force de-bouncing
+ (when (and preview-current-region
+ (not preview-abort-flag)
+ ;; (< beg (cdr preview-current-region))
+ )
+ (progn
+ (ignore-errors (TeX-kill-job))
+ (setq preview-abort-flag t)))
+ (with-local-quit (accept-process-output cur-process))
+ (setq debounce t))
+ (let ((TeX-suppress-compilation-message t)
+ (save-silently t))
+ (advice-add 'write-region :around
+ #'preview-point <at> around <at> write-region)
+ (unwind-protect
+ ;; If we are working in a file buffer that is not a tex file,
+ ;; then we want preview-region to operate in "non-file" mode,
+ ;; where it passes "<none>" to TeX-region-create.
+ (save-excursion
+ ;; TODO: Check if we can rely on the `preview-region'
+ ;; returning the process. It calls
+ ;; `preview-generate-preview' which has this documented
+ ;; behaviour, but not `preview-region'.
+ (unless (consp pos-region)
+ (goto-char pos-region)
+ (setq pos-region
+ (cons (preview-next-border t)
+ (preview-next-border nil))))
+ (let ((process (preview-region (car pos-region)
+ (cdr pos-region))))
+ (with-current-buffer (process-buffer process)
+ (setq-local preview-silent-errors t))))
+ (advice-remove 'write-region
+ #'preview-point <at> around <at> write-region))))))
+
+ (when debounce
+ (setq preview-point-force-update--debounce-timer
+ (run-with-idle-timer
+ preview-point-auto-delay nil
+ #'preview-point-force-update
+ pos-region buffer)))))
+
+(defun preview-point-has-preview-p (&optional pt)
+ "Return non-nil if PT has a preview overlay."
+ (cl-find-if
+ (lambda (ov) (overlay-get ov 'preview-state))
+ (overlays-at (or pt (point)))))
+
+(defun preview-point-buf-change (&rest _)
+ "Run preview at point if there is a preview overlay."
+ (let (region)
+ (when (and preview-point-mode
+ (or (preview-point-has-preview-p)
+ (and preview-point-auto-function
+ (setq region (funcall preview-point-auto-function)))))
+ (preview-point-force-update
+ (if (consp region) region (point)) (current-buffer) t))))
+
;;;###autoload
(defun preview-report-bug () "Report a bug in the preview-latex package."
(interactive)
--
2.50.1 (Apple Git-155)
bug-auctex <at> gnu.org:bug#79708; Package auctex.
(Sun, 02 Nov 2025 16:41:01 GMT) Full text and rfc822 format available.Message #26 received at 79708 <at> debbugs.gnu.org (full text, mbox):
From: "Paul D. Nelson" <ultrono <at> gmail.com> To: Al Haji-Ali <abdo.haji.ali <at> gmail.com> Cc: 79708 <at> debbugs.gnu.org Subject: Re: bug#79708: 14.1.0; [PATCH] New feature: preview-point Date: Sun, 02 Nov 2025 17:40:30 +0100
Hi Al,
Responding just to the structural question for now. I think I
miscommunicated:
> We could frame the feature as what's being displayed by default, with
> display-styles for either mode being after-string, before-string or
> buframe's.
I wasn't proposing to change what's displayed *by default* for all
previews, but rather what's shown *after entering an existing preview*.
The options would include:
- just the construction symbol and the tex code (default behavior in
AUCTeX)
- the preview before the tex code (current behavior of
preview-leave-open-previews-visible t)
- the preview after the tex code
- a buframe showing the preview
Does that clarify? Could either shoehorn this option into
preview-leave-open-previews-visible, or absorb that into a new defcustom
('preview-reveal-display'?) taking the values 'none, 'after, 'before,
'buframe. The issue is orthogonal to preview-point vs. normal -- it's
just about "reveal behavior on entry". Note that we're not trying to
edit inside the preview image - we're just choosing how the preview is
displayed when the tex source is made visible after you enter the
overlay.
Does that clarify? I think this would be useful (e.g., I would try it
out with traditional previews).
Paul
bug-auctex <at> gnu.org:bug#79708; Package auctex.
(Sun, 02 Nov 2025 20:01:02 GMT) Full text and rfc822 format available.Message #29 received at 79708 <at> debbugs.gnu.org (full text, mbox):
From: Al Haji-Ali <abdo.haji.ali <at> gmail.com> To: "Paul D. Nelson" <ultrono <at> gmail.com> Cc: 79708 <at> debbugs.gnu.org Subject: Re: bug#79708: 14.1.0; [PATCH] New feature: preview-point Date: Sun, 02 Nov 2025 20:55:56 +0100
Hello Paul,
Apologies, there's something I don't fully understand. Below is an
attempt at explaining what I currently understand.
On 02/11/2025, Paul D. Nelson wrote:
>
> - just the construction symbol and the tex code (default behavior in
> AUCTeX)
>
> - the preview before the tex code (current behavior of
> preview-leave-open-previews-visible t)
> - the preview after the tex code
My understanding of the `preview-leave-open-previews-visible` option is
that the previews remain open only when the tex code is changed rather than
being replaced with a sign. If the tex source is not changed, the
previews are not kept open. In particular, this shouldn't affect the
position of the image AFAIK.
So, I assume then that you don't mean changing the traditional preview
style after all? But rather have a mode which always show the preview
before or after the tex source with the point movement not affecting
previews.
> - a buframe showing the preview
This has to be point-specific, otherwise it would require showing too
many frames and I don't think it would look good to always show and move
them around.
In summary, here are the behaviours we can have:
- classical preview, before-string (open on cursor going inside image).
- classical preview, after-string (open on cursor going inside image) -- New, needed?
- preview-point with {after,before}-string or buframe.
- a new mode where previews are not affected by cursor movement, and
previews are always shown as {before,after}-string.
If my understanding is correct of your proposal, then indeed one can have two options, let's say:
- preview-display: 'preview, 'src, 'both
- preview-display-style: 'after-string, 'before-string, 'buframe
with 'buframe being only supported when `preview-display` is `'src`.
Here:
- preview-display='src is the preview-point style.
- preview-display='preview: is the current preview style.
- preview-display='both: is the new style you want where both source and preview are always shown and point movement does not affect them.
If my understanding is correct, it shouldn't be too difficult to implement these, I think.
Best regards,
-- Al
bug-auctex <at> gnu.org:bug#79708; Package auctex.
(Sun, 02 Nov 2025 21:25:02 GMT) Full text and rfc822 format available.Message #32 received at 79708 <at> debbugs.gnu.org (full text, mbox):
From: "Paul D. Nelson" <ultrono <at> gmail.com> To: Al Haji-Ali <abdo.haji.ali <at> gmail.com> Cc: 79708 <at> debbugs.gnu.org Subject: Re: bug#79708: 14.1.0; [PATCH] New feature: preview-point Date: Sun, 02 Nov 2025 22:24:45 +0100
Hi Al,
>> - the preview before the tex code (current behavior of
>> preview-leave-open-previews-visible t)
>> - the preview after the tex code
> My understanding of the `preview-leave-open-previews-visible` option is
> that the previews remain open only when the tex code is changed rather than
> being replaced with a sign. If the tex source is not changed, the
> previews are not kept open. In particular, this shouldn't affect the
> position of the image AFAIK.
The main effect of preview-leave-open-previews-visible isn't tied to
whether the tex source has been modified, but is rather that when point
enters a preview overlay, the preview remains visible instead of
collapsing to the construction symbol.
Let me restate the proposal using your terminology and proposed setting
'preview-display-style' (for which the 'both option is not what I had in
mind, but could also be considered). Two independent knobs:
- preview-display-style ('preview, 'src): controls what's shown for
previews away from point, that the cursor is *not* inside.
- preview-reveal-display ('none, 'after, 'before, 'buframe). What to
show when point enters a previewed region (i.e., the overlay or the
underlying tex source):
- 'none means just show the tex source and the construction sign
- 'before means show the preview before the tex source while editing
- 'after means show the preview after the tex source while editing
- 'buframe means to show the preview in a buframe while editing
Let's translate current behaviors to the above setup:
Traditional preview with preview-leave-open-previews-visible nil:
(setopt preview-display-style 'preview)
(setopt preview-reveal-display 'none)
Traditional preview with preview-leave-open-previews-visible t:
(setopt preview-display-style 'preview)
(setopt preview-reveal-display 'before)
(In particular, if this proposal makes sense, then I think
preview-reveal-display could supersede
preview-leave-open-previews-visible.)
preview-point with buframe:
(setopt preview-display-style 'src)
(setopt preview-reveal-display 'buframe)
One benefit of separating these concerns is that we could keep
traditional preview behavior away from point while using a buframe for
live editing of tex source:
(setopt preview-display-style 'preview)
(setopt preview-reveal-display 'buframe)
We could similarly position the preview after the tex source, if
desired.
Does that sound consistent with what you had in mind?
Thanks, best,
Paul
bug-auctex <at> gnu.org:bug#79708; Package auctex.
(Mon, 03 Nov 2025 07:58:01 GMT) Full text and rfc822 format available.Message #35 received at 79708 <at> debbugs.gnu.org (full text, mbox):
From: Al Haji-Ali <abdo.haji.ali <at> gmail.com> To: "Paul D. Nelson" <ultrono <at> gmail.com> Cc: 79708 <at> debbugs.gnu.org Subject: Re: bug#79708: 14.1.0; [PATCH] New feature: preview-point Date: Mon, 03 Nov 2025 08:57:06 +0100
On 02/11/2025, Paul D. Nelson wrote:
> The main effect of preview-leave-open-previews-visible isn't tied to
> whether the tex source has been modified, but is rather that when point
> enters a preview overlay, the preview remains visible instead of
> collapsing to the construction symbol.
Hmmm... I am not sure what I am missing. On my setup, the construction
symbol only appears when the source is modified. If I open the preview
by having the cursor "go into" the preview image, then navigate away
from the source, the preview is collapsed again if I don't modify the
source.
The documentation is also unclear, because the first part of
`preview-leave-open-previews-visible` leans toward what you say:
--8<---------------cut here---------------start------------->8---
Whether to leave previews visible when they are opened.
If nil, then the TeX preview icon is used when the preview is opened.
If non-nil, then the preview image remains visible. In either case, the
TeX code appears either below or to the right of the displayed graphic.
--8<---------------cut here---------------end--------------->8---
but then the next part is what I am seeing:
--8<---------------cut here---------------start------------->8---
If you enable this option, the preview image doesn't turn into
construction sign temporarily when you edit the underlying LaTeX code
and regenerate the preview; it is just replaced by updated image when
ready. This behavior suppresses flicker in the appearance.
--8<---------------cut here---------------end--------------->8---
> Let me restate the proposal using your terminology and proposed setting
> 'preview-display-style' (for which the 'both option is not what I had in
> mind, but could also be considered). Two independent knobs:
>
> - preview-display-style ('preview, 'src): controls what's shown for
> previews away from point, that the cursor is *not* inside.
>
> - preview-reveal-display ('none, 'after, 'before, 'buframe). What to
> show when point enters a previewed region (i.e., the overlay or the
> underlying tex source):
>
> - 'none means just show the tex source and the construction sign
>
> - 'before means show the preview before the tex source while editing
>
> - 'after means show the preview after the tex source while editing
>
> - 'buframe means to show the preview in a buframe while editing
>
OK, this makes it clearer somewhat. Though see above regarding how
modification of the TeX source changes behaviour (at least in my
setup). You also mention "while editing", so what happens when not
editing?
Also, the placement of the construction sign can be before or after the
source, just like the preview (in fact that's what preview-point does as
well when preview-leave-open-previews-visible is nil).
> Let's translate current behaviors to the above setup:
>
> Traditional preview with preview-leave-open-previews-visible nil:
>
> (setopt preview-display-style 'preview)
> (setopt preview-reveal-display 'none)
I am gonna assume you mean that while editing or during the generation
of the preview the construction sign appears (before or after?). What
happens when the preview is ready?
> One benefit of separating these concerns is that we could keep
> traditional preview behavior away from point while using a buframe for
> live editing of tex source:
>
> (setopt preview-display-style 'preview)
> (setopt preview-reveal-display 'buframe)
This is what I was trying to say. I think using a buframe for source
editing is not really tenable and would be too difficult to get
right.
Overall, I am of the opinion that (modulo some forward-thinking
introduction of the options) we do not over-complicate the current
implementation at this point by introducing more modes of operation.
Best regards,
-- Al
bug-auctex <at> gnu.org:bug#79708; Package auctex.
(Mon, 03 Nov 2025 09:17:02 GMT) Full text and rfc822 format available.Message #38 received at 79708 <at> debbugs.gnu.org (full text, mbox):
From: "Paul D. Nelson" <ultrono <at> gmail.com> To: Al Haji-Ali <abdo.haji.ali <at> gmail.com> Cc: 79708 <at> debbugs.gnu.org Subject: Re: bug#79708: 14.1.0; [PATCH] New feature: preview-point Date: Mon, 03 Nov 2025 10:16:34 +0100
> Hmmm... I am not sure what I am missing. On my setup, the construction
> symbol only appears when the source is modified. If I open the preview
> by having the cursor "go into" the preview image, then navigate away
> from the source, the preview is collapsed again if I don't modify the
> source.
>
> The documentation is also unclear, because the first part of
> `preview-leave-open-previews-visible` leans toward what you say:
>
> --8<---------------cut here---------------start------------->8---
> Whether to leave previews visible when they are opened.
>
> If nil, then the TeX preview icon is used when the preview is opened.
> If non-nil, then the preview image remains visible. In either case, the
> TeX code appears either below or to the right of the displayed graphic.
> --8<---------------cut here---------------end--------------->8---
>
> but then the next part is what I am seeing:
>
> --8<---------------cut here---------------start------------->8---
> If you enable this option, the preview image doesn't turn into
> construction sign temporarily when you edit the underlying LaTeX code
> and regenerate the preview; it is just replaced by updated image when
> ready. This behavior suppresses flicker in the appearance.
> --8<---------------cut here---------------end--------------->8---
I may have added to the confusion by writing "construction symbol" (what
shows up when a preview is regenerating) in a few places where I should
have written "TeX symbol" (what shows up when the TeX source is made
visible after point enters a preview).
You're right that the docstring covers two behaviors: (i) what happens
when a preview is revealed, and (ii) what happens when it's regenerated.
I was talking about (i) before. Since you write that the discussion
below clarified things somewhat, I'll focus my response there.
>
>> Let me restate the proposal using your terminology and proposed setting
>> 'preview-display-style' (for which the 'both option is not what I had in
>> mind, but could also be considered). Two independent knobs:
>>
>> - preview-display-style ('preview, 'src): controls what's shown for
>> previews away from point, that the cursor is *not* inside.
>>
>> - preview-reveal-display ('none, 'after, 'before, 'buframe). What to
>> show when point enters a previewed region (i.e., the overlay or the
>> underlying tex source):
>>
>> - 'none means just show the tex source and the construction sign
>>
>> - 'before means show the preview before the tex source while editing
>>
>> - 'after means show the preview after the tex source while editing
>>
>> - 'buframe means to show the preview in a buframe while editing
>>
>
> OK, this makes it clearer somewhat. Though see above regarding how
> modification of the TeX source changes behaviour (at least in my
> setup). You also mention "while editing", so what happens when not
> editing?
When I say "while editing", I mean "when the point enters the TeX
source, so that the user could in principle edit it". Consider how
'preview-point' behaves right now: either the point is inside some TeX
region (that's what I mean by "while editing"), or away from it.
Behavior "when not editing" is controlled by 'preview-display-style'.
>> Let's translate current behaviors to the above setup:
>>
>> Traditional preview with preview-leave-open-previews-visible nil:
>>
>> (setopt preview-display-style 'preview)
>> (setopt preview-reveal-display 'none)
>
> I am gonna assume you mean that while editing or during the generation
> of the preview the construction sign appears (before or after?). What
> happens when the preview is ready?
When the point later exits the TeX source (and, if modification occurs,
after the preview regenerates), the display reverts to what is specified
by 'preview-display-style'.
>> One benefit of separating these concerns is that we could keep
>> traditional preview behavior away from point while using a buframe for
>> live editing of tex source:
>>
>> (setopt preview-display-style 'preview)
>> (setopt preview-reveal-display 'buframe)
> This is what I was trying to say. I think using a buframe for source
> editing is not really tenable and would be too difficult to get
> right.
I think we have a misunderstanding. By "using a buframe for source
editing", I mean:
- The point is in the TeX source, editing the TeX code there.
- The previewed math is (only) displayed in a separate buframe (updating
live as the user edits, if automatic previewing is enabled).
This is what exactly 'preview-point' already does in its current
implementation. (It sounds to me like you thought I was proposing to
have the TeX source in the buframe, which was not my intention; I can
see how you would view that proposal as untenable.)
> Overall, I am of the opinion that (modulo some forward-thinking
> introduction of the options) we do not over-complicate the current
> implementation at this point by introducing more modes of operation.
I don't think I'm proposing to introduce more modes of operation. I'm
just observing that preview-point bundles two orthogonal features: (a)
disabling preview display by default, and (b) richer customization of
how to display the preview at point. Feature (b) would be useful even
without feature (a), so it seems worth decoupling the two and allowing
them to be configured separately. Does that clarify what I had in mind?
Thanks, best,
Paul
bug-auctex <at> gnu.org:bug#79708; Package auctex.
(Mon, 03 Nov 2025 11:31:01 GMT) Full text and rfc822 format available.Message #41 received at 79708 <at> debbugs.gnu.org (full text, mbox):
From: Al Haji-Ali <abdo.haji.ali <at> gmail.com> To: "Paul D. Nelson" <ultrono <at> gmail.com> Cc: 79708 <at> debbugs.gnu.org Subject: Re: bug#79708: 14.1.0; [PATCH] New feature: preview-point Date: Mon, 03 Nov 2025 12:30:18 +0100
On 03/11/2025, Paul D. Nelson wrote: > I may have added to the confusion by writing "construction symbol" (what > shows up when a preview is regenerating) in a few places where I should > have written "TeX symbol" (what shows up when the TeX source is made > visible after point enters a preview). Ah this is finally becoming clear to me. Sorry it took a while and I thank you for your patience. > I don't think I'm proposing to introduce more modes of operation. I'm > just observing that preview-point bundles two orthogonal features: (a) > disabling preview display by default, and (b) richer customization of > how to display the preview at point. Feature (b) would be useful even > without feature (a), so it seems worth decoupling the two and allowing > them to be configured separately. Does that clarify what I had in mind? I largely agree with you, and I am happy for finer control over the behaviour to be added. The new mode of operation I was referring to is when `preview-display-style` is set to 'preview (so that previews away from point are displayed) and `preview-reveal-display` is `buframe`. Presumably the previews away from the cursor are being shown using the 'display' property of the overlay (as is currently done). When the cursor opens the preview, I think you are proposing that the TeX source is displayed in the buffer (by setting 'display to nil) while the preview *moves* to a buframe. When the cursor moves out of the source, the preview moves back into the buffer as a 'display property, correct? If so, don't you think previews moving between buframe and main buffer would be jarring? I am also still unclear what happens in this case when the TeX source is modified. Does the preview return back to the buffer as a 'display property or does the TeX source remain visible (I'd guess the latter is more reasonable)? In any case, if my understanding is correct, this would require new, careful implementation of moving the preview back and forth. Best regards, -- Al
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.