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-batch-size, org-link-preview-delay, org-link-preview--timer, org-link-preview--queue, org-link-preview-overlays, org-link-preview--get-overlays, org-link-preview--remove-overlay, org-link-preview, org-link-preview-region, org-link-preview--process-queue, org-link-preview-clear, org-link-preview-file, org-display-remote-inline-images, org-image-align, org--create-inline-image, org-display-inline-image--width, org-image--align): 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. This link parameter is a function called asynchronously to place previes. File links and attachments are previewed using inline image previews as before. Move image handling utilities from lisp/org.el to lisp/ol.el. * 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, org-startup-with-inline-images, org-startup-with-link-previews, org-startup-options): 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. Rename `org-startup-with-inline-images' to `org-startup-with-link-previews'. Add new STARTUP options for link previews to `org-startup-options': "linkpreviews" and "nolinkpreviews". * 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, org-cycle-display-link-previews, org-cycle-inline-images-display, org-cycle-inline-link-previews): Use `org-link-preview' and `org-link-preview-region'. Rename inline-images functions and user options to their link-previews equivalents: - `org-cycle-display-inline-images' to `org-cycle-display-link-previews' - `org-cycle-inline-images-display' to `org-cycle-inline-link-previews' * 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'.
This commit is contained in:
parent
4ff4828944
commit
9cce40c94f
603
lisp/ol.el
603
lisp/ol.el
|
@ -82,6 +82,11 @@
|
|||
(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-element-contents-end "org-element" (node))
|
||||
(declare-function org-property-or-variable-value "org" (var &optional inherit))
|
||||
|
||||
|
||||
;;; Customization
|
||||
|
@ -171,6 +176,18 @@ link.
|
|||
|
||||
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 syntax node for the link
|
||||
|
||||
This function must return a non-nil value to indicate success.
|
||||
A return value of nil implies that the preview failed, and the
|
||||
overlay placed on the link will be removed.
|
||||
|
||||
`:help-echo'
|
||||
|
||||
String or function used as a value for the `help-echo' text
|
||||
|
@ -521,6 +538,81 @@ links more efficient."
|
|||
:type 'boolean
|
||||
:safe #'booleanp)
|
||||
|
||||
(defcustom org-link-preview-delay 0.05
|
||||
"Idle delay in seconds between link previews when using
|
||||
`org-link-preview'. Links are previewed in batches (see
|
||||
`org-link-preview-batch-size') spaced out by this delay. Set
|
||||
this to a small number for more immediate previews, but at the
|
||||
expense of higher lag."
|
||||
:group 'org-link
|
||||
:type 'number)
|
||||
|
||||
(defcustom org-link-preview-batch-size 6
|
||||
"Number of links that are previewed at once with
|
||||
`org-link-preview'. Links are previewed asynchronously, in
|
||||
batches spaced out in time (see `org-link-preview-delay'). Set
|
||||
this to a large integer for more immediate previews, but at the
|
||||
expense of higher lag."
|
||||
:group 'org-link
|
||||
:type 'natnum)
|
||||
|
||||
(defcustom org-display-remote-inline-images 'skip
|
||||
"How to display remote inline images.
|
||||
Possible values of this option are:
|
||||
|
||||
skip Don't display remote images.
|
||||
download Always download and display remote images.
|
||||
t
|
||||
cache Display remote images, and open them in separate buffers
|
||||
for caching. Silently update the image buffer when a file
|
||||
change is detected."
|
||||
:group 'org-appearance
|
||||
:package-version '(Org . "9.7")
|
||||
:type '(choice
|
||||
(const :tag "Ignore remote images" skip)
|
||||
(const :tag "Always display remote images" download)
|
||||
(const :tag "Display and silently update remote images" cache))
|
||||
:safe #'symbolp)
|
||||
|
||||
(defcustom org-image-max-width 'fill-column
|
||||
"When non-nil, limit the displayed image width.
|
||||
This setting only takes effect when `org-image-actual-width' is set to
|
||||
t or when #+ATTR* is set to t.
|
||||
|
||||
Possible values:
|
||||
- `fill-column' :: limit width to `fill-column'
|
||||
- `window' :: limit width to window width
|
||||
- integer :: limit width to number in pixels
|
||||
- float :: limit width to that fraction of window width
|
||||
- nil :: do not limit image width"
|
||||
:group 'org-appearance
|
||||
:package-version '(Org . "9.7")
|
||||
:type '(choice
|
||||
(const :tag "Do not limit image width" nil)
|
||||
(const :tag "Limit to `fill-column'" fill-column)
|
||||
(const :tag "Limit to window width" window)
|
||||
(integer :tag "Limit to a number of pixels")
|
||||
(float :tag "Limit to a fraction of window width")))
|
||||
|
||||
(defcustom org-image-align 'left
|
||||
"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.
|
||||
|
||||
Possible values of this option are:
|
||||
|
||||
left Insert image at specified position.
|
||||
center Center image previews.
|
||||
right Right-align image previews."
|
||||
:group 'org-appearance
|
||||
:package-version '(Org . "9.7")
|
||||
:type '(choice
|
||||
(const :tag "Left align (or don\\='t align) image previews" left)
|
||||
(const :tag "Center image previews" center)
|
||||
(const :tag "Right align image previews" right))
|
||||
:safe #'symbolp)
|
||||
|
||||
;;; Public variables
|
||||
|
||||
(defconst org-target-regexp (let ((border "[^<>\n\r \t]"))
|
||||
|
@ -649,6 +741,29 @@ exact and fuzzy text search.")
|
|||
(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)
|
||||
|
||||
(defvar-local org-link-preview--timer nil
|
||||
"Timer for previewing Org links in buffer.
|
||||
|
||||
This timer creates previews for specs in
|
||||
`org-link-preview--queue'.")
|
||||
|
||||
(defvar-local org-link-preview--queue nil
|
||||
"Queue of pending previews for Org links in buffer.
|
||||
|
||||
Each element of this queue is a list of the form
|
||||
|
||||
(PREVIEW-FUNC OVERLAY PATH LINK)
|
||||
|
||||
where PREVIEW-FUNC places a preview of PATH using OVERLAY. LINK
|
||||
is the Org element being previewed.")
|
||||
|
||||
|
||||
;;; Internal Functions
|
||||
|
||||
|
@ -881,7 +996,227 @@ Return t when a link has been stored in `org-link-store-props'."
|
|||
(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 (delq ov org-link-preview-overlays))
|
||||
;; Clear image from cache to avoid image not updating upon
|
||||
;; changing on disk. See Emacs bug#59902.
|
||||
(when-let* ((disp (overlay-get ov 'display))
|
||||
((imagep disp)))
|
||||
(image-flush disp))
|
||||
(delete-overlay ov)))
|
||||
|
||||
|
||||
|
||||
;;;; Utilities for image preview display
|
||||
|
||||
;; For without-x builds.
|
||||
(declare-function image-flush "image" (spec &optional frame))
|
||||
|
||||
(defun org--create-inline-image (file width)
|
||||
"Create image located at FILE, or return nil.
|
||||
WIDTH is the width of the image. The image may not be created
|
||||
according to the value of `org-display-remote-inline-images'."
|
||||
(let* ((remote? (file-remote-p file))
|
||||
(file-or-data
|
||||
(pcase org-display-remote-inline-images
|
||||
((guard (not remote?)) file)
|
||||
(`download (with-temp-buffer
|
||||
(set-buffer-multibyte nil)
|
||||
(insert-file-contents-literally file)
|
||||
(buffer-string)))
|
||||
((or `cache `t)
|
||||
(let ((revert-without-query '(".")))
|
||||
(with-current-buffer (find-file-noselect file)
|
||||
(buffer-string))))
|
||||
(`skip nil)
|
||||
(other
|
||||
(message "Invalid value of `org-display-remote-inline-images': %S"
|
||||
other)
|
||||
nil))))
|
||||
(when file-or-data
|
||||
(create-image file-or-data
|
||||
(and (image-type-available-p 'imagemagick)
|
||||
width
|
||||
'imagemagick)
|
||||
remote?
|
||||
:width width
|
||||
:max-width
|
||||
(pcase org-image-max-width
|
||||
(`fill-column (* fill-column (frame-char-width (selected-frame))))
|
||||
(`window (window-width nil t))
|
||||
((pred integerp) org-image-max-width)
|
||||
((pred floatp) (floor (* org-image-max-width (window-width nil t))))
|
||||
(`nil nil)
|
||||
(_ (error "Unsupported value of `org-image-max-width': %S"
|
||||
org-image-max-width)))
|
||||
:scale 1))))
|
||||
|
||||
(declare-function org-export-read-attribute "ox"
|
||||
(attribute element &optional property))
|
||||
(defvar visual-fill-column-width) ; Silence compiler warning
|
||||
(defun org-display-inline-image--width (link)
|
||||
"Determine the display width of the image LINK, in pixels.
|
||||
- When `org-image-actual-width' is t, the image's pixel width is used.
|
||||
- When `org-image-actual-width' is a number, that value will is used.
|
||||
- When `org-image-actual-width' is nil or a list, :width attribute of
|
||||
#+attr_org or the first #+attr_... (if it exists) is used to set the
|
||||
image width. A width of X% is divided by 100. If the value is a
|
||||
float between 0 and 2, it interpreted as that proportion of the text
|
||||
width in the buffer.
|
||||
|
||||
If no :width attribute is given and `org-image-actual-width' is a
|
||||
list with a number as the car, then that number is used as the
|
||||
default value."
|
||||
;; Apply `org-image-actual-width' specifications.
|
||||
;; Support subtree-level property "ORG-IMAGE-ACTUAL-WIDTH" specified
|
||||
;; width.
|
||||
(let ((org-image-actual-width (org-property-or-variable-value 'org-image-actual-width)))
|
||||
(cond
|
||||
((eq org-image-actual-width t) nil)
|
||||
((listp org-image-actual-width)
|
||||
(require 'ox)
|
||||
(let* ((par (org-element-lineage link 'paragraph))
|
||||
;; Try to find an attribute providing a :width.
|
||||
;; #+ATTR_ORG: :width ...
|
||||
(attr-width (org-export-read-attribute :attr_org par :width))
|
||||
(width-unreadable?
|
||||
(lambda (value)
|
||||
(or (not (stringp value))
|
||||
(unless (string= value "t")
|
||||
(or (not (string-match
|
||||
(rx bos (opt "+")
|
||||
(or
|
||||
;; Number of pixels
|
||||
;; must be a lone number, not
|
||||
;; things like 4in
|
||||
(seq (1+ (in "0-9")) eos)
|
||||
;; Numbers ending with %
|
||||
(seq (1+ (in "0-9.")) (group-n 1 "%"))
|
||||
;; Fractions
|
||||
(seq (0+ (in "0-9")) "." (1+ (in "0-9")))))
|
||||
value))
|
||||
(let ((number (string-to-number value)))
|
||||
(and (floatp number)
|
||||
(not (match-string 1 value)) ; X%
|
||||
(not (<= 0.0 number 2.0)))))))))
|
||||
;; #+ATTR_BACKEND: :width ...
|
||||
(attr-other
|
||||
(catch :found
|
||||
(org-element-properties-map
|
||||
(lambda (prop _)
|
||||
(when (and
|
||||
(not (eq prop :attr_org))
|
||||
(string-match-p "^:attr_" (symbol-name prop))
|
||||
(not (funcall width-unreadable? (org-export-read-attribute prop par :width))))
|
||||
(throw :found prop)))
|
||||
par)))
|
||||
(attr-width
|
||||
(if (not (funcall width-unreadable? attr-width))
|
||||
attr-width
|
||||
;; When #+attr_org: does not have readable :width
|
||||
(and attr-other
|
||||
(org-export-read-attribute attr-other par :width))))
|
||||
(width
|
||||
(cond
|
||||
;; Treat :width t as if `org-image-actual-width' were t.
|
||||
((string= attr-width "t") nil)
|
||||
;; Fallback to `org-image-actual-width' if no interprable width is given.
|
||||
((funcall width-unreadable? attr-width)
|
||||
(car org-image-actual-width))
|
||||
;; Convert numeric widths to numbers, converting percentages.
|
||||
((string-match-p "\\`[[+]?[0-9.]+%" attr-width)
|
||||
(/ (string-to-number attr-width) 100.0))
|
||||
(t (string-to-number attr-width)))))
|
||||
(if (and (floatp width) (<= 0.0 width 2.0))
|
||||
;; A float in [0,2] should be interpereted as this portion of
|
||||
;; the text width in the window. This works well with cases like
|
||||
;; #+attr_latex: :width 0.X\{line,page,column,etc.}width,
|
||||
;; as the "0.X" is pulled out as a float. We use 2 as the upper
|
||||
;; bound as cases such as 1.2\linewidth are feasible.
|
||||
(round (* width
|
||||
(window-pixel-width)
|
||||
(/ (or (and (bound-and-true-p visual-fill-column-mode)
|
||||
(or visual-fill-column-width auto-fill-function))
|
||||
(when auto-fill-function fill-column)
|
||||
(- (window-text-width) (line-number-display-width)))
|
||||
(float (window-total-width)))))
|
||||
width)))
|
||||
((numberp org-image-actual-width)
|
||||
org-image-actual-width)
|
||||
(t nil))))
|
||||
|
||||
(defun org-image--align (link)
|
||||
"Determine the alignment of the image LINK.
|
||||
LINK is a link object.
|
||||
|
||||
In decreasing order of priority, this is controlled:
|
||||
- Per image by the value of `:center' or `:align' in the
|
||||
affiliated keyword `#+attr_org'.
|
||||
- By the `#+attr_html' or `#+attr_latex` keywords with valid
|
||||
`:center' or `:align' values.
|
||||
- Globally by the user option `org-image-align'.
|
||||
|
||||
The result is either nil or one of the strings \"left\",
|
||||
\"center\" or \"right\".
|
||||
|
||||
\"center\" will cause the image preview to be centered, \"right\"
|
||||
will cause it to be right-aligned. A value of \"left\" or nil
|
||||
implies no special alignment."
|
||||
(let ((par (org-element-lineage link 'paragraph)))
|
||||
;; Only align when image is not surrounded by paragraph text:
|
||||
(when (and par ; when image is not in paragraph, but in table/headline/etc, do not align
|
||||
(= (org-element-begin link)
|
||||
(save-excursion
|
||||
(goto-char (org-element-contents-begin par))
|
||||
(skip-chars-forward "\t ")
|
||||
(point))) ;account for leading space
|
||||
;before link
|
||||
(<= (- (org-element-contents-end par)
|
||||
(org-element-end link))
|
||||
1)) ;account for trailing newline
|
||||
;at end of paragraph
|
||||
(save-match-data
|
||||
;; Look for a valid ":center t" or ":align left|center|right"
|
||||
;; attribute.
|
||||
;;
|
||||
;; An attr_org keyword has the highest priority, with
|
||||
;; any attr.* next. Choosing between these is
|
||||
;; unspecified.
|
||||
(let ((center-re ":\\(center\\)[[:space:]]+t\\b")
|
||||
(align-re ":align[[:space:]]+\\(left\\|center\\|right\\)\\b")
|
||||
attr-align)
|
||||
(catch 'exit
|
||||
(org-element-properties-mapc
|
||||
(lambda (propname propval)
|
||||
(when (and propval
|
||||
(string-match-p ":attr.*" (symbol-name propname)))
|
||||
(setq propval (car-safe propval))
|
||||
(when (or (string-match center-re propval)
|
||||
(string-match align-re propval))
|
||||
(setq attr-align (match-string 1 propval))
|
||||
(when (eq propname :attr_org)
|
||||
(throw 'exit t)))))
|
||||
par))
|
||||
(if attr-align
|
||||
(when (member attr-align '("center" "right")) attr-align)
|
||||
;; No image-specific keyword, check global alignment property
|
||||
(when (memq org-image-align '(center right))
|
||||
(symbol-name org-image-align))))))))
|
||||
|
||||
;;; Public API
|
||||
|
||||
(defun org-link-types ()
|
||||
|
@ -1573,6 +1908,231 @@ If there is no description, use the link target."
|
|||
(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, also preview links with description in
|
||||
the active region, at point or in the current section.
|
||||
|
||||
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] Displaying %d images 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")))))
|
||||
|
||||
;;;###autoload
|
||||
(defun org-link-preview-refresh ()
|
||||
"Assure display of link previews in buffer and refresh them."
|
||||
(interactive)
|
||||
(org-link-preview-region nil t (point-min) (point-max)))
|
||||
|
||||
(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))
|
||||
(org-with-point-at (or beg (point-min))
|
||||
(let ((case-fold-search t)
|
||||
preview-queue)
|
||||
;; Collect links to preview
|
||||
(while (re-search-forward org-link-any-re end t)
|
||||
(forward-char -1) ;ensure we are on the link
|
||||
(when-let*
|
||||
((link (org-element-lineage (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)))))
|
||||
(overlay-put ov 'modification-hooks
|
||||
(list 'org-link-preview--remove-overlay))
|
||||
(push ov org-link-preview-overlays)
|
||||
(push (list preview-func ov path link) preview-queue))))
|
||||
;; Collect previews in buffer-local LIFO preview queue
|
||||
(setq org-link-preview--queue
|
||||
(nconc (nreverse preview-queue) org-link-preview--queue))
|
||||
;; Run preview possibly asynchronously
|
||||
(when org-link-preview--queue
|
||||
(org-link-preview--process-queue (current-buffer))))))
|
||||
|
||||
(defun org-link-preview--process-queue (org-buffer)
|
||||
"Preview pending Org link previews in ORG-BUFFER.
|
||||
|
||||
Previews are generated from the specs in
|
||||
`org-link-preview--queue', which see."
|
||||
(and (buffer-live-p org-buffer)
|
||||
(with-current-buffer org-buffer
|
||||
(cl-loop
|
||||
for spec in org-link-preview--queue
|
||||
for ov = (cadr spec) ;SPEC is (preview-func ov path link)
|
||||
for count from org-link-preview-batch-size above 0
|
||||
do (pop org-link-preview--queue)
|
||||
if (overlay-buffer ov) do
|
||||
(if (apply spec)
|
||||
(overlay-put ov 'org-image-overlay t)
|
||||
;; Preview was unsuccessful, delete overlay
|
||||
(delete-overlay ov)
|
||||
(setq org-link-preview-overlays
|
||||
(delq ov org-link-preview-overlays)))
|
||||
else do (cl-incf count) end
|
||||
finally do
|
||||
(setq org-link-preview--timer
|
||||
(and org-link-preview--queue
|
||||
(run-with-idle-timer
|
||||
(time-add (or (current-idle-time) 0)
|
||||
org-link-preview-delay)
|
||||
nil #'org-link-preview--process-queue org-buffer)))))))
|
||||
|
||||
(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)
|
||||
;; Remove pending preview tasks between BEG and END
|
||||
(when-let ((spec (cl-find ov org-link-preview--queue
|
||||
:key #'cadr)))
|
||||
(setq org-link-preview--queue (delq spec org-link-preview--queue)))
|
||||
;; Remove placed overlays between BEG and END
|
||||
(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))))))
|
||||
|
||||
|
||||
;;; Built-in link types
|
||||
|
||||
|
@ -1595,7 +2155,48 @@ PATH is the sexp to evaluate, as a string."
|
|||
(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!"))
|
||||
(require 'image)
|
||||
(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 '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 _)
|
||||
|
|
|
@ -797,9 +797,18 @@ It is meant to be added to `org-export-before-parsing-hook'."
|
|||
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-with-point-at (org-element-begin link)
|
||||
(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."
|
||||
|
|
|
@ -1010,6 +1010,191 @@ use of this function is for the stuck project list."
|
|||
(define-obsolete-function-alias 'org-add-angle-brackets
|
||||
'org-link-add-angle-brackets "9.3")
|
||||
|
||||
(declare-function org-link-preview--remove-overlay "ol"
|
||||
(ov after beg end &optional len))
|
||||
(declare-function org-link-preview--get-overlays "ol" (&optional beg end))
|
||||
(declare-function org-link-preview-clear "ol" (&optional beg end))
|
||||
(declare-function org-link-preview--remove-overlay "ol"
|
||||
(ov after beg end &optional len))
|
||||
(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))
|
||||
|
||||
(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-function-alias 'org-redisplay-inline-images
|
||||
'org-link-preview-refresh "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)
|
||||
|
||||
(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")
|
||||
(declare-function org-link-preview-region "ol")
|
||||
;; 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-link-preview-region 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"))))))
|
||||
|
||||
|
||||
;; The function was made obsolete by commit 65399674d5 of 2013-02-22.
|
||||
;; This make-obsolete call was added 2016-09-01.
|
||||
(make-obsolete 'org-capture-import-remember-templates
|
||||
|
|
|
@ -40,14 +40,14 @@
|
|||
(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" ())
|
||||
|
@ -217,7 +217,7 @@ the values `folded', `children', or `subtree'."
|
|||
(defcustom org-cycle-hook '(org-cycle-hide-archived-subtrees
|
||||
org-cycle-show-empty-lines
|
||||
org-cycle-optimize-window-after-visibility-change
|
||||
org-cycle-display-inline-images)
|
||||
org-cycle-display-link-previews)
|
||||
"Hook that is run after `org-cycle' has changed the buffer visibility.
|
||||
The function(s) in this hook must accept a single argument which indicates
|
||||
the new state that was set by the most recent `org-cycle' command. The
|
||||
|
@ -237,11 +237,15 @@ normal outline commands like `show-all', but not with the cycling commands."
|
|||
:group 'org-cycle
|
||||
:type 'boolean)
|
||||
|
||||
(defcustom org-cycle-inline-images-display nil
|
||||
"Non-nil means auto display inline images under subtree when cycling."
|
||||
(defvaralias 'org-cycle-inline-images-display
|
||||
'org-cycle-link-previews-display
|
||||
"Non-nil means auto display inline images under subtree when cycling.")
|
||||
|
||||
(defcustom org-cycle-link-previews-display nil
|
||||
"Non-nil means auto display link previews under subtree when cycling."
|
||||
:group 'org-startup
|
||||
:group 'org-cycle
|
||||
:package-version '(Org . "9.6")
|
||||
:package-version '(Org . "9.8")
|
||||
:type 'boolean)
|
||||
|
||||
(defvaralias 'org-tab-first-hook 'org-cycle-tab-first-hook)
|
||||
|
@ -804,12 +808,15 @@ STATE should be one of the symbols listed in the docstring of
|
|||
"Subtree is archived and stays closed. Use \
|
||||
`\\[org-cycle-force-archived]' to cycle it anyway."))))))
|
||||
|
||||
(defun org-cycle-display-inline-images (state)
|
||||
(defalias 'org-cycle-inline-images-display
|
||||
'org-cycle-display-link-previews)
|
||||
|
||||
(defun org-cycle-display-link-previews (state)
|
||||
"Auto display inline images under subtree when cycling.
|
||||
It works when `org-cycle-inline-images-display' is non-nil.
|
||||
It works when `org-cycle-link-previews-display' is non-nil.
|
||||
STATE is the current outline visibility state. It should be one of
|
||||
symbols `content', `all', `folded', `children', or `subtree'."
|
||||
(when org-cycle-inline-images-display
|
||||
(when org-cycle-link-previews-display
|
||||
(pcase state
|
||||
('children
|
||||
(org-with-wide-buffer
|
||||
|
@ -817,19 +824,19 @@ symbols `content', `all', `folded', `children', or `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
|
||||
(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)
|
||||
|
|
|
@ -218,7 +218,8 @@
|
|||
(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-link-preview-refresh "ol" ())
|
||||
(declare-function org-latex-preview "org" (&optional arg))
|
||||
(declare-function org-toggle-narrow-to-subtree "org" ())
|
||||
(declare-function org-toggle-ordered-property "org" ())
|
||||
|
@ -652,8 +653,8 @@ COMMANDS is a list of alternating OLDDEF NEWDEF command names."
|
|||
(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-M-v") #'org-redisplay-inline-images)
|
||||
(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-link-preview-refresh)
|
||||
(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)
|
||||
(org-defkey org-mode-map (kbd "C-c C-x C-r") #'org-toggle-radio-button)
|
||||
|
|
|
@ -633,7 +633,7 @@ manner suitable for prepending to a user-specified script."
|
|||
|
||||
(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))
|
||||
|
|
554
lisp/org.el
554
lisp/org.el
|
@ -1160,14 +1160,22 @@ the following lines anywhere in the buffer:
|
|||
:package-version '(Org . "9.2")
|
||||
:safe #'booleanp)
|
||||
|
||||
(defcustom org-startup-with-inline-images nil
|
||||
(defvaralias 'org-startup-with-inline-images
|
||||
'org-startup-with-link-previews
|
||||
"Non-nil means show inline images when loading a new Org file.
|
||||
This can also be configured on a per-file basis by adding one of
|
||||
the following lines anywhere in the buffer:
|
||||
#+STARTUP: inlineimages
|
||||
#+STARTUP: noinlineimages"
|
||||
#+STARTUP: noinlineimages")
|
||||
|
||||
(defcustom org-startup-with-link-previews nil
|
||||
"Non-nil means show link previews when loading a new Org file.
|
||||
This can also be configured on a per-file basis by adding one of
|
||||
the following lines anywhere in the buffer:
|
||||
#+STARTUP: linkpreviews
|
||||
#+STARTUP: nolinkpreviews"
|
||||
:group 'org-startup
|
||||
:version "24.1"
|
||||
:version "29.4"
|
||||
:type 'boolean)
|
||||
|
||||
(defcustom org-startup-with-latex-preview nil
|
||||
|
@ -4153,8 +4161,10 @@ After a match, the following groups carry important information:
|
|||
("shrink" org-startup-shrink-all-tables t)
|
||||
("descriptivelinks" org-link-descriptive t)
|
||||
("literallinks" org-link-descriptive nil)
|
||||
("inlineimages" org-startup-with-inline-images t)
|
||||
("noinlineimages" org-startup-with-inline-images nil)
|
||||
("inlineimages" org-startup-with-link-previews t)
|
||||
("noinlineimages" org-startup-with-link-previews nil)
|
||||
("linkpreviews" org-startup-with-link-previews t)
|
||||
("nolinkpreviews" org-startup-with-link-previews nil)
|
||||
("latexpreview" org-startup-with-latex-preview t)
|
||||
("nolatexpreview" org-startup-with-latex-preview nil)
|
||||
("customtime" org-display-custom-times t)
|
||||
|
@ -5079,7 +5089,7 @@ The following commands are available:
|
|||
;; 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))
|
||||
|
@ -15601,26 +15611,6 @@ This requires Emacs >= 24.1, built with imagemagick support."
|
|||
(list :tag "Use #+ATTR* or a number of pixels" (integer))
|
||||
(const :tag "Use #+ATTR* or don't resize" nil)))
|
||||
|
||||
(defcustom org-image-max-width 'fill-column
|
||||
"When non-nil, limit the displayed image width.
|
||||
This setting only takes effect when `org-image-actual-width' is set to
|
||||
t or when #+ATTR* is set to t.
|
||||
|
||||
Possible values:
|
||||
- `fill-column' :: limit width to `fill-column'
|
||||
- `window' :: limit width to window width
|
||||
- integer :: limit width to number in pixels
|
||||
- float :: limit width to that fraction of window width
|
||||
- nil :: do not limit image width"
|
||||
:group 'org-appearance
|
||||
:package-version '(Org . "9.7")
|
||||
:type '(choice
|
||||
(const :tag "Do not limit image width" nil)
|
||||
(const :tag "Limit to `fill-column'" fill-column)
|
||||
(const :tag "Limit to window width" window)
|
||||
(integer :tag "Limit to a number of pixels")
|
||||
(float :tag "Limit to a fraction of window width")))
|
||||
|
||||
(defcustom org-agenda-inhibit-startup nil
|
||||
"Inhibit startup when preparing agenda buffers.
|
||||
When this variable is t, the initialization of the Org agenda
|
||||
|
@ -16667,518 +16657,6 @@ SNIPPETS-P indicates if this is run to create snippet images for HTML."
|
|||
(format "%g" (/ value 65535.0)))
|
||||
|
||||
|
||||
;; 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))
|
||||
|
||||
(defcustom org-display-remote-inline-images 'skip
|
||||
"How to display remote inline images.
|
||||
Possible values of this option are:
|
||||
|
||||
skip Don't display remote images.
|
||||
download Always download and display remote images.
|
||||
t
|
||||
cache Display remote images, and open them in separate buffers
|
||||
for caching. Silently update the image buffer when a file
|
||||
change is detected."
|
||||
:group 'org-appearance
|
||||
:package-version '(Org . "9.7")
|
||||
:type '(choice
|
||||
(const :tag "Ignore remote images" skip)
|
||||
(const :tag "Always display remote images" download)
|
||||
(const :tag "Display and silently update remote images" cache))
|
||||
:safe #'symbolp)
|
||||
|
||||
(defcustom org-image-align 'left
|
||||
"How to align images previewed using `org-display-inline-images'.
|
||||
|
||||
Only stand-alone image links are affected by this setting. These
|
||||
are links without surrounding text.
|
||||
|
||||
Possible values of this option are:
|
||||
|
||||
left Insert image at specified position.
|
||||
center Center image previews.
|
||||
right Right-align image previews."
|
||||
:group 'org-appearance
|
||||
:package-version '(Org . "9.7")
|
||||
:type '(choice
|
||||
(const :tag "Left align (or don\\='t align) image previews" left)
|
||||
(const :tag "Center image previews" center)
|
||||
(const :tag "Right align image previews" right))
|
||||
:safe #'symbolp)
|
||||
|
||||
(defun org--create-inline-image (file width)
|
||||
"Create image located at FILE, or return nil.
|
||||
WIDTH is the width of the image. The image may not be created
|
||||
according to the value of `org-display-remote-inline-images'."
|
||||
(let* ((remote? (file-remote-p file))
|
||||
(file-or-data
|
||||
(pcase org-display-remote-inline-images
|
||||
((guard (not remote?)) file)
|
||||
(`download (with-temp-buffer
|
||||
(set-buffer-multibyte nil)
|
||||
(insert-file-contents-literally file)
|
||||
(buffer-string)))
|
||||
((or `cache `t)
|
||||
(let ((revert-without-query '(".")))
|
||||
(with-current-buffer (find-file-noselect file)
|
||||
(buffer-string))))
|
||||
(`skip nil)
|
||||
(other
|
||||
(message "Invalid value of `org-display-remote-inline-images': %S"
|
||||
other)
|
||||
nil))))
|
||||
(when file-or-data
|
||||
(create-image file-or-data
|
||||
(and (image-type-available-p 'imagemagick)
|
||||
width
|
||||
'imagemagick)
|
||||
remote?
|
||||
:width width
|
||||
:max-width
|
||||
(pcase org-image-max-width
|
||||
(`fill-column (* fill-column (frame-char-width (selected-frame))))
|
||||
(`window (window-width nil t))
|
||||
((pred integerp) org-image-max-width)
|
||||
((pred floatp) (floor (* org-image-max-width (window-width nil t))))
|
||||
(`nil nil)
|
||||
(_ (error "Unsupported value of `org-image-max-width': %S"
|
||||
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
|
||||
(defun org-display-inline-image--width (link)
|
||||
"Determine the display width of the image LINK, in pixels.
|
||||
- When `org-image-actual-width' is t, the image's pixel width is used.
|
||||
- When `org-image-actual-width' is a number, that value will is used.
|
||||
- When `org-image-actual-width' is nil or a list, :width attribute of
|
||||
#+attr_org or the first #+attr_... (if it exists) is used to set the
|
||||
image width. A width of X% is divided by 100. If the value is a
|
||||
float between 0 and 2, it interpreted as that proportion of the text
|
||||
width in the buffer.
|
||||
|
||||
If no :width attribute is given and `org-image-actual-width' is a
|
||||
list with a number as the car, then that number is used as the
|
||||
default value."
|
||||
;; Apply `org-image-actual-width' specifications.
|
||||
;; Support subtree-level property "ORG-IMAGE-ACTUAL-WIDTH" specified
|
||||
;; width.
|
||||
(let ((org-image-actual-width (org-property-or-variable-value 'org-image-actual-width)))
|
||||
(cond
|
||||
((eq org-image-actual-width t) nil)
|
||||
((listp org-image-actual-width)
|
||||
(require 'ox)
|
||||
(let* ((par (org-element-lineage link 'paragraph))
|
||||
;; Try to find an attribute providing a :width.
|
||||
;; #+ATTR_ORG: :width ...
|
||||
(attr-width (org-export-read-attribute :attr_org par :width))
|
||||
(width-unreadable?
|
||||
(lambda (value)
|
||||
(or (not (stringp value))
|
||||
(unless (string= value "t")
|
||||
(or (not (string-match
|
||||
(rx bos (opt "+")
|
||||
(or
|
||||
;; Number of pixels
|
||||
;; must be a lone number, not
|
||||
;; things like 4in
|
||||
(seq (1+ (in "0-9")) eos)
|
||||
;; Numbers ending with %
|
||||
(seq (1+ (in "0-9.")) (group-n 1 "%"))
|
||||
;; Fractions
|
||||
(seq (0+ (in "0-9")) "." (1+ (in "0-9")))))
|
||||
value))
|
||||
(let ((number (string-to-number value)))
|
||||
(and (floatp number)
|
||||
(not (match-string 1 value)) ; X%
|
||||
(not (<= 0.0 number 2.0)))))))))
|
||||
;; #+ATTR_BACKEND: :width ...
|
||||
(attr-other
|
||||
(catch :found
|
||||
(org-element-properties-map
|
||||
(lambda (prop _)
|
||||
(when (and
|
||||
(not (eq prop :attr_org))
|
||||
(string-match-p "^:attr_" (symbol-name prop))
|
||||
(not (funcall width-unreadable? (org-export-read-attribute prop par :width))))
|
||||
(throw :found prop)))
|
||||
par)))
|
||||
(attr-width
|
||||
(if (not (funcall width-unreadable? attr-width))
|
||||
attr-width
|
||||
;; When #+attr_org: does not have readable :width
|
||||
(and attr-other
|
||||
(org-export-read-attribute attr-other par :width))))
|
||||
(width
|
||||
(cond
|
||||
;; Treat :width t as if `org-image-actual-width' were t.
|
||||
((string= attr-width "t") nil)
|
||||
;; Fallback to `org-image-actual-width' if no interprable width is given.
|
||||
((funcall width-unreadable? attr-width)
|
||||
(car org-image-actual-width))
|
||||
;; Convert numeric widths to numbers, converting percentages.
|
||||
((string-match-p "\\`[[+]?[0-9.]+%" attr-width)
|
||||
(/ (string-to-number attr-width) 100.0))
|
||||
(t (string-to-number attr-width)))))
|
||||
(if (and (floatp width) (<= 0.0 width 2.0))
|
||||
;; A float in [0,2] should be interpereted as this portion of
|
||||
;; the text width in the window. This works well with cases like
|
||||
;; #+attr_latex: :width 0.X\{line,page,column,etc.}width,
|
||||
;; as the "0.X" is pulled out as a float. We use 2 as the upper
|
||||
;; bound as cases such as 1.2\linewidth are feasible.
|
||||
(round (* width
|
||||
(window-pixel-width)
|
||||
(/ (or (and (bound-and-true-p visual-fill-column-mode)
|
||||
(or visual-fill-column-width auto-fill-function))
|
||||
(when auto-fill-function fill-column)
|
||||
(- (window-text-width) (line-number-display-width)))
|
||||
(float (window-total-width)))))
|
||||
width)))
|
||||
((numberp org-image-actual-width)
|
||||
org-image-actual-width)
|
||||
(t nil))))
|
||||
|
||||
(defun org-image--align (link)
|
||||
"Determine the alignment of the image LINK.
|
||||
LINK is a link object.
|
||||
|
||||
In decreasing order of priority, this is controlled:
|
||||
- Per image by the value of `:center' or `:align' in the
|
||||
affiliated keyword `#+attr_org'.
|
||||
- By the `#+attr_html' or `#+attr_latex` keywords with valid
|
||||
`:center' or `:align' values.
|
||||
- Globally by the user option `org-image-align'.
|
||||
|
||||
The result is either nil or one of the strings \"left\",
|
||||
\"center\" or \"right\".
|
||||
|
||||
\"center\" will cause the image preview to be centered, \"right\"
|
||||
will cause it to be right-aligned. A value of \"left\" or nil
|
||||
implies no special alignment."
|
||||
(let ((par (org-element-lineage link 'paragraph)))
|
||||
;; Only align when image is not surrounded by paragraph text:
|
||||
(when (and par ; when image is not in paragraph, but in table/headline/etc, do not align
|
||||
(= (org-element-begin link)
|
||||
(save-excursion
|
||||
(goto-char (org-element-contents-begin par))
|
||||
(skip-chars-forward "\t ")
|
||||
(point))) ;account for leading space
|
||||
;before link
|
||||
(<= (- (org-element-contents-end par)
|
||||
(org-element-end link))
|
||||
1)) ;account for trailing newline
|
||||
;at end of paragraph
|
||||
(save-match-data
|
||||
;; Look for a valid ":center t" or ":align left|center|right"
|
||||
;; attribute.
|
||||
;;
|
||||
;; An attr_org keyword has the highest priority, with
|
||||
;; any attr.* next. Choosing between these is
|
||||
;; unspecified.
|
||||
(let ((center-re ":\\(center\\)[[:space:]]+t\\b")
|
||||
(align-re ":align[[:space:]]+\\(left\\|center\\|right\\)\\b")
|
||||
attr-align)
|
||||
(catch 'exit
|
||||
(org-element-properties-mapc
|
||||
(lambda (propname propval)
|
||||
(when (and propval
|
||||
(string-match-p ":attr.*" (symbol-name propname)))
|
||||
(setq propval (car-safe propval))
|
||||
(when (or (string-match center-re propval)
|
||||
(string-match align-re propval))
|
||||
(setq attr-align (match-string 1 propval))
|
||||
(when (eq propname :attr_org)
|
||||
(throw 'exit t)))))
|
||||
par))
|
||||
(if attr-align
|
||||
(when (member attr-align '("center" "right")) attr-align)
|
||||
;; No image-specific keyword, check global alignment property
|
||||
(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)
|
||||
|
||||
|
|
|
@ -716,14 +716,14 @@ Unfolded Paragraph.
|
|||
(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))
|
||||
|
|
Loading…
Reference in New Issue