emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
* [PATCH] add a function to only refresh inline images under current headline instead of global buffer
@ 2023-05-15  3:28 Christopher M. Miles
  2023-05-15 11:08 ` Ihor Radchenko
  0 siblings, 1 reply; 40+ messages in thread
From: Christopher M. Miles @ 2023-05-15  3:28 UTC (permalink / raw)
  To: Org mode

[-- Attachment #1: Type: text/plain, Size: 2369 bytes --]


I found a lot of third-part Emacs packages refresh Org source block image result using the API function like this:

#+begin_src emacs-lisp
;; Automatically refresh inline images.
  (add-hook 'org-babel-after-execute-hook
            (defun ob-dall-e--refresh-inline-images ()
              (when org-inline-image-overlays
                (org-redisplay-inline-images))))
#+end_src

The `org-redisplay-inline-images' will refresh whole buffer inline
images. When the buffer is a big Org file, and not all inline images are
display already by default (still image file links under fold status).
Invoking `org-redisplay-inline-images' will cause Emacs suspend a long
time.

So I suggest to add an variant local function of
`org-redisplay-inline-images' which named
`org-redisplay-inline-images-under-headline' that only redisplay inline
images under current headline to solve the issue.

Here is the diff code prototype, Ihor, can you review it? If it's ok, I
will send patch update then.

#+begin_src diff
 (defun org-redisplay-inline-images ()
-  "Assure display of inline images and refresh them."
+  "Assure display of global all inline images in buffer and refresh them.
+
+NOTE: This function will refresh whole buffer inline images, if
+you only want to refresh inline images under headline, suggest to
+use `org-redisplay-inline-images-under-headline' in your hook or advice."
   (interactive)
   (org-toggle-inline-images)
   (unless org-inline-image-overlays
     (org-toggle-inline-images)))
 
+(defun org-redisplay-inline-images-under-headline ()
+  "Assure display of images under current headline and refresh them.
+This function is the suggested to be used in hook or advice."
+  (interactive)
+  (org-with-wide-buffer
+   (org-narrow-to-subtree)
+   ;; If has nested headlines, beg,end only from parent headline
+   ;; to first child headline which reference to upper
+   ;; let-binding `org-next-visible-heading'.
+   (org-display-inline-images
+    nil nil
+    (point-min) (progn (org-next-visible-heading 1) (point)))))
+
#+end_src

-- 

[ stardiviner ]
I try to make every word tell the meaning that I want to express without misunderstanding.

Blog: https://stardiviner.github.io/
IRC(libera.chat, freenode): stardiviner, Matrix: stardiviner
GPG: F09F650D7D674819892591401B5DF1C95AE89AC3

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 487 bytes --]

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] add a function to only refresh inline images under current headline instead of global buffer
  2023-05-15  3:28 [PATCH] add a function to only refresh inline images under current headline instead of global buffer Christopher M. Miles
@ 2023-05-15 11:08 ` Ihor Radchenko
  2023-05-15 13:01   ` Christopher M. Miles
  2023-05-15 14:00   ` [PATCH v2] " Christopher M. Miles
  0 siblings, 2 replies; 40+ messages in thread
From: Ihor Radchenko @ 2023-05-15 11:08 UTC (permalink / raw)
  To: numbchild; +Cc: Org mode

"Christopher M. Miles" <numbchild@gmail.com> writes:

> The `org-redisplay-inline-images' will refresh whole buffer inline
> images. When the buffer is a big Org file, and not all inline images are
> display already by default (still image file links under fold status).
> Invoking `org-redisplay-inline-images' will cause Emacs suspend a long
> time.
>
> So I suggest to add an variant local function of
> `org-redisplay-inline-images' which named
> `org-redisplay-inline-images-under-headline' that only redisplay inline
> images under current headline to solve the issue.
>
> Here is the diff code prototype, Ihor, can you review it? If it's ok, I
> will send patch update then.

I'd prefer something more closely resembling `org-latex-preview'
approach with prefix arguments:

    Toggle preview of the LaTeX fragment at point.
    
    If the cursor is on a LaTeX fragment, create the image and
    overlay it over the source code, if there is none.  Remove it
    otherwise.  If there is no fragment at point, display images for
    all fragments in the current section.  With an active region,
    display images for all fragments in the region.
    
    With a C-u prefix argument ARG, clear images for all fragments
    in the current section.
    
    With a C-u C-u prefix argument ARG, display image for all
    fragments in the buffer.
    
    With a C-u C-u C-u prefix argument ARG, clear image for all
    fragments in the buffer.

`org-toggle-inline-images' should also be changed.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] add a function to only refresh inline images under current headline instead of global buffer
  2023-05-15 11:08 ` Ihor Radchenko
@ 2023-05-15 13:01   ` Christopher M. Miles
  2023-05-15 14:00   ` [PATCH v2] " Christopher M. Miles
  1 sibling, 0 replies; 40+ messages in thread
From: Christopher M. Miles @ 2023-05-15 13:01 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: numbchild, Org mode

[-- Attachment #1: Type: text/plain, Size: 2019 bytes --]


Ihor Radchenko <yantar92@posteo.net> writes:

> "Christopher M. Miles" <numbchild@gmail.com> writes:
>
>> The `org-redisplay-inline-images' will refresh whole buffer inline
>> images. When the buffer is a big Org file, and not all inline images are
>> display already by default (still image file links under fold status).
>> Invoking `org-redisplay-inline-images' will cause Emacs suspend a long
>> time.
>>
>> So I suggest to add an variant local function of
>> `org-redisplay-inline-images' which named
>> `org-redisplay-inline-images-under-headline' that only redisplay inline
>> images under current headline to solve the issue.
>>
>> Here is the diff code prototype, Ihor, can you review it? If it's ok, I
>> will send patch update then.
>
> I'd prefer something more closely resembling `org-latex-preview'
> approach with prefix arguments:
>
>     Toggle preview of the LaTeX fragment at point.
>     
>     If the cursor is on a LaTeX fragment, create the image and
>     overlay it over the source code, if there is none.  Remove it
>     otherwise.  If there is no fragment at point, display images for
>     all fragments in the current section.  With an active region,
>     display images for all fragments in the region.
>     
>     With a C-u prefix argument ARG, clear images for all fragments
>     in the current section.
>     
>     With a C-u C-u prefix argument ARG, display image for all
>     fragments in the buffer.
>     
>     With a C-u C-u C-u prefix argument ARG, clear image for all
>     fragments in the buffer.
>
> `org-toggle-inline-images' should also be changed.

I agree this solution. I will check out latex fragment preview source
code whether I can implement this.

-- 

[ stardiviner ]
I try to make every word tell the meaning that I want to express without misunderstanding.

Blog: https://stardiviner.github.io/
IRC(libera.chat, freenode): stardiviner, Matrix: stardiviner
GPG: F09F650D7D674819892591401B5DF1C95AE89AC3

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 487 bytes --]

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH v2] Re: [PATCH] add a function to only refresh inline images under current headline instead of global buffer
  2023-05-15 11:08 ` Ihor Radchenko
  2023-05-15 13:01   ` Christopher M. Miles
@ 2023-05-15 14:00   ` Christopher M. Miles
  2023-05-16  9:17     ` Ihor Radchenko
  1 sibling, 1 reply; 40+ messages in thread
From: Christopher M. Miles @ 2023-05-15 14:00 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: numbchild, Org mode

[-- Attachment #1: Type: text/plain, Size: 5505 bytes --]


Ihor Radchenko <yantar92@posteo.net> writes:

> "Christopher M. Miles" <numbchild@gmail.com> writes:
>
>> The `org-redisplay-inline-images' will refresh whole buffer inline
>> images. When the buffer is a big Org file, and not all inline images are
>> display already by default (still image file links under fold status).
>> Invoking `org-redisplay-inline-images' will cause Emacs suspend a long
>> time.
>>
>> So I suggest to add an variant local function of
>> `org-redisplay-inline-images' which named
>> `org-redisplay-inline-images-under-headline' that only redisplay inline
>> images under current headline to solve the issue.
>>
>> Here is the diff code prototype, Ihor, can you review it? If it's ok, I
>> will send patch update then.
>
> I'd prefer something more closely resembling `org-latex-preview'
> approach with prefix arguments:
>
>     Toggle preview of the LaTeX fragment at point.
>     
>     If the cursor is on a LaTeX fragment, create the image and
>     overlay it over the source code, if there is none.  Remove it
>     otherwise.  If there is no fragment at point, display images for
>     all fragments in the current section.  With an active region,
>     display images for all fragments in the region.
>     
>     With a C-u prefix argument ARG, clear images for all fragments
>     in the current section.
>     
>     With a C-u C-u prefix argument ARG, display image for all
>     fragments in the buffer.
>     
>     With a C-u C-u C-u prefix argument ARG, clear image for all
>     fragments in the buffer.
>
> `org-toggle-inline-images' should also be changed.

Here is the source code of `org-toggle-inline-images'. I implement this
by reference `org-latex-preview'. I have not write testing, but only
manually tested with Edebug and on actual Org buffer displaying and
disable inline images. The command works fine. Ihor, can you review the code?

#+begin_src emacs-lisp
(defun org-toggle-inline-images (&optional arg include-linked beg end)
  "Toggle the display of inline images at point.
INCLUDE-LINKED is passed to `org-display-inline-images'.

If cursor is on an inline image link, display the inline image.
If there is none, remove it otherwise.
If there is no inline image link at point, display all inline images in the current section.
With an active region, display inline images in the region.

With a `\\[universal-argument]' prefix argument ARG, clear inline
images in the current section.

With a `\\[universal-argument] \\[universal-argument]' prefix
 argument ARG, display all inline images in the buffer.

With a `\\[universal-argument] \\[universal-argument] \
\\[universal-argument]' prefix argument ARG, clear all inline
images in the buffer."
  (interactive "P")
  (cond
   ((not (display-graphic-p)) nil)
   ;; Clear whole buffer inline images.
   ((equal arg '(64))
    (org-remove-inline-images (point-min) (point-max))
    (message "Inline images preview disabled in buffer."))
   ;; Display whole buffer inline images.
   ((equal arg '(16))
    (message "Displaying all inline images in buffer...")
    (org-display-inline-images include-linked nil (point-min) (point-max))
    (message "Displaying all inline images in buffer... done."))
   ;; Clear current section.
   ((equal arg '(4))
    (let* ((beg (if (use-region-p)
                    (region-beginning)
                  (if (org-before-first-heading-p) (point-min)
                    (save-excursion
	              (org-with-limited-levels (org-back-to-heading t) (point))))))
           (end (if (use-region-p)
                    (region-end)
                  (org-with-limited-levels (org-entry-end-position))))
           (inline-images (org--inline-image-overlays beg end)))
      (org-remove-inline-images beg end)
      (message "%d inline images display removed." (length inline-images))))
   ;; Display region selected inline images.
   ((use-region-p)
    (message "Displaying inline images in region...")
    (org-display-inline-images include-linked t (region-beginning) (region-end))
    (message "Displaying inline images in region... done."))
   ;; Toggle display of inline image link at point.
   ((let ((context (org-element-context)))
      (and (memq (org-element-type context) '(link))
	   (let ((beg (org-element-property :begin context))
		 (end (org-element-property :end context)))
	     (if (org--inline-image-overlays beg end)
                 (progn
                   (org-remove-inline-images beg end)
	           (message "Display inline image at point removed."))
	       (org-display-inline-images include-linked t beg end)
	       (message "Displaying inline image at point ... done."))
	     t))))
   ;; Display inline images under current section.
   (t
    (let ((beg (if (org-before-first-heading-p) (point-min)
		 (save-excursion
		   (org-with-limited-levels (org-back-to-heading t) (point)))))
	  (end (org-with-limited-levels (org-entry-end-position))))
      (message "Displaying inline images in section...")
      (org-display-inline-images include-linked t beg end)
      (message "Displaying inline images in section... done.")))))
#+end_src

-- 

[ stardiviner ]
I try to make every word tell the meaning that I want to express without misunderstanding.

Blog: https://stardiviner.github.io/
IRC(libera.chat, freenode): stardiviner, Matrix: stardiviner
GPG: F09F650D7D674819892591401B5DF1C95AE89AC3

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 487 bytes --]

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v2] Re: [PATCH] add a function to only refresh inline images under current headline instead of global buffer
  2023-05-15 14:00   ` [PATCH v2] " Christopher M. Miles
@ 2023-05-16  9:17     ` Ihor Radchenko
  2023-05-16 12:18       ` Christopher M. Miles
  0 siblings, 1 reply; 40+ messages in thread
From: Ihor Radchenko @ 2023-05-16  9:17 UTC (permalink / raw)
  To: Christopher M. Miles; +Cc: Org mode

"Christopher M. Miles" <numbchild@gmail.com> writes:

>> I'd prefer something more closely resembling `org-latex-preview'
>> approach with prefix arguments:
>> ...
>> `org-toggle-inline-images' should also be changed.
>
> Here is the source code of `org-toggle-inline-images'. I implement this
> by reference `org-latex-preview'. I have not write testing, but only
> manually tested with Edebug and on actual Org buffer displaying and
> disable inline images. The command works fine. Ihor, can you review the code?

Unlike `org-latex-preview', here we need to (1) respect active region;
(2) keep the backward compatibility for INCLUDE-LINKED.

For (1), for example, it would make sense to respect region when prefix
argument is C-u and clear images only there. For (2), we need to at
least allow toggling images with description using some prefix argument
(previously, any prefix argument would do).

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v2] Re: [PATCH] add a function to only refresh inline images under current headline instead of global buffer
  2023-05-16  9:17     ` Ihor Radchenko
@ 2023-05-16 12:18       ` Christopher M. Miles
  2023-07-24 11:25         ` Ihor Radchenko
  0 siblings, 1 reply; 40+ messages in thread
From: Christopher M. Miles @ 2023-05-16 12:18 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: Christopher M. Miles, Org mode

[-- Attachment #1: Type: text/plain, Size: 3125 bytes --]


Ihor Radchenko <yantar92@posteo.net> writes:

> "Christopher M. Miles" <numbchild@gmail.com> writes:
>
>>> I'd prefer something more closely resembling `org-latex-preview'
>>> approach with prefix arguments:
>>> ...
>>> `org-toggle-inline-images' should also be changed.
>>
>> Here is the source code of `org-toggle-inline-images'. I implement this
>> by reference `org-latex-preview'. I have not write testing, but only
>> manually tested with Edebug and on actual Org buffer displaying and
>> disable inline images. The command works fine. Ihor, can you review the code?
>
> Unlike `org-latex-preview', here we need to (1) respect active region;
> (2) keep the backward compatibility for INCLUDE-LINKED.
>
> For (1), for example, it would make sense to respect region when prefix
> argument is C-u and clear images only there. For (2), we need to at
> least allow toggling images with description using some prefix argument
> (previously, any prefix argument would do).

I indeed implemented all same behavior like `org-latex-preview' in new
`org-toggle-inline-images'.

For (1), org-latex-preview has a `cond' logic to toggle preview in
region. Here is the code from `org-latex-preview'.

((use-region-p)
    (message "Creating LaTeX previews in region...")
    (org--latex-preview-region (region-beginning) (region-end))
    (message "Creating LaTeX previews in region... done."))

+

;; Clear current section.
   ((equal arg '(4))
    (org-clear-latex-preview
     (if (use-region-p)
         (region-beginning)
       (if (org-before-first-heading-p) (point-min)
         (save-excursion
	   (org-with-limited-levels (org-back-to-heading t) (point)))))
     (if (use-region-p)
         (region-end)
       (org-with-limited-levels (org-entry-end-position)))))

And I also implement the toggle inline images in region logic in
`org-toggle-inline-images' as bellowing:

;; Display region selected inline images.
   ((use-region-p)
    (message "Displaying inline images in region...")
    (org-display-inline-images include-linked t (region-beginning) (region-end))
    (message "Displaying inline images in region... done."))

+

;; Clear current section.
   ((equal arg '(4))
    (org-clear-latex-preview
     (if (use-region-p)
         (region-beginning)
       (if (org-before-first-heading-p) (point-min)
         (save-excursion
	   (org-with-limited-levels (org-back-to-heading t) (point)))))
     (if (use-region-p)
         (region-end)
       (org-with-limited-levels (org-entry-end-position)))))

------------------------------------------------------------------------

For (2), It's working. The code passed the parameter `include-linked' to
`org-display-inline-images'. So they works in any case of [C-u] prefix.

Maybe you want to eval the patch code to test.

-- 

[ stardiviner ]
I try to make every word tell the meaning that I want to express without misunderstanding.

Blog: https://stardiviner.github.io/
IRC(libera.chat, freenode): stardiviner, Matrix: stardiviner
GPG: F09F650D7D674819892591401B5DF1C95AE89AC3

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 487 bytes --]

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v2] Re: [PATCH] add a function to only refresh inline images under current headline instead of global buffer
  2023-05-16 12:18       ` Christopher M. Miles
@ 2023-07-24 11:25         ` Ihor Radchenko
  2023-08-01  4:40           ` [PATCH v3] " Christopher M. Miles
  0 siblings, 1 reply; 40+ messages in thread
From: Ihor Radchenko @ 2023-07-24 11:25 UTC (permalink / raw)
  To: Christopher M. Miles; +Cc: Org mode

"Christopher M. Miles" <numbchild@gmail.com> writes:

>> Unlike `org-latex-preview', here we need to (1) respect active region;
>> (2) keep the backward compatibility for INCLUDE-LINKED.
>>
>> For (1), for example, it would make sense to respect region when prefix
>> argument is C-u and clear images only there. For (2), we need to at
>> least allow toggling images with description using some prefix argument
>> (previously, any prefix argument would do).
>
> I indeed implemented all same behavior like `org-latex-preview' in new
> `org-toggle-inline-images'.
>
> ...
> And I also implement the toggle inline images in region logic in
> `org-toggle-inline-images' as bellowing:
>
> ;; Display region selected inline images.
>    ((use-region-p)
>     (message "Displaying inline images in region...")
>     (org-display-inline-images include-linked t (region-beginning) (region-end))
>     (message "Displaying inline images in region... done."))

This is not a toggle. This is unconditional refresh.

> For (2), It's working. The code passed the parameter `include-linked' to
> `org-display-inline-images'. So they works in any case of [C-u] prefix.

My concern is that previously C-u M-x org-toggle-inline-images would
"display links with a text description part". With your patch, it is no
longer the case because INCLUDE-LINKED is not affected by the prefix
argument.

And there is no clean way to allow INCLUDE-LINKED while keeping
consistency with latex preview commands.

What we might do here is making a new defcustom that will control
whether linked images should be displayed. Then, something like C-1
org-toggle-inline-images could toggle that defcustom and refresh all the
image previews in buffer (if any).

WDYT?

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH v3] Re: [PATCH] add a function to only refresh inline images under current headline instead of global buffer
  2023-07-24 11:25         ` Ihor Radchenko
@ 2023-08-01  4:40           ` Christopher M. Miles
  2023-08-01  8:04             ` Ihor Radchenko
  0 siblings, 1 reply; 40+ messages in thread
From: Christopher M. Miles @ 2023-08-01  4:40 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: Christopher M. Miles, Org mode


[-- Attachment #1.1: Type: text/plain, Size: 3372 bytes --]


Ihor Radchenko <yantar92@posteo.net> writes:

> "Christopher M. Miles" <numbchild@gmail.com> writes:
>
>>> Unlike `org-latex-preview', here we need to (1) respect active region;
>>> (2) keep the backward compatibility for INCLUDE-LINKED.
>>>
>>> For (1), for example, it would make sense to respect region when prefix
>>> argument is C-u and clear images only there. For (2), we need to at
>>> least allow toggling images with description using some prefix argument
>>> (previously, any prefix argument would do).
>>
>> I indeed implemented all same behavior like `org-latex-preview' in new
>> `org-toggle-inline-images'.
>>
>> ...
>> And I also implement the toggle inline images in region logic in
>> `org-toggle-inline-images' as bellowing:
>>
>> ;; Display region selected inline images.
>>    ((use-region-p)
>>     (message "Displaying inline images in region...")
>>     (org-display-inline-images include-linked t (region-beginning) (region-end))
>>     (message "Displaying inline images in region... done."))
>
> This is not a toggle. This is unconditional refresh.
>
Yes, indeed it's a unconditional refresh. It does not match the meaning of word "toggle".

Seems need to detect whether has image overlays in region. I added this
detection in new patch. Like bellowing:

#+begin_src emacs-lisp
...
((use-region-p)
    (if (seq-contains-p
         (mapcar
          (lambda (ov)
            (plist-get (overlay-properties ov) 'org-image-overlay))
          (overlays-in beg end))
         t)
        (progn
          (org-remove-inline-images beg end)
          (message "Inline images in region removed."))
      (message "Displaying inline images in region...")
      (org-display-inline-images include-linked nil (region-beginning) (region-end))
      (message "Displaying inline images in region... done.")))
....
#+end_src

>> For (2), It's working. The code passed the parameter `include-linked' to
>> `org-display-inline-images'. So they works in any case of [C-u] prefix.
>
> My concern is that previously C-u M-x org-toggle-inline-images would
> "display links with a text description part". With your patch, it is no
> longer the case because INCLUDE-LINKED is not affected by the prefix
> argument.
>
> And there is no clean way to allow INCLUDE-LINKED while keeping
> consistency with latex preview commands.

About the INCLUDE-LINKED argument, I don't know how to process it. In
theory, it should be handled by function org-display-inline-images
instead of org-toggle-inline-images. If you have improvements on it, can
you add code on my patch?

>
> What we might do here is making a new defcustom that will control
> whether linked images should be displayed. Then, something like C-1
> org-toggle-inline-images could toggle that defcustom and refresh all the
> image previews in buffer (if any).
>
> WDYT?

Refreshing all image previews in buffer is same as old behavior. My
patch's purpose is to improve function org-toggle-inline-images behavior
which refresh only in current level scope instead of whole buffer with
lot of inline images especially heavy and suspend Emacs. Because
function org-toggle-inline-images is used in of lot Emacs ob-* related
packages on after babel execution hook. Old behavior caused execute one
source block need to refresh whole buffer all images. Instead of only
current headline images, or just results image.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: 0001-org-Improve-inline-images-displaying-like-LaTeX-prev.patch --]
[-- Type: text/x-patch, Size: 5252 bytes --]

From 635624cb8446791b9e39f2803077ac9fa6d17225 Mon Sep 17 00:00:00 2001
From: stardiviner <numbchild@gmail.com>
Date: Mon, 22 May 2023 16:25:33 +0800
Subject: [PATCH] org: Improve inline images displaying like LaTeX previewing

* lisp/org.el (org-toggle-inline-images): Implement LaTeX previewing
same logic in inline images toggle displaying.
---
 lisp/org.el | 92 ++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 77 insertions(+), 15 deletions(-)

diff --git a/lisp/org.el b/lisp/org.el
index e72cf056a..f847a42e7 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -16160,22 +16160,84 @@ SNIPPETS-P indicates if this is run to create snippet images for HTML."
       (when (memq ov org-inline-image-overlays)
         (push ov result)))))
 
-(defun org-toggle-inline-images (&optional include-linked beg end)
-  "Toggle the display of inline images.
-INCLUDE-LINKED is passed to `org-display-inline-images'."
+(defun org-toggle-inline-images (&optional arg include-linked beg end)
+  "Toggle the display of inline images at point.
+INCLUDE-LINKED is passed to `org-display-inline-images'.
+
+If cursor is on an inline image link, display the inline image.
+If there is none, remove it otherwise.
+If there is no inline image link at point, display all inline images in the current section.
+With an active region, display inline images in the region.
+
+With a `\\[universal-argument]' prefix argument ARG, clear inline
+images in the current section.
+
+With a `\\[universal-argument] \\[universal-argument]' prefix
+ argument ARG, display all inline images in the buffer.
+
+With a `\\[universal-argument] \\[universal-argument] \
+\\[universal-argument]' prefix argument ARG, clear all inline
+images in the buffer."
   (interactive "P")
-  (if (org--inline-image-overlays beg end)
-      (progn
-        (org-remove-inline-images beg end)
-        (when (called-interactively-p 'interactive)
-	  (message "Inline image display turned off")))
-    (org-display-inline-images include-linked nil beg end)
-    (when (called-interactively-p 'interactive)
-      (let ((new (org--inline-image-overlays beg end)))
-        (message (if new
-		     (format "%d images displayed inline"
-			     (length new))
-		   "No images to display inline"))))))
+  (cond
+   ((not (display-graphic-p)) nil)
+   ;; Clear whole buffer inline images.
+   ((equal arg '(64))
+    (org-remove-inline-images (point-min) (point-max))
+    (message "Inline images preview disabled in buffer."))
+   ;; Display whole buffer inline images.
+   ((equal arg '(16))
+    (message "Displaying all inline images in buffer...")
+    (org-display-inline-images include-linked nil (point-min) (point-max))
+    (message "Displaying all inline images in buffer... done."))
+   ;; Clear current section.
+   ((equal arg '(4))
+    (let* ((beg (if (use-region-p)
+                    (region-beginning)
+                  (if (org-before-first-heading-p) (point-min)
+                    (save-excursion
+	              (org-with-limited-levels (org-back-to-heading t) (point))))))
+           (end (if (use-region-p)
+                    (region-end)
+                  (org-with-limited-levels (org-entry-end-position))))
+           (inline-images (org--inline-image-overlays beg end)))
+      (org-remove-inline-images beg end)
+      (message "%d inline images display removed." (length inline-images))))
+   ;; Display region selected inline images.
+   ((use-region-p)
+    (if (seq-contains-p
+         (mapcar
+          (lambda (ov)
+            (plist-get (overlay-properties ov) 'org-image-overlay))
+          (overlays-in beg end))
+         t)
+        (progn
+          (org-remove-inline-images beg end)
+          (message "Inline images in region removed."))
+      (message "Displaying inline images in region...")
+      (org-display-inline-images include-linked nil (region-beginning) (region-end))
+      (message "Displaying inline images in region... done.")))
+   ;; Toggle display of inline image link at point.
+   ((let ((context (org-element-context)))
+      (and (memq (org-element-type context) '(link))
+	   (let ((beg (org-element-property :begin context))
+		 (end (org-element-property :end context)))
+	     (if (org--inline-image-overlays beg end)
+                 (progn
+                   (org-remove-inline-images beg end)
+	           (message "Display inline image at point removed."))
+	       (org-display-inline-images include-linked t beg end)
+	       (message "Displaying inline image at point ... done."))
+	     t))))
+   ;; Display inline images under current section.
+   (t
+    (let ((beg (if (org-before-first-heading-p) (point-min)
+		 (save-excursion
+		   (org-with-limited-levels (org-back-to-heading t) (point)))))
+	  (end (org-with-limited-levels (org-entry-end-position))))
+      (message "Displaying inline images in section...")
+      (org-display-inline-images include-linked t beg end)
+      (message "Displaying inline images in section... done.")))))
 
 (defun org-redisplay-inline-images ()
   "Assure display of inline images and refresh them."
-- 
2.39.2 (Apple Git-143)


[-- Attachment #1.3: Type: text/plain, Size: 267 bytes --]


-- 

[ stardiviner ]
I try to make every word tell the meaning that I want to express without misunderstanding.

Blog: https://stardiviner.github.io/
IRC(libera.chat, freenode): stardiviner, Matrix: stardiviner
GPG: F09F650D7D674819892591401B5DF1C95AE89AC3

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 487 bytes --]

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [PATCH v3] Re: [PATCH] add a function to only refresh inline images under current headline instead of global buffer
  2023-08-01  4:40           ` [PATCH v3] " Christopher M. Miles
@ 2023-08-01  8:04             ` Ihor Radchenko
  2023-08-01 12:17               ` [PATCH v3.1] " Christopher M. Miles
  0 siblings, 1 reply; 40+ messages in thread
From: Ihor Radchenko @ 2023-08-01  8:04 UTC (permalink / raw)
  To: Christopher M. Miles; +Cc: Org mode

"Christopher M. Miles" <numbchild@gmail.com> writes:

>> This is not a toggle. This is unconditional refresh.
>>
> Yes, indeed it's a unconditional refresh. It does not match the meaning of word "toggle".
>
> Seems need to detect whether has image overlays in region. I added this
> detection in new patch. Like bellowing:
>
> #+begin_src emacs-lisp
> ...
> ((use-region-p)
>     (if (seq-contains-p
>          (mapcar
>           (lambda (ov)
>             (plist-get (overlay-properties ov) 'org-image-overlay))
>           (overlays-in beg end))
>          t)

You can just use `org--inline-image-overlays'.

>> And there is no clean way to allow INCLUDE-LINKED while keeping
>> consistency with latex preview commands.
>
> About the INCLUDE-LINKED argument, I don't know how to process it. In
> theory, it should be handled by function org-display-inline-images
> instead of org-toggle-inline-images. If you have improvements on it, can
> you add code on my patch?

The problem here is backwards compatibility. `org-toggle-inline-images'
is bound to C-c C-x C-v and people may be used to C-u C-c C-x C-v
displaying linked images like

[[https://orgmode.org/resources/img/org-mode-unicorn.svg][description]]

I will need to think more how to approach this.

>> What we might do here is making a new defcustom that will control
>> whether linked images should be displayed. Then, something like C-1
>> org-toggle-inline-images could toggle that defcustom and refresh all the
>> image previews in buffer (if any).
>>
>> WDYT?
>
> Refreshing all image previews in buffer is same as old behavior.

Sure. But the idea of this specific C-1 prefix argument is to toggle the
hypothetical defcustom `org-inline-images-include-linked'. If we flip it
we may need to remove/add linked image previews or otherwise risk users
being confused by the defcustom not taking effect.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH v3.1] Re: [PATCH] add a function to only refresh inline images under current headline instead of global buffer
  2023-08-01  8:04             ` Ihor Radchenko
@ 2023-08-01 12:17               ` Christopher M. Miles
  2023-08-01 14:09                 ` Ihor Radchenko
  2023-08-02  7:26                 ` Ihor Radchenko
  0 siblings, 2 replies; 40+ messages in thread
From: Christopher M. Miles @ 2023-08-01 12:17 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: Christopher M. Miles, Org mode


[-- Attachment #1.1: Type: text/plain, Size: 2342 bytes --]


Ihor Radchenko <yantar92@posteo.net> writes:

> "Christopher M. Miles" <numbchild@gmail.com> writes:
>
>>> This is not a toggle. This is unconditional refresh.
>>>
>> Yes, indeed it's a unconditional refresh. It does not match the meaning of word "toggle".
>>
>> Seems need to detect whether has image overlays in region. I added this
>> detection in new patch. Like bellowing:
>>
>> #+begin_src emacs-lisp
>> ...
>> ((use-region-p)
>>     (if (seq-contains-p
>>          (mapcar
>>           (lambda (ov)
>>             (plist-get (overlay-properties ov) 'org-image-overlay))
>>           (overlays-in beg end))
>>          t)
>
> You can just use `org--inline-image-overlays'.
>

Aha, I forget this API function, I applied in new patch.

>>> And there is no clean way to allow INCLUDE-LINKED while keeping
>>> consistency with latex preview commands.
>>
>> About the INCLUDE-LINKED argument, I don't know how to process it. In
>> theory, it should be handled by function org-display-inline-images
>> instead of org-toggle-inline-images. If you have improvements on it, can
>> you add code on my patch?
>
> The problem here is backwards compatibility. `org-toggle-inline-images'
> is bound to C-c C-x C-v and people may be used to C-u C-c C-x C-v
> displaying linked images like
>
> [[https://orgmode.org/resources/img/org-mode-unicorn.svg][description]]
>
> I will need to think more how to approach this.
>

Indeed.

>>> What we might do here is making a new defcustom that will control
>>> whether linked images should be displayed. Then, something like C-1
>>> org-toggle-inline-images could toggle that defcustom and refresh all the
>>> image previews in buffer (if any).
>>>
>>> WDYT?
>>
>> Refreshing all image previews in buffer is same as old behavior.
>
> Sure. But the idea of this specific C-1 prefix argument is to toggle the
> hypothetical defcustom `org-inline-images-include-linked'. If we flip it
> we may need to remove/add linked image previews or otherwise risk users
> being confused by the defcustom not taking effect.

I checked source code, don't know where to insert this functionality.
Is it be in `org-display-inline-images` or somewhere else?
I will find time to checking code whether can add this in another patch.
If you have plan for this, let me know.

I think current patch is ready for merging now. WDYT?


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: 0001-org-Improve-inline-images-displaying-like-LaTeX-prev.patch --]
[-- Type: text/x-patch, Size: 5168 bytes --]

From 2f68f0172dc5e452c05a9d254eab8ae797bcd15b Mon Sep 17 00:00:00 2001
From: stardiviner <numbchild@gmail.com>
Date: Mon, 22 May 2023 16:25:33 +0800
Subject: [PATCH] org: Improve inline images displaying like LaTeX previewing

* lisp/org.el (org-toggle-inline-images): Implement LaTeX previewing
same logic in inline images toggle displaying.
---
 lisp/org.el | 89 ++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 74 insertions(+), 15 deletions(-)

diff --git a/lisp/org.el b/lisp/org.el
index e72cf056a..04f713d26 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -16160,22 +16160,81 @@ SNIPPETS-P indicates if this is run to create snippet images for HTML."
       (when (memq ov org-inline-image-overlays)
         (push ov result)))))
 
-(defun org-toggle-inline-images (&optional include-linked beg end)
-  "Toggle the display of inline images.
-INCLUDE-LINKED is passed to `org-display-inline-images'."
+(defun org-toggle-inline-images (&optional arg include-linked beg end)
+  "Toggle the display of inline images at point.
+INCLUDE-LINKED is passed to `org-display-inline-images'.
+
+If cursor is on an inline image link, display the inline image.
+If there is none, remove it otherwise.
+If there is no inline image link at point, display all inline images in the current section.
+With an active region, display inline images in the region.
+
+With a `\\[universal-argument]' prefix argument ARG, clear inline
+images in the current section.
+
+With a `\\[universal-argument] \\[universal-argument]' prefix
+ argument ARG, display all inline images in the buffer.
+
+With a `\\[universal-argument] \\[universal-argument] \
+\\[universal-argument]' prefix argument ARG, clear all inline
+images in the buffer."
   (interactive "P")
-  (if (org--inline-image-overlays beg end)
-      (progn
-        (org-remove-inline-images beg end)
-        (when (called-interactively-p 'interactive)
-	  (message "Inline image display turned off")))
-    (org-display-inline-images include-linked nil beg end)
-    (when (called-interactively-p 'interactive)
-      (let ((new (org--inline-image-overlays beg end)))
-        (message (if new
-		     (format "%d images displayed inline"
-			     (length new))
-		   "No images to display inline"))))))
+  (cond
+   ((not (display-graphic-p)) nil)
+   ;; Clear whole buffer inline images.
+   ((equal arg '(64))
+    (org-remove-inline-images (point-min) (point-max))
+    (message "Inline images preview disabled in buffer."))
+   ;; Display whole buffer inline images.
+   ((equal arg '(16))
+    (message "Displaying all inline images in buffer...")
+    (org-display-inline-images include-linked nil (point-min) (point-max))
+    (message "Displaying all inline images in buffer... done."))
+   ;; Clear current section.
+   ((equal arg '(4))
+    (let* ((beg (if (use-region-p)
+                    (region-beginning)
+                  (if (org-before-first-heading-p) (point-min)
+                    (save-excursion
+	              (org-with-limited-levels (org-back-to-heading t) (point))))))
+           (end (if (use-region-p)
+                    (region-end)
+                  (org-with-limited-levels (org-entry-end-position))))
+           (inline-images (org--inline-image-overlays beg end)))
+      (org-remove-inline-images beg end)
+      (message "%d inline images display removed." (length inline-images))))
+   ;; Display region selected inline images.
+   ((use-region-p)
+    (let ((beg (region-beginning))
+          (end (region-end)))
+      (if (org--inline-image-overlays beg end)
+          (progn
+            (org-remove-inline-images beg end)
+            (message "Inline images in region removed."))
+        (message "Displaying inline images in region...")
+        (org-display-inline-images include-linked t beg end)
+        (message "Displaying inline images in region... done."))))
+   ;; Toggle display of inline image link at point.
+   ((let ((context (org-element-context)))
+      (and (memq (org-element-type context) '(link))
+	   (let ((beg (org-element-property :begin context))
+		 (end (org-element-property :end context)))
+	     (if (org--inline-image-overlays beg end)
+                 (progn
+                   (org-remove-inline-images beg end)
+	           (message "Display inline image at point removed."))
+	       (org-display-inline-images include-linked t beg end)
+	       (message "Displaying inline image at point ... done."))
+	     t))))
+   ;; Display inline images under current section.
+   (t
+    (let ((beg (if (org-before-first-heading-p) (point-min)
+		 (save-excursion
+		   (org-with-limited-levels (org-back-to-heading t) (point)))))
+	  (end (org-with-limited-levels (org-entry-end-position))))
+      (message "Displaying inline images in section...")
+      (org-display-inline-images include-linked t beg end)
+      (message "Displaying inline images in section... done.")))))
 
 (defun org-redisplay-inline-images ()
   "Assure display of inline images and refresh them."
-- 
2.39.2 (Apple Git-143)


[-- Attachment #1.3: Type: text/plain, Size: 267 bytes --]


-- 

[ stardiviner ]
I try to make every word tell the meaning that I want to express without misunderstanding.

Blog: https://stardiviner.github.io/
IRC(libera.chat, freenode): stardiviner, Matrix: stardiviner
GPG: F09F650D7D674819892591401B5DF1C95AE89AC3

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 487 bytes --]

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [PATCH v3.1] Re: [PATCH] add a function to only refresh inline images under current headline instead of global buffer
  2023-08-01 12:17               ` [PATCH v3.1] " Christopher M. Miles
@ 2023-08-01 14:09                 ` Ihor Radchenko
  2023-08-01 15:22                   ` Christopher M. Miles
  2023-08-01 15:46                   ` Christopher M. Miles
  2023-08-02  7:26                 ` Ihor Radchenko
  1 sibling, 2 replies; 40+ messages in thread
From: Ihor Radchenko @ 2023-08-01 14:09 UTC (permalink / raw)
  To: Christopher M. Miles; +Cc: Org mode

"Christopher M. Miles" <numbchild@gmail.com> writes:

> I think current patch is ready for merging now. WDYT?

No, unfortunately.
With your patch, it will become impossible to display linked images
using interactive command.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v3.1] Re: [PATCH] add a function to only refresh inline images under current headline instead of global buffer
  2023-08-01 14:09                 ` Ihor Radchenko
@ 2023-08-01 15:22                   ` Christopher M. Miles
  2023-08-01 15:46                   ` Christopher M. Miles
  1 sibling, 0 replies; 40+ messages in thread
From: Christopher M. Miles @ 2023-08-01 15:22 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: Christopher M. Miles, Org mode

[-- Attachment #1: Type: text/plain, Size: 716 bytes --]


Ihor Radchenko <yantar92@posteo.net> writes:

> "Christopher M. Miles" <numbchild@gmail.com> writes:
>
>> I think current patch is ready for merging now. WDYT?
>
> No, unfortunately.
> With your patch, it will become impossible to display linked images
> using interactive command.

I still need time to study how to add support for this. Most likely I
can't implement it by myself. Would you modify my patch to add support
for this?

-- 

[ stardiviner ]
I try to make every word tell the meaning that I want to express without misunderstanding.

Blog: https://stardiviner.github.io/
IRC(libera.chat, freenode): stardiviner, Matrix: stardiviner
GPG: F09F650D7D674819892591401B5DF1C95AE89AC3

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 487 bytes --]

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v3.1] Re: [PATCH] add a function to only refresh inline images under current headline instead of global buffer
  2023-08-01 14:09                 ` Ihor Radchenko
  2023-08-01 15:22                   ` Christopher M. Miles
@ 2023-08-01 15:46                   ` Christopher M. Miles
  2023-08-02 16:08                     ` Ihor Radchenko
  1 sibling, 1 reply; 40+ messages in thread
From: Christopher M. Miles @ 2023-08-01 15:46 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: Christopher M. Miles, Org mode

[-- Attachment #1: Type: text/plain, Size: 978 bytes --]


Ihor Radchenko <yantar92@posteo.net> writes:

> "Christopher M. Miles" <numbchild@gmail.com> writes:
>
>> I think current patch is ready for merging now. WDYT?
>
> No, unfortunately.
> With your patch, it will become impossible to display linked images
> using interactive command.

Does this code match the needs?

#+begin_src emacs-lisp
   ;; [M-1] / [C-1] argument for linked images like:
   ;; [[https://orgmode.org/resources/img/org-mode-unicorn.svg][description]]
   ((equal arg 1)
    (setq org-inline-images-include-linked (not org-inline-images-include-linked))
    (let ((current-prefix-arg nil))
      (org-toggle-inline-images nil org-inline-images-include-linked)))
#+end_src

-- 

[ stardiviner ]
I try to make every word tell the meaning that I want to express without misunderstanding.

Blog: https://stardiviner.github.io/
IRC(libera.chat, freenode): stardiviner, Matrix: stardiviner
GPG: F09F650D7D674819892591401B5DF1C95AE89AC3

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 487 bytes --]

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v3.1] Re: [PATCH] add a function to only refresh inline images under current headline instead of global buffer
  2023-08-01 12:17               ` [PATCH v3.1] " Christopher M. Miles
  2023-08-01 14:09                 ` Ihor Radchenko
@ 2023-08-02  7:26                 ` Ihor Radchenko
  2023-08-02 15:44                   ` Christopher M. Miles
  1 sibling, 1 reply; 40+ messages in thread
From: Ihor Radchenko @ 2023-08-02  7:26 UTC (permalink / raw)
  To: Christopher M. Miles; +Cc: Org mode

"Christopher M. Miles" <numbchild@gmail.com> writes:

>> The problem here is backwards compatibility. `org-toggle-inline-images'
>> is bound to C-c C-x C-v and people may be used to C-u C-c C-x C-v
>> displaying linked images like
>>
>> [[https://orgmode.org/resources/img/org-mode-unicorn.svg][description]]
>>
>> I will need to think more how to approach this.
>>
>
> Indeed.

Another problem with your change is that the order of arguments changed.
If there is some Elisp doing something like
(org-toggle-inline-images INCLUDE-LINKED), your patch will break the
code.

I think that instead of changing the existing function, we can convert
your patch into a new function `org-toggle-inline-images-command' that
will be free to alter the argument order. We can then re-bind that
function in org-keys to make it used by default, but only interactively.

As for displaying linked images, what about something like


C-1 C-c C-x C-v being equivalent of
C-c C-x C-v + INCLUDE-LINKED=t
(display in current section/region, with linked)

and

C-11 C-c C-x C-v being equivalent of
C-u C-u C-c C-x C-v + INCLUDE-LINKED=t
(display in the whole buffer, with linked)

> +(defun org-toggle-inline-images (&optional arg include-linked beg end)
> +  "Toggle the display of inline images at point.
> +INCLUDE-LINKED is passed to `org-display-inline-images'.
> +
> +If cursor is on an inline image link, display the inline image.
> +If there is none, remove it otherwise.

I do not quite understand what the last line is trying to say.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v3.1] Re: [PATCH] add a function to only refresh inline images under current headline instead of global buffer
  2023-08-02  7:26                 ` Ihor Radchenko
@ 2023-08-02 15:44                   ` Christopher M. Miles
  2023-08-04  8:20                     ` Ihor Radchenko
  0 siblings, 1 reply; 40+ messages in thread
From: Christopher M. Miles @ 2023-08-02 15:44 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: Christopher M. Miles, Org mode

[-- Attachment #1: Type: text/plain, Size: 2590 bytes --]


Ihor Radchenko <yantar92@posteo.net> writes:

> "Christopher M. Miles" <numbchild@gmail.com> writes:
>
>>> The problem here is backwards compatibility. `org-toggle-inline-images'
>>> is bound to C-c C-x C-v and people may be used to C-u C-c C-x C-v
>>> displaying linked images like
>>>
>>> [[https://orgmode.org/resources/img/org-mode-unicorn.svg][description]]
>>>
>>> I will need to think more how to approach this.
>>>
>>
>> Indeed.
>
> Another problem with your change is that the order of arguments changed.
> If there is some Elisp doing something like
> (org-toggle-inline-images INCLUDE-LINKED), your patch will break the
> code.
>
> I think that instead of changing the existing function, we can convert
> your patch into a new function `org-toggle-inline-images-command' that
> will be free to alter the argument order. We can then re-bind that
> function in org-keys to make it used by default, but only interactively.
>

I don't think so, the patch main purpose is for improve image refreshing
after babel result image displaying. Because the function is hooked by
other ob-* packages. Another purpose is headline level images displaying.
So modifying this function is the only way.

> As for displaying linked images, what about something like
>
>
> C-1 C-c C-x C-v being equivalent of
> C-c C-x C-v + INCLUDE-LINKED=t
> (display in current section/region, with linked)
>
> and
>
> C-11 C-c C-x C-v being equivalent of
> C-u C-u C-c C-x C-v + INCLUDE-LINKED=t
> (display in the whole buffer, with linked)
>

Don't know, I have not use it this way. I think INCLUDE-LINKED is just a
option argument for function org-display-inline-images. No need to be
available for toggle in interactive command. An option like
org-inline-images-include-linked is enough.

>> +(defun org-toggle-inline-images (&optional arg include-linked beg end)
>> +  "Toggle the display of inline images at point.
>> +INCLUDE-LINKED is passed to `org-display-inline-images'.
>> +
>> +If cursor is on an inline image link, display the inline image.
>> +If there is none, remove it otherwise.
>
> I do not quite understand what the last line is trying to say.

Emmm, I forget the meaning of it. I read the docstring again, seems it
can be deleted. I will delete it in my patch.

-- 

[ stardiviner ]
I try to make every word tell the meaning that I want to express without misunderstanding.

Blog: https://stardiviner.github.io/
IRC(libera.chat, freenode): stardiviner, Matrix: stardiviner
GPG: F09F650D7D674819892591401B5DF1C95AE89AC3

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 487 bytes --]

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v3.1] Re: [PATCH] add a function to only refresh inline images under current headline instead of global buffer
  2023-08-01 15:46                   ` Christopher M. Miles
@ 2023-08-02 16:08                     ` Ihor Radchenko
  2023-08-04  6:30                       ` Christopher M. Miles
  0 siblings, 1 reply; 40+ messages in thread
From: Ihor Radchenko @ 2023-08-02 16:08 UTC (permalink / raw)
  To: Christopher M. Miles; +Cc: Org mode

"Christopher M. Miles" <numbchild@gmail.com> writes:

>> With your patch, it will become impossible to display linked images
>> using interactive command.
>
> Does this code match the needs?

Please check my latest reply (https://list.orgmode.org/87o7jpoqfl.fsf@localhost/T/#m25fbb254635512a7bf86d368bf93a24a1c2fb3f1).
I think we may go away without introducing an extra defcustom.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v3.1] Re: [PATCH] add a function to only refresh inline images under current headline instead of global buffer
  2023-08-02 16:08                     ` Ihor Radchenko
@ 2023-08-04  6:30                       ` Christopher M. Miles
  0 siblings, 0 replies; 40+ messages in thread
From: Christopher M. Miles @ 2023-08-04  6:30 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: Christopher M. Miles, Org mode

[-- Attachment #1: Type: text/plain, Size: 881 bytes --]


Ihor Radchenko <yantar92@posteo.net> writes:

> "Christopher M. Miles" <numbchild@gmail.com> writes:
>
>>> With your patch, it will become impossible to display linked images
>>> using interactive command.
>>
>> Does this code match the needs?
>
> Please check my latest reply (https://list.orgmode.org/87o7jpoqfl.fsf@localhost/T/#m25fbb254635512a7bf86d368bf93a24a1c2fb3f1).
> I think we may go away without introducing an extra defcustom.

After yesterday night studying source code, I still can't figure out
solution. So I pass this patch to you. Wait you to finish the unfinished
part of path.

-- 

[ stardiviner ]
I try to make every word tell the meaning that I want to express without misunderstanding.

Blog: https://stardiviner.github.io/
IRC(libera.chat, freenode): stardiviner, Matrix: stardiviner
GPG: F09F650D7D674819892591401B5DF1C95AE89AC3

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 487 bytes --]

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v3.1] Re: [PATCH] add a function to only refresh inline images under current headline instead of global buffer
  2023-08-02 15:44                   ` Christopher M. Miles
@ 2023-08-04  8:20                     ` Ihor Radchenko
  2023-08-05  5:28                       ` [PATCH v3.2] " Christopher M. Miles
  0 siblings, 1 reply; 40+ messages in thread
From: Ihor Radchenko @ 2023-08-04  8:20 UTC (permalink / raw)
  To: Christopher M. Miles; +Cc: Org mode

"Christopher M. Miles" <numbchild@gmail.com> writes:

>> I think that instead of changing the existing function, we can convert
>> your patch into a new function `org-toggle-inline-images-command' that
>> will be free to alter the argument order. We can then re-bind that
>> function in org-keys to make it used by default, but only interactively.
>>
> I don't think so, the patch main purpose is for improve image refreshing
> after babel result image displaying. Because the function is hooked by
> other ob-* packages. Another purpose is headline level images displaying.
> So modifying this function is the only way.

Fair point.
Then, for backward compatibility, we may treat any non-nil, non-list
(like '(4), '(16), '(64)), non-number (like 1, 11) value as
INCLUDE-LINKED. This way, the existing calls like
(org-toggle-inline-images t) will not be broken.

Also, the signature should be

(defun org-toggle-inline-images (&optional arg beg end include-linked)

So that the meaning of the second and third argument is unchanged.

>> As for displaying linked images, what about something like
>>
>>
>> C-1 C-c C-x C-v being equivalent of
>> C-c C-x C-v + INCLUDE-LINKED=t
>> (display in current section/region, with linked)
>>
>> and
>>
>> C-11 C-c C-x C-v being equivalent of
>> C-u C-u C-c C-x C-v + INCLUDE-LINKED=t
>> (display in the whole buffer, with linked)
>>
> Don't know, I have not use it this way. I think INCLUDE-LINKED is just a
> option argument for function org-display-inline-images. No need to be
> available for toggle in interactive command. An option like
> org-inline-images-include-linked is enough.

Sorry, but ignoring backwards compatibility is not an option.
If you personally haven't used some feature, it does not mean that
others also didn't.

We can make limited compromises, but should try our best not to break
things that were working before.
See https://bzg.fr/en/the-software-maintainers-pledge/

>>> +If cursor is on an inline image link, display the inline image.
>>> +If there is none, remove it otherwise.
>>
>> I do not quite understand what the last line is trying to say.
>
> Emmm, I forget the meaning of it. I read the docstring again, seems it
> can be deleted. I will delete it in my patch.

> After yesterday night studying source code, I still can't figure out
> solution. So I pass this patch to you. Wait you to finish the unfinished
> part of path.

I hope that now you have enough information to update the patch.
Let me know if not.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH v3.2] Re: [PATCH] add a function to only refresh inline images under current headline instead of global buffer
  2023-08-04  8:20                     ` Ihor Radchenko
@ 2023-08-05  5:28                       ` Christopher M. Miles
  2024-07-22 10:46                         ` Ihor Radchenko
  0 siblings, 1 reply; 40+ messages in thread
From: Christopher M. Miles @ 2023-08-05  5:28 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: Christopher M. Miles, Org mode


[-- Attachment #1.1: Type: text/plain, Size: 3247 bytes --]


Ihor Radchenko <yantar92@posteo.net> writes:

> "Christopher M. Miles" <numbchild@gmail.com> writes:
>
>>> I think that instead of changing the existing function, we can convert
>>> your patch into a new function `org-toggle-inline-images-command' that
>>> will be free to alter the argument order. We can then re-bind that
>>> function in org-keys to make it used by default, but only interactively.
>>>
>> I don't think so, the patch main purpose is for improve image refreshing
>> after babel result image displaying. Because the function is hooked by
>> other ob-* packages. Another purpose is headline level images displaying.
>> So modifying this function is the only way.
>
> Fair point.
> Then, for backward compatibility, we may treat any non-nil, non-list
> (like '(4), '(16), '(64)), non-number (like 1, 11) value as
> INCLUDE-LINKED. This way, the existing calls like
> (org-toggle-inline-images t) will not be broken.
>
> Also, the signature should be
>
> (defun org-toggle-inline-images (&optional arg beg end include-linked)
>
> So that the meaning of the second and third argument is unchanged.
>

I prefer this compromise result.
I updated the patch, Please review it whether it's correct.

>>> As for displaying linked images, what about something like
>>>
>>>
>>> C-1 C-c C-x C-v being equivalent of
>>> C-c C-x C-v + INCLUDE-LINKED=t
>>> (display in current section/region, with linked)
>>>
>>> and
>>>
>>> C-11 C-c C-x C-v being equivalent of
>>> C-u C-u C-c C-x C-v + INCLUDE-LINKED=t
>>> (display in the whole buffer, with linked)
>>>
>> Don't know, I have not use it this way. I think INCLUDE-LINKED is just a
>> option argument for function org-display-inline-images. No need to be
>> available for toggle in interactive command. An option like
>> org-inline-images-include-linked is enough.
>
> Sorry, but ignoring backwards compatibility is not an option.
> If you personally haven't used some feature, it does not mean that
> others also didn't.
>
> We can make limited compromises, but should try our best not to break
> things that were working before.
> See https://bzg.fr/en/the-software-maintainers-pledge/
>

I agree with backward compatibility is very important.

I did a source code statistics researching of using the function org-toggle-inline-images at two places:

- GitHub: https://github.com/search?q=org-toggle-inline-images&ref=opensearch&type=code&p=3
(Only package scimax incoke this function with INCLUDE-LINKED argument t)
- My installed Emacs packages, NO package invoke this function with argument INCLUDE-LINKED.

So lucky this change will not affect lot.

>>>> +If cursor is on an inline image link, display the inline image.
>>>> +If there is none, remove it otherwise.
>>>
>>> I do not quite understand what the last line is trying to say.
>>
>> Emmm, I forget the meaning of it. I read the docstring again, seems it
>> can be deleted. I will delete it in my patch.
>
>> After yesterday night studying source code, I still can't figure out
>> solution. So I pass this patch to you. Wait you to finish the unfinished
>> part of path.
>
> I hope that now you have enough information to update the patch.
> Let me know if not.

If this patch is still not ok, really hope you can edit my patch.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: 0001-org-Improve-inline-images-displaying-like-LaTeX-prev.patch --]
[-- Type: text/x-patch, Size: 6281 bytes --]

From a2707a0f92c76188c3ebb412fe2b57788b50ca9a Mon Sep 17 00:00:00 2001
From: stardiviner <numbchild@gmail.com>
Date: Mon, 22 May 2023 16:25:33 +0800
Subject: [PATCH] org: Improve inline images displaying like LaTeX previewing

* lisp/org.el (org-toggle-inline-images): Implement LaTeX previewing
same logic in inline images toggle displaying.
---
 lisp/org-keys.el |  2 +-
 lisp/org.el      | 95 ++++++++++++++++++++++++++++++++++++++++--------
 2 files changed, 81 insertions(+), 16 deletions(-)

diff --git a/lisp/org-keys.el b/lisp/org-keys.el
index 38fac57d8..7b3b84af4 100644
--- a/lisp/org-keys.el
+++ b/lisp/org-keys.el
@@ -204,7 +204,7 @@
 (declare-function org-toggle-radio-button "org" (&optional arg))
 (declare-function org-toggle-comment "org" ())
 (declare-function org-toggle-fixed-width "org" ())
-(declare-function org-toggle-inline-images "org" (&optional include-linked beg end))
+(declare-function org-toggle-inline-images "org" (&optional arg beg end include-linked))
 (declare-function org-latex-preview "org" (&optional arg))
 (declare-function org-toggle-narrow-to-subtree "org" ())
 (declare-function org-toggle-ordered-property "org" ())
diff --git a/lisp/org.el b/lisp/org.el
index e72cf056a..c01952b97 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -16160,22 +16160,87 @@ SNIPPETS-P indicates if this is run to create snippet images for HTML."
       (when (memq ov org-inline-image-overlays)
         (push ov result)))))
 
-(defun org-toggle-inline-images (&optional include-linked beg end)
-  "Toggle the display of inline images.
-INCLUDE-LINKED is passed to `org-display-inline-images'."
+(defun org-toggle-inline-images (&optional arg beg end include-linked)
+  "Toggle the display of inline images at point.
+INCLUDE-LINKED is passed to `org-display-inline-images'.
+
+If cursor is on an inline image link, display the inline image.
+If there is no inline image link at point, display all inline images in the current section.
+With an active region, display inline images in the region.
+
+With a `\\[universal-argument]' prefix argument ARG, clear inline
+images in the current section.
+
+With a `\\[universal-argument] \\[universal-argument]' prefix
+ argument ARG, display all inline images in the buffer.
+
+With a `\\[universal-argument] \\[universal-argument] \
+\\[universal-argument]' prefix argument ARG, clear all inline
+images in the buffer."
   (interactive "P")
-  (if (org--inline-image-overlays beg end)
-      (progn
-        (org-remove-inline-images beg end)
-        (when (called-interactively-p 'interactive)
-	  (message "Inline image display turned off")))
-    (org-display-inline-images include-linked nil beg end)
-    (when (called-interactively-p 'interactive)
-      (let ((new (org--inline-image-overlays beg end)))
-        (message (if new
-		     (format "%d images displayed inline"
-			     (length new))
-		   "No images to display inline"))))))
+  (cond
+   ((not (display-graphic-p)) nil)
+   ;; Clear whole buffer inline images.
+   ((equal arg '(64))
+    (org-remove-inline-images (point-min) (point-max))
+    (message "Inline images preview disabled in buffer."))
+   ;; Display whole buffer inline images.
+   ((equal arg '(16))
+    (message "Displaying all inline images in buffer...")
+    (let ((include-linked t)) ; assume INCLUDE-LINKED be t here for backward compatibility.
+      (org-display-inline-images include-linked nil (point-min) (point-max)))
+    (message "Displaying all inline images in buffer... done."))
+   ;; Clear current section.
+   ((equal arg '(4))
+    (let* ((beg (if (use-region-p)
+                    (region-beginning)
+                  (if (org-before-first-heading-p) (point-min)
+                    (save-excursion
+	              (org-with-limited-levels (org-back-to-heading t) (point))))))
+           (end (if (use-region-p)
+                    (region-end)
+                  (org-with-limited-levels (org-entry-end-position))))
+           (inline-images (org--inline-image-overlays beg end)))
+      (org-remove-inline-images beg end)
+      (message "%d inline images display removed." (length inline-images))))
+   ;; [M-1] / [C-1] argument for linked images like:
+   ;; [[https://orgmode.org/resources/img/org-mode-unicorn.svg][description]]
+   ((equal arg 1)
+    (let ((current-prefix-arg nil)
+          (include-linked t)) ; assume INCLUDE-LINKED be t here for backward compatibility.
+      (org-toggle-inline-images nil nil nil include-linked)))
+   ;; Display region selected inline images.
+   ((use-region-p)
+    (let ((beg (region-beginning))
+          (end (region-end)))
+      (if (org--inline-image-overlays beg end)
+          (progn
+            (org-remove-inline-images beg end)
+            (message "Inline images in region removed."))
+        (message "Displaying inline images in region...")
+        (org-display-inline-images include-linked t beg end)
+        (message "Displaying inline images in region... done."))))
+   ;; Toggle display of inline image link at point.
+   ((let ((context (org-element-context)))
+      (and (memq (org-element-type context) '(link))
+	   (let ((beg (org-element-property :begin context))
+		 (end (org-element-property :end context)))
+	     (if (org--inline-image-overlays beg end)
+                 (progn
+                   (org-remove-inline-images beg end)
+	           (message "Display inline image at point removed."))
+	       (org-display-inline-images include-linked t beg end)
+	       (message "Displaying inline image at point ... done."))
+	     t))))
+   ;; Display inline images under current section.
+   (t
+    (let ((beg (if (org-before-first-heading-p) (point-min)
+		 (save-excursion
+		   (org-with-limited-levels (org-back-to-heading t) (point)))))
+	  (end (org-with-limited-levels (org-entry-end-position))))
+      (message "Displaying inline images in section...")
+      (org-display-inline-images include-linked t beg end)
+      (message "Displaying inline images in section... done.")))))
 
 (defun org-redisplay-inline-images ()
   "Assure display of inline images and refresh them."
-- 
2.39.2 (Apple Git-143)


[-- Attachment #1.3: Type: text/plain, Size: 267 bytes --]


-- 

[ stardiviner ]
I try to make every word tell the meaning that I want to express without misunderstanding.

Blog: https://stardiviner.github.io/
IRC(libera.chat, freenode): stardiviner, Matrix: stardiviner
GPG: F09F650D7D674819892591401B5DF1C95AE89AC3

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 487 bytes --]

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [PATCH v3.2] Re: [PATCH] add a function to only refresh inline images under current headline instead of global buffer
  2023-08-05  5:28                       ` [PATCH v3.2] " Christopher M. Miles
@ 2024-07-22 10:46                         ` Ihor Radchenko
  2024-08-01 22:58                           ` [PATCH v4.0] " stardiviner
       [not found]                           ` <66a8b73b.170a0220.383476.996e@mx.google.com>
  0 siblings, 2 replies; 40+ messages in thread
From: Ihor Radchenko @ 2024-07-22 10:46 UTC (permalink / raw)
  To: Christopher M. Miles; +Cc: Org mode

"Christopher M. Miles" <numbchild@gmail.com> writes:

>> Then, for backward compatibility, we may treat any non-nil, non-list
>> (like '(4), '(16), '(64)), non-number (like 1, 11) value as
>> INCLUDE-LINKED. This way, the existing calls like
>> (org-toggle-inline-images t) will not be broken.
> ...
> I prefer this compromise result.
> I updated the patch, Please review it whether it's correct.

I think that C-u C-u unconditionally including linked images is
confusing.

What about using my idea with M-1/M-11 to be interpreted as INCLUDE-LINKED=t?

Also, you did not document in the docstring what happens if ARG is
something like t.

> I did a source code statistics researching of using the function org-toggle-inline-images at two places:
>
> - GitHub: https://github.com/search?q=org-toggle-inline-images&ref=opensearch&type=code&p=3
> (Only package scimax incoke this function with INCLUDE-LINKED argument t)
> - My installed Emacs packages, NO package invoke this function with argument INCLUDE-LINKED.
>
> So lucky this change will not affect lot.

I have found user configs using the argument:

https://github.com/search?q=%22%28org-toggle-inline-images+t%29%22&type=code
https://github.com/search?q=%22%28org-toggle-inline-images+%27%22&type=code

So, please do as I advised - treat non-special ARG values as INCLUDE-LINKED.

Also, looking at the proposed prefix arguments, I feel that it might not
necessarily be the best idea to copy over what org-latex-preview does
exactly. org-latex-preview is not a "toggle", unlike org-toggle-inline-images

What about the following treatment of ARG:

1. No argument, no region selected :: toggle (display or hide dwim) images in current section 
2. No argument, region selected: toggle images in region
3. C-u argument :: toggle images in the whole buffer
4. C-u C-u argument, no region selected :: unconditionally hide images in the buffer
5. M-1 argument, no region selected :: display images in current section with INCLUDE-LINKED
6. M-1 argument, region selected :: ... in region ...
7. M-11 argument :: ... in the whole buffer ...
8. Any other argument :: treat as INCLUDE-LINKED = t

And please document all the new arguments in the manual and etc/ORG-NEWS file.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v4.0] Re: [PATCH] add a function to only refresh inline images under current headline instead of global buffer
  2024-07-22 10:46                         ` Ihor Radchenko
@ 2024-08-01 22:58                           ` stardiviner
       [not found]                           ` <66a8b73b.170a0220.383476.996e@mx.google.com>
  1 sibling, 0 replies; 40+ messages in thread
From: stardiviner @ 2024-08-01 22:58 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: Org mode


[-- Attachment #1.1: Type: text/plain, Size: 3178 bytes --]

I followed you upper 8 conditions to re-write my patch.
Except the 8. condition I'm not sure I understand correctly.
And I extend 1. condition to support the inline image link at point toggle
displaying.

[stardiviner]           <Hack this world!>      GPG key ID: 47C32433
IRC(freeenode): stardiviner                     Twitter:  @numbchild
Key fingerprint = 9BAA 92BC CDDD B9EF 3B36  CB99 B8C4 B8E5 47C3 2433
Blog: http://stardiviner.github.io/


On Mon, Jul 22, 2024 at 6:44 PM Ihor Radchenko <yantar92@posteo.net> wrote:

> "Christopher M. Miles" <numbchild@gmail.com> writes:
>
> >> Then, for backward compatibility, we may treat any non-nil, non-list
> >> (like '(4), '(16), '(64)), non-number (like 1, 11) value as
> >> INCLUDE-LINKED. This way, the existing calls like
> >> (org-toggle-inline-images t) will not be broken.
> > ...
> > I prefer this compromise result.
> > I updated the patch, Please review it whether it's correct.
>
> I think that C-u C-u unconditionally including linked images is
> confusing.
>
> What about using my idea with M-1/M-11 to be interpreted as
> INCLUDE-LINKED=t?
>
> Also, you did not document in the docstring what happens if ARG is
> something like t.
>
> > I did a source code statistics researching of using the function
> org-toggle-inline-images at two places:
> >
> > - GitHub:
> https://github.com/search?q=org-toggle-inline-images&ref=opensearch&type=code&p=3
> > (Only package scimax incoke this function with INCLUDE-LINKED argument t)
> > - My installed Emacs packages, NO package invoke this function with
> argument INCLUDE-LINKED.
> >
> > So lucky this change will not affect lot.
>
> I have found user configs using the argument:
>
>
> https://github.com/search?q=%22%28org-toggle-inline-images+t%29%22&type=code
> https://github.com/search?q=%22%28org-toggle-inline-images+%27%22&type=code
>
> So, please do as I advised - treat non-special ARG values as
> INCLUDE-LINKED.
>
> Also, looking at the proposed prefix arguments, I feel that it might not
> necessarily be the best idea to copy over what org-latex-preview does
> exactly. org-latex-preview is not a "toggle", unlike
> org-toggle-inline-images
>
> What about the following treatment of ARG:
>
> 1. No argument, no region selected :: toggle (display or hide dwim) images
> in current section
> 2. No argument, region selected: toggle images in region
> 3. C-u argument :: toggle images in the whole buffer
> 4. C-u C-u argument, no region selected :: unconditionally hide images in
> the buffer
> 5. M-1 argument, no region selected :: display images in current section
> with INCLUDE-LINKED
> 6. M-1 argument, region selected :: ... in region ...
> 7. M-11 argument :: ... in the whole buffer ...
> 8. Any other argument :: treat as INCLUDE-LINKED = t
>
> And please document all the new arguments in the manual and etc/ORG-NEWS
> file.
>
> --
> Ihor Radchenko // yantar92,
> Org mode contributor,
> Learn more about Org mode at <https://orgmode.org/>.
> Support Org development at <https://liberapay.com/org-mode>,
> or support my work at <https://liberapay.com/yantar92>
>

[-- Attachment #1.2: Type: text/html, Size: 4784 bytes --]

[-- Attachment #2: 0001-org-Implement-conditionally-inline-images-displaying.patch --]
[-- Type: application/octet-stream, Size: 8511 bytes --]

From 63c482d0c3782dcb328581f1d56275a131e78610 Mon Sep 17 00:00:00 2001
From: stardiviner <numbchild@gmail.com>
Date: Mon, 22 May 2023 16:25:33 +0800
Subject: [PATCH] org: Implement conditionally inline images displaying logic

* lisp/org.el (org-toggle-inline-images): Implement conditionally
inline images displaying logic based on universal-argument.
---
 etc/ORG-NEWS     |   5 ++
 lisp/org-keys.el |   2 +-
 lisp/org.el      | 117 +++++++++++++++++++++++++++++++++++++++++------
 3 files changed, 108 insertions(+), 16 deletions(-)

diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS
index 8a2a1ec0e..2798fb131 100644
--- a/etc/ORG-NEWS
+++ b/etc/ORG-NEWS
@@ -113,6 +113,11 @@ accept the INFO channel and return a string.  This makes it possible
 to dynamically generate the content of the resulting ~<head>~ tag in
 the resulting HTML document.
 
+*** ~org-toggle-inline-images~ implement conditionally inline images displaying logic
+
+You can display or hide inline images at point, region, or current
+section through universal-argument.
+
 ** Miscellaneous
 *** ~org-refile~ now saves current position to Org mark ring when jumping to heading
 
diff --git a/lisp/org-keys.el b/lisp/org-keys.el
index edd4059fc..52608b747 100644
--- a/lisp/org-keys.el
+++ b/lisp/org-keys.el
@@ -218,7 +218,7 @@
 (declare-function org-toggle-radio-button "org" (&optional arg))
 (declare-function org-toggle-comment "org" ())
 (declare-function org-toggle-fixed-width "org" ())
-(declare-function org-toggle-inline-images "org" (&optional include-linked beg end))
+(declare-function org-toggle-inline-images "org" (&optional arg beg end include-linked))
 (declare-function org-latex-preview "org" (&optional arg))
 (declare-function org-toggle-narrow-to-subtree "org" ())
 (declare-function org-toggle-ordered-property "org" ())
diff --git a/lisp/org.el b/lisp/org.el
index 362f0c158..83e440632 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -16665,22 +16665,109 @@ SNIPPETS-P indicates if this is run to create snippet images for HTML."
       (when (memq ov org-inline-image-overlays)
         (push ov result)))))
 
-(defun org-toggle-inline-images (&optional include-linked beg end)
-  "Toggle the display of inline images.
-INCLUDE-LINKED is passed to `org-display-inline-images'."
+(defun org-toggle-inline-images (&optional arg beg end)
+  "Toggle the display of inline images at point.
+
+The parameter ARG from `\\[universal-argument]' is used as condition in bellowing \"argument\".
+
+1. No argument, no region selected :: toggle (display or hide dwim) images in current section or image link at point
+2. No argument, region selected :: toggle images in region
+3. C-u argument :: toggle images in the whole buffer
+4. C-u C-u argument, no region selected :: unconditionally hide images in the buffer
+5. M-1 argument, no region selected :: display images in current section with INCLUDE-LINKED
+6. M-1 argument, region selected :: ... in region ...
+7. M-11 argument :: ... in the whole buffer ...
+8. Any other argument :: treat as INCLUDE-LINKED = t"
   (interactive "P")
-  (if (org--inline-image-overlays beg end)
-      (progn
-        (org-remove-inline-images beg end)
-        (when (called-interactively-p 'interactive)
-	  (message "Inline image display turned off")))
-    (org-display-inline-images include-linked nil beg end)
-    (when (called-interactively-p 'interactive)
-      (let ((new (org--inline-image-overlays beg end)))
-        (message (if new
-		     (format "%d images displayed inline"
-			     (length new))
-		   "No images to display inline"))))))
+  (cond
+   ((not (display-graphic-p)) (message "Your Emacs does not support displaying images!"))
+   ;; 1. No argument, no region selected :: toggle (display or hide dwim) images in current section or image link at point.
+   ((and (null arg) (not (use-region-p)))
+    (let ((context (org-element-context))
+          (beg (if (org-before-first-heading-p) (point-min)
+	         (save-excursion
+	           (org-with-limited-levels (org-back-to-heading t) (point)))))
+          (end (org-with-limited-levels (org-entry-end-position)))
+          (include-linked nil))
+      ;; toggle display of inline image link at point.
+      (if (memq (org-element-type context) '(link))
+          (let ((beg (org-element-property :begin context))
+		(end (org-element-property :end context)))
+	    (if (org--inline-image-overlays beg end)
+                (progn
+                  (org-remove-inline-images beg end)
+	          (message "Remove inline image at point."))
+	      (org-display-inline-images include-linked t beg end)
+	      (message "Display inline image at point ... done.")))
+        (if (org--inline-image-overlays beg end)
+            (org-remove-inline-images beg end)
+          (message "Display inline images in section...")
+          (org-display-inline-images include-linked t beg end)
+          (message "Display inline images in section... done.")))))
+   ;; 2. No argument, region selected :: toggle images in region.
+   ((and (null arg) (use-region-p))
+    (let* ((beg (region-beginning))
+           (end (region-end))
+           (include-linked nil)
+           (inline-images (org--inline-image-overlays beg end)))
+      (if (org--inline-image-overlays beg end)
+          (progn
+            (org-remove-inline-images beg end)
+            (message "%d inline images display removed." (length inline-images)))
+        (message "Display inline images displayed in region...")
+        (org-display-inline-images include-linked t beg end)
+        (message "Display inline images displayed in region... done."))))
+   ;; 3. C-u argument :: toggle images in the whole buffer.
+   ((equal arg '(4))
+    (let ((include-linked nil))
+      (if (org--inline-image-overlays (point-min) (point-max))
+          (org-remove-inline-images (point-min) (point-max))
+        (message "Display all inline images in buffer...")
+        (org-display-inline-images include-linked nil (point-min) (point-max))
+        (message "Display all inline images in buffer... done."))))
+   ;; 4. C-u C-u argument, no region selected :: unconditionally hide images in the buffer.
+   ((and (equal arg '(16)) (not (use-region-p)))
+    (org-remove-inline-images (point-min) (point-max))
+    (message "Remove all inline images in buffer displaying."))
+   ;; 5. M-1 argument, no region selected :: display images in current section with `INCLUDE-LINKED'.
+   ((and (equal arg 1) (not (use-region-p)))
+    (let ((context (org-element-context))
+          (beg (if (org-before-first-heading-p) (point-min)
+	         (save-excursion
+	           (org-with-limited-levels (org-back-to-heading t) (point)))))
+          (end (org-with-limited-levels (org-entry-end-position)))
+          (include-linked t))
+      (message "Display inline images in section...")
+      (org-display-inline-images include-linked t beg end)
+      (message "Display inline images in section... done.")))
+   ;; 6. M-1 argument, region selected :: ... in region ...
+   ;; [M-1] / [C-1] argument for linked images like:
+   ;; [[https://orgmode.org/resources/img/org-mode-unicorn.svg][description]]
+   ((and (equal arg 1) (use-region-p))
+    (let* ((beg (region-beginning))
+	   (end (region-end))
+           (include-linked t)
+           (inline-images (org--inline-image-overlays beg end)))
+      (org-display-inline-images include-linked t beg end)
+      (message "%d inline images displayed in region... done."  (length inline-images))))
+   ;; 7. M-11 argument :: ... in the whole buffer ...
+   ((equal arg '11)
+    (let ((beg (point-min))
+          (end (point-max))
+          (include-linked t))
+      (message "Display inline images in buffer...")
+      (org-display-inline-images include-linked t beg end)
+      (message "Display inline images in buffer... done.")))
+   ;; 8. Any other argument :: treat ARG as INCLUDE-LINKED = t
+   ((not (null arg))
+    (let ((beg (if (org-before-first-heading-p) (point-min)
+	         (save-excursion
+	           (org-with-limited-levels (org-back-to-heading t) (point)))))
+          (end (org-with-limited-levels (org-entry-end-position)))
+          (include-linked arg))
+      (message "Display inline images in section...")
+      (org-display-inline-images include-linked t beg end)
+      (message "Display inline images in section... done.")))))
 
 (defun org-redisplay-inline-images ()
   "Assure display of inline images and refresh them."
-- 
2.39.3 (Apple Git-146)


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [PATCH v4.0] Re: [PATCH] add a function to only refresh inline images under current headline instead of global buffer
       [not found]                           ` <66a8b73b.170a0220.383476.996e@mx.google.com>
@ 2024-08-12 10:18                             ` Ihor Radchenko
  2024-08-14  2:04                               ` stardiviner
  0 siblings, 1 reply; 40+ messages in thread
From: Ihor Radchenko @ 2024-08-12 10:18 UTC (permalink / raw)
  To: Christopher M. Miles; +Cc: Org mode

[-- Attachment #1: Type: text/plain, Size: 1522 bytes --]

"Christopher M. Miles" <numbchild@gmail.com> writes:

>> What about the following treatment of ARG:
>>
>> 1. No argument, no region selected :: toggle (display or hide dwim) images in current section 
>> 2. No argument, region selected: toggle images in region
>> 3. C-u argument :: toggle images in the whole buffer
>> 4. C-u C-u argument, no region selected :: unconditionally hide images in the buffer
>> 5. M-1 argument, no region selected :: display images in current section with INCLUDE-LINKED
>> 6. M-1 argument, region selected :: ... in region ...
>> 7. M-11 argument :: ... in the whole buffer ...
>> 8. Any other argument :: treat as INCLUDE-LINKED = t
>>
>> And please document all the new arguments in the manual and etc/ORG-NEWS file.
>
> I followed you upper 8 conditions to re-write my patch.
> Except the 8. condition I'm not sure I understand correctly.
> And I extend 1. condition to support the inline image link at point toggle displaying.
> ...

I do not like the code repetitions in the patch and relying upon
`use-region-p' even for non-interactive use.

I am attaching a complete rewrite of your idea.
Please let me know if my patch does everything you want to include into
the command.

Note that I went with a new idea of introducing a branch new function
instead of changing `org-toggle-inline-images'.  This way, existing
users of `org-toggle-inline-images' will not be affected at all.  We are
just changing the default C-c C-x C-v binding.  This way, the breakage
is a little as possible.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-org-toggle-inline-images-command-New-command-for-C-c.patch --]
[-- Type: text/x-patch, Size: 10393 bytes --]

From 0a7b2a8850013be3ca916f4e5c67ac68b94feb25 Mon Sep 17 00:00:00 2001
Message-ID: <0a7b2a8850013be3ca916f4e5c67ac68b94feb25.1723457647.git.yantar92@posteo.net>
From: Ihor Radchenko <yantar92@posteo.net>
Date: Mon, 12 Aug 2024 12:11:17 +0200
Subject: [PATCH] org-toggle-inline-images-command: New command for C-c C-x C-v
 binding

* lisp/org.el (org-toggle-inline-images-command): New command to
toggle images.  Unlike the old `org-toggle-inline-image', it is more
flexible and default to toggling images at point/current entry.
* lisp/org-keys.el (org-mode-map): Bind C-c C-x C-v to the new
command.
* doc/org-manual.org (Images): Update the manual describing the new
command behaviour.
* etc/ORG-NEWS (=C-c C-x C-v= command toggling inline image display
has been reworked): Document the breaking change.

Link: https://list.orgmode.org/6461a84b.a70a0220.b6d36.5d00@mx.google.com/
---
 doc/org-manual.org | 17 +++++++---
 etc/ORG-NEWS       | 31 ++++++++++++++++++
 lisp/org-keys.el   |  4 +--
 lisp/org.el        | 82 +++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 126 insertions(+), 8 deletions(-)

diff --git a/doc/org-manual.org b/doc/org-manual.org
index 6cf51ebcac..9365c66b10 100644
--- a/doc/org-manual.org
+++ b/doc/org-manual.org
@@ -11806,14 +11806,21 @@ ** Images
 Such images can be displayed within the buffer with the following
 command:
 
-- {{{kbd(C-c C-x C-v)}}} (~org-toggle-inline-images~) ::
+- {{{kbd(C-c C-x C-v)}}} (~org-toggle-inline-images-command~) ::
 
   #+kindex: C-c C-x C-v
-  #+findex: org-toggle-inline-images
+  #+findex: org-toggle-inline-images-command
+  Toggle the inline display of linked images in current section or at
+  point.  With a prefix argument, toggle inline images in the whole
+  buffer.  With double prefix argument, hide all the images in buffer.
+
+  By default, only the image links without description are displayed.
+  You can force displaying all the images using numeric argument to
+  toggle all the images in current section (~1~ argument) or the whole
+  buffer (~11~ argument).
+
   #+vindex: org-startup-with-inline-images
-  Toggle the inline display of linked images.  When called with a
-  prefix argument, also display images that do have a link
-  description.  You can ask for inline images to be displayed at
+  You can ask for inline images to be displayed at
   startup by configuring the variable
   ~org-startup-with-inline-images~[fn:: The variable
   ~org-startup-with-inline-images~ can be set within a buffer with the
diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS
index 6f858f3ca7..533965311a 100644
--- a/etc/ORG-NEWS
+++ b/etc/ORG-NEWS
@@ -18,6 +18,37 @@ Please send Org bug reports to mailto:emacs-orgmode@gnu.org.
 # require user action for most Org mode users.
 # Sorted from most important to least important.
 
+*** =C-c C-x C-v= command toggling inline image display has been reworked
+
+Previously, =C-c C-x C-v= always toggled image display in the whole
+buffer (or narrowed part of the buffer).  With prefix argument, it
+also forced displaying image links with description.
+
+Now, =C-c C-x C-v= is bound to a new command
+~org-toggle-inline-images-command~, which uses different defaults:
+
+1. By default, it toggles image at point or, if there is no image at
+   point, images in current entry
+
+2. When region is active, it is honored
+
+3. =C-u= argument changed its meaning.  Now, it forces toggling images
+   in the whole buffer
+
+4. =C-u C-u= argument unconditionally hides all the images in buffer
+
+5. Displaying images over links with description can be forced using
+   numeric argument:
+   - ~C-u 1~ for toggling all images at point/current entry
+   - ~C-u 11~ for toggling all images in buffer
+
+The old ~org-toggle-inline-images~ command is still available.  You
+can bind it back to =C-c C-x C-v= by adding the following to you config:
+#+begin_src emacs-lisp
+(eval-after-load 'org-keys
+  (org-defkey org-mode-map (kbd "C-c C-x C-v") #'org-toggle-inline-images))
+#+end_src
+
 *** Org mode may throw an error when attempting to include remote unsafe resource noninteractively
 
 Previously, when ~org-resource-download-policy~ is ~ask~ (default),
diff --git a/lisp/org-keys.el b/lisp/org-keys.el
index edd4059fc6..1daedaae8c 100644
--- a/lisp/org-keys.el
+++ b/lisp/org-keys.el
@@ -218,7 +218,7 @@ (declare-function org-toggle-checkbox "org" (&optional toggle-presence))
 (declare-function org-toggle-radio-button "org" (&optional arg))
 (declare-function org-toggle-comment "org" ())
 (declare-function org-toggle-fixed-width "org" ())
-(declare-function org-toggle-inline-images "org" (&optional include-linked beg end))
+(declare-function org-toggle-inline-images-command "org" (&optional arg beg end))
 (declare-function org-latex-preview "org" (&optional arg))
 (declare-function org-toggle-narrow-to-subtree "org" ())
 (declare-function org-toggle-ordered-property "org" ())
@@ -618,7 +618,7 @@ (org-defkey org-mode-map (kbd "C-c C-x C-d") #'org-clock-display)
 (org-defkey org-mode-map (kbd "C-c C-x x") #'org-dynamic-block-insert-dblock)
 (org-defkey org-mode-map (kbd "C-c C-x C-u") #'org-dblock-update)
 (org-defkey org-mode-map (kbd "C-c C-x C-l") #'org-latex-preview)
-(org-defkey org-mode-map (kbd "C-c C-x C-v") #'org-toggle-inline-images)
+(org-defkey org-mode-map (kbd "C-c C-x C-v") #'org-toggle-inline-images-command)
 (org-defkey org-mode-map (kbd "C-c C-x C-M-v") #'org-redisplay-inline-images)
 (org-defkey org-mode-map (kbd "C-c C-x \\") #'org-toggle-pretty-entities)
 (org-defkey org-mode-map (kbd "C-c C-x C-b") #'org-toggle-checkbox)
diff --git a/lisp/org.el b/lisp/org.el
index bcab7ca860..39167c656f 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -16654,7 +16654,8 @@ (defun org-normalize-color (value)
 (defvar-local org-inline-image-overlays nil)
 ;; Preserve when switching modes or when restarting Org.
 ;; If we clear the overlay list and later enable Or mode, the existing
-;; image overlays will never be cleared by `org-toggle-inline-images'.
+;; image overlays will never be cleared by `org-toggle-inline-images'
+;; and `org-toggle-inline-images-command'.
 (put 'org-inline-image-overlays 'permanent-local t)
 
 (defun org--inline-image-overlays (&optional beg end)
@@ -16667,6 +16668,85 @@ (defun org--inline-image-overlays (&optional beg end)
       (when (memq ov org-inline-image-overlays)
         (push ov result)))))
 
+(defun org-toggle-inline-images-command (&optional arg beg end)
+  "Toggle display of inline images without description at point.
+
+When point is at an image link, toggle displaying that image.
+Otherwise, toggle displaying images in current entry.
+
+When region BEG..END is active, toggle displaying images in the
+region.
+
+With numeric prefix ARG 1, display images with description as well.
+
+With prefix ARG `\\[universal-argument]', toggle displaying images in
+the accessible portion of the buffer.  With numeric prefix ARG 11, do
+the same, but include images with description.
+
+With prefix ARG `\\[universal-argument] \\[universal-argument]', hide
+all the images in accessible portion of the buffer.
+
+This command is designed for interactive use.  From Elisp, you can
+also use `org-toggle-inline-images'."
+  (interactive (cons current-prefix-arg
+                     (when (use-region-p)
+                       (list (region-beginning) (region-end)))))
+  (let* ((include-linked
+          (cond
+           ((member arg '(nil (4) (16)) ) nil)
+           ((member arg '(1 11)) 'include-linked)
+           (t 'include-linked)))
+         (interactive? (called-interactively-p 'any))
+         (toggle-images
+          (lambda (&optional beg end scope force-remove)
+            (let* ((beg (or beg (point-min)))
+                   (end (or end (point-max)))
+                   (old (org--inline-image-overlays beg end))
+                   (scope (or scope (format "%d:%d" beg end))))
+              (if (or old force-remove)
+                  (progn
+                    (org-remove-inline-images beg end)
+                    (when interactive?
+                      (message
+                       "[%s] Inline image display turned off (removed %d images)"
+                       scope (length old))))
+	        (org-display-inline-images include-linked t beg end)
+                (when interactive?
+                  (let ((new (org--inline-image-overlays beg end)))
+                    (message
+                     (if new
+		         (format "[%s] %d images displayed inline %s"
+			         scope (length new)
+                                 (if include-linked "(including images with description)"
+                                   ""))
+		       (format "[%s] No images to display inline" scope))))))))))
+    (cond
+     ((not (display-graphic-p))
+      (message "Your Emacs does not support displaying images!"))
+     ;; Region selected :: toggle images in region.
+     ((and beg end) (funcall toggle-images beg end "region"))
+     ;; C-u or C-11 argument :: toggle images in the whole buffer.
+     ((member arg '(11 (4))) (funcall toggle-images nil nil "buffer"))
+     ;; C-u C-u argument :: unconditionally hide images in the buffer.
+     ((equal arg '(16)) (funcall toggle-images nil nil "buffer" 'remove))
+     ;; Argument nil or 1, no region selected :: toggle (display or hide
+     ;; dwim) images in current section or image link at point.
+     ((and (member arg '(nil 1)) (null beg) (null end))
+      (let ((context (org-element-context)))
+        ;; toggle display of inline image link at point.
+        (if (org-element-type-p context 'link)
+            (funcall toggle-images
+                     (org-element-begin context)
+                     (org-element-end context)
+                     "image at point")
+          (let ((beg (if (org-before-first-heading-p) (point-min)
+	               (save-excursion
+	                 (org-with-limited-levels (org-back-to-heading t) (point)))))
+                (end (org-with-limited-levels (org-entry-end-position))))
+            (funcall toggle-images beg end "current section")))))
+     ;; Any other non-nil argument.
+     ((not (null arg)) (funcall toggle-images beg end "region")))))
+
 (defun org-toggle-inline-images (&optional include-linked beg end)
   "Toggle the display of inline images.
 INCLUDE-LINKED is passed to `org-display-inline-images'."
-- 
2.45.2


[-- Attachment #3: Type: text/plain, Size: 224 bytes --]


-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [PATCH v4.0] Re: [PATCH] add a function to only refresh inline images under current headline instead of global buffer
  2024-08-12 10:18                             ` Ihor Radchenko
@ 2024-08-14  2:04                               ` stardiviner
  2024-08-18 10:27                                 ` Ihor Radchenko
  2024-08-18 10:34                                 ` [FR] Automatically display images in resutls of evaluation (was: [PATCH v4.0] Re: [PATCH] add a function to only refresh inline images under current headline instead of global buffer) Ihor Radchenko
  0 siblings, 2 replies; 40+ messages in thread
From: stardiviner @ 2024-08-14  2:04 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: Org mode

[-- Attachment #1: Type: text/plain, Size: 3145 bytes --]

I agree with your patch solution. I have tested fine. Thanks for your
re-write.

I have an idea, would you like to add an function in bellowing:

#+begin_src emacs-lisp
(defun org-toggle-inline-images-in-results ()
  "Toggle inline images in babel source block results."
  (save-excursion
    ;; [C-c C-v C-o] `org-babel-open-src-block-result'
    (let ((begin (org-babel-where-is-src-block-result))
          (end (progn
                 (end-of-line)
                 (skip-chars-forward " \r\t\n")
                 (looking-at org-link-bracket-re)
                 ;; (org-babel-read-result)
                 (point))))
      (org-toggle-inline-images-command nil begin end))))

(add-hook 'org-babel-after-execute-hook
'org-toggle-inline-images-in-results)
#+end_src

WDYT? after all I originally propose this patch for this purpose to
improve the babel result inline image toggle displaying performance.


[stardiviner]           <Hack this world!>      GPG key ID: 47C32433
IRC(freeenode): stardiviner                     Twitter:  @numbchild
Key fingerprint = 9BAA 92BC CDDD B9EF 3B36  CB99 B8C4 B8E5 47C3 2433
Blog: http://stardiviner.github.io/


On Mon, Aug 12, 2024 at 6:17 PM Ihor Radchenko <yantar92@posteo.net> wrote:

> "Christopher M. Miles" <numbchild@gmail.com> writes:
>
> >> What about the following treatment of ARG:
> >>
> >> 1. No argument, no region selected :: toggle (display or hide dwim)
> images in current section
> >> 2. No argument, region selected: toggle images in region
> >> 3. C-u argument :: toggle images in the whole buffer
> >> 4. C-u C-u argument, no region selected :: unconditionally hide images
> in the buffer
> >> 5. M-1 argument, no region selected :: display images in current
> section with INCLUDE-LINKED
> >> 6. M-1 argument, region selected :: ... in region ...
> >> 7. M-11 argument :: ... in the whole buffer ...
> >> 8. Any other argument :: treat as INCLUDE-LINKED = t
> >>
> >> And please document all the new arguments in the manual and
> etc/ORG-NEWS file.
> >
> > I followed you upper 8 conditions to re-write my patch.
> > Except the 8. condition I'm not sure I understand correctly.
> > And I extend 1. condition to support the inline image link at point
> toggle displaying.
> > ...
>
> I do not like the code repetitions in the patch and relying upon
> `use-region-p' even for non-interactive use.
>
> I am attaching a complete rewrite of your idea.
> Please let me know if my patch does everything you want to include into
> the command.
>
> Note that I went with a new idea of introducing a branch new function
> instead of changing `org-toggle-inline-images'.  This way, existing
> users of `org-toggle-inline-images' will not be affected at all.  We are
> just changing the default C-c C-x C-v binding.  This way, the breakage
> is a little as possible.
>
>
> --
> Ihor Radchenko // yantar92,
> Org mode contributor,
> Learn more about Org mode at <https://orgmode.org/>.
> Support Org development at <https://liberapay.com/org-mode>,
> or support my work at <https://liberapay.com/yantar92>
>

[-- Attachment #2: Type: text/html, Size: 4549 bytes --]

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v4.0] Re: [PATCH] add a function to only refresh inline images under current headline instead of global buffer
  2024-08-14  2:04                               ` stardiviner
@ 2024-08-18 10:27                                 ` Ihor Radchenko
  2024-08-20  2:02                                   ` Karthik Chikmagalur
  2024-08-18 10:34                                 ` [FR] Automatically display images in resutls of evaluation (was: [PATCH v4.0] Re: [PATCH] add a function to only refresh inline images under current headline instead of global buffer) Ihor Radchenko
  1 sibling, 1 reply; 40+ messages in thread
From: Ihor Radchenko @ 2024-08-18 10:27 UTC (permalink / raw)
  To: stardiviner; +Cc: Org mode

stardiviner <numbchild@gmail.com> writes:

> I agree with your patch solution. I have tested fine. Thanks for your
> re-write.

Applied, onto main.
https://git.savannah.gnu.org/cgit/emacs/org-mode.git/commit/?id=d51dc4aa29

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* [FR] Automatically display images in resutls of evaluation (was: [PATCH v4.0] Re: [PATCH] add a function to only refresh inline images under current headline instead of global buffer)
  2024-08-14  2:04                               ` stardiviner
  2024-08-18 10:27                                 ` Ihor Radchenko
@ 2024-08-18 10:34                                 ` Ihor Radchenko
       [not found]                                   ` <66c54dfc.a70a0220.3c823a.2899@mx.google.com>
  1 sibling, 1 reply; 40+ messages in thread
From: Ihor Radchenko @ 2024-08-18 10:34 UTC (permalink / raw)
  To: stardiviner; +Cc: Org mode

stardiviner <numbchild@gmail.com> writes:

> I have an idea, would you like to add an function in bellowing:
>
> #+begin_src emacs-lisp
> (defun org-toggle-inline-images-in-results ()
>   "Toggle inline images in babel source block results."
>   (save-excursion
>     ;; [C-c C-v C-o] `org-babel-open-src-block-result'
>     (let ((begin (org-babel-where-is-src-block-result))
>           (end (progn
>                  (end-of-line)
>                  (skip-chars-forward " \r\t\n")
>                  (looking-at org-link-bracket-re)
>                  ;; (org-babel-read-result)
>                  (point))))
>       (org-toggle-inline-images-command nil begin end))))
>
> (add-hook 'org-babel-after-execute-hook
> 'org-toggle-inline-images-in-results)
> #+end_src
>
> WDYT? after all I originally propose this patch for this purpose to
> improve the babel result inline image toggle displaying performance.

I do not mind this kind of feature, but `org-babel-after-execute-hook'
is probably not the best place - it may be triggered noninteractively,
including in Emacs running in batch mode, where displaying images is
impossible. In particular, `org-babel-tangle' does it.

Also, you do not need `org-toggle-inline-images-command' for this. You
do not need "toggle" in general - what if an image was previously
displayed and you evaluate an src block?

A simple `org-display-inline-images' would do (with REFRESH argument).

I suggest to put this (1) under a new custom option; (2) only when
Emacs can actually display images.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v4.0] Re: [PATCH] add a function to only refresh inline images under current headline instead of global buffer
  2024-08-18 10:27                                 ` Ihor Radchenko
@ 2024-08-20  2:02                                   ` Karthik Chikmagalur
  2024-08-20 15:43                                     ` Karthik Chikmagalur
  0 siblings, 1 reply; 40+ messages in thread
From: Karthik Chikmagalur @ 2024-08-20  2:02 UTC (permalink / raw)
  To: Ihor Radchenko, stardiviner; +Cc: Org mode

> stardiviner <numbchild@gmail.com> writes:
>
>> I agree with your patch solution. I have tested fine. Thanks for your
>> re-write.
>
> Applied, onto main.
> https://git.savannah.gnu.org/cgit/emacs/org-mode.git/commit/?id=d51dc4aa29

I just noticed this change, and had a couple of suggestions.  Right now
the commands org-latex-preview and org-toggle-inline-images-command do
similar things -- placing overlays over LaTeX fragments or image links
respectively.  But their regular and prefix arg behaviors are different:

| Calling convention | org-latex-preview             | org-toggle-inline-images-command  |
|--------------------+-------------------------------+-----------------------------------|
| C-c C-x C-[l,v]    | toggle preview at point       | toggle preview at point           |
|                    | or preview current entry      | or toggle in current entry        |
| With C-u           | Clear previews in section     | Toggle previews in whole buffer   |
| With C-u C-u       | Preview whole buffer          | Hide all previews in whole buffer |
| With C-u C-u C-u   | Hide previews in whole buffer | -                                 |

I think this is confusing, and it will help to stick to a single
convention for previewing "things" in Org.  Of the two, I prefer
org-latex-preview's behavior and have been using a custom library [1] to
toggle images this way, but so long as it is consistent I would be okay
with either set of behaviors.

Karthik

[1]: https://github.com/karthink/org-image-preview


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v4.0] Re: [PATCH] add a function to only refresh inline images under current headline instead of global buffer
  2024-08-20  2:02                                   ` Karthik Chikmagalur
@ 2024-08-20 15:43                                     ` Karthik Chikmagalur
  2024-08-20 18:19                                       ` Ihor Radchenko
  0 siblings, 1 reply; 40+ messages in thread
From: Karthik Chikmagalur @ 2024-08-20 15:43 UTC (permalink / raw)
  To: Ihor Radchenko, stardiviner; +Cc: Org mode

> | Calling convention | org-latex-preview             | org-toggle-inline-images-command  |
> |--------------------+-------------------------------+-----------------------------------|
> | C-c C-x C-[l,v]    | toggle preview at point       | toggle preview at point           |
> |                    | or preview current entry      | or toggle in current entry        |
> | With C-u           | Clear previews in section     | Toggle previews in whole buffer   |
> | With C-u C-u       | Preview whole buffer          | Hide all previews in whole buffer |
> | With C-u C-u C-u   | Hide previews in whole buffer | -                                 |
>
> I think this is confusing, and it will help to stick to a single
> convention for previewing "things" in Org.  Of the two, I prefer
> org-latex-preview's behavior and have been using a custom library [1] to
> toggle images this way, but so long as it is consistent I would be okay
> with either set of behaviors.

Ihor: Based on this, what do you think of the following behavior for
org-toggle-inline-images-command?

C-c C-x C-v  : toggle link preview at point
               or unconditionally preview active region (not toggle)
               or unconditionally preview current entry/section (not toggle)

With C-u     : Clear preview in active region (not toggle)
               or clear preview in current entry/section (not toggle)

With C-u C-u : Unconditionally preview whole buffer (not toggle)

With C-u C-u C-u: Clear previews in whole buffer

With C-u 1   : Same as C-c C-x C-v, but including images for links with descriptions
With C-u 11  : Same as C-u C-u, but including images for links with descriptions

This is much closer to the behavior of org-latex-preview.  Since all
these behaviors are new I think it makes sense to be as consistent as
possible for "preview" behavior in Org.

----

Separately, are you interested in separating the link preview code into
an org-image-preview library?  This will include the feature of
registering link preview handlers for different kinds of links, such as
video thumbnails for local video links and youtube links, etc.  I
already have this working for a couple of years now in
org-image-preview.el (linked in previous email), but hadn't submitted it
yet since the previews are synchronous.  I was waiting for org-async to
be added along with the LaTeX preview patch so I could submit an async
version.  But there appears to be activity around image previews right
now so I can submit it and work on making it async later.

Karthik


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v4.0] Re: [PATCH] add a function to only refresh inline images under current headline instead of global buffer
  2024-08-20 15:43                                     ` Karthik Chikmagalur
@ 2024-08-20 18:19                                       ` Ihor Radchenko
  2024-08-20 19:46                                         ` Karthik Chikmagalur
  0 siblings, 1 reply; 40+ messages in thread
From: Ihor Radchenko @ 2024-08-20 18:19 UTC (permalink / raw)
  To: Karthik Chikmagalur; +Cc: stardiviner, Org mode

Karthik Chikmagalur <karthikchikmagalur@gmail.com> writes:

> Ihor: Based on this, what do you think of the following behavior for
> org-toggle-inline-images-command?
>
> C-c C-x C-v  : toggle link preview at point
>                or unconditionally preview active region (not toggle)
>                or unconditionally preview current entry/section (not toggle)
>
> With C-u     : Clear preview in active region (not toggle)
>                or clear preview in current entry/section (not toggle)
>
> With C-u C-u : Unconditionally preview whole buffer (not toggle)
>
> With C-u C-u C-u: Clear previews in whole buffer
>
> With C-u 1   : Same as C-c C-x C-v, but including images for links with descriptions
> With C-u 11  : Same as C-u C-u, but including images for links with descriptions
>
> This is much closer to the behavior of org-latex-preview.  Since all
> these behaviors are new I think it makes sense to be as consistent as
> possible for "preview" behavior in Org.

I agree.
Do you want to create a patch to that effect?

> Separately, are you interested in separating the link preview code into
> an org-image-preview library?  This will include the feature of
> registering link preview handlers for different kinds of links, such as
> video thumbnails for local video links and youtube links, etc.  I
> already have this working for a couple of years now in
> org-image-preview.el (linked in previous email), but hadn't submitted it
> yet since the previews are synchronous.  I was waiting for org-async to
> be added along with the LaTeX preview patch so I could submit an async
> version.  But there appears to be activity around image previews right
> now so I can submit it and work on making it async later.

This sounds like a reasonable addition, yes.
Maybe even hook into link parameters.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v4.0] Re: [PATCH] add a function to only refresh inline images under current headline instead of global buffer
  2024-08-20 18:19                                       ` Ihor Radchenko
@ 2024-08-20 19:46                                         ` Karthik Chikmagalur
  2024-08-22 13:19                                           ` Ihor Radchenko
  0 siblings, 1 reply; 40+ messages in thread
From: Karthik Chikmagalur @ 2024-08-20 19:46 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: stardiviner, Org mode

>> This is much closer to the behavior of org-latex-preview.  Since all
>> these behaviors are new I think it makes sense to be as consistent as
>> possible for "preview" behavior in Org.
>
> I agree.
> Do you want to create a patch to that effect?

I'll send a patch.

>> Separately, are you interested in separating the link preview code into
>> an org-image-preview library?  This will include the feature of
>> registering link preview handlers for different kinds of links, such as
>> video thumbnails for local video links and youtube links, etc.  I
>> already have this working for a couple of years now in
>> org-image-preview.el (linked in previous email), but hadn't submitted it
>> yet since the previews are synchronous.  I was waiting for org-async to
>> be added along with the LaTeX preview patch so I could submit an async
>> version.  But there appears to be activity around image previews right
>> now so I can submit it and work on making it async later.
>
> This sounds like a reasonable addition, yes.
> Maybe even hook into link parameters.

Yes, the idea is to add an org-link-parameter named ":preview" so each
link type can register how it should be previewed.  When omitted, we
fall back to a default (only for file links) that's the current
image preview behavior.

More fine-grained behavior may be desired in the future -- for example,
web url links to YouTube should be previewed differently from web url
links to arXiv, but for now this will be the responsibility of the
single :preview function in org-link-parameters.

Would you like this to be part of org.el or should I spin out an
org-image-preview.el feature+library?

Karthik


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [FR] Automatically display images in resutls of evaluation
       [not found]                                   ` <66c54dfc.a70a0220.3c823a.2899@mx.google.com>
@ 2024-08-22 13:06                                     ` Ihor Radchenko
  0 siblings, 0 replies; 40+ messages in thread
From: Ihor Radchenko @ 2024-08-22 13:06 UTC (permalink / raw)
  To: Christopher M. Miles; +Cc: emacs-orgmode


[ Adding Org ML back to CC ]

"Christopher M. Miles" <numbchild@gmail.com> writes:

>> A simple `org-display-inline-images' would do (with REFRESH argument).
>
> I will adjust my upper code snippet in my Emacs config.

I myself have something similar in my config:

(add-hook
 'org-babel-after-execute-hook
 (lambda ()
   (unless (eq this-command 'org-babel-tangle)
     (org-display-inline-images
      nil nil
      (save-excursion (org-back-to-heading-or-point-min t) (point))
      (save-excursion (or (outline-next-heading) (point-max)))))))

And unless (eq this-command 'org-babel-tangle) was there for a reason
(although I do not remember what was that reason). Still, need to be
careful.

>> I suggest to put this (1) under a new custom option; (2) only when
>> Emacs can actually display images.
>
> I suggest use an custom option for this behavior. About (2), can add a condition: (display-graphic-p)
>
> (when (display-graphic-p)

Looks reasonable.

>     (save-excursion
>       ;; [C-c C-v C-o] `org-babel-open-src-block-result'
>       (let ((begin (org-babel-where-is-src-block-result))
>             (end (progn
>                    (end-of-line)
>                    (skip-chars-forward " \r\t\n")
>                    (looking-at org-link-bracket-re)
>                    ;; (org-babel-read-result)
>                    (point))))

What is more than one image? What if it is wrapped into, say, a drawer?
I'd rather be a bit less selective and refresh the whole result element.

Looking forward to your updated patch.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v4.0] Re: [PATCH] add a function to only refresh inline images under current headline instead of global buffer
  2024-08-20 19:46                                         ` Karthik Chikmagalur
@ 2024-08-22 13:19                                           ` Ihor Radchenko
  2024-08-23  6:04                                             ` Karthik Chikmagalur
  2024-08-23 23:36                                             ` [PATCH v1] Inline image display as part of a new org-link-preview system Karthik Chikmagalur
  0 siblings, 2 replies; 40+ messages in thread
From: Ihor Radchenko @ 2024-08-22 13:19 UTC (permalink / raw)
  To: Karthik Chikmagalur; +Cc: stardiviner, Org mode

Karthik Chikmagalur <karthikchikmagalur@gmail.com> writes:

>> Maybe even hook into link parameters.
>
> Yes, the idea is to add an org-link-parameter named ":preview" so each
> link type can register how it should be previewed.  When omitted, we
> fall back to a default (only for file links) that's the current
> image preview behavior.
>
> More fine-grained behavior may be desired in the future -- for example,
> web url links to YouTube should be previewed differently from web url
> links to arXiv, but for now this will be the responsibility of the
> single :preview function in org-link-parameters.

This is not a problem.
It is possible (and also Elispy) to use advices:

(add-function :before-until (org-link-get-parameter "id" :follow) #'my-function)

We may want to document this fact better though.

> Would you like this to be part of org.el or should I spin out an
> org-image-preview.el feature+library?

Spin out will be easier when for my rebase :)

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v4.0] Re: [PATCH] add a function to only refresh inline images under current headline instead of global buffer
  2024-08-22 13:19                                           ` Ihor Radchenko
@ 2024-08-23  6:04                                             ` Karthik Chikmagalur
  2024-08-23 23:36                                             ` [PATCH v1] Inline image display as part of a new org-link-preview system Karthik Chikmagalur
  1 sibling, 0 replies; 40+ messages in thread
From: Karthik Chikmagalur @ 2024-08-23  6:04 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: stardiviner, Org mode

> This is not a problem.
> It is possible (and also Elispy) to use advices:
>
> (add-function :before-until (org-link-get-parameter "id" :follow) #'my-function)
>
> We may want to document this fact better though.

I've noticed that org-link-parameters that are functions, like the
:follow, :export and :activate-func parameters, are given very specific
arguments.  For example:

`:activate-func'

  Function to run at the end of Font Lock activation.  It must
  accept four arguments:
  - the buffer position at the start of the link,
  - the buffer position at its end,
  - the path, as a string,
  - a boolean, non-nil when the link has brackets.

This is even though these functions can gather any information about the
link using org-element.  This suggests that we have something specific
in mind for what these functions should do.  Along the same lines, my
plan is to add a :preview (or :preview-func) parameter that looks like
this:

`:preview'

  Function to run when generating an in-buffer preview for the
  link.  It must accept two arguments:
  - an overlay placed from the start to the end of the link.
  - the path, as a string.

(I can add more arguments if it proves necessary.)

The idea is that the preview function can specify an image as the
overlay's display property, or add some other overlay property with
suitable content.  For example, for notmuch links you could specify a
before-string that adds relevant metadata from the email that's not part
of the link path, like a date/sender.

My question is: is it okay to assume that preview actions for all link
types should work by placing an overlay over the link?  Or is it too
restrictive to pass an overlay?  A more general version could leave it
to the :preview function to create the overlay, or preview it in some
other way entirely, such as by adding text properties instead of an
overlay.

One reason I would like to restrict it to an overlay is that I think a
:preview feature should not modify the buffer in any way, as adding text
properties will.

Karthik


^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH v1] Inline image display as part of a new org-link-preview system
  2024-08-22 13:19                                           ` Ihor Radchenko
  2024-08-23  6:04                                             ` Karthik Chikmagalur
@ 2024-08-23 23:36                                             ` Karthik Chikmagalur
  2024-08-24  1:00                                               ` Karthik Chikmagalur
  2024-08-31 14:22                                               ` Ihor Radchenko
  1 sibling, 2 replies; 40+ messages in thread
From: Karthik Chikmagalur @ 2024-08-23 23:36 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: stardiviner, Org mode

[-- Attachment #1: Type: text/plain, Size: 3217 bytes --]

>> Would you like this to be part of org.el or should I spin out an
>> org-image-preview.el feature+library?
>
> Spin out will be easier when for my rebase :)

Please find attached the draft of a patch implementing a general
link-preview system.

----
The idea is the following:

1. Introduce the :preview link parameter.  This is a function that is
   passed an overlay placed over a link (along with some other link
   details) and should adorn the overlay however the link should be
   previewed.  Typically this is by adding an image to the overlay, but
   it can be more general.
  
   This has a few advantages over the current system:
   - The code is much more modular.
   - Previewing image links is no longer "special": all links can have
     custom preview behavior. Users or package authors can specify how
     they want each link type to be previewed.
   - About 300 lines of code have been moved out of org.el, with more
     removals to come (details below).

2. A :preview function for links of type "file" or "attachment" is
   provided -- it is the old org-display-inline-images function, but broken
   up into a couple of more modular functions.
   
   - Note: the new preview behavior for image files should be identical,
     no changes or breaking changes are expected.

3. Introduce a new org-link-preview command.  This command has the same
   prefix arg behaviors as org-latex-preview, and previews each link
   using its :preview function.  This is a drop-in replacement for
   org-toggle-inline-images-command and org-toggle-inline-images.
   org-toggle-inline-images-command has been removed, and
   org-toggle-inline-images has been moved to org-compat.  There are a
   couple of other commands for use from elisp: org-link-preview-region
   and org-link-preview-clear.
  
   Advantages:
   - Uniform preview behavior across Org preview types (links, latex)
   - Can preview individual links, links in the section or across the buffer.
   - Can preview, refresh existing previews or disable them independently
     using different prefix arg behaviors (no need to toggle/run twice).

4. Bind C-c C-x C-v to org-link-preview.

----
Organization:

I didn't create a new feature/library: All the link-preview code is part
of ol.el.  I think it fits well there.

I can move the code for creating and examining images from org.el to a
new org-image.el or org-image-utils.el library if required.

----

Not yet handled or final:

- Link abbreviations: I'm using org-link-any-re to find links, and this
  appears to be handling link abbreviations fine.  So there is no
  special code to handle link abbreviations.  But I'm not sure.

- Updating NEWS and the manual.  I can do this at the end, before
  merging.

- The calling convention for the :preview function is not final.  Right
  now it is given the overlay, the link type and the link path.  But
  other link details can be required -- for example, image links need to
  read the org keywords for the image width and alignment, so I end up
  calling (org-element-context) again inside the :preview function.

----

I'll send a short example of using org-link-preview to asynchronously
preview youtube links as thumbnails soon.

Karthik

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-org-link-Move-inline-image-display-to-org-link.patch --]
[-- Type: text/x-patch, Size: 45086 bytes --]

From 93b7e50a50d7c6f72439169e5647a840c6e04bcc Mon Sep 17 00:00:00 2001
From: Karthik Chikmagalur <karthikchikmagalur@gmail.com>
Date: Fri, 23 Aug 2024 15:46:53 -0700
Subject: [PATCH 2/2] org-link: Move inline image display to org-link

Make inline image previews a part of a more universal org-link
preview feature.  Each link type can now be previewed differently
based on a new link parameter.

* lisp/ol.el (org-link-parameters, org-link-preview-overlays,
org-link-preview--get-overlays, org-link-preview--remove-overlay,
org-link-previeworg-link-preview-region, org-link-preview-clear,
org-link-preview-file): Add new commands `org-link-preview',
`org-link-preview-region' and `org-link-preview-clear' for
creating link previews for any kind of link.  Add new org-link
parameter `:preview' for specifying how a link type should be
previewed.  File links and attachments are previewed using inline
image previews as before.

* testing/lisp/test-org-fold.el: Use `org-link-preview'.

* lisp/org.el (org-toggle-inline-images,
org-toggle-inline-images-command, org-display-inline-images,
org--inline-image-overlays, org-inline-image-overlays,
org-redisplay-inline-images, org-image-align,
org-display-inline-remove-overlay, org-remove-inline-images):
Obsolete and move `org-toggle-inline-images',
`org-display-inline-images' and `org-redisplay-inline-images' to
org-compat.  These are obsoleted by `org-link-preview' and
`org-link-preview-region'.  Remove
`org-toggle-inline-images-command'.  Move the other internal
functions to org-link.

* lisp/org-plot.el (org-plot/redisplay-img-in-buffer): Modify to
use `org-link-preview'.

* lisp/org-keys.el: Bind `C-c C-x C-v' to new command
`org-link-preview', which has the same prefix arg behaviors as
`org-latex-preview'.

* lisp/org-cycle.el (org-cycle-display-inline-images): Use
`org-link-preview'.

* lisp/org-compat.el (org-display-inline-remove-overlay,
org--inline-image-overlays, org-remove-inline-images,
org-inline-image-overlays, org-display-inline-images,
org-toggle-inline-images):

* lisp/org-attach.el: Add new `:preview' link parameter for links
of type "attachment".
---
 lisp/ol.el                    | 290 +++++++++++++++++++++++++++++++++-
 lisp/org-attach.el            |   4 +-
 lisp/org-compat.el            | 189 ++++++++++++++++++++++
 lisp/org-cycle.el             |  10 +-
 lisp/org-keys.el              |   4 +-
 lisp/org-plot.el              |   2 +-
 lisp/org.el                   | 283 +--------------------------------
 testing/lisp/test-org-fold.el |   4 +-
 8 files changed, 493 insertions(+), 293 deletions(-)

diff --git a/lisp/ol.el b/lisp/ol.el
index 52ea62d69..78543f8c7 100644
--- a/lisp/ol.el
+++ b/lisp/ol.el
@@ -82,6 +82,13 @@ (declare-function org-src-source-buffer "org-src" ())
 (declare-function org-src-source-type "org-src" ())
 (declare-function org-time-stamp-format "org" (&optional long inactive))
 (declare-function outline-next-heading "outline" ())
+(declare-function image-flush "image" (spec &optional frame))
+(declare-function org-entry-end-position "org" ())
+(declare-function org-element-contents-begin "org-element" (node))
+(declare-function org-attach-expand "org-attach" (file))
+(declare-function org-display-inline-image--width "org" (link))
+(declare-function org-image--align "org" (link))
+(declare-function org--create-inline-image "org" (file width))
 
 \f
 ;;; Customization
@@ -171,6 +178,14 @@ (defcustom org-link-parameters nil
 
   The default face is `org-link'.
 
+`:preview'
+
+  Function to run when generating an in-buffer preview for the
+  link.  It must accept three arguments:
+  - an overlay placed from the start to the end of the link.
+  - the link type, as a string.
+  - the path, as a string.
+
 `:help-echo'
 
   String or function used as a value for the `help-echo' text
@@ -649,6 +664,13 @@ (defvar org-link--insert-history nil
 (defvar org-link--search-failed nil
   "Non-nil when last link search failed.")
 
+(defvar-local org-link-preview-overlays nil)
+;; Preserve when switching modes or when restarting Org.
+;; If we clear the overlay list and later enable Or mode, the existing
+;; image overlays will never be cleared by `org-link-preview'
+;; and `org-link-preview-clear'.
+(put 'org-link-preview-overlays 'permanent-local t)
+
 \f
 ;;; Internal Functions
 
@@ -881,6 +903,28 @@ (defun org-link--file-link-to-here ()
          (setq desc search-desc))))
     (cons link desc)))
 
+(defun org-link-preview--get-overlays (&optional beg end)
+  "Return link preview overlays between BEG and END."
+  (let* ((beg (or beg (point-min)))
+         (end (or end (point-max)))
+         (overlays (overlays-in beg end))
+         result)
+    (dolist (ov overlays result)
+      (when (memq ov org-link-preview-overlays)
+        (push ov result)))))
+
+(defun org-link-preview--remove-overlay (ov after _beg _end &optional _len)
+  "Remove link-preview overlay OV if a corresponding region is modified.
+
+AFTER is true when this function is called post-change."
+  (when (and ov after)
+    (setq org-link-preview-overlays (delete ov org-link-preview-overlays))
+    ;; Clear image from cache to avoid image not updating upon
+    ;; changing on disk.  See Emacs bug#59902.
+    (when (overlay-get ov 'org-image-overlay)
+      (image-flush (overlay-get ov 'display)))
+    (delete-overlay ov)))
+
 \f
 ;;; Public API
 
@@ -1573,6 +1617,195 @@ (defun org-link-add-angle-brackets (s)
   (unless (equal (substring s -1) ">") (setq s (concat s ">")))
   s)
 
+;;;###autoload
+(defun org-link-preview (&optional arg beg end)
+  "Toggle display of link previews in the buffer.
+
+When region BEG..END is active, preview links in the
+region.
+
+When point is at a link, display a preview for that link only.
+Otherwise, display previews for links in current entry.
+
+With numeric prefix ARG 1, preview links with description as
+well.
+
+With prefix ARG `\\[universal-argument]', clear link previews at
+point or in the current entry.
+
+With prefix ARG `\\[universal-argument] \\[universal-argument]',
+ display link previews in the accessible portion of the
+ buffer.  With numeric prefix ARG 11, do the same, but include
+ links with descriptions.
+
+With prefix ARG `\\[universal-argument] \\[universal-argument] \\[universal-argument]',
+hide all link previews in the accessible portion of the buffer.
+
+This command is designed for interactive use.  From Elisp, you can
+also use `org-link-preview-region'."
+  (interactive (cons current-prefix-arg
+                     (when (use-region-p)
+                       (list (region-beginning) (region-end)))))
+  (let* ((include-linked
+          (cond
+           ((member arg '(nil (4) (16)) ) nil)
+           ((member arg '(1 11)) 'include-linked)
+           (t 'include-linked)))
+         (interactive? (called-interactively-p 'any))
+         (toggle-images
+          (lambda (&optional beg end scope remove)
+            (let* ((beg (or beg (point-min)))
+                   (end (or end (point-max)))
+                   (old (org-link-preview--get-overlays beg end))
+                   (scope (or scope (format "%d:%d" beg end))))
+              (if remove
+                  (progn
+                    (org-link-preview-clear beg end)
+                    (when interactive?
+                      (message
+                       "[%s] Inline link previews turned off (removed %d images)"
+                       scope (length old))))
+	        (org-link-preview-region include-linked t beg end)
+                (when interactive?
+                  (let ((new (org-link-preview--get-overlays beg end)))
+                    (message
+                     (if new
+		         (format "[%s] %d images displayed inline %s"
+			         scope (length new)
+                                 (if include-linked "(including images with description)"
+                                   ""))
+		       (format "[%s] No images to display inline" scope))))))))))
+    (cond
+     ((not (display-graphic-p))
+      (message "Your Emacs does not support displaying images!"))
+     ;; Region selected :: display previews in region.
+     ((and beg end)
+      (funcall toggle-images beg end "region"
+               (and (equal arg '(4)) 'remove)))
+     ;; C-u argument: clear image at point or in entry
+     ((equal arg '(4))
+      (if (get-char-property (point) 'org-image-overlay)
+          ;; clear link preview at point
+          (when-let ((context (org-element-context))
+                     ((org-element-type-p context 'link)))
+            (funcall toggle-images
+                     (org-element-begin context)
+                     (org-element-end context)
+                     "preview at point" 'remove))
+        ;; Clear link previews in entry
+        (funcall toggle-images
+                 (if (org-before-first-heading-p) (point-min)
+                   (save-excursion
+                     (org-with-limited-levels (org-back-to-heading t) (point))))
+                 (org-with-limited-levels (org-entry-end-position))
+                 "current section" 'remove)))
+     ;; C-u C-u or C-11 argument :: display images in the whole buffer.
+     ((member arg '(11 (16))) (funcall toggle-images nil nil "buffer"))
+     ;; C-u C-u C-u argument :: unconditionally hide images in the buffer.
+     ((equal arg '(64)) (funcall toggle-images nil nil "buffer" 'remove))
+     ;; Argument nil or 1, no region selected :: display images in
+     ;; current section or image link at point.
+     ((and (member arg '(nil 1)) (null beg) (null end))
+      (let ((context (org-element-context)))
+        ;; toggle display of inline image link at point.
+        (if (org-element-type-p context 'link)
+            (let* ((ov (cdr-safe (get-char-property-and-overlay
+                                  (point) 'org-image-overlay)))
+                   (remove? (and ov (memq ov org-link-preview-overlays)
+                                 'remove)))
+              (funcall toggle-images
+                       (org-element-begin context)
+                       (org-element-end context)
+                       "image at point" remove?))
+          (let ((beg (if (org-before-first-heading-p) (point-min)
+	               (save-excursion
+	                 (org-with-limited-levels (org-back-to-heading t) (point)))))
+                (end (org-with-limited-levels (org-entry-end-position))))
+            (funcall toggle-images beg end "current section")))))
+     ;; Any other non-nil argument.
+     ((not (null arg)) (funcall toggle-images beg end "region")))))
+
+(defun org-link-preview-region (&optional include-linked refresh beg end)
+  "Display link previews.
+
+A previewable link type is one that has a `:preview' link
+parameter, see `org-link-parameters'.
+
+By default, a file link or attachment is previewable if it
+follows either of these conventions:
+
+  1. Its path is a file with an extension matching return value
+     from `image-file-name-regexp' and it has no contents.
+
+  2. Its description consists in a single link of the previous
+     type.  In this case, that link must be a well-formed plain
+     or angle link, i.e., it must have an explicit \"file\" or
+     \"attachment\" type.
+
+File links are equipped with the keymap `image-map'.
+
+When optional argument INCLUDE-LINKED is non-nil, links with a
+text description part will also be inlined.  This can be nice for
+a quick look at those images, but it does not reflect what
+exported files will look like.
+
+When optional argument REFRESH is non-nil, refresh existing
+images between BEG and END.  This will create new image displays
+only if necessary.
+
+BEG and END define the considered part.  They default to the
+buffer boundaries with possible narrowing."
+  (interactive "P")
+  (when (display-graphic-p)
+    (when refresh (org-link-preview-clear beg end))
+    (when (fboundp 'clear-image-cache) (clear-image-cache)))
+  (org-with-point-at (or beg (point-min))
+    (let ((case-fold-search t))
+      (while (re-search-forward org-link-any-re end t)
+        (when-let* ((link (org-element-lineage
+                           (save-match-data (org-element-context))
+                           'link t))
+                    (linktype (org-element-property :type link))
+                    (preview-func (org-link-get-parameter linktype :preview))
+                    (path (and (or include-linked
+                                   (not (org-element-contents-begin link)))
+                               (org-element-property :path link))))
+          ;; Create an overlay to hold the preview
+          (let ((ov (make-overlay
+                     (org-element-begin link)
+                     (progn
+		       (goto-char
+			(org-element-end link))
+		       (unless (eolp) (skip-chars-backward " \t"))
+		       (point)))))
+            ;; TODO: Change this overlay property to `org-link-preview' everywhere.
+            (overlay-put ov 'org-image-overlay t)
+            (overlay-put ov 'modification-hooks
+                         (list 'org-link-preview--remove-overlay))
+            ;; call preview function for link type
+            (funcall preview-func ov linktype path)
+            ;; If overlay still exists, add it to the list
+            (when (overlay-buffer ov)
+              (push ov org-link-preview-overlays))))))))
+
+(defun org-link-preview-clear (&optional beg end)
+  "Clear link previews in region BEG to END."
+  (interactive (and (use-region-p) (list (region-beginning) (region-end))))
+  (let* ((beg (or beg (point-min)))
+         (end (or end (point-max)))
+         (overlays (overlays-in beg end)))
+    (dolist (ov overlays)
+      (when (memq ov org-link-preview-overlays)
+        (when-let ((image (overlay-get ov 'display))
+                   ((imagep image)))
+          (image-flush image))
+        (setq org-link-preview-overlays (delq ov org-link-preview-overlays))
+        (delete-overlay ov)))
+    ;; Clear removed overlays.
+    (dolist (ov org-link-preview-overlays)
+      (unless (overlay-buffer ov)
+        (setq org-link-preview-overlays (delq ov org-link-preview-overlays))))))
+
 \f
 ;;; Built-in link types
 
@@ -1595,7 +1828,62 @@ (defun org-link--open-elisp (path _)
 (org-link-set-parameters "elisp" :follow #'org-link--open-elisp)
 
 ;;;; "file" link type
-(org-link-set-parameters "file" :complete #'org-link-complete-file)
+(org-link-set-parameters "file"
+                         :complete #'org-link-complete-file
+                         :preview #'org-link-preview-file)
+
+(defun org-link-preview-file (ov linktype path)
+  "Display image file PATH in overlay OV.
+
+LINKTYPE is the Org link type used to preview PATH, either
+\"file\" or \"attachment\".
+
+Equip each image with the keymap `image-map'.
+
+This is intended to be used as the `:preview' link property of
+file links, see `org-link-parameters'."
+  (if-let ((file-full
+            (if (equal "attachment" linktype)
+		(progn
+                  (require 'org-attach)
+		  (ignore-errors (org-attach-expand path)))
+              (expand-file-name path)))
+           (file (substitute-in-file-name file-full))
+           ((string-match-p (image-file-name-regexp) file))
+           ((file-exists-p file)))
+      (let* ((link (org-element-lineage
+		    (save-excursion
+                      (goto-char (overlay-start ov))
+                      (save-match-data (org-element-context)))
+		    'link t))
+             (width (org-display-inline-image--width link))
+	     (align (org-image--align link))
+             (image (org--create-inline-image file width)))
+	(if (not image)
+            ;; Image not available, clean up overlay
+            (delete-overlay ov)
+          ;; Add image to overlay:
+
+	  ;; See bug#59902.  We cannot rely
+          ;; on Emacs to update image if the file
+          ;; has changed.
+          (image-flush image)
+	  (overlay-put ov 'display image)
+	  (overlay-put ov 'face 'default)
+	  (overlay-put ov 'org-image-overlay t)
+	  (when (boundp 'image-map)
+	    (overlay-put ov 'keymap image-map))
+          (when align
+            (overlay-put
+             ov 'before-string
+             (propertize
+              " " 'face 'default
+              'display
+              (pcase align
+                ("center" `(space :align-to (- center (0.5 . ,image))))
+                ("right"  `(space :align-to (- right ,image)))))))))
+    ;; file or image not available, clean up overlay
+    (delete-overlay ov)))
 
 ;;;; "help" link type
 (defun org-link--open-help (path _)
diff --git a/lisp/org-attach.el b/lisp/org-attach.el
index 7a03d170e..7d90dae0b 100644
--- a/lisp/org-attach.el
+++ b/lisp/org-attach.el
@@ -797,9 +797,11 @@ (defun org-attach-follow (file arg)
 See `org-open-file' for details about ARG."
   (org-link-open-as-file (org-attach-expand file) arg))
 
+(declare-function org-link-preview-file "org-link-preview")
 (org-link-set-parameters "attachment"
 			 :follow #'org-attach-follow
-                         :complete #'org-attach-complete-link)
+                         :complete #'org-attach-complete-link
+                         :preview #'org-link-preview-file)
 
 (defun org-attach-complete-link ()
   "Advise the user with the available files in the attachment directory."
diff --git a/lisp/org-compat.el b/lisp/org-compat.el
index d843216f3..242b46a86 100644
--- a/lisp/org-compat.el
+++ b/lisp/org-compat.el
@@ -783,6 +783,195 @@ (defun org-add-link-type (type &optional follow export)
 
 (make-obsolete 'org-add-link-type "use `org-link-set-parameters' instead." "9.0")
 
+(declare-function org-link-preview--remove-overlay "ol")
+(declare-function org-link-preview--get-overlays "ol")
+(declare-function org-link-preview-clear "ol")
+(declare-function org-link-preview--remove-overlay "ol")
+
+(define-obsolete-function-alias 'org-display-inline-remove-overlay
+  'org-link-preview--remove-overlay "9.8")
+(define-obsolete-function-alias 'org--inline-image-overlays
+  'org-link-preview--get-overlays "9.8")
+(define-obsolete-function-alias 'org-remove-inline-images
+  'org-link-preview-clear "9.8")
+(define-obsolete-variable-alias 'org-inline-image-overlays
+  'org-link-preview-overlays "9.8")
+(defvar org-link-preview-overlays)
+(defvar org-link-abbrev-alist-local)
+(defvar org-link-abbrev-alist)
+(defvar org-link-angle-re)
+(defvar org-link-plain-re)
+(declare-function org-attach-expand "org-attach")
+(declare-function org-display-inline-image--width "org")
+(declare-function org-image--align "org")
+(declare-function org--create-inline-image "org")
+
+(make-obsolete 'org-display-inline-images
+               'org-link-preview-region "9.8")
+;; FIXME: Unused; obsoleted; to be removed
+(defun org-display-inline-images (&optional include-linked refresh beg end)
+  "Display inline images.
+
+An inline image is a link which follows either of these
+conventions:
+
+  1. Its path is a file with an extension matching return value
+     from `image-file-name-regexp' and it has no contents.
+
+  2. Its description consists in a single link of the previous
+     type.  In this case, that link must be a well-formed plain
+     or angle link, i.e., it must have an explicit \"file\" or
+     \"attachment\" type.
+
+Equip each image with the key-map `image-map'.
+
+When optional argument INCLUDE-LINKED is non-nil, also links with
+a text description part will be inlined.  This can be nice for
+a quick look at those images, but it does not reflect what
+exported files will look like.
+
+When optional argument REFRESH is non-nil, refresh existing
+images between BEG and END.  This will create new image displays
+only if necessary.
+
+BEG and END define the considered part.  They default to the
+buffer boundaries with possible narrowing."
+  (interactive "P")
+  (when (display-graphic-p)
+    (when refresh
+      (org-link-preview-clear beg end)
+      (when (fboundp 'clear-image-cache) (clear-image-cache)))
+    (let ((end (or end (point-max))))
+      (org-with-point-at (or beg (point-min))
+	(let* ((case-fold-search t)
+	       (file-extension-re (image-file-name-regexp))
+	       (link-abbrevs (mapcar #'car
+				     (append org-link-abbrev-alist-local
+					     org-link-abbrev-alist)))
+	       ;; Check absolute, relative file names and explicit
+	       ;; "file:" links.  Also check link abbreviations since
+	       ;; some might expand to "file" links.
+	       (file-types-re
+		(format "\\[\\[\\(?:file%s:\\|attachment:\\|[./~]\\)\\|\\]\\[\\(<?\\(?:file\\|attachment\\):\\)"
+			(if (not link-abbrevs) ""
+			  (concat "\\|" (regexp-opt link-abbrevs))))))
+	  (while (re-search-forward file-types-re end t)
+	    (let* ((link (org-element-lineage
+			  (save-match-data (org-element-context))
+			  'link t))
+                   (linktype (org-element-property :type link))
+		   (inner-start (match-beginning 1))
+		   (path
+		    (cond
+		     ;; No link at point; no inline image.
+		     ((not link) nil)
+		     ;; File link without a description.  Also handle
+		     ;; INCLUDE-LINKED here since it should have
+		     ;; precedence over the next case.  I.e., if link
+		     ;; contains filenames in both the path and the
+		     ;; description, prioritize the path only when
+		     ;; INCLUDE-LINKED is non-nil.
+		     ((or (not (org-element-contents-begin link))
+			  include-linked)
+		      (and (or (equal "file" linktype)
+                               (equal "attachment" linktype))
+			   (org-element-property :path link)))
+		     ;; Link with a description.  Check if description
+		     ;; is a filename.  Even if Org doesn't have syntax
+		     ;; for those -- clickable image -- constructs, fake
+		     ;; them, as in `org-export-insert-image-links'.
+		     ((not inner-start) nil)
+		     (t
+		      (org-with-point-at inner-start
+			(and (looking-at
+			      (if (char-equal ?< (char-after inner-start))
+				  org-link-angle-re
+				org-link-plain-re))
+			     ;; File name must fill the whole
+			     ;; description.
+			     (= (org-element-contents-end link)
+				(match-end 0))
+			     (progn
+                               (setq linktype (match-string 1))
+                               (match-string 2))))))))
+	      (when (and path (string-match-p file-extension-re path))
+		(let ((file (if (equal "attachment" linktype)
+				(progn
+                                  (require 'org-attach)
+				  (ignore-errors (org-attach-expand path)))
+                              (expand-file-name path))))
+                  ;; Expand environment variables.
+                  (when file (setq file (substitute-in-file-name file)))
+		  (when (and file (file-exists-p file))
+		    (let ((width (org-display-inline-image--width link))
+			  (align (org-image--align link))
+                          (old (get-char-property-and-overlay
+				(org-element-begin link)
+				'org-image-overlay)))
+		      (if (and (car-safe old) refresh)
+                          (image-flush (overlay-get (cdr old) 'display))
+			(let ((image (org--create-inline-image file width)))
+			  (when image
+			    (let ((ov (make-overlay
+				       (org-element-begin link)
+				       (progn
+					 (goto-char
+					  (org-element-end link))
+					 (unless (eolp) (skip-chars-backward " \t"))
+					 (point)))))
+                              ;; See bug#59902.  We cannot rely
+                              ;; on Emacs to update image if the file
+                              ;; has changed.
+                              (image-flush image)
+			      (overlay-put ov 'display image)
+			      (overlay-put ov 'face 'default)
+			      (overlay-put ov 'org-image-overlay t)
+			      (overlay-put
+			       ov 'modification-hooks
+			       (list 'org-link-preview--remove-overlay))
+			      (when (boundp 'image-map)
+				(overlay-put ov 'keymap image-map))
+                              (when align
+                                (overlay-put
+                                 ov 'before-string
+                                 (propertize
+                                  " " 'face 'default
+                                  'display
+                                  (pcase align
+                                    ("center" `(space :align-to (- center (0.5 . ,image))))
+                                    ("right"  `(space :align-to (- right ,image)))))))
+			      (push ov org-inline-image-overlays))))))))))))))))
+
+(make-obsolete 'org-toggle-inline-images
+               'org-link-preview "9.8")
+;; FIXME: Unused; obsoleted; to be removed
+(defun org-toggle-inline-images (&optional include-linked beg end)
+  "Toggle the display of inline images.
+INCLUDE-LINKED is passed to `org-display-inline-images'."
+  (interactive "P")
+  (if (org-link-preview--get-overlays beg end)
+      (progn
+        (org-link-preview-clear beg end)
+        (when (called-interactively-p 'interactive)
+	  (message "Inline image display turned off")))
+    (org-display-inline-images include-linked nil beg end)
+    (when (called-interactively-p 'interactive)
+      (let ((new (org-link-preview--get-overlays beg end)))
+        (message (if new
+		     (format "%d images displayed inline"
+			     (length new))
+		   "No images to display inline"))))))
+
+(make-obsolete 'org-redisplay-inline-images
+               'org-link-preview "9.8")
+;; FIXME: Unused; obsoleted; to be removed
+(defun org-redisplay-inline-images ()
+  "Assure display of inline images and refresh them."
+  (interactive)
+  (org-toggle-inline-images)
+  (unless org-link-preview-overlays
+    (org-toggle-inline-images)))
+
 ;;;; Functions unused in Org core.
 (defun org-table-recognize-table.el ()
   "If there is a table.el table nearby, recognize it and move into it."
diff --git a/lisp/org-cycle.el b/lisp/org-cycle.el
index 8a39bdb8c..1a1c916bd 100644
--- a/lisp/org-cycle.el
+++ b/lisp/org-cycle.el
@@ -40,14 +40,14 @@ (declare-function org-element-property "org-element-ast" (property node))
 (declare-function org-element-post-affiliated "org-element" (node))
 (declare-function org-element-lineage "org-element-ast" (datum &optional types with-self))
 (declare-function org-element-at-point "org-element" (&optional pom cached-only))
-(declare-function org-display-inline-images "org" (&optional include-linked refresh beg end))
+(declare-function org-link-preview-region "ol" (&optional include-linked refresh beg end))
 (declare-function org-get-tags "org" (&optional pos local fontify))
 (declare-function org-subtree-end-visible-p "org" ())
 (declare-function org-narrow-to-subtree "org" (&optional element))
 (declare-function org-next-visible-heading "org" (arg))
 (declare-function org-at-property-p "org" ())
 (declare-function org-re-property "org" (property &optional literal allow-null value))
-(declare-function org-remove-inline-images "org" (&optional beg end))
+(declare-function org-link-preview-clear "ol" (&optional beg end))
 (declare-function org-item-beginning-re "org" ())
 (declare-function org-at-heading-p "org" (&optional invisible-not-ok))
 (declare-function org-at-item-p "org" ())
@@ -817,19 +817,19 @@ (defun org-cycle-display-inline-images (state)
         ;; If has nested headlines, beg,end only from parent headline
         ;; to first child headline which reference to upper
         ;; let-binding `org-next-visible-heading'.
-        (org-display-inline-images
+        (org-link-preview-region
          nil nil
          (point-min) (progn (org-next-visible-heading 1) (point)))))
       ('subtree
        (org-with-wide-buffer
         (org-narrow-to-subtree)
         ;; If has nested headlines, also inline display images under all sub-headlines.
-        (org-display-inline-images nil nil (point-min) (point-max))))
+        (org-link-preview-region nil nil (point-min) (point-max))))
       ('folded
        (org-with-wide-buffer
         (org-narrow-to-subtree)
         (if (numberp (point-max))
-            (org-remove-inline-images (point-min) (point-max))
+            (org-link-preview-clear (point-min) (point-max))
           (ignore)))))))
 
 (provide 'org-cycle)
diff --git a/lisp/org-keys.el b/lisp/org-keys.el
index 1daedaae8..77cbe5c0f 100644
--- a/lisp/org-keys.el
+++ b/lisp/org-keys.el
@@ -218,7 +218,7 @@ (declare-function org-toggle-checkbox "org" (&optional toggle-presence))
 (declare-function org-toggle-radio-button "org" (&optional arg))
 (declare-function org-toggle-comment "org" ())
 (declare-function org-toggle-fixed-width "org" ())
-(declare-function org-toggle-inline-images-command "org" (&optional arg beg end))
+(declare-function org-link-preview "ol" (&optional arg beg end))
 (declare-function org-latex-preview "org" (&optional arg))
 (declare-function org-toggle-narrow-to-subtree "org" ())
 (declare-function org-toggle-ordered-property "org" ())
@@ -618,7 +618,7 @@ (org-defkey org-mode-map (kbd "C-c C-x C-d") #'org-clock-display)
 (org-defkey org-mode-map (kbd "C-c C-x x") #'org-dynamic-block-insert-dblock)
 (org-defkey org-mode-map (kbd "C-c C-x C-u") #'org-dblock-update)
 (org-defkey org-mode-map (kbd "C-c C-x C-l") #'org-latex-preview)
-(org-defkey org-mode-map (kbd "C-c C-x C-v") #'org-toggle-inline-images-command)
+(org-defkey org-mode-map (kbd "C-c C-x C-v") #'org-link-preview)
 (org-defkey org-mode-map (kbd "C-c C-x C-M-v") #'org-redisplay-inline-images)
 (org-defkey org-mode-map (kbd "C-c C-x \\") #'org-toggle-pretty-entities)
 (org-defkey org-mode-map (kbd "C-c C-x C-b") #'org-toggle-checkbox)
diff --git a/lisp/org-plot.el b/lisp/org-plot.el
index b045344f0..836cfaffc 100644
--- a/lisp/org-plot.el
+++ b/lisp/org-plot.el
@@ -633,7 +633,7 @@ (defun org-plot/gnuplot-script (table data-file num-cols params &optional prefac
 
 (defun org-plot/redisplay-img-in-buffer (img-file)
   "Find any overlays for IMG-FILE in the current Org buffer, and refresh them."
-  (dolist (img-overlay org-inline-image-overlays)
+  (dolist (img-overlay org-link-preview-overlays)
     (when (string= img-file (plist-get (cdr (overlay-get img-overlay 'display)) :file))
       (when (and (file-exists-p img-file)
                  (fboundp 'image-flush))
diff --git a/lisp/org.el b/lisp/org.el
index d5c1dcb35..091a09344 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -5079,7 +5079,7 @@ (define-derived-mode org-mode outline-mode "Org"
     ;; modifications to make cache updates work reliably.
     (org-unmodified
      (when org-startup-with-beamer-mode (org-beamer-mode))
-     (when org-startup-with-inline-images (org-display-inline-images))
+     (when org-startup-with-inline-images (org-link-preview '(16)))
      (when org-startup-with-latex-preview (org-latex-preview '(16)))
      (unless org-inhibit-startup-visibility-stuff (org-cycle-set-startup-visibility))
      (when org-startup-truncated (setq truncate-lines t))
@@ -16651,126 +16651,6 @@ (defun org-normalize-color (value)
 \f
 ;; Image display
 
-(defvar-local org-inline-image-overlays nil)
-;; Preserve when switching modes or when restarting Org.
-;; If we clear the overlay list and later enable Or mode, the existing
-;; image overlays will never be cleared by `org-toggle-inline-images'
-;; and `org-toggle-inline-images-command'.
-(put 'org-inline-image-overlays 'permanent-local t)
-
-(defun org--inline-image-overlays (&optional beg end)
-  "Return image overlays between BEG and END."
-  (let* ((beg (or beg (point-min)))
-         (end (or end (point-max)))
-         (overlays (overlays-in beg end))
-         result)
-    (dolist (ov overlays result)
-      (when (memq ov org-inline-image-overlays)
-        (push ov result)))))
-
-(defun org-toggle-inline-images-command (&optional arg beg end)
-  "Toggle display of inline images without description at point.
-
-When point is at an image link, toggle displaying that image.
-Otherwise, toggle displaying images in current entry.
-
-When region BEG..END is active, toggle displaying images in the
-region.
-
-With numeric prefix ARG 1, display images with description as well.
-
-With prefix ARG `\\[universal-argument]', toggle displaying images in
-the accessible portion of the buffer.  With numeric prefix ARG 11, do
-the same, but include images with description.
-
-With prefix ARG `\\[universal-argument] \\[universal-argument]', hide
-all the images in accessible portion of the buffer.
-
-This command is designed for interactive use.  From Elisp, you can
-also use `org-toggle-inline-images'."
-  (interactive (cons current-prefix-arg
-                     (when (use-region-p)
-                       (list (region-beginning) (region-end)))))
-  (let* ((include-linked
-          (cond
-           ((member arg '(nil (4) (16)) ) nil)
-           ((member arg '(1 11)) 'include-linked)
-           (t 'include-linked)))
-         (interactive? (called-interactively-p 'any))
-         (toggle-images
-          (lambda (&optional beg end scope force-remove)
-            (let* ((beg (or beg (point-min)))
-                   (end (or end (point-max)))
-                   (old (org--inline-image-overlays beg end))
-                   (scope (or scope (format "%d:%d" beg end))))
-              (if (or old force-remove)
-                  (progn
-                    (org-remove-inline-images beg end)
-                    (when interactive?
-                      (message
-                       "[%s] Inline image display turned off (removed %d images)"
-                       scope (length old))))
-	        (org-display-inline-images include-linked t beg end)
-                (when interactive?
-                  (let ((new (org--inline-image-overlays beg end)))
-                    (message
-                     (if new
-		         (format "[%s] %d images displayed inline %s"
-			         scope (length new)
-                                 (if include-linked "(including images with description)"
-                                   ""))
-		       (format "[%s] No images to display inline" scope))))))))))
-    (cond
-     ((not (display-graphic-p))
-      (message "Your Emacs does not support displaying images!"))
-     ;; Region selected :: toggle images in region.
-     ((and beg end) (funcall toggle-images beg end "region"))
-     ;; C-u or C-11 argument :: toggle images in the whole buffer.
-     ((member arg '(11 (4))) (funcall toggle-images nil nil "buffer"))
-     ;; C-u C-u argument :: unconditionally hide images in the buffer.
-     ((equal arg '(16)) (funcall toggle-images nil nil "buffer" 'remove))
-     ;; Argument nil or 1, no region selected :: toggle (display or hide
-     ;; dwim) images in current section or image link at point.
-     ((and (member arg '(nil 1)) (null beg) (null end))
-      (let ((context (org-element-context)))
-        ;; toggle display of inline image link at point.
-        (if (org-element-type-p context 'link)
-            (funcall toggle-images
-                     (org-element-begin context)
-                     (org-element-end context)
-                     "image at point")
-          (let ((beg (if (org-before-first-heading-p) (point-min)
-	               (save-excursion
-	                 (org-with-limited-levels (org-back-to-heading t) (point)))))
-                (end (org-with-limited-levels (org-entry-end-position))))
-            (funcall toggle-images beg end "current section")))))
-     ;; Any other non-nil argument.
-     ((not (null arg)) (funcall toggle-images beg end "region")))))
-
-(defun org-toggle-inline-images (&optional include-linked beg end)
-  "Toggle the display of inline images.
-INCLUDE-LINKED is passed to `org-display-inline-images'."
-  (interactive "P")
-  (if (org--inline-image-overlays beg end)
-      (progn
-        (org-remove-inline-images beg end)
-        (when (called-interactively-p 'interactive)
-	  (message "Inline image display turned off")))
-    (org-display-inline-images include-linked nil beg end)
-    (when (called-interactively-p 'interactive)
-      (let ((new (org--inline-image-overlays beg end)))
-        (message (if new
-		     (format "%d images displayed inline"
-			     (length new))
-		   "No images to display inline"))))))
-
-(defun org-redisplay-inline-images ()
-  "Assure display of inline images and refresh them."
-  (interactive)
-  (org-toggle-inline-images)
-  (unless org-inline-image-overlays
-    (org-toggle-inline-images)))
-
 ;; For without-x builds.
 (declare-function image-flush "image" (spec &optional frame))
 
@@ -16793,7 +16673,7 @@ (defcustom org-display-remote-inline-images 'skip
   :safe #'symbolp)
 
 (defcustom org-image-align 'left
-  "How to align images previewed using `org-display-inline-images'.
+  "How to align images previewed using `org-link-preview-region'.
 
 Only stand-alone image links are affected by this setting.  These
 are links without surrounding text.
@@ -16850,139 +16730,6 @@ (defun org--create-inline-image (file width)
                                 org-image-max-width)))
                     :scale 1))))
 
-(defun org-display-inline-images (&optional include-linked refresh beg end)
-  "Display inline images.
-
-An inline image is a link which follows either of these
-conventions:
-
-  1. Its path is a file with an extension matching return value
-     from `image-file-name-regexp' and it has no contents.
-
-  2. Its description consists in a single link of the previous
-     type.  In this case, that link must be a well-formed plain
-     or angle link, i.e., it must have an explicit \"file\" or
-     \"attachment\" type.
-
-Equip each image with the key-map `image-map'.
-
-When optional argument INCLUDE-LINKED is non-nil, also links with
-a text description part will be inlined.  This can be nice for
-a quick look at those images, but it does not reflect what
-exported files will look like.
-
-When optional argument REFRESH is non-nil, refresh existing
-images between BEG and END.  This will create new image displays
-only if necessary.
-
-BEG and END define the considered part.  They default to the
-buffer boundaries with possible narrowing."
-  (interactive "P")
-  (when (display-graphic-p)
-    (when refresh
-      (org-remove-inline-images beg end)
-      (when (fboundp 'clear-image-cache) (clear-image-cache)))
-    (let ((end (or end (point-max))))
-      (org-with-point-at (or beg (point-min))
-	(let* ((case-fold-search t)
-	       (file-extension-re (image-file-name-regexp))
-	       (link-abbrevs (mapcar #'car
-				     (append org-link-abbrev-alist-local
-					     org-link-abbrev-alist)))
-	       ;; Check absolute, relative file names and explicit
-	       ;; "file:" links.  Also check link abbreviations since
-	       ;; some might expand to "file" links.
-	       (file-types-re
-		(format "\\[\\[\\(?:file%s:\\|attachment:\\|[./~]\\)\\|\\]\\[\\(<?\\(?:file\\|attachment\\):\\)"
-			(if (not link-abbrevs) ""
-			  (concat "\\|" (regexp-opt link-abbrevs))))))
-	  (while (re-search-forward file-types-re end t)
-	    (let* ((link (org-element-lineage
-			  (save-match-data (org-element-context))
-			  'link t))
-                   (linktype (org-element-property :type link))
-		   (inner-start (match-beginning 1))
-		   (path
-		    (cond
-		     ;; No link at point; no inline image.
-		     ((not link) nil)
-		     ;; File link without a description.  Also handle
-		     ;; INCLUDE-LINKED here since it should have
-		     ;; precedence over the next case.  I.e., if link
-		     ;; contains filenames in both the path and the
-		     ;; description, prioritize the path only when
-		     ;; INCLUDE-LINKED is non-nil.
-		     ((or (not (org-element-contents-begin link))
-			  include-linked)
-		      (and (or (equal "file" linktype)
-                               (equal "attachment" linktype))
-			   (org-element-property :path link)))
-		     ;; Link with a description.  Check if description
-		     ;; is a filename.  Even if Org doesn't have syntax
-		     ;; for those -- clickable image -- constructs, fake
-		     ;; them, as in `org-export-insert-image-links'.
-		     ((not inner-start) nil)
-		     (t
-		      (org-with-point-at inner-start
-			(and (looking-at
-			      (if (char-equal ?< (char-after inner-start))
-				  org-link-angle-re
-				org-link-plain-re))
-			     ;; File name must fill the whole
-			     ;; description.
-			     (= (org-element-contents-end link)
-				(match-end 0))
-			     (progn
-                               (setq linktype (match-string 1))
-                               (match-string 2))))))))
-	      (when (and path (string-match-p file-extension-re path))
-		(let ((file (if (equal "attachment" linktype)
-				(progn
-                                  (require 'org-attach)
-				  (ignore-errors (org-attach-expand path)))
-                              (expand-file-name path))))
-                  ;; Expand environment variables.
-                  (when file (setq file (substitute-in-file-name file)))
-		  (when (and file (file-exists-p file))
-		    (let ((width (org-display-inline-image--width link))
-			  (align (org-image--align link))
-                          (old (get-char-property-and-overlay
-				(org-element-begin link)
-				'org-image-overlay)))
-		      (if (and (car-safe old) refresh)
-                          (image-flush (overlay-get (cdr old) 'display))
-			(let ((image (org--create-inline-image file width)))
-			  (when image
-			    (let ((ov (make-overlay
-				       (org-element-begin link)
-				       (progn
-					 (goto-char
-					  (org-element-end link))
-					 (unless (eolp) (skip-chars-backward " \t"))
-					 (point)))))
-                              ;; See bug#59902.  We cannot rely
-                              ;; on Emacs to update image if the file
-                              ;; has changed.
-                              (image-flush image)
-			      (overlay-put ov 'display image)
-			      (overlay-put ov 'face 'default)
-			      (overlay-put ov 'org-image-overlay t)
-			      (overlay-put
-			       ov 'modification-hooks
-			       (list 'org-display-inline-remove-overlay))
-			      (when (boundp 'image-map)
-				(overlay-put ov 'keymap image-map))
-                              (when align
-                                (overlay-put
-                                 ov 'before-string
-                                 (propertize
-                                  " " 'face 'default
-                                  'display
-                                  (pcase align
-                                    ("center" `(space :align-to (- center (0.5 . ,image))))
-                                    ("right"  `(space :align-to (- right ,image)))))))
-			      (push ov org-inline-image-overlays))))))))))))))))
-
 (declare-function org-export-read-attribute "ox"
                   (attribute element &optional property))
 (defvar visual-fill-column-width) ; Silence compiler warning
@@ -17135,32 +16882,6 @@ (defun org-image--align (link)
             (when (memq org-image-align '(center right))
               (symbol-name org-image-align))))))))
 
-
-(defun org-display-inline-remove-overlay (ov after _beg _end &optional _len)
-  "Remove inline-display overlay if a corresponding region is modified."
-  (when (and ov after)
-    (setq org-inline-image-overlays (delete ov org-inline-image-overlays))
-    ;; Clear image from cache to avoid image not updating upon
-    ;; changing on disk.  See Emacs bug#59902.
-    (when (overlay-get ov 'org-image-overlay)
-      (image-flush (overlay-get ov 'display)))
-    (delete-overlay ov)))
-
-(defun org-remove-inline-images (&optional beg end)
-  "Remove inline display of images."
-  (interactive)
-  (let* ((beg (or beg (point-min)))
-         (end (or end (point-max)))
-         (overlays (overlays-in beg end)))
-    (dolist (ov overlays)
-      (when (memq ov org-inline-image-overlays)
-        (setq org-inline-image-overlays (delq ov org-inline-image-overlays))
-        (delete-overlay ov)))
-    ;; Clear removed overlays.
-    (dolist (ov org-inline-image-overlays)
-      (unless (overlay-buffer ov)
-        (setq org-inline-image-overlays (delq ov org-inline-image-overlays))))))
-
 (defvar org-self-insert-command-undo-counter 0)
 (defvar org-speed-command nil)
 
diff --git a/testing/lisp/test-org-fold.el b/testing/lisp/test-org-fold.el
index f58642be6..809738f6c 100644
--- a/testing/lisp/test-org-fold.el
+++ b/testing/lisp/test-org-fold.el
@@ -716,14 +716,14 @@ (ert-deftest test-org-fold/org-fold-display-inline-images ()
       (org-show-subtree)
       (org-fold-subtree t)
       (run-hook-with-args 'org-cycle-hook 'folded)
-      (should-not org-inline-image-overlays)
+      (should-not org-link-preview-overlays)
       (should-not
        (cl-every
         (lambda (ov) (overlay-get ov 'org-image-overlay))
         (overlays-in (point-min) (point-max))))
       (org-show-subtree)
       (run-hook-with-args 'org-cycle-hook 'subtree)
-      (should org-inline-image-overlays)
+      (should org-link-preview-overlays)
       (should
        (cl-every
         (lambda (ov) (overlay-get ov 'org-image-overlay))
-- 
2.44.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [PATCH v1] Inline image display as part of a new org-link-preview system
  2024-08-23 23:36                                             ` [PATCH v1] Inline image display as part of a new org-link-preview system Karthik Chikmagalur
@ 2024-08-24  1:00                                               ` Karthik Chikmagalur
  2024-08-31 14:22                                               ` Ihor Radchenko
  1 sibling, 0 replies; 40+ messages in thread
From: Karthik Chikmagalur @ 2024-08-24  1:00 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: stardiviner, Org mode

> I'll send a short example of using org-link-preview to asynchronously
> preview youtube links as thumbnails soon.

Here is a prototype of asynchronous org-link-preview of Youtube links in
Org mode: https://share.karthinks.com/ol-preview-web.el

Essentially I defined an async fetcher `ol-preview-web-link', and
registered it as a previewer for https links:

(org-link-set-parameters "https" :preview #'ol-preview-web-link)

Here's a demo of this in action, previewing image files and links
together with M-x org-link-preview:
https://share.karthinks.com/org-link-preview-demo.mp4

Karthik


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v1] Inline image display as part of a new org-link-preview system
  2024-08-23 23:36                                             ` [PATCH v1] Inline image display as part of a new org-link-preview system Karthik Chikmagalur
  2024-08-24  1:00                                               ` Karthik Chikmagalur
@ 2024-08-31 14:22                                               ` Ihor Radchenko
  2024-08-31 16:41                                                 ` Karthik Chikmagalur
  1 sibling, 1 reply; 40+ messages in thread
From: Ihor Radchenko @ 2024-08-31 14:22 UTC (permalink / raw)
  To: Karthik Chikmagalur; +Cc: stardiviner, Org mode

Karthik Chikmagalur <karthikchikmagalur@gmail.com> writes:

>> Spin out will be easier when for my rebase :)
>
> Please find attached the draft of a patch implementing a general
> link-preview system.

Thanks!

> Not yet handled or final:
>
> - Link abbreviations: I'm using org-link-any-re to find links, and this
>   appears to be handling link abbreviations fine.  So there is no
>   special code to handle link abbreviations.  But I'm not sure.

> - The calling convention for the :preview function is not final.  Right
>   now it is given the overlay, the link type and the link path.  But
>   other link details can be required -- for example, image links need to
>   read the org keywords for the image width and alignment, so I end up
>   calling (org-element-context) again inside the :preview function.

We may simply pass the link object to :preview function.

> Subject: [PATCH 2/2] org-link: Move inline image display to org-link

Is there [PATCH 1/2]?

> * lisp/org-keys.el: Bind `C-c C-x C-v' to new command
> `org-link-preview', which has the same prefix arg behaviors as
> `org-latex-preview'.

Didn't we discuss changes to the behavior?

> +`:preview'
> +
> +  Function to run when generating an in-buffer preview for the
> +  link.  It must accept three arguments:
> +  - an overlay placed from the start to the end of the link.
> +  - the link type, as a string.
> +  - the path, as a string.

Maybe we can ask the function to return non-nil when the preview is
going to happen. The current approach with "overlay deleted then no
preview" is not ideal.

> +(defun org-link-preview--get-overlays (&optional beg end)
> +  "Return link preview overlays between BEG and END."
> +  (let* ((beg (or beg (point-min)))
> +         (end (or end (point-max)))
> +         (overlays (overlays-in beg end))
> +         result)
> +    (dolist (ov overlays result)
> +      (when (memq ov org-link-preview-overlays)
> +        (push ov result)))))

I know that this is a copy-paste, but we may utilize 'org-image-overlay
+ `org-find-overlays' here.

> +(defun org-link-preview--remove-overlay (ov after _beg _end &optional _len)
> +  "Remove link-preview overlay OV if a corresponding region is modified.
> +
> +AFTER is true when this function is called post-change."
> +  (when (and ov after)
> +    (setq org-link-preview-overlays (delete ov org-link-preview-overlays))
> +    ;; Clear image from cache to avoid image not updating upon
> +    ;; changing on disk.  See Emacs bug#59902.
> +    (when (overlay-get ov 'org-image-overlay)
> +      (image-flush (overlay-get ov 'display)))
> +    (delete-overlay ov)))

It implies that every :preview function _must_ put an image as 'display
property. If it does not, we will run into errors. But should it?

Also, when if preview is asynchronous, and we run this function when the
image is not yet assigned to the overlay?

> +    (cond
> +     ((not (display-graphic-p))
> +      (message "Your Emacs does not support displaying images!"))

May some third-party previews not require graphic?

> +(defun org-link-preview-clear (&optional beg end)
> +  "Clear link previews in region BEG to END."
> +  (interactive (and (use-region-p) (list (region-beginning) (region-end))))
> +  (let* ((beg (or beg (point-min)))
> +         (end (or end (point-max)))
> +         (overlays (overlays-in beg end)))
> +    (dolist (ov overlays)
> +      (when (memq ov org-link-preview-overlays)
> +        (when-let ((image (overlay-get ov 'display))
> +                   ((imagep image)))
> +          (image-flush image))
> +        (setq org-link-preview-overlays (delq ov org-link-preview-overlays))
> +        (delete-overlay ov)))

In asynchronous previews, some overlays may be deleted already. We
should be careful with this.

> +(defun org-link-preview-file (ov linktype path)
> +  "Display image file PATH in overlay OV.
> +
> +LINKTYPE is the Org link type used to preview PATH, either
> +\"file\" or \"attachment\".
> +
> +Equip each image with the keymap `image-map'.
> +
> +This is intended to be used as the `:preview' link property of
> +file links, see `org-link-parameters'."
> +  (if-let ((file-full
> +            (if (equal "attachment" linktype)
> +		(progn
> +                  (require 'org-attach)
> +		  (ignore-errors (org-attach-expand path)))
> +              (expand-file-name path)))

I'd rather put this part into org-attach, as a separate function that
calls `org-link-preview-file'.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v1] Inline image display as part of a new org-link-preview system
  2024-08-31 14:22                                               ` Ihor Radchenko
@ 2024-08-31 16:41                                                 ` Karthik Chikmagalur
  2024-08-31 16:53                                                   ` Ihor Radchenko
  0 siblings, 1 reply; 40+ messages in thread
From: Karthik Chikmagalur @ 2024-08-31 16:41 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: stardiviner, Org mode

Thanks Ihor.  Before I send the next iteration of the patch, I'd like
your input on some decisions marked with "Q:" below.

>> Not yet handled or final:
>>
>> - Link abbreviations: I'm using org-link-any-re to find links, and this
>>   appears to be handling link abbreviations fine.  So there is no
>>   special code to handle link abbreviations.  But I'm not sure.
>
>> - The calling convention for the :preview function is not final.  Right
>>   now it is given the overlay, the link type and the link path.  But
>>   other link details can be required -- for example, image links need to
>>   read the org keywords for the image width and alignment, so I end up
>>   calling (org-element-context) again inside the :preview function.
>
> We may simply pass the link object to :preview function.

If we pass the link object instead of the overlay, it will be the
preview function's job to create overlays as needed.  This overlay
should have special properties (like `org-image-overlay') for previewing
to work correctly.  

Q: Is this okay? Or did you mean we can pass both the link and the
overlay, like this:

(funcall preview-func ov link)

and let the previewer figure out the link type and path details?

>> Subject: [PATCH 2/2] org-link: Move inline image display to org-link
>
> Is there [PATCH 1/2]?

There is no [PATCH 1/2], sorry about the naming.  What I sent is the
complete patch.

>> * lisp/org-keys.el: Bind `C-c C-x C-v' to new command
>> `org-link-preview', which has the same prefix arg behaviors as
>> `org-latex-preview'.
>
> Didn't we discuss changes to the behavior?

Yes, those changes have been implemented, please see the docstring for
org-link-preview.  The behavior is identical to that of
org-latex-preview, but in addition the 1 and the 11 numeric prefix args
are handled specially.

>> +`:preview'
>> +
>> +  Function to run when generating an in-buffer preview for the
>> +  link.  It must accept three arguments:
>> +  - an overlay placed from the start to the end of the link.
>> +  - the link type, as a string.
>> +  - the path, as a string.
>
> Maybe we can ask the function to return non-nil when the preview is
> going to happen. The current approach with "overlay deleted then no
> preview" is not ideal.

Good idea.

>> +(defun org-link-preview--get-overlays (&optional beg end)
>> +  "Return link preview overlays between BEG and END."
>> +  (let* ((beg (or beg (point-min)))
>> +         (end (or end (point-max)))
>> +         (overlays (overlays-in beg end))
>> +         result)
>> +    (dolist (ov overlays result)
>> +      (when (memq ov org-link-preview-overlays)
>> +        (push ov result)))))
>
> I know that this is a copy-paste, but we may utilize 'org-image-overlay
> + `org-find-overlays' here.

Noted.

>> +(defun org-link-preview--remove-overlay (ov after _beg _end &optional _len)
>> +  "Remove link-preview overlay OV if a corresponding region is modified.
>> +
>> +AFTER is true when this function is called post-change."
>> +  (when (and ov after)
>> +    (setq org-link-preview-overlays (delete ov org-link-preview-overlays))
>> +    ;; Clear image from cache to avoid image not updating upon
>> +    ;; changing on disk.  See Emacs bug#59902.
>> +    (when (overlay-get ov 'org-image-overlay)
>> +      (image-flush (overlay-get ov 'display)))
>> +    (delete-overlay ov)))
>
> It implies that every :preview function _must_ put an image as 'display
> property. If it does not, we will run into errors. But should it?

This was an oversight, I meant to add

(when-let ((disp (overlay-get ov 'display))
           ((imagep disp)))
  (image-flush disp))

Will fix.

> Also, when if preview is asynchronous, and we run this function when the
> image is not yet assigned to the overlay?

Handled by the above, plus the fact that we delete the overlay.  It's up
to the async callback to handle the case where the overlay no longer exists.

>> +    (cond
>> +     ((not (display-graphic-p))
>> +      (message "Your Emacs does not support displaying images!"))
>
> May some third-party previews not require graphic?

Good point, will handle.

>> +(defun org-link-preview-clear (&optional beg end)
>> +  "Clear link previews in region BEG to END."
>> +  (interactive (and (use-region-p) (list (region-beginning) (region-end))))
>> +  (let* ((beg (or beg (point-min)))
>> +         (end (or end (point-max)))
>> +         (overlays (overlays-in beg end)))
>> +    (dolist (ov overlays)
>> +      (when (memq ov org-link-preview-overlays)
>> +        (when-let ((image (overlay-get ov 'display))
>> +                   ((imagep image)))
>> +          (image-flush image))
>> +        (setq org-link-preview-overlays (delq ov org-link-preview-overlays))
>> +        (delete-overlay ov)))
>
> In asynchronous previews, some overlays may be deleted already. We
> should be careful with this.

Noted.

>> +(defun org-link-preview-file (ov linktype path)
>> +  "Display image file PATH in overlay OV.
>> +
>> +LINKTYPE is the Org link type used to preview PATH, either
>> +\"file\" or \"attachment\".
>> +
>> +Equip each image with the keymap `image-map'.
>> +
>> +This is intended to be used as the `:preview' link property of
>> +file links, see `org-link-parameters'."
>> +  (if-let ((file-full
>> +            (if (equal "attachment" linktype)
>> +		(progn
>> +                  (require 'org-attach)
>> +		  (ignore-errors (org-attach-expand path)))
>> +              (expand-file-name path)))
>
> I'd rather put this part into org-attach, as a separate function that
> calls `org-link-preview-file'.

Q: I don't follow.  Right now `org-link-preview-file' is the :preview
org-link-parameter of file links and attachments.  Could you explain how
this indirection should work instead?

Karthik


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v1] Inline image display as part of a new org-link-preview system
  2024-08-31 16:41                                                 ` Karthik Chikmagalur
@ 2024-08-31 16:53                                                   ` Ihor Radchenko
  2024-08-31 22:37                                                     ` [PATCH v2] " Karthik Chikmagalur
  0 siblings, 1 reply; 40+ messages in thread
From: Ihor Radchenko @ 2024-08-31 16:53 UTC (permalink / raw)
  To: Karthik Chikmagalur; +Cc: stardiviner, Org mode

Karthik Chikmagalur <karthikchikmagalur@gmail.com> writes:

>> We may simply pass the link object to :preview function.
>
> If we pass the link object instead of the overlay, it will be the
> preview function's job to create overlays as needed.  This overlay
> should have special properties (like `org-image-overlay') for previewing
> to work correctly.  
>
> Q: Is this okay? Or did you mean we can pass both the link and the
> overlay, like this:
>
> (funcall preview-func ov link)
>
> and let the previewer figure out the link type and path details?

No, I meant to pass link object in addition to other parameters:

(funcall preview-func ov path link)

We need to pass PATH because we use special rules to derive it. It is
not simply LINK :path property.

>>> * lisp/org-keys.el: Bind `C-c C-x C-v' to new command
>>> `org-link-preview', which has the same prefix arg behaviors as
>>> `org-latex-preview'.
>>
>> Didn't we discuss changes to the behavior?
>
> Yes, those changes have been implemented, please see the docstring for
> org-link-preview.  The behavior is identical to that of
> org-latex-preview, but in addition the 1 and the 11 numeric prefix args
> are handled specially.

Then, the commit message is not accurate.

>>> +  (if-let ((file-full
>>> +            (if (equal "attachment" linktype)
>>> +		(progn
>>> +                  (require 'org-attach)
>>> +		  (ignore-errors (org-attach-expand path)))
>>> +              (expand-file-name path)))
>>
>> I'd rather put this part into org-attach, as a separate function that
>> calls `org-link-preview-file'.
>
> Q: I don't follow.  Right now `org-link-preview-file' is the :preview
> org-link-parameter of file links and attachments.  Could you explain how
> this indirection should work instead?

What I meant is that org-attach will define a custom
`org-attach-preview-file' function that will compute the filename, and
then internally call `org-link-preview-file'. Then, attachment: link
will have :preview set to `org-attach-preview-file'. This way, you will
not need to require org-attach from ol and ol from org-attach
simultaneously. (no cyclic dependencies, please)

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v2] Inline image display as part of a new org-link-preview system
  2024-08-31 16:53                                                   ` Ihor Radchenko
@ 2024-08-31 22:37                                                     ` Karthik Chikmagalur
  2024-09-01 13:06                                                       ` Ihor Radchenko
  0 siblings, 1 reply; 40+ messages in thread
From: Karthik Chikmagalur @ 2024-08-31 22:37 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: stardiviner, Org mode

[-- Attachment #1: Type: text/plain, Size: 3046 bytes --]

v2 of the patch is attached.  I incorporated most of your suggested
changes including in the commit message, except for a couple that I talk
about below.

First, here's an updated description of the proposed API:

1. You can register a previewer with each type of Org link in the
following way:

(org-link-set-parameters "file"  :preview #'org-link-preview-file)
(org-link-set-parameters "https" :preview #'my/org-link-preview-web)

2. This previewer is called by Org with three parameters: an overlay,
the link path being previewed and the link element:

(funcall #'org-link-preview-file ov path link)

   - To preview the link, the previewer must update the overlay ov as
     needed, for example by placing an image as its `display' property.
     It should not modify the buffer contents.
   - The previewer must return a non-nil value to indicate preview
     success.  If the preview fails, it should return nil.

That's it.

>> Q: I don't follow.  Right now `org-link-preview-file' is the :preview
>> org-link-parameter of file links and attachments.  Could you explain how
>> this indirection should work instead?
>
> What I meant is that org-attach will define a custom
> `org-attach-preview-file' function that will compute the filename, and
> then internally call `org-link-preview-file'. Then, attachment: link
> will have :preview set to `org-attach-preview-file'. This way, you will
> not need to require org-attach from ol and ol from org-attach
> simultaneously. (no cyclic dependencies, please)

Done.

> Then, the commit message is not accurate.

Fixed.

> I know that this is a copy-paste, but
> we may utilize 'org-image-overlay
> + `org-find-overlays' here.

I decided not to do this since the logic in
org-link-preview--remove-overlay is different: it checks for the
existence of overlays in the maintained list org-link-preview-overlays
instead of checking for overlays in the buffer.

> It implies that every :preview function _must_ put an image as 'display
> property. If it does not, we will run into errors. But should it?

Fixed.

> Also, when if preview is asynchronous, and we run this function when the
> image is not yet assigned to the overlay?

> In asynchronous previews, some overlays may be deleted already. We
> should be careful with this.

No changes here.  When the async callback runs, the state of the buffer
can have changed.  There's nothing Org can do about that.  The callback
has access to the overlay, so it will have to use a construct like

(and (overlay-buffer ov) (add-preview-to link))

If the preview fails, there will be an undecorated overlay hanging
around, I'm not sure what to do about it.  The async function can run
`(delete-overlay ov)', but that breaks the abstraction boundary we're
trying to create.  (It will also have to remove the overlay from
`org-link-preview-overlays'.)

It can't run `org-link-preview-clear' on the link, since the link
element's bounds might be invalid.  I'm assuming that the :begin and
:end property of the link are integers and not markers.

Karthik


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-org-link-Move-inline-image-display-to-org-link.patch --]
[-- Type: text/x-patch, Size: 45064 bytes --]

From d60d5bef78841d548cfbcdca3a461cb9c52e4314 Mon Sep 17 00:00:00 2001
From: Karthik Chikmagalur <karthikchikmagalur@gmail.com>
Date: Fri, 23 Aug 2024 15:46:53 -0700
Subject: [PATCH] org-link: Move inline image display to org-link

Make inline image previews a part of a more universal org-link
preview feature.  Each link type can now be previewed differently
based on a new link parameter.

* lisp/ol.el (org-link-parameters, org-link-preview-overlays,
org-link-preview--get-overlays, org-link-preview--remove-overlay,
org-link-previeworg-link-preview-region, org-link-preview-clear,
org-link-preview-file): Add new commands `org-link-preview',
`org-link-preview-region' and `org-link-preview-clear' for
creating link previews for any kind of link.  Add new org-link
parameter `:preview' for specifying how a link type should be
previewed.  File links and attachments are previewed using inline
image previews as before.

* testing/lisp/test-org-fold.el: Use `org-link-preview'.

* lisp/org.el (org-toggle-inline-images,
org-toggle-inline-images-command, org-display-inline-images,
org--inline-image-overlays, org-inline-image-overlays,
org-redisplay-inline-images, org-image-align,
org-display-inline-remove-overlay, org-remove-inline-images):
Obsolete and move `org-toggle-inline-images',
`org-display-inline-images' and `org-redisplay-inline-images' to
org-compat.  These are obsoleted by `org-link-preview' and
`org-link-preview-region'.  Remove
`org-toggle-inline-images-command'.  Move the other internal
functions to org-link.

* lisp/org-plot.el (org-plot/redisplay-img-in-buffer): Modify to
use `org-link-preview'.

* lisp/org-keys.el: Bind `C-c C-x C-v' to new command
`org-link-preview', which has the same prefix arg behaviors as
`org-latex-preview'.  In addition to these, it supports numeric
prefix args 1 and 11 to preview links with descriptions at
point/region (with 1) and across the buffer (with 11).

* lisp/org-cycle.el (org-cycle-display-inline-images): Use
`org-link-preview'.

* lisp/org-compat.el (org-display-inline-remove-overlay,
org--inline-image-overlays, org-remove-inline-images,
org-inline-image-overlays, org-display-inline-images,
org-toggle-inline-images):

* lisp/org-attach.el: Add new `:preview' link parameter for links
of type "attachment".
---
 lisp/ol.el                    | 280 ++++++++++++++++++++++++++++++++-
 lisp/org-attach.el            |  10 +-
 lisp/org-compat.el            | 189 +++++++++++++++++++++++
 lisp/org-cycle.el             |  10 +-
 lisp/org-keys.el              |   4 +-
 lisp/org-plot.el              |   2 +-
 lisp/org.el                   | 283 +---------------------------------
 testing/lisp/test-org-fold.el |   4 +-
 8 files changed, 489 insertions(+), 293 deletions(-)

diff --git a/lisp/ol.el b/lisp/ol.el
index 52ea62d69..baed73daa 100644
--- a/lisp/ol.el
+++ b/lisp/ol.el
@@ -82,6 +82,13 @@ (declare-function org-src-source-buffer "org-src" ())
 (declare-function org-src-source-type "org-src" ())
 (declare-function org-time-stamp-format "org" (&optional long inactive))
 (declare-function outline-next-heading "outline" ())
+(declare-function image-flush "image" (spec &optional frame))
+(declare-function org-entry-end-position "org" ())
+(declare-function org-element-contents-begin "org-element" (node))
+(declare-function org-attach-expand "org-attach" (file))
+(declare-function org-display-inline-image--width "org" (link))
+(declare-function org-image--align "org" (link))
+(declare-function org--create-inline-image "org" (file width))
 
 \f
 ;;; Customization
@@ -171,6 +178,16 @@ (defcustom org-link-parameters nil
 
   The default face is `org-link'.
 
+`:preview'
+
+  Function to run to generate an in-buffer preview for the link.  It
+  must accept three arguments:
+  - an overlay placed from the start to the end of the link.
+  - the link path, as a string.
+  - the link element
+
+  This function must return a non-nil value to indicate success.
+
 `:help-echo'
 
   String or function used as a value for the `help-echo' text
@@ -649,6 +666,13 @@ (defvar org-link--insert-history nil
 (defvar org-link--search-failed nil
   "Non-nil when last link search failed.")
 
+(defvar-local org-link-preview-overlays nil)
+;; Preserve when switching modes or when restarting Org.
+;; If we clear the overlay list and later enable Or mode, the existing
+;; image overlays will never be cleared by `org-link-preview'
+;; and `org-link-preview-clear'.
+(put 'org-link-preview-overlays 'permanent-local t)
+
 \f
 ;;; Internal Functions
 
@@ -881,6 +905,30 @@ (defun org-link--file-link-to-here ()
          (setq desc search-desc))))
     (cons link desc)))
 
+(defun org-link-preview--get-overlays (&optional beg end)
+  "Return link preview overlays between BEG and END."
+  (let* ((beg (or beg (point-min)))
+         (end (or end (point-max)))
+         (overlays (overlays-in beg end))
+         result)
+    (dolist (ov overlays result)
+      (when (memq ov org-link-preview-overlays)
+        (push ov result)))))
+
+(defun org-link-preview--remove-overlay (ov after _beg _end &optional _len)
+  "Remove link-preview overlay OV if a corresponding region is modified.
+
+AFTER is true when this function is called post-change."
+  (when (and ov after)
+    (setq org-link-preview-overlays (delete ov org-link-preview-overlays))
+    ;; Clear image from cache to avoid image not updating upon
+    ;; changing on disk.  See Emacs bug#59902.
+    (when-let* (((overlay-get ov 'org-image-overlay))
+                (disp (overlay-get ov 'display))
+                ((imagep disp)))
+      (image-flush disp))
+    (delete-overlay ov)))
+
 \f
 ;;; Public API
 
@@ -1573,6 +1621,194 @@ (defun org-link-add-angle-brackets (s)
   (unless (equal (substring s -1) ">") (setq s (concat s ">")))
   s)
 
+;;;###autoload
+(defun org-link-preview (&optional arg beg end)
+  "Toggle display of link previews in the buffer.
+
+When region BEG..END is active, preview links in the
+region.
+
+When point is at a link, display a preview for that link only.
+Otherwise, display previews for links in current entry.
+
+With numeric prefix ARG 1, preview links with description as
+well.
+
+With prefix ARG `\\[universal-argument]', clear link previews at
+point or in the current entry.
+
+With prefix ARG `\\[universal-argument] \\[universal-argument]',
+ display link previews in the accessible portion of the
+ buffer.  With numeric prefix ARG 11, do the same, but include
+ links with descriptions.
+
+With prefix ARG `\\[universal-argument] \\[universal-argument] \\[universal-argument]',
+hide all link previews in the accessible portion of the buffer.
+
+This command is designed for interactive use.  From Elisp, you can
+also use `org-link-preview-region'."
+  (interactive (cons current-prefix-arg
+                     (when (use-region-p)
+                       (list (region-beginning) (region-end)))))
+  (let* ((include-linked
+          (cond
+           ((member arg '(nil (4) (16)) ) nil)
+           ((member arg '(1 11)) 'include-linked)
+           (t 'include-linked)))
+         (interactive? (called-interactively-p 'any))
+         (toggle-previews
+          (lambda (&optional beg end scope remove)
+            (let* ((beg (or beg (point-min)))
+                   (end (or end (point-max)))
+                   (old (org-link-preview--get-overlays beg end))
+                   (scope (or scope (format "%d:%d" beg end))))
+              (if remove
+                  (progn
+                    (org-link-preview-clear beg end)
+                    (when interactive?
+                      (message
+                       "[%s] Inline link previews turned off (removed %d images)"
+                       scope (length old))))
+	        (org-link-preview-region include-linked t beg end)
+                (when interactive?
+                  (let ((new (org-link-preview--get-overlays beg end)))
+                    (message
+                     (if new
+		         (format "[%s] %d images displayed inline %s"
+			         scope (length new)
+                                 (if include-linked "(including images with description)"
+                                   ""))
+		       (format "[%s] No images to display inline" scope))))))))))
+    (cond
+     ;; Region selected :: display previews in region.
+     ((and beg end)
+      (funcall toggle-previews beg end "region"
+               (and (equal arg '(4)) 'remove)))
+     ;; C-u argument: clear image at point or in entry
+     ((equal arg '(4))
+      (if (get-char-property (point) 'org-image-overlay)
+          ;; clear link preview at point
+          (when-let ((context (org-element-context))
+                     ((org-element-type-p context 'link)))
+            (funcall toggle-previews
+                     (org-element-begin context)
+                     (org-element-end context)
+                     "preview at point" 'remove))
+        ;; Clear link previews in entry
+        (funcall toggle-previews
+                 (if (org-before-first-heading-p) (point-min)
+                   (save-excursion
+                     (org-with-limited-levels (org-back-to-heading t) (point))))
+                 (org-with-limited-levels (org-entry-end-position))
+                 "current section" 'remove)))
+     ;; C-u C-u or C-11 argument :: display images in the whole buffer.
+     ((member arg '(11 (16))) (funcall toggle-previews nil nil "buffer"))
+     ;; C-u C-u C-u argument :: unconditionally hide images in the buffer.
+     ((equal arg '(64)) (funcall toggle-previews nil nil "buffer" 'remove))
+     ;; Argument nil or 1, no region selected :: display images in
+     ;; current section or image link at point.
+     ((and (member arg '(nil 1)) (null beg) (null end))
+      (let ((context (org-element-context)))
+        ;; toggle display of inline image link at point.
+        (if (org-element-type-p context 'link)
+            (let* ((ov (cdr-safe (get-char-property-and-overlay
+                                  (point) 'org-image-overlay)))
+                   (remove? (and ov (memq ov org-link-preview-overlays)
+                                 'remove)))
+              (funcall toggle-previews
+                       (org-element-begin context)
+                       (org-element-end context)
+                       "image at point" remove?))
+          (let ((beg (if (org-before-first-heading-p) (point-min)
+	               (save-excursion
+	                 (org-with-limited-levels (org-back-to-heading t) (point)))))
+                (end (org-with-limited-levels (org-entry-end-position))))
+            (funcall toggle-previews beg end "current section")))))
+     ;; Any other non-nil argument.
+     ((not (null arg)) (funcall toggle-previews beg end "region")))))
+
+(defun org-link-preview-region (&optional include-linked refresh beg end)
+  "Display link previews.
+
+A previewable link type is one that has a `:preview' link
+parameter, see `org-link-parameters'.
+
+By default, a file link or attachment is previewable if it
+follows either of these conventions:
+
+  1. Its path is a file with an extension matching return value
+     from `image-file-name-regexp' and it has no contents.
+
+  2. Its description consists in a single link of the previous
+     type.  In this case, that link must be a well-formed plain
+     or angle link, i.e., it must have an explicit \"file\" or
+     \"attachment\" type.
+
+File links are equipped with the keymap `image-map'.
+
+When optional argument INCLUDE-LINKED is non-nil, links with a
+text description part will also be inlined.  This can be nice for
+a quick look at those images, but it does not reflect what
+exported files will look like.
+
+When optional argument REFRESH is non-nil, refresh existing
+images between BEG and END.  This will create new image displays
+only if necessary.
+
+BEG and END define the considered part.  They default to the
+buffer boundaries with possible narrowing."
+  (interactive "P")
+  (when (display-graphic-p)
+    (when refresh (org-link-preview-clear beg end))
+    (when (fboundp 'clear-image-cache) (clear-image-cache)))
+  (org-with-point-at (or beg (point-min))
+    (let ((case-fold-search t))
+      (while (re-search-forward org-link-any-re end t)
+        (when-let* ((link (org-element-lineage
+                           (save-match-data (org-element-context))
+                           'link t))
+                    (linktype (org-element-property :type link))
+                    (preview-func (org-link-get-parameter linktype :preview))
+                    (path (and (or include-linked
+                                   (not (org-element-contents-begin link)))
+                               (org-element-property :path link))))
+          ;; Create an overlay to hold the preview
+          (let ((ov (make-overlay
+                     (org-element-begin link)
+                     (progn
+		       (goto-char
+			(org-element-end link))
+		       (unless (eolp) (skip-chars-backward " \t"))
+		       (point)))))
+            ;; TODO: Change this overlay property to `org-link-preview' everywhere.
+            (overlay-put ov 'org-image-overlay t)
+            (overlay-put ov 'modification-hooks
+                         (list 'org-link-preview--remove-overlay))
+            ;; call preview function for link type
+            (if (funcall preview-func ov path link)
+              (when (overlay-buffer ov)
+                (push ov org-link-preview-overlays))
+              ;; Preview was unsuccessful, delete overlay
+              (delete-overlay ov))))))))
+
+(defun org-link-preview-clear (&optional beg end)
+  "Clear link previews in region BEG to END."
+  (interactive (and (use-region-p) (list (region-beginning) (region-end))))
+  (let* ((beg (or beg (point-min)))
+         (end (or end (point-max)))
+         (overlays (overlays-in beg end)))
+    (dolist (ov overlays)
+      (when (memq ov org-link-preview-overlays)
+        (when-let ((image (overlay-get ov 'display))
+                   ((imagep image)))
+          (image-flush image))
+        (setq org-link-preview-overlays (delq ov org-link-preview-overlays))
+        (delete-overlay ov)))
+    ;; Clear removed overlays.
+    (dolist (ov org-link-preview-overlays)
+      (unless (overlay-buffer ov)
+        (setq org-link-preview-overlays (delq ov org-link-preview-overlays))))))
+
 \f
 ;;; Built-in link types
 
@@ -1595,7 +1831,49 @@ (defun org-link--open-elisp (path _)
 (org-link-set-parameters "elisp" :follow #'org-link--open-elisp)
 
 ;;;; "file" link type
-(org-link-set-parameters "file" :complete #'org-link-complete-file)
+(org-link-set-parameters "file"
+                         :complete #'org-link-complete-file
+                         :preview #'org-link-preview-file)
+
+(defun org-link-preview-file (ov path link)
+  "Display image file PATH in overlay OV for LINK.
+
+LINK is the Org element being previewed.
+
+Equip each image with the keymap `image-map'.
+
+This is intended to be used as the `:preview' link property of
+file links, see `org-link-parameters'."
+  (if (not (display-graphic-p))
+      (prog1 nil
+        (message "Your Emacs does not support displaying images!"))
+    (when-let* ((file-full (expand-file-name path))
+                (file (substitute-in-file-name file-full))
+                ((string-match-p (image-file-name-regexp) file))
+                ((file-exists-p file)))
+      (let* ((width (org-display-inline-image--width link))
+	     (align (org-image--align link))
+             (image (org--create-inline-image file width)))
+        (when image            ; Add image to overlay
+	  ;; See bug#59902.  We cannot rely
+          ;; on Emacs to update image if the file
+          ;; has changed.
+          (image-flush image)
+	  (overlay-put ov 'display image)
+	  (overlay-put ov 'face 'default)
+	  (overlay-put ov 'org-image-overlay t)
+	  (when (boundp 'image-map)
+	    (overlay-put ov 'keymap image-map))
+          (when align
+            (overlay-put
+             ov 'before-string
+             (propertize
+              " " 'face 'default
+              'display
+              (pcase align
+                ("center" `(space :align-to (- center (0.5 . ,image))))
+                ("right"  `(space :align-to (- right ,image)))))))
+          t)))))
 
 ;;;; "help" link type
 (defun org-link--open-help (path _)
diff --git a/lisp/org-attach.el b/lisp/org-attach.el
index 7a03d170e..4b0887fcd 100644
--- a/lisp/org-attach.el
+++ b/lisp/org-attach.el
@@ -797,9 +797,17 @@ (defun org-attach-follow (file arg)
 See `org-open-file' for details about ARG."
   (org-link-open-as-file (org-attach-expand file) arg))
 
+(defun org-attach-preview-file (ov path link)
+  "Preview attachment with PATH in overlay OV.
+
+LINK is the Org link element being previewed."
+  (org-link-preview-file
+   ov (org-attach-expand path) link))
+
 (org-link-set-parameters "attachment"
 			 :follow #'org-attach-follow
-                         :complete #'org-attach-complete-link)
+                         :complete #'org-attach-complete-link
+                         :preview #'org-attach-preview-file)
 
 (defun org-attach-complete-link ()
   "Advise the user with the available files in the attachment directory."
diff --git a/lisp/org-compat.el b/lisp/org-compat.el
index d843216f3..242b46a86 100644
--- a/lisp/org-compat.el
+++ b/lisp/org-compat.el
@@ -783,6 +783,195 @@ (defun org-add-link-type (type &optional follow export)
 
 (make-obsolete 'org-add-link-type "use `org-link-set-parameters' instead." "9.0")
 
+(declare-function org-link-preview--remove-overlay "ol")
+(declare-function org-link-preview--get-overlays "ol")
+(declare-function org-link-preview-clear "ol")
+(declare-function org-link-preview--remove-overlay "ol")
+
+(define-obsolete-function-alias 'org-display-inline-remove-overlay
+  'org-link-preview--remove-overlay "9.8")
+(define-obsolete-function-alias 'org--inline-image-overlays
+  'org-link-preview--get-overlays "9.8")
+(define-obsolete-function-alias 'org-remove-inline-images
+  'org-link-preview-clear "9.8")
+(define-obsolete-variable-alias 'org-inline-image-overlays
+  'org-link-preview-overlays "9.8")
+(defvar org-link-preview-overlays)
+(defvar org-link-abbrev-alist-local)
+(defvar org-link-abbrev-alist)
+(defvar org-link-angle-re)
+(defvar org-link-plain-re)
+(declare-function org-attach-expand "org-attach")
+(declare-function org-display-inline-image--width "org")
+(declare-function org-image--align "org")
+(declare-function org--create-inline-image "org")
+
+(make-obsolete 'org-display-inline-images
+               'org-link-preview-region "9.8")
+;; FIXME: Unused; obsoleted; to be removed
+(defun org-display-inline-images (&optional include-linked refresh beg end)
+  "Display inline images.
+
+An inline image is a link which follows either of these
+conventions:
+
+  1. Its path is a file with an extension matching return value
+     from `image-file-name-regexp' and it has no contents.
+
+  2. Its description consists in a single link of the previous
+     type.  In this case, that link must be a well-formed plain
+     or angle link, i.e., it must have an explicit \"file\" or
+     \"attachment\" type.
+
+Equip each image with the key-map `image-map'.
+
+When optional argument INCLUDE-LINKED is non-nil, also links with
+a text description part will be inlined.  This can be nice for
+a quick look at those images, but it does not reflect what
+exported files will look like.
+
+When optional argument REFRESH is non-nil, refresh existing
+images between BEG and END.  This will create new image displays
+only if necessary.
+
+BEG and END define the considered part.  They default to the
+buffer boundaries with possible narrowing."
+  (interactive "P")
+  (when (display-graphic-p)
+    (when refresh
+      (org-link-preview-clear beg end)
+      (when (fboundp 'clear-image-cache) (clear-image-cache)))
+    (let ((end (or end (point-max))))
+      (org-with-point-at (or beg (point-min))
+	(let* ((case-fold-search t)
+	       (file-extension-re (image-file-name-regexp))
+	       (link-abbrevs (mapcar #'car
+				     (append org-link-abbrev-alist-local
+					     org-link-abbrev-alist)))
+	       ;; Check absolute, relative file names and explicit
+	       ;; "file:" links.  Also check link abbreviations since
+	       ;; some might expand to "file" links.
+	       (file-types-re
+		(format "\\[\\[\\(?:file%s:\\|attachment:\\|[./~]\\)\\|\\]\\[\\(<?\\(?:file\\|attachment\\):\\)"
+			(if (not link-abbrevs) ""
+			  (concat "\\|" (regexp-opt link-abbrevs))))))
+	  (while (re-search-forward file-types-re end t)
+	    (let* ((link (org-element-lineage
+			  (save-match-data (org-element-context))
+			  'link t))
+                   (linktype (org-element-property :type link))
+		   (inner-start (match-beginning 1))
+		   (path
+		    (cond
+		     ;; No link at point; no inline image.
+		     ((not link) nil)
+		     ;; File link without a description.  Also handle
+		     ;; INCLUDE-LINKED here since it should have
+		     ;; precedence over the next case.  I.e., if link
+		     ;; contains filenames in both the path and the
+		     ;; description, prioritize the path only when
+		     ;; INCLUDE-LINKED is non-nil.
+		     ((or (not (org-element-contents-begin link))
+			  include-linked)
+		      (and (or (equal "file" linktype)
+                               (equal "attachment" linktype))
+			   (org-element-property :path link)))
+		     ;; Link with a description.  Check if description
+		     ;; is a filename.  Even if Org doesn't have syntax
+		     ;; for those -- clickable image -- constructs, fake
+		     ;; them, as in `org-export-insert-image-links'.
+		     ((not inner-start) nil)
+		     (t
+		      (org-with-point-at inner-start
+			(and (looking-at
+			      (if (char-equal ?< (char-after inner-start))
+				  org-link-angle-re
+				org-link-plain-re))
+			     ;; File name must fill the whole
+			     ;; description.
+			     (= (org-element-contents-end link)
+				(match-end 0))
+			     (progn
+                               (setq linktype (match-string 1))
+                               (match-string 2))))))))
+	      (when (and path (string-match-p file-extension-re path))
+		(let ((file (if (equal "attachment" linktype)
+				(progn
+                                  (require 'org-attach)
+				  (ignore-errors (org-attach-expand path)))
+                              (expand-file-name path))))
+                  ;; Expand environment variables.
+                  (when file (setq file (substitute-in-file-name file)))
+		  (when (and file (file-exists-p file))
+		    (let ((width (org-display-inline-image--width link))
+			  (align (org-image--align link))
+                          (old (get-char-property-and-overlay
+				(org-element-begin link)
+				'org-image-overlay)))
+		      (if (and (car-safe old) refresh)
+                          (image-flush (overlay-get (cdr old) 'display))
+			(let ((image (org--create-inline-image file width)))
+			  (when image
+			    (let ((ov (make-overlay
+				       (org-element-begin link)
+				       (progn
+					 (goto-char
+					  (org-element-end link))
+					 (unless (eolp) (skip-chars-backward " \t"))
+					 (point)))))
+                              ;; See bug#59902.  We cannot rely
+                              ;; on Emacs to update image if the file
+                              ;; has changed.
+                              (image-flush image)
+			      (overlay-put ov 'display image)
+			      (overlay-put ov 'face 'default)
+			      (overlay-put ov 'org-image-overlay t)
+			      (overlay-put
+			       ov 'modification-hooks
+			       (list 'org-link-preview--remove-overlay))
+			      (when (boundp 'image-map)
+				(overlay-put ov 'keymap image-map))
+                              (when align
+                                (overlay-put
+                                 ov 'before-string
+                                 (propertize
+                                  " " 'face 'default
+                                  'display
+                                  (pcase align
+                                    ("center" `(space :align-to (- center (0.5 . ,image))))
+                                    ("right"  `(space :align-to (- right ,image)))))))
+			      (push ov org-inline-image-overlays))))))))))))))))
+
+(make-obsolete 'org-toggle-inline-images
+               'org-link-preview "9.8")
+;; FIXME: Unused; obsoleted; to be removed
+(defun org-toggle-inline-images (&optional include-linked beg end)
+  "Toggle the display of inline images.
+INCLUDE-LINKED is passed to `org-display-inline-images'."
+  (interactive "P")
+  (if (org-link-preview--get-overlays beg end)
+      (progn
+        (org-link-preview-clear beg end)
+        (when (called-interactively-p 'interactive)
+	  (message "Inline image display turned off")))
+    (org-display-inline-images include-linked nil beg end)
+    (when (called-interactively-p 'interactive)
+      (let ((new (org-link-preview--get-overlays beg end)))
+        (message (if new
+		     (format "%d images displayed inline"
+			     (length new))
+		   "No images to display inline"))))))
+
+(make-obsolete 'org-redisplay-inline-images
+               'org-link-preview "9.8")
+;; FIXME: Unused; obsoleted; to be removed
+(defun org-redisplay-inline-images ()
+  "Assure display of inline images and refresh them."
+  (interactive)
+  (org-toggle-inline-images)
+  (unless org-link-preview-overlays
+    (org-toggle-inline-images)))
+
 ;;;; Functions unused in Org core.
 (defun org-table-recognize-table.el ()
   "If there is a table.el table nearby, recognize it and move into it."
diff --git a/lisp/org-cycle.el b/lisp/org-cycle.el
index 8a39bdb8c..1a1c916bd 100644
--- a/lisp/org-cycle.el
+++ b/lisp/org-cycle.el
@@ -40,14 +40,14 @@ (declare-function org-element-property "org-element-ast" (property node))
 (declare-function org-element-post-affiliated "org-element" (node))
 (declare-function org-element-lineage "org-element-ast" (datum &optional types with-self))
 (declare-function org-element-at-point "org-element" (&optional pom cached-only))
-(declare-function org-display-inline-images "org" (&optional include-linked refresh beg end))
+(declare-function org-link-preview-region "ol" (&optional include-linked refresh beg end))
 (declare-function org-get-tags "org" (&optional pos local fontify))
 (declare-function org-subtree-end-visible-p "org" ())
 (declare-function org-narrow-to-subtree "org" (&optional element))
 (declare-function org-next-visible-heading "org" (arg))
 (declare-function org-at-property-p "org" ())
 (declare-function org-re-property "org" (property &optional literal allow-null value))
-(declare-function org-remove-inline-images "org" (&optional beg end))
+(declare-function org-link-preview-clear "ol" (&optional beg end))
 (declare-function org-item-beginning-re "org" ())
 (declare-function org-at-heading-p "org" (&optional invisible-not-ok))
 (declare-function org-at-item-p "org" ())
@@ -817,19 +817,19 @@ (defun org-cycle-display-inline-images (state)
         ;; If has nested headlines, beg,end only from parent headline
         ;; to first child headline which reference to upper
         ;; let-binding `org-next-visible-heading'.
-        (org-display-inline-images
+        (org-link-preview-region
          nil nil
          (point-min) (progn (org-next-visible-heading 1) (point)))))
       ('subtree
        (org-with-wide-buffer
         (org-narrow-to-subtree)
         ;; If has nested headlines, also inline display images under all sub-headlines.
-        (org-display-inline-images nil nil (point-min) (point-max))))
+        (org-link-preview-region nil nil (point-min) (point-max))))
       ('folded
        (org-with-wide-buffer
         (org-narrow-to-subtree)
         (if (numberp (point-max))
-            (org-remove-inline-images (point-min) (point-max))
+            (org-link-preview-clear (point-min) (point-max))
           (ignore)))))))
 
 (provide 'org-cycle)
diff --git a/lisp/org-keys.el b/lisp/org-keys.el
index 1daedaae8..77cbe5c0f 100644
--- a/lisp/org-keys.el
+++ b/lisp/org-keys.el
@@ -218,7 +218,7 @@ (declare-function org-toggle-checkbox "org" (&optional toggle-presence))
 (declare-function org-toggle-radio-button "org" (&optional arg))
 (declare-function org-toggle-comment "org" ())
 (declare-function org-toggle-fixed-width "org" ())
-(declare-function org-toggle-inline-images-command "org" (&optional arg beg end))
+(declare-function org-link-preview "ol" (&optional arg beg end))
 (declare-function org-latex-preview "org" (&optional arg))
 (declare-function org-toggle-narrow-to-subtree "org" ())
 (declare-function org-toggle-ordered-property "org" ())
@@ -618,7 +618,7 @@ (org-defkey org-mode-map (kbd "C-c C-x C-d") #'org-clock-display)
 (org-defkey org-mode-map (kbd "C-c C-x x") #'org-dynamic-block-insert-dblock)
 (org-defkey org-mode-map (kbd "C-c C-x C-u") #'org-dblock-update)
 (org-defkey org-mode-map (kbd "C-c C-x C-l") #'org-latex-preview)
-(org-defkey org-mode-map (kbd "C-c C-x C-v") #'org-toggle-inline-images-command)
+(org-defkey org-mode-map (kbd "C-c C-x C-v") #'org-link-preview)
 (org-defkey org-mode-map (kbd "C-c C-x C-M-v") #'org-redisplay-inline-images)
 (org-defkey org-mode-map (kbd "C-c C-x \\") #'org-toggle-pretty-entities)
 (org-defkey org-mode-map (kbd "C-c C-x C-b") #'org-toggle-checkbox)
diff --git a/lisp/org-plot.el b/lisp/org-plot.el
index b045344f0..836cfaffc 100644
--- a/lisp/org-plot.el
+++ b/lisp/org-plot.el
@@ -633,7 +633,7 @@ (defun org-plot/gnuplot-script (table data-file num-cols params &optional prefac
 
 (defun org-plot/redisplay-img-in-buffer (img-file)
   "Find any overlays for IMG-FILE in the current Org buffer, and refresh them."
-  (dolist (img-overlay org-inline-image-overlays)
+  (dolist (img-overlay org-link-preview-overlays)
     (when (string= img-file (plist-get (cdr (overlay-get img-overlay 'display)) :file))
       (when (and (file-exists-p img-file)
                  (fboundp 'image-flush))
diff --git a/lisp/org.el b/lisp/org.el
index d5c1dcb35..091a09344 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -5079,7 +5079,7 @@ (define-derived-mode org-mode outline-mode "Org"
     ;; modifications to make cache updates work reliably.
     (org-unmodified
      (when org-startup-with-beamer-mode (org-beamer-mode))
-     (when org-startup-with-inline-images (org-display-inline-images))
+     (when org-startup-with-inline-images (org-link-preview '(16)))
      (when org-startup-with-latex-preview (org-latex-preview '(16)))
      (unless org-inhibit-startup-visibility-stuff (org-cycle-set-startup-visibility))
      (when org-startup-truncated (setq truncate-lines t))
@@ -16651,126 +16651,6 @@ (defun org-normalize-color (value)
 \f
 ;; Image display
 
-(defvar-local org-inline-image-overlays nil)
-;; Preserve when switching modes or when restarting Org.
-;; If we clear the overlay list and later enable Or mode, the existing
-;; image overlays will never be cleared by `org-toggle-inline-images'
-;; and `org-toggle-inline-images-command'.
-(put 'org-inline-image-overlays 'permanent-local t)
-
-(defun org--inline-image-overlays (&optional beg end)
-  "Return image overlays between BEG and END."
-  (let* ((beg (or beg (point-min)))
-         (end (or end (point-max)))
-         (overlays (overlays-in beg end))
-         result)
-    (dolist (ov overlays result)
-      (when (memq ov org-inline-image-overlays)
-        (push ov result)))))
-
-(defun org-toggle-inline-images-command (&optional arg beg end)
-  "Toggle display of inline images without description at point.
-
-When point is at an image link, toggle displaying that image.
-Otherwise, toggle displaying images in current entry.
-
-When region BEG..END is active, toggle displaying images in the
-region.
-
-With numeric prefix ARG 1, display images with description as well.
-
-With prefix ARG `\\[universal-argument]', toggle displaying images in
-the accessible portion of the buffer.  With numeric prefix ARG 11, do
-the same, but include images with description.
-
-With prefix ARG `\\[universal-argument] \\[universal-argument]', hide
-all the images in accessible portion of the buffer.
-
-This command is designed for interactive use.  From Elisp, you can
-also use `org-toggle-inline-images'."
-  (interactive (cons current-prefix-arg
-                     (when (use-region-p)
-                       (list (region-beginning) (region-end)))))
-  (let* ((include-linked
-          (cond
-           ((member arg '(nil (4) (16)) ) nil)
-           ((member arg '(1 11)) 'include-linked)
-           (t 'include-linked)))
-         (interactive? (called-interactively-p 'any))
-         (toggle-images
-          (lambda (&optional beg end scope force-remove)
-            (let* ((beg (or beg (point-min)))
-                   (end (or end (point-max)))
-                   (old (org--inline-image-overlays beg end))
-                   (scope (or scope (format "%d:%d" beg end))))
-              (if (or old force-remove)
-                  (progn
-                    (org-remove-inline-images beg end)
-                    (when interactive?
-                      (message
-                       "[%s] Inline image display turned off (removed %d images)"
-                       scope (length old))))
-	        (org-display-inline-images include-linked t beg end)
-                (when interactive?
-                  (let ((new (org--inline-image-overlays beg end)))
-                    (message
-                     (if new
-		         (format "[%s] %d images displayed inline %s"
-			         scope (length new)
-                                 (if include-linked "(including images with description)"
-                                   ""))
-		       (format "[%s] No images to display inline" scope))))))))))
-    (cond
-     ((not (display-graphic-p))
-      (message "Your Emacs does not support displaying images!"))
-     ;; Region selected :: toggle images in region.
-     ((and beg end) (funcall toggle-images beg end "region"))
-     ;; C-u or C-11 argument :: toggle images in the whole buffer.
-     ((member arg '(11 (4))) (funcall toggle-images nil nil "buffer"))
-     ;; C-u C-u argument :: unconditionally hide images in the buffer.
-     ((equal arg '(16)) (funcall toggle-images nil nil "buffer" 'remove))
-     ;; Argument nil or 1, no region selected :: toggle (display or hide
-     ;; dwim) images in current section or image link at point.
-     ((and (member arg '(nil 1)) (null beg) (null end))
-      (let ((context (org-element-context)))
-        ;; toggle display of inline image link at point.
-        (if (org-element-type-p context 'link)
-            (funcall toggle-images
-                     (org-element-begin context)
-                     (org-element-end context)
-                     "image at point")
-          (let ((beg (if (org-before-first-heading-p) (point-min)
-	               (save-excursion
-	                 (org-with-limited-levels (org-back-to-heading t) (point)))))
-                (end (org-with-limited-levels (org-entry-end-position))))
-            (funcall toggle-images beg end "current section")))))
-     ;; Any other non-nil argument.
-     ((not (null arg)) (funcall toggle-images beg end "region")))))
-
-(defun org-toggle-inline-images (&optional include-linked beg end)
-  "Toggle the display of inline images.
-INCLUDE-LINKED is passed to `org-display-inline-images'."
-  (interactive "P")
-  (if (org--inline-image-overlays beg end)
-      (progn
-        (org-remove-inline-images beg end)
-        (when (called-interactively-p 'interactive)
-	  (message "Inline image display turned off")))
-    (org-display-inline-images include-linked nil beg end)
-    (when (called-interactively-p 'interactive)
-      (let ((new (org--inline-image-overlays beg end)))
-        (message (if new
-		     (format "%d images displayed inline"
-			     (length new))
-		   "No images to display inline"))))))
-
-(defun org-redisplay-inline-images ()
-  "Assure display of inline images and refresh them."
-  (interactive)
-  (org-toggle-inline-images)
-  (unless org-inline-image-overlays
-    (org-toggle-inline-images)))
-
 ;; For without-x builds.
 (declare-function image-flush "image" (spec &optional frame))
 
@@ -16793,7 +16673,7 @@ (defcustom org-display-remote-inline-images 'skip
   :safe #'symbolp)
 
 (defcustom org-image-align 'left
-  "How to align images previewed using `org-display-inline-images'.
+  "How to align images previewed using `org-link-preview-region'.
 
 Only stand-alone image links are affected by this setting.  These
 are links without surrounding text.
@@ -16850,139 +16730,6 @@ (defun org--create-inline-image (file width)
                                 org-image-max-width)))
                     :scale 1))))
 
-(defun org-display-inline-images (&optional include-linked refresh beg end)
-  "Display inline images.
-
-An inline image is a link which follows either of these
-conventions:
-
-  1. Its path is a file with an extension matching return value
-     from `image-file-name-regexp' and it has no contents.
-
-  2. Its description consists in a single link of the previous
-     type.  In this case, that link must be a well-formed plain
-     or angle link, i.e., it must have an explicit \"file\" or
-     \"attachment\" type.
-
-Equip each image with the key-map `image-map'.
-
-When optional argument INCLUDE-LINKED is non-nil, also links with
-a text description part will be inlined.  This can be nice for
-a quick look at those images, but it does not reflect what
-exported files will look like.
-
-When optional argument REFRESH is non-nil, refresh existing
-images between BEG and END.  This will create new image displays
-only if necessary.
-
-BEG and END define the considered part.  They default to the
-buffer boundaries with possible narrowing."
-  (interactive "P")
-  (when (display-graphic-p)
-    (when refresh
-      (org-remove-inline-images beg end)
-      (when (fboundp 'clear-image-cache) (clear-image-cache)))
-    (let ((end (or end (point-max))))
-      (org-with-point-at (or beg (point-min))
-	(let* ((case-fold-search t)
-	       (file-extension-re (image-file-name-regexp))
-	       (link-abbrevs (mapcar #'car
-				     (append org-link-abbrev-alist-local
-					     org-link-abbrev-alist)))
-	       ;; Check absolute, relative file names and explicit
-	       ;; "file:" links.  Also check link abbreviations since
-	       ;; some might expand to "file" links.
-	       (file-types-re
-		(format "\\[\\[\\(?:file%s:\\|attachment:\\|[./~]\\)\\|\\]\\[\\(<?\\(?:file\\|attachment\\):\\)"
-			(if (not link-abbrevs) ""
-			  (concat "\\|" (regexp-opt link-abbrevs))))))
-	  (while (re-search-forward file-types-re end t)
-	    (let* ((link (org-element-lineage
-			  (save-match-data (org-element-context))
-			  'link t))
-                   (linktype (org-element-property :type link))
-		   (inner-start (match-beginning 1))
-		   (path
-		    (cond
-		     ;; No link at point; no inline image.
-		     ((not link) nil)
-		     ;; File link without a description.  Also handle
-		     ;; INCLUDE-LINKED here since it should have
-		     ;; precedence over the next case.  I.e., if link
-		     ;; contains filenames in both the path and the
-		     ;; description, prioritize the path only when
-		     ;; INCLUDE-LINKED is non-nil.
-		     ((or (not (org-element-contents-begin link))
-			  include-linked)
-		      (and (or (equal "file" linktype)
-                               (equal "attachment" linktype))
-			   (org-element-property :path link)))
-		     ;; Link with a description.  Check if description
-		     ;; is a filename.  Even if Org doesn't have syntax
-		     ;; for those -- clickable image -- constructs, fake
-		     ;; them, as in `org-export-insert-image-links'.
-		     ((not inner-start) nil)
-		     (t
-		      (org-with-point-at inner-start
-			(and (looking-at
-			      (if (char-equal ?< (char-after inner-start))
-				  org-link-angle-re
-				org-link-plain-re))
-			     ;; File name must fill the whole
-			     ;; description.
-			     (= (org-element-contents-end link)
-				(match-end 0))
-			     (progn
-                               (setq linktype (match-string 1))
-                               (match-string 2))))))))
-	      (when (and path (string-match-p file-extension-re path))
-		(let ((file (if (equal "attachment" linktype)
-				(progn
-                                  (require 'org-attach)
-				  (ignore-errors (org-attach-expand path)))
-                              (expand-file-name path))))
-                  ;; Expand environment variables.
-                  (when file (setq file (substitute-in-file-name file)))
-		  (when (and file (file-exists-p file))
-		    (let ((width (org-display-inline-image--width link))
-			  (align (org-image--align link))
-                          (old (get-char-property-and-overlay
-				(org-element-begin link)
-				'org-image-overlay)))
-		      (if (and (car-safe old) refresh)
-                          (image-flush (overlay-get (cdr old) 'display))
-			(let ((image (org--create-inline-image file width)))
-			  (when image
-			    (let ((ov (make-overlay
-				       (org-element-begin link)
-				       (progn
-					 (goto-char
-					  (org-element-end link))
-					 (unless (eolp) (skip-chars-backward " \t"))
-					 (point)))))
-                              ;; See bug#59902.  We cannot rely
-                              ;; on Emacs to update image if the file
-                              ;; has changed.
-                              (image-flush image)
-			      (overlay-put ov 'display image)
-			      (overlay-put ov 'face 'default)
-			      (overlay-put ov 'org-image-overlay t)
-			      (overlay-put
-			       ov 'modification-hooks
-			       (list 'org-display-inline-remove-overlay))
-			      (when (boundp 'image-map)
-				(overlay-put ov 'keymap image-map))
-                              (when align
-                                (overlay-put
-                                 ov 'before-string
-                                 (propertize
-                                  " " 'face 'default
-                                  'display
-                                  (pcase align
-                                    ("center" `(space :align-to (- center (0.5 . ,image))))
-                                    ("right"  `(space :align-to (- right ,image)))))))
-			      (push ov org-inline-image-overlays))))))))))))))))
-
 (declare-function org-export-read-attribute "ox"
                   (attribute element &optional property))
 (defvar visual-fill-column-width) ; Silence compiler warning
@@ -17135,32 +16882,6 @@ (defun org-image--align (link)
             (when (memq org-image-align '(center right))
               (symbol-name org-image-align))))))))
 
-
-(defun org-display-inline-remove-overlay (ov after _beg _end &optional _len)
-  "Remove inline-display overlay if a corresponding region is modified."
-  (when (and ov after)
-    (setq org-inline-image-overlays (delete ov org-inline-image-overlays))
-    ;; Clear image from cache to avoid image not updating upon
-    ;; changing on disk.  See Emacs bug#59902.
-    (when (overlay-get ov 'org-image-overlay)
-      (image-flush (overlay-get ov 'display)))
-    (delete-overlay ov)))
-
-(defun org-remove-inline-images (&optional beg end)
-  "Remove inline display of images."
-  (interactive)
-  (let* ((beg (or beg (point-min)))
-         (end (or end (point-max)))
-         (overlays (overlays-in beg end)))
-    (dolist (ov overlays)
-      (when (memq ov org-inline-image-overlays)
-        (setq org-inline-image-overlays (delq ov org-inline-image-overlays))
-        (delete-overlay ov)))
-    ;; Clear removed overlays.
-    (dolist (ov org-inline-image-overlays)
-      (unless (overlay-buffer ov)
-        (setq org-inline-image-overlays (delq ov org-inline-image-overlays))))))
-
 (defvar org-self-insert-command-undo-counter 0)
 (defvar org-speed-command nil)
 
diff --git a/testing/lisp/test-org-fold.el b/testing/lisp/test-org-fold.el
index f58642be6..809738f6c 100644
--- a/testing/lisp/test-org-fold.el
+++ b/testing/lisp/test-org-fold.el
@@ -716,14 +716,14 @@ (ert-deftest test-org-fold/org-fold-display-inline-images ()
       (org-show-subtree)
       (org-fold-subtree t)
       (run-hook-with-args 'org-cycle-hook 'folded)
-      (should-not org-inline-image-overlays)
+      (should-not org-link-preview-overlays)
       (should-not
        (cl-every
         (lambda (ov) (overlay-get ov 'org-image-overlay))
         (overlays-in (point-min) (point-max))))
       (org-show-subtree)
       (run-hook-with-args 'org-cycle-hook 'subtree)
-      (should org-inline-image-overlays)
+      (should org-link-preview-overlays)
       (should
        (cl-every
         (lambda (ov) (overlay-get ov 'org-image-overlay))
-- 
2.44.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [PATCH v2] Inline image display as part of a new org-link-preview system
  2024-08-31 22:37                                                     ` [PATCH v2] " Karthik Chikmagalur
@ 2024-09-01 13:06                                                       ` Ihor Radchenko
  2024-09-02 20:13                                                         ` [PATCH v3] " Karthik Chikmagalur
  0 siblings, 1 reply; 40+ messages in thread
From: Ihor Radchenko @ 2024-09-01 13:06 UTC (permalink / raw)
  To: Karthik Chikmagalur; +Cc: stardiviner, Org mode

Karthik Chikmagalur <karthikchikmagalur@gmail.com> writes:

> First, here's an updated description of the proposed API:
>
> 1. You can register a previewer with each type of Org link in the
> following way:
>
> (org-link-set-parameters "file"  :preview #'org-link-preview-file)
> (org-link-set-parameters "https" :preview #'my/org-link-preview-web)
>
> 2. This previewer is called by Org with three parameters: an overlay,
> the link path being previewed and the link element:
>
> (funcall #'org-link-preview-file ov path link)
>
>    - To preview the link, the previewer must update the overlay ov as
>      needed, for example by placing an image as its `display' property.
>      It should not modify the buffer contents.
>    - The previewer must return a non-nil value to indicate preview
>      success.  If the preview fails, it should return nil.
>
> That's it.

Sounds reasonable.

> Subject: [PATCH] org-link: Move inline image display to org-link

The patch does a lot more than merely "moving" things around. Please,
name it accordingly. Maybe something like

   New customizable preview API for arbitrary link types

> --- a/lisp/ol.el
> +++ b/lisp/ol.el
> @@ -82,6 +82,13 @@ (declare-function org-src-source-buffer "org-src" ())
>  (declare-function org-src-source-type "org-src" ())
>  (declare-function org-time-stamp-format "org" (&optional long inactive))
>  (declare-function outline-next-heading "outline" ())
> +(declare-function image-flush "image" (spec &optional frame))
> +(declare-function org-entry-end-position "org" ())
> +(declare-function org-element-contents-begin "org-element" (node))
> +(declare-function org-attach-expand "org-attach" (file))
> +(declare-function org-display-inline-image--width "org" (link))
> +(declare-function org-image--align "org" (link))
> +(declare-function org--create-inline-image "org" (file width))

Some of these declares are now redundant.
  
> +`:preview'
> +
> +  Function to run to generate an in-buffer preview for the link.  It
> +  must accept three arguments:
> +  - an overlay placed from the start to the end of the link.
> +  - the link path, as a string.
> +  - the link element
> +  This function must return a non-nil value to indicate success.

I am wondering whether asynchronicity should be implemented on high
level rather than inside individual link preview functions.
We may, for example, first create the necessary overlays and indicate
that they are "processing..." first, and then call the actual preview
functions asynchronously.

If we leave asynchronous handling to individual previews, they will have
no way to handle queuing large number of link previews, and we may arrive
at the common situation with network processes when they schedule and
finish around the same time, hanging Emacs while it is handling
a bunch of process sentinels.

> +     ;; C-u argument: clear image at point or in entry
> +     ((equal arg '(4))
> +      (if (get-char-property (point) 'org-image-overlay)
> +          ;; clear link preview at point
> +          (when-let ((context (org-element-context))
> +                     ((org-element-type-p context 'link)))

It will be more reliable to clear across overlay boundaries rather than
assuming that the overlay covers exactly one link.

> +BEG and END define the considered part.  They default to the
> +buffer boundaries with possible narrowing."
> +  (interactive "P")
> +  (when (display-graphic-p)

Do we need it here? You check graphics both here and later in the
preview function. We may probably drop the check herein.

> +      (let* ((width (org-display-inline-image--width link))
> +	     (align (org-image--align link))
> +             (image (org--create-inline-image file width)))

I am wondering why you left these functions in org.el. Why not moving
them here?

> +        (when image            ; Add image to overlay
> ...
> +	  (overlay-put ov 'org-image-overlay t)

This is redundant, isn't it?

> +	  (when (boundp 'image-map)

What if not bound? Why not simply (require 'image)?

... and ORG-NEWS entry.

You also need to fixup the manual where it talks about image previews.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v3] Inline image display as part of a new org-link-preview system
  2024-09-01 13:06                                                       ` Ihor Radchenko
@ 2024-09-02 20:13                                                         ` Karthik Chikmagalur
  0 siblings, 0 replies; 40+ messages in thread
From: Karthik Chikmagalur @ 2024-09-02 20:13 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: stardiviner, Org mode

[-- Attachment #1: Type: text/plain, Size: 5521 bytes --]

New patch version attached.  Not all your points were addressed, please
check my comments below.

>> Subject: [PATCH] org-link: Move inline image display to org-link
>
> The patch does a lot more than merely "moving" things around. Please,
> name it accordingly. Maybe something like
>
>    New customizable preview API for arbitrary link types

Renamed commit.

>> +(declare-function org-attach-expand "org-attach" (file))
>
> Some of these declares are now redundant.

Only one declare was redundant (org-attach-expand), fixed.

>> +     ;; C-u argument: clear image at point or in entry
>> +     ((equal arg '(4))
>> +      (if (get-char-property (point) 'org-image-overlay)
>> +          ;; clear link preview at point
>> +          (when-let ((context (org-element-context))
>> +                     ((org-element-type-p context 'link)))
>
> It will be more reliable to clear across overlay boundaries rather than
> assuming that the overlay covers exactly one link.

Fixed.

>> +BEG and END define the considered part.  They default to the
>> +buffer boundaries with possible narrowing."
>> +  (interactive "P")
>> +  (when (display-graphic-p)
>
> Do we need it here? You check graphics both here and later in the
> preview function. We may probably drop the check herein.

I moved the `refresh' clause out of the display-graphic-p check, but I
think it's needed.  Otherwise this line will run once per previewed
image instead of once per call to `org-link-preview':

(when (fboundp 'clear-image-cache) (clear-image-cache))

clearing newly placed previews (within the same run) from the cache.

That said, I have a question about `clear-image-cache' here.  Why does
Org clear the Emacs frame's entire image cache every time
`org-link-preview-region' (or the previous `org-display-inline-images')
is called?  This seems overreaching.  There are many situations even
within Org mode where we want to avoid the extra file access that
clearing the image cache will cause, like in a buffer with hundreds of
LaTeX previews.  Images in unrelated buffers/major-modes are also
affected.

>> +      (let* ((width (org-display-inline-image--width link))
>> +	     (align (org-image--align link))
>> +             (image (org--create-inline-image file width)))
>
> I am wondering why you left these functions in org.el. Why not moving
> them here?

They seemed out of place in ol.el, so my plan was the following:
1. This patch: Implement org-link-preview.
2. Another patch: Move image creation/manipulation/geometry functions
from org into an org-image (or org-image-utils) library.  Require it in
ol.

However, I can move them wherever you want, let me know.

>> +        (when image            ; Add image to overlay
>> ...
>> +	  (overlay-put ov 'org-image-overlay t)
>
> This is redundant, isn't it?

I don't know how create-image can fail.  Suppose a .jpg file exists but
is corrupted or does not have image/jpeg data.  Then create-image
returns nil, as does `org--create-inline-image'.  This check guards
against trying to preview an "image" that's nil.

>> +	  (when (boundp 'image-map)
>
> What if not bound? Why not simply (require 'image)?

Just unmodified old code.  I've require'd image in ol now, let me know
if I should do it differently.

> ... and ORG-NEWS entry.
>
> You also need to fixup the manual where it talks about image previews.

Yes, I will do both at the end, after the changes are final and before
merging.

>> +`:preview'
>> +
>> +  Function to run to generate an in-buffer preview for the link.  It
>> +  must accept three arguments:
>> +  - an overlay placed from the start to the end of the link.
>> +  - the link path, as a string.
>> +  - the link element
>> +  This function must return a non-nil value to indicate success.
>
> I am wondering whether asynchronicity should be implemented on high
> level rather than inside individual link preview functions.
> We may, for example, first create the necessary overlays and indicate
> that they are "processing..." first, and then call the actual preview
> functions asynchronously.
>
> If we leave asynchronous handling to individual previews, they will have
> no way to handle queuing large number of link previews, and we may arrive
> at the common situation with network processes when they schedule and
> finish around the same time, hanging Emacs while it is handling
> a bunch of process sentinels.

I'm not sure how to solve this problem.  Here's what I'm picturing --
note that this doesn't actually avoid the process sentinel pile-up:

The preview provider should return its callback function to Org so Org
can run it at its convenience.

Org runs (funcall #'preview-func ov path link)

preview-func returns either
1. t, if preview is synchronous and successful,
2. nil, if preview is synchronous but failed,
3. A callback-func, if preview is asynchronous.  In this case the
preview-func starts the network request or async job.

Org adds callback-func to the queue of callback-funcs for this run, and
runs them spaced out on a timer or something.  Preview success depends
on whether the callback-func returns t or nil.

Implementing something like this should be easy with org-async, included
in the LaTeX preview patchset.

But the process sentinels will run independent of Org's callback queue.
The callbacks only place the resulting image (or other metadata) on the
overlays.  The bottleneck here is not the display engine, so this
doesn't solve the problem.

Can you give me some more details of what you have in mind?

Karthik

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-org-link-Customizable-preview-API-for-arbitrary-link.patch --]
[-- Type: text/x-patch, Size: 45217 bytes --]

From 7c2df91fb6f41e24af8ee5bee452784e896149f8 Mon Sep 17 00:00:00 2001
From: Karthik Chikmagalur <karthikchikmagalur@gmail.com>
Date: Fri, 23 Aug 2024 15:46:53 -0700
Subject: [PATCH] org-link: Customizable preview API for arbitrary link types

Add a customizable preview API for arbitrary link types.  Make
inline image previews a part of the more universal org-link
preview feature.  Each link type can now be previewed differently
based on a new link parameter.

* lisp/ol.el (org-link-parameters, org-link-preview-overlays,
org-link-preview--get-overlays, org-link-preview--remove-overlay,
org-link-previeworg-link-preview-region, org-link-preview-clear,
org-link-preview-file): Add new commands `org-link-preview',
`org-link-preview-region' and `org-link-preview-clear' for
creating link previews for any kind of link.  Add new org-link
parameter `:preview' for specifying how a link type should be
previewed.  File links and attachments are previewed using inline
image previews as before.

* testing/lisp/test-org-fold.el: Use `org-link-preview'.

* lisp/org.el (org-toggle-inline-images,
org-toggle-inline-images-command, org-display-inline-images,
org--inline-image-overlays, org-inline-image-overlays,
org-redisplay-inline-images, org-image-align,
org-display-inline-remove-overlay, org-remove-inline-images):
Obsolete and move `org-toggle-inline-images',
`org-display-inline-images' and `org-redisplay-inline-images' to
org-compat.  These are obsoleted by `org-link-preview' and
`org-link-preview-region'.  Remove
`org-toggle-inline-images-command'.  Move the other internal
functions to org-link.

* lisp/org-plot.el (org-plot/redisplay-img-in-buffer): Modify to
use `org-link-preview'.

* lisp/org-keys.el: Bind `C-c C-x C-v' to new command
`org-link-preview', which has the same prefix arg behaviors as
`org-latex-preview'.  In addition to these, it supports numeric
prefix args 1 and 11 to preview links with descriptions at
point/region (with 1) and across the buffer (with 11).

* lisp/org-cycle.el (org-cycle-display-inline-images): Use
`org-link-preview'.

* lisp/org-compat.el (org-display-inline-remove-overlay,
org--inline-image-overlays, org-remove-inline-images,
org-inline-image-overlays, org-display-inline-images,
org-toggle-inline-images):

* lisp/org-attach.el (org-attach-preview-file): Add new `:preview'
link parameter for links of type "attachment", set to the new
function `org-attach-preview-file'.
---
 lisp/ol.el                    | 277 ++++++++++++++++++++++++++++++++-
 lisp/org-attach.el            |  10 +-
 lisp/org-compat.el            | 189 +++++++++++++++++++++++
 lisp/org-cycle.el             |  10 +-
 lisp/org-keys.el              |   4 +-
 lisp/org-plot.el              |   2 +-
 lisp/org.el                   | 283 +---------------------------------
 testing/lisp/test-org-fold.el |   4 +-
 8 files changed, 486 insertions(+), 293 deletions(-)

diff --git a/lisp/ol.el b/lisp/ol.el
index 52ea62d69..f06fe5a34 100644
--- a/lisp/ol.el
+++ b/lisp/ol.el
@@ -33,6 +33,7 @@ (org-assert-version)
 (require 'org-compat)
 (require 'org-macs)
 (require 'org-fold)
+(require 'image)
 
 (defvar clean-buffer-list-kill-buffer-names)
 (defvar org-agenda-buffer-name)
@@ -82,6 +83,12 @@ (declare-function org-src-source-buffer "org-src" ())
 (declare-function org-src-source-type "org-src" ())
 (declare-function org-time-stamp-format "org" (&optional long inactive))
 (declare-function outline-next-heading "outline" ())
+(declare-function image-flush "image" (spec &optional frame))
+(declare-function org-entry-end-position "org" ())
+(declare-function org-element-contents-begin "org-element" (node))
+(declare-function org-display-inline-image--width "org" (link))
+(declare-function org-image--align "org" (link))
+(declare-function org--create-inline-image "org" (file width))
 
 \f
 ;;; Customization
@@ -171,6 +178,16 @@ (defcustom org-link-parameters nil
 
   The default face is `org-link'.
 
+`:preview'
+
+  Function to run to generate an in-buffer preview for the link.  It
+  must accept three arguments:
+  - an overlay placed from the start to the end of the link.
+  - the link path, as a string.
+  - the link element
+
+  This function must return a non-nil value to indicate success.
+
 `:help-echo'
 
   String or function used as a value for the `help-echo' text
@@ -649,6 +666,13 @@ (defvar org-link--insert-history nil
 (defvar org-link--search-failed nil
   "Non-nil when last link search failed.")
 
+(defvar-local org-link-preview-overlays nil)
+;; Preserve when switching modes or when restarting Org.
+;; If we clear the overlay list and later enable Or mode, the existing
+;; image overlays will never be cleared by `org-link-preview'
+;; and `org-link-preview-clear'.
+(put 'org-link-preview-overlays 'permanent-local t)
+
 \f
 ;;; Internal Functions
 
@@ -881,6 +905,30 @@ (defun org-link--file-link-to-here ()
          (setq desc search-desc))))
     (cons link desc)))
 
+(defun org-link-preview--get-overlays (&optional beg end)
+  "Return link preview overlays between BEG and END."
+  (let* ((beg (or beg (point-min)))
+         (end (or end (point-max)))
+         (overlays (overlays-in beg end))
+         result)
+    (dolist (ov overlays result)
+      (when (memq ov org-link-preview-overlays)
+        (push ov result)))))
+
+(defun org-link-preview--remove-overlay (ov after _beg _end &optional _len)
+  "Remove link-preview overlay OV if a corresponding region is modified.
+
+AFTER is true when this function is called post-change."
+  (when (and ov after)
+    (setq org-link-preview-overlays (delete ov org-link-preview-overlays))
+    ;; Clear image from cache to avoid image not updating upon
+    ;; changing on disk.  See Emacs bug#59902.
+    (when-let* (((overlay-get ov 'org-image-overlay))
+                (disp (overlay-get ov 'display))
+                ((imagep disp)))
+      (image-flush disp))
+    (delete-overlay ov)))
+
 \f
 ;;; Public API
 
@@ -1573,6 +1621,192 @@ (defun org-link-add-angle-brackets (s)
   (unless (equal (substring s -1) ">") (setq s (concat s ">")))
   s)
 
+;;;###autoload
+(defun org-link-preview (&optional arg beg end)
+  "Toggle display of link previews in the buffer.
+
+When region BEG..END is active, preview links in the
+region.
+
+When point is at a link, display a preview for that link only.
+Otherwise, display previews for links in current entry.
+
+With numeric prefix ARG 1, preview links with description as
+well.
+
+With prefix ARG `\\[universal-argument]', clear link previews at
+point or in the current entry.
+
+With prefix ARG `\\[universal-argument] \\[universal-argument]',
+ display link previews in the accessible portion of the
+ buffer.  With numeric prefix ARG 11, do the same, but include
+ links with descriptions.
+
+With prefix ARG `\\[universal-argument] \\[universal-argument] \\[universal-argument]',
+hide all link previews in the accessible portion of the buffer.
+
+This command is designed for interactive use.  From Elisp, you can
+also use `org-link-preview-region'."
+  (interactive (cons current-prefix-arg
+                     (when (use-region-p)
+                       (list (region-beginning) (region-end)))))
+  (let* ((include-linked
+          (cond
+           ((member arg '(nil (4) (16)) ) nil)
+           ((member arg '(1 11)) 'include-linked)
+           (t 'include-linked)))
+         (interactive? (called-interactively-p 'any))
+         (toggle-previews
+          (lambda (&optional beg end scope remove)
+            (let* ((beg (or beg (point-min)))
+                   (end (or end (point-max)))
+                   (old (org-link-preview--get-overlays beg end))
+                   (scope (or scope (format "%d:%d" beg end))))
+              (if remove
+                  (progn
+                    (org-link-preview-clear beg end)
+                    (when interactive?
+                      (message
+                       "[%s] Inline link previews turned off (removed %d images)"
+                       scope (length old))))
+	        (org-link-preview-region include-linked t beg end)
+                (when interactive?
+                  (let ((new (org-link-preview--get-overlays beg end)))
+                    (message
+                     (if new
+		         (format "[%s] %d images displayed inline %s"
+			         scope (length new)
+                                 (if include-linked "(including images with description)"
+                                   ""))
+		       (format "[%s] No images to display inline" scope))))))))))
+    (cond
+     ;; Region selected :: display previews in region.
+     ((and beg end)
+      (funcall toggle-previews beg end "region"
+               (and (equal arg '(4)) 'remove)))
+     ;; C-u argument: clear image at point or in entry
+     ((equal arg '(4))
+      (if-let ((ov (cdr (get-char-property-and-overlay
+                         (point) 'org-image-overlay))))
+          ;; clear link preview at point
+          (funcall toggle-previews
+                   (overlay-start ov) (overlay-end ov)
+                   "preview at point" 'remove)
+        ;; Clear link previews in entry
+        (funcall toggle-previews
+                 (if (org-before-first-heading-p) (point-min)
+                   (save-excursion
+                     (org-with-limited-levels (org-back-to-heading t) (point))))
+                 (org-with-limited-levels (org-entry-end-position))
+                 "current section" 'remove)))
+     ;; C-u C-u or C-11 argument :: display images in the whole buffer.
+     ((member arg '(11 (16))) (funcall toggle-previews nil nil "buffer"))
+     ;; C-u C-u C-u argument :: unconditionally hide images in the buffer.
+     ((equal arg '(64)) (funcall toggle-previews nil nil "buffer" 'remove))
+     ;; Argument nil or 1, no region selected :: display images in
+     ;; current section or image link at point.
+     ((and (member arg '(nil 1)) (null beg) (null end))
+      (let ((context (org-element-context)))
+        ;; toggle display of inline image link at point.
+        (if (org-element-type-p context 'link)
+            (let* ((ov (cdr-safe (get-char-property-and-overlay
+                                  (point) 'org-image-overlay)))
+                   (remove? (and ov (memq ov org-link-preview-overlays)
+                                 'remove)))
+              (funcall toggle-previews
+                       (org-element-begin context)
+                       (org-element-end context)
+                       "image at point" remove?))
+          (let ((beg (if (org-before-first-heading-p) (point-min)
+	               (save-excursion
+	                 (org-with-limited-levels (org-back-to-heading t) (point)))))
+                (end (org-with-limited-levels (org-entry-end-position))))
+            (funcall toggle-previews beg end "current section")))))
+     ;; Any other non-nil argument.
+     ((not (null arg)) (funcall toggle-previews beg end "region")))))
+
+(defun org-link-preview-region (&optional include-linked refresh beg end)
+  "Display link previews.
+
+A previewable link type is one that has a `:preview' link
+parameter, see `org-link-parameters'.
+
+By default, a file link or attachment is previewable if it
+follows either of these conventions:
+
+  1. Its path is a file with an extension matching return value
+     from `image-file-name-regexp' and it has no contents.
+
+  2. Its description consists in a single link of the previous
+     type.  In this case, that link must be a well-formed plain
+     or angle link, i.e., it must have an explicit \"file\" or
+     \"attachment\" type.
+
+File links are equipped with the keymap `image-map'.
+
+When optional argument INCLUDE-LINKED is non-nil, links with a
+text description part will also be inlined.  This can be nice for
+a quick look at those images, but it does not reflect what
+exported files will look like.
+
+When optional argument REFRESH is non-nil, refresh existing
+images between BEG and END.  This will create new image displays
+only if necessary.
+
+BEG and END define the considered part.  They default to the
+buffer boundaries with possible narrowing."
+  (interactive "P")
+  (when refresh (org-link-preview-clear beg end))
+  (when (display-graphic-p)
+    (when (fboundp 'clear-image-cache) (clear-image-cache)))
+  (org-with-point-at (or beg (point-min))
+    (let ((case-fold-search t))
+      (while (re-search-forward org-link-any-re end t)
+        (when-let* ((link (org-element-lineage
+                           (save-match-data (org-element-context))
+                           'link t))
+                    (linktype (org-element-property :type link))
+                    (preview-func (org-link-get-parameter linktype :preview))
+                    (path (and (or include-linked
+                                   (not (org-element-contents-begin link)))
+                               (org-element-property :path link))))
+          ;; Create an overlay to hold the preview
+          (let ((ov (make-overlay
+                     (org-element-begin link)
+                     (progn
+		       (goto-char
+			(org-element-end link))
+		       (unless (eolp) (skip-chars-backward " \t"))
+		       (point)))))
+            ;; TODO: Change this overlay property to `org-link-preview' everywhere.
+            (overlay-put ov 'org-image-overlay t)
+            (overlay-put ov 'modification-hooks
+                         (list 'org-link-preview--remove-overlay))
+            ;; call preview function for link type
+            (if (funcall preview-func ov path link)
+              (when (overlay-buffer ov)
+                (push ov org-link-preview-overlays))
+              ;; Preview was unsuccessful, delete overlay
+              (delete-overlay ov))))))))
+
+(defun org-link-preview-clear (&optional beg end)
+  "Clear link previews in region BEG to END."
+  (interactive (and (use-region-p) (list (region-beginning) (region-end))))
+  (let* ((beg (or beg (point-min)))
+         (end (or end (point-max)))
+         (overlays (overlays-in beg end)))
+    (dolist (ov overlays)
+      (when (memq ov org-link-preview-overlays)
+        (when-let ((image (overlay-get ov 'display))
+                   ((imagep image)))
+          (image-flush image))
+        (setq org-link-preview-overlays (delq ov org-link-preview-overlays))
+        (delete-overlay ov)))
+    ;; Clear removed overlays.
+    (dolist (ov org-link-preview-overlays)
+      (unless (overlay-buffer ov)
+        (setq org-link-preview-overlays (delq ov org-link-preview-overlays))))))
+
 \f
 ;;; Built-in link types
 
@@ -1595,7 +1829,48 @@ (defun org-link--open-elisp (path _)
 (org-link-set-parameters "elisp" :follow #'org-link--open-elisp)
 
 ;;;; "file" link type
-(org-link-set-parameters "file" :complete #'org-link-complete-file)
+(org-link-set-parameters "file"
+                         :complete #'org-link-complete-file
+                         :preview #'org-link-preview-file)
+
+(defun org-link-preview-file (ov path link)
+  "Display image file PATH in overlay OV for LINK.
+
+LINK is the Org element being previewed.
+
+Equip each image with the keymap `image-map'.
+
+This is intended to be used as the `:preview' link property of
+file links, see `org-link-parameters'."
+  (if (not (display-graphic-p))
+      (prog1 nil
+        (message "Your Emacs does not support displaying images!"))
+    (when-let* ((file-full (expand-file-name path))
+                (file (substitute-in-file-name file-full))
+                ((string-match-p (image-file-name-regexp) file))
+                ((file-exists-p file)))
+      (let* ((width (org-display-inline-image--width link))
+	     (align (org-image--align link))
+             (image (org--create-inline-image file width)))
+        (when image            ; Add image to overlay
+	  ;; See bug#59902.  We cannot rely
+          ;; on Emacs to update image if the file
+          ;; has changed.
+          (image-flush image)
+	  (overlay-put ov 'display image)
+	  (overlay-put ov 'face 'default)
+	  (overlay-put ov 'org-image-overlay t)
+	  (overlay-put ov 'keymap image-map)
+          (when align
+            (overlay-put
+             ov 'before-string
+             (propertize
+              " " 'face 'default
+              'display
+              (pcase align
+                ("center" `(space :align-to (- center (0.5 . ,image))))
+                ("right"  `(space :align-to (- right ,image)))))))
+          t)))))
 
 ;;;; "help" link type
 (defun org-link--open-help (path _)
diff --git a/lisp/org-attach.el b/lisp/org-attach.el
index 7a03d170e..4b0887fcd 100644
--- a/lisp/org-attach.el
+++ b/lisp/org-attach.el
@@ -797,9 +797,17 @@ (defun org-attach-follow (file arg)
 See `org-open-file' for details about ARG."
   (org-link-open-as-file (org-attach-expand file) arg))
 
+(defun org-attach-preview-file (ov path link)
+  "Preview attachment with PATH in overlay OV.
+
+LINK is the Org link element being previewed."
+  (org-link-preview-file
+   ov (org-attach-expand path) link))
+
 (org-link-set-parameters "attachment"
 			 :follow #'org-attach-follow
-                         :complete #'org-attach-complete-link)
+                         :complete #'org-attach-complete-link
+                         :preview #'org-attach-preview-file)
 
 (defun org-attach-complete-link ()
   "Advise the user with the available files in the attachment directory."
diff --git a/lisp/org-compat.el b/lisp/org-compat.el
index d843216f3..242b46a86 100644
--- a/lisp/org-compat.el
+++ b/lisp/org-compat.el
@@ -783,6 +783,195 @@ (defun org-add-link-type (type &optional follow export)
 
 (make-obsolete 'org-add-link-type "use `org-link-set-parameters' instead." "9.0")
 
+(declare-function org-link-preview--remove-overlay "ol")
+(declare-function org-link-preview--get-overlays "ol")
+(declare-function org-link-preview-clear "ol")
+(declare-function org-link-preview--remove-overlay "ol")
+
+(define-obsolete-function-alias 'org-display-inline-remove-overlay
+  'org-link-preview--remove-overlay "9.8")
+(define-obsolete-function-alias 'org--inline-image-overlays
+  'org-link-preview--get-overlays "9.8")
+(define-obsolete-function-alias 'org-remove-inline-images
+  'org-link-preview-clear "9.8")
+(define-obsolete-variable-alias 'org-inline-image-overlays
+  'org-link-preview-overlays "9.8")
+(defvar org-link-preview-overlays)
+(defvar org-link-abbrev-alist-local)
+(defvar org-link-abbrev-alist)
+(defvar org-link-angle-re)
+(defvar org-link-plain-re)
+(declare-function org-attach-expand "org-attach")
+(declare-function org-display-inline-image--width "org")
+(declare-function org-image--align "org")
+(declare-function org--create-inline-image "org")
+
+(make-obsolete 'org-display-inline-images
+               'org-link-preview-region "9.8")
+;; FIXME: Unused; obsoleted; to be removed
+(defun org-display-inline-images (&optional include-linked refresh beg end)
+  "Display inline images.
+
+An inline image is a link which follows either of these
+conventions:
+
+  1. Its path is a file with an extension matching return value
+     from `image-file-name-regexp' and it has no contents.
+
+  2. Its description consists in a single link of the previous
+     type.  In this case, that link must be a well-formed plain
+     or angle link, i.e., it must have an explicit \"file\" or
+     \"attachment\" type.
+
+Equip each image with the key-map `image-map'.
+
+When optional argument INCLUDE-LINKED is non-nil, also links with
+a text description part will be inlined.  This can be nice for
+a quick look at those images, but it does not reflect what
+exported files will look like.
+
+When optional argument REFRESH is non-nil, refresh existing
+images between BEG and END.  This will create new image displays
+only if necessary.
+
+BEG and END define the considered part.  They default to the
+buffer boundaries with possible narrowing."
+  (interactive "P")
+  (when (display-graphic-p)
+    (when refresh
+      (org-link-preview-clear beg end)
+      (when (fboundp 'clear-image-cache) (clear-image-cache)))
+    (let ((end (or end (point-max))))
+      (org-with-point-at (or beg (point-min))
+	(let* ((case-fold-search t)
+	       (file-extension-re (image-file-name-regexp))
+	       (link-abbrevs (mapcar #'car
+				     (append org-link-abbrev-alist-local
+					     org-link-abbrev-alist)))
+	       ;; Check absolute, relative file names and explicit
+	       ;; "file:" links.  Also check link abbreviations since
+	       ;; some might expand to "file" links.
+	       (file-types-re
+		(format "\\[\\[\\(?:file%s:\\|attachment:\\|[./~]\\)\\|\\]\\[\\(<?\\(?:file\\|attachment\\):\\)"
+			(if (not link-abbrevs) ""
+			  (concat "\\|" (regexp-opt link-abbrevs))))))
+	  (while (re-search-forward file-types-re end t)
+	    (let* ((link (org-element-lineage
+			  (save-match-data (org-element-context))
+			  'link t))
+                   (linktype (org-element-property :type link))
+		   (inner-start (match-beginning 1))
+		   (path
+		    (cond
+		     ;; No link at point; no inline image.
+		     ((not link) nil)
+		     ;; File link without a description.  Also handle
+		     ;; INCLUDE-LINKED here since it should have
+		     ;; precedence over the next case.  I.e., if link
+		     ;; contains filenames in both the path and the
+		     ;; description, prioritize the path only when
+		     ;; INCLUDE-LINKED is non-nil.
+		     ((or (not (org-element-contents-begin link))
+			  include-linked)
+		      (and (or (equal "file" linktype)
+                               (equal "attachment" linktype))
+			   (org-element-property :path link)))
+		     ;; Link with a description.  Check if description
+		     ;; is a filename.  Even if Org doesn't have syntax
+		     ;; for those -- clickable image -- constructs, fake
+		     ;; them, as in `org-export-insert-image-links'.
+		     ((not inner-start) nil)
+		     (t
+		      (org-with-point-at inner-start
+			(and (looking-at
+			      (if (char-equal ?< (char-after inner-start))
+				  org-link-angle-re
+				org-link-plain-re))
+			     ;; File name must fill the whole
+			     ;; description.
+			     (= (org-element-contents-end link)
+				(match-end 0))
+			     (progn
+                               (setq linktype (match-string 1))
+                               (match-string 2))))))))
+	      (when (and path (string-match-p file-extension-re path))
+		(let ((file (if (equal "attachment" linktype)
+				(progn
+                                  (require 'org-attach)
+				  (ignore-errors (org-attach-expand path)))
+                              (expand-file-name path))))
+                  ;; Expand environment variables.
+                  (when file (setq file (substitute-in-file-name file)))
+		  (when (and file (file-exists-p file))
+		    (let ((width (org-display-inline-image--width link))
+			  (align (org-image--align link))
+                          (old (get-char-property-and-overlay
+				(org-element-begin link)
+				'org-image-overlay)))
+		      (if (and (car-safe old) refresh)
+                          (image-flush (overlay-get (cdr old) 'display))
+			(let ((image (org--create-inline-image file width)))
+			  (when image
+			    (let ((ov (make-overlay
+				       (org-element-begin link)
+				       (progn
+					 (goto-char
+					  (org-element-end link))
+					 (unless (eolp) (skip-chars-backward " \t"))
+					 (point)))))
+                              ;; See bug#59902.  We cannot rely
+                              ;; on Emacs to update image if the file
+                              ;; has changed.
+                              (image-flush image)
+			      (overlay-put ov 'display image)
+			      (overlay-put ov 'face 'default)
+			      (overlay-put ov 'org-image-overlay t)
+			      (overlay-put
+			       ov 'modification-hooks
+			       (list 'org-link-preview--remove-overlay))
+			      (when (boundp 'image-map)
+				(overlay-put ov 'keymap image-map))
+                              (when align
+                                (overlay-put
+                                 ov 'before-string
+                                 (propertize
+                                  " " 'face 'default
+                                  'display
+                                  (pcase align
+                                    ("center" `(space :align-to (- center (0.5 . ,image))))
+                                    ("right"  `(space :align-to (- right ,image)))))))
+			      (push ov org-inline-image-overlays))))))))))))))))
+
+(make-obsolete 'org-toggle-inline-images
+               'org-link-preview "9.8")
+;; FIXME: Unused; obsoleted; to be removed
+(defun org-toggle-inline-images (&optional include-linked beg end)
+  "Toggle the display of inline images.
+INCLUDE-LINKED is passed to `org-display-inline-images'."
+  (interactive "P")
+  (if (org-link-preview--get-overlays beg end)
+      (progn
+        (org-link-preview-clear beg end)
+        (when (called-interactively-p 'interactive)
+	  (message "Inline image display turned off")))
+    (org-display-inline-images include-linked nil beg end)
+    (when (called-interactively-p 'interactive)
+      (let ((new (org-link-preview--get-overlays beg end)))
+        (message (if new
+		     (format "%d images displayed inline"
+			     (length new))
+		   "No images to display inline"))))))
+
+(make-obsolete 'org-redisplay-inline-images
+               'org-link-preview "9.8")
+;; FIXME: Unused; obsoleted; to be removed
+(defun org-redisplay-inline-images ()
+  "Assure display of inline images and refresh them."
+  (interactive)
+  (org-toggle-inline-images)
+  (unless org-link-preview-overlays
+    (org-toggle-inline-images)))
+
 ;;;; Functions unused in Org core.
 (defun org-table-recognize-table.el ()
   "If there is a table.el table nearby, recognize it and move into it."
diff --git a/lisp/org-cycle.el b/lisp/org-cycle.el
index 8a39bdb8c..1a1c916bd 100644
--- a/lisp/org-cycle.el
+++ b/lisp/org-cycle.el
@@ -40,14 +40,14 @@ (declare-function org-element-property "org-element-ast" (property node))
 (declare-function org-element-post-affiliated "org-element" (node))
 (declare-function org-element-lineage "org-element-ast" (datum &optional types with-self))
 (declare-function org-element-at-point "org-element" (&optional pom cached-only))
-(declare-function org-display-inline-images "org" (&optional include-linked refresh beg end))
+(declare-function org-link-preview-region "ol" (&optional include-linked refresh beg end))
 (declare-function org-get-tags "org" (&optional pos local fontify))
 (declare-function org-subtree-end-visible-p "org" ())
 (declare-function org-narrow-to-subtree "org" (&optional element))
 (declare-function org-next-visible-heading "org" (arg))
 (declare-function org-at-property-p "org" ())
 (declare-function org-re-property "org" (property &optional literal allow-null value))
-(declare-function org-remove-inline-images "org" (&optional beg end))
+(declare-function org-link-preview-clear "ol" (&optional beg end))
 (declare-function org-item-beginning-re "org" ())
 (declare-function org-at-heading-p "org" (&optional invisible-not-ok))
 (declare-function org-at-item-p "org" ())
@@ -817,19 +817,19 @@ (defun org-cycle-display-inline-images (state)
         ;; If has nested headlines, beg,end only from parent headline
         ;; to first child headline which reference to upper
         ;; let-binding `org-next-visible-heading'.
-        (org-display-inline-images
+        (org-link-preview-region
          nil nil
          (point-min) (progn (org-next-visible-heading 1) (point)))))
       ('subtree
        (org-with-wide-buffer
         (org-narrow-to-subtree)
         ;; If has nested headlines, also inline display images under all sub-headlines.
-        (org-display-inline-images nil nil (point-min) (point-max))))
+        (org-link-preview-region nil nil (point-min) (point-max))))
       ('folded
        (org-with-wide-buffer
         (org-narrow-to-subtree)
         (if (numberp (point-max))
-            (org-remove-inline-images (point-min) (point-max))
+            (org-link-preview-clear (point-min) (point-max))
           (ignore)))))))
 
 (provide 'org-cycle)
diff --git a/lisp/org-keys.el b/lisp/org-keys.el
index 1daedaae8..77cbe5c0f 100644
--- a/lisp/org-keys.el
+++ b/lisp/org-keys.el
@@ -218,7 +218,7 @@ (declare-function org-toggle-checkbox "org" (&optional toggle-presence))
 (declare-function org-toggle-radio-button "org" (&optional arg))
 (declare-function org-toggle-comment "org" ())
 (declare-function org-toggle-fixed-width "org" ())
-(declare-function org-toggle-inline-images-command "org" (&optional arg beg end))
+(declare-function org-link-preview "ol" (&optional arg beg end))
 (declare-function org-latex-preview "org" (&optional arg))
 (declare-function org-toggle-narrow-to-subtree "org" ())
 (declare-function org-toggle-ordered-property "org" ())
@@ -618,7 +618,7 @@ (org-defkey org-mode-map (kbd "C-c C-x C-d") #'org-clock-display)
 (org-defkey org-mode-map (kbd "C-c C-x x") #'org-dynamic-block-insert-dblock)
 (org-defkey org-mode-map (kbd "C-c C-x C-u") #'org-dblock-update)
 (org-defkey org-mode-map (kbd "C-c C-x C-l") #'org-latex-preview)
-(org-defkey org-mode-map (kbd "C-c C-x C-v") #'org-toggle-inline-images-command)
+(org-defkey org-mode-map (kbd "C-c C-x C-v") #'org-link-preview)
 (org-defkey org-mode-map (kbd "C-c C-x C-M-v") #'org-redisplay-inline-images)
 (org-defkey org-mode-map (kbd "C-c C-x \\") #'org-toggle-pretty-entities)
 (org-defkey org-mode-map (kbd "C-c C-x C-b") #'org-toggle-checkbox)
diff --git a/lisp/org-plot.el b/lisp/org-plot.el
index b045344f0..836cfaffc 100644
--- a/lisp/org-plot.el
+++ b/lisp/org-plot.el
@@ -633,7 +633,7 @@ (defun org-plot/gnuplot-script (table data-file num-cols params &optional prefac
 
 (defun org-plot/redisplay-img-in-buffer (img-file)
   "Find any overlays for IMG-FILE in the current Org buffer, and refresh them."
-  (dolist (img-overlay org-inline-image-overlays)
+  (dolist (img-overlay org-link-preview-overlays)
     (when (string= img-file (plist-get (cdr (overlay-get img-overlay 'display)) :file))
       (when (and (file-exists-p img-file)
                  (fboundp 'image-flush))
diff --git a/lisp/org.el b/lisp/org.el
index d5c1dcb35..091a09344 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -5079,7 +5079,7 @@ (define-derived-mode org-mode outline-mode "Org"
     ;; modifications to make cache updates work reliably.
     (org-unmodified
      (when org-startup-with-beamer-mode (org-beamer-mode))
-     (when org-startup-with-inline-images (org-display-inline-images))
+     (when org-startup-with-inline-images (org-link-preview '(16)))
      (when org-startup-with-latex-preview (org-latex-preview '(16)))
      (unless org-inhibit-startup-visibility-stuff (org-cycle-set-startup-visibility))
      (when org-startup-truncated (setq truncate-lines t))
@@ -16651,126 +16651,6 @@ (defun org-normalize-color (value)
 \f
 ;; Image display
 
-(defvar-local org-inline-image-overlays nil)
-;; Preserve when switching modes or when restarting Org.
-;; If we clear the overlay list and later enable Or mode, the existing
-;; image overlays will never be cleared by `org-toggle-inline-images'
-;; and `org-toggle-inline-images-command'.
-(put 'org-inline-image-overlays 'permanent-local t)
-
-(defun org--inline-image-overlays (&optional beg end)
-  "Return image overlays between BEG and END."
-  (let* ((beg (or beg (point-min)))
-         (end (or end (point-max)))
-         (overlays (overlays-in beg end))
-         result)
-    (dolist (ov overlays result)
-      (when (memq ov org-inline-image-overlays)
-        (push ov result)))))
-
-(defun org-toggle-inline-images-command (&optional arg beg end)
-  "Toggle display of inline images without description at point.
-
-When point is at an image link, toggle displaying that image.
-Otherwise, toggle displaying images in current entry.
-
-When region BEG..END is active, toggle displaying images in the
-region.
-
-With numeric prefix ARG 1, display images with description as well.
-
-With prefix ARG `\\[universal-argument]', toggle displaying images in
-the accessible portion of the buffer.  With numeric prefix ARG 11, do
-the same, but include images with description.
-
-With prefix ARG `\\[universal-argument] \\[universal-argument]', hide
-all the images in accessible portion of the buffer.
-
-This command is designed for interactive use.  From Elisp, you can
-also use `org-toggle-inline-images'."
-  (interactive (cons current-prefix-arg
-                     (when (use-region-p)
-                       (list (region-beginning) (region-end)))))
-  (let* ((include-linked
-          (cond
-           ((member arg '(nil (4) (16)) ) nil)
-           ((member arg '(1 11)) 'include-linked)
-           (t 'include-linked)))
-         (interactive? (called-interactively-p 'any))
-         (toggle-images
-          (lambda (&optional beg end scope force-remove)
-            (let* ((beg (or beg (point-min)))
-                   (end (or end (point-max)))
-                   (old (org--inline-image-overlays beg end))
-                   (scope (or scope (format "%d:%d" beg end))))
-              (if (or old force-remove)
-                  (progn
-                    (org-remove-inline-images beg end)
-                    (when interactive?
-                      (message
-                       "[%s] Inline image display turned off (removed %d images)"
-                       scope (length old))))
-	        (org-display-inline-images include-linked t beg end)
-                (when interactive?
-                  (let ((new (org--inline-image-overlays beg end)))
-                    (message
-                     (if new
-		         (format "[%s] %d images displayed inline %s"
-			         scope (length new)
-                                 (if include-linked "(including images with description)"
-                                   ""))
-		       (format "[%s] No images to display inline" scope))))))))))
-    (cond
-     ((not (display-graphic-p))
-      (message "Your Emacs does not support displaying images!"))
-     ;; Region selected :: toggle images in region.
-     ((and beg end) (funcall toggle-images beg end "region"))
-     ;; C-u or C-11 argument :: toggle images in the whole buffer.
-     ((member arg '(11 (4))) (funcall toggle-images nil nil "buffer"))
-     ;; C-u C-u argument :: unconditionally hide images in the buffer.
-     ((equal arg '(16)) (funcall toggle-images nil nil "buffer" 'remove))
-     ;; Argument nil or 1, no region selected :: toggle (display or hide
-     ;; dwim) images in current section or image link at point.
-     ((and (member arg '(nil 1)) (null beg) (null end))
-      (let ((context (org-element-context)))
-        ;; toggle display of inline image link at point.
-        (if (org-element-type-p context 'link)
-            (funcall toggle-images
-                     (org-element-begin context)
-                     (org-element-end context)
-                     "image at point")
-          (let ((beg (if (org-before-first-heading-p) (point-min)
-	               (save-excursion
-	                 (org-with-limited-levels (org-back-to-heading t) (point)))))
-                (end (org-with-limited-levels (org-entry-end-position))))
-            (funcall toggle-images beg end "current section")))))
-     ;; Any other non-nil argument.
-     ((not (null arg)) (funcall toggle-images beg end "region")))))
-
-(defun org-toggle-inline-images (&optional include-linked beg end)
-  "Toggle the display of inline images.
-INCLUDE-LINKED is passed to `org-display-inline-images'."
-  (interactive "P")
-  (if (org--inline-image-overlays beg end)
-      (progn
-        (org-remove-inline-images beg end)
-        (when (called-interactively-p 'interactive)
-	  (message "Inline image display turned off")))
-    (org-display-inline-images include-linked nil beg end)
-    (when (called-interactively-p 'interactive)
-      (let ((new (org--inline-image-overlays beg end)))
-        (message (if new
-		     (format "%d images displayed inline"
-			     (length new))
-		   "No images to display inline"))))))
-
-(defun org-redisplay-inline-images ()
-  "Assure display of inline images and refresh them."
-  (interactive)
-  (org-toggle-inline-images)
-  (unless org-inline-image-overlays
-    (org-toggle-inline-images)))
-
 ;; For without-x builds.
 (declare-function image-flush "image" (spec &optional frame))
 
@@ -16793,7 +16673,7 @@ (defcustom org-display-remote-inline-images 'skip
   :safe #'symbolp)
 
 (defcustom org-image-align 'left
-  "How to align images previewed using `org-display-inline-images'.
+  "How to align images previewed using `org-link-preview-region'.
 
 Only stand-alone image links are affected by this setting.  These
 are links without surrounding text.
@@ -16850,139 +16730,6 @@ (defun org--create-inline-image (file width)
                                 org-image-max-width)))
                     :scale 1))))
 
-(defun org-display-inline-images (&optional include-linked refresh beg end)
-  "Display inline images.
-
-An inline image is a link which follows either of these
-conventions:
-
-  1. Its path is a file with an extension matching return value
-     from `image-file-name-regexp' and it has no contents.
-
-  2. Its description consists in a single link of the previous
-     type.  In this case, that link must be a well-formed plain
-     or angle link, i.e., it must have an explicit \"file\" or
-     \"attachment\" type.
-
-Equip each image with the key-map `image-map'.
-
-When optional argument INCLUDE-LINKED is non-nil, also links with
-a text description part will be inlined.  This can be nice for
-a quick look at those images, but it does not reflect what
-exported files will look like.
-
-When optional argument REFRESH is non-nil, refresh existing
-images between BEG and END.  This will create new image displays
-only if necessary.
-
-BEG and END define the considered part.  They default to the
-buffer boundaries with possible narrowing."
-  (interactive "P")
-  (when (display-graphic-p)
-    (when refresh
-      (org-remove-inline-images beg end)
-      (when (fboundp 'clear-image-cache) (clear-image-cache)))
-    (let ((end (or end (point-max))))
-      (org-with-point-at (or beg (point-min))
-	(let* ((case-fold-search t)
-	       (file-extension-re (image-file-name-regexp))
-	       (link-abbrevs (mapcar #'car
-				     (append org-link-abbrev-alist-local
-					     org-link-abbrev-alist)))
-	       ;; Check absolute, relative file names and explicit
-	       ;; "file:" links.  Also check link abbreviations since
-	       ;; some might expand to "file" links.
-	       (file-types-re
-		(format "\\[\\[\\(?:file%s:\\|attachment:\\|[./~]\\)\\|\\]\\[\\(<?\\(?:file\\|attachment\\):\\)"
-			(if (not link-abbrevs) ""
-			  (concat "\\|" (regexp-opt link-abbrevs))))))
-	  (while (re-search-forward file-types-re end t)
-	    (let* ((link (org-element-lineage
-			  (save-match-data (org-element-context))
-			  'link t))
-                   (linktype (org-element-property :type link))
-		   (inner-start (match-beginning 1))
-		   (path
-		    (cond
-		     ;; No link at point; no inline image.
-		     ((not link) nil)
-		     ;; File link without a description.  Also handle
-		     ;; INCLUDE-LINKED here since it should have
-		     ;; precedence over the next case.  I.e., if link
-		     ;; contains filenames in both the path and the
-		     ;; description, prioritize the path only when
-		     ;; INCLUDE-LINKED is non-nil.
-		     ((or (not (org-element-contents-begin link))
-			  include-linked)
-		      (and (or (equal "file" linktype)
-                               (equal "attachment" linktype))
-			   (org-element-property :path link)))
-		     ;; Link with a description.  Check if description
-		     ;; is a filename.  Even if Org doesn't have syntax
-		     ;; for those -- clickable image -- constructs, fake
-		     ;; them, as in `org-export-insert-image-links'.
-		     ((not inner-start) nil)
-		     (t
-		      (org-with-point-at inner-start
-			(and (looking-at
-			      (if (char-equal ?< (char-after inner-start))
-				  org-link-angle-re
-				org-link-plain-re))
-			     ;; File name must fill the whole
-			     ;; description.
-			     (= (org-element-contents-end link)
-				(match-end 0))
-			     (progn
-                               (setq linktype (match-string 1))
-                               (match-string 2))))))))
-	      (when (and path (string-match-p file-extension-re path))
-		(let ((file (if (equal "attachment" linktype)
-				(progn
-                                  (require 'org-attach)
-				  (ignore-errors (org-attach-expand path)))
-                              (expand-file-name path))))
-                  ;; Expand environment variables.
-                  (when file (setq file (substitute-in-file-name file)))
-		  (when (and file (file-exists-p file))
-		    (let ((width (org-display-inline-image--width link))
-			  (align (org-image--align link))
-                          (old (get-char-property-and-overlay
-				(org-element-begin link)
-				'org-image-overlay)))
-		      (if (and (car-safe old) refresh)
-                          (image-flush (overlay-get (cdr old) 'display))
-			(let ((image (org--create-inline-image file width)))
-			  (when image
-			    (let ((ov (make-overlay
-				       (org-element-begin link)
-				       (progn
-					 (goto-char
-					  (org-element-end link))
-					 (unless (eolp) (skip-chars-backward " \t"))
-					 (point)))))
-                              ;; See bug#59902.  We cannot rely
-                              ;; on Emacs to update image if the file
-                              ;; has changed.
-                              (image-flush image)
-			      (overlay-put ov 'display image)
-			      (overlay-put ov 'face 'default)
-			      (overlay-put ov 'org-image-overlay t)
-			      (overlay-put
-			       ov 'modification-hooks
-			       (list 'org-display-inline-remove-overlay))
-			      (when (boundp 'image-map)
-				(overlay-put ov 'keymap image-map))
-                              (when align
-                                (overlay-put
-                                 ov 'before-string
-                                 (propertize
-                                  " " 'face 'default
-                                  'display
-                                  (pcase align
-                                    ("center" `(space :align-to (- center (0.5 . ,image))))
-                                    ("right"  `(space :align-to (- right ,image)))))))
-			      (push ov org-inline-image-overlays))))))))))))))))
-
 (declare-function org-export-read-attribute "ox"
                   (attribute element &optional property))
 (defvar visual-fill-column-width) ; Silence compiler warning
@@ -17135,32 +16882,6 @@ (defun org-image--align (link)
             (when (memq org-image-align '(center right))
               (symbol-name org-image-align))))))))
 
-
-(defun org-display-inline-remove-overlay (ov after _beg _end &optional _len)
-  "Remove inline-display overlay if a corresponding region is modified."
-  (when (and ov after)
-    (setq org-inline-image-overlays (delete ov org-inline-image-overlays))
-    ;; Clear image from cache to avoid image not updating upon
-    ;; changing on disk.  See Emacs bug#59902.
-    (when (overlay-get ov 'org-image-overlay)
-      (image-flush (overlay-get ov 'display)))
-    (delete-overlay ov)))
-
-(defun org-remove-inline-images (&optional beg end)
-  "Remove inline display of images."
-  (interactive)
-  (let* ((beg (or beg (point-min)))
-         (end (or end (point-max)))
-         (overlays (overlays-in beg end)))
-    (dolist (ov overlays)
-      (when (memq ov org-inline-image-overlays)
-        (setq org-inline-image-overlays (delq ov org-inline-image-overlays))
-        (delete-overlay ov)))
-    ;; Clear removed overlays.
-    (dolist (ov org-inline-image-overlays)
-      (unless (overlay-buffer ov)
-        (setq org-inline-image-overlays (delq ov org-inline-image-overlays))))))
-
 (defvar org-self-insert-command-undo-counter 0)
 (defvar org-speed-command nil)
 
diff --git a/testing/lisp/test-org-fold.el b/testing/lisp/test-org-fold.el
index f58642be6..809738f6c 100644
--- a/testing/lisp/test-org-fold.el
+++ b/testing/lisp/test-org-fold.el
@@ -716,14 +716,14 @@ (ert-deftest test-org-fold/org-fold-display-inline-images ()
       (org-show-subtree)
       (org-fold-subtree t)
       (run-hook-with-args 'org-cycle-hook 'folded)
-      (should-not org-inline-image-overlays)
+      (should-not org-link-preview-overlays)
       (should-not
        (cl-every
         (lambda (ov) (overlay-get ov 'org-image-overlay))
         (overlays-in (point-min) (point-max))))
       (org-show-subtree)
       (run-hook-with-args 'org-cycle-hook 'subtree)
-      (should org-inline-image-overlays)
+      (should org-link-preview-overlays)
       (should
        (cl-every
         (lambda (ov) (overlay-get ov 'org-image-overlay))
-- 
2.44.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

end of thread, other threads:[~2024-09-02 20:14 UTC | newest]

Thread overview: 40+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-05-15  3:28 [PATCH] add a function to only refresh inline images under current headline instead of global buffer Christopher M. Miles
2023-05-15 11:08 ` Ihor Radchenko
2023-05-15 13:01   ` Christopher M. Miles
2023-05-15 14:00   ` [PATCH v2] " Christopher M. Miles
2023-05-16  9:17     ` Ihor Radchenko
2023-05-16 12:18       ` Christopher M. Miles
2023-07-24 11:25         ` Ihor Radchenko
2023-08-01  4:40           ` [PATCH v3] " Christopher M. Miles
2023-08-01  8:04             ` Ihor Radchenko
2023-08-01 12:17               ` [PATCH v3.1] " Christopher M. Miles
2023-08-01 14:09                 ` Ihor Radchenko
2023-08-01 15:22                   ` Christopher M. Miles
2023-08-01 15:46                   ` Christopher M. Miles
2023-08-02 16:08                     ` Ihor Radchenko
2023-08-04  6:30                       ` Christopher M. Miles
2023-08-02  7:26                 ` Ihor Radchenko
2023-08-02 15:44                   ` Christopher M. Miles
2023-08-04  8:20                     ` Ihor Radchenko
2023-08-05  5:28                       ` [PATCH v3.2] " Christopher M. Miles
2024-07-22 10:46                         ` Ihor Radchenko
2024-08-01 22:58                           ` [PATCH v4.0] " stardiviner
     [not found]                           ` <66a8b73b.170a0220.383476.996e@mx.google.com>
2024-08-12 10:18                             ` Ihor Radchenko
2024-08-14  2:04                               ` stardiviner
2024-08-18 10:27                                 ` Ihor Radchenko
2024-08-20  2:02                                   ` Karthik Chikmagalur
2024-08-20 15:43                                     ` Karthik Chikmagalur
2024-08-20 18:19                                       ` Ihor Radchenko
2024-08-20 19:46                                         ` Karthik Chikmagalur
2024-08-22 13:19                                           ` Ihor Radchenko
2024-08-23  6:04                                             ` Karthik Chikmagalur
2024-08-23 23:36                                             ` [PATCH v1] Inline image display as part of a new org-link-preview system Karthik Chikmagalur
2024-08-24  1:00                                               ` Karthik Chikmagalur
2024-08-31 14:22                                               ` Ihor Radchenko
2024-08-31 16:41                                                 ` Karthik Chikmagalur
2024-08-31 16:53                                                   ` Ihor Radchenko
2024-08-31 22:37                                                     ` [PATCH v2] " Karthik Chikmagalur
2024-09-01 13:06                                                       ` Ihor Radchenko
2024-09-02 20:13                                                         ` [PATCH v3] " Karthik Chikmagalur
2024-08-18 10:34                                 ` [FR] Automatically display images in resutls of evaluation (was: [PATCH v4.0] Re: [PATCH] add a function to only refresh inline images under current headline instead of global buffer) Ihor Radchenko
     [not found]                                   ` <66c54dfc.a70a0220.3c823a.2899@mx.google.com>
2024-08-22 13:06                                     ` [FR] Automatically display images in resutls of evaluation Ihor Radchenko

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).