org-latex-preview: Skip blank fragments

* lisp/org-latex-preview.el (org-latex-preview--construct-entries,
org-latex-preview-auto--regenerate-overlay): Blank fragments produce
invisible previews, which is at best silly and at worst confusing.  It's
much better to simply not produce a preview image of blank fragments.
We also now avoid exessive re-numbering calculations when repeatadly
generating live previews.
This commit is contained in:
TEC 2024-01-10 14:51:33 +08:00
parent de4fb9de11
commit fdaeb38609
Signed by: tec
SSH Key Fingerprint: SHA256:eobz41Mnm0/iYWBvWThftS0ElEs1ftBr6jamutnXc/A
2 changed files with 137 additions and 83 deletions

View File

@ -789,21 +789,34 @@ image. The preview image is regenerated if necessary."
(overlay-put ov 'display (overlay-get ov 'preview-image)))
(run-hook-with-args 'org-latex-preview-overlay-close-functions ov))))
(defun org-latex-preview-auto--regenerate-overlay (ov)
"Regenerate the LaTeX fragment under overlay OV."
(defun org-latex-preview-auto--regenerate-overlay (ov &optional inhibit-renumbering)
"Regenerate the LaTeX fragment under overlay OV.
When `org-latex-preview-numbered' is non-nil, and the overlay
being updated is for an environment, other numbered environments
will be updated should their numbering change.
Numbering checking and updating can be prevented by setting
INHIBIT-RENUMBERING to a non-nil value."
(with-current-buffer (overlay-buffer ov)
(let* ((fragment (save-excursion
(goto-char (overlay-start ov))
(let* ((start (overlay-start ov))
(end (overlay-end ov))
(fragment (save-excursion
(goto-char start)
(org-element-context)))
(others (and org-latex-preview-numbered
(not inhibit-renumbering)
(eq (org-element-type fragment) 'latex-environment)
(org-latex-preview--get-numbered-environments
(overlay-end ov) nil))))
(org-latex-preview--get-numbered-environments end nil))))
(if (memq (org-element-type fragment)
'(latex-fragment latex-environment))
(org-latex-preview--place-from-elements
org-latex-preview-process-default
(cons fragment others))
(if (org-latex-preview--empty-fragment-p
(org-element-property :value fragment))
(progn (delete-overlay ov)
(org-latex-preview--ensure-overlay start end))
(org-latex-preview--place-from-elements
org-latex-preview-process-default
(cons fragment others)))
(delete-overlay ov)
(when others
(org-latex-preview--place-from-elements
@ -1068,6 +1081,7 @@ BOX-FACE is the face to apply in addition."
(let ((props (get-char-property-and-overlay (point) 'org-overlay-type)))
(and (eq (car props) 'org-latex-overlay)
(cdr props)))))
(image (overlay-get ov 'preview-image))
(end (overlay-end ov)))
(let ((latex-env-p
(progn
@ -1093,8 +1107,7 @@ BOX-FACE is the face to apply in addition."
(concat (and latex-env-p "\n") " "))
(overlay-put ov 'view-text t)
(overlay-put ov 'after-string org-latex-preview-live--docstring)))
(org-latex-preview-live--update-props
(overlay-get ov 'preview-image) '(:box t))))))
(org-latex-preview-live--update-props image '(:box t))))))
(defun org-latex-preview-live--update-overlay (ov)
"Update the live LaTeX preview for overlay OV."
@ -1476,32 +1489,45 @@ protection against placing doubled up overlays."
"Constuct a well formatted list of entries and (optinally) numbering offsets.
This operates by processing ELEMENTS. When CONSTRUCT-NUMBERING-P is non-nil,
the number offsets will also be calculated, using PARSE-TREE if given."
(let* ((numbering-table (and construct-numbering-p
(cl-find 'latex-environment elements
:key #'org-element-type :test #'eq)
(org-latex-preview--environment-numbering-table
parse-tree)))
(numbering-offsets
(and numbering-table
(mapcar
(lambda (element)
(and numbering-table
(eq (org-element-type element) 'latex-environment)
(gethash element numbering-table)))
elements)))
(entries
(mapcar
(lambda (element)
(list (or (org-element-property :post-affiliated element)
(org-element-property :begin element))
(- (org-element-property :end element)
(or (org-element-property :post-blank element) 0)
(if (eq (char-before (org-element-property :end element))
?\n)
1 0))
(org-element-property :value element)))
elements)))
(list entries numbering-offsets)))
(let ((numbering-table (and construct-numbering-p
(cl-find 'latex-environment elements
:key #'org-element-type :test #'eq)
(org-latex-preview--environment-numbering-table
parse-tree)))
entries numbering-offsets)
(dolist (element elements)
(let ((beg (or (org-element-property :post-affiliated element)
(org-element-property :begin element)))
(end (- (org-element-property :end element)
(or (org-element-property :post-blank element) 0)
(if (eq (char-before (org-element-property :end element))
?\n)
1 0)))
(content (org-element-property :value element)))
(push (list beg end content) entries)
(when numbering-table
(push (and (eq (org-element-type element) 'latex-environment)
(gethash element numbering-table))
numbering-offsets))))
(list (nreverse entries) (nreverse numbering-offsets))))
(defun org-latex-preview--empty-fragment-p (content)
"Test if the LaTeX string CONTENT is an empty LaTeX fragment (e.g. \\[\\])."
(let ((content-point 0)
(content-max (1- (length content)))
(only-blanks t))
(cond
((eq (aref content 0) ?$)
(if (eq (aref content 1) ?$)
(setq content-point 2 content-max (- content-max 2))
(setq content-point 1 content-max (- content-max 1))))
((eq (aref content 0) ?\\)
(setq content-point 2 content-max (- content-max 2))))
(while (and only-blanks (<= content-point content-max))
(if (memq (aref content content-point) '(?\s ?\t ?\n ?\r))
(cl-incf content-point)
(setq only-blanks nil)))
only-blanks))
(defun org-latex-preview--place-from-elements (processing-type elements)
"Preview LaTeX math fragments ELEMENTS using PROCESSING-TYPE."
@ -1551,11 +1577,12 @@ is either the substring between BEG and END or (when provided) VALUE."
(org-latex-preview--update-overlay
(org-latex-preview--ensure-overlay beg end)
path-info)
(push (list :string (org-latex-preview--tex-styled
processing-type value options)
:overlay (org-latex-preview--ensure-overlay beg end)
:key hash)
fragment-info))
(unless (org-latex-preview--empty-fragment-p value)
(push (list :string (org-latex-preview--tex-styled
processing-type value options)
:overlay (org-latex-preview--ensure-overlay beg end)
:key hash)
fragment-info)))
(setq prev-fg fg prev-bg bg))))
(when fragment-info
(org-latex-preview--create-image-async

View File

@ -1184,6 +1184,7 @@ This supports two extra properties,
:inline images that should not be saved according to :image-dir,
but instead inlined in the generated HTML. This can be:
- t, to inline all images
- svg, to inline all images, using <svg> with SVGs
- nil, to never inline images
- an extension or list of extensions, for images that
should be inline (e.g. \"svg\")"
@ -3207,54 +3208,80 @@ that an image for ELEMENT already exists within it."
(path-info (or (org-latex-preview--get-cached hash)
(error "Expected LaTeX preview %S to exist in the cache" hash)))
(image-options (plist-get info :html-latex-image-options))
(image-dir (plist-get image-options :image-dir))
(inline-condition (plist-get image-options :inline))
(rescale-factor (if (eq (plist-get (cdr path-info) :image-type) 'svg)
(plist-get image-options :scale)
1))
(image-source
(cond
((or (eq inline-condition 't)
(member (file-name-extension (car path-info))
(org-ensure-list inline-condition)))
(let ((coding-system-for-read 'utf-8)
(file-name-handler-alist nil))
(with-temp-buffer
(insert-file-contents-literally (car path-info))
(base64-encode-region (point-min) (point-max))
(goto-char (point-min))
(insert "data:image/svg+xml;base64,")
(buffer-string))))
((stringp image-dir)
(let* ((image-dir (expand-file-name image-dir))
(image-path (file-name-with-extension
(file-name-concat image-dir (substring hash 0 11))
(file-name-extension (car path-info)))))
(unless (file-directory-p image-dir)
(mkdir image-dir t))
(unless (file-exists-p image-path)
(copy-file (car path-info) image-path))
image-path))
(t (car path-info)))))
(org-html-latex-image--data (car path-info) hash info)))
(unless (and (plist-get (cdr path-info) :height)
(plist-get (cdr path-info) :depth))
(error "Something went wrong during image generation"))
(org-html-close-tag
"img"
(org-html--make-attribute-string
(list :src image-source
:alt (org-html-encode-plain-text
(org-element-property :value element))
:style (if (eq (org-element-type element) 'latex-environment)
(format "height: %.4fem"
(* rescale-factor (plist-get (cdr path-info) :height)))
(format "height: %.4fem; vertical-align: -%.4fem; display: inline-block"
(* rescale-factor (plist-get (cdr path-info) :height))
(* rescale-factor (plist-get (cdr path-info) :depth))))
:class (if (eq (org-element-type element) 'latex-environment)
"org-latex org-latex-environment"
"org-latex org-latex-fragment")))
info)))
(if (and (eq (plist-get image-options :inline) 'svg)
(string= (file-name-extension (car path-info)) "svg"))
image-source
(org-html-close-tag
"img"
(org-html--make-attribute-string
(list :src image-source
:alt (org-html-encode-plain-text
(org-element-property :value element))
:style (if (eq (org-element-type element) 'latex-environment)
(format "height: %.4fem"
(* rescale-factor (plist-get (cdr path-info) :height)))
(format "height: %.4fem; vertical-align: -%.4fem; display: inline-block"
(* rescale-factor (plist-get (cdr path-info) :height))
(* rescale-factor (plist-get (cdr path-info) :depth))))
:class (if (eq (org-element-type element) 'latex-environment)
"org-latex org-latex-environment"
"org-latex org-latex-fragment")))
info))))
(defun org-html-latex-image--data (source-file hash info)
"Obtaine the image source for SOURCE-FILE as a string, based on HASH and INFO.
This can take the form of a path, data URI, or <svg> element."
(let* ((image-options (plist-get info :html-latex-image-options))
(inline-condition (plist-get image-options :inline))
(image-dir (plist-get image-options :image-dir)))
(cond
((or inline-condition
(member (file-name-extension source-file)
(org-ensure-list inline-condition)))
(let ((coding-system-for-read 'utf-8)
(file-name-handler-alist nil))
(with-temp-buffer
(insert-file-contents-literally source-file)
(cond
((and (eq inline-condition 'svg)
(string= (file-name-extension source-file) "svg"))
(buffer-string))
((string= (file-name-extension source-file) "svg")
;; Modelled after <https://codepen.io/tigt/post/optimizing-svgs-in-data-uris>.
(concat "data:image/svg+xml,"
(url-hexify-string
(subst-char-in-string ?\" ?\' (buffer-string))
'(?a ?b ?c ?d ?e ?f ?g ?h ?i ?j ?k ?l ?m ?n
?o ?p ?q ?r ?s ?t ?u ?v ?w ?x ?y ?z ?A ?B
?C ?D ?E ?F ?G ?H ?I ?J ?K ?L ?M ?N ?O ?P
?Q ?R ?S ?T ?U ?V ?W ?X ?Y ?Z ?0 ?1 ?2 ?3
?4 ?5 ?6 ?7 ?8 ?9 ?- ?_ ?. ?~
;;Special additions
?\s ?= ?: ?/))))
(t
(base64-encode-region (point-min) (point-max))
(goto-char (point-min))
(insert "data:image/" (file-name-extension source-file) ";base64,")
(buffer-string))))))
((stringp image-dir)
(let* ((image-dir (expand-file-name image-dir))
(image-path (file-name-with-extension
(file-name-concat image-dir (substring hash 0 11))
(file-name-extension source-file))))
(unless (file-directory-p image-dir)
(mkdir image-dir t))
(unless (file-exists-p image-path)
(copy-file source-file image-path))
image-path))
(t source-file))))
;;;; Line Break