Compare commits

...

151 Commits

Author SHA1 Message Date
TEC 3edac8fcc6
---END PERSONAL NOPUSH DIVIDER---
--
2.42.0
2024-01-30 13:37:20 +08:00
TEC ed9893898f
NOPUSH org: Don't fill displayed equations in text
* list/org.el (org-fill-element): If a displayed equation (\[ ... \])
starts on its own line, it should not be filled into the rest of the
text. I.e.,

some nice text
\[
  1+1=2
\]
more text.

should not become,

some nice text \[ 1+1=3 \] more text.

While the above example may not look bad, with non-trivial equations
this can become quite messy.
2024-01-30 13:37:20 +08:00
TEC 579f748af9
NOPUSH org-src: Prettify inline results
* lisp/org.el (org-inline-src-prettify-results):

* lisp/org-src.el (org-fontify-inline-src-blocks-1):
2024-01-30 13:37:20 +08:00
TEC c9a8f74cbe
---NOPUSH PERSONAL DIVIDER---
--
2.42.0
2024-01-30 13:37:20 +08:00
TEC f308ecfbab
org-latex-preview: Take advantage of dvisvgm3.2
* lisp/org-latex-preview.el (org-latex-preview--tex-styled,
org-latex-preview--dvisvgm-filter,
org-latex-preview--dvisvgm-version>=3.1,
org-latex-preview-process-alist,
org-latex-preview--dvisvgm3-minor-version): Take advantage of the new
--message flag of dvisvgm 3.2 to produce a more concise output.
2024-01-30 13:37:12 +08:00
TEC b49cefc7ea
ox-html: Allow inlining svg tex as <svg> elements
* lisp/ox-html.el (org-html-latex-image--data, org-html-latex-image):
Add support for inlining dvisvgm-exported svgs as <svg> elements,
preserving the effect of the currentColor attribute.  While making this
change, we improve a few other aspects of the html LaTeX fragment export
system, namely refactoring/code style improvements and the recognition
of \[...\] and $$...$$ fragments as blocks not inline fragments.
2024-01-30 13:37:12 +08:00
TEC 8284cec27e
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.
2024-01-30 13:37:12 +08:00
TEC fee79ce34f
org-latex-preview: Accommodate a flaky cache
* lisp/org-latex-preview.el (org-latex-preview--get-cached): When using
persist, occasionally we need to be more careful about assuming that
cache entries exist.
2024-01-30 13:37:12 +08:00
TEC 775ed43c90
org-latex-preview: Tweak to be rebased later
* lisp/org-latex-preview.el (org-latex-preview--cache-image):
2024-01-30 13:37:12 +08:00
Karthik Chikmagalur 43b925a712
org-latex-preview: Handle html export preview fail
* lisp/org-latex-preview.el (org-latex-preview--check-all-fragments-produced):
This function assumes that previews are being generated for placement in
the buffer.  Handle the case of preview generation for HTML exports.
2024-01-30 13:37:12 +08:00
TEC 5ee791d0af
org-latex-preview: Fix face selection Emacs 28 bug
* lisp/org-latex-preview.el (org-latex-preview--face-around): On Emacs
28 (and presumably below), should a face with :extend set be identified
as appropriate, the overlay may cast a pall (background colour) over the
rest of the line.  This can be addressed by replacing the use of the
default face to normalise display with an anonymous face that inherits
from default and has the :extend attribute set.

Reported-by: Roshan Shariff <roshan.shariff@gmail.com>
Link: https://list.orgmode.org/CAG8iPGxoAD7qmKzDXQ_SRFbmxD7jdM96piCa-dCSCpzae4rCsw@mail.gmail.com
2024-01-30 13:37:12 +08:00
TEC 21476abcce
ox-html: Support for customised latex image dir
* lisp/ox-html.el (org-html-latex-image, org-html-prepare-latex-images,
org-html-latex-image-options): Allow for customising the LaTex image
directory in `org-html-latex-image-options'.
2024-01-30 13:37:12 +08:00
TEC dccc392855
org-latex-preview: Rework general cache variable
* lisp/org-latex-preview.el (org-latex-preview--get-cached,
org-latex-preview--table, org-latex-preview-persist,
org-latex-preview-cache): Rename and tweak `org-latex-preview-persist'
to also allow for caching to a custom directory, and (in the near
future) unify behaviour with HTML export.

* testing/lisp/test-org-latex-preview.el: Accommodate for the cache variable
change.

* etc/ORG-NEWS: Accommodate for the cache variable change.
2024-01-30 13:37:12 +08:00
TEC f9772da05c
org-latex-preview: Add ignored auto environments
* lisp/org-latex-preview.el (org-latex-preview-live--src-buffer-setup,
org-latex-preview-auto--maybe-track-element-here,
org-latex-preview-auto-ignored-environments): Introduce a new
customisation variable `org-latex-preview-auto-ignored-environments',
for specifying environments that should not be automatically previewed.
2024-01-30 13:37:12 +08:00
Karthik Chikmagalur 45cedee0a9
org-latex-preview: Dynamic throttle for live previews
* lisp/org-latex-preview.el (org-latex-preview-live--throttle,
org-latex-preview-live-throttle,
org-latex-preview-live--preview-times,
org-latex-preview-live--update-times,
org-latex-preview-live--record-hook,
org-latex-preview-live--regenerate,
org-latex-preview-live--update-props,
org-latex-preview-live--src-buffer-setup,
org-latex-preview-live--setup, org-latex-preview-live--teardown,
org-latex-preview--create-image-async): Find the optimal throttle
time for live preview updates dynamically.  The variable
`org-latex-preview-live--preview-times' records the last three
process run times, and `org-latex-preview-live-throttle' is set to
the average of these.  This ensures that there are never more than
two concurrent processes live-previewing a single fragment.  Start
another preview run process the end of the throttle period if the
preview image is out of date to ensure that the state of the
preview is eventually consistent with the contents of the
fragment.
2024-01-30 13:37:12 +08:00
TEC 72b829cd90
org-latex-preview: Adjust customisation scheme
* lisp/org-latex-preview.el (org-latex-preview-live--teardown,
org-latex-preview-live--setup, org-latex-preview-live--src-buffer-setup,
org-latex-preview-live--ensure-overlay, org-latex-preview-throttle,
org-latex-preview-debounce, org-latex-preview-live-preview-inline,
org-latex-preview-auto--open-this-overlay,
org-latex-preview-auto--detect-fragments-in-change,
org-latex-preview-auto--handle-post-cursor,
org-latex-preview--face-around, org-latex-preview-auto-generate,
org-latex-preview-auto-blacklist, org-latex-preview-clear-cache,
org-latex-preview--latex-preview-filter,
org-latex-preview--create-tex-file,
org-latex-preview--create-image-async, org-latex-preview--hash,
org-latex-preview--auto-aware-toggle, org-latex-preview--preview-region,
org-latex-preview-live--teardown, org-latex-preview-live--setup,
org-latex-preview-live--src-buffer-setup,
org-latex-preview-live--ensure-overlay,
org-latex-preview-auto--regenerate-overlay,
org-latex-preview-auto--close-previous-overlay,
org-latex-preview-auto--open-this-overlay,
org-latex-preview-auto--detect-fragments-in-change,
org-latex-preview--update-overlay,
org-latex-preview--indicate-processing, org-latex-preview-precompile,
org-latex-preview-open-functions, org-latex-preview-close-functions,
org-latex-preview-update-overlay-functions,
org-latex-preview-auto-command-blacklist,
org-latex-preview-processing-indicator,
org-latex-preview-default-process): Change the customisation naming
scheme to be more consistent.

* testing/lisp/test-org-latex-preview.el: Change the LaTeX preview
customisation naming scheme to be more consistent.

* lisp/org-compat.el: Change the LaTeX preview customisation naming
scheme to be more consistent.

* etc/ORG-NEWS: Change the LaTeX preview customisation naming scheme to
be more consistent.

* doc/org-manual.org (Footnotes, Previewing LaTeX fragments): Change the
LaTeX preview customisation naming scheme to be more consistent.
2024-01-30 13:37:12 +08:00
TEC 4e9d89a431
ox-latex: Introduce \codefont command
* lisp/ox-latex.el (org-latex-engraved-preamble): Make it easier to
customise the font used in engraved Code environments with a \codefont
command (defaulting to \footnotesize).
2024-01-30 13:37:12 +08:00
TEC ea636c27d2
ox-latex: Use more robust engraved theme grouping
* lisp/ox-latex.el (org-latex-src--engrave-code): Use of curly brackets
for grouping has a few edge-cases which \begingroup-\endgroup should not
suffer from.
2024-01-30 13:37:12 +08:00
TEC 96c0c34875
ox-latex: Better handle multiple engraved themes
* lisp/ox-latex.el (org-latex-generate-engraved-preamble): Improve the
generated LaTeX code in the multiple-themes case. Using "\long\def"
instead of "\newcommand" mixed with "\renewcommand" is needed without
without duplicating the default theme.  The "\efstrut" command also
needs to be extracted out of the theme-generated commands, which was
previously overlooked.
2024-01-30 13:37:12 +08:00
TEC cf3c6152ee
ox-latex: Fix engraved-theme propagation
* lisp/ox-latex.el (org-latex-src-block--engraved,
org-latex-src--engrave-code, org-latex-inline-src-block--engraved):
Actually propagate the ":latex-engraved-theme" property through to the
`org-latex-src--engrave-code` call.  To account for whether the theme is
the default theme, or whether it will need to be explicitly switched to,
a new indicator argument ("explicit-theme-p") has been added to
`org-latex-src--engrave-code`.
2024-01-30 13:37:12 +08:00
TEC 34891ff59e
ol: more versatile #+link replacement forms (WIP)
* lisp/ol.el (org-link-expand-abbrev, org-link--abbrev-functions): Allow
link abbreviations to use %s and %h as format-specs, as well as allowing
an anonymous function form with %(sexpr using tag).
2024-01-30 13:37:12 +08:00
TEC 07545b4ca4
org: Introduce semantic seperator fontification
* lisp/org.el (org-fontify-semantic-seperator,
org-set-font-lock-defaults): TODO
2024-01-30 13:37:12 +08:00
TEC 5553b040fb
ox-html: Fix C++ label CSS
* lisp/ox-html.el (org-html-style-default): The "C++" pre-label works if
the "+" characters are backslash-escaped.
2024-01-30 13:37:12 +08:00
TEC 34f0dd395d
---PATCH SET DIVIDER---
--
2.42.0
2024-01-30 13:37:12 +08:00
TEC 5b6b97a264
org-latex-preview: Formatting and spacing tweaks
* lisp/org-latex-preview.el (org-latex-preview--dvipng-filter,
org-latex-preview--latex-preview-filter,
org-latex-preview--create-tex-file,
org-latex-preview--create-image-async,
org-latex-preview--get-numbered-environments,
org-latex-preview-live--setup,
org-latex-preview-live--update-overlay-run,
org-latex-preview-auto--detect-fragments-in-change,
org-latex-preview--update-overlay): Adjust formatting/spacing.
2024-01-30 13:37:12 +08:00
Karthik Chikmagalur 5caf6d9e91
org-latex-preview: Live previews in org-src bufs
* lisp/org-latex-preview.el (org-latex-preview-live--src-buffer-setup):
When live previews are enabled in an Org buffer and using org-src
buffers to edit LaTeX fragments (via `org-edit-special'), show
continuously updated previews in the source Org buffer if it is
visible.  If it is not visible, show continuously updated previews
in the org-src buffer.
2024-01-30 13:37:12 +08:00
Karthik Chikmagalur bf3f7e3c02
org-latex-preview: Eldoc support for live previews
* lisp/org-latex-preview.el (org-latex-preview-live-display-type,
org-latex-preview-live--display-in-eldoc,
org-latex-preview-live--update-eldoc,
org-latex-preview-live--setup, org-latex-preview-live--teardown):
Add Eldoc support for live previews.  The user option
`org-latex-preview-live-display-type' now accepts the symbols
buffer and eldoc as values.  When it is set to eldoc and live
previews are enabled, display of the continuously updated previews is
handled by Eldoc.  Note that previewing larger images with Eldoc may
require `eldoc-echo-area-use-multiline-p' and `max-mini-window-height'
to be set appropriately.
2024-01-30 13:37:12 +08:00
Karthik Chikmagalur d4d050380a
org-latex-preview: Add support for live previews
* lisp/org-latex-preview.el (org-latex-preview-auto-generate,
org-latex-preview-live-preview-inline, org-latex-preview-throttle,
org-latex-preview-debounce, org-latex-preview-live-display-type,
org-latex-preview-live--debounce,
org-latex-preview-live--throttle,
org-latex-preview-live--clearout,
org-latex-preview-live--regenerate,
org-latex-preview-live--update-props,
org-latex-preview-live--ensure-overlay,
org-latex-preview-live--update-overlay,
org-latex-preview-live--setup, org-latex-preview-live--teardown,
org-latex-preview-live--docstring,
org-latex-preview-live--element-type,
org-latex-preview-live--generator,
org-latex-preview--ensure-overlay,
org-latex-preview--failure-callback,
org-latex-preview--svg-make-fg-currentColor): Add support for
live-previewing LaTeX fragments.  When
`org-latex-preview-auto-generate' is set to the symbol live and
`org-latex-preview-auto-mode' is turned on, LaTeX previews are
continuously updated when editing a LaTeX fragment.  These
previews are shown to the right of or below the fragment.  The
preview generation timing can be controlled using the options
`org-latex-preview-debounce' and `org-latex-preview-throttle'.
2024-01-30 13:37:12 +08:00
TEC d4d644c2e2
---LIVE PREVIEW DIVIDER--- 2024-01-30 13:37:12 +08:00
TEC 1652e5402c
org-latex-preview: Update copyright years 2024-01-30 13:37:12 +08:00
TEC 45de17ef08
org-latex-preview: Put :page-width in opt plist
* lisp/org-latex-preview.el (org-latex-preview-options,
org-latex-preview-appearance-options): Rename
`org-latex-preview-options' to `org-latex-preview-appearance-options',
as it better reflects the purpose of the variable.

(org-latex-preview--tex-styled, org-latex-preview--image-extract-async,
org-latex-preview--create-tex-file,
org-latex-preview--create-image-async, org-latex-preview--hash,
org-latex-preview-place, org-latex-preview--update-overlay): Put the
page width specification in `org-latex-preview-appearance-options', and
adjust existing code to handle this new structuring.

* lisp/ox-html.el (org-html-prepare-latex-images,
org-html-latex-image-options): Adjust for the
`org-latex-preview-appearance-options' rename, and put :page-width in
the options plist, just with a raised value of 1.0 as the HTML default.

* lisp/org.el (org-do-latex-and-related, org-latex-preview-options),
org-compute-latex-and-related-regexp): Adjust for the
`org-latex-preview-appearance-options' rename.

* lisp/org-compat.el: Adjust for the
`org-latex-preview-appearance-options' rename.

* lisp/ob-latex.el (org-babel-execute:latex, org-latex-preview-header)):
Adjust for the `org-latex-preview-appearance-options' rename.

* etc/ORG-NEWS: Adjust for the `org-latex-preview-appearance-options'
rename.

* doc/org-manual.org (Previewing LaTeX fragments): Adjust for the
`org-latex-preview-appearance-options' rename.
2024-01-30 13:37:12 +08:00
Karthik Chikmagalur 787508d284
org-latex-preview: Fix preview help-echo property
* lisp/org-latex-preview.el (org-latex-preview--update-overlay):
Add LaTeX compilation errors to the help-echo property when the
cursor is inside the fragment that is being previewed.  This
primarily affects the use of `org-latex-preview-auto-mode`.
2024-01-30 13:37:12 +08:00
TEC 0c5b3c29c7
org-latex-preview: Improved face heuristics
* lisp/org-latex-preview.el (org-latex-preview--face-around): To work
around issues where syntax highlighting of the underlying LaTeX fragment
interferers with the foreground colour of the preview, we append default
to the face list regardless.

(org-latex-preview--ignored-faces): While we're improving face
heuristics, it's also come to my attention that whitespace-mode can
interferer with face selection, and whitespace-mode should also be
ignored.  Perhaps this should become part of the API?
2024-01-30 13:37:12 +08:00
TEC 1354b2d084
org-latex-preview: Support symbol entrypoint args
* lisp/org-latex-preview.el (org-latex-preview): Refactor to support a
symbol-value "mode" argument as well as prefix arguments.  This stops
forcing programmatic invocations from having to use uninformative
values, and actually makes the implementation slightly nicer to read I
think.

* lisp/org.el: Change the argument in the preview startup invocation to 'buffer.
2024-01-30 13:37:12 +08:00
TEC eddf27e32f
org-latex-preview: Robustify DPI calculation
* lisp/org-latex-preview.el (org-latex-preview--get-display-dpi): It was
reported that on a WSLg system using pgtk that
`org-latex-preview--get-display-dpi' produced an arithmetic overflow
error.  Inspecting the calculation performed and docstrings of functions
involved, it seems we need to be more careful of the `display-mm-height'
output.  We now guard against it being zero or nil, which should make
the DPI calculation more robust.

Simply falling back to a guessed DPI of 140 is non-ideal, but probably
the best we can reasonably do here.
2024-01-30 13:37:12 +08:00
TEC a76be67517
org-latex-preview: Guard against deleted buf/ov
* lisp/org-latex-preview.el (org-latex-preview--place-images): Since the
image generation and placement is asynchronous, it is possible that in
the meantime the target overlay or even buffer could be deleted.  To
avoid errors, we simple check that this is not the case before
attempting to place preview images.
2024-01-30 13:37:12 +08:00
TEC 90bee079e0
org-latex-preview: Still show errs with no tooltip
* lisp/org-latex-preview.el (org-latex-preview--update-overlay): When
`tooltip-mode' is not active, still show the error, just remove multiple
spaces to be economic with the horizontal room available.  This isn't
good as showing the tooltip, but it's better than not showing anything.
2024-01-30 13:37:12 +08:00
TEC 9a36397a75
org-macs: Set some process variables in org-async
* lisp/org-macs.el (org-async-call): When eking out maximum performance
from external commands, there are a few potentially important process
variables. `org-async-call' is extended to support setting these, with
default values that differ from Emacs' defaults but should enable better
performance in general.
2024-01-30 13:37:12 +08:00
TEC d3c1243a60
org-latex-preview: Mention latex buffer if no dvi
* lisp/org-latex-preview.el (org-latex-preview--failure-callback,
org-latex-preview--create-image-async): When the image conversion step
fails due to a missing input file, point the user to the LaTeX output
buffer instead of the image conversion output buffer.
2024-01-30 13:37:12 +08:00
TEC dd4d16b886
org-latex-preview: Include running command in bufs
* lisp/org-latex-preview.el (org-latex-preview--image-extract-async,
org-latex-preview--tex-compile-async): Add a comment at the start of the
process output buffers mentioning what the command being run is.
2024-01-30 13:37:12 +08:00
TEC 6259461f04
org-latex-preview: Simplify color formatting
* lisp/org-latex-preview.el (org-latex-preview--format-color,
org-latex-preview--normalize-color): Use three decimal places, and
remove the now-obsolete `org-latex-preview--normalize-color'.

* lisp/org-compat.el (org-normalize-color): With the removal of the
`org-latex-preview--normalize-color' alias, mark `org-normalize-color'
as obsolete.
2024-01-30 13:37:12 +08:00
TEC a8f3357bff
org-latex-preview: Use dvisvgm 3.1+ currentcolor
* lisp/org-latex-preview.el (org-latex-preview--tex-styled,
org-latex-preview--svg-make-fg-currentColor,
org-latex-preview--dvisvgm-filter,
org-latex-preview--dvisvgm-version>=3.1): With dvisvgm 3.1+, it can
replace the foreground color with "currentColor" itself, and so we can
skip `org-latex-preview--svg-make-fg-currentColor' when we are using a
new enough dvisvgm.

(org-latex-preview--await-fragment-existance): Just in case the
asyncronicity in file writing causes issues, we keep the file existence
check (for now).
2024-01-30 13:37:12 +08:00
TEC f99b1a320a
org-latex-preview: Improve env numbering calc
* lisp/org-latex-preview.el (org-latex-preview--get-numbered-environments,
org-latex-preview--environment-numbering-table): Make numbering
calculations more accurate, at the expense of a ~10x increase in the
time to calculate numbering in a document, mitigated by the use of
caching — resulting in a ~2x improvement compared to the simpler method
in subsequent runs.

(org-latex-preview--numbered-environments,
org-latex-preview--numbered-environments-single,
org-latex-preview--numbered-environments-multi,
org-latex-preview--numbered-environments-all): Split
`org-latex-preview--numbered-environments' into
`org-latex-preview--numbered-environments-single' and
`org-latex-preview--numbered-environments-multi', then rename
`org-latex-preview--numbered-environments' to
`org-latex-preview--numbered-environments-all' for the sake of clarity.

Determining the count of numbered equations in a LaTeX environment is
non-trivial.  Previously, a simple heuristic was used that counted the
number of lines ending with "\\" in particular environments, then
subtracted the number of "\nonumber" and "\tag{...}" instances.

However, lines can end with "\\" without contributing to the number of
equations in the environment, consider the "cases" and "bmatrix"
environments.  To improve the heuristic, we (with some care) remove
/all/ inner environments from the LaTeX maths environment before
processing.  Since this takes more effort, we split the numbered
environments into those we know will contain exactly one numbered
equation where we can avoid the extra processing, and those that require
the more sophisticated heuristics.

The new org-element caching API is very helpful for recovering the
performance cost of this extra computation in the long run.
2024-01-30 13:37:12 +08:00
Karthik Chikmagalur 2b40ffef8d
org-latex-preview: Fix process filter timing errs
* lisp/org-latex-preview.el (org-latex-preview--create-image-async,
org-latex-preview--latex-preview-filter,
org-latex-preview--dvipng-filter, org-latex-preview--dvisvgm-filter,
org-latex-preview--place-images): The dvipng and latex-preview filters
run concurrently (interleaved), and both contribute image metadata.
So caching/placing images cannot be associated with the dvipng filter,
this leads to non-deterministic errors where preview images can have
incomplete metadata.  To fix this, check if we are using dvipng when
running the LaTeX filter, and place images from whichever of the two
filters processes each fragment second.

Refactor: Move the image placement/caching logic fully to
`org-latex-preview--place-images' instead of duplicating code in all
three (latex-filter, dvipng and dvisvgm) previews.
2024-01-30 13:37:12 +08:00
Karthik Chikmagalur 65bb5ed444
org-latex-preview: Fix LaTeX header on fails + reruns
*
lisp/org-latex-preview.el (org-latex-preview--check-all-fragments-produced):
When rerunning a preview run (because of catastrophic failures), pass
the LaTeX header used to the new process.  The current behavior passes
an empty header, which causes the process to fail again.
2024-01-30 13:37:12 +08:00
Karthik Chikmagalur 3fc5787831
org-latex-preview: Fix xelatex preview image sizes
*
lisp/org-latex-preview.el (org-latex-preview--include-preview-string,
org-latex-preview--latex-preview-filter):  when xetex is used,
preview.sty assumes PDF output by default and does not write any
postscript data to the output XDV file.  This makes dvisvgm unable to
correctly determine the preview geometry.  Fix by specifying the
`dvips' option to preview, which adds (apparently as a side effect)
this geometry information to the XDV file.

Remove a conditional in `org-latex-preview--latex-preview-filter' that
was previously used to attempt to work around this issue.
2024-01-30 13:37:12 +08:00
Karthik Chikmagalur c185a6dddb
ox-latex: Disable precompile for xelatex/lualatex
* lisp/ox-latex.el (org-latex-make-preamble): If xelatex or
lualatex are used for LaTeX export, disable LaTeX header
precompilation (via the CTAN package mylatexformat) locally in the
buffer and issue a warning.  Xelatex does not support
precompilation, and while Lualatex supports it in some cases, it
is best left unsupported by the Org LaTeX export process until
precompilation support for them improves upstream.

* lisp/org-latex-preview.el (org-latex-preview--create-tex-file):
Make the same changes as above when precompiling LaTeX headers
for LaTeX preview purposes.
2024-01-30 13:37:12 +08:00
Karthik Chikmagalur 934a68eb26
org-latex-preview: Rename precompilation vars
* lisp/org-latex-preview.el (org-latex-preview-precompile,
org-latex-preview--latex-preview-filter,
org-latex-preview--create-tex-file,
org-latex-preview-use-precompilation, org-latex-preview--precompile):
Rename (i) the user option that controls precompilation for LaTeX
previews, and (ii) the function that precompiles headres for LaTeX
previews.  This makes the names shorter and consistent with their
corresponding equivalents in `ox-latex'.

Rename
`org-latex-preview-use-precompilation' -> `org-latex-preview-precompile'
`org-latex-preview-precompile' -> `org-latex-preview--precompile'

The new names have equivalents `org-latex-precompile' and
`org-latex--precompile' in `ox-latex'.

* testing/lisp/test-org-latex-preview.el: Update tests that set this
user option.

* etc/ORG-NEWS: Update the NEWS file.
2024-01-30 13:37:12 +08:00
Karthik Chikmagalur ab1229e88b
org-latex-preview: Fix bug clearing precompile cache
* lisp/org-latex-preview.el (org-latex-preview-clear-cache,
org-latex-preview--create-tex-file,
org-latex-preview--include-preview-string): LaTeX headers that are
precompiled include additional strings that set the
textwidth (according to `org-latex-preview-width') and include
preview.sty.  These strings are not appended to the header when
trying to clear the precompile cache for the present buffer.  Fix
by (i) removing the textwidth declaration from the precompiled
text, and (ii) including the preview.sty inclusion string with the
header we look for when trying to remove the corresponding fmt
file in the org-persist cache.

org-latex-preview--include-preview-string: Introduce string that
holds the text to include preview.sty in the document header.
2024-01-30 13:37:12 +08:00
Karthik Chikmagalur 784d7caa3c
org-latex-preview: Reduce delay when re-rendering
*
lisp/org-latex-preview.el (org-latex-preview-auto--close-previous-overlay):
Reduce the delay when re-rendering fragments (with `org-latex-preview-auto-mode' turned
on) from 50 ms to 10 ms. This delay is a heuristic number for
perceived smoothness, and this change represents a tuning effort.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur ef3788cc65
org-latex-preview: Change preview hashing parameters
* lisp/org-latex-preview.el (org-latex-preview--hash): Use only the
`:scale' parameter from `org-latex-preview-options' when hashing
fragments.  Other parameters like `:zoom' do not affect the content of
the image, so this helps avoid building up garbage in the org-persist
cache.  `org-latex-preview' is also faster since re-rendering images
is required less often.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur 3bf3baf4ab
org-latex-preview: Change hooks to abnormal hooks
*
lisp/org-latex-preview.el (org-latex-preview-auto--close-previous-overlay,
org-latex-preview-auto--open-this-overlay,
org-latex-preview-close-hook, org-latex-preview-open-hook): Change
`org-latex-preview-open-hook' and `org-latex-preview-close-hook' to
abnormal hooks that accept an overlay as the argument.  This makes it
easier to apply overlay-specific changes -- which is what these hooks
are primarily for -- without having to find the overlay by probing the
buffer first.

Rename:
`org-latex-preview-open-hook' to `org-latex-preview-open-functions'
`org-latex-preview-close-hook' to `org-latex-preview-close-functions'
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur 8af00eba7e
org-latex-preview: Fix clear-cache command
* lisp/org-latex-preview.el (org-latex-preview-clear-cache): When
clearing the preview cache, clear the cached preamble after clearing
the image cache, since the preamble is used to compute the image
hashes.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur 08836fb076
test-org-latex-preview: Add preliminary tests
* testing/lisp/test-org-latex-preview.el: Tests for
org-latex-preview.el.

* testing/examples/org-latex-preview-test.org: Short but
full-featured document with LaTeX fragments to run tests on.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur 8c0a05c797
org-latex-preview: Don't fully reset overlay state
* lisp/org-latex-preview.el (org-latex-preview--ensure-overlay,
org-latex-preview--update-overlay): When ensuring a preview overlay
exists, do not fully reset the state of the overlay, such as the
stored image spec, the flag that checks if the preview is open, etc.
Persisting prior state is required for the "live" preview
feature (introduced in the following commits) to function.  Similarly,
if "live" previewing a LaTeX element that has an overlay attached, do
not set the overlay face or error display indicator(s).
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur 0e95d16a33
org-latex-preview: Add hooks for customization
*
lisp/org-latex-preview.el (org-latex-preview-process-finish-functions,
org-latex-preview-update-overlay-hook,
org-latex-preview-close-hook,
org-latex-preview-open-hook,
org-latex-preview--create-image-async,
org-latex-preview-auto--handle-post-cursor,
org-latex-preview--run-finish-functions): Add four hooks for
better control of the LaTeX preview process.

`org-latex-preview-process-finish-functions': Runs after the image
conversion process. This is an abnormal hook: each hook function
accepts the same arguments as other `org-async' callbacks for this
process.

`org-latex-preview-close-hook' and `org-latex-preview-open-hook':
Run after a preview is closed (text hidden to reveal image) or
opened (image hidden to reveal text) respectively.

`org-latex-preview-update-overlay-functions': Run after a LaTeX
preview overlay is updated with a new image.  This is an abnormal
hook: each hook function accepts one argument, the overlay that was
updated.

The "live" preview system introduced in the following commits uses
these hooks, along with the facilities provided by
`org-latex-preview-auto-mode'.  In addition, these hooks will
prove useful when writing code that reuse the API afforded by
`org-latex-preview-place' to provide LaTeX previews for other
major modes.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur 2a52e43301
org-latex-preview: Option to fine-tune preview opening
* lisp/org-latex-preview.el (org-latex-preview-auto-blacklist,
org-latex-preview-auto--open-this-overlay): Add a blacklist for commands
that should not cause LaTeX preview overlays to be "opened", i.e. for
preview images to be hidden and text revealed when using
`org-latex-preview-auto-mode'.  A common use case would be cursor
navigation commands like `next-line' or `scroll-up-command' that are
often intended to move the view of the buffer, where opening preview
overlays can be distracting.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur d84aff830a
org-latex-preview: Fix overlay boundary deletion bug
*
lisp/org-latex-preview.el (org-latex-preview-auto--regenerate-overlay):
When `org-latex-preview-auto-mode' is active and a LaTeX fragment
or environment boundary is deleted,
`org-latex-preview-auto--regenerate-overlay' generates a new
preview for the new org-element at point, which is no longer a
LaTeX fragment or environment.  This results in paragraph text or
other syntax being captured into the preview.  Fix by adding a
check to ensure that the element post-change is still a LaTeX
fragment or environment.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur 453363cb77
org-latex-preview: non-buffer-local auto-marker bug
* lisp/org-latex-preview.el (org-latex-preview-auto--marker,
org-latex-preview-auto-mode): `org-latex-preview-auto--marker' is
initialized to a marker, which can cause it to not be
buffer-local.  Instead, initialize it to nil and explicitly set it
to a marker when running `org-latex-preview-auto-mode'.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur e10b8b9a02
org-latex-preview: Fix startup preamble generation
* lisp/org-latex-preview.el (org-latex-preview--get-preamble):
When `org-startup-with-latex-preview' (or the `#+startup:
latexpreview') option is set, preamble generation and
precompilation fail as latex previews are generated in the clone
of the current buffer created by `org-export-with-buffer-copy'.
This is because org-mode is turned on in the cloned buffer, which
requires creating LaTeX previews there.  Not only is this
unnecessary, it causes a flurry of errors since the cloned buffer
is killed before the previews can be placed.  Explicitly avoid
org-startup-* tasks in the cloned buffer when generating the LaTeX
preamble for our main Org buffer.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur 8274613308
org-latex-preview: Ensure fmt file cache is cleared
* lisp/org-latex-preview.el (org-latex-preview-clear-cache): When
running `org-latex-preview-clear-cache', the precompiled format
file is only removed from the `org-persist' cache if the preamble
has been cached in the current buffer.  We require the format file
to always be unregistered from the cache, so generate the preamble
if necessary so it can be hashed and used as the key to find the
corresponding format file in the cache.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur b4904f8617
org-latex-preview: Optimize overlay-modify hook
*
lisp/org-latex-preview.el (org-latex-preview-auto--mark-overlay-modified):
Reduce slightly the number of checks needed to run each time text
inside a LaTeX fragment overlay is modified.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur ba691a0c12
Update ORG-NEWS
* etc/ORG-NEWS: Add summary of `org-latex-preview' changes.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur d92210ed0e
org-manual: Update LaTeX preview section
* doc/org-manual.org (Previewing LaTeX fragments): Mention newly
added user options and `org-latex-preview-auto-mode'.
2024-01-30 13:37:11 +08:00
TEC e100ec8f26
ox-html: Allow inlining of LaTeX images
* lisp/ox-html.el (org-html-latex-image, org-html-latex-image-options):
Add a new `org-html-latex-image-options' keyword, ":inline", which
controls image inlining in `org-html-latex-image'.
2024-01-30 13:37:11 +08:00
TEC 0ab7cebbe2
org-latex-preview: Emit warning when hyperref seen
* lisp/org-latex-preview.el (org-latex-preview--latex-preview-filter):
If during LaTeX compilation hyperref seems to be present, emit a warning
mentioning the sizing issue it is known to cause.
2024-01-30 13:37:11 +08:00
TEC 23578e25a1
org-latex-preview: Add preview-order eqn numbering
* lisp/org-latex-preview.el (org-latex-preview--tex-styled,
org-latex-preview-numbered): Allow for preview-order based equation
numbering, by setting `org-latex-preview-numbered' to the symbol
"preview".
2024-01-30 13:37:11 +08:00
TEC c65e9ad180
org-latex-preview: Use icon for non-numbered eqns
* lisp/org-latex-preview.el (org-latex-preview--get-preamble,
org-latex-preview--single-eqn-format): When numbering is turned off (via
`org-latex-preview-numbered'), instead of always showing "(1)" as the
equation number, use a diamond symbol, and in multiline environments
show +offset.  The LaTeX setup for this is stored in the new const
`org-latex-preview--single-eqn-format'.
2024-01-30 13:37:11 +08:00
TEC 5b8286f45b
org-latex-preview: Fix snippet preamble hash
* lisp/org-latex-preview.el (org-latex-preview--create-tex-file,
org-latex-preview--hash, org-latex-preview-place,
org-latex-preview-clear-cache): The only the default preamble was being
hashed, which led to incorrect results across documents.  To correctly
hash the preamble, it is now determined at the start of
`org-latex-preview-place', and used in `org-latex-preview--hash',
`org-latex-preview--create-tex-file', and
`org-latex-preview-clear-cache'.
2024-01-30 13:37:11 +08:00
TEC 530b63464c
org-latex-preview: Set overlay priority to -80
* lisp/org-latex-preview.el (org-latex-preview--ensure-overlay): Setting
the overlay priority to -80 ensures that the background colour of
hl-line-mode's overlays takes priority, improving the visual consistency
of previews in the buffer.
2024-01-30 13:37:11 +08:00
TEC 7824b610f4
ox-html: Update LaTeX export for images and mathml
* lisp/ox-html.el (org-html-latex-environment, org-html-format-latex,
org-latex-to-html-convert-command, org-format-latex-as-html,
org-html-latex-image-options): Introduce new functions and variables to
work directly with the new org-latex-preview and ox-mathml API.

* lisp/org-latex-preview.el (org-format-latex-as-html,
org-latex-preview--tex-styled, org-latex-preview-replace-fragments,
org-latex-to-html-convert-command, org-latex-preview-options,
org-latex-preview-place-image-link): Move all of the HTML-specific
processing out of org-latex-preview.el, and into ox-html.el, and remove
now-obsolete code.

* lisp/org-compat.el (org-place-formula-image, org-html-format-latex):
Relocate a copy of `org-place-formula-image' and `org-html-format-latex'
here, and mark them as obsolete.
2024-01-30 13:37:11 +08:00
TEC 874b7d5ce1
ox-mathml: Refactor mathml export
* lisp/ox-mathml.el: Introduce a new library for managing mathml conversion.

* lisp/org-latex-preview.el (org-create-math-formula,
org-format-latex-mathml-available-p, org-latex-to-mathml-jar-file): Move
the various mathml functions into ox-mathml.

* lisp/org-compat.el: Add compat entries for the various mathml
conversion functions that have now been brought under ox-mathml.

* lisp/ox-odt.el (org-odt-export-as-odf,
org-odt--translate-latex-fragments): Use the new org-mathml functions.
2024-01-30 13:37:11 +08:00
TEC 4cd9d951df
org: Update LaTeX overlay during fontification
* lisp/org.el (org-do-latex-and-related, org-latex-preview-options): To
ensure that LaTeX preview overlays update as the face changes (for
instance, when in a heading that changes level), the face used is
updated during fontification when applicable.  This also ensures that
the correct face is used when JIT fontification is active.
2024-01-30 13:37:11 +08:00
TEC 4685b6e967
org-latex-preview: Improved face adaptation
* lisp/org-latex-preview.el (org-latex-preview--face-around): Instead of
only examining the face immediately before the LaTeX snippet, also look
at the face immediately after before determining the appropriate face to
use.  This is relevant when the prior face is
uninformative (e.g. org-indent) but the latter face contains the
applicable face (e.g. org-list-dt).  Determination of the applicable
face is now performed in the new function
`org-latex-preview--face-around'.
(org-latex-preview--colors-at, org-latex-preview--update-overlay):
Rename `org-latex-preview--colors-at' to
`org-latex-preview--colors-around', and use
`org-latex-preview--face-around' for better face determination.
(org-latex-preview-place, org-latex-preview-clear-cache): Update to
provide an "end" value to `org-latex-preview--colors-around'.
2024-01-30 13:37:11 +08:00
TEC 5395207923
org-latex-preview: Better handle temp/remote files
* lisp/org-latex-preview.el (org-latex-preview-precompile,
org-latex-preview--create-tex-file): Before obtaining the (compiled)
preamble, check for the temp-ness and remote-ness of the file, and act
accordingly.  Non-temp remote files are not currently supported, and an
error will now be thrown in such cases.  The temporary file status is
now passed on to `org-latex-preview-precompile' and through to
`org-latex--precompile'.
2024-01-30 13:37:11 +08:00
TEC 146ce64413
ox-latex: Handle preamble temp-ness explicitly
* lisp/ox-latex.el (org-latex--precompile, org-latex-make-preamble):
Instead of detecting relative file includes within
`org-latex--precompile', have an optional argument to signal a file can
be safely compile in the tempdir.  Move the check to
`org-latex-make-preamble' when calling `org-latex--precompile'.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur 4a73d55a5b
org-latex-preview: Clean up tex file on failure
*
lisp/org-latex-preview.el (org-latex-preview--create-image-async):
Ensure that the latex-preview cleanup callback runs when the
preview image extraction process fails.  This is to avoid
littering the default-directory with temporary tex files.
2024-01-30 13:37:11 +08:00
TEC 9a0251fd8f
org-latex-preview: Work around XeTeX misbehaviour
* lisp/org-latex-preview.el (org-latex-preview--latex-preview-filter):
Since XeLaTeX seems to misbehave with tightpage, we special-case the
tightpage processing to account for it.
2024-01-30 13:37:11 +08:00
TEC beea15f433
org-latex-preview: Improved error messages
* lisp/org-latex-preview.el (org-latex-preview--image-extract-async,
org-latex-preview--tex-compile-async,
org-latex-preview--create-image-async): Edit the error messages for
LaTeX compilation and image generation failure to be slightly more informative.
2024-01-30 13:37:11 +08:00
TEC 2d96e36f7d
org-latex-preview: Disable buf precompile on error
* lisp/org-latex-preview.el (org-latex-preview--create-tex-file): When
an error occurs during LaTeX precompilation, disable it using
`setq-local' and emit an informative warning message.
2024-01-30 13:37:11 +08:00
TEC bbf5274b85
org-latex-preview: Use stand-in color for SVG fg
* lisp/org-latex-preview.el (org-latex-preview--svg-make-fg-currentColor,
org-latex-preview-place): Instead of guessing the SVG foreground to be
the first color seen, set a static stand-in color that is unlikely to
occur organically.
2024-01-30 13:37:11 +08:00
TEC f6d5440fd9
org-latex-preview: Guard against caching nil-files
* lisp/org-latex-preview.el (org-latex-preview--cache-image): When
caching an image with `org-latex-preview--cache-image', check that the
image path is non-nil.  Should this not be true, a warning message is
emitted suggesting this is a bug that should be reported to the Org
mailing list.
2024-01-30 13:37:11 +08:00
TEC 125ea5af68
org-latex-preview: Get a list of all started tasks
* lisp/org-latex-preview.el (org-latex-preview--create-image-async):
Instead of just returning the main tex-compile task, return a list of
all async tasks created (i.e. the dvipng task, when used).  This will
allow for `org-async-wait-for' to be used on the list to wait until all
processing has completed.
2024-01-30 13:37:11 +08:00
TEC 126000dd22
org-latex-preview: Split out entry construction
* lisp/org-latex-preview.el (org-latex-preview--place-from-elements,
org-latex-preview--construct-entries): Split the entry construction code
into its own function `org-latex-preview--construct-entries'.

This change will make it easier to generate previews during export.
2024-01-30 13:37:11 +08:00
TEC 64da9ff169
org-latex-preview: Construct numbering from tree
* lisp/org-latex-preview.el (org-latex-preview--get-numbered-environments,
org-latex-preview--environment-numbering-table): Extend
`org-latex-preview--get-numbered-environments' and
`org-latex-preview--environment-numbering-table' to accept a parse tree
to operate on as an optional argument.

This will be useful when trying to integrate numbering with exports.
2024-01-30 13:37:11 +08:00
TEC fa1464b76b
org-latex-preview: Wait for SVGs more robustly
* lisp/org-latex-preview.el (org-latex-preview--svg-make-fg-currentColor,
org-latex-preview--dvisvgm-filter): Instead of waiting 0.01s and hoping
that an SVG exists by that point, we can wait and check for the
existance of an SVG within
`org-latex-preview--svg-make-fg-currentColor', and that should reduce
the chance of edge cases where the delay is insufficient.
(org-latex-preview--svg-make-fg-currentColor): Adjust the
`buffer-substring' call to not error when the buffer is empty.
2024-01-30 13:37:11 +08:00
TEC 2da7552b35
org-latex-preview: Move org-format-latex to compat
* lisp/org-latex-preview.el (org-latex-preview-create-image,
org-format-latex): It has become apparent that it is not reasonably
possible to maintain the behaviour of `org-format-latex' and
`org-create-formula-image' using the new image, so instead put the
original implementations in org-compat.
(org-preview-latex-image-directory): Move and mark as obsolete in
org-compat as it has not be used.

* lisp/org-compat.el: Introduce the original `org-format-latex' and
`org-create-formula-image' definitions.  Also move
`org-preview-latex-image-directory' here and mark as obsolete, since it
has ended up being completely unused.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur 3ff99452c2
org-latex-preview: Get geometry from preview.sty
* lisp/org-latex-preview.el (org-latex-preview--latex-preview-filter,
org-latex-preview--tex-scale-divisor,
org-latex-preview--dvipng-dpi-pt-factor): Fetch image geometry and
alignment information from the LaTeX compilation output instead of
dvisvgm or dvipng.  This calculation is simpler and should work for all
image converters (including imagemagick) and with all latex
processors (including xelatex and lualatex).

(org-latex-preview--shameful-magic-tex-scaling-factor): New
variable to match image geometry reported by preview.sty and that
computed by dvisvgm.

(org-latex-preview--dvipng-filter, org-latex-preview--dvisvgm-filter,
org-latex-preview--latex-preview-filter,
org-latex-preview--display-info): Adjust to no longer use the old sizing
information.

* lisp/org-latex-preview.el (org-latex-preview-process-alist,
org-latex-preview-create-image, org-latex-preview--display-info,
org-latex-preview--image-extract-async): Remove the :image-size-adjust
keyword, as with the new geometry detection system it is redundant.

We tried also switching dvisgm from "--bbox=preview" to "--exact-bbox",
as it should no longer be needed, but testing found "--exact-bbox" to
cause sizing issues in practice.
2024-01-30 13:37:11 +08:00
TEC 864ec3e0c9
org-latex-preview: Introduce a place-preview arg
* lisp/org-latex-preview.el (org-latex-preview--dvipng-filter,
org-latex-preview--dvisvgm-filter,
org-latex-preview--check-all-fragments-produced,
org-latex-preview--generic-callback,
org-latex-preview--create-image-async, org-latex-preview-place):
Refactor the preview pipeline to use a "place-preview" argument to
indicate that LaTeX previews should be placed after generation.

This change will pave the way for use with export, where the LaTeX
preview should be generated but not previewed.
2024-01-30 13:37:11 +08:00
TEC 3448ec738f
ox-latex: Precompile preamble for export
* lisp/ox-latex.el (org-latex-precompile, org-latex-make-preamble): Make
use of "mylatexformat" to precompile the LaTeX preamble, for faster
exports.
(org-latex--remove-cached-preamble): Add a function to clear a cached
preamble.

* lisp/org-latex-preview.el (org-latex-preview-precompile,
org-latex-preview--get-preamble): Relocate the precompilation
functionality to ox-latex.el, and use the new ox-latex preamble
precompilation API.
(org-latex-preview-clear-cache): Use the new preamble cache clearing
functionality in ox-latex.
2024-01-30 13:37:11 +08:00
TEC f486a5ee18
org-latex-preview: Use org-persist for .fmt cache
* lisp/org-latex-preview.el (org-latex-preview-precompile,
org-latex-preview--create-tex-file): Cache compiled ".fmt" format dump
files with org-persist, instead of using predictably named tempfiles.
`org-latex-preview--precompile-preamble' is introduced to seperate out
the compilation process from the org-persist interaction.  As a result
of the new changes, the ".fmt" extension is also returned now, and so it
must be stripped in `org-latex-preview--create-tex-file'.
2024-01-30 13:37:11 +08:00
TEC fe1b32f20e
org-latex-preview: Rework auto toggle behaviour
* lisp/org-latex-preview.el (org-latex-preview--auto-aware-toggle):
Adjust the toggle behaviour to hopefully behave more intuitively.
2024-01-30 13:37:11 +08:00
TEC b54d64f41d
org-latex-preview: org-latex-conditional-features
* lisp/org-latex-preview.el (org-latex-preview--get-preamble):
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur 6034fdad7e
org-latex-preview: Reduce verbosity of messaging
* lisp/org-latex-preview.el (org-latex-preview--cleanup-callback,
org-latex-preview--create-image-async, org-latex-preview-place,
org-latex-preview--auto-aware-toggle, org-latex-preview,
org-latex-preview-auto--regenerate-overlay): Do not emit a message
when previewing is successful.  This reduces how "busy" the echo area
is, especially when `org-latex-preview-auto-mode' is on.  When
previewing fails, display a message as before (behaviour unchanged).
2024-01-30 13:37:11 +08:00
TEC 13774486fb
org-latex-preview: Lazy-load, with autoloads
* lisp/org.el: No longer require org-latex-preview.

* lisp/org-latex-preview.el: Require the relevant files, and add
autoload tokens to `org-latex-preview-options',
`org-latex-preview-process-alist' (for backwards compatibility),
`org-latex-preview-auto-mode', `org-latex-preview' (the major likely
entry points), and `org-latex-preview-place` (potential external entry
point).
2024-01-30 13:37:11 +08:00
TEC e503794506
org-latex-preview: Use the conditional preamble
* lisp/org-latex-preview.el (org-latex-preview--create-tex-file,
org-latex-preview--clear-preamble-cache): Instead using a minimal info
export plist, populate it with buffer-specific values so that the
conditional preamble can be appropriately generated, and cache the
result.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur 57e7ee0405
org-latex-preview: Speed up texfile creation time
* lisp/org-latex-preview.el (org-latex-preview--create-tex-file):
Speed up texfile creation time by inhibiting fsync and setting the
`coding-system-for-write' explicitly.  Times are reduced by about
40-50%.
2024-01-30 13:37:11 +08:00
TEC 9146941da4
org-latex-preview: Fix spacing before LaTeX envs
* lisp/org-latex-preview.el (org-latex-preview--create-tex-file): Set
the \abovedisplayskip length to zero to remove the default padding.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur 9fc61e4b89
org-latex-preview: Fix element start positions
* lisp/org-latex-preview.el (org-latex-preview--place-from-elements,
org-latex-preview-auto--maybe-track-element-here): The org-element
property `:begin' includes any Org keyword text associated with the
element, such as "#+RESULTS:" or "#+ATTR_LATEX:" and these are swallowed
up in the created preview overlays.  Fix by using the `:post-affiliated'
property over `:begin' when it is available.  Note that some
calculations, such as equation numbering, still use the `:begin'
keyword.  These calculations don't involve creating overlays and thus
this is not (expected to be) an issue.
2024-01-30 13:37:11 +08:00
TEC 0635d33702
org-macs: Support blocking on async tasks
* lisp/org-macs.el (org-async--blocking-tasks, org-async-wait-for,
org-async--cleanup-process, org-async--execute-callback): Add support
for waiting for a set of async tasks to complete via the new function
`org-async-wait-for'.
2024-01-30 13:37:11 +08:00
TEC a14b864f8e
org-latex-preview: Redesign preview creation API
* lisp/org-latex-preview.el (org-latex-preview--check-all-fragments-produced,
org-latex-preview--create, org-latex-preview-fragments,
org-latex-preview-auto--regenerate-overlay,
org-latex-preview-auto--detect-fragments-in-change): Split the
org-element processing and the preview creation components of
`org-latex-preview--create` into two new functions, `
org-latex-preview--place-from-elements' and `org-latex-preview-place'.
The latter of these can serve as a convenient public API for creating
fragments.
(org-latex-preview-place, org-latex-preview-create-image-async): To make
`org-latex-preview-place' this easier to use, we also allow the LaTeX
preamble to be provided as an optional argument, and adjust
`org-latex-preview-create-image-async' to add this as the :latex-header
to the processing-info plist.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur 0e345223aa
org-latex-preview: Better imagemagick cleanup
* lisp/org-latex-preview.el (org-latex-preview--generic-callback,
org-latex-preview-create-image-async,
org-latex-preview-process-alist): Reuse
`org-latex-preview--cleanup-callback' for imagemagick-based previews.
Additionally, check produced fragments and regenerate them if
necessary.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur d570e0dca7
org-latex-preview: Fix auto-gen at end of overlay
* lisp/org-latex-preview.el (org-latex-preview-auto--maybe-track-element-here):
`overlays-at' does not include overlays that end at the position it is
called on.  This caused auto-generation to not trigger immediately
when manually typing the closing delimiters of a LaTeX fragment. Fix
this by recording the position just before the end of a newly created overlay.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur a724c130d2
org-latex-preview: Respect auto-generate option
* lisp/org-latex-preview.el (org-latex-preview-auto--detect-fragments-in-change):
Respect the user option `org-latex-preview-auto-generate' when
`org-latex-preview-auto-mode' is active.  (This was lost when the
auto-generation code was rewritten.)
2024-01-30 13:37:11 +08:00
TEC 58e2cbc1b4
org-latex-preview: Use appropriate TeX compiler
* lisp/org-latex-preview.el (org-latex-preview--tex-compile-async,
org-latex-preview-process-alist): Introduce %l and %L placeholders for
the LaTeX compiler.
(org-latex-preview-precompile): Record the LaTeX compiler in the
preamble hash, and add %l/%L to the `org-compile-file' format spec.
(org-latex-preview-compiler-command-map): Introduce a new variable to
map each LaTeX compiler name to the command and arguments needed.

Note that due to idiosyncrasies in how the various TeX compilers behave,
pdfLaTeX will likely continue to provide a smoother experience.  In the
future, some work can be done to improve this situation.
2024-01-30 13:37:11 +08:00
TEC 3746b798e4
org-latex-preview: Allow setting persist expiry
* lisp/org-latex-preview.el (org-latex-preview--cache-image,
org-latex-preview-persist-expiry): Introduce a new variable
`org-latex-preview-persist-expiry' which is used within
`org-latex-preview--cache-image' as the expiry value when calling
`org-persist-register' on preview data.
2024-01-30 13:37:11 +08:00
TEC 8a3aebb986
org-latex-preview: Customisable preview width
* lisp/org-latex-preview.el (org-latex-preview--create-tex-file,
org-latex-preview-width ): Introduce a new variable
`org-latex-preview-width' for convenient setting of the preview width,
and use it in the preamble generation.
(org-latex-preview-header): Remove now-redundant content (thanks to the
use of preview.sty).
2024-01-30 13:37:11 +08:00
TEC 1c2061b799
org-latex-preview: Wait for complete SVG file
* lisp/org-latex-preview.el (org-latex-preview--svg-make-fg-currentColor):
Wait until the SVG file is complete before processing it.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur 1351cff6eb
org-latex-preview: Custom processing indicator
* lisp/org-latex-preview.el (org-latex-preview-create-image-async,
org-latex-preview--update-overlay, org-latex-preview--ensure-overlay):
These functions are modified to incorporate customizable visual
indication of preview processing.
(org-latex-preview-processing-indicator): User option to customize how
preview processing is indicated visually.  The current options are:
no indication, show a fringe marker, or apply the
face `org-latex-preview-processing-face'.  The fringe marker is
currently set as the default.
(org-latex-preview--indicate-processing): Add function to handle
applying the appropriate processing indicator.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur f4ace4be19
org-latex-preview: Compile previews in default-dir
* lisp/org-latex-preview.el (org-latex-preview--generic-callback,
org-latex-preview--tex-compile-async,
org-latex-preview--create-tex-file): Compile latex fragments in
`default-directory', with output placed in `temporary-file-directory'.
This is to ensure that relative paths in fragments (such as paths to
figures) are parsed correctly.  Note that relative paths in the header
are handled during precompilation instead.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur 08c16b034b
org-latex-preview: Rename filename parts uniformly
* lisp/org-latex-preview.el (org-latex-preview-create-image,
org-latex-preview--dvipng-filter, org-latex-preview--generic-callback,
org-latex-preview--do-cleanup,
org-latex-preview--image-extract-async): Adopt the following
convention for parts of file names used in the latex and image
processing: For file with path 'foo', foo-base refers to its base
name (no directory, no extension) and foo-no-ext refers to its full
path but without a file extension.  The third option (no directory
component but with file extension) is not used in org-latex-preview.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur 2ac83404ff
org-latex-preview: Precompile with relative paths
* lisp/org-latex-preview.el (org-latex-preview-precompile,
org-latex-preview-process-alist): Change the precompilation parameters
so the created format file includes all files included/input in the
header with paths relative to the original Org buffer.  The
precompilation is carried out by calling latex from the
`default-directory', with the source tex file and destination format
dump file both placed in `temporary-file-directory'.  Additionally the
source tex file for precompilation is deleted if the precompilation is
successful.
2024-01-30 13:37:11 +08:00
TEC 327e63f6ea
org-persist: Add situational write inhibition
* lisp/org-persist.el (org-persist-write, org-persist--inhibit-write): TODO
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur e6c5e45b65
org-latex-preview: Compile latex in default-dir
* lisp/org-latex-preview.el (org-latex-preview-precompile,
org-latex-preview--do-cleanup, org-latex-preview--image-extract-async,
org-latex-preview--tex-compile-async,
org-latex-preview--create-tex-file): Format dump-files can be referred
to by their full paths in latex file preambles by adding a space after the "%&"
token.  Using this, we can compile the tex file containing the
previews in the same directory as the org file and handle relative
file references.  The above functions now do the following:
- format dump-file: Compiled and placed in
temporary-file-directory (no change)
- preview tex file: Refers to the format dump file in
temporary-file-directory. Compiled in default-directory, with output to
default-directory.
- image processors: Input (from tex output) in and output to
temporary-file-directory.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur ae1580c34a
org-latex-preview: Indicate errors when using pngs
* lisp/org-latex-preview.el (org-latex-preview--update-overlay,
org-latex-preview--ensure-overlay): When using dvipng, latex errors
cannot be indicated using an error face, and if a preview is generated
it is indistinguishable from a correct one.  Fall back to a fringe
marker in this situation.
2024-01-30 13:37:11 +08:00
TEC 4d70983b88
org-latex-preview: Introduce auto-aware toggling
* lisp/org-latex-preview.el (org-latex-preview--auto-aware-toggle,
org-latex-preview): Toggling of fragments with auto-mode active needs a
bit of work to function as most people would likely expect.  To provide
this more nuanced behaviour a new function
`org-latex-preview--auto-aware-toggle' is created and replaces the prior
"toggle this element" implementation in `org-latex-preview'.
2024-01-30 13:37:11 +08:00
TEC a7f52bbc19
org-latex-preview: Document async image logic
* lisp/org-latex-preview.el (org-latex-preview-create-image-async):
Explain the async call structure/logic with a large code comment.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur 32b3350fb0
org-latex-preview: Add error reporting via tooltip
* lisp/org-latex-preview.el (org-latex-preview--update-overlay): Add a
rudimentary interface for viewing compile errors (via tooltip).
2024-01-30 13:37:11 +08:00
TEC 0dc83ae01f
org-persist: Fallback to associated files in write
* lisp/org-persist.el (org-persist-write:file): If the path given in a
file container does not exist, instead of returning nothing return the
associated path if possible.  This fixes an issue where should the
original file be deleted and `org-persist-write-all' be run, then the
file container's association will be set to nil and so when
`org-persist-gc' is run the nil path will cause
org-persist-associated-files:file to produce an error.
2024-01-30 13:37:11 +08:00
TEC 9d6973ac8b
org-latex-preview: Fix face checking
* lisp/org-latex-preview.el (org-latex-preview--resolved-faces-attr,
org-latex-preview--update-overlay): Handle more of the complexity of the
forms of face specifications, and avoid inheriting information from the
`org-indent' face, which is never useful.
2024-01-30 13:37:11 +08:00
TEC 9e8011b335
org-latex-preview: Wait for dvisvgm to write
* lisp/org-latex-preview.el (org-latex-preview--dvisvgm-filter): As
mentioned in the code comment, dvisvgm seems to sometimes lie about when
file content has been written, so we need to work around that by waiting
a little bit.
(org-latex-preview--cleanup-callback): Now that the svg processing is on
a timer, we must be careful not to run the callback to soon.  This isn't
desperately urgent, so we can use a relatively generous timer for this.
2024-01-30 13:37:11 +08:00
TEC 608c3a7bba
org-latex-preview: Adjust defaults
* lisp/org-latex-preview.el (org-latex-preview,
org-latex-to-html-convert-command, org-latex-preview-process-alist):
Adjust the default LaTeX preview parameters to better suit the reworked
preview system.
2024-01-30 13:37:11 +08:00
TEC 9a3f41c24d
org-latex-preview: Equation numbering
* lisp/org-latex-preview.el (org-latex-preview-numbered): Introduce a
new variable to signal whether equations numbering should be calculated
to be correct throughout the document, or not.
(org-latex-preview--numbered-environments): Create a list of known
numbered environments.
(org-latex-preview--environment-numbering-table,
org-latex-preview--get-numbered-environments): Introduce functions which
create a numbering hash table from the buffer.
(org-latex-preview--tex-styled): When an initial equation number is
provided, add LaTeX code to set the counter to apply the numbering.
(org-latex-preview--create,
org-latex-preview-auto--detect-fragments-in-change,
org-latex-preview--create): Make use of the new equation numbering
facilities.
(org-latex-preview--hash): Include first equation number (if applicable)
in the hash.
(org-latex-preview-clear-cache): Use numbering information.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur 1bc075de32
org-latex-preview: Simplify overlay regeneration
* lisp/org-latex-preview.el (org-latex-preview--close-previous-overlay,
org-latex-preview--regenerate-overlay): Overlays carry information
about the buffer they belong to, so it is unnecessary to pass this
information explicitly when passing an overlay argument to a function.
2024-01-30 13:37:11 +08:00
TEC d3e297c78b
org-latex-preview: Reuse overlays more
* lisp/org-latex-preview.el (org-latex-preview--create,
org-latex-preview--maybe-track-element-here,
org-latex-preview--make-overlay): Instead of always deleting and
re-creating overlays in a region when wanting to ensure a suitable
overlay exists, we can look at the scanned overlays, check if a suitable
overlay already exists, and re-use it.  To indicate the change in
behaviour, as well as documentation updates
`org-latex-preview--make-overlay' is renamed to
`org-latex-preview--ensure-overlay'.  While we're at it, the
"front-advance" argument is now set when calling `make-overlay', to make
sure that text typed at the beginning of the fragment is not absorbed
into the overlay.
(org-latex-preview--failure-callback): It's possible the overlay
provided could be nil when something goes wrong, in which case do
nothing.
(org-latex-preview--mark-overlay-modified): Move to a separate function
for neatness.
2024-01-30 13:37:11 +08:00
TEC 2453c8a127
org-latex-preview: Better fragment insertion check
* lisp/org-latex-preview.el (org-latex-preview--handle-insert,
org-latex-preview--detect-fragments-in-change, ): Replace the old
checker `org-latex-preview--handle-insert' that was called as a
`post-insert-hook' with a new method of checking for newly created
fragments based on buffer modifications as a `after-change-functions'
hook.  This has a number of benefits, including generally improved
robustness, and the removal of a reliance on font-lock information.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur 40fcbd2bd0
org-latex-preview: Previews stored in /tmp
* lisp/org-latex-preview.el (org-latex-preview--get-cached,
org-latex-preview--remove-cached, org-latex-preview--cache-image):
These functions are modified to search in, remove from or add to a
session cache instead of org-persist's cache.
(org-latex-preview-persist-p): User option to turn off or on
persistent caching.
(org-latex-preview--table): Hash table used to hold preview image
metadata when using a session cache instead of org-persist.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur 78b94ce83a
org-latex-preview: Fix precomp when backend switch
* lisp/org-latex-preview: (org-latex-preview-process-alist,
org-latex-preview-precompile): Update programs required for
imagemagick conversion to include pdflatex.  Precompilation now
generates a new format file when switching
`org-latex-preview-default-process' to or from imagemagick.
2024-01-30 13:37:11 +08:00
TEC e54dfbf4b4
org-macs: Ensure that filter run before callbacks
* lisp/org-macs.el (org-async--cleanup-process): Run
`accept-process-output` until no further output is fetched on process
exit, so we can assume that the callbacks are run after all filter
invocations.
2024-01-30 13:37:11 +08:00
TEC bd593af82c
org-macs: Add :coding kwarg to org-async-call
* lisp/org-macs.el (org-async-call): It is recommended in
(info "(elisp) Decoding Output") that the process coding system be set.
To allow for this we add a new keyword argument, :coding, and set the
default value to utf-8.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur 2bf81ed249
org-latex-preview: Improve preview creation msg
* lisp/org-latex-preview.el: (org-latex-preview,
org-latex-preview-create-image-async): `org-latex-preview' starts an
async process, and so it can only inform the user of the start of the
process. Information about the completion (to success or failure) is
provided by the relevant process sentinels instead.
(org-latex-preview--latex-log, org-latex-preview--image-log,
org-latex-preview--precompile-log): Log buffer names for preview latex
processing.
(org-latex-preview--tex-compile-async,
org-latex-preview--image-extract-async, org-latex-preview-precompile,
org-latex-preview-create-image): Use the newly created log buffer name
variables.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur fa63fc5c8f
org-latex-preview: Clear failed preview overlays
* lisp/org-latex-preview.el: (org-latex-preview-create-image-async): If
preview images fail to generate for some or all LaTeX fragments, the
overlays placed on the fragments during processing need to be cleared.
This is done by adding a (failure) callback function to the image
generation process.
(org-latex-preview--failure-callback): Add callback that clears overlays
for previews that fail to generate.  Other behaviours are possible here
but not implemented yet.  This includes signalling failure by changing
how the overlays are displayed, such as by adding a face or fringe
marker.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur c4a68d7ab4
org-latex-preview: Make clear-cache user-friendly
* lisp/org-latex-preview.el (org-latex-preview-clear-cache): Ask for
confirmation before wiping the entire LaTeX preview cache, and confirm
cache clearing at the end when clearing the buffer cache.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur beba8515ac
org-latex-preview: Add cache clearing function
* lisp/org-latex-preview.el (org-latex-preview-clear-cache): Clears the
latex preview cache for LaTeX fragments in a region.  This can be called
as a command by itself, but is primarily required when previewing
fragments by force-regenerating their preview images.  This might be
necessary when the output image corresponding to a fragment is malformed
in some way, for instance.
2024-01-30 13:37:11 +08:00
TEC 3bc2a4ff01
org-latex-preview: More robust face resolving
* lisp/org-latex-preview.el (org-latex-preview--colors-at,
org-latex-preview--resolved-faces-attr): Just using `face-attribute' on
the first face spec given when the face text property is a list is too
naive.  To do this correctly, a new function
`org-latex-preview--resolved-faces-attr' is introduced which takes care
of the annoying semantics, and used in `org-latex-preview--colors-at' to
better resolve the face attribute.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur b0de57ef71
org-latex-preview: Split org-latex-preview--create
* lisp/org-latex-preview.el (org-latex-preview--create): This function
does many tasks, including computing face colors and hashes for
fragments.  Split this function into three to reuse the parts for other
planned purposes, such as clearing cached images.
(org-latex-preview--colors-at): Finds appropriate foreground and
background colors at a position for the preview image of a LaTeX
fragment.  Also improve the code to handle multiple faces.
(org-latex-preview--hash): Computes the hash key for a LaTeX fragment
combined with relevant processing metadata.  This key is used to
identify the fragment when caching and placing images.
2024-01-30 13:37:11 +08:00
TEC f232aab63f
org-latex-preview: Graceful precompile failure
* lisp/org-latex-preview.el (org-latex-preview-precompile,
org-latex-preview--create-tex-file): Fall back to compiling without
using a preamble format file if the preamble could not be precompiled
without error.  In such an event, alert the user that preamble
precompilation failed, and in particular let them know if mylatexformat
could not be found.
2024-01-30 13:37:11 +08:00
TEC 3ce9f76703
org-latex-preview: Check all fragments produced
* lisp/org-latex-preview.el (org-latex-preview--check-all-fragments-produced):
Create a new callback that checks that each fragment has indeed been
produced not, and if not guesses the last produced fragment caused a
problem.  The last produced fragment is then marked as erroneous,
its cache entry updated (replaced and re-inserted), and the remaining
fragments are regenerated.
(org-latex-preview-create-image-async): Run
`org-latex-preview--check-all-fragments-produced' after successfully
extracting images.
(org-latex-preview--cache-name, org-latex-preview--cache-image,
org-latex-preview--get-cached): Use a defconst instead of hardcoding the
cache container string in `org-latex-preview--cache-image' and
`org-latex-preview--get-cached'.
(org-latex-preview--remove-cached): Easy removal of an item from the
org-persist cache, as a counterpart to `org-latex-preview--cache-image'.
2024-01-30 13:37:11 +08:00
TEC 5c40409f64
org-latex-preview: Strip redundant color switching
* lisp/org-latex-preview.el (org-latex-preview--create,
org-latex-preview--create-tex-file): Keep track of the last fragment's
foreground/background color, and only include LaTeX color specifications
as needed.
(org-latex-preview-create-image-async): Provide the processing type so
`org-latex-preview--create-tex-file' can change the style of color
setting as appropriate.  This allows the dvipng route to use postscript
special statements instead of regular color declarations.
2024-01-30 13:37:11 +08:00
TEC 57e205306c
org-latex-preview: Do not show empty SVG fragments
* lisp/org-latex-preview.el (org-latex-preview--svg-make-fg-currentColor):
When an SVG is empty, delete it.  This will cause
`org-latex-preview--cache-image' to give nil as the path.  When the
provided path is nil, do nothing.
(org-latex-preview--update-overlay): If the image path is nil, do
attempt to place an image.  If an error is recorded and there is no
image this causes the text to be shown with the error face.
(org-latex-preview--cleanup-callback): If the image path is nil, do not
try to delete it.
2024-01-30 13:37:11 +08:00
TEC 13e7d02b84
org-persist: Allow inhibiting of normalisation
* lisp/org-persist.el (org-persist-register,
org-persist--normalize-container,
org-persist--inhibit-container-normalization): Since container
normalisation is applied frequently (via
`org-persist--normalize-container'), when registering many new
containers the cost can quickly add up.  To avoid redundant overhead,
after normalising the container initially in `org-persist-register' we
bind a new variable `org-persist--inhibit-container-normalization' to t
and adjust `org-persist--normalize-container' to do nothing when this
new variable is non-nil.
2024-01-30 13:37:11 +08:00
TEC 0db9f1e0de
org-latex-preview: Cache formatted color strings
* lisp/org-latex-preview.el (org-latex-preview--format-color,
org-latex-preview--format-color-cache): Introduce a color cache alist, and use
it.
2024-01-30 13:37:11 +08:00
TEC 1aa997dd57
org-latex-preview: Reduce overhead in SVG editing
* lisp/org-latex-preview.el (org-latex-preview--svg-make-fg-currentColor):
By setting the coding system and avoiding triggering any file
handlers (such as the `image-file-handler'), memory usage is nearly
halved, reducing GC pressure.
2024-01-30 13:37:11 +08:00
TEC b1f9c0bfc8
org-latex-preview: Tweak baseline alignment
* lisp/org-latex-preview.el (org-latex-preview--update-overlay): After
doing quite a bit of testing, tweak the ascent formula to introduce a
slight correction to visually improve the final result.
2024-01-30 13:37:11 +08:00
TEC fd029fc666
org-latex-preview: Introduce dvipng filter
* lisp/org-latex-preview.el (org-latex-preview--dvipng-filter,
org-latex-preview-create-image-async): Introduce a dvipng filter
function to capture information from the dvipng stdout, and place images
as they are generated.
(org-latex-preview-process-alist): Update default dvipng process to emit
depth and height information.
2024-01-30 13:37:11 +08:00
TEC c78812fb8f
org-latex-preview: Eagerly make fragment overlays
* lisp/org-latex-preview.el (org-create-latex-export,
org-latex-preview--place-images, org-latex-preview--generic-callback,
org-latex-preview--create-tex-file,
org-latex-preview-create-image-async, org-latex-preview--create,
org-latex-preview--close-previous-overlay,
org-latex-preview--make-overlay, org-latex-preview--update-overlay,
org-latex-preview-processing-face): Instead of saving buffer locations
and creating an overlay after the fragment image has been generated,
create an overlay initially and then update it when the image has been
created.  This is done by splitting the image-related code of
`org-latex-preview--make-overlay' into a new function,
`org-latex-preview--update-overlay'.  This provides a number of
advantages, primarily robustness to buffer edits during image
generation.  It also allows us to create a face to indicate
in-progress (`org-latex-preview-processing-face'), which is a nice
visual indicator.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur 115f3f59a1
org-latex-preview: Avoid duplicating cached images
* lisp/org-latex-preview.el (org-latex-preview--cache-image): When
caching an image, check if there is already an entry in the
`org-persist--index' with the same hash as this one.  This avoids
missing preview images for fragments with duplicates in a buffer, or
across org-persist's cache.  Without this measure, when we try to
register two fragments identified by the same hash,
`org-persist-register' returns a structure with the correct metadata
for both, but with the cached image path field missing for the second
fragment.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur fa73360b42
org-latex-preview: Prioritise near latex previews
* lisp/org-latex-preview.el (org-latex-preview-fragments): Reorder
gathered latex fragments so that they are processed starting at the
window start position.  When previewing a large file, this makes a
significant difference to the perceived speed of the processing.
Remove references to `org-preview-latex-image-directory' from this
function, as it is no longer used to cache images.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur 396718f97f
org-latex-preview: Avoid duplicate latex fragments
* lisp/org-latex-preview.el (org-latex-preview-collect-fragments): This
function was collecting duplicate org-elements when handling nested
latex environments (For instance, a matrix env inside an equation env).
Fix by comparing the current element with the previously collected one.
2024-01-30 13:37:11 +08:00
TEC 97e662057d
org-latex-preview: Inhibit fsync when editing SVGs
* lisp/org-latex-preview.el (org-latex-preview--svg-make-fg-currentColor):
The value of fsync appears questionable at best on modern hardware, and
makes little sense for small files where the performance overhead is
significant.  Thus, it makes sense to inhibit fsync when editing the
generated SVGs.
2024-01-30 13:37:11 +08:00
Karthik Chikmagalur 9a1cd8df71
org-latex-preview: Add org-preview-latex-auto-mode
* lisp/org-latex-preview.el (org-latex-preview--make-overlay): Add
overlay hooks that correct for any edits made inside the overlay, and
store a copy of the image specification in the "preview-image" slot.
Also return the created overlay, so it can be used in other functions.
(org-latex-preview--from-overlay-p, org-latex-preview--marker,
org-latex-preview--inhibit): New variables to keep track of overlay
state when using auto-mode.
(org-latex-preview--handle-pre-cursor,
org-latex-preview--handle-post-cursor, org-latex-preview--move-into):
Detect when the cursor is entering or leaving a preview overlay, and
trigger the appropriate action.
(org-latex-preview--open-this-overlay,
org-latex-preview--close-previous-overlay): When cursor has entered/left
a preview overlay, show the text/image as appropriate.
(org-latex-preview--handle-insert): Create a dummy preview overlay when
a new LaTeX fragment is created.
(org-latex-preview--insert-front-handler,
org-preview--insert-behind-handler): Extend preview overlay boundaries
when their content changes.
(org-latex-preview-auto-mode): A new minor mode for automatic
opening/closing of preview overlays, and regeneration.
(org-latex-preview-auto-generate-p): Variable which affects the
regeneration behaviour of `org-latex-preview-auto-mode'.
2024-01-30 13:37:03 +08:00
16 changed files with 4511 additions and 1210 deletions

View File

@ -11381,20 +11381,19 @@ lines:
:END:
#+cindex: @LaTeX{} fragments, preview
#+vindex: org-latex-preview-default-process
#+vindex: org-latex-preview-process-default
If you have a working LaTeX installation and =dvipng=, =dvisvgm= or
=convert= installed[fn:38], LaTeX fragments can be processed to
produce images of the typeset expressions to be used for inclusion
while exporting to HTML (see [[*LaTeX fragments]]), or for inline
previewing within Org mode.
#+vindex: org-latex-preview-options
#+vindex: org-latex-preview-appearance-options
#+vindex: org-latex-preview-header
You can customize the variables ~org-latex-preview-options~ and
You can customize the variables ~org-latex-preview-appearance-options~ and
~org-latex-preview-header~ to influence some aspects of the preview.
In particular, the ~:scale~ (and for HTML export, ~:html-scale~)
property of the former can be used to adjust the size of the preview
images.
In particular, the ~:scale~ and ~:zoom~ properties of the former can
be used to adjust the size of the preview images.
- {{{kbd(C-c C-x C-l)}}} (~org-latex-preview~) ::
#+kindex: C-c C-x C-l
@ -11418,6 +11417,24 @@ To disable it, simply use
: #+STARTUP: nolatexpreview
#+vindex: org-latex-preview-numbered
When generating previews, Org mode can track equation numbers and keep
them consistent by regenerating previews when necessary. This
behavior is controlled by the variable ~org-latex-preview-numbered~.
Org mode can automatically preview LaTeX fragments as you type them,
and hide and reveal preview images as the cursor moves into or out of
them. To enable this, turn on the minor mode
~org-latex-preview-auto-mode~.
- (~org-latex-preview-auto-mode~) ::
#+findex: org-latex-preview-auto-mode
Generate previews of LaTeX fragments as they are entered in the
buffer. Previews will be generated when there is any change to the
buffer that includes the insertion of a LaTeX environment or
fragment.
*** Using CDLaTeX to enter math
:PROPERTIES:
:DESCRIPTION: Speed up entering of formulas.
@ -23279,7 +23296,7 @@ used to create images, any LaTeX environment is handled.
[fn:38] These are respectively available at
[[https://sourceforge.net/projects/dvipng/]], [[http://dvisvgm.bplaced.net/]]
and from the ImageMagick suite. Choose the converter by setting the
variable ~org-latex-preview-default-process~ accordingly.
variable ~org-latex-preview-process-default~ accordingly.
[fn:39] This works automatically for the HTML backend (it requires
version 1.34 of the =htmlize.el= package, which you need to install).

View File

@ -325,6 +325,157 @@ constant.
If you still want to use python-mode with ob-python, you might
consider [[https://gitlab.com/jackkamm/ob-python-mode-mode][ob-python-mode-mode]], where the code to support python-mode
has been ported to.
*** The LaTeX preview system has been overhauled
Org's LaTeX preview system has been overhauled
Org mode's LaTeX preview system has been rewritten with several improvements and new features.
- LaTeX Previews are generated in bulk, and hundreds of LaTeX fragments can be processed per second.
- Images are placed in the buffer continuously as they are generated.
- Preview generation is asynchronous and will not block Emacs.
- Inline previews are aligned and scaled to match the font baseline and size.
- Previews scale along with text when the text scale is changed.
- Previews are coloured to match surrounding text and the active theme.
- SVG previews automatically change colors when the active theme changes.
- Error encountered when compiling LaTeX fragments can be accessed by mousing over preview images.
- Preview overlays can hide and show themselves dynamically based on cursor position.
- Org mode can auto-generate LaTeX previews as you type or edit the text of existing ones.
- Org mode can keep equation numbering consistent by regenerating previews as needed.
**** New features
***** New minor mode ~org-latex-preview-auto-mode~
When this mode is turned on, LaTeX preview overlays in the buffer can be temporarily disabled by moving the cursor into them. Moving the cursor out will display the LaTeX preview image overlay again. Additionally, editing LaTeX fragments that have previews will cause the preview images to be updated.
If the option ~org-latex-preview-auto-track-inserts~ is non-nil (which see), previews for LaTeX fragments will be auto-generated as you type.
**** New options
***** A new option ~org-latex-preview-compiler-command-map~ for setting precompile commands
This alist maps compilers in ~org-latex-compilers~ to command strings
used for LaTeX precompilation when creating previews or LaTeX exports.
***** New option ~org-latex-preview-cache~ to enable preview image caching
When set to =persist=, images produced using ~org-latex-preview~ will
be cached and persisted across Emacs sessions using
~org-persist~. Temporary or custom directories can also be used.
***** New option ~org-latex-preview-persist-expiry~ to set persistence period
This is the number of days for which LaTeX preview images will be
cached, assuming persistence is turned on with
~org-latex-preview-cache~.
***** New option ~org-latex-preview-process-active-indicator~ to indicate preview processing for LaTeX fragments
This option controls the style of visual indicator for LaTeX fragments
currently being processed.
***** New option ~org-latex-preview-numbered~ to automatically renumber previewed LaTeX environments
When non-nil, previewed LaTeX environments in the buffer are
renumbered automatically as required.
***** New option =:page-width= in ~org-latex-preview-appearance-options~ to control the text width for LaTeX fragment previews
This option controls the width of text in preview images. This is
relevant for displaymath-type LaTeX environments, and can be specified
in multiple ways.
***** New option ~org-latex-preview-process-precompiled~ to control LaTeX precompilation
This option controls whether LaTeX headers for buffers are precompiled
when generating the first preview for the buffer. Precompilation can
speed up preview generation by a moderate to large amount depending on
the complexity of the header.
***** New option ~org-latex-preview-auto-track-inserts~ to auto-generate LaTeX previews when typing
When using ~org-latex-preview-auto-mode~ (which see), setting this option to a non-nil value will cause LaTeX previews to be rendered as you type LaTeX fragments. This works however new text is added to the buffer, for example by yanking. When this option is nil and ~org-latex-preview-auto-mode~ is on, existing previews for LaTeX fragments will still be auto-regenerated when edited but no new ones will be auto-generated.
**** Removed or renamed functions and variables
***** Mark ~org-format-latex-options~ obsolete
Use ~org-latex-preview-appearance-options~ instead. The replacement acts in the
same way, except that
- the preview image render size and display size can be independently
controlled with the =:scale= and =:zoom= plist keys, and
- the HTML export-specific parameters =:html-scale=,
=:html-foreground= and =:html-background= have been moved to
~org-html-latex-image-options~, which see.
- the new option =:page-width= (mentioned earlier)
***** Mark ~org-format-latex-header~ obsolete
Use ~org-latex-preview-header~ instead. The replacement variable
behaves the exact same way and is renamed for consistency.
***** Mark ~org-preview-latex-default-process~ obsolete
Use ~org-latex-preview-process-default~ instead. The replacement
variable behaves the exact same way and is renamed for consistency.
***** Mark ~org-preview-latex-process-alist~ obsolete
Use ~org-latex-preview-process-alist~ instead. The replacement
variable acts in the same way, except that =:latex-compiler= must now
be a single command or a list containing a single command. The
placeholder ="%S"= in the format string for =:latex-compiler= is
ignored.
***** Mark ~org-clear-latex-preview~ obsolete
Use ~org-latex-preview-clear-overlays~ instead. The replacement
function acts in the exact same way and is renamed for consistency.
***** Mark ~org-place-formula-image~ obsolete
This functionality is replaced with ~org-latex-preview-place-image~
(for images) and ~org-latex-preview-place-image-link~ (for links).
***** Mark ~org-latex-color-format~ obsolete
Use ~org-latex-preview--format-color~ instead. The replacement
function acts in the exact same way and is renamed for consistency.
***** Mark ~org-latex-color~ obsolete
Use ~org-latex-preview--attr-color~ instead. The replacement function
acts in the exact same way and is renamed for consistency.
***** Mark ~org-normalize-color~ obsolete
Use ~org-latex-preview--normalize-color~ instead. The replacement
function acts in the exact same way and is renamed for consistency.
***** Mark ~org-latex-to-mathml-jar-file~ obsolete
Use ~org-mathml-converter-jar-file~ instead. The replacement variable
acts in the exact same way and is renamed for consistency.
***** Mark ~org-latex-to-mathml-convert-command~ obsolete
Use ~org-mathml-convert-command~ instead. The replacement variable
acts in the exact same way and is renamed for consistency.
***** Mark ~org-format-latex-mathml-available-p~ obsolete
Use ~org-mathml-converter-available-p~ instead. The replacement
function acts in the exact same way and is renamed for consistency.
***** Mark ~org-create-math-formula~ obsolete
Use ~org-mathml-convert-latex~ instead. The replacement function acts
in the exact same way and is renamed for consistency.
*** =ox-icalendar.el= line ending fix may affect downstream packages

View File

@ -48,10 +48,10 @@
(defvar org-babel-tangle-lang-exts)
(add-to-list 'org-babel-tangle-lang-exts '("latex" . "tex"))
(defvar org-latex-preview-header) ; From org-latex-preview.el
(defvar org-latex-preview-options) ; From org-latex-preview.el
(defvar org-latex-default-packages-alist) ; From org-latex-preview.el
(defvar org-latex-packages-alist) ; From org-latex-preview.el
(defvar org-latex-preview-header) ; From org-latex-preview.el
(defvar org-latex-preview-appearance-options) ; From org-latex-preview.el
(defvar org-latex-default-packages-alist) ; From org-latex-preview.el
(defvar org-latex-packages-alist) ; From org-latex-preview.el
(defvar org-babel-default-header-args:latex
'((:results . "latex") (:exports . "results"))
@ -171,7 +171,7 @@ This function is called by `org-babel-execute-src-block'."
(concat org-latex-preview-header "\n"
(mapconcat #'identity headers "\n"))))
(org-latex-preview-create-image
body out-file org-latex-preview-options in-buffer)))
body out-file org-latex-preview-appearance-options in-buffer)))
((string= "svg" extension)
(with-temp-file tex-file
(insert (concat (funcall org-babel-latex-preamble params)

View File

@ -1068,6 +1068,9 @@ and then used in capture templates."
if store-func
collect store-func))
(defvar org-link--abbrev-functions nil
"Alist of abbrev link expressions and functions.")
(defun org-link-expand-abbrev (link)
"Replace link abbreviations in LINK string.
Abbreviations are defined in `org-link-abbrev-alist'."
@ -1082,14 +1085,27 @@ Abbreviations are defined in `org-link-abbrev-alist'."
(setq rpl (cdr as))
(cond
((symbolp rpl) (funcall rpl tag))
((string-match "%(\\([^)]+\\))" rpl)
((string-match "%(\\([^) ]+\\))" rpl) ; %(function)
(replace-match
(save-match-data
(funcall (intern-soft (match-string 1 rpl)) tag))
t t rpl))
((string-match "%s" rpl) (replace-match (or tag "") t t rpl))
((string-match "%h" rpl)
(replace-match (url-hexify-string (or tag "")) t t rpl))
((string-match "%(\\(.+\\))" rpl) ; %(sexpr using tag)
(replace-match
(save-match-data
(funcall (or (cdr (assoc (match-string 1 rpl)
org-link--abbrev-functions))
(cdar (push (cons (match-string 1 rpl)
(eval (read (format
"(lambda (tag) (%s))"
(match-string 1 rpl)))))
org-link--abbrev-functions)))
tag))
t t rpl))
((string-match-p "%[0-<>^_]?[0-9]*\\(?:\\.[0-9]+\\)?s" rpl)
(format-spec rpl `((?s . ,(or tag "")))))
((string-match-p "%[0-<>^_]?[0-9]*\\(?:\\.[0-9]+\\)?h" rpl)
(format-spec rpl `((?h . ,(url-hexify-string (or tag ""))))))
(t (concat rpl tag)))))))
(defun org-link-open (link &optional arg)

View File

@ -650,29 +650,60 @@ Counting starts at 1."
"9.0")
(define-obsolete-variable-alias
'org-format-latex-options 'org-latex-preview-options "9.7")
'org-format-latex-options 'org-latex-preview-appearance-options "9.7")
(make-obsolete-variable
'org-format-latex-signal-error "no longer used" "9.7")
(define-obsolete-variable-alias
'org-format-latex-header 'org-latex-preview-preamble "9.7")
(define-obsolete-variable-alias
'org-preview-latex-default-process 'org-latex-preview-default-process "9.7")
'org-preview-latex-default-process 'org-latex-preview-process-default "9.7")
(define-obsolete-variable-alias
'org-preview-latex-process-alist 'org-latex-preview-process-alist "9.7")
;; (make-obsolete-variable
;; 'org-preview-latex-image-directory "replaced with org-persist" "9.7")
(define-obsolete-function-alias
'org-clear-latex-preview 'org-latex-preview-clear-overlays "9.7")
(make-obsolete
'org-place-formula-image "replaced with org-latex-preview-place-image and org-latex-preview-place-image-link" "9.7")
(define-obsolete-function-alias
'org-create-formula-image 'org-latex-preview-create-image "9.7")
'org-place-formula-image "no longer used" "9.7")
(define-obsolete-function-alias
'org-latex-color-format 'org-latex-preview--format-color "9.7")
(define-obsolete-function-alias
'org-latex-color 'org-latex-preview--attr-color "9.7")
;; MathML related functions from org-latex-preview.el
(define-obsolete-variable-alias
'org-latex-to-mathml-jar-file 'org-mathml-converter-jar-file "9.7")
(define-obsolete-variable-alias
'org-latex-to-mathml-convert-command 'org-mathml-convert-command "9.7")
(define-obsolete-function-alias
'org-normalize-color 'org-latex-preview--normalize-color "9.7")
'org-format-latex-mathml-available-p 'org-mathml-converter-available-p "9.7")
(define-obsolete-function-alias
'org-create-math-formula 'org-mathml-convert-latex "9.7")
;; FIXME: Unused; obsoleted; to be removed.
(defun org-format-latex-as-mathml (latex-frag latex-frag-type
prefix &optional dir)
(let* ((absprefix (expand-file-name prefix dir))
(print-length nil) (print-level nil)
(formula-id (concat
"formula-"
(sha1
(prin1-to-string
(list latex-frag
org-latex-to-mathml-convert-command)))))
(formula-cache (format "%s-%s.mathml" absprefix formula-id))
(formula-cache-dir (file-name-directory formula-cache)))
(unless (file-directory-p formula-cache-dir)
(make-directory formula-cache-dir t))
(unless (file-exists-p formula-cache)
(org-mathml-convert-latex latex-frag formula-cache))
(if (file-exists-p formula-cache)
;; Successful conversion. Return the link to MathML file.
(org-add-props
(format "[[file:%s]]" (file-relative-name formula-cache dir))
(list 'org-latex-src (replace-regexp-in-string "\"" "" latex-frag)
'org-latex-src-embed-type (if latex-frag-type
'paragraph 'character)))
;; Failed conversion. Return the LaTeX fragment verbatim
latex-frag)))
(make-obsolete #'org-format-latex-as-mathml "to be removed" "9.7")
;; FIXME: Unused; obsoleted; to be removed.
(defun org-dvipng-color (attr)
@ -690,6 +721,321 @@ Counting starts at 1."
(make-obsolete
'org-dvipng-color-format "to be removed" "9.7")
;; FIXME: Unused; obsoleted; to be removed.
(defun org-normalize-color (value)
"Return string to be used as color value for an RGB component."
(format "%g" (/ value 65535.0)))
(make-obsolete 'org-normalize-color "to be removed" "9.7")
;; FIXME: Unused; obsoleted; to be removed.
(defcustom org-preview-latex-image-directory "ltximg/"
"Path to store latex preview images.
A relative path here creates many directories relative to the
processed Org files paths. An absolute path puts all preview
images at the same place."
:group 'org-latex
:version "26.1"
:package-version '(Org . "9.0")
:type 'string)
(make-obsolete-variable
'org-preview-latex-image-directory "replaced with org-persist" "9.7")
;; FIXME: Unused; obsoleted; to be removed.
(defun org-format-latex
(prefix &optional beg end dir overlays msg forbuffer processing-type)
"Replace LaTeX fragments with links to an image.
The function takes care of creating the replacement image.
Only consider fragments between BEG and END when those are
provided.
When optional argument OVERLAYS is non-nil, display the image on
top of the fragment instead of replacing it.
PROCESSING-TYPE is the conversion method to use, as a symbol.
Some of the options can be changed using the variable
`org-format-latex-options', which see."
(when (and overlays (fboundp 'clear-image-cache)) (clear-image-cache))
(unless (eq processing-type 'verbatim)
(let* ((math-regexp "\\$\\|\\\\[([]\\|^[ \t]*\\\\begin{[A-Za-z0-9*]+}")
(cnt 0)
checkdir-flag)
(goto-char (or beg (point-min)))
;; Optimize overlay creation: (info "(elisp) Managing Overlays").
(when (and overlays (memq processing-type '(dvipng imagemagick)))
(overlay-recenter (or end (point-max))))
(while (re-search-forward math-regexp end t)
(unless (and overlays
(eq (get-char-property (point) 'org-overlay-type)
'org-latex-overlay))
(let* ((context (org-element-context))
(type (org-element-type context)))
(when (memq type '(latex-environment latex-fragment))
(let ((block-type (eq type 'latex-environment))
(value (org-element-property :value context))
(beg (org-element-property :begin context))
(end (save-excursion
(goto-char (org-element-property :end context))
(skip-chars-backward " \r\t\n")
(point))))
(cond
((eq processing-type 'mathjax)
;; Prepare for MathJax processing.
(if (not (string-match "\\`\\$\\$?" value))
(goto-char end)
(delete-region beg end)
(if (string= (match-string 0 value) "$$")
(insert "\\[" (substring value 2 -2) "\\]")
(insert "\\(" (substring value 1 -1) "\\)"))))
((eq processing-type 'html)
(goto-char beg)
(delete-region beg end)
(insert (org-format-latex-as-html value)))
((assq processing-type org-preview-latex-process-alist)
;; Process to an image.
(cl-incf cnt)
(goto-char beg)
(let* ((processing-info
(cdr (assq processing-type org-preview-latex-process-alist)))
(face (face-at-point))
;; Get the colors from the face at point.
(fg
(let ((color (plist-get org-format-latex-options
:foreground)))
(if forbuffer
(cond
((eq color 'auto)
(face-attribute face :foreground nil 'default))
((eq color 'default)
(face-attribute 'default :foreground nil))
(t color))
color)))
(bg
(let ((color (plist-get org-format-latex-options
:background)))
(if forbuffer
(cond
((eq color 'auto)
(face-attribute face :background nil 'default))
((eq color 'default)
(face-attribute 'default :background nil))
(t color))
color)))
(hash (sha1 (prin1-to-string
(list org-format-latex-header
org-latex-default-packages-alist
org-latex-packages-alist
org-format-latex-options
forbuffer value fg bg))))
(imagetype (or (plist-get processing-info :image-output-type) "png"))
(absprefix (expand-file-name prefix dir))
(linkfile (format "%s_%s.%s" prefix hash imagetype))
(movefile (format "%s_%s.%s" absprefix hash imagetype))
(sep (and block-type "\n\n"))
(link (concat sep "[[file:" linkfile "]]" sep))
(options
(org-combine-plists
org-format-latex-options
`(:foreground ,fg :background ,bg))))
(when msg (message msg cnt))
(unless checkdir-flag ; Ensure the directory exists.
(setq checkdir-flag t)
(let ((todir (file-name-directory absprefix)))
(unless (file-directory-p todir)
(make-directory todir t))))
(unless (file-exists-p movefile)
(org-create-formula-image
value movefile options forbuffer processing-type))
(org-place-formula-image link block-type beg end value overlays movefile imagetype)))
((eq processing-type 'mathml)
;; Process to MathML.
(unless (org-format-latex-mathml-available-p)
(user-error "LaTeX to MathML converter not configured"))
(cl-incf cnt)
(when msg (message msg cnt))
(goto-char beg)
(delete-region beg end)
(insert (org-format-latex-as-mathml
value block-type prefix dir)))
(t
(error "Unknown conversion process %s for LaTeX fragments"
processing-type)))))))))))
;; FIXME: Unused; obsoleted; to be removed.
(defun org-place-formula-image (link block-type beg end value overlays movefile imagetype)
"Place an overlay from BEG to END showing MOVEFILE.
The overlay will be above BEG if OVERLAYS is non-nil."
(if overlays
(progn
(dolist (o (overlays-in beg end))
(when (eq (overlay-get o 'org-overlay-type)
'org-latex-overlay)
(delete-overlay o)))
(let ((ov (make-overlay beg end))
(imagetype (or (intern imagetype) 'png)))
(overlay-put ov 'org-overlay-type 'org-latex-overlay)
(overlay-put ov 'evaporate t)
(overlay-put ov
'modification-hooks
(list (lambda (o _flag _beg _end &optional _l)
(delete-overlay o))))
(overlay-put ov
'display
(list 'image :type imagetype :file movefile :ascent 'center)))
(goto-char end))
(delete-region beg end)
(insert
(org-add-props link
(list 'org-latex-src
(replace-regexp-in-string "\"" "" value)
'org-latex-src-embed-type
(if block-type 'paragraph 'character))))))
;; FIXME: Unused; obsoleted; to be removed.
(defun org-create-formula-image
(string tofile options buffer &optional processing-type)
"Create an image from LaTeX source using external processes.
The LaTeX STRING is saved to a temporary LaTeX file, then
converted to an image file by process PROCESSING-TYPE defined in
`org-preview-latex-process-alist'. A nil value defaults to
`org-preview-latex-default-process'.
The generated image file is eventually moved to TOFILE.
The OPTIONS argument controls the size, foreground color and
background color of the generated image.
When BUFFER non-nil, this function is used for LaTeX previewing.
Otherwise, it is used to deal with LaTeX snippets showed in
a HTML file."
(let* ((processing-type (or processing-type
org-preview-latex-default-process))
(processing-info
(cdr (assq processing-type org-preview-latex-process-alist)))
(programs (plist-get processing-info :programs))
(error-message (or (plist-get processing-info :message) ""))
(image-input-type (plist-get processing-info :image-input-type))
(image-output-type (plist-get processing-info :image-output-type))
(post-clean (or (plist-get processing-info :post-clean)
'(".dvi" ".xdv" ".pdf" ".tex" ".aux" ".log"
".svg" ".png" ".jpg" ".jpeg" ".out")))
(latex-header
(or (plist-get processing-info :latex-header)
(org-latex-make-preamble
(org-export-get-environment (org-export-get-backend 'latex))
org-format-latex-header
'snippet)))
(latex-compiler (plist-get processing-info :latex-compiler))
(tmpdir temporary-file-directory)
(texfilebase (make-temp-name
(expand-file-name "orgtex" tmpdir)))
(texfile (concat texfilebase ".tex"))
(image-size-adjust (or (plist-get processing-info :image-size-adjust)
'(1.0 . 1.0)))
(scale (* (if buffer (car image-size-adjust) (cdr image-size-adjust))
(or (plist-get options (if buffer :scale :html-scale)) 1.0)))
(dpi (* scale (if (and buffer (display-graphic-p)) (org--get-display-dpi) 140.0)))
(fg (or (plist-get options (if buffer :foreground :html-foreground))
"Black"))
(bg (or (plist-get options (if buffer :background :html-background))
"Transparent"))
(image-converter
(or (and (string= bg "Transparent")
(plist-get processing-info :transparent-image-converter))
(plist-get processing-info :image-converter)))
(log-buf (get-buffer-create "*Org Preview LaTeX Output*"))
(resize-mini-windows nil)) ;Fix Emacs flicker when creating image.
(dolist (program programs)
(org-check-external-command program error-message))
(if (eq fg 'default)
(setq fg (org-latex-color :foreground))
(setq fg (org-latex-color-format fg)))
(setq bg (cond
((eq bg 'default) (org-latex-color :background))
((string= bg "Transparent") nil)
(t (org-latex-color-format bg))))
;; Remove TeX \par at end of snippet to avoid trailing space.
(if (string-suffix-p string "\n")
(aset string (1- (length string)) ?%)
(setq string (concat string "%")))
(with-temp-file texfile
(insert latex-header)
(insert "\n\\begin{document}\n"
"\\definecolor{fg}{rgb}{" fg "}%\n"
(if bg
(concat "\\definecolor{bg}{rgb}{" bg "}%\n"
"\n\\pagecolor{bg}%\n")
"")
"\n{\\color{fg}\n"
string
"\n}\n"
"\n\\end{document}\n"))
(let* ((err-msg (format "Please adjust `%s' part of \
`org-preview-latex-process-alist'."
processing-type))
(image-input-file
(org-compile-file
texfile latex-compiler image-input-type err-msg log-buf))
(image-output-file
(org-compile-file
image-input-file image-converter image-output-type err-msg log-buf
`((?D . ,(shell-quote-argument (format "%s" dpi)))
(?S . ,(shell-quote-argument (format "%s" (/ dpi 140.0))))))))
(copy-file image-output-file tofile 'replace)
(dolist (e post-clean)
(when (file-exists-p (concat texfilebase e))
(delete-file (concat texfilebase e))))
image-output-file)))
;; FIXME: Unused; obsoleted; to be removed.
(defun org-html-format-latex (latex-frag processing-type info)
"Format a LaTeX fragment LATEX-FRAG into HTML.
PROCESSING-TYPE designates the tool used for conversion. It can
be `mathjax', `verbatim', `html', nil, t or symbols in
`org-preview-latex-process-alist', e.g., `dvipng', `dvisvgm' or
`imagemagick'. See `org-html-with-latex' for more information.
INFO is a plist containing export properties."
(let ((cache-relpath "") (cache-dir ""))
(unless (or (eq processing-type 'mathjax)
(eq processing-type 'html))
(let ((bfn (or (buffer-file-name)
(make-temp-name
(expand-file-name "latex" temporary-file-directory))))
(latex-header
(let ((header (plist-get info :latex-header)))
(and header
(concat (mapconcat
(lambda (line) (concat "#+LATEX_HEADER: " line))
(org-split-string header "\n")
"\n")
"\n")))))
(setq cache-relpath
(concat (file-name-as-directory org-preview-latex-image-directory)
(file-name-sans-extension
(file-name-nondirectory bfn)))
cache-dir (file-name-directory bfn))
;; Re-create LaTeX environment from original buffer in
;; temporary buffer so that dvipng/imagemagick can properly
;; turn the fragment into an image.
(setq latex-frag (concat latex-header latex-frag))))
(org-export-with-buffer-copy
:to-buffer (get-buffer-create " *Org HTML Export LaTeX*")
:drop-visibility t :drop-narrowing t :drop-contents t
(erase-buffer)
(insert latex-frag)
(org-format-latex cache-relpath nil nil cache-dir nil
"Creating LaTeX Image..." nil processing-type)
(buffer-string))))
(make-obsolete #'org-format-latex "to be removed" "9.7")
(make-obsolete #'org-create-formula-image "to be removed" "9.7")
(make-obsolete #'org-html-format-latex "to be removed" "9.7")
;; FIXME: Unused; obsoleted; to be removed.
(defun org-let (list &rest body) ;FIXME: So many kittens are suffering here.
(declare (indent 1) (obsolete cl-progv "2021"))

File diff suppressed because it is too large Load Diff

View File

@ -359,10 +359,20 @@ If EXCLUDE-TMP is non-nil, ignore temporary buffers."
;;; Async stack
(defvar org-async--stack nil
"List of (%PROCESS :start-time %FLOAT :success %FUN :failure %FUN :timeout %FLOAT :buffer %BUFFER) forms.")
"List of async currently running task forms.
Each running task is represented by a list with the following structure:
(%PROCESS :success %FUN :failure %FUN
:filter %FUN :buffer %BUFFER
:timeout %FLOAT :start-time %FLOAT
:info %SEXP)")
(defvar org-async--wait-queue nil
"List of (%PROCESS :success %FUN :failure %FUN :timeout %FLOAT :buffer %BUFFER) forms.")
"List of async queued task forms.
Each queued task is represented by a list with the following structure:
(%PROCESS :success %FUN :failure %FUN
:filter %FUN :buffer %BUFFER
:info %SEXP :dir %STRING
:timeout %FLOAT :coding %SYMBOL)")
(defvar org-async-process-limit 4
"Maximum number of processes to run at once.")
@ -375,8 +385,8 @@ If EXCLUDE-TMP is non-nil, ignore temporary buffers."
(defvar org-async--counter 0)
(cl-defun org-async-call (proc &key success failure filter buffer info timeout now
(dir default-directory))
(cl-defun org-async-call (proc &key success failure filter buffer info timeout now process-variables
(dir default-directory) (coding 'utf-8))
"Start PROC and register it with callbacks SUCCESS and FAILURE.
PROC can be a process, string, or list. A string will be run as
@ -403,9 +413,13 @@ namely:
process-buffer, and INFO as arguments.
- A function, which is called with exit-code, process-buffer,
and INFO as arguments.
- A list, which is used as an argument list for a new `org-async-call' invocation.
- A list, which is used as an argument list for a new `org-async-call' call.
- nil, which does nothing.
When PROC succeeds by exiting with an exit code of zero, the SUCCESS
callback will be run. Should PROC fail, or be killed, or the process
runs for more than TIMEOUT seconds, the FAILURE callback will be run.
A function FILTER can be provided, in which case it will be
called in the same manner as a normal procecss filter, however
the function FILTER will be called with INFO as a third argument.
@ -415,12 +429,20 @@ When BUFFER is non-nil, there are two other major differences:
- Note that `point' is left alone and is not moved by this.
- The process buffer is the current buffer when FILTER is called.
When PROC succeeds by exiting with an exit code of zero, the SUCCESS
callback will be run. Should PROC fail, or be killed, or the process
runs for more than TIMEOUT seconds, the FAILURE callback will be run.
When CODING is non-nil, both the process encode and decode system
will be set to CODING. If unset, UTF-8 is used.
When NOW is non-nil, the PROC is started immediately, regardless
of `org-async-process-limit'."
of `org-async-process-limit'.
For improved performance, PROCESS-VARIABLES is a list of
let-style bindings that should be applied to the process.
Variables are supported on an individual basis (i.e. only certain
variables can be set), with the default value being equivalent to:
:process-variables ((process-adaptive-read-buffering nil)
(process-connection-type nil)
(read-process-output-max 65536))"
(cond
;; Called with a task (as can be used with callbacks), so re-call
;; with expanded arguments.
@ -430,7 +452,13 @@ of `org-async-process-limit'."
;; Start the async process now.
((or now (< (length org-async--stack) org-async-process-limit))
(let ((proc
(let ((default-directory (or dir default-directory)))
(let ((default-directory (or dir default-directory))
(process-adaptive-read-buffering ; No by default
(cadr (or (assoc 'process-adaptive-read-buffering process-variables) nil)))
(process-connection-type ; Use a pipe by default
(cadr (or (assoc 'process-connection-type process-variables) nil)))
(read-process-output-max ; Can be worth changing depending on the process
(or (assq 'read-process-output-max process-variables) read-process-output-max)))
(cond ((processp proc) proc)
((stringp proc)
(start-process-shell-command
@ -447,15 +475,17 @@ of `org-async-process-limit'."
(set-process-sentinel proc #'org-async--sentinel)
(when filter
(set-process-filter proc #'org-async--filter))
(when coding
(set-process-coding-system proc coding coding))
(push (list proc
:success success
:failure failure
:filter filter
:timeout timeout
:buffer (if (eq buffer t)
(cons :temp (generate-new-buffer " *temp*" t))
buffer)
:info info
:timeout timeout
:start-time (float-time))
org-async--stack)
(org-async--monitor t)
@ -467,13 +497,24 @@ of `org-async-process-limit'."
(list (list proc
:success success
:failure failure
:dir dir
:info info
:filter filter
:buffer buffer
:info info
:dir dir
:timeout timeout
:filter filter))))
:coding coding))))
(last org-async--wait-queue))))
(defvar org-async--blocking-tasks nil
"List of async tasks currently being waited on.")
(defun org-async-wait-for (&rest tasks)
"Block until every task of TASKS has finished (including callback tasks)."
(setq org-async--blocking-tasks tasks)
(while org-async--blocking-tasks
(dolist (task org-async--blocking-tasks)
(accept-process-output (car task)))))
(defun org-async--filter (process string)
"After PROCESS recieves STRING, call the async filter.
This is implementated to satisfy the filter function documentation in
@ -510,9 +551,13 @@ Otherwise, the failure callback is run."
(when (assq process org-async--stack)
(let* ((proc-info (cdr (assq process org-async--stack)))
(buffer-val (plist-get proc-info :buffer))
(proc-buf (if (consp buffer-val) (cdr buffer-val) buffer-val)))
(proc-buf (if (consp buffer-val) (cdr buffer-val) buffer-val))
(blocking-p (cl-member process org-async--blocking-tasks :key #'car)))
(setq org-async--stack
(delq (assq process org-async--stack) org-async--stack))
;; Ensure that any filter is called on the final output
;; prior to the callbacks.
(while (accept-process-output process))
(org-async--execute-callback
(plist-get
proc-info
@ -521,14 +566,18 @@ Otherwise, the failure callback is run."
:success :failure))
(process-exit-status process)
proc-buf
(plist-get proc-info :info))
(plist-get proc-info :info)
blocking-p)
(when blocking-p
(setq org-async--blocking-tasks
(cl-delete process org-async--blocking-tasks :key #'car)))
(when (and (consp buffer-val) (eq :temp (car buffer-val)))
(kill-buffer proc-buf)))
(when (and org-async--wait-queue
(< org-async-process-limit (length org-async--stack)))
(apply #'org-async-call (pop org-async--wait-queue)))))
(defun org-async--execute-callback (callback exit-code process-buffer info)
(defun org-async--execute-callback (callback exit-code process-buffer info &optional blocking)
"Run CALLBACK with EXIT-CODE, PROCESS-BUFFER, and INFO.
CALLBACK can take one of four forms:
- A string, which is used a `message' string with EXIT-CODE,
@ -539,7 +588,9 @@ CALLBACK can take one of four forms:
- An (org-async-task ...) structure, which passed to an
`org-async-call' invocation.
- A list of callbacks, which are individually evaluated.
- nil, which does nothing."
- nil, which does nothing.
When BLOCKING is set, all callback tasks are made blocking."
(cond
((stringp callback)
(message callback exit-code process-buffer info))
@ -547,9 +598,11 @@ CALLBACK can take one of four forms:
(funcall callback exit-code process-buffer info))
((consp callback)
(if (eq (car callback) 'org-async-task)
(org-async-call callback)
(if blocking
(push (org-async-call callback) org-async--blocking-tasks)
(org-async-call callback))
(dolist (clbk callback)
(org-async--execute-callback clbk exit-code process-buffer info))))
(org-async--execute-callback clbk exit-code process-buffer info blocking))))
((null callback)) ; Do nothing.
(t (message "Ignoring invalid `org-async-call' callback: %S" callback))))

View File

@ -602,22 +602,27 @@ MISC, if non-nil will be appended to the collection. It must be a plist."
;;;; Reading container data.
(defvar org-persist--inhibit-container-normalization nil
"Prevent `org-persist--normalize-container' from doing anything.")
(defun org-persist--normalize-container (container &optional inner)
"Normalize CONTAINER representation into (type . settings).
When INNER is non-nil, do not try to match as list of containers."
(pcase container
((or `elisp `elisp-data `version `file `index `url)
`(,container nil))
((or (pred keywordp) (pred stringp) `(quote . ,_))
`(elisp-data ,container))
((pred symbolp)
`(elisp ,container))
(`(,(or `elisp `elisp-data `version `file `index `url) . ,_)
container)
((and (pred listp) (guard (not inner)))
(mapcar (lambda (c) (org-persist--normalize-container c 'inner)) container))
(_ (error "org-persist: Unknown container type: %S" container))))
(if org-persist--inhibit-container-normalization
container
(pcase container
((or `elisp `elisp-data `version `file `index `url)
`(,container nil))
((or (pred keywordp) (pred stringp) `(quote . ,_))
`(elisp-data ,container))
((pred symbolp)
`(elisp ,container))
(`(,(or `elisp `elisp-data `version `file `index `url) . ,_)
container)
((and (pred listp) (guard (not inner)))
(mapcar (lambda (c) (org-persist--normalize-container c 'inner)) container))
(_ (error "org-persist: Unknown container type: %S" container)))))
(defvar org-persist--associated-buffer-cache (make-hash-table :weakness 'key)
"Buffer hash cache.")
@ -823,20 +828,23 @@ COLLECTION is the plist holding data collection."
(defun org-persist-write:file (c collection)
"Write file container C according to COLLECTION."
(org-persist-collection-let collection
(when (or (and path (file-exists-p path))
(and (stringp (cadr c)) (file-exists-p (cadr c))))
(when (and (stringp (cadr c)) (file-exists-p (cadr c)))
(setq path (cadr c)))
(let* ((persist-file (plist-get collection :persist-file))
(ext (file-name-extension path))
(file-copy (org-file-name-concat
org-persist-directory
(format "%s-%s.%s" persist-file (md5 path) ext))))
(unless (file-exists-p file-copy)
(unless (file-exists-p (file-name-directory file-copy))
(make-directory (file-name-directory file-copy) t))
(copy-file path file-copy 'overwrite))
(format "%s-%s.%s" persist-file (md5 path) ext)))))
(if (or (and path (file-exists-p path))
(and (stringp (cadr c)) (file-exists-p (cadr c))))
(progn
(when (and (stringp (cadr c)) (file-exists-p (cadr c)))
(setq path (cadr c)))
(let* ((persist-file (plist-get collection :persist-file))
(ext (file-name-extension path))
(file-copy (org-file-name-concat
org-persist-directory
(format "%s-%s.%s" persist-file (md5 path) ext))))
(unless (file-exists-p file-copy)
(unless (file-exists-p (file-name-directory file-copy))
(make-directory (file-name-directory file-copy) t))
(copy-file path file-copy 'overwrite))
(format "%s-%s.%s" persist-file (md5 path) ext)))
(when-let ((file-copy (org-persist-read c associated)))
(file-relative-name file-copy org-persist-directory)))))
(defun org-persist-write:url (c collection)
"Write url container C according to COLLECTION."
@ -941,26 +949,27 @@ VALUE pairs.
When WRITE-IMMEDIATELY is non-nil, the return value will be the same
with `org-persist-write'."
(unless org-persist--index (org-persist--load-index))
(setq container (org-persist--normalize-container container))
(when inherit
(setq inherit (org-persist--normalize-container inherit))
(let ((inherited-collection (org-persist--get-collection inherit associated))
new-collection)
(unless (member container (plist-get inherited-collection :container))
(setq new-collection
(plist-put (copy-sequence inherited-collection) :container
(cons container (plist-get inherited-collection :container))))
(org-persist--remove-from-index inherited-collection)
(org-persist--add-to-index new-collection))))
(let ((collection (org-persist--get-collection container associated misc)))
(when (and expiry (not inherit))
(when expiry (plist-put collection :expiry expiry))))
(when (or (bufferp associated) (bufferp (plist-get associated :buffer)))
(with-current-buffer (if (bufferp associated)
associated
(plist-get associated :buffer))
(add-hook 'kill-buffer-hook #'org-persist-write-all-buffer nil 'local)))
(when write-immediately (org-persist-write container associated)))
(let ((container (org-persist--normalize-container container))
(inherit (and inherit (org-persist--normalize-container inherit)))
(org-persist--inhibit-container-normalization t))
(when inherit
(let ((inherited-collection (org-persist--get-collection inherit associated))
new-collection)
(unless (member container (plist-get inherited-collection :container))
(setq new-collection
(plist-put (copy-sequence inherited-collection) :container
(cons container (plist-get inherited-collection :container))))
(org-persist--remove-from-index inherited-collection)
(org-persist--add-to-index new-collection))))
(let ((collection (org-persist--get-collection container associated misc)))
(when (and expiry (not inherit))
(when expiry (plist-put collection :expiry expiry))))
(when (or (bufferp associated) (bufferp (plist-get associated :buffer)))
(with-current-buffer (if (bufferp associated)
associated
(plist-get associated :buffer))
(add-hook 'kill-buffer-hook #'org-persist-write-all-buffer nil 'local)))
(when write-immediately (org-persist-write container associated))))
(cl-defun org-persist-unregister (container &optional associated &key remove-related)
"Unregister CONTAINER in ASSOCIATED to be persistent.
@ -1075,6 +1084,9 @@ have the same meaning as in `org-persist-read'."
"Call `org-persist-load-all' in current buffer."
(org-persist-load-all (current-buffer)))
(defvar org-persist--inhibit-write nil
"Whether `org-persist-write' should be inhibited.")
(defun org-persist-write (container &optional associated ignore-return)
"Save CONTAINER according to ASSOCIATED.
ASSOCIATED can be a plist, a buffer, or a string.
@ -1084,31 +1096,33 @@ The return value is nil when writing fails and the written value (as
returned by `org-persist-read') on success.
When IGNORE-RETURN is non-nil, just return t on success without calling
`org-persist-read'."
(setq associated (org-persist--normalize-associated associated))
;; Update hash
(when (and (plist-get associated :file)
(plist-get associated :hash)
(get-file-buffer (plist-get associated :file)))
(setq associated (org-persist--normalize-associated (get-file-buffer (plist-get associated :file)))))
(let ((collection (org-persist--get-collection container associated)))
(setf collection (plist-put collection :associated associated))
(unless (or
;; Prevent data leakage from encrypted files.
;; We do it in somewhat paranoid manner and do not
;; allow anything related to encrypted files to be
;; written.
(and (plist-get associated :file)
(string-match-p epa-file-name-regexp (plist-get associated :file)))
(seq-find (lambda (v)
(run-hook-with-args-until-success 'org-persist-before-write-hook v associated))
(plist-get collection :container)))
(when (or (file-exists-p org-persist-directory) (org-persist--save-index))
(let ((file (org-file-name-concat org-persist-directory (plist-get collection :persist-file)))
(data (mapcar (lambda (c) (cons c (org-persist-write:generic c collection)))
(plist-get collection :container))))
(puthash file data org-persist--write-cache)
(org-persist--write-elisp-file file data)
(or ignore-return (org-persist-read container associated)))))))
(unless org-persist--inhibit-write
(setq associated (org-persist--normalize-associated associated))
;; Update hash
(when (and (plist-get associated :file)
(plist-get associated :hash)
(get-file-buffer (plist-get associated :file)))
(setq associated (org-persist--normalize-associated (get-file-buffer (plist-get associated :file)))))
(let ((collection (org-persist--get-collection container associated))
(org-persist--inhibit-write t))
(setf collection (plist-put collection :associated associated))
(unless (or
;; Prevent data leakage from encrypted files.
;; We do it in somewhat paranoid manner and do not
;; allow anything related to encrypted files to be
;; written.
(and (plist-get associated :file)
(string-match-p epa-file-name-regexp (plist-get associated :file)))
(cl-some (lambda (v)
(run-hook-with-args-until-success 'org-persist-before-write-hook v associated))
(plist-get collection :container)))
(when (or (file-exists-p org-persist-directory) (org-persist--save-index))
(let ((file (org-file-name-concat org-persist-directory (plist-get collection :persist-file)))
(data (mapcar (lambda (c) (cons c (org-persist-write:generic c collection)))
(plist-get collection :container))))
(puthash file data org-persist--write-cache)
(org-persist--write-elisp-file file data)
(or ignore-return (org-persist-read container associated))))))))
(defun org-persist-write-all (&optional associated)
"Save all the persistent data.

View File

@ -808,9 +808,42 @@ as `org-src-fontify-natively' is non-nil."
(1+ pt) (1- (point)) 'face 'org-inline-src-block)))
(font-lock-append-text-property
(1- (point)) (point) 'face '(org-inline-src-block shadow))
(setq pt (point)))))
(setq pt (point)))
(when (and org-inline-src-prettify-results
(re-search-forward "\\= {{{results(" limit t))
(font-lock-append-text-property pt (1+ pt) 'face 'org-inline-src-block)
(goto-char pt))))
t)))
(defun org-fontify-inline-src-results (limit)
"Apply prettify-symbols modifications to inline results blocks.
Performed according to `org-inline-src-prettify-results'."
(when (and org-inline-src-prettify-results
(re-search-forward "{{{results(\\(.+?\\))}}}" limit t))
(remove-list-of-text-properties (match-beginning 0) (point)
'(composition
prettify-symbols-start
prettify-symbols-end))
(font-lock-append-text-property (match-beginning 0) (match-end 0)
'face 'org-block)
(let ((start (match-beginning 0)) (end (match-beginning 1)))
(with-silent-modifications
(compose-region start end (if (eq org-inline-src-prettify-results t)
"(" (car org-inline-src-prettify-results)))
(add-text-properties start end `(prettify-symbols-start ,start prettify-symbols-end ,end))))
(let ((start (match-end 1)) (end (point)))
(with-silent-modifications
(compose-region start end (if (eq org-inline-src-prettify-results t)
")" (cdr org-inline-src-prettify-results)))
(add-text-properties start end `(prettify-symbols-start ,start prettify-symbols-end ,end))))
t))
(defun org-toggle-inline-results-display ()
"Toggle the literal or contracted display of inline src blocks results."
(interactive)
(setq org-inline-src-prettify-results (not org-inline-src-prettify-results))
(org-restart-font-lock))
;;; Escape contents

View File

@ -4738,7 +4738,7 @@ The following commands are available:
(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-latex-preview (org-latex-preview '(16)))
(when org-startup-with-latex-preview (org-latex-preview 'buffer))
(unless org-inhibit-startup-visibility-stuff (org-cycle-set-startup-visibility))
(when org-startup-truncated (setq truncate-lines t))
(when org-startup-numerated (require 'org-num) (org-num-mode 1))
@ -5179,6 +5179,15 @@ by a #."
:version "24.1"
:group 'org-appearance)
(defcustom org-inline-src-prettify-results t
"Whether to use (ab)use prettify-symbols-mode on {{{results(...)}}}.
Either t or a cons cell of strings which are used as substitutions
for the start and end of inline results, respectively."
:type '(choice boolean (cons string string))
:package-version '(Org . "9.5")
:group 'org-appearance
:group 'org-babel)
(defun org-fontify-meta-lines-and-blocks (limit)
(condition-case-unless-debug nil
(org-fontify-meta-lines-and-blocks-1 limit)
@ -5439,7 +5448,7 @@ Result depends on variable `org-highlight-latex-and-related'."
(re-latex
(when (or (memq 'latex org-highlight-latex-and-related)
(memq 'native org-highlight-latex-and-related))
(let ((matchers (plist-get org-latex-preview-options :matchers)))
(let ((matchers (plist-get org-latex-preview-appearance-options :matchers)))
(delq nil
(mapcar (lambda (x)
(and (member (car x) matchers) (nth 1 x)))
@ -5453,6 +5462,9 @@ Result depends on variable `org-highlight-latex-and-related'."
(append re-latex re-entities re-sub)
"\\|"))))
(defvar org-latex-preview-appearance-options) ; Defined in org-latex-preview.el.
(declare-function org-latex-preview--face-around "org-latex-preview" (start end))
(defun org-do-latex-and-related (limit)
"Highlight LaTeX snippets and environments, entities and sub/superscript.
Stop at first highlighted object, if any. Return t if some
@ -5493,6 +5505,17 @@ highlighting was done, nil otherwise."
'face 'org-latex-and-related))
(add-text-properties (+ offset (match-beginning 0)) (match-end 0)
'(font-lock-multiline t))
;; Refresh the face of LaTeX previews (when applicable).
(when (eq (plist-get org-latex-preview-appearance-options :foreground)
'auto)
(dolist (ov (overlays-at start))
(when (and (eq (overlay-get ov 'org-overlay-type)
'org-latex-overlay)
(overlay-get ov 'face)
(not (eq (overlay-get ov 'face) 'error)))
(overlay-put ov 'face
(org-latex-preview--face-around
(overlay-start ov) (overlay-end ov))))))
(throw 'found t)))))
nil))))
@ -5653,6 +5676,10 @@ needs to be inserted at a specific position in the font-lock sequence.")
(list (concat "\\<" org-clock-string) '(0 'org-special-keyword t))
;; Emphasis
(when org-fontify-emphasized-text '(org-do-emphasis-faces))
;; Semantic seperator
(when org-fontify-semantic-seperator
`("\u200b"
(0 '(face shadow display ,org-semantic-seperator-displayed))))
;; Checkboxes
`(,org-list-full-item-re 3 'org-checkbox prepend lax)
(when (cdr (assq 'checkbox org-list-automatic-rules))
@ -5773,6 +5800,23 @@ needs to be inserted at a specific position in the font-lock sequence.")
(throw 'match t))))
nil))))
(defcustom org-fontify-semantic-seperator t
"Whether to prettify the semantic seperator.
When non-nil, `org-semantic-seperator-displayed' will be displayed in place of the semantic seperator."
:type 'boolean)
(defcustom org-semantic-seperator-displayed
#("" 0 1 (display ((raise -0.3) (height 0.3))))
"String that should be displayed in place of the semantic seperator.
This is only relevant when `org-fontify-semantic-seperator' is non-nil."
:type 'string)
(defun org-toggle-semantic-seperator-display ()
"Toggle display of the semantic seperator."
(interactive)
(cl-callf not org-fontify-semantic-seperator)
(user-error "TODO make this work better"))
(defun org-fontify-like-in-org-mode (s &optional odd-levels)
"Fontify string S like in Org mode."
(with-temp-buffer
@ -15553,8 +15597,6 @@ environment remains unintended."
;;;; LaTeX fragments
(require 'org-latex-preview)
(defun org-inside-LaTeX-fragment-p (&optional element)
"Test if point is inside a LaTeX fragment or environment.
@ -19101,12 +19143,23 @@ a footnote definition, try to fill the first paragraph within."
(save-excursion
(goto-char beg)
(let ((cuts (list beg)))
;; Cut fill on line breaks.
(while (re-search-forward "\\\\\\\\[ \t]*\n" end t)
(when (org-element-type-p
(save-excursion (backward-char)
(org-element-context))
'line-break)
(push (point) cuts)))
;; Cut fill on displayed equations.
(while (re-search-forward "^[ \t]*\\\\\\[" end t)
(let ((el (org-element-context)))
(when (eq 'latex-fragment (org-element-type el))
(setf cuts (append
(list (org-element-property :end el)
(- (org-element-property :end el) 2)
(+ (org-element-property :begin el) 2)
(org-element-property :begin el))
cuts)))))
(dolist (c (delq end cuts))
(fill-region-as-paragraph c end justify)
(setq end c))))

View File

@ -39,6 +39,8 @@
(require 'ox)
(require 'ox-publish)
(require 'table)
(require 'org-latex-preview)
(require 'ox-mathml)
;;; Function Declarations
@ -107,7 +109,8 @@
(verbatim . org-html-verbatim)
(verse-block . org-html-verse-block))
:filters-alist '((:filter-options . org-html-infojs-install-script)
(:filter-parse-tree . org-html-image-link-filter)
(:filter-parse-tree org-html-image-link-filter
org-html-prepare-latex-images)
(:filter-final-output . org-html-final-function))
:menu-entry
'(?h "Export to HTML"
@ -155,6 +158,7 @@
(:html-infojs-template nil nil org-html-infojs-template)
(:html-inline-image-rules nil nil org-html-inline-image-rules)
(:html-link-org-files-as-html nil nil org-html-link-org-files-as-html)
(:html-latex-image-options nil nil org-html-latex-image-options)
(:html-mathjax-options nil nil org-html-mathjax-options)
(:html-mathjax-template nil nil org-html-mathjax-template)
(:html-metadata-timestamp-format nil nil org-html-metadata-timestamp-format)
@ -319,7 +323,7 @@ This affects IDs that are determined from the ID property.")
pre.src-awk:before { content: 'Awk'; }
pre.src-authinfo::before { content: 'Authinfo'; }
pre.src-C:before { content: 'C'; }
/* pre.src-C++ doesn't work in CSS */
pre.src-C\\+\\+:before { content: 'C++'; }
pre.src-clojure:before { content: 'Clojure'; }
pre.src-css:before { content: 'CSS'; }
pre.src-D:before { content: 'D'; }
@ -1168,6 +1172,25 @@ See `format-time-string' for more information on its components."
:package-version '(Org . "8.0")
:type 'string)
(defcustom org-html-latex-image-options
'(:foreground "Black" :background "Transparent"
:page-width 1.0 :scale 1.0 :image-dir "ltximg" :inline nil)
"LaTeX preview options that apply to generated images.
This is a HTML-specific counterpart to
`org-latex-preview-appearance-options', which see.
This supports two extra properties,
:image-dir an html-export counterpart of `org-latex-preview-cache', and
:inline a list of image formats (or single format symbol) that
should not be saved according to :image-dir, but instead
inlined in the generated HTML. Valid format symbols are:
- png, to inline png images using <img> with a data URI
- svg, to inline svg images using <img> with a data URI
- svg-embed, to inline svg images using an <svg> element"
:group 'org-export-html
:package-version '(Org . "9.7")
:type 'plist)
;;;; Template :: Mathjax
(defcustom org-html-mathjax-options
@ -1653,6 +1676,31 @@ https://developer.mozilla.org/en-US/docs/Mozilla/Mobile/Viewport_meta_tag"
:package-version '(Org . "9.1")
:type 'string)
;;;; LaTeX Fragments
(defcustom org-latex-to-html-convert-command nil
"Command to convert LaTeX fragments to HTML.
This command is very open-ended: the output of the command will
directly replace the LaTeX fragment in the resulting HTML.
Replace format-specifiers in the command as noted below and use
`shell-command' to convert LaTeX to HTML.
%i: The LaTeX fragment to be converted.
For example, this could be used with LaTeXML as
\"latexmlc \\='literal:%i\\=' --profile=math --preload=siunitx.sty 2>/dev/null\"."
:group 'org-latex
:package-version '(Org . "9.4")
:type '(choice
(const :tag "None" nil)
(string :tag "Shell command")))
(defun org-format-latex-as-html (latex-fragment)
"Convert LATEX-FRAGMENT to HTML.
This uses `org-latex-to-html-convert-command', which see."
(let ((cmd (format-spec org-latex-to-html-convert-command
`((?i . ,latex-fragment)))))
(message "Running %s" cmd)
(shell-command-to-string cmd)))
;;;; Todos
@ -1777,11 +1825,7 @@ a communication channel."
(org-html--make-attribute-string
(org-combine-plists
(list :src source
:alt (if (string-match-p
(concat "^" org-preview-latex-image-directory) source)
(org-html-encode-plain-text
(org-find-text-property-in-string 'org-latex-src source))
(file-name-nondirectory source)))
:alt (file-name-nondirectory source))
(if (string= "svg" (file-name-extension source))
(org-combine-plists '(:class "org-svg") attributes '(:fallback nil))
attributes)))
@ -2991,58 +3035,102 @@ CONTENTS is nil. INFO is a plist holding contextual information."
;;;; LaTeX Environment
(defun org-html-format-latex (latex-frag processing-type info)
"Format a LaTeX fragment LATEX-FRAG into HTML.
PROCESSING-TYPE designates the tool used for conversion. It can
be `mathjax', `verbatim', `html', nil, t or symbols in
`org-latex-preview-process-alist', e.g., `dvipng', `dvisvgm' or
`imagemagick'. See `org-html-with-latex' for more information.
INFO is a plist containing export properties."
(let ((cache-relpath "") (cache-dir ""))
(unless (or (eq processing-type 'mathjax)
(eq processing-type 'html))
(let ((bfn (or (buffer-file-name)
(make-temp-name
(expand-file-name "latex" temporary-file-directory))))
(latex-header
(let ((header (plist-get info :latex-header)))
(and header
(concat (mapconcat
(lambda (line) (concat "#+LATEX_HEADER: " line))
(org-split-string header "\n")
"\n")
"\n")))))
(setq cache-relpath
(concat (file-name-as-directory org-preview-latex-image-directory)
(file-name-sans-extension
(file-name-nondirectory bfn)))
cache-dir (file-name-directory bfn))
;; Re-create LaTeX environment from original buffer in
;; temporary buffer so that dvipng/imagemagick can properly
;; turn the fragment into an image.
(setq latex-frag (concat latex-header latex-frag))))
(org-export-with-buffer-copy
:to-buffer (get-buffer-create " *Org HTML Export LaTeX*")
:drop-visibility t :drop-narrowing t :drop-contents t
(erase-buffer)
(insert latex-frag)
(org-latex-preview-replace-fragments
cache-relpath processing-type cache-dir "Creating LaTeX Image...")
(buffer-string))))
(defun org-html-prepare-latex-images (parse-tree _backend info)
"Make sure that appropriate preview images exist for all LaTeX.
TODO."
(when (assq (plist-get info :with-latex) org-latex-preview-process-alist)
(let* ((latex-preamble
(or org-latex-preview--preamble-content
(setq org-latex-preview--preamble-content
(org-latex-preview--get-preamble))))
(elements
(org-element-map parse-tree
'(latex-fragment latex-environment)
#'identity
info))
(entries-and-numbering
(org-latex-preview--construct-entries
elements t parse-tree))
(processing-type (plist-get info :with-latex))
(processing-info
(cdr (assq processing-type org-latex-preview-process-alist)))
(imagetype (or (plist-get processing-info :image-output-type) "png"))
(numbering-offsets (cons nil (cadr entries-and-numbering)))
(html-options (plist-get info :html-latex-image-options))
(element-hash-table (make-hash-table :test #'eq :size (length elements)))
fragment-info prev-fg prev-bg)
(cl-loop
for entry in (car entries-and-numbering)
for element in elements
do
(pcase-let* ((`(,beg ,end ,provided-value) entry)
(value (or provided-value
(buffer-substring-no-properties beg end)))
(fg (plist-get html-options :foreground))
(bg (plist-get html-options :background))
(number (car (setq numbering-offsets (cdr numbering-offsets))))
(hash (org-latex-preview--hash
processing-type latex-preamble value imagetype fg bg number))
(options (org-combine-plists
org-latex-preview-appearance-options
html-options
(list :number number
:continue-color
(and (equal prev-bg bg)
(equal prev-fg fg))))))
(puthash element hash element-hash-table)
(unless (org-latex-preview--get-cached hash)
(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
(apply #'org-async-wait-for
(org-latex-preview--create-image-async
processing-type
(nreverse fragment-info)
:latex-preamble latex-preamble
:appearance-options html-options)))
(plist-put info :html-latex-preview-hash-table element-hash-table)
nil)))
(defun org-html--wrap-latex-environment (contents _ &optional caption label)
(defun org-html--as-latex (element info &optional content)
(let ((content (or content (org-element-property :value element))))
(pcase (plist-get info :with-latex)
('verbatim ; Do nothing.
content)
((or 't 'mathjax)
(cond ; Prepare for MathJax processing.
((string-match-p "\\`\\$\\$" content)
(concat "\\[" (substring content 2 -2) "\\]"))
((string-match-p "\\`\\$" content)
(concat "\\(" (substring content 1 -1) "\\)"))
(t content)))
('html
(org-format-latex-as-html content))
('mathml
(if-let ((path (org-mathml-convert-latex-cached content)))
(with-temp-buffer
(insert-file-contents path)
(buffer-string))
content))
((and ptype (guard (assq ptype org-latex-preview-process-alist)))
(org-html-latex-image element info))
(processing-type
(warn "LaTeX fragment processor `%s' is unknown" processing-type)
content))))
(defun org-html--wrap-latex-environment (contents &optional label)
"Wrap CONTENTS string within appropriate environment for equations.
When optional arguments CAPTION and LABEL are given, use them for
caption and \"id\" attribute."
(format "\n<div%s class=\"equation-container\">\n%s%s\n</div>"
(format "\n<div%s class=\"equation-container\">\n%s\n</div>"
;; ID.
(if (org-string-nw-p label) (format " id=\"%s\"" label) "")
;; Contents.
(format "<span class=\"equation\">\n%s\n</span>" contents)
;; Caption.
(if (not (org-string-nw-p caption)) ""
(format "\n<span class=\"equation-label\">\n%s\n</span>"
caption))))
(format "<span class=\"equation\">\n%s\n</span>" contents)))
(defun org-html--math-environment-p (element &optional _)
"Non-nil when ELEMENT is a LaTeX math environment.
@ -3074,57 +3162,141 @@ For instance, change an `equation' environment to `equation*'."
"Transcode a LATEX-ENVIRONMENT element from Org to HTML.
CONTENTS is nil. INFO is a plist holding contextual information."
(let ((processing-type (plist-get info :with-latex))
(latex-frag (org-remove-indentation
(org-element-property :value latex-environment)))
(attributes (org-export-read-attribute :attr_html latex-environment))
(label (org-html--reference latex-environment info t))
(caption (and (org-html--latex-environment-numbered-p latex-environment)
(number-to-string
(org-export-get-ordinal
latex-environment info nil
(lambda (l _)
(and (org-html--math-environment-p l)
(org-html--latex-environment-numbered-p l))))))))
(cond
((memq processing-type '(t mathjax))
(org-html-format-latex
(if (org-string-nw-p label)
(replace-regexp-in-string "\\`.*"
(format "\\&\n\\\\label{%s}" label)
latex-frag)
latex-frag)
'mathjax info))
((assq processing-type org-latex-preview-process-alist)
(let ((formula-link
(org-html-format-latex
(org-html--unlabel-latex-environment latex-frag)
processing-type info)))
(when (and formula-link (string-match "file:\\([^]]*\\)" formula-link))
(let ((source (org-export-file-uri (match-string 1 formula-link))))
(org-html--wrap-latex-environment
(org-html--format-image source attributes info)
info caption label)))))
(t (org-html--wrap-latex-environment latex-frag info caption label)))))
(latex-frag (org-remove-indentation
(org-element-property :value latex-environment)))
(label (org-html--reference latex-environment info t)))
(if (memq processing-type '(t mathjax))
(org-html--as-latex
latex-environment info
(if (org-string-nw-p label)
(replace-regexp-in-string "\\`.*"
(format "\\&\n\\\\label{%s}" label)
latex-frag)
latex-frag))
(org-html--wrap-latex-environment
(org-html--as-latex latex-environment info latex-frag)
label))))
;;;; LaTeX Fragment
(defun org-html-latex-fragment (latex-fragment _contents info)
"Transcode a LATEX-FRAGMENT object from Org to HTML.
CONTENTS is nil. INFO is a plist holding contextual information."
(let ((latex-frag (org-element-property :value latex-fragment))
(processing-type (plist-get info :with-latex)))
(org-html--as-latex latex-fragment info))
(defun org-html-latex-image (element info)
"Transcode the LaTeX fragment or environment ELEMENT from Org to HTML.
INFO is a plist holding contextual information, and it is assumed
that an image for ELEMENT already exists within it."
(let* ((hash (or (gethash element (plist-get info :html-latex-preview-hash-table))
(error "Expected LaTeX preview hash to exist for element, but none found")))
(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))
(block-p (memq (aref (org-element-property :value element) 1) '(?$ ?\[)))
(image-source
(org-html-latex-image--data path-info hash info block-p)))
(unless (and (plist-get (cdr path-info) :height)
(plist-get (cdr path-info) :depth))
(error "Something went wrong during image generation"))
(if (and (eq (plist-get image-options :inline) 'svg-embed)
(eq (plist-get (cdr path-info) :image-type) 'svg))
image-source
(let ((scaling (org-html-latex-image--scaling path-info info)))
(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 block-p
(format "height: %.4fem; display: block" (plist-get scaling :height))
(format "height: %.4fem; vertical-align: -%.4fem; display: inline-block"
(plist-get scaling :height) (plist-get scaling :depth)))
:class (format "org-latex org-latex-%s" (if block-p "block" "inline"))))
info)))))
(defun org-html-latex-image--scaling (image-path-info info)
"Determine the appropriate (<height> . <depth>) of IMAGE-PATH-INFO given INFO."
(let* ((image-options (plist-get info :html-latex-image-options))
(rescale-factor (if (eq (plist-get (cdr image-path-info) :image-type) 'svg)
(plist-get image-options :scale)
1)))
(list :height (* rescale-factor (plist-get (cdr image-path-info) :height))
:depth (* rescale-factor (plist-get (cdr image-path-info) :depth)))))
(defun org-html-latex-image--data (image-path-info hash info &optional block-p)
"Obtaine the image source for IMAGE-PATH-INFO as a string.
This can take the form of a path, data URI, or <svg> element
depending on HASH and INFO. BLOCK-P signals that the image
should be a block 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))
(image-format (plist-get (cdr image-path-info) :image-type))
(source-file (car image-path-info)))
(cond
((memq processing-type '(t mathjax))
(org-html-format-latex latex-frag 'mathjax info))
((memq processing-type '(t html))
(org-html-format-latex latex-frag 'html info))
((assq processing-type org-latex-preview-process-alist)
(let ((formula-link
(org-html-format-latex latex-frag processing-type info)))
(when (and formula-link (string-match "file:\\([^]]*\\)" formula-link))
(let ((source (org-export-file-uri (match-string 1 formula-link))))
(org-html--format-image source nil info)))))
(t latex-frag))))
((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-embed)
(eq image-format 'svg))
(goto-char (point-min))
(let ((svg-closing-tag (and (search-forward "<svg" nil t)
(search-forward ">" nil t))))
(dolist (search '("<!-- This file was generated by dvisvgm [^\n]+ -->"
" height=['\"][^\"']+[\"']"
" width=['\"][^\"']+[\"']"))
(goto-char (point-min))
(when (re-search-forward search svg-closing-tag t)
(replace-match "")))
(goto-char (point-min))
(when (re-search-forward "viewBox=['\"][^\"']+[\"']" svg-closing-tag t)
(insert
" style=\""
(let ((scaling (org-html-latex-image--scaling image-path-info info)))
(if block-p
(format "height: %.4fem; display: block" (plist-get scaling :height))
(format "height: %.4fem; vertical-align: -%.4fem; display: inline-block"
(plist-get scaling :height) (plist-get scaling :depth))))
"\" class=\"org-latex org-latex-"
(if block-p "block" "inline")
"\"")))
(buffer-string))
((eq image-format '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/" (symbol-name image-format) ";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

View File

@ -48,6 +48,7 @@
(defvar engrave-faces-latex-output-style)
(defvar engrave-faces-current-preset-style)
(defvar engrave-faces-latex-mathescape)
(defvar engrave-faces-latex-colorbox-strut)
;;; Define Backend
@ -1286,9 +1287,10 @@ will produce
% Define a Code environment to prettily wrap the fontified code.
\\usepackage[breakable,xparse]{tcolorbox}
\\providecommand{\\codefont}{\\footnotesize}
\\DeclareTColorBox[]{Code}{o}%
{colback=EfD!98!EFD, colframe=EfD!95!EFD,
fontupper=\\footnotesize\\setlength{\\fboxsep}{0pt},
fontupper=\\setlength{\\fboxsep}{0pt}\\codefont,
colupper=EFD,
IfNoValueTF={#1}%
{boxsep=2pt, arc=2.5pt, outer arc=2.5pt,
@ -1312,7 +1314,9 @@ as long as it:
In the default value the colors \"EFD\" and \"EfD\" are provided
as they are respectively the foreground and background colors,
just in case they aren't provided by the generated preamble, so
we can assume they are always set.
we can assume they are always set. The command \"\\codefont\" is
also provided (defaulting to \"\\footnotesize\"), to allow the
font used in \"Code\" environments to be easily tweaked.
Within this preamble there are two recognized macro-like placeholders:
@ -1408,7 +1412,19 @@ default values of which are given by `org-latex-engraved-preamble' and
(alist-get 'default
(if theme
(engrave-faces-get-theme (intern theme))
engrave-faces-current-preset-style)))))))
engrave-faces-current-preset-style))))))
(gen-theme-command
(lambda (theme)
(format "\n\\newcommand{\\engravedtheme%s}{%%\n%s\n}"
(replace-regexp-in-string
"[^A-Za-z]" "" (symbol-name theme))
(replace-regexp-in-string
"\\\\newcommand\\\\efstrut[^\n]*\n" ""
(replace-regexp-in-string
"\\\\newcommand{\\(.+?\\)}\\[1\\]" "\\\\long\\\\def\\1##1"
(replace-regexp-in-string
"#1" "##1"
(funcall gen-theme-spec theme))))))))
(when (stringp engraved-theme)
(setq engraved-theme (intern engraved-theme)))
(when (string-match "^[ \t]*\\[FVEXTRA-SETUP\\][ \t]*\n?" engraved-preamble)
@ -1443,26 +1459,24 @@ default values of which are given by `org-latex-engraved-preamble' and
(if (require 'engrave-faces-latex nil t)
(if engraved-themes
(concat
;; We don't want to re-define the efstrut, so we now need to
;; define it seperately.
(format "\\newcommand\\efstrut{%s}\n\n"
engrave-faces-latex-colorbox-strut)
;; Define default theme
(funcall gen-theme-command engraved-theme)
"\n"
;; Define other themes
(mapconcat
(lambda (theme)
(format
"\n\\newcommand{\\engravedtheme%s}{%%\n%s\n}"
(replace-regexp-in-string "[^A-Za-z]" "" (symbol-name theme))
(replace-regexp-in-string
"newcommand" "renewcommand"
(replace-regexp-in-string
"#" "##"
(funcall gen-theme-spec theme)))))
engraved-themes
gen-theme-command
(cl-remove-if (lambda (theme) (string= theme (symbol-name engraved-theme)))
engraved-themes)
"\n")
"\n\n"
(cond
((memq engraved-theme engraved-themes)
(concat "\\engravedtheme"
(replace-regexp-in-string
"[^A-Za-z]" "" engraved-theme)
"\n"))
(t (funcall gen-theme-spec engraved-theme))))
;; Load the default theme
"\n\n\\engravedtheme"
(replace-regexp-in-string
"[^A-Za-z]" "" (symbol-name engraved-theme))
"\n")
(funcall gen-theme-spec engraved-theme))
(warn "Cannot engrave source blocks. Consider installing `engrave-faces'.")
"% WARNING syntax highlighting unavailable as engrave-faces-latex was missing.\n")
@ -1478,7 +1492,13 @@ default values of which are given by `org-latex-engraved-preamble' and
(bibliography-biblatex
:condition (eq (org-cite-processor info) 'biblatex)
:when bibliography
:snippet org-cite-biblatex--generate-latex-preamble)
:snippet org-cite-biblatex--generate-latex-usepackage)
(bibliography-biblatex-resources
:condition (eq (org-cite-processor info) 'biblatex)
:when bibliography
:snippet org-cite-biblatex--generate-latex-bibresources
:no-precompile t
:order 90)
(bibliography-natbib
:condition (eq (org-cite-processor info) 'natbib)
:when bibliography
@ -2072,7 +2092,13 @@ specified in `org-latex-default-packages-alist' or
"^[ \t]*\\\\documentclass\\(\\(\\[[^]]*\\]\\)?\\)"
class-options header t nil 1))))
(user-error "Unknown LaTeX class `%s'" class)))
generated-preamble)
(header-split (format "\n%%--org-latex-header-temp-split-%d--\n" (random 10000)))
(header (concat (org-element-normalize-string (plist-get info :latex-header))
header-split
(and (not snippet?)
(org-element-normalize-string
(plist-get info :latex-header-extra)))))
generated-preamble preamble-nonprecompilable)
(plist-put info :latex-full-header
(org-element-normalize-string
(org-splice-latex-header
@ -2080,32 +2106,79 @@ specified in `org-latex-default-packages-alist' or
(org-latex--remove-packages org-latex-default-packages-alist info)
(org-latex--remove-packages org-latex-packages-alist info)
snippet?
(mapconcat #'org-element-normalize-string
(list (plist-get info :latex-header)
(and (not snippet?)
(plist-get info :latex-header-extra)))
""))))
(setq generated-preamble
(if snippet?
header)))
(if snippet?
(setq generated-preamble
(progn
(org-latex-guess-inputenc info)
(org-latex-guess-babel-language info)
(org-latex-guess-polyglossia-language info)
"\n% Generated preamble omitted for snippets.")
"\n% Generated preamble omitted for snippets."))
(let (impl-precomp impl-noprecomp)
(dolist (impl (plist-get info :feature-implementations))
(message "LaTeX feature: %s" (car impl))
(if (or impl-noprecomp (plist-get (cdr impl) :no-precompile))
(push impl impl-noprecomp)
(push impl impl-precomp)))
(message "Precomp feats: %S" (reverse (mapcar #'car impl-precomp)))
(message "No precomp feats: %S" (reverse (mapcar #'car impl-noprecomp)))
(setq generated-preamble
(string-join
(org-export-expand-feature-snippets
info (nreverse impl-precomp))
"\n\n")
preamble-nonprecompilable
(string-join
(org-export-expand-feature-snippets
info (nreverse impl-noprecomp))
"\n\n"))))
(let* ((header-parts
(split-string (plist-get info :latex-full-header)
(regexp-quote header-split)))
(header-main (car header-parts))
(header-extra (cadr header-parts))
(preamble
(concat
(org-latex--insert-compiler info)
header-main
"\n"
(string-join
(org-export-expand-feature-snippets info)
"\n\n")
"\n")))
(concat
;; Time-stamp.
(and (plist-get info :time-stamp-file)
(format-time-string "%% Created %Y-%m-%d %a %H:%M\n"))
;; LaTeX compiler.
(org-latex--insert-compiler info)
(plist-get info :latex-full-header)
generated-preamble)))
generated-preamble
"\n"))
(format-file
(and org-latex-precompile
;; Precompilation is disabled for xelatex/lualatex for now.
(if (member (plist-get info :latex-compiler)
'("xelatex" "lualatex"))
(progn
(display-warning
'(org latex-export disable-local-precompile)
(format "%s does not support precompilation, disabling LaTeX precompile in this buffer.\n To re-enable, run `(setq-local org-latex-precompile t)' or reopen this buffer."
(plist-get info :latex-compiler)))
(setf (buffer-local-value
'org-latex-precompile (get-buffer (plist-get info :input-buffer)))
nil))
(org-latex--precompile
info preamble
(string-match-p "\\(?:\\\\input{\\|\\\\include{\\)[^/]" preamble))))))
(when (and format-file (not snippet?))
(let ((preamble-parts (split-string preamble (regexp-quote header-split))))
(setq preamble (car preamble-parts)
preamble-nonprecompilable
(concat preamble-nonprecompilable
(cadr preamble-parts)))))
(concat (and format-file
(concat "%& " (file-name-sans-extension format-file) "\n"))
(and (plist-get info :time-stamp-file)
(format-time-string "%% Created %Y-%m-%d %a %H:%M\n"))
preamble
(and format-file
"\n% end precompiled preamble\n\\ifcsname endofdump\\endcsname\\endofdump\\fi\n")
"\n"
preamble-nonprecompilable
(and preamble-nonprecompilable
(not (string-empty-p preamble-nonprecompilable))
"\n")
header-extra))))
(defun org-latex-template (contents info)
"Return complete document string after LaTeX conversion.
@ -2178,6 +2251,118 @@ holding export options."
;; Document end.
"\\end{document}")))
(defvar org-latex-precompile t
"Precompile the preamble during export.
This requires the LaTeX package \"mylatexformat\" to be installed.")
(defconst org-latex--precompile-log "*Org LaTeX Precompilation*")
(defvar org-latex-precompile-command
"%l -output-directory %o -ini -jobname=%b \"&%L\" mylatexformat.ltx %f")
(defvar org-latex-precompile-compiler-map
'(("pdflatex" . "latex")
("xelatex" . "xelatex -no-pdf")
("lualatex" . "dvilualatex")))
(defun org-latex--precompile (info preamble &optional tempfile-p)
"Precompile/dump LaTeX PREAMBLE text.
The path to the format file (.fmt) is returned. If the format
file could not be found in the persist cache, it is generated
according to PROCESSING-INFO and stored. INFO is a plist used as
a communication channel.
If TEMPFILE-P is non-nil, then it is assumed the preamble does
not contain any relative references to other files.
This is intended to speed up Org's LaTeX preview generation
process."
(let ((preamble-hash
(thread-first
preamble
(concat
(plist-get info :latex-compiler)
(if tempfile-p "-temp"
default-directory))
(sha1)))
(default-directory
(if tempfile-p temporary-file-directory default-directory)))
(or (cadr
(org-persist-read "LaTeX format file cache"
(list :key preamble-hash)
nil nil :read-related t))
(when-let ((dump-file
(org-latex--precompile-preamble
info preamble (expand-file-name preamble-hash temporary-file-directory))))
(cadr
(org-persist-register `(,"LaTeX format file cache"
(file ,dump-file))
(list :key preamble-hash)
:write-immediately t))))))
(defun org-latex--remove-cached-preamble (latex-compiler preamble &optional tempfile-p)
"Remove the cached preamble file for PREAMBLE compiled with LATEX-COMPILER.
TEMPFILE-P should be set to mirror the caching `org-latex--precompile' call
which is intended to be evicted from the cache."
(let ((preamble-hash
(thread-first
preamble
(concat
latex-compiler
(if tempfile-p "-temp"
default-directory))
(sha1))))
(org-persist-unregister "LaTeX format file cache"
(list :key preamble-hash)
:remove-related t)))
(defun org-latex--precompile-preamble (info preamble basepath)
"Precompile PREAMBLE with \"mylatexformat\".
The PREAMBLE string is placed in BASEPATH.tex and compiled
according to PROCESSING-INFO. If compilation and dumping
succeeded, BASEPATH.fmt will be returned.
Should any errors occur during compilation, nil will be returned,
and appropriate warnings may be emitted."
(let ((dump-file (concat basepath ".fmt"))
(preamble-file (concat basepath ".tex"))
(precompile-buffer
(with-current-buffer
(get-buffer-create org-latex--precompile-log)
(erase-buffer)
(current-buffer))))
(with-temp-file preamble-file
(insert preamble "\n\\endofdump\n"))
(message "Precompiling Org LaTeX preamble...")
(condition-case nil
(org-compile-file
preamble-file (list org-latex-precompile-command)
"fmt" nil precompile-buffer
(or (plist-get info :precompile-format-spec)
`((?l . ,(plist-get info :latex-compiler))
(?L . ,(plist-get info :latex-compiler)))))
(:success
(kill-buffer precompile-buffer)
(delete-file preamble-file)
dump-file)
(error
(unless (= 0 (call-process "kpsewhich" nil nil nil "mylatexformat.ltx"))
(display-warning
'(org latex-preview preamble-precompilation)
"The LaTeX package \"mylatexformat\" is required for precompilation, but could not be found")
:warning)
(unless (= 0 (call-process "kpsewhich" nil nil nil "preview.sty"))
(display-warning
'(org latex-preview preamble-precompilation)
"The LaTeX package \"preview\" is required for precompilation, but could not be found")
:warning)
(display-warning
'(org latex-preview preamble-precompilation)
(format "Failed to precompile preamble (%s), see the \"%s\" buffer."
preamble-file precompile-buffer)
:warning)
nil))))
;;; Transcode Functions
@ -2562,8 +2747,11 @@ INFO, CODE, and LANG are provided by `org-latex-inline-src-block'."
(defun org-latex-inline-src-block--engraved (info code lang)
"Transcode an inline src block's content from Org to LaTeX, using engrave-faces.
INFO, CODE, and LANG are provided by `org-latex-inline-src-block'."
(org-latex-src--engrave-code
code lang nil (plist-get info :latex-engraved-options) t))
(let ((engraved-theme (plist-get info :latex-engraved-theme)))
(org-latex-src--engrave-code
code lang
(and engraved-theme (intern engraved-theme)) nil
(plist-get info :latex-engraved-options) t)))
(defun org-latex-inline-src-block--listings (info code lang)
"Transcode an inline src block's content from Org to LaTeX, using lstlistings.
@ -3608,7 +3796,7 @@ and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'."
(when (eq mathescape 'yes)
(or engrave-faces-latex-mathescape t)))))
(defun org-latex-src--engrave-code (content lang &optional theme options inline)
(defun org-latex-src--engrave-code (content lang &optional theme explicit-theme-p options inline)
"Engrave CONTENT to LaTeX in a LANG-mode buffer, and give the result.
When the THEME symbol is non-nil, that theme will be used.
@ -3649,12 +3837,12 @@ to the Verbatim environment or Verb command."
(concat "\\begin{Code}\n\\begin{Verbatim}" engraved-options "\n"
engraved-code "\n\\end{Verbatim}\n\\end{Code}"))))
(kill-buffer engraved-buffer)
(if theme
(concat "{\\engravedtheme"
(if (and theme explicit-theme-p)
(concat "\\begingroup\\engravedtheme"
(replace-regexp-in-string "[^A-Za-z]" ""
(symbol-name theme))
engraved-wrapped
"}")
"\\endgroup")
engraved-wrapped))
(user-error "Cannot engrave code as `engrave-faces-latex' is unavailable.")))
@ -3688,7 +3876,9 @@ and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'."
`(("linenos")
("firstnumber" ,(number-to-string (1+ num-start)))))
(and local-options `((,local-options))))))
(engraved-theme (plist-get attributes :engraved-theme))
(engraved-doc-theme (plist-get info :latex-engraved-theme))
(engraved-theme (or (plist-get attributes :engraved-theme)
engraved-doc-theme))
(content
(let* ((code-info (org-export-unravel-code src-block))
(max-width
@ -3714,7 +3904,8 @@ and FLOAT are extracted from SRC-BLOCK and INFO in `org-latex-src-block'."
(org-latex-src--engrave-mathescape-p info options)))
(org-latex-src--engrave-code
content lang
(when engraved-theme (intern engraved-theme))
(and engraved-theme (intern engraved-theme))
(not (eq engraved-theme engraved-doc-theme))
options))))
(concat (car float-env) body (cdr float-env))))

155
lisp/ox-mathml.el Normal file
View File

@ -0,0 +1,155 @@
;;; ox-mathml.el --- Support for MathML exports -*- lexical-binding: t; -*-
;;
;; Copyright (C) 2023 TEC
;;
;; Author: TEC <contact@tecosaur.net>
;; Maintainer: TEC <contact@tecosaur.net>
;; Created: February 27, 2023
;; Modified: February 27, 2023
;; Version: 0.0.1
;; Keywords: abbrev bib c calendar comm convenience data docs emulations extensions faces files frames games hardware help hypermedia i18n internal languages lisp local maint mail matching mouse multimedia news outlines processes terminals tex tools unix vc wp
;; Homepage: https://github.com/tecosaur/ox-mathml
;; Package-Requires: ((emacs "24.3"))
;;
;; This file is not part of GNU Emacs.
;;
;;; Commentary:
;;
;; Support for MathML exports
;;
;;; Code:
(defgroup org-mathml nil
"Options for generation of MathML representations of LaTeX math."
:tag "Org MathML export"
:group 'org-export)
(defcustom org-mathml-converter-jar-file nil
"Value of\"%j\" in `org-mathml-convert-command'.
Use this to specify additional executable file say a jar file.
When using MathToWeb as the converter, specify the full-path to
your mathtoweb.jar file."
:group 'org-mathml
:version "24.1"
:type '(choice
(const :tag "None" nil)
(file :tag "JAR file" :must-match t)))
(defcustom org-mathml-convert-command nil
"Command to convert LaTeX fragments to MathML.
Replace format-specifiers in the command as noted below and use
`shell-command' to convert LaTeX to MathML.
%j: Executable file in fully expanded form as specified by
`org-latex-to-mathml-jar-file'.
%I: Input LaTeX file in fully expanded form.
%i: The latex fragment to be converted.
%o: Output MathML file.
This command is used by `org-mathml-convert-latex'.
When using MathToWeb as the converter, set this option to
\"java -jar %j -unicode -force -df %o %I\".
When using LaTeXML set this option to
\"latexmlmath \"%i\" --preload=amsmath.sty --preload=amssymb.sty --presentationmathml=%o\"."
:group 'org-mathml
:version "24.1"
:type '(choice
(const :tag "None" nil)
(string :tag "\nShell command")))
(defun org-mathml-converter-available-p ()
"Return t if `org-mathml-convert-command' is usable."
(save-match-data
(when (and (boundp 'org-mathml-convert-command)
org-mathml-convert-command)
(let ((executable (car (split-string
org-mathml-convert-command))))
(when (executable-find executable)
(if (string-match
"%j" org-mathml-convert-command)
(file-readable-p org-mathml-converter-jar-file)
t))))))
(defun org-mathml-convert-latex (latex-frag &optional mathml-file)
"Convert LATEX-FRAG to MathML and store it in MATHML-FILE.
Use `org-latex-to-mathml-convert-command'. If the conversion is
successful, return the portion between \"<math...> </math>\"
elements otherwise return nil. When MATHML-FILE is specified,
write the results in to that file. When invoked as an
interactive command, prompt for LATEX-FRAG, with initial value
set to the current active region and echo the results for user
inspection."
(interactive (list (let ((frag (when (org-region-active-p)
(buffer-substring-no-properties
(region-beginning) (region-end)))))
(read-string "LaTeX Fragment: " frag nil frag))))
(unless latex-frag (user-error "Invalid LaTeX fragment"))
(let* ((tmp-in-file
(let ((file (file-relative-name
(make-temp-name (expand-file-name "ltxmathml-in")))))
(write-region latex-frag nil file)
file))
(tmp-out-file (file-relative-name
(make-temp-name (expand-file-name "ltxmathml-out"))))
(cmd (format-spec
org-mathml-convert-command
`((?j . ,(and org-mathml-converter-jar-file
(shell-quote-argument
(expand-file-name
org-mathml-converter-jar-file))))
(?I . ,(shell-quote-argument tmp-in-file))
(?i . ,latex-frag)
(?o . ,(shell-quote-argument tmp-out-file)))))
mathml shell-command-output)
(when (called-interactively-p 'any)
(unless (org-mathml-converter-available-p)
(user-error "LaTeX to MathML converter not configured")))
(message "Running %s" cmd)
(setq shell-command-output (shell-command-to-string cmd))
(setq mathml
(when (file-readable-p tmp-out-file)
(with-current-buffer (find-file-noselect tmp-out-file t)
(goto-char (point-min))
(when (re-search-forward
(format "<math[^>]*?%s[^>]*?>\\(.\\|\n\\)*</math>"
(regexp-quote
"xmlns=\"http://www.w3.org/1998/Math/MathML\""))
nil t)
(prog1 (match-string 0) (kill-buffer))))))
(cond
(mathml
(setq mathml
(concat "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" mathml))
(when mathml-file
(write-region mathml nil mathml-file))
(when (called-interactively-p 'any)
(message mathml)))
((warn "LaTeX to MathML conversion failed")
(message shell-command-output)))
(delete-file tmp-in-file)
(when (file-exists-p tmp-out-file)
(delete-file tmp-out-file))
mathml))
(defun org-mathml-convert-latex-cached (latex-frag)
"Use `org-mathml-convert-latex' but check local cache first."
(let ((latex-hash-path
(expand-file-name
(concat
"org-mathml-formula-"
(sha1
(prin1-to-string
(list latex-frag
org-mathml-convert-command)))
".mathml")
temporary-file-directory))
print-length print-level)
(unless (file-exists-p latex-hash-path)
(org-mathml-convert-latex latex-frag latex-hash-path))
(and (file-exists-p latex-hash-path)
latex-hash-path)))
(provide 'ox-mathml)
;;; ox-mathml.el ends here

View File

@ -34,6 +34,7 @@
(require 'org-macs)
(require 'ox)
(require 'table nil 'noerror)
(require 'ox-mathml)
(declare-function org-at-heading-p "org" (&optional _))
(declare-function org-back-to-heading "org" (&optional invisible-ok))
@ -3711,113 +3712,147 @@ contextual information."
(defun org-odt--translate-latex-fragments (tree _backend info)
(let ((processing-type (plist-get info :with-latex))
(count 0)
(count 0)
(warning nil))
;; Normalize processing-type to one of dvipng, mathml or verbatim.
;; If the desired converter is not available, force verbatim
;; processing.
(cl-case processing-type
((t mathml)
(if (and (fboundp 'org-format-latex-mathml-available-p)
(org-format-latex-mathml-available-p))
(setq processing-type 'mathml)
(setq warning "`org-odt-with-latex': LaTeX to MathML converter not available. Falling back to verbatim.")
(setq processing-type 'verbatim)))
((dvipng imagemagick)
(unless (and (org-check-external-command "latex" "" t)
(org-check-external-command
(if (eq processing-type 'dvipng) "dvipng" "convert") "" t))
(setq warning "`org-odt-with-latex': LaTeX to PNG converter not available. Falling back to verbatim.")
(setq processing-type 'verbatim)))
(otherwise
(setq warning "`org-odt-with-latex': Unknown LaTeX option. Forcing verbatim.")
(setq processing-type 'verbatim)))
;; Display warning if the selected PROCESSING-TYPE is not
;; available, but there are fragments to be converted.
(when warning
(org-element-map tree '(latex-fragment latex-environment)
(lambda (_) (warn warning))
info 'first-match nil t))
;; Store normalized value for later use.
(when (plist-get info :with-latex)
(plist-put info :with-latex processing-type))
(message "Formatting LaTeX using %s" processing-type)
;; Convert `latex-fragment's and `latex-environment's.
(when (memq processing-type '(mathml dvipng imagemagick))
(org-element-map tree '(latex-fragment latex-environment)
(lambda (latex-*)
(cl-incf count)
(let* ((latex-frag (org-element-property :value latex-*))
(input-file (plist-get info :input-file))
(cache-dir (file-name-directory input-file))
(cache-subdir (concat
(cl-case processing-type
((dvipng imagemagick)
org-preview-latex-image-directory)
(mathml "ltxmathml/"))
(file-name-sans-extension
(file-name-nondirectory input-file))))
(display-msg
(cl-case processing-type
((dvipng imagemagick)
(format "Creating LaTeX Image %d..." count))
(mathml (format "Creating MathML snippet %d..." count))))
;; Get an Org-style link to PNG image or the MathML
;; file.
(link
(with-temp-buffer
(insert latex-frag)
(delay-mode-hooks (let ((org-inhibit-startup t)) (org-mode)))
;; When converting to a PNG image, make sure to
;; copy all LaTeX header specifications from the
;; Org source.
(unless (eq processing-type 'mathml)
(let ((h (plist-get info :latex-header)))
(when h
(insert "\n"
(replace-regexp-in-string
"^" "#+LATEX_HEADER: " h)))))
(org-latex-preview-replace-fragments
cache-subdir processing-type cache-dir display-msg)
(goto-char (point-min))
(skip-chars-forward " \t\n")
(org-element-link-parser))))
(if (not (org-element-type-p link 'link))
(message "LaTeX Conversion failed.")
;; Conversion succeeded. Parse above Org-style link to
;; a `link' object.
(let ((replacement
(cl-case (org-element-type latex-*)
;;LaTeX environment. Mimic a "standalone image
;; or formula" by enclosing the `link' in
;; a `paragraph'. Copy over original
;; attributes, captions to the enclosing
;; paragraph.
(latex-environment
(org-element-adopt
(list 'paragraph
(list :style "OrgFormula"
:name
(org-element-property :name latex-*)
:caption
(org-element-property :caption latex-*)))
link))
;; LaTeX fragment. No special action.
(latex-fragment link))))
;; Note down the object that link replaces.
(org-element-put-property replacement :replaces
(list (org-element-type latex-*)
(list :value latex-frag)))
;; Restore blank after initial element or object.
(org-element-put-property
replacement :post-blank
(org-element-property :post-blank latex-*))
;; Replace now.
(org-element-set latex-* replacement)))))
info nil nil t)))
;; MathML will be handled seperately.
(if (and (memq processing-type '(t mathml))
(fboundp 'org-format-latex-mathml-available-p)
(org-format-latex-mathml-available-p)
(plist-put info :with-latex 'mathml))
(org-element-map tree '(latex-fragment latex-environment)
(lambda (latex)
(cl-incf count)
(if-let ((latex-frag (org-element-property :value latex))
(path (org-mathml-convert-latex-cached latex-frag))
(link (list 'link
(list :type "file"
:path path
:format 'bracket
:raw-link (format "file:%s" path))))
(replacement
(if (eq (org-element-type latex) 'latex-environment)
;;LaTeX environment. Mimic a "standalone image
;; or formula" by enclosing the `link' in
;; a `paragraph'. Copy over original
;; attributes, captions to the enclosing
;; paragraph.
(org-element-adopt-elements
(list 'paragraph
(list :style "OrgFormula"
:name
(org-element-property :name latex)
:caption
(org-element-property :caption latex)))
link)
link)))
(progn
;; Note down the object that link replaces.
(org-element-put-property replacement :replaces
(list (org-element-type latex)
(list :value latex-frag)))
;; Restore blank after initial element or object.
(org-element-put-property
replacement :post-blank
(org-element-property :post-blank latex))
;; Replace now.
(org-element-set-element latex replacement))
(setq warning "Conversion of LaTeX to MathML failed. Falling back to verbatim.")))
info nil nil)
;; Normalize processing-type to one of dvipng or verbatim.
;; If the desired converter is not available, force verbatim
;; processing.
(cl-case processing-type
((t mathml)
(setq warning "LaTeX to MathML converter not available. Falling back to verbatim."
processing-type 'verbatim))
((dvipng imagemagick)
(unless (and (org-check-external-command "latex" "" t)
(org-check-external-command
(if (eq processing-type 'dvipng) "dvipng" "convert") "" t))
(setq warning "LaTeX to PNG converter not available. Falling back to verbatim."
processing-type 'verbatim)))
(otherwise
(setq warning "Unknown LaTeX option. Forcing verbatim."
processing-type 'verbatim)))
;; Display warning if the selected PROCESSING-TYPE is not
;; available, but there are fragments to be converted.
(when warning
(org-element-map tree '(latex-fragment latex-environment)
(lambda (_) (warn warning))
info 'first-match nil t))
;; Store normalized value for later use.
(when (plist-get info :with-latex)
(plist-put info :with-latex processing-type))
(message "Formatting LaTeX using %s" processing-type)
;; Convert `latex-fragment's and `latex-environment's.
(when (memq processing-type '(dvipng imagemagick))
(org-element-map tree '(latex-fragment latex-environment)
(lambda (latex-*)
(cl-incf count)
(let* ((latex-frag (org-element-property :value latex-*))
(input-file (plist-get info :input-file))
(cache-dir (file-name-directory input-file))
(cache-subdir (concat
(cl-case processing-type
((dvipng imagemagick)
org-preview-latex-image-directory))
(file-name-sans-extension
(file-name-nondirectory input-file))))
(display-msg
(cl-case processing-type
((dvipng imagemagick)
(format "Creating LaTeX Image %d..." count))))
;; Get an Org-style link to PNG image.
(link
(with-temp-buffer
(insert latex-frag)
(delay-mode-hooks (let ((org-inhibit-startup t)) (org-mode)))
;; When converting to a PNG image, make sure to
;; copy all LaTeX header specifications from the
;; Org source.
(let ((h (plist-get info :latex-header)))
(when h
(insert "\n"
(replace-regexp-in-string
"^" "#+LATEX_HEADER: " h))))
(org-latex-preview-replace-fragments
cache-subdir processing-type cache-dir display-msg)
(goto-char (point-min))
(skip-chars-forward " \t\n")
(org-element-link-parser))))
(if (not (eq 'link (org-element-type link)))
(message "LaTeX Conversion failed.")
;; Conversion succeeded. Parse above Org-style link to
;; a `link' object.
(let ((replacement
(cl-case (org-element-type latex-*)
;;LaTeX environment. Mimic a "standalone image
;; or formula" by enclosing the `link' in
;; a `paragraph'. Copy over original
;; attributes, captions to the enclosing
;; paragraph.
(latex-environment
(org-element-adopt-elements
(list 'paragraph
(list :style "OrgFormula"
:name
(org-element-property :name latex-*)
:caption
(org-element-property :caption latex-*)))
link))
;; LaTeX fragment. No special action.
(latex-fragment link))))
;; Note down the object that link replaces.
(org-element-put-property replacement :replaces
(list (org-element-type latex-*)
(list :value latex-frag)))
;; Restore blank after initial element or object.
(org-element-put-property
replacement :post-blank
(org-element-property :post-blank latex-*))
;; Replace now.
(org-element-set-element latex-* replacement)))))
info nil nil t))))
tree)
@ -4144,7 +4179,7 @@ MathML source to kill ring depending on the value of
(save-buffer-coding-system 'utf-8))
(set-buffer buffer)
(set-buffer-file-coding-system coding-system-for-write)
(let ((mathml (org-create-math-formula latex-frag)))
(let ((mathml (org-mathml-convert-latex-cached latex-frag)))
(unless mathml (error "No Math formula created"))
(insert mathml)
;; Add MathML to kill ring, if needed.

View File

@ -0,0 +1,30 @@
#+latex_header: \usepackage{amsmath}
#+latex_header: \usepackage{amssymb}
* Inline fragments and LaTeX environments
:PROPERTIES:
:ID: 0b3807b3-69af-40cb-a27a-b380d54879cc
:END:
The LQR problem for a time-periodic system of the form
\begin{align}
\dot{x} = A(t) x + B(t) u, \quad t \in [0, \infty), \quad x(0) = x_i \label{eq:time-varying-system}\\
A(t+T) = A(t),\ B(t + T) = B(t) \nonumber
\end{align}
is as follows. With a quadratic form defined on \( (x,u) \) pairs
\begin{align}
\label{eq:quadratic-form}
\mathbf{q}(x, u) := \lim_{t_f \to \infty} \int_{0}^{t_f} \begin{bmatrix} x \\ u \end{bmatrix}^{\star} \begin{bmatrix}
Q & 0 \\
0 & r
\end{bmatrix} \begin{bmatrix} x \\ u \end{bmatrix} =: \lim_{t_f \to \infty} \int_{0}^{t_f} q(x,u) dt
\end{align}
with \( q \ge 0 \) and \( r \ge 0 \), find the infimum of the quadratic form \( \mathbf{q} \) subject to the dynamics:
\[
\inf_{x,u} \mathbf{q}(x,u).
\]
\begin{align}
\label{eq:lqr-inf-via-duality}
\inf_{x, u} \mathbf{q}(x, u) = x_i^{\star} \bar{\lambda}(0) x_i,
\end{align}
where \( \bar{\lambda} \) is the maximal solution of the differential linear matrix inequality over \( [0, t] \).

View File

@ -0,0 +1,344 @@
;;; test-org-latex-preview.el --- tests for org-latex-preview.el -*- lexical-binding: t; -*-
;; Copyright (c) 2023 Karthik Chikmagalur
;; Authors: Karthik Chikmagalur
;; This file is not part of GNU Emacs.
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
;;; Code:
(unless (featurep 'org-latex-preview)
(signal 'missing-test-dependency "Support for LaTeX previews"))
(require 'org-latex-preview)
(require 'cl-lib)
(ert-deftest test-org-latex-preview/assert ()
(should t))
;; Test for executables required for preview generation
(org-test-for-executable "latex")
(org-test-for-executable "dvisvgm")
(org-test-for-executable "dvipng")
;; Should we test imagemagick?
;; (org-test-for-executable "convert")
;; fragment pre-processing tests
;;; Collect fragments
(ert-deftest test-org-latex-preview/collect-fragments-inline ()
"Test LaTeX fragment collection"
(let ((elements
'((latex-fragment
(:value "\\( q \\ge 0 \\)" :begin 770 :end 784 :post-blank 1 :parent
(paragraph
(:begin 765 :end 918 :contents-begin 765 :contents-end 918 :post-blank 0 :post-affiliated 765 :mode nil :granularity element :parent
(section
(:begin 118 :end 1154 :contents-begin 118 :contents-end 1154 :robust-begin 118 :robust-end 1152 :post-blank 0 :post-affiliated 118 :mode section :granularity element :parent
(headline
(:raw-value "Inline fragments and LaTeX environments" :begin 76 :end 1154 :pre-blank 0 :contents-begin 118 :contents-end 1154 :robust-begin 184 :robust-end 1152 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 76 :ID "0b3807b3-69af-40cb-a27a-b380d54879cc" :title "Inline fragments and LaTeX environments"))))))))
(latex-fragment
(:value "\\( r \\ge 0 \\)" :begin 788 :end 801 :post-blank 0 :parent
(paragraph
(:begin 765 :end 918 :contents-begin 765 :contents-end 918 :post-blank 0 :post-affiliated 765 :mode nil :granularity element :parent
(section
(:begin 118 :end 1154 :contents-begin 118 :contents-end 1154 :robust-begin 118 :robust-end 1152 :post-blank 0 :post-affiliated 118 :mode section :granularity element :parent
(headline
(:raw-value "Inline fragments and LaTeX environments" :begin 76 :end 1154 :pre-blank 0 :contents-begin 118 :contents-end 1154 :robust-begin 184 :robust-end 1152 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 76 :ID "0b3807b3-69af-40cb-a27a-b380d54879cc" :title "Inline fragments and LaTeX environments")))))))))))
(org-test-at-id
"0b3807b3-69af-40cb-a27a-b380d54879cc"
(should
(equal (org-latex-preview-collect-fragments 765 807) elements))
(should
(equal (org-latex-preview--construct-entries elements)
'(((770 783 "\\( q \\ge 0 \\)")
(788 801 "\\( r \\ge 0 \\)"))
nil)))
(should
(equal (org-latex-preview--construct-entries elements)
(org-latex-preview--construct-entries elements 'with-numbering))))))
(ert-deftest test-org-latex-preview/collect-fragments-environment ()
"Test LaTeX fragment collection"
(let ((elements
'((latex-environment
(:begin 241 :end 412 :value "\\begin{align}\n\\dot{x} = A(t) x + B(t) u, \\quad t \\in [0, \\infty), \\quad x(0) = x_i \\label{eq:time-varying-system}\\\\\nA(t+T) = A(t),\\ B(t + T) = B(t) \\nonumber\n\\end{align}\n" :post-blank 0 :post-affiliated 241 :mode nil :granularity element :parent
(section
(:begin 118 :end 1154 :contents-begin 118 :contents-end 1154 :robust-begin 118 :robust-end 1152 :post-blank 0 :post-affiliated 118 :mode section :granularity element :parent
(headline
(:raw-value "Inline fragments and LaTeX environments" :begin 76 :end 1154 :pre-blank 0 :contents-begin 118 :contents-end 1154 :robust-begin 184 :robust-end 1152 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 76 :ID "0b3807b3-69af-40cb-a27a-b380d54879cc" :title "Inline fragments and LaTeX environments")))))))))
(org-test-at-id
"0b3807b3-69af-40cb-a27a-b380d54879cc"
(should
(equal (org-latex-preview-collect-fragments 186 426) elements))
(should
(equal (org-latex-preview--construct-entries elements)
'(((241 411 "\\begin{align}\n\\dot{x} = A(t) x + B(t) u, \\quad t \\in [0, \\infty), \\quad x(0) = x_i \\label{eq:time-varying-system}\\\\\nA(t+T) = A(t),\\ B(t + T) = B(t) \\nonumber\n\\end{align}\n"))
nil)))
(should
(equal (org-latex-preview--construct-entries elements 'with-numbering)
'(((241 411 "\\begin{align}\n\\dot{x} = A(t) x + B(t) u, \\quad t \\in [0, \\infty), \\quad x(0) = x_i \\label{eq:time-varying-system}\\\\\nA(t+T) = A(t),\\ B(t + T) = B(t) \\nonumber\n\\end{align}\n"))
(1)))))))
(ert-deftest test-org-latex-preview/collect-fragments-all ()
"Test LaTeX fragment collection"
(let ((elements
'((latex-environment
(:begin 241 :end 412 :value "\\begin{align}\n\\dot{x} = A(t) x + B(t) u, \\quad t \\in [0, \\infty), \\quad x(0) = x_i \\label{eq:time-varying-system}\\\\\nA(t+T) = A(t),\\ B(t + T) = B(t) \\nonumber\n\\end{align}\n" :post-blank 0 :post-affiliated 241 :mode nil :granularity element :parent
(section
(:begin 118 :end 1154 :contents-begin 118 :contents-end 1154 :robust-begin 118 :robust-end 1152 :post-blank 0 :post-affiliated 118 :mode section :granularity element :parent
(headline
(:raw-value "Inline fragments and LaTeX environments" :begin 76 :end 1154 :pre-blank 0 :contents-begin 118 :contents-end 1154 :robust-begin 184 :robust-end 1152 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 76 :ID "0b3807b3-69af-40cb-a27a-b380d54879cc" :title "Inline fragments and LaTeX environments"))))))
(latex-fragment
(:value "\\( (x,u) \\)" :begin 460 :end 472 :post-blank 1 :parent
(paragraph
(:begin 412 :end 478 :contents-begin 412 :contents-end 478 :post-blank 0 :post-affiliated 412 :mode nil :granularity element :parent
(section
(:begin 118 :end 1154 :contents-begin 118 :contents-end 1154 :robust-begin 118 :robust-end 1152 :post-blank 0 :post-affiliated 118 :mode section :granularity element :parent
(headline
(:raw-value "Inline fragments and LaTeX environments" :begin 76 :end 1154 :pre-blank 0 :contents-begin 118 :contents-end 1154 :robust-begin 184 :robust-end 1152 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 76 :ID "0b3807b3-69af-40cb-a27a-b380d54879cc" :title "Inline fragments and LaTeX environments"))))))))
(latex-environment
(:begin 478 :end 765 :value "\\begin{align}\n\\label{eq:quadratic-form}\n\\mathbf{q}(x, u) := \\lim_{t_f \\to \\infty} \\int_{0}^{t_f} \\begin{bmatrix} x \\\\ u \\end{bmatrix}^{\\star} \\begin{bmatrix}\nQ & 0 \\\\\n0 & r\n \\end{bmatrix} \\begin{bmatrix} x \\\\ u \\end{bmatrix} =: \\lim_{t_f \\to \\infty} \\int_{0}^{t_f} q(x,u) dt\n\\end{align}\n" :post-blank 0 :post-affiliated 478 :mode nil :granularity element :parent
(section
(:begin 118 :end 1154 :contents-begin 118 :contents-end 1154 :robust-begin 118 :robust-end 1152 :post-blank 0 :post-affiliated 118 :mode section :granularity element :parent
(headline
(:raw-value "Inline fragments and LaTeX environments" :begin 76 :end 1154 :pre-blank 0 :contents-begin 118 :contents-end 1154 :robust-begin 184 :robust-end 1152 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 76 :ID "0b3807b3-69af-40cb-a27a-b380d54879cc" :title "Inline fragments and LaTeX environments"))))))
(latex-fragment
(:value "\\( q \\ge 0 \\)" :begin 770 :end 784 :post-blank 1 :parent
(paragraph
(:begin 765 :end 918 :contents-begin 765 :contents-end 918 :post-blank 0 :post-affiliated 765 :mode nil :granularity element :parent
(section
(:begin 118 :end 1154 :contents-begin 118 :contents-end 1154 :robust-begin 118 :robust-end 1152 :post-blank 0 :post-affiliated 118 :mode section :granularity element :parent
(headline
(:raw-value "Inline fragments and LaTeX environments" :begin 76 :end 1154 :pre-blank 0 :contents-begin 118 :contents-end 1154 :robust-begin 184 :robust-end 1152 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 76 :ID "0b3807b3-69af-40cb-a27a-b380d54879cc" :title "Inline fragments and LaTeX environments"))))))))
(latex-fragment
(:value "\\( r \\ge 0 \\)" :begin 788 :end 801 :post-blank 0 :parent
(paragraph
(:begin 765 :end 918 :contents-begin 765 :contents-end 918 :post-blank 0 :post-affiliated 765 :mode nil :granularity element :parent
(section
(:begin 118 :end 1154 :contents-begin 118 :contents-end 1154 :robust-begin 118 :robust-end 1152 :post-blank 0 :post-affiliated 118 :mode section :granularity element :parent
(headline
(:raw-value "Inline fragments and LaTeX environments" :begin 76 :end 1154 :pre-blank 0 :contents-begin 118 :contents-end 1154 :robust-begin 184 :robust-end 1152 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 76 :ID "0b3807b3-69af-40cb-a27a-b380d54879cc" :title "Inline fragments and LaTeX environments"))))))))
(latex-fragment
(:value "\\( \\mathbf{q} \\)" :begin 842 :end 859 :post-blank 1 :parent
(paragraph
(:begin 765 :end 918 :contents-begin 765 :contents-end 918 :post-blank 0 :post-affiliated 765 :mode nil :granularity element :parent
(section
(:begin 118 :end 1154 :contents-begin 118 :contents-end 1154 :robust-begin 118 :robust-end 1152 :post-blank 0 :post-affiliated 118 :mode section :granularity element :parent
(headline
(:raw-value "Inline fragments and LaTeX environments" :begin 76 :end 1154 :pre-blank 0 :contents-begin 118 :contents-end 1154 :robust-begin 184 :robust-end 1152 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 76 :ID "0b3807b3-69af-40cb-a27a-b380d54879cc" :title "Inline fragments and LaTeX environments"))))))))
(latex-fragment
(:value "\\[\n\\inf_{x,u} \\mathbf{q}(x,u).\n\\]" :begin 884 :end 917 :post-blank 0 :parent
(paragraph
(:begin 765 :end 918 :contents-begin 765 :contents-end 918 :post-blank 0 :post-affiliated 765 :mode nil :granularity element :parent
(section
(:begin 118 :end 1154 :contents-begin 118 :contents-end 1154 :robust-begin 118 :robust-end 1152 :post-blank 0 :post-affiliated 118 :mode section :granularity element :parent
(headline
(:raw-value "Inline fragments and LaTeX environments" :begin 76 :end 1154 :pre-blank 0 :contents-begin 118 :contents-end 1154 :robust-begin 184 :robust-end 1152 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 76 :ID "0b3807b3-69af-40cb-a27a-b380d54879cc" :title "Inline fragments and LaTeX environments"))))))))
(latex-environment
(:begin 918 :end 1040 :value "\\begin{align}\n\\label{eq:lqr-inf-via-duality}\n\\inf_{x, u} \\mathbf{q}(x, u) = x_i^{\\star} \\bar{\\lambda}(0) x_i,\n\\end{align}\n" :post-blank 0 :post-affiliated 918 :mode nil :granularity element :parent
(section
(:begin 118 :end 1154 :contents-begin 118 :contents-end 1154 :robust-begin 118 :robust-end 1152 :post-blank 0 :post-affiliated 118 :mode section :granularity element :parent
(headline
(:raw-value "Inline fragments and LaTeX environments" :begin 76 :end 1154 :pre-blank 0 :contents-begin 118 :contents-end 1154 :robust-begin 184 :robust-end 1152 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 76 :ID "0b3807b3-69af-40cb-a27a-b380d54879cc" :title "Inline fragments and LaTeX environments"))))))
(latex-fragment
(:value "\\( \\bar{\\lambda} \\)" :begin 1046 :end 1066 :post-blank 1 :parent
(paragraph
(:begin 1040 :end 1154 :contents-begin 1040 :contents-end 1154 :post-blank 0 :post-affiliated 1040 :mode nil :granularity element :parent
(section
(:begin 118 :end 1154 :contents-begin 118 :contents-end 1154 :robust-begin 118 :robust-end 1152 :post-blank 0 :post-affiliated 118 :mode section :granularity element :parent
(headline
(:raw-value "Inline fragments and LaTeX environments" :begin 76 :end 1154 :pre-blank 0 :contents-begin 118 :contents-end 1154 :robust-begin 184 :robust-end 1152 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 76 :ID "0b3807b3-69af-40cb-a27a-b380d54879cc" :title "Inline fragments and LaTeX environments"))))))))
(latex-fragment
(:value "\\( [0, t] \\)" :begin 1140 :end 1152 :post-blank 0 :parent
(paragraph
(:begin 1040 :end 1154 :contents-begin 1040 :contents-end 1154 :post-blank 0 :post-affiliated 1040 :mode nil :granularity element :parent
(section
(:begin 118 :end 1154 :contents-begin 118 :contents-end 1154 :robust-begin 118 :robust-end 1152 :post-blank 0 :post-affiliated 118 :mode section :granularity element :parent
(headline
(:raw-value "Inline fragments and LaTeX environments" :begin 76 :end 1154 :pre-blank 0 :contents-begin 118 :contents-end 1154 :robust-begin 184 :robust-end 1152 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 76 :ID "0b3807b3-69af-40cb-a27a-b380d54879cc" :title "Inline fragments and LaTeX environments")))))))))))
(org-test-at-id
"0b3807b3-69af-40cb-a27a-b380d54879cc"
(should
(equal (org-latex-preview-collect-fragments) elements))
(should (equal (org-latex-preview--construct-entries elements)
'(((241 411 "\\begin{align}\n\\dot{x} = A(t) x + B(t) u, \\quad t \\in [0, \\infty), \\quad x(0) = x_i \\label{eq:time-varying-system}\\\\\nA(t+T) = A(t),\\ B(t + T) = B(t) \\nonumber\n\\end{align}\n")
(460 471 "\\( (x,u) \\)")
(478 764 "\\begin{align}\n\\label{eq:quadratic-form}\n\\mathbf{q}(x, u) := \\lim_{t_f \\to \\infty} \\int_{0}^{t_f} \\begin{bmatrix} x \\\\ u \\end{bmatrix}^{\\star} \\begin{bmatrix}\nQ & 0 \\\\\n0 & r\n \\end{bmatrix} \\begin{bmatrix} x \\\\ u \\end{bmatrix} =: \\lim_{t_f \\to \\infty} \\int_{0}^{t_f} q(x,u) dt\n\\end{align}\n")
(770 783 "\\( q \\ge 0 \\)")
(788 801 "\\( r \\ge 0 \\)")
(842 858 "\\( \\mathbf{q} \\)")
(884 917 "\\[\n\\inf_{x,u} \\mathbf{q}(x,u).\n\\]")
(918 1039 "\\begin{align}\n\\label{eq:lqr-inf-via-duality}\n\\inf_{x, u} \\mathbf{q}(x, u) = x_i^{\\star} \\bar{\\lambda}(0) x_i,\n\\end{align}\n")
(1046 1065 "\\( \\bar{\\lambda} \\)")
(1140 1152 "\\( [0, t] \\)"))
nil)))
(should (equal (org-latex-preview--construct-entries elements 'with-numbering)
'(((241 411 "\\begin{align}\n\\dot{x} = A(t) x + B(t) u, \\quad t \\in [0, \\infty), \\quad x(0) = x_i \\label{eq:time-varying-system}\\\\\nA(t+T) = A(t),\\ B(t + T) = B(t) \\nonumber\n\\end{align}\n")
(460 471 "\\( (x,u) \\)")
(478 764 "\\begin{align}\n\\label{eq:quadratic-form}\n\\mathbf{q}(x, u) := \\lim_{t_f \\to \\infty} \\int_{0}^{t_f} \\begin{bmatrix} x \\\\ u \\end{bmatrix}^{\\star} \\begin{bmatrix}\nQ & 0 \\\\\n0 & r\n \\end{bmatrix} \\begin{bmatrix} x \\\\ u \\end{bmatrix} =: \\lim_{t_f \\to \\infty} \\int_{0}^{t_f} q(x,u) dt\n\\end{align}\n")
(770 783 "\\( q \\ge 0 \\)")
(788 801 "\\( r \\ge 0 \\)")
(842 858 "\\( \\mathbf{q} \\)")
(884 917 "\\[\n\\inf_{x,u} \\mathbf{q}(x,u).\n\\]")
(918 1039 "\\begin{align}\n\\label{eq:lqr-inf-via-duality}\n\\inf_{x, u} \\mathbf{q}(x, u) = x_i^{\\star} \\bar{\\lambda}(0) x_i,\n\\end{align}\n")
(1046 1065 "\\( \\bar{\\lambda} \\)")
(1140 1152 "\\( [0, t] \\)"))
(1 nil 2 nil nil nil nil 4 nil nil)))))))
;;; Set up overlays
(ert-deftest test-org-latex-preview/ensure-overlay ()
(org-test-at-id "0b3807b3-69af-40cb-a27a-b380d54879cc"
(org-latex-preview-clear-overlays (point-min) (point-max))
(let* ((elements (org-latex-preview-collect-fragments))
(entries (car (org-latex-preview--construct-entries elements)))
(ov) (all-ovs))
(pcase-dolist(`(,beg ,end ,value) entries)
(setq ov (org-latex-preview--ensure-overlay beg end))
(push ov all-ovs)
(should (eq (get-char-property beg 'org-overlay-type) 'org-latex-overlay))
(should (eq (overlay-get ov 'org-overlay-type) 'org-latex-overlay))
(should (eq (overlay-get ov 'evaporate) t))
(should (eq (overlay-get ov 'priority) org-latex-preview--overlay-priority))
(should (equal (overlay-get ov 'modification-hooks)
(list #'org-latex-preview-auto--mark-overlay-modified)))
(should (equal (overlay-get ov 'insert-in-front-hooks)
(list #'org-latex-preview-auto--insert-front-handler)))
(should (equal (overlay-get ov 'insert-behind-hooks)
(list #'org-latex-preview-auto--insert-behind-handler))))
(should (eq (length all-ovs) (length elements))))
(org-latex-preview-clear-overlays (point-min) (point-max))))
;; Precompilation test
;; TODO
;; Process fragments
;;; No precompilation, no caching
(ert-deftest test-org-latex-preview/place-previews-1 ()
(org-test-at-id "0b3807b3-69af-40cb-a27a-b380d54879cc"
(let ((org-latex-preview-process-precompiled nil)
(org-latex-preview-cache 'temp)
(org-latex-preview-process-default 'dvisvgm))
(org-latex-preview-auto-mode -1)
(goto-char 255)
(let ((element (org-element-context)))
(should (eq (org-element-type element) 'latex-environment))
(org-latex-preview-clear-cache (org-element-property :begin element)
(org-element-property :end element))
(apply #'org-async-wait-for
(org-latex-preview--place-from-elements
org-latex-preview-process-default
(list element)))
(let ((ov (cl-some (lambda (o) (and (eq (overlay-get o 'org-overlay-type)
'org-latex-overlay)
o))
(overlays-at (point)))))
(should (overlayp ov))
(let ((display (overlay-get ov 'display))
(face (overlay-get ov 'face))
(hidden-face (overlay-get ov 'hidden-face))
(preview-image (overlay-get ov 'preview-image)))
;; Image properties
(should (consp display))
(should (eq (car display) 'image))
(should (eq (plist-get (cdr display) :type) 'svg))
(should (stringp (plist-get (cdr display) :file)))
(should (string-suffix-p ".svg" (plist-get (cdr display) :file)))
(should (eq preview-image display))
;; Face properties
(should (eq face 'default))
(should (eq hidden-face face))))))))
(ert-deftest test-org-latex-preview/place-previews-all ()
(org-test-at-id "0b3807b3-69af-40cb-a27a-b380d54879cc"
(let ((org-latex-preview-process-precompiled nil)
(org-latex-preview-cache 'temp)
(org-latex-preview-process-default 'dvisvgm))
(org-latex-preview-auto-mode -1)
(org-latex-preview-clear-cache (point-min) (point-max))
(let ((elements (org-latex-preview-collect-fragments)))
(apply #'org-async-wait-for
(org-latex-preview--place-from-elements
org-latex-preview-process-default
elements))
(dolist (element elements)
(let ((ov (cl-some (lambda (o) (and (eq (overlay-get o 'org-overlay-type)
'org-latex-overlay)
o))
(overlays-at (org-element-property :begin element)))))
(should (overlayp ov))
(let ((display (overlay-get ov 'display))
(face (overlay-get ov 'face))
(hidden-face (overlay-get ov 'hidden-face))
(preview-image (overlay-get ov 'preview-image)))
;; Image properties
(should (consp display))
(should (eq (car display) 'image))
(should (eq (plist-get (cdr display) :type) 'svg))
(should (stringp (plist-get (cdr display) :file)))
(should (string-suffix-p ".svg" (plist-get (cdr display) :file)))
(should (eq preview-image display))
;; Face properties
(should (eq face 'default))
(should (eq hidden-face face)))))
(org-latex-preview-clear-cache (point-min) (point-max))))))
;; TODO: Test with precompilation
;; TODO: Test with caching
;; dvisvgm filter+callback test
;; dvipng filter+callback test
;; imagemagick filter+callback test
;; TODO
;; Color extraction
;; TODO
;; Scaling
;; TODO
;; Caching
;; TODO
;;; clear-cache test
;; Numbering
;; TODO
;; org-latex-preview-auto-mode
;; TODO
;; live previews
;; TODO
;; lualatex-specific tests
;; xelatex-specific tests
(provide 'test-org-latex-preview)
;;; test-org-latex-preview.el ends here