forked from mirrors/org-mode
Compare commits
303 Commits
d49d3e18f2
...
8dac1e25f5
Author | SHA1 | Date |
---|---|---|
TEC | 8dac1e25f5 | |
TEC | 32b0a20060 | |
TEC | 8c5456b66e | |
TEC | 6a587f5577 | |
TEC | 12cee84433 | |
TEC | 177ba504a7 | |
TEC | 318460f369 | |
TEC | 2f2a12d50b | |
Karthik Chikmagalur | cd5fbb92eb | |
TEC | 020291fe43 | |
TEC | aaf233d664 | |
TEC | 5c93e3745d | |
TEC | 8c01ec6703 | |
Karthik Chikmagalur | d21a944473 | |
TEC | e9751ede2c | |
TEC | b600b3c814 | |
TEC | c6e437b38e | |
TEC | fd8c3f5593 | |
TEC | 9735905fb3 | |
TEC | 9e783262d4 | |
TEC | e24a13764a | |
TEC | a4c782d686 | |
TEC | d47fdb7da2 | |
TEC | 4ed6bb632d | |
Karthik Chikmagalur | cd57cafea4 | |
Karthik Chikmagalur | b3c5251f02 | |
Karthik Chikmagalur | 0c64cb39ef | |
TEC | 4a7f68b63f | |
TEC | 2a9b650443 | |
TEC | beed6c970f | |
Karthik Chikmagalur | bbf569140e | |
TEC | 8efc1c8f1d | |
TEC | da7605a95e | |
TEC | fe1d9228c4 | |
TEC | 7ef969acb9 | |
TEC | 96e319f5f4 | |
TEC | 3c836f0bf3 | |
TEC | bdc438f4ed | |
TEC | 252133b597 | |
TEC | 9fc512bc6e | |
TEC | 7295bf6b0f | |
TEC | 540690c02a | |
Karthik Chikmagalur | c67992527d | |
Karthik Chikmagalur | cb2906ea13 | |
Karthik Chikmagalur | 7e537b93d0 | |
Karthik Chikmagalur | 73a7f69642 | |
Karthik Chikmagalur | 47f848b154 | |
Karthik Chikmagalur | e5e5c968cb | |
Karthik Chikmagalur | de2e0a8117 | |
Karthik Chikmagalur | 9e0e12320f | |
Karthik Chikmagalur | 453029dfb0 | |
Karthik Chikmagalur | cbfc622810 | |
Karthik Chikmagalur | a56c582473 | |
Karthik Chikmagalur | 45bcff54a7 | |
Karthik Chikmagalur | 4dd6672b6a | |
TEC | 3ae13a43f9 | |
Karthik Chikmagalur | b4f883861f | |
Karthik Chikmagalur | 49d0c446a4 | |
Karthik Chikmagalur | ab38d6c974 | |
Karthik Chikmagalur | 772b0e5dba | |
Karthik Chikmagalur | 52f27790e2 | |
Karthik Chikmagalur | ce02811869 | |
Karthik Chikmagalur | a9f69fc4ef | |
TEC | 9226f38879 | |
TEC | d485fceb7c | |
TEC | 70d6b3c24e | |
TEC | 3afd1d0c9f | |
TEC | f7af98999c | |
TEC | d8dd2c7222 | |
TEC | 8111a28e77 | |
TEC | 65cdc3ad83 | |
TEC | f4b9b891c5 | |
TEC | 16ce57134d | |
TEC | fe2d28ad33 | |
TEC | bd16d37976 | |
Karthik Chikmagalur | 4709ce1003 | |
TEC | cca2b007ed | |
TEC | 386316e5c1 | |
TEC | 8da34d836e | |
TEC | 4d9b64ace0 | |
TEC | a28f487e6c | |
TEC | 127016cff1 | |
TEC | c465870516 | |
TEC | 48aab53799 | |
TEC | f55d9d544f | |
TEC | fd4a5a2f1d | |
Karthik Chikmagalur | aab33d6872 | |
TEC | 768fbc9afc | |
TEC | 2aa6c8b81e | |
TEC | fcb98fa2bb | |
TEC | ea6e996fa0 | |
TEC | de22f5e4aa | |
Karthik Chikmagalur | 5802eaa2ac | |
TEC | 0ee6e1f44d | |
TEC | 329b6e9eba | |
Karthik Chikmagalur | fcb1b6137f | |
TEC | 70d07ed4e5 | |
Karthik Chikmagalur | 2a84a0d712 | |
TEC | d533b6f0ff | |
TEC | a4648bbeb4 | |
Karthik Chikmagalur | cf4e72ac1a | |
Karthik Chikmagalur | 18ab7bc22c | |
Karthik Chikmagalur | 613b873891 | |
TEC | 3b9d33bbf2 | |
TEC | b48745fa11 | |
TEC | 0b674082e7 | |
TEC | f3c0add85a | |
Karthik Chikmagalur | c8ab31a72d | |
Karthik Chikmagalur | 65c6b8334f | |
Karthik Chikmagalur | 4c9396b622 | |
Karthik Chikmagalur | c0ff434a0f | |
TEC | fa33184c53 | |
Karthik Chikmagalur | ad8bc4201c | |
Karthik Chikmagalur | ea0b32dadd | |
TEC | f9fe58dc04 | |
TEC | bd4497deae | |
Karthik Chikmagalur | 03624d0124 | |
TEC | e8bccb2e96 | |
TEC | d7beb5c495 | |
TEC | 164df5b2a3 | |
TEC | 26fb9d79de | |
TEC | a0b9e17f82 | |
Karthik Chikmagalur | c4823b5314 | |
TEC | 942e4dc9db | |
TEC | 34e7495b59 | |
Karthik Chikmagalur | 606a18c66f | |
Karthik Chikmagalur | a1da3ed93b | |
TEC | ef62c0bbaf | |
TEC | a10c6199c0 | |
Karthik Chikmagalur | 86a99c773e | |
Karthik Chikmagalur | 4fed12c45c | |
Karthik Chikmagalur | d3ffd0b82c | |
Karthik Chikmagalur | 974b6e1bc3 | |
TEC | 747480ec89 | |
Karthik Chikmagalur | 9de526b642 | |
TEC | 911b52b9a3 | |
TEC | 1dbd8103b5 | |
TEC | f44d9ee651 | |
TEC | 20d341f30b | |
TEC | b2cf025ec4 | |
TEC | 4492e665dd | |
TEC | e9261c8da6 | |
TEC | f2137e3e8e | |
TEC | c2d9c88316 | |
TEC | ba12d0d668 | |
Karthik Chikmagalur | f045db7abd | |
Karthik Chikmagalur | ab1d88477d | |
Karthik Chikmagalur | 38b7621a9c | |
TEC | 4e1559fc50 | |
Karthik Chikmagalur | c4246c6a97 | |
TEC | b817e59f8d | |
TEC | 50ce38e6cc | |
TEC | 0f1a04878d | |
TEC | ae5a053c5a | |
TEC | b28b749952 | |
Karthik Chikmagalur | 11b003c8b9 | |
Karthik Chikmagalur | 9a1a4b79f5 | |
TEC | 9faf5e25ec | |
TEC | 32e0665c3c | |
TEC | 0fc1851c94 | |
TEC | 1a7cafe87a | |
TEC | 1a26162c1b | |
Karthik Chikmagalur | 0de6a605c3 | |
Karthik Chikmagalur | 2bb8cd7959 | |
TEC | 912c0734d4 | |
Karthik Chikmagalur | 2f7646fa3c | |
TEC | bf16883d07 | |
TEC | bf9ae8b46c | |
TEC | 2b3cab47e8 | |
TEC | cfe471f4da | |
TEC | 8b000cac24 | |
TEC | 7a6ae07b2c | |
TEC | f941e1bc4d | |
TEC | 50826a1ab1 | |
TEC | 24b75f8302 | |
TEC | a06e33a165 | |
TEC | 32c965e7a6 | |
TEC | bc1decc2e8 | |
TEC | 9aa4d667cf | |
TEC | b97014ece2 | |
Ihor Radchenko | 0dd2c5ea39 | |
Ihor Radchenko | d5b98bcfb5 | |
Ihor Radchenko | d6c3ab08b4 | |
Martin Edström | a8443f2c79 | |
Ihor Radchenko | d314882301 | |
Ihor Radchenko | 7360c6b427 | |
Ihor Radchenko | 85aafac417 | |
Ihor Radchenko | ea487bffb5 | |
Ihor Radchenko | 388ba5b5c4 | |
Ihor Radchenko | c9fc4c03e8 | |
Ihor Radchenko | 1cca1967e9 | |
Ihor Radchenko | 0e1f0e1605 | |
Juan Manuel Macias | 9eec4af620 | |
Ihor Radchenko | 97cc71b594 | |
Ihor Radchenko | fd45bfa648 | |
Ihor Radchenko | b8ee1315a1 | |
Ihor Radchenko | 666bd90497 | |
Ihor Radchenko | a250fc745f | |
Ihor Radchenko | 61c235b778 | |
Martin Marshall | 38dd882685 | |
Ihor Radchenko | 5cbaa87473 | |
Ihor Radchenko | a70f216e3f | |
Ihor Radchenko | f9fc9d95c7 | |
Ihor Radchenko | 1087a7b4af | |
Ihor Radchenko | 46cf76259c | |
Ihor Radchenko | 1ff72e0918 | |
Ihor Radchenko | cf7ef80a13 | |
Ihor Radchenko | 6ff0de5c3e | |
Ihor Radchenko | f4f0fc8bda | |
Ihor Radchenko | 807bf95c49 | |
Ihor Radchenko | 7e547fd3b6 | |
Ihor Radchenko | 2a999b298f | |
Ihor Radchenko | 01a074d0b5 | |
Ihor Radchenko | 5be39ff798 | |
Ihor Radchenko | 130382779b | |
Ihor Radchenko | 112f1c5fcd | |
Ihor Radchenko | ce1da4d201 | |
Ihor Radchenko | c2a58bbd53 | |
Ihor Radchenko | bc0e14a1ab | |
Ihor Radchenko | d3a1394270 | |
Ihor Radchenko | 8c7313d397 | |
Jack Kamm | 644bf846d6 | |
Ihor Radchenko | 13d0f8bf8e | |
Ihor Radchenko | cbfe1354b3 | |
Ihor Radchenko | 9ddfb66996 | |
Ihor Radchenko | 942b4d97c1 | |
Gerard Vermeulen | 80e7c9f80f | |
Martin Marshall | 981402a93d | |
Ihor Radchenko | cfb48624f3 | |
Ihor Radchenko | 7319136420 | |
Ihor Radchenko | df1f9be7f8 | |
Ihor Radchenko | aa3724dbde | |
Ihor Radchenko | 0d77cf8421 | |
Ihor Radchenko | 27d6f8305c | |
Ihor Radchenko | c76d498f44 | |
Ihor Radchenko | 71fbe92c2e | |
Stefan Monnier | ecb5b605d7 | |
Ihor Radchenko | 8e2ed45bb1 | |
Ihor Radchenko | e3f327d1e6 | |
Ilya Chernyshov | 8d2fcfea99 | |
Ihor Radchenko | 4797ebf834 | |
Ihor Radchenko | adf841219d | |
Ihor Radchenko | ee395b9b8e | |
Ihor Radchenko | bfc0cb3723 | |
Ihor Radchenko | 62956196d0 | |
Rick Lupton | f016545aa1 | |
Ihor Radchenko | b26745b985 | |
Sławomir Grochowski | 18d98ee655 | |
Ihor Radchenko | 8ccda1737b | |
Ihor Radchenko | 4254a54f88 | |
Pedro A. Aranda Gutiérrez | 10d2868c58 | |
Ihor Radchenko | 7f5e085cad | |
Ihor Radchenko | f4414f5dbb | |
Sławomir Grochowski | 0938795fd7 | |
Ihor Radchenko | 0a58a53eda | |
Ihor Radchenko | b2ee10545e | |
Ihor Radchenko | 1abff38597 | |
Ihor Radchenko | 97f4ae0c2d | |
Ihor Radchenko | 7a6bb0904d | |
Ihor Radchenko | 09ced6d2c2 | |
Ihor Radchenko | 5cb52f379b | |
Ihor Radchenko | 3f4bdf80cb | |
Ihor Radchenko | 56748ea4e2 | |
Ihor Radchenko | 57f1c02556 | |
Ihor Radchenko | c67af5c24a | |
Ihor Radchenko | 1156554aaf | |
Ihor Radchenko | 844bd9f1f1 | |
Ihor Radchenko | 83bc81b750 | |
Ihor Radchenko | 96944e8d43 | |
Gerard Vermeulen | 71fa0014db | |
Ihor Radchenko | 344d4624e1 | |
Ihor Radchenko | 62c6d5668d | |
Sławomir Grochowski | 614d534a9d | |
Tommy Kelly | 055ed4a2f6 | |
Ihor Radchenko | 40d1352b29 | |
Ihor Radchenko | 14acf626fe | |
Ihor Radchenko | 788af56753 | |
Ihor Radchenko | 402643f194 | |
Gerard Vermeulen | 84f56c47f2 | |
Ihor Radchenko | 5f22a1be40 | |
Eric S Fraga | c9ed0388e7 | |
Ihor Radchenko | 13a8a74a99 | |
Ihor Radchenko | d4eaf8fe5f | |
Ihor Radchenko | 28e38a47aa | |
Ihor Radchenko | ee0196e6af | |
Ihor Radchenko | f1978ede29 | |
Ihor Radchenko | ad90ff7cb2 | |
Ihor Radchenko | 75b6f2712a | |
Ihor Radchenko | a5e84c2fb8 | |
Ihor Radchenko | 4aced687b8 | |
Ihor Radchenko | ede8294cf7 | |
Ihor Radchenko | fe663b6c80 | |
Ihor Radchenko | 03b383df8b | |
Ihor Radchenko | bd305ecdf6 | |
Ihor Radchenko | 15e51d7083 | |
Ihor Radchenko | afc529b4a0 | |
Hunter Jozwiak | 86c4038da6 | |
Ihor Radchenko | da9ac6da1d | |
Ihor Radchenko | 7de8b3917c | |
Ihor Radchenko | a5c977b43e | |
Ihor Radchenko | e2144f5f32 | |
Ihor Radchenko | cfef7f85f1 | |
Ihor Radchenko | 6533eedc41 |
|
@ -22,6 +22,9 @@ Org Mode is an authoring tool and a TODO lists manager for GNU Emacs.
|
|||
It relies on a lightweight plain-text markup language used in files
|
||||
with the =.org= extension.
|
||||
|
||||
Authoring Org files is best supported by Emacs, but you can view,
|
||||
understand, and change them with any text editor.
|
||||
|
||||
As an authoring tool, Org helps you write structured documents and
|
||||
provides exporting facilities. Org files can also be used for literate
|
||||
programming and reproducible research. As a TODO lists manager, Org
|
||||
|
@ -4108,10 +4111,9 @@ meaning here.]. For example:
|
|||
(sequence "|" "CANCELED(c)")))
|
||||
#+end_src
|
||||
|
||||
#+vindex: org-fast-tag-selection-include-todo
|
||||
If you then press {{{kbd(C-c C-t)}}} followed by the selection key,
|
||||
the entry is switched to this state. {{{kbd(SPC)}}} can be used to
|
||||
remove any TODO keyword from an entry[fn:15].
|
||||
remove any TODO keyword from an entry.
|
||||
|
||||
*** Setting up keywords for individual files
|
||||
:PROPERTIES:
|
||||
|
@ -4367,7 +4369,7 @@ example, with the setting
|
|||
You not only define global TODO keywords and fast access keys, but
|
||||
also request that a time is recorded when the entry is set to =DONE=,
|
||||
and that a note is recorded when switching to =WAIT= or
|
||||
=CANCELED=[fn:16]. The setting for =WAIT= is even more special: the
|
||||
=CANCELED=[fn:15]. The setting for =WAIT= is even more special: the
|
||||
=!= after the slash means that in addition to the note taken when
|
||||
entering the state, a timestamp should be recorded when /leaving/ the
|
||||
=WAIT= state, if and only if the /target/ state does not configure
|
||||
|
@ -4665,7 +4667,7 @@ of) a large number of subtasks (see [[*Checkboxes]]).
|
|||
#+cindex: checkboxes
|
||||
|
||||
#+vindex: org-list-automatic-rules
|
||||
Every item in a plain list[fn:17] (see [[*Plain Lists]]) can be made into
|
||||
Every item in a plain list[fn:16] (see [[*Plain Lists]]) can be made into
|
||||
a checkbox by starting it with the string =[ ]=. This feature is
|
||||
similar to TODO items (see [[*TODO Items]]), but is more lightweight.
|
||||
Checkboxes are not included into the global TODO list, so they are
|
||||
|
@ -4685,37 +4687,6 @@ Here is an example of a checkbox list.
|
|||
- [X] talk to the neighbors
|
||||
#+end_example
|
||||
|
||||
A checkbox can be in one of the three states:
|
||||
1. not checked =[ ]=
|
||||
2. partially checked =[-]=
|
||||
3. checked =[X]=
|
||||
|
||||
Checkboxes work hierarchically, so if a checkbox item has children
|
||||
that are checkboxes, toggling one of the children checkboxes makes the
|
||||
parent checkbox reflect if none, some, or all of the children are
|
||||
checked.
|
||||
|
||||
If all child checkboxes are not checked, the parent checkbox is also not checked.
|
||||
#+begin_example
|
||||
- [ ] call people
|
||||
- [ ] Peter
|
||||
- [ ] Sarah
|
||||
#+end_example
|
||||
|
||||
If some but not all child checkboxes are checked, the parent checkbox is partially checked.
|
||||
#+begin_example
|
||||
- [-] call people
|
||||
- [X] Peter
|
||||
- [ ] Sarah
|
||||
#+end_example
|
||||
|
||||
If all child checkboxes are checked, the parent checkbox is also checked.
|
||||
#+begin_example
|
||||
- [X] call people
|
||||
- [X] Peter
|
||||
- [X] Sarah
|
||||
#+end_example
|
||||
|
||||
#+cindex: statistics, for checkboxes
|
||||
#+cindex: checkbox statistics
|
||||
#+cindex: @samp{COOKIE_DATA}, property
|
||||
|
@ -4746,6 +4717,37 @@ If the current outline node has an =ORDERED= property, checkboxes must
|
|||
be checked off in sequence, and an error is thrown if you try to check
|
||||
off a box while there are unchecked boxes above it.
|
||||
|
||||
A checkbox can be in one of the three states:
|
||||
1. not checked =[ ]=
|
||||
2. partially checked =[-]=
|
||||
3. checked =[X]=
|
||||
|
||||
Checkboxes work hierarchically, so if a checkbox item has children
|
||||
that are checkboxes, toggling one of the children checkboxes makes the
|
||||
parent checkbox reflect if none, some, or all of the children are
|
||||
checked.
|
||||
|
||||
If all child checkboxes are not checked, the parent checkbox is also not checked.
|
||||
#+begin_example
|
||||
- [ ] call people
|
||||
- [ ] Peter
|
||||
- [ ] Sarah
|
||||
#+end_example
|
||||
|
||||
If some but not all child checkboxes are checked, the parent checkbox is partially checked.
|
||||
#+begin_example
|
||||
- [-] call people
|
||||
- [X] Peter
|
||||
- [ ] Sarah
|
||||
#+end_example
|
||||
|
||||
If all child checkboxes are checked, the parent checkbox is also checked.
|
||||
#+begin_example
|
||||
- [X] call people
|
||||
- [X] Peter
|
||||
- [X] Sarah
|
||||
#+end_example
|
||||
|
||||
The following commands work with checkboxes:
|
||||
|
||||
- {{{kbd(C-c C-c)}}} (~org-toggle-checkbox~) ::
|
||||
|
@ -5465,8 +5467,8 @@ not be used as keys in the properties drawer:
|
|||
| =PRIORITY= | The priority of the entry, a string with a single letter. |
|
||||
| =SCHEDULED= | The scheduling timestamp. |
|
||||
| =TAGS= | The tags defined directly in the headline. |
|
||||
| =TIMESTAMP= | The first keyword-less timestamp in the entry. |
|
||||
| =TIMESTAMP_IA= | The first inactive timestamp in the entry. |
|
||||
| =TIMESTAMP= | The first active keyword-less timestamp in the entry.[fn:17] |
|
||||
| =TIMESTAMP_IA= | The first inactive keyword-less timestamp in the entry. |
|
||||
| =TODO= | The TODO keyword of the entry. |
|
||||
|
||||
** Property Searches
|
||||
|
@ -6677,16 +6679,16 @@ special repeaters =++= and =.+=. For example:
|
|||
Marking this DONE shifts the date to exactly one hour from now.
|
||||
#+end_example
|
||||
|
||||
#+vindex: org-agenda-skip-scheduled-if-deadline-is-shown
|
||||
#+vindex: org-agenda-skip-scheduled-repeats-after-deadline
|
||||
You may have both scheduling and deadline information for a specific
|
||||
task. If the repeater is set for the scheduling information only, you
|
||||
probably want the repeater to be ignored after the deadline. If so,
|
||||
set the variable ~org-agenda-skip-scheduled-if-deadline-is-shown~ to
|
||||
~repeated-after-deadline~. However, any scheduling information
|
||||
without a repeater is no longer relevant once the task is done, and
|
||||
thus, removed upon repeating the task. If you want both scheduling
|
||||
and deadline information to repeat after the same interval, set the
|
||||
same repeater for both timestamps.
|
||||
set the variable ~org-agenda-skip-scheduled-repeats-after-deadline~ to
|
||||
~t~. However, any scheduling information without a repeater is no
|
||||
longer relevant once the task is done, and thus, removed upon
|
||||
repeating the task. If you want both scheduling and deadline
|
||||
information to repeat after the same interval, set the same repeater
|
||||
for both timestamps.
|
||||
|
||||
An alternative to using a repeater is to create a number of copies of
|
||||
a task subtree, with dates shifted in each copy. The command
|
||||
|
@ -7819,10 +7821,10 @@ with prefix commands:
|
|||
|
||||
Visit the last stored capture item in its buffer.
|
||||
|
||||
#+vindex: org-capture-bookmark
|
||||
#+vindex: org-bookmark-names-plist
|
||||
#+vindex: org-capture-last-stored
|
||||
You can also jump to the bookmark ~org-capture-last-stored~, which is
|
||||
automatically created unless you set ~org-capture-bookmark~ to ~nil~.
|
||||
automatically created unless you customize ~org-bookmark-names-plist~.
|
||||
|
||||
To insert the capture at point in an Org buffer, call ~org-capture~
|
||||
with a {{{kbd(C-0)}}} prefix argument.
|
||||
|
@ -11331,7 +11333,7 @@ pretty output for a number of export backends.
|
|||
:END:
|
||||
#+cindex: @LaTeX{} fragments
|
||||
|
||||
#+vindex: org-format-latex-header
|
||||
#+vindex: org-latex-preview-header
|
||||
Org mode can contain LaTeX math fragments, and it supports ways to
|
||||
process these for several export backends. When exporting to LaTeX,
|
||||
the code is left as it is. When exporting to HTML, Org can use either
|
||||
|
@ -11388,20 +11390,19 @@ lines:
|
|||
:END:
|
||||
#+cindex: @LaTeX{} fragments, preview
|
||||
|
||||
#+vindex: org-preview-latex-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-format-latex-options
|
||||
#+vindex: org-format-latex-header
|
||||
You can customize the variables ~org-format-latex-options~ and
|
||||
~org-format-latex-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.
|
||||
#+vindex: org-latex-preview-appearance-options
|
||||
#+vindex: org-latex-preview-header
|
||||
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 ~: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
|
||||
|
@ -11425,6 +11426,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.
|
||||
|
@ -12415,11 +12434,11 @@ value.
|
|||
#+end_example
|
||||
|
||||
#+cindex: @samp{TOC}, keyword
|
||||
Org normally inserts the table of contents directly before the first
|
||||
headline of the file. To move the table of contents to a different
|
||||
location, first turn off the default with ~org-export-with-toc~
|
||||
variable or with =#+OPTIONS: toc:nil=. Then insert =#+TOC: headlines
|
||||
N= at the desired location(s).
|
||||
Org normally inserts the table of contents in front of the exported
|
||||
document. To move the table of contents to a different location,
|
||||
first turn off the default with ~org-export-with-toc~ variable or with
|
||||
=#+OPTIONS: toc:nil=. Then insert =#+TOC: headlines N= at the desired
|
||||
location(s).
|
||||
|
||||
#+begin_example
|
||||
,#+OPTIONS: toc:nil
|
||||
|
@ -12479,7 +12498,7 @@ the table of contents.
|
|||
#+cindex: export, include files
|
||||
#+cindex: @samp{INCLUDE}, keyword
|
||||
|
||||
During export, you can include the content of another file. For
|
||||
[[*Summary of the export process][During export]], you can include the content of another file. For
|
||||
example, to include your =.emacs= file, you could use:
|
||||
|
||||
: #+INCLUDE: "~/.emacs" src emacs-lisp
|
||||
|
@ -13917,8 +13936,11 @@ general options (see [[*Export Settings]]).
|
|||
#+cindex: @samp{LANGUAGE}, keyword
|
||||
#+vindex: org-latex-packages-alist
|
||||
#+vindex: org-latex-language-alist
|
||||
#+vindex: org-export-default-language
|
||||
|
||||
Language code of the primary document language.
|
||||
Language code of the primary document language. When =LANGUAGE=
|
||||
keyword is not not specified use the value of
|
||||
~org-export-default-language~ (by default - =en=, American English)
|
||||
|
||||
The list of language codes supported by Org is stored in the
|
||||
variable ~org-latex-language-alist~.
|
||||
|
@ -16415,12 +16437,14 @@ for usage and configuration details.
|
|||
:END:
|
||||
|
||||
#+vindex: org-export-before-processing-hook
|
||||
#+vindex: org-export-before-processing-functions
|
||||
#+vindex: org-export-before-parsing-hook
|
||||
The export process executes two hooks before the actual exporting
|
||||
begins. The first hook, ~org-export-before-processing-hook~, runs
|
||||
before any expansions of macros, Babel code, and include keywords in
|
||||
the buffer. The second hook, ~org-export-before-parsing-hook~, runs
|
||||
before the buffer is parsed.
|
||||
begins. The first hook, ~org-export-before-processing-functions~,
|
||||
runs before any expansions of macros, Babel code, and include keywords
|
||||
in the buffer. The second hook,
|
||||
~org-export-before-parsing-functions~, runs before the buffer is
|
||||
parsed.
|
||||
|
||||
Functions added to these hooks are called with a single argument: the
|
||||
export backend actually used, as a symbol. You may use them for
|
||||
|
@ -16439,7 +16463,7 @@ BACKEND is the export backend being used, as a symbol."
|
|||
;; the docstring of `org-map-entries' for details.
|
||||
(setq org-map-continue-from (point)))))
|
||||
|
||||
(add-hook 'org-export-before-parsing-hook #'my-headline-removal)
|
||||
(add-hook 'org-export-before-parsing-functions #'my-headline-removal)
|
||||
#+end_src
|
||||
|
||||
*** Filters
|
||||
|
@ -16521,6 +16545,158 @@ debugging.
|
|||
,#+END_SRC
|
||||
#+end_example
|
||||
|
||||
*** Summary of the export process
|
||||
:PROPERTIES:
|
||||
:UNNUMBERED: notoc
|
||||
:END:
|
||||
|
||||
#+findex: org-export-as
|
||||
Org mode export is a multi-step process that works on a temporary copy
|
||||
of the buffer. The export process consists of 4 major steps:
|
||||
|
||||
1. Process the temporary copy, making necessary changes to the buffer
|
||||
text;
|
||||
|
||||
2. Parse the buffer, converting plain Org markup into an abstract
|
||||
syntax tree (AST);
|
||||
|
||||
3. Convert the AST to text, as prescribed by the selected export
|
||||
backend;
|
||||
|
||||
4. Post-process the resulting exported text.
|
||||
|
||||
|
||||
#+texinfo: @noindent
|
||||
Process temporary copy of the source Org buffer [fn::Unless
|
||||
otherwise specified, each step of the export process only operates on
|
||||
the accessible portion of the buffer. When subtree export is selected
|
||||
(see [[*The Export Dispatcher]]), the buffer is narrowed to the body of
|
||||
the selected subtree, so that the rest of the buffer text, except
|
||||
export keywords, does not contribute to the export output.]:
|
||||
|
||||
1. Execute ~org-export-before-processing-functions~ (see [[*Export hooks]]);
|
||||
|
||||
2. Expand =#+include= keywords in the whole buffer (see
|
||||
[[*Include Files]]);
|
||||
|
||||
3. Remove commented subtrees in the whole buffer (see [[*Comment
|
||||
Lines]]);
|
||||
|
||||
4. Replace macros in the whole buffer (see [[*Macro Replacement]]);
|
||||
|
||||
5. When ~org-export-use-babel~ is non-nil (default), process code
|
||||
blocks:
|
||||
|
||||
- Leave code blocks inside archived subtrees (see [[*Internal
|
||||
archiving]]) as is;
|
||||
|
||||
- Evaluate all the other code blocks according to code block
|
||||
headers (see [[*Limit code block evaluation]]);
|
||||
|
||||
- Remove code, results of evaluation, both, or neither according
|
||||
to =:exports= header argument (see [[*Exporting Code Blocks]]).
|
||||
|
||||
|
||||
#+texinfo: @noindent
|
||||
Parse the temporary buffer, creating AST:
|
||||
|
||||
1. Execute ~org-export-before-parsing-functions~ (see [[*Export hooks]]).
|
||||
The hook functions may still modify the buffer;
|
||||
|
||||
2. Calculate export option values according to subtree-specific export
|
||||
settings, in-buffer keywords, =#+BIND= keywords, and buffer-local
|
||||
and global customization. The whole buffer is considered;
|
||||
|
||||
3. When ~org-org-with-cite-processors~ is non-nil (default), determine
|
||||
contributing bibliographies and record them into export options
|
||||
(see [[*Citations]]). The whole buffer is considered;
|
||||
|
||||
4. Execute ~org-export-filter-options-functions~;
|
||||
|
||||
5. Parse the accessible portion of the temporary buffer to generate an
|
||||
AST. The AST is a nested list of lists representing Org syntax
|
||||
elements (see [[https://orgmode.org/worg/dev/org-element-api.html][Org Element API]] for more details):
|
||||
|
||||
: (org-data ...
|
||||
: (heading
|
||||
: (section
|
||||
: (paragraph (plain-text) (bold (plain-text))))
|
||||
: (heading)
|
||||
: (heading (section ...))))
|
||||
|
||||
Past this point, modifications to the temporary buffer no longer
|
||||
affect the export; Org export works only with the AST;
|
||||
|
||||
6. Remove elements that are not exported from the AST:
|
||||
|
||||
- Headings according to =SELECT_TAGS= and =EXCLUDE_TAGS= export
|
||||
keywords; =task=, =inline=, =arch= export options (see
|
||||
[[*Export Settings]]);
|
||||
|
||||
- Comments;
|
||||
|
||||
- Clocks, drawers, fixed-width environments, footnotes, LaTeX
|
||||
environments and fragments, node properties, planning lines,
|
||||
property drawers, statistics cookies, timestamps, etc according
|
||||
to =#+OPTIONS= keyword (see [[*Export Settings]]);
|
||||
|
||||
- Table rows containing width and alignment markers (see [[*Column
|
||||
Width and Alignment]]);
|
||||
|
||||
- Table columns containing recalc marks (see [[*Advanced features]]).
|
||||
|
||||
7. Expand environment variables in file link AST nodes according to
|
||||
the =expand-links= export option (see [[*Export Settings]]);
|
||||
|
||||
8. Execute ~org-export-filter-parse-tree-functions~. These
|
||||
functions can modify the AST by side effects;
|
||||
|
||||
9. When ~org-org-with-cite-processors~ is non-nil (default), replace
|
||||
citation AST nodes and =#+print_bibliography= keyword AST nodes as
|
||||
prescribed by the selected citation export processor (see [[*Citation
|
||||
export processors]]).
|
||||
|
||||
|
||||
#+texinfo: @noindent
|
||||
Convert the AST to text by traversing the AST nodes, depth-first:
|
||||
|
||||
1. Convert the leaf nodes (without children) to text as prescribed
|
||||
by "transcoders" in the selected export backend
|
||||
[fn:: See transcoders and ~:translate-alist~ in the docstrings
|
||||
of ~org-export-define-backend~ and ~org-export-define-derived-backend~.];
|
||||
|
||||
2. Pass the converted nodes through the corresponding export
|
||||
filters (see [[*Filters]]);
|
||||
|
||||
3. Concatenate all the converted child nodes to produce parent
|
||||
node contents;
|
||||
|
||||
4. Convert the nodes with children to text, passing the nodes
|
||||
themselves and their contents to the corresponding transcoders
|
||||
and then to the export filters (see [[*Filters]]).
|
||||
|
||||
|
||||
#+texinfo: @noindent
|
||||
Post-process the exported text:
|
||||
|
||||
1. Post-process the converted AST, as prescribed by the export
|
||||
backend. [fn:: See ~inner-template~ in the docstring of ~org-export-define-backend~.]
|
||||
This step usually adds generated content (like Table of Contents)
|
||||
to the exported text;
|
||||
|
||||
2. Execute ~org-export-filter-body-functions~;
|
||||
|
||||
3. Unless body-only export is selected (see [[*The Export Dispatcher]]),
|
||||
add the necessary metadata to the final document, as prescribed
|
||||
by the export backend. Examples: Document author/title; HTML
|
||||
headers/footers; LaTeX preamble;
|
||||
|
||||
4. When ~org-org-with-cite-processors~ is non-nil (default), add
|
||||
bibliography metadata, as prescribed by the citation export
|
||||
processor;
|
||||
|
||||
5. Execute ~org-export-filter-final-output-functions~.
|
||||
|
||||
*** Extending an existing backend
|
||||
:PROPERTIES:
|
||||
:UNNUMBERED: notoc
|
||||
|
@ -16577,7 +16753,381 @@ buffer:
|
|||
|
||||
Further steps to consider would be an interactive function,
|
||||
self-installing an item in the export dispatcher menu, and other
|
||||
user-friendly improvements.
|
||||
user-friendly improvements. See
|
||||
<https://orgmode.org/worg/dev/org-export-reference.html> for more
|
||||
details.
|
||||
|
||||
*** Export features
|
||||
**** The underlying idea
|
||||
|
||||
Across export backends it is common to want to include certain chunks
|
||||
of content that are only relevant in particular situations.
|
||||
|
||||
With static export templates, one is forced to choose between
|
||||
including everything that /might/ be wanted, or including very little
|
||||
by default and requiring common content to be manually added every
|
||||
time it is wanted.
|
||||
|
||||
"Export features" allow for a third option, a much more sophisticated
|
||||
method of resolving this dilemma. At the start of the export process,
|
||||
the buffer being exported and the export communication plist (~info~)
|
||||
are scanned to determine which capabilities are relevant to the
|
||||
current export. During the construction of the final output this list
|
||||
of capabilities is used to produce snippets of content to be included.
|
||||
|
||||
This can be thought of as the construction of a graph between conditions,
|
||||
features, and feature implementations. For example, say we have three conditions
|
||||
we want to support:
|
||||
+ Say that images need some extra setup to be supported well, we can
|
||||
just include it when image links are found in the buffer.
|
||||
+ Say we can better support emojis by treating them as images in a
|
||||
particular export backend. We could look for a signal in the buffer
|
||||
that emojis should be handled as images, and then make use of some
|
||||
"image support" and "emoji support" snippets.
|
||||
+ Say that LaTeX maths requires some extra setup, we can just
|
||||
do this when inline LaTeX fragments are found.
|
||||
This situation can be crudely drawn with the following graph:
|
||||
|
||||
#+begin_example
|
||||
condition feature implementation
|
||||
========= ======= ===============
|
||||
|
||||
[emoji] -----------> emoji ------> [emoji plist]
|
||||
\
|
||||
'---->----.
|
||||
\
|
||||
[image link] ------> image ------> [image plist]
|
||||
|
||||
[inline LaTeX] ----> maths ------> [maths plist]
|
||||
|
||||
\____________________/ \__________________/
|
||||
phase 1 phase 2
|
||||
#+end_example
|
||||
|
||||
In phase 1 "feature detection" the relevant features are determined, and in
|
||||
phase 2 "feature implementation" how those features can be provided is worked
|
||||
out.
|
||||
|
||||
**** Feature detection
|
||||
|
||||
After the expansion of =#+include= statements and the removal of
|
||||
comments, the export communication plist (~info~) is annotated. At the
|
||||
very end of the annotation process, ~org-export-detect-features~ is
|
||||
run to determine the list of capabilities relevant to the current export.
|
||||
|
||||
This operates by merging the global feature condition alist
|
||||
(~org-export-conditional-features~) with the ~feature-conditions~ slot
|
||||
of the current backend and each of its parents. This produces the
|
||||
total feature conditions alist, which has the form:
|
||||
|
||||
#+begin_example
|
||||
((condition . implied-features)
|
||||
...)
|
||||
#+end_example
|
||||
|
||||
Where =condition= is a test that implies that =implied-features= are
|
||||
relevant. While =implied-features= is always a list of feature
|
||||
symbols, for convenience =condition= can take a number of forms,
|
||||
namely:
|
||||
+ A regexp which is searched for in the export buffer.
|
||||
+ A variable, if a string it is used as a regexp search, otherwise any
|
||||
non-nil value is taken to imply =implied-features=.
|
||||
+ A (unary) function, which is called with on the export communication
|
||||
plist (~info~). A returned string is used as a regexp search,
|
||||
otherwise any non-nil value is taken to imply =implied-features=.
|
||||
|
||||
As an example, a feature conditions alist which checks whether any
|
||||
headings exist, and if the word "hello" appears could take the
|
||||
following form:
|
||||
|
||||
#+begin_example
|
||||
(((lambda (info)
|
||||
(org-element-map (plist-get info :parse-tree) 'heading
|
||||
#'identity info t))
|
||||
headlines)
|
||||
("hello" has-greeting))
|
||||
#+end_example
|
||||
|
||||
Conditions are inherited from parent export backends and (for conditions general
|
||||
enough to apply across backends) the variable ~org-export-conditional-features~.
|
||||
|
||||
#+begin_example
|
||||
,--> beamer
|
||||
/
|
||||
html <----. ,----> latex --'
|
||||
\ /
|
||||
org-export-conditional-features
|
||||
/ \
|
||||
ascii <----' '----> odt
|
||||
#+end_example
|
||||
|
||||
**** Feature implementations
|
||||
|
||||
The other half of the export feature system is of course producing
|
||||
snippets of content from the list of features. Export backends can do
|
||||
this at any point via ~org-export-expand-feature-snippets~. This
|
||||
operates on a /feature implementation alist/. The implementation alist
|
||||
is essentially a mirror of the condition alist, instead of =(condition
|
||||
. feature-list)= elements it takes =(feature . implementation-plist)=
|
||||
elements. This reversal of order may seem a bit odd, but it should
|
||||
help make the condition--feature--implementation graph more apparent.
|
||||
|
||||
For example, considering this example condition alist and implementation alist
|
||||
would be represented as the earlier graph.
|
||||
|
||||
#+begin_example
|
||||
;; The condition alist
|
||||
(([emoji predicate] emoji image)
|
||||
([image predicate] image)
|
||||
([inline LaTeX predicate] maths))
|
||||
;; The implementation alist
|
||||
((emoji [plist])
|
||||
(image [plist])
|
||||
(maths [plist])
|
||||
#+end_example
|
||||
|
||||
The implementation plist recognises a number of keywords, but the
|
||||
primary keyword is ~:snippet~. The snippet value provides the snippet
|
||||
content used to provide the feature's capability. Much like
|
||||
~condition~, it accepts a number of forms for convenience, namely:
|
||||
+ A string, which is passed on.
|
||||
+ A variable symbol, the value of which must be a string.
|
||||
+ A (unary) function, which is called on the export communication
|
||||
plist (~info~), and must return a string.
|
||||
|
||||
Note that no keys are mandatory in the implementation plist (not even
|
||||
~:snippet~).
|
||||
|
||||
Like conditions, implementations are also inherited from parent backends, but
|
||||
there is no "root" global list of implementations, as they are always
|
||||
backend-specific.
|
||||
|
||||
#+begin_example
|
||||
,--> beamer
|
||||
/
|
||||
html <---o o---> latex --'
|
||||
|
||||
ascii <---o o---> odt
|
||||
#+end_example
|
||||
|
||||
**** Feature dependency and incompatibility
|
||||
|
||||
While just connecting features with snippets satisfies most use cases,
|
||||
this system is designed to also allow for complex configurations of
|
||||
inter-dependent snippets.
|
||||
|
||||
In slightly more complex examples, we may run across implementations
|
||||
which either (a) only make sense when another feature is active, or
|
||||
(b) require another implementation to be used in order to work. These
|
||||
two situations are covered by the ~:when~ and ~:requires~ keywords
|
||||
respectively. The accept either a single feature symbol or a list of
|
||||
feature symbols.
|
||||
|
||||
For example, if an implementation contains ~:when featA~, it will only
|
||||
be used when =featA= is active. If the implementation contains ~:when
|
||||
(featA featB)~ it will require /both/ =featA= and =featB= to be
|
||||
active. The ~:requires~ keyword works in the same way, but
|
||||
unconditionally requires implementations instead of testing for them.
|
||||
|
||||
Occasionally one implementation may be incompatible with another. For
|
||||
example, in LaTeX loading the same package with different options will
|
||||
often produce an "options clash" error. To ensure that incompatible
|
||||
implementations are not used, the ~:prevents~ keyword makes it as if
|
||||
the feature were never used in the first place.
|
||||
|
||||
Circular ~:requires~ and ~:prevents~, or features that are
|
||||
simultaneously required and prevented result in undefined behaviour.
|
||||
Similarly, the behaviour of mutual ~:when~s (e.g. ~(a :when b) (b
|
||||
:when a)~ is also undefined.
|
||||
|
||||
**** Feature ordering
|
||||
|
||||
In many scenarios it is not only /which/ snippets are included that
|
||||
matters, but the /order/ in which they are placed. A requirement for a
|
||||
certain snippet to appear before/after others can be specified through
|
||||
the ~:before~ and ~:after~ keywords. Like ~:when~, ~:requires~, and
|
||||
~:prevents~ they accept either a single feature symbol or a list of
|
||||
feature symbols.
|
||||
|
||||
As an example, should an implementation plist contain ~:before featA
|
||||
:after (featB featC)~ it will be placed after =featA= but before
|
||||
=featB= and =featC=. It is possible to accidentally create circular
|
||||
dependencies, in which case an error will be raised.
|
||||
|
||||
While ~:before~ and ~:after~ work well for specifying relative
|
||||
ordering, it can also be useful to specify the /absolute/ ordering,
|
||||
for instance to put something first or last. This can be controlled
|
||||
via the ~:order~ keyword. Each implementation has an ~:order~ of zero
|
||||
by default. Implementations with a higher ~:order~ come later.
|
||||
|
||||
# REVIEW maybe give a convention on :order ranges?
|
||||
# Perhaps take inspiration from ~add-hook~.
|
||||
|
||||
-----
|
||||
|
||||
The overall ordering behaviour can be characterized as a ascending
|
||||
sort of ~:order~ followed by a stable [[https://en.wikipedia.org/wiki/Topological_sorting][topological sort]] based on
|
||||
~:before~ and ~:after~.
|
||||
|
||||
**** Adding or editing export features
|
||||
|
||||
The export features of a backend can be modified via the convenience
|
||||
macro ~org-export-update-features~. This is invoked with the following
|
||||
form:
|
||||
|
||||
#+begin_example
|
||||
(org-export-update-features 'BACKEND
|
||||
(FEATURE-NAME
|
||||
:PROPERTY VALUE
|
||||
...)
|
||||
...)
|
||||
#+end_example
|
||||
|
||||
For each feature mentioned, it sets the each =:PROPERTY= to =VALUE= in
|
||||
the implementation plist. The one exception to this is ~:condition~ in
|
||||
which case the backend's feature condition alist is modified so that
|
||||
the condition is taken to imply the feature.
|
||||
|
||||
Setting ~:condition t~ will thus make the feature enabled by default. This is not
|
||||
a special case, but rather an instance of the general behaviour of obtaining the
|
||||
value of any non-function symbol provided, and as ~(symbol-value 't)~ is always
|
||||
non-nil, the associated features will always be considered active. Conversely
|
||||
setting ~:condition nil~ will make it so no conditions imply the feature. This is
|
||||
possible thanks to special behavior that removes the feature from all other
|
||||
conditions' associations when ~nil~ is given.
|
||||
|
||||
Since having a anonymous function (lambda) is expected to be
|
||||
reasonably common with ~:condition~ and ~:snippet~, for those keywords
|
||||
and sexp given is implicitly wrapped with ~(lambda (info) SEXP)~.
|
||||
|
||||
If the backend is not available at the time the feature update is run,
|
||||
an error will be raised.
|
||||
|
||||
**** Custom export feature examples
|
||||
|
||||
To make the usage of ~org-export-update-features~ and the capabilities
|
||||
of the export feature system clearer, here are a few examples
|
||||
~org-export-update-features~ invocations.
|
||||
|
||||
Say you want to apply the [[https://ctan.org/pkg/chickenize][chickenize]] package to the word "wacky" when
|
||||
the title starts with "wacky". We can implement that by testing for
|
||||
the regexp =^#\\+title: Wacky= and including
|
||||
src_latex{\usepackage[chickenstring[1]='wacky']{chickenize}} when it is
|
||||
found.
|
||||
|
||||
#+begin_example
|
||||
(org-export-update-features 'latex
|
||||
(wacky-chicken
|
||||
:condition "^#\\+title: Wacky"
|
||||
:snippet "\\usepackage[chickenstring[1]='wacky']{chickenize}"))
|
||||
#+end_example
|
||||
|
||||
However, if =#+title: Wacky= is placed inside an example block, this
|
||||
regexp will match even though the match isn't actually parsed as a
|
||||
keyword. To be more robust, we can inspect ~info~ instead.
|
||||
|
||||
#+begin_example
|
||||
(org-export-update-features 'latex
|
||||
(wacky-chicken
|
||||
:condition (and (car (plist-get info :title))
|
||||
(string-match-p "^Wacky" (car (plist-get info :title))))
|
||||
:snippet "\\usepackage[chickenstring[1]='wacky']{chickenize}"))
|
||||
#+end_example
|
||||
|
||||
=chickenize= is a LuaLaTeX only package, and so trying to use this
|
||||
when compiling with pdfLaTeX or XeLaTeX will cause issues. This may
|
||||
well apply to other snippets too, so it could make sense to make a
|
||||
=lualatex= feature to indicate when LuaLaTeX is being used.
|
||||
|
||||
#+begin_example
|
||||
(org-export-update-features 'latex
|
||||
(lualatex
|
||||
:condition (equal (plist-get info :latex-compiler) "lualatex")))
|
||||
#+end_example
|
||||
|
||||
To only use the chickenize snippet with LuaLaTeX, we can now add
|
||||
=lualatex= as a ~:when~ clause.
|
||||
|
||||
#+begin_example
|
||||
(org-export-update-features 'latex
|
||||
(wacky-chicken
|
||||
:when lualatex))
|
||||
#+end_example
|
||||
|
||||
Hopefully this has given you an impression of how ~:condition~, ~:when~, and
|
||||
~:snippet~ can look in practice. To demonstrate ~:requires~, ~:prevents~, and
|
||||
~:after~ we will consider another LaTeX example.
|
||||
|
||||
Say that you wanted a few named special blocks to automatically export nicely,
|
||||
such as =#+begin_warning=, =#+begin_info=, and =#+begin_note=. All three of
|
||||
these can be individually detected and handled appropriately. For the sake of
|
||||
simplicity, a crude regexp will be used here, however examining the parse tree
|
||||
would be a more robust solution.
|
||||
|
||||
#+begin_example
|
||||
(org-export-update-features 'latex
|
||||
(box-warning
|
||||
:condition "^[ \t]*#\\+begin_warning"
|
||||
:snippet "\\mysetupbox{warning}"
|
||||
:requires mysetupbox
|
||||
:after mysetupbox)
|
||||
(box-info
|
||||
:condition "^[ \t]*#\\+begin_info"
|
||||
:snippet "\\mysetupbox{info}"
|
||||
:requires mysetupbox
|
||||
:after mysetupbox)
|
||||
(box-note
|
||||
:condition "^[ \t]*#\\+begin_note"
|
||||
:snippet "\\mysetupbox{note}"
|
||||
:requires mysetupbox
|
||||
:after mysetupbox)
|
||||
(mysetupbox
|
||||
:snippet "\newcommand{\mysetupbox}...")
|
||||
#+end_example
|
||||
|
||||
Here, all three box types make use of LaTeX command ~\mysetupbox~ which is
|
||||
provided by the =mysetupbox= feature implementation. By using a ~:requires~ for
|
||||
this, we can make sure it is availible that it is loaded once, and thanks to the
|
||||
~:after mysetupbox~ lines the specific box setup invocations will occur after
|
||||
the ~\newcommand{\mysetupbox}...~ definition.
|
||||
|
||||
Say that when using beamer you use a package that defines its own
|
||||
warning/info/note environments and you'd like to use those. In that case one can
|
||||
make an on-by-default beamer feature that prevents the box features from being
|
||||
used.
|
||||
|
||||
#+begin_example
|
||||
(org-export-update-features 'beamer
|
||||
(no-custom-boxes
|
||||
:condition t
|
||||
:prevents (box-warning box-info box-note)))
|
||||
#+end_example
|
||||
|
||||
**** Detailed explanation of the implementation resolution process
|
||||
|
||||
The previous descriptions of the "export feature" behaviour should give a clear
|
||||
overview of how this feature works. In case more detail is wanted, or should
|
||||
there be any ambiguity, here is a more technical description of the overall
|
||||
feature implementation resolution process.
|
||||
|
||||
1. The list of detected features is used to obtain all applicable corresponding
|
||||
feature implementations. Detected feature symbols may have /no/ corresponding
|
||||
implementation.
|
||||
2. The list of feature implementations is sorted according to ~:order~.
|
||||
3. Using a queue, all required features (~:requires~) are added to the list of feature
|
||||
implementations, as are their requirements recursively. Should a feature that
|
||||
has no implementation be required, an ~org-missing-feature-dependency~ error is raised.
|
||||
4. The implementations with a ~:when~ condition are scanned and marked as
|
||||
confirmed when all of the ~:when~ conditions are known to be satisfied. This is
|
||||
repeated until there is no change in the list of confirmed implementations,
|
||||
at which point all non-confirmed implementations are removed.
|
||||
5. For each of the feature implementations in turn, prevented features
|
||||
(~:prevents~) are removed from the list. Feature implementations that are only
|
||||
present because of a feature that has now been removed are themselves
|
||||
removed, recursively.
|
||||
6. The list of feature implementations is sorted according to ~:order~, again.
|
||||
7. A stable topological sort is performed using ~:before~ and ~:after~. Should any
|
||||
circular dependencies be found, a ~org-circular-feature-dependency~ error is raised.
|
||||
|
||||
** Export Region
|
||||
:PROPERTIES:
|
||||
|
@ -16968,6 +17518,7 @@ to HTML, the following links all point to a dedicated anchor in
|
|||
:END:
|
||||
#+cindex: sitemap, of published pages
|
||||
|
||||
#+vindex: org-publish-project-alist
|
||||
The following properties may be used to control publishing of
|
||||
a map of files for a given project.
|
||||
|
||||
|
@ -16985,6 +17536,12 @@ a map of files for a given project.
|
|||
|
||||
Title of sitemap page. Defaults to name of file.
|
||||
|
||||
- ~:sitemap-style~ ::
|
||||
|
||||
Can be ~list~ (site-map is just an itemized list of the titles of
|
||||
the files involved) or ~tree~ (the directory structure of the
|
||||
source files is reflected in the site-map). Defaults to ~tree~.
|
||||
|
||||
- ~:sitemap-format-entry~ ::
|
||||
|
||||
#+findex: org-publish-find-date
|
||||
|
@ -17030,21 +17587,6 @@ a map of files for a given project.
|
|||
|
||||
Should sorting be case-sensitive? Default ~nil~.
|
||||
|
||||
- ~:sitemap-file-entry-format~ ::
|
||||
|
||||
With this option one can tell how a sitemap's entry is formatted in
|
||||
the sitemap. This is a format string with some escape sequences:
|
||||
~%t~ stands for the title of the file, ~%a~ stands for the author of
|
||||
the file and ~%d~ stands for the date of the file. The date is
|
||||
retrieved with the ~org-publish-find-date~ function and formatted
|
||||
with ~org-publish-sitemap-date-format~. Default ~%t~.
|
||||
|
||||
- ~:sitemap-date-format~ ::
|
||||
|
||||
Format string for the ~format-time-string~ function that tells how
|
||||
a sitemap entry's date is to be formatted. This property bypasses
|
||||
~org-publish-sitemap-date-format~ which defaults to ~%Y-%m-%d~.
|
||||
|
||||
*** Generating an index
|
||||
:PROPERTIES:
|
||||
:DESCRIPTION: An index that reaches across pages.
|
||||
|
@ -20383,6 +20925,7 @@ changes.
|
|||
| =fnconfirm= | Offer automatic label for editing or confirmation. |
|
||||
| =fnadjust= | Automatically renumber and sort footnotes. |
|
||||
| =nofnadjust= | Do not renumber and sort automatically. |
|
||||
| =fnanon= | Create anonymous footnotes with ~org-footnote-new~. |
|
||||
|
||||
#+vindex: org-hide-block-startup
|
||||
#+vindex: org-hide-drawer-startup
|
||||
|
@ -22817,20 +23360,20 @@ from the list of stored links. To keep it in the list for later use,
|
|||
use a triple {{{kbd(C-u)}}} prefix argument to {{{kbd(C-c C-l)}}}, or
|
||||
configure the option ~org-link-keep-stored-after-insertion~.
|
||||
|
||||
[fn:15] Check also the variable ~org-fast-tag-selection-include-todo~,
|
||||
it allows you to change the TODO state through the tags interface (see
|
||||
[[*Setting Tags]]), in case you like to mingle the two concepts. Note
|
||||
that this means you need to come up with unique keys across both sets
|
||||
of keywords.
|
||||
|
||||
[fn:16] It is possible that Org mode records two timestamps when you
|
||||
[fn:15] It is possible that Org mode records two timestamps when you
|
||||
are using both ~org-log-done~ and state change logging. However, it
|
||||
never prompts for two notes: if you have configured both, the state
|
||||
change recording note takes precedence and cancel the closing note.
|
||||
|
||||
[fn:17] With the exception of description lists. But you can allow it
|
||||
[fn:16] With the exception of description lists. But you can allow it
|
||||
by modifying ~org-list-automatic-rules~ accordingly.
|
||||
|
||||
[fn:17] For both =TIMESTAMP= and =TIMESTAMP_IA=: the word "first"
|
||||
refers to the first occurrence in the entry, not the earliest in time;
|
||||
the prefix =CLOCK:= at the beginning of a clock entry is considered a
|
||||
keyword in this context; and timestamps inside property drawers are
|
||||
ignored.
|
||||
|
||||
[fn:18] An age can be defined as a duration, using units defined in
|
||||
~org-duration-units~, e.g., =3d 1h=. If any value in the column is as
|
||||
such, the summary is also expressed as a duration.
|
||||
|
@ -22948,7 +23491,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-preview-latex-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).
|
||||
|
@ -23021,7 +23564,6 @@ values.
|
|||
,#+END_SRC
|
||||
#+end_example
|
||||
|
||||
|
||||
[fn:50] Org Indent mode also sets ~wrap-prefix~ correctly for
|
||||
indenting and wrapping long lines of headlines or text. This minor
|
||||
mode also handles Visual Line mode and directly applied settings
|
||||
|
|
312
etc/ORG-NEWS
312
etc/ORG-NEWS
|
@ -13,6 +13,103 @@ Please send Org bug reports to mailto:emacs-orgmode@gnu.org.
|
|||
|
||||
* Version 9.7 (not released yet)
|
||||
** Important announcements and breaking changes
|
||||
*** When ~org-link-file-path-type~ is a function, its argument is now a filename as it is read by ~org-insert-link~; not an absolute path
|
||||
|
||||
Previously, when ~org-link-file-path-type~ is set to a function, the
|
||||
function argument was the filename from the link expanded via
|
||||
~expand-file-name~. Now, a bare filename is passed to the function.
|
||||
|
||||
*** Org export backends can now disable citation processors
|
||||
|
||||
A new global export option ~:with-cite-processors~, when set to nil,
|
||||
disables citation processors completely. This option is available to
|
||||
export backends via ~:options-alist~ when defining the backend.
|
||||
|
||||
The backends disabling citation processors must take care about
|
||||
exporting citation objects and =print_bibliography= keywords via
|
||||
transcoders.
|
||||
|
||||
Users can disable citations processors by customizing new
|
||||
~org-export-process-citations~ option.
|
||||
|
||||
*** =ox-org= disables citation processors by default
|
||||
|
||||
Previously, when exporting to Org, all the citations and
|
||||
=print_bibliography= keywords, were transformed according to the
|
||||
chosen citation processor.
|
||||
|
||||
This is no loner the case. All the citation-related markup is now
|
||||
exported as is.
|
||||
|
||||
The previous behavior can be reverted by setting new custom option
|
||||
~org-org-with-cite-processors~.
|
||||
|
||||
*** =ox-org= now exports special table rows by default
|
||||
|
||||
Previously, when exporting to Org, special table rows (for example,
|
||||
width cookies) were not exported. Now, they are exported by default.
|
||||
|
||||
You can customize new option ~org-org-with-special-rows~ to fall back to previous behavior.
|
||||
|
||||
*** Org babel backends are now expected to define an additional API function ~org-babel-session-buffer:<lang>~
|
||||
|
||||
Org babel now uses session buffer (if it exists) to retrieve
|
||||
~default-directory~ environment during src block evaluation.
|
||||
|
||||
By default, buffer named like session is checked. All the backends
|
||||
that create sessions inside buffers named differently should provide a
|
||||
function ~org-babel-session-buffer:<lang>~. The function must accept
|
||||
two arguments - session name and info list (as returned by
|
||||
~org-babel-get-src-block-info~); and return the session buffer name.
|
||||
|
||||
*** ~org-insert-subheading~ no longer inserts a sub-heading above current when point is at the beginning of line
|
||||
|
||||
Previously, calling ~org-insert-subheading~ on
|
||||
|
||||
: * Heading 1
|
||||
: <point>* Heading 2
|
||||
|
||||
yielded
|
||||
|
||||
: * Heading 1
|
||||
: ** <point>
|
||||
: * Heading 2
|
||||
|
||||
This is no longer the case. The sub-heading is always created below
|
||||
current heading (prefix arguments have the same meaning as in
|
||||
~org-insert-heading~):
|
||||
|
||||
: * Heading 1
|
||||
: * Heading 2
|
||||
: ** <point>
|
||||
|
||||
*** Org mode now fontifies whole table lines (including newline) according to ~org-table~ face
|
||||
|
||||
Previously, leading indentation and trailing newline in table rows
|
||||
were not fontified using ~org-table~ face. ~default~ face was used instead.
|
||||
This made it impossible to scale line height when ~org-table~ face has
|
||||
smaller height than default (Emacs calculates line height using the tallest face).
|
||||
|
||||
Now, new ~org-table-row~ face is used on the whole table row lines,
|
||||
including indentation and the final newline. This face, by default,
|
||||
inherits from ~org-table~ face.
|
||||
|
||||
If the new behavior is not desired, ~org-table-row~ face can be
|
||||
changed to inherit from ~default~ face.
|
||||
|
||||
~org-table~ takes precedence over ~org-table-row~ for the parts of
|
||||
table rows without indentation and newline.
|
||||
|
||||
*** =ox-latex=: ~org-latex-line-break-safe~ is deprecated
|
||||
|
||||
~org-latex-line-break-safe~ constant was previously introduced to deal
|
||||
with edge cases when LaTeX interprets [...] as LaTeX command
|
||||
argument. However, it caused a number of other issues and proved
|
||||
itself not to be as "safe" as it supposed to be.
|
||||
|
||||
We now use a Pandoc's approach to deal with the same problem,
|
||||
utilizing ={[}= to escape =[...]= instances where needed.
|
||||
|
||||
*** ob-python now sets ~python-shell-buffer-name~ in Org edit buffers
|
||||
|
||||
When editing a Python src block, the editing buffer is now associated
|
||||
|
@ -396,6 +493,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
|
||||
|
||||
|
@ -442,6 +690,62 @@ The change is breaking when ~org-use-property-inheritance~ is set to ~t~.
|
|||
|
||||
The =TEST= parameter is better served by Emacs debugging tools.
|
||||
** New and changed options
|
||||
*** New option ~org-export-process-citations~
|
||||
|
||||
The new option controls whether to use citation processors to process
|
||||
citations.
|
||||
|
||||
*** New option ~org-org-with-cite-processors~
|
||||
|
||||
The new option controls whether to use citation processors to process
|
||||
citations when exporting to Org.
|
||||
|
||||
*** New option ~org-org-with-special-rows~
|
||||
|
||||
The new options controls whether to export special table rows in
|
||||
Org-Org (=ox-org=) export. The default value is ~t~.
|
||||
|
||||
*** New option ~org-babel-comint-fallback-regexp-threshold~
|
||||
|
||||
Org babel is often using Emacs' interactive REPL feature to implement
|
||||
:session functionality in code blocks. However, Emacs' REPLs use
|
||||
heuristics to detect which lines in the REPL buffer correspond to
|
||||
output and which lines are user prompts.
|
||||
|
||||
Normally, Org babel changes the default prompt to something unique. It
|
||||
avoids incorrect detection of code block output.
|
||||
|
||||
Sometimes, the Org-configured prompt is changed manually by users or
|
||||
when running a sub-REPL (for example, when running ssh/python
|
||||
interpreter inside shell).
|
||||
|
||||
The new option controls Org mode's heuristics for catching
|
||||
user-changed prompt in interactive Org babel sessions. When Org mode
|
||||
cannot find REPL's prompt for more than
|
||||
~org-babel-comint-fallback-regexp-threshold~ seconds, imprecise
|
||||
generic prompt is tried to detect whether the code block output has
|
||||
arrived.
|
||||
|
||||
Users who often work with altering REPL prompts may consider reducing
|
||||
the default 5 second value of the new option.
|
||||
|
||||
*** ~repeated-after-deadline~ value of ~org-agenda-skip-scheduled-repeats-after-deadline~ is moved to a new customization
|
||||
|
||||
A new custom option ~org-agenda-skip-scheduled-repeats-after-deadline~
|
||||
is introduced in place of ~repeated-after-deadline~ value of
|
||||
~org-agenda-skip-scheduled-repeats-after-deadline~.
|
||||
|
||||
Introducing a new option allow more control over agenda display and
|
||||
resolves a confusion about the meaning of ~repeated-after-deadline~.
|
||||
~repeated-after-deadline~ has nothing to do with /showing/ deadline.
|
||||
It just prevents agenda display repeated scheduled entries past
|
||||
deadline. The following example illustrates the meaning:
|
||||
|
||||
: * TODO Do me every day before Jan, 12th (included)
|
||||
: SCHEDULED: <2024-01-03 Wed +1d> DEADLINE: <2024-01-05 Fri>
|
||||
|
||||
The old customization will continue to work, ensuring backwards compatibility.
|
||||
|
||||
*** New custom setting ~org-icalendar-ttl~ for the ~ox-icalendar~ backend
|
||||
|
||||
The option ~org-icalendar-ttl~ allows to advise a subscriber to the
|
||||
|
@ -890,6 +1194,14 @@ Completion is enabled for links to man pages added using ~org-insert-link~:
|
|||
=C-c C-l man RET emacscl TAB= to get =emacsclient=. Of course, the ~ol-man~
|
||||
library should be loaded first.
|
||||
|
||||
*** ~org-footnote-new~ can be configured to create anonymous footnotes
|
||||
|
||||
When ~org-footnote-auto-label~ is set to ~'anonymous~, create
|
||||
anonymous footnotes automatically with ~org-footnote-new~.
|
||||
|
||||
The same can be done via startup options:
|
||||
: #+STARTUP: fnanon
|
||||
|
||||
** New functions and changes in function arguments
|
||||
*** New API functions to store data within ~org-element-cache~
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
.NOTPARALLEL: # always run this make serially
|
||||
.SUFFIXES: # we don't need default suffix rules
|
||||
ifeq ($(MAKELEVEL), 0)
|
||||
$(error This make needs to be started as a sub-make from the toplevel directory.)
|
||||
|
@ -10,7 +9,8 @@ LISPA := $(LISPV) $(LISPI)
|
|||
LISPB := $(LISPA:%el=%elc) org-install.elc
|
||||
LISPF := $(filter-out $(LISPA),$(sort $(wildcard *.el)))
|
||||
LISPC := $(filter-out $(LISPB) $(LISPN:%el=%elc),$(LISPF:%el=%elc))
|
||||
_ORGCM_ := dirall single source slint1 slint2
|
||||
LISPN := $(filter-out $(LISPB) $(LISPN:%el=%eln),$(LISPF:%el=%eln))
|
||||
_ORGCM_ := dirall single native source slint1 slint2
|
||||
-include local.mk
|
||||
|
||||
.PHONY: all compile compile-dirty \
|
||||
|
@ -19,7 +19,7 @@ _ORGCM_ := dirall single source slint1 slint2
|
|||
install clean cleanauto cleanall cleanelc clean-install
|
||||
|
||||
# do not clean here, done in toplevel make
|
||||
all compile compile-dirty:: autoloads
|
||||
all compile compile-dirty:: | autoloads
|
||||
ifeq ($(filter-out $(_ORGCM_),$(ORGCM)),)
|
||||
$(MAKE) compile-$(ORGCM)
|
||||
else
|
||||
|
@ -27,10 +27,11 @@ else
|
|||
endif
|
||||
|
||||
compile-dirall: dirall
|
||||
compile-single: single $(LISPC)
|
||||
compile-source: source dirall
|
||||
compile-slint1: dirall slint1
|
||||
compile-slint2: source dirall slint1
|
||||
compile-single: $(LISPC) | single
|
||||
compile-native: $(LISPN) | native
|
||||
compile-source: | source dirall
|
||||
compile-slint1: | dirall slint1
|
||||
compile-slint2: | source dirall slint1
|
||||
|
||||
# internal
|
||||
dirall:
|
||||
|
@ -38,6 +39,8 @@ dirall:
|
|||
@$(ELCDIR)
|
||||
single:
|
||||
@$(info ==================== $@ ====================)
|
||||
native:
|
||||
@$(info ==================== $@ ====================)
|
||||
source: cleanelc
|
||||
@$(info ==================== $@ ====================)
|
||||
@$(foreach elc,$(LISPC),$(MAKE) $(elc) && $(RM) $(elc);)
|
||||
|
@ -49,6 +52,10 @@ slint1:
|
|||
@$(info Compiling single $(abspath $<)...)
|
||||
-@$(ELC) $<
|
||||
|
||||
%.eln: %.el
|
||||
@$(info Native compiling single $(abspath $<)...)
|
||||
-@$(ELN) $<
|
||||
|
||||
autoloads: cleanauto $(LISPI) $(LISPV)
|
||||
|
||||
$(LISPV): $(LISPF)
|
||||
|
|
|
@ -64,6 +64,7 @@
|
|||
(colormodel . :any)
|
||||
(useDingbats . :any)
|
||||
(horizontal . :any)
|
||||
(async . ((yes no)))
|
||||
(results . ((file list vector table scalar verbatim)
|
||||
(raw html latex org code pp drawer)
|
||||
(replace silent none append prepend)
|
||||
|
|
|
@ -237,7 +237,9 @@ or set the `:backend' header argument"))))
|
|||
"clojure" (format "clojure -A%s" alias)
|
||||
cmd0)
|
||||
cmd0)))
|
||||
(setq comint-prompt-regexp inf-clojure-comint-prompt-regexp)
|
||||
(setq
|
||||
org-babel-comint-prompt-regexp-old comint-prompt-regexp
|
||||
comint-prompt-regexp inf-clojure-comint-prompt-regexp)
|
||||
(funcall-interactively #'inf-clojure cmd)
|
||||
(goto-char (point-max))))
|
||||
(sit-for 1))
|
||||
|
|
|
@ -58,6 +58,22 @@ executed inside the protection of `save-excursion' and
|
|||
(let ((comint-input-filter (lambda (_input) nil)))
|
||||
,@body))))))
|
||||
|
||||
(defvar-local org-babel-comint-prompt-regexp-old nil
|
||||
"Fallback regexp used to detect prompt.")
|
||||
|
||||
(defcustom org-babel-comint-fallback-regexp-threshold 5.0
|
||||
"Waiting time until trying to use fallback regexp to detect prompt.
|
||||
This is useful when prompt unexpectedly changes."
|
||||
:type 'float
|
||||
:group 'org-babel)
|
||||
|
||||
(defun org-babel-comint--set-fallback-prompt ()
|
||||
"Swap `comint-prompt-regexp' and `org-babel-comint-prompt-regexp-old'."
|
||||
(when org-babel-comint-prompt-regexp-old
|
||||
(let ((tmp comint-prompt-regexp))
|
||||
(setq comint-prompt-regexp org-babel-comint-prompt-regexp-old
|
||||
org-babel-comint-prompt-regexp-old tmp))))
|
||||
|
||||
(defmacro org-babel-comint-with-output (meta &rest body)
|
||||
"Evaluate BODY in BUFFER and return process output.
|
||||
Will wait until EOE-INDICATOR appears in the output, then return
|
||||
|
@ -96,14 +112,29 @@ or user `keyboard-quit' during execution of body."
|
|||
;; pass FULL-BODY to process
|
||||
,@body
|
||||
;; wait for end-of-evaluation indicator
|
||||
(while (progn
|
||||
(goto-char comint-last-input-end)
|
||||
(not (save-excursion
|
||||
(and (re-search-forward
|
||||
(regexp-quote ,eoe-indicator) nil t)
|
||||
(re-search-forward
|
||||
comint-prompt-regexp nil t)))))
|
||||
(accept-process-output (get-buffer-process (current-buffer))))
|
||||
(let ((start-time (current-time)))
|
||||
(while (progn
|
||||
(goto-char comint-last-input-end)
|
||||
(not (save-excursion
|
||||
(and (re-search-forward
|
||||
(regexp-quote ,eoe-indicator) nil t)
|
||||
(re-search-forward
|
||||
comint-prompt-regexp nil t)))))
|
||||
(accept-process-output
|
||||
(get-buffer-process (current-buffer))
|
||||
org-babel-comint-fallback-regexp-threshold)
|
||||
(when (and org-babel-comint-prompt-regexp-old
|
||||
(> (float-time (time-since start-time))
|
||||
org-babel-comint-fallback-regexp-threshold)
|
||||
(progn
|
||||
(goto-char comint-last-input-end)
|
||||
(save-excursion
|
||||
(and
|
||||
(re-search-forward
|
||||
(regexp-quote ,eoe-indicator) nil t)
|
||||
(re-search-forward
|
||||
org-babel-comint-prompt-regexp-old nil t)))))
|
||||
(org-babel-comint--set-fallback-prompt))))
|
||||
;; replace cut dangling text
|
||||
(goto-char (process-mark (get-buffer-process (current-buffer))))
|
||||
(insert dangling-text)
|
||||
|
@ -148,11 +179,23 @@ The input will not be echoed."
|
|||
Note: this is only safe when waiting for the result of a single
|
||||
statement (not large blocks of code)."
|
||||
(org-babel-comint-in-buffer buffer
|
||||
(while (progn
|
||||
(goto-char comint-last-input-end)
|
||||
(not (and (re-search-forward comint-prompt-regexp nil t)
|
||||
(goto-char (match-beginning 0)))))
|
||||
(accept-process-output (get-buffer-process buffer)))))
|
||||
(let ((start-time (current-time)))
|
||||
(while (progn
|
||||
(goto-char comint-last-input-end)
|
||||
(not (and (re-search-forward comint-prompt-regexp nil t)
|
||||
(goto-char (match-beginning 0)))))
|
||||
(accept-process-output
|
||||
(get-buffer-process buffer)
|
||||
org-babel-comint-fallback-regexp-threshold)
|
||||
(when (and org-babel-comint-prompt-regexp-old
|
||||
(> (float-time (time-since start-time))
|
||||
org-babel-comint-fallback-regexp-threshold)
|
||||
(progn
|
||||
(goto-char comint-last-input-end)
|
||||
(save-excursion
|
||||
(re-search-forward
|
||||
org-babel-comint-prompt-regexp-old nil t))))
|
||||
(org-babel-comint--set-fallback-prompt))))))
|
||||
|
||||
(defun org-babel-comint-eval-invisibly-and-wait-for-file
|
||||
(buffer file string &optional period)
|
||||
|
@ -224,6 +267,8 @@ STRING contains the output originally inserted into the comint buffer."
|
|||
(file-callback org-babel-comint-async-file-callback)
|
||||
(combined-string (concat org-babel-comint-async-dangling string))
|
||||
(new-dangling combined-string)
|
||||
;; Assumes comint filter called with session buffer current
|
||||
(session-dir default-directory)
|
||||
;; list of UUID's matched by `org-babel-comint-async-indicator'
|
||||
uuid-list)
|
||||
(with-temp-buffer
|
||||
|
@ -248,7 +293,8 @@ STRING contains the output originally inserted into the comint buffer."
|
|||
(let* ((info (org-babel-get-src-block-info))
|
||||
(params (nth 2 info))
|
||||
(result-params
|
||||
(cdr (assq :result-params params))))
|
||||
(cdr (assq :result-params params)))
|
||||
(default-directory session-dir))
|
||||
(org-babel-insert-result
|
||||
(funcall file-callback
|
||||
(nth
|
||||
|
@ -291,7 +337,8 @@ STRING contains the output originally inserted into the comint buffer."
|
|||
(let* ((info (org-babel-get-src-block-info))
|
||||
(params (nth 2 info))
|
||||
(result-params
|
||||
(cdr (assq :result-params params))))
|
||||
(cdr (assq :result-params params)))
|
||||
(default-directory session-dir))
|
||||
(org-babel-insert-result
|
||||
res-str result-params info))
|
||||
t))))
|
||||
|
|
|
@ -767,8 +767,30 @@ When `:file-desc' is missing, return nil."
|
|||
(`(:file-desc) result)
|
||||
(`(:file-desc . ,(and (pred stringp) val)) val)))
|
||||
|
||||
(defvar *this*) ; Dynamically bound in `org-babel-execute-src-block'
|
||||
; and `org-babel-read'
|
||||
(defvar *this*)
|
||||
;; Dynamically bound in `org-babel-execute-src-block'
|
||||
;; and `org-babel-read'
|
||||
|
||||
(defun org-babel-session-buffer (&optional info)
|
||||
"Return buffer name for session associated with current code block.
|
||||
Return nil when no such live buffer with process exists.
|
||||
When INFO is non-nil, it should be a list returned by
|
||||
`org-babel-get-src-block-info'.
|
||||
This function uses org-babel-session-buffer:<lang> function to
|
||||
retrieve backend-specific session buffer name."
|
||||
(declare-function org-babel-comint-buffer-livep "ob-comint" (buffer))
|
||||
(when-let* ((info (or info (org-babel-get-src-block-info 'no-eval)))
|
||||
(lang (nth 0 info))
|
||||
(session (cdr (assq :session (nth 2 info))))
|
||||
(cmd (intern (concat "org-babel-session-buffer:" lang)))
|
||||
(buffer-name
|
||||
(if (fboundp cmd)
|
||||
(funcall cmd session info)
|
||||
;; Use session name as buffer name by default.
|
||||
session)))
|
||||
(require 'ob-comint)
|
||||
(when (org-babel-comint-buffer-livep buffer-name)
|
||||
buffer-name)))
|
||||
|
||||
;;;###autoload
|
||||
(defun org-babel-execute-src-block (&optional arg info params executor-type)
|
||||
|
@ -840,14 +862,16 @@ guess will be made."
|
|||
(dir (cdr (assq :dir params)))
|
||||
(mkdirp (cdr (assq :mkdirp params)))
|
||||
(default-directory
|
||||
(cond
|
||||
((not dir) default-directory)
|
||||
((member mkdirp '("no" "nil" nil))
|
||||
(file-name-as-directory (expand-file-name dir)))
|
||||
(t
|
||||
(let ((d (file-name-as-directory (expand-file-name dir))))
|
||||
(make-directory d 'parents)
|
||||
d))))
|
||||
(cond
|
||||
((not dir) default-directory)
|
||||
((when-let ((session (org-babel-session-buffer info)))
|
||||
(buffer-local-value 'default-directory (get-buffer session))))
|
||||
((member mkdirp '("no" "nil" nil))
|
||||
(file-name-as-directory (expand-file-name dir)))
|
||||
(t
|
||||
(let ((d (file-name-as-directory (expand-file-name dir))))
|
||||
(make-directory d 'parents)
|
||||
d))))
|
||||
(cmd (intern (concat "org-babel-execute:" lang)))
|
||||
result exec-start-time)
|
||||
(unless (fboundp cmd)
|
||||
|
|
|
@ -152,8 +152,10 @@ This function should only be called by `org-babel-execute:haskell'."
|
|||
(org-require-package 'inf-haskell "haskell-mode")
|
||||
(add-hook 'inferior-haskell-hook
|
||||
(lambda ()
|
||||
(setq-local comint-prompt-regexp
|
||||
(concat haskell-prompt-regexp "\\|^λ?> "))))
|
||||
(setq-local
|
||||
org-babel-comint-prompt-regexp-old comint-prompt-regexp
|
||||
comint-prompt-regexp
|
||||
(concat haskell-prompt-regexp "\\|^λ?> "))))
|
||||
(org-babel-haskell-with-session session params
|
||||
(cl-labels
|
||||
((send-txt-to-ghci (txt)
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
(require 'ob)
|
||||
(require 'org-macs)
|
||||
|
||||
(declare-function org-create-formula-image "org" (string tofile options buffer &optional type))
|
||||
(declare-function org-latex-preview-create-image "org-latex-preview" (string tofile options buffer &optional type))
|
||||
(declare-function org-latex-compile "ox-latex" (texfile &optional snippet))
|
||||
(declare-function org-latex-guess-inputenc "ox-latex" (header))
|
||||
(declare-function org-splice-latex-header "org" (tpl def-pkg pkg snippets-p &optional extra))
|
||||
|
@ -48,10 +48,10 @@
|
|||
(defvar org-babel-tangle-lang-exts)
|
||||
(add-to-list 'org-babel-tangle-lang-exts '("latex" . "tex"))
|
||||
|
||||
(defvar org-format-latex-header) ; From org.el
|
||||
(defvar org-format-latex-options) ; From org.el
|
||||
(defvar org-latex-default-packages-alist) ; From org.el
|
||||
(defvar org-latex-packages-alist) ; From org.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"))
|
||||
|
@ -167,11 +167,11 @@ This function is called by `org-babel-execute-src-block'."
|
|||
(append (cdr (assq :packages params)) org-latex-packages-alist)))
|
||||
(cond
|
||||
((and (string-suffix-p ".png" out-file) (not imagemagick))
|
||||
(let ((org-format-latex-header
|
||||
(concat org-format-latex-header "\n"
|
||||
(let ((org-latex-preview-header
|
||||
(concat org-latex-preview-header "\n"
|
||||
(mapconcat #'identity headers "\n"))))
|
||||
(org-create-formula-image
|
||||
body out-file org-format-latex-options in-buffer)))
|
||||
(org-latex-preview-create-image
|
||||
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)
|
||||
|
@ -238,7 +238,7 @@ This function is called by `org-babel-execute-src-block'."
|
|||
(insert
|
||||
(org-latex-guess-inputenc
|
||||
(org-splice-latex-header
|
||||
org-format-latex-header
|
||||
org-latex-preview-header
|
||||
(delq
|
||||
nil
|
||||
(mapcar
|
||||
|
|
|
@ -184,6 +184,11 @@ Emacs-lisp table, otherwise return the results as a string."
|
|||
name
|
||||
(format "*%s*" name))))
|
||||
|
||||
(defun org-babel-session-buffer:lua (session &optional _)
|
||||
"Return session buffer name for SESSION."
|
||||
(or (org-babel-lua-session-buffer session)
|
||||
(org-babel-lua-with-earmuffs session)))
|
||||
|
||||
(defun org-babel-lua-without-earmuffs (session)
|
||||
"Remove stars around *SESSION*, leaving SESSION."
|
||||
(let ((name (if (stringp session) session (format "%s" session))))
|
||||
|
|
|
@ -43,7 +43,8 @@
|
|||
|
||||
(defconst org-babel-header-args:python
|
||||
'((return . :any)
|
||||
(python . :any))
|
||||
(python . :any)
|
||||
(async . ((yes no))))
|
||||
"Python-specific header arguments.")
|
||||
|
||||
(defcustom org-babel-python-command 'auto
|
||||
|
@ -259,6 +260,11 @@ results as a string."
|
|||
(substring name 1 (- (length name) 1))
|
||||
name)))
|
||||
|
||||
(defun org-babel-session-buffer:python (session &optional _)
|
||||
"Return session buffer name for SESSION."
|
||||
(or (org-babel-python-session-buffer session)
|
||||
(org-babel-python-with-earmuffs session)))
|
||||
|
||||
(defun org-babel-python--python-util-comint-end-of-output-p ()
|
||||
"Return non-nil if the last prompt matches input prompt.
|
||||
Backport of `python-util-comint-end-of-output-p' to emacs28. To
|
||||
|
@ -301,8 +307,7 @@ already been configured as such, do nothing. Return the
|
|||
initialized session."
|
||||
(save-window-excursion
|
||||
(let* ((session (if session (intern session) :default))
|
||||
(py-buffer (or (org-babel-python-session-buffer session)
|
||||
(org-babel-python-with-earmuffs session)))
|
||||
(py-buffer (org-babel-session-buffer:python session))
|
||||
(python-shell-buffer-name
|
||||
(org-babel-python-without-earmuffs py-buffer))
|
||||
(existing-session-p (comint-check-proc py-buffer))
|
||||
|
|
|
@ -191,7 +191,9 @@ Session settings (`:ruby' header arg value) are taken from PARAMS."
|
|||
;; uniquely by regexp.
|
||||
(when new-session?
|
||||
(with-current-buffer session-buffer
|
||||
(setq-local comint-prompt-regexp (concat "^" org-babel-ruby-prompt))
|
||||
(setq-local
|
||||
org-babel-comint-prompt-regexp-old comint-prompt-regexp
|
||||
comint-prompt-regexp (concat "^" org-babel-ruby-prompt))
|
||||
(insert org-babel-ruby-define-prompt ";")
|
||||
(insert "_org_prompt_mode=conf.prompt_mode;conf.prompt_mode=:CUSTOM;")
|
||||
(insert "conf.echo=false\n")
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
(defvar geiser-debug-jump-to-debug-p) ; Defined in geiser-debug.el
|
||||
(defvar geiser-repl-use-other-window) ; Defined in geiser-repl.el
|
||||
(defvar geiser-repl-window-allow-split) ; Defined in geiser-repl.el
|
||||
|
||||
(declare-function geiser-connect "ext:geiser-repl" (impl &optional host port))
|
||||
(declare-function run-geiser "ext:geiser-repl" (impl))
|
||||
(declare-function geiser "ext:geiser-repl" (impl))
|
||||
(declare-function geiser-mode "ext:geiser-mode" ())
|
||||
|
@ -78,6 +78,9 @@
|
|||
|
||||
(defvar org-babel-default-header-args:scheme '()
|
||||
"Default header arguments for scheme code blocks.")
|
||||
(defconst org-babel-header-args:scheme '((host . :any)
|
||||
(port . :any))
|
||||
"Header arguments supported in Scheme.")
|
||||
|
||||
(defun org-babel-scheme-expand-header-arg-vars (vars)
|
||||
"Expand :var header arguments given as VARS."
|
||||
|
@ -121,13 +124,17 @@
|
|||
(with-current-buffer (set-buffer buffer)
|
||||
geiser-impl--implementation))
|
||||
|
||||
(defun org-babel-scheme-get-repl (impl name)
|
||||
"Switch to a scheme REPL, creating it if it doesn't exist."
|
||||
(defun org-babel-scheme-get-repl (impl name &optional host port)
|
||||
"Switch to a Scheme REPL, creating it if it doesn't exist.
|
||||
|
||||
If the variables HOST and PORT are set, connect to the running Scheme REPL."
|
||||
(let ((buffer (org-babel-scheme-get-session-buffer name)))
|
||||
(or buffer
|
||||
(progn
|
||||
(if (fboundp 'geiser)
|
||||
(geiser impl)
|
||||
(if (and host port)
|
||||
(geiser-connect impl host port)
|
||||
(geiser impl))
|
||||
;; Obsolete since Geiser 0.26.
|
||||
(run-geiser impl))
|
||||
(when name
|
||||
|
@ -164,7 +171,7 @@ org-babel-scheme-execute-with-geiser will use a temporary session."
|
|||
,@body
|
||||
(current-message))))
|
||||
|
||||
(defun org-babel-scheme-execute-with-geiser (code output impl repl)
|
||||
(defun org-babel-scheme-execute-with-geiser (code output impl repl &optional host port)
|
||||
"Execute code in specified REPL.
|
||||
If the REPL doesn't exist, create it using the given scheme
|
||||
implementation.
|
||||
|
@ -180,7 +187,7 @@ is true; otherwise returns the last value."
|
|||
(let ((geiser-repl-window-allow-split nil)
|
||||
(geiser-repl-use-other-window nil))
|
||||
(let ((repl-buffer (save-current-buffer
|
||||
(org-babel-scheme-get-repl impl repl))))
|
||||
(org-babel-scheme-get-repl impl repl host port))))
|
||||
(when (not (eq impl (org-babel-scheme-get-buffer-impl
|
||||
(current-buffer))))
|
||||
(message "Implementation mismatch: %s (%s) %s (%s)" impl (symbolp impl)
|
||||
|
@ -244,6 +251,8 @@ This function is called by `org-babel-execute-src-block'."
|
|||
geiser-scheme-implementation
|
||||
geiser-default-implementation
|
||||
(car geiser-active-implementations)))
|
||||
(host (cdr (assq :host params)))
|
||||
(port (cdr (assq :port params)))
|
||||
(session (org-babel-scheme-make-session-name
|
||||
source-buffer-name (cdr (assq :session params)) impl))
|
||||
(full-body (org-babel-expand-body:scheme body params))
|
||||
|
@ -253,7 +262,9 @@ This function is called by `org-babel-execute-src-block'."
|
|||
full-body ; code
|
||||
(string= result-type "output") ; output?
|
||||
impl ; implementation
|
||||
(and (not (string= session "none")) session)))) ; session
|
||||
(and (not (string= session "none")) session) ; session
|
||||
host ; REPL host
|
||||
port))) ; REPL port
|
||||
(let ((table
|
||||
(org-babel-reassemble-table
|
||||
result
|
||||
|
|
|
@ -45,6 +45,11 @@
|
|||
(declare-function orgtbl-to-generic "org-table" (table params))
|
||||
|
||||
(defvar org-babel-default-header-args:shell '())
|
||||
|
||||
(defconst org-babel-header-args:shell
|
||||
'((async . ((yes no))))
|
||||
"Shell-specific header arguments.")
|
||||
|
||||
(defvar org-babel-shell-names)
|
||||
|
||||
(defconst org-babel-shell-set-prompt-commands
|
||||
|
@ -86,6 +91,9 @@ variables."
|
|||
name))
|
||||
(funcall (if (fboundp 'defvar-1) #'defvar-1 #'set) ;Emacs-29
|
||||
(intern (concat "org-babel-default-header-args:" name))
|
||||
nil)
|
||||
(funcall (if (fboundp 'defvar-1) #'defvar-1 #'set) ;Emacs-29
|
||||
(intern (concat "org-babel-header-args:" name))
|
||||
nil)))
|
||||
|
||||
(defcustom org-babel-shell-names
|
||||
|
@ -265,9 +273,11 @@ var of the same value."
|
|||
org-babel-shell-set-prompt-commands))
|
||||
(alist-get t org-babel-shell-set-prompt-commands))
|
||||
org-babel-sh-prompt))
|
||||
(setq-local comint-prompt-regexp
|
||||
(concat "^" (regexp-quote org-babel-sh-prompt)
|
||||
" *"))
|
||||
(setq-local
|
||||
org-babel-comint-prompt-regexp-old comint-prompt-regexp
|
||||
comint-prompt-regexp
|
||||
(concat "^" (regexp-quote org-babel-sh-prompt)
|
||||
" *"))
|
||||
;; Needed for Emacs 23 since the marker is initially
|
||||
;; undefined and the filter functions try to use it without
|
||||
;; checking.
|
||||
|
|
|
@ -376,61 +376,47 @@ INFO is the export state, as a property list."
|
|||
(other
|
||||
(user-error "Invalid entry %S in `org-cite-biblatex-styles'" other))))))
|
||||
|
||||
(defun org-cite-biblatex-prepare-preamble (output _keys files style &rest _)
|
||||
"Prepare document preamble for \"biblatex\" usage.
|
||||
(defun org-cite-biblatex--generate-latex-usepackage (info)
|
||||
"Ensure that the biblatex package is loaded.
|
||||
This is performed by extracting relevant information from the
|
||||
INFO export plist, and modifying any existing
|
||||
\\usepackage{biblatex} statement in the LaTeX header."
|
||||
(let ((style (org-cite-bibliography-style info))
|
||||
(usepackage-rx (rx "\\usepackage"
|
||||
(opt (group "[" (*? anything) "]"))
|
||||
"{biblatex}")))
|
||||
(concat
|
||||
(if (string-match usepackage-rx (plist-get info :latex-full-header))
|
||||
;; "biblatex" package loaded, but with none (or different) options.
|
||||
;; Replace with style-including command.
|
||||
(plist-put info :latex-full-header
|
||||
(replace-match
|
||||
(format "\\usepackage%s{biblatex}"
|
||||
(save-match-data
|
||||
(org-cite-biblatex--package-options nil style)))
|
||||
t t
|
||||
(plist-get info :latex-full-header)))
|
||||
;; No "biblatex" package loaded. Insert "usepackage" command
|
||||
;; with appropriate options, including style.
|
||||
(format "\\usepackage%s{biblatex}\n"
|
||||
(org-cite-biblatex--package-options
|
||||
org-cite-biblatex-options style))))))
|
||||
|
||||
OUTPUT is the final output of the export process. FILES is the list of file
|
||||
names used as the bibliography.
|
||||
|
||||
This function ensures \"biblatex\" package is required. It also adds resources
|
||||
to the document, and set styles."
|
||||
(with-temp-buffer
|
||||
(save-excursion (insert output))
|
||||
(when (search-forward "\\begin{document}" nil t)
|
||||
;; Ensure there is a \usepackage{biblatex} somewhere or add one.
|
||||
;; Then set options.
|
||||
(goto-char (match-beginning 0))
|
||||
(let ((re (rx "\\usepackage"
|
||||
(opt (group "[" (*? anything) "]"))
|
||||
"{biblatex}")))
|
||||
(cond
|
||||
;; No "biblatex" package loaded. Insert "usepackage" command
|
||||
;; with appropriate options, including style.
|
||||
((not (re-search-backward re nil t))
|
||||
(save-excursion
|
||||
(insert
|
||||
(format "\\usepackage%s{biblatex}\n"
|
||||
(org-cite-biblatex--package-options
|
||||
org-cite-biblatex-options style)))))
|
||||
;; "biblatex" package loaded, but without any option.
|
||||
;; Include style only.
|
||||
((not (match-beginning 1))
|
||||
(search-forward "{" nil t)
|
||||
(insert (org-cite-biblatex--package-options nil style)))
|
||||
;; "biblatex" package loaded with some options set. Override
|
||||
;; style-related options with ours.
|
||||
(t
|
||||
(replace-match
|
||||
(save-match-data
|
||||
(org-cite-biblatex--package-options (match-string 1) style))
|
||||
nil nil nil 1))))
|
||||
;; Insert resources below.
|
||||
(forward-line)
|
||||
(insert (mapconcat (lambda (f)
|
||||
(format "\\addbibresource%s{%s}"
|
||||
(if (org-url-p f) "[location=remote]" "")
|
||||
f))
|
||||
files
|
||||
"\n")
|
||||
"\n"))
|
||||
(buffer-string)))
|
||||
(defun org-cite-biblatex--generate-latex-bibresources (info)
|
||||
"From INFO generate LaTeX that loads the relevant bibliography resource files."
|
||||
(let ((files (plist-get info :bibliography)))
|
||||
(mapconcat (lambda (f)
|
||||
(format "\\addbibresource%s{%s}"
|
||||
(if (org-url-p f) "[location=remote]" "")
|
||||
f))
|
||||
files
|
||||
"\n")))
|
||||
|
||||
|
||||
;;; Register `biblatex' processor
|
||||
(org-cite-register-processor 'biblatex
|
||||
:export-bibliography #'org-cite-biblatex-export-bibliography
|
||||
:export-citation #'org-cite-biblatex-export-citation
|
||||
:export-finalizer #'org-cite-biblatex-prepare-preamble
|
||||
:cite-styles #'org-cite-biblatex-list-styles)
|
||||
|
||||
(provide 'oc-biblatex)
|
||||
|
|
|
@ -847,27 +847,11 @@ INFO is the export state, as a property list."
|
|||
;; process.
|
||||
(org-cite-parse-elements output)))))
|
||||
|
||||
(defun org-cite-csl-finalizer (output _keys _files _style _backend info)
|
||||
"Add \"hanging\" package if missing from LaTeX output.
|
||||
OUTPUT is the export document, as a string. INFO is the export state, as a
|
||||
property list."
|
||||
(org-cite-csl--barf-without-citeproc)
|
||||
(if (not (eq 'org-latex (org-cite-csl--output-format info)))
|
||||
output
|
||||
(with-temp-buffer
|
||||
(save-excursion (insert output))
|
||||
(when (search-forward "\\begin{document}" nil t)
|
||||
(goto-char (match-beginning 0))
|
||||
;; Insert the CSL-specific parts of the LaTeX preamble.
|
||||
(insert (org-cite-csl--generate-latex-preamble info)))
|
||||
(buffer-string))))
|
||||
|
||||
|
||||
;;; Register `csl' processor
|
||||
(org-cite-register-processor 'csl
|
||||
:export-citation #'org-cite-csl-render-citation
|
||||
:export-bibliography #'org-cite-csl-render-bibliography
|
||||
:export-finalizer #'org-cite-csl-finalizer
|
||||
:cite-styles
|
||||
'((("author" "a") ("bare" "b") ("caps" "c") ("full" "f") ("bare-caps" "bc") ("caps-full" "cf") ("bare-caps-full" "bcf"))
|
||||
(("noauthor" "na") ("bare" "b") ("caps" "c") ("bare-caps" "bc"))
|
||||
|
|
|
@ -168,32 +168,25 @@ state, as a property list."
|
|||
(org-cite-natbib--build-optional-arguments citation info)
|
||||
(org-cite-natbib--build-arguments citation)))
|
||||
|
||||
(defun org-cite-natbib-use-package (output &rest _)
|
||||
"Ensure output requires \"natbib\" package.
|
||||
OUTPUT is the final output of the export process."
|
||||
(with-temp-buffer
|
||||
(save-excursion (insert output))
|
||||
(when (search-forward "\\begin{document}" nil t)
|
||||
;; Ensure there is a \usepackage{natbib} somewhere or add one.
|
||||
(goto-char (match-beginning 0))
|
||||
(let ((re (rx "\\usepackage" (opt "[" (*? nonl) "]") "{natbib}")))
|
||||
(unless (re-search-backward re nil t)
|
||||
(insert
|
||||
(format "\\usepackage%s{natbib}\n"
|
||||
(if (null org-cite-natbib-options)
|
||||
""
|
||||
(format "[%s]"
|
||||
(mapconcat #'symbol-name
|
||||
org-cite-natbib-options
|
||||
","))))))))
|
||||
(buffer-string)))
|
||||
(defun org-cite-natbib--generate-latex-preamble (info)
|
||||
"Ensure that the \"natbib\" package is loaded.
|
||||
INFO is a plist used as a communication channel."
|
||||
(and (not (string-match
|
||||
(rx "\\usepackage" (opt "[" (*? nonl) "]") "{natbib}")
|
||||
(plist-get info :latex-full-header)))
|
||||
(format "\\usepackage%s{natbib}\n"
|
||||
(if (null org-cite-natbib-options)
|
||||
""
|
||||
(format "[%s]"
|
||||
(mapconcat #'symbol-name
|
||||
org-cite-natbib-options
|
||||
","))))))
|
||||
|
||||
|
||||
;;; Register `natbib' processor
|
||||
(org-cite-register-processor 'natbib
|
||||
:export-bibliography #'org-cite-natbib-export-bibliography
|
||||
:export-citation #'org-cite-natbib-export-citation
|
||||
:export-finalizer #'org-cite-natbib-use-package
|
||||
:cite-styles
|
||||
'((("author" "a") ("caps" "a") ("full" "f"))
|
||||
(("noauthor" "na") ("bare" "b"))
|
||||
|
|
57
lisp/ol.el
57
lisp/ol.el
|
@ -246,7 +246,7 @@ adaptive Use relative path for files in the current directory and sub-
|
|||
directories of it. For other files, use an absolute path.
|
||||
|
||||
Alternatively, users may supply a custom function that takes the
|
||||
full filename as an argument and returns the path."
|
||||
filename in the link as an argument and returns the path."
|
||||
:group 'org-link
|
||||
:type '(choice
|
||||
(const relative)
|
||||
|
@ -368,14 +368,17 @@ another window."
|
|||
(const wl-other-frame)))))
|
||||
|
||||
(defcustom org-link-search-must-match-exact-headline 'query-to-create
|
||||
"Non-nil means internal fuzzy links can only match headlines.
|
||||
"Control fuzzy link behaviour when specific matches not found.
|
||||
|
||||
When nil, the fuzzy link may point to a target or a named
|
||||
construct in the document. When set to the special value
|
||||
`query-to-create', offer to create a new headline when none
|
||||
matched.
|
||||
When nil, if a fuzzy link does not match a more specific
|
||||
target (such as a heading, named block, target, or code ref),
|
||||
attempt a regular text search. When set to the special value
|
||||
`query-to-create', offer to create a new heading matching the
|
||||
link instead. Otherwise, signal an error rather than attempting
|
||||
a regular text search.
|
||||
|
||||
Spaces and statistics cookies are ignored during heading searches."
|
||||
This option only affects behaviour in Org buffers. Spaces and
|
||||
statistics cookies are ignored during heading searches."
|
||||
:group 'org-link-follow
|
||||
:version "24.1"
|
||||
:type '(choice
|
||||
|
@ -853,12 +856,12 @@ This should be called after the variable `org-link-parameters' has changed."
|
|||
org-link-plain-re
|
||||
(let* ((non-space-bracket "[^][ \t\n()<>]")
|
||||
(parenthesis
|
||||
`(seq "("
|
||||
`(seq (any "<([")
|
||||
(0+ (or (regex ,non-space-bracket)
|
||||
(seq "("
|
||||
(seq (any "<([")
|
||||
(0+ (regex ,non-space-bracket))
|
||||
")")))
|
||||
")")))
|
||||
(any "])>"))))
|
||||
(any "])>"))))
|
||||
;; Heuristics for an URL link inspired by
|
||||
;; https://daringfireball.net/2010/07/improved_regex_for_matching_urls
|
||||
(rx-to-string
|
||||
|
@ -1065,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'."
|
||||
|
@ -1079,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)
|
||||
|
@ -1911,9 +1930,8 @@ non-interactively, don't allow to edit the default description."
|
|||
(mapcar (lambda (x) (concat x ":")) all-prefixes)
|
||||
(mapcar #'car org-stored-links)
|
||||
;; Allow description completion. Avoid "nil" option
|
||||
;; in the case of `completing-read-default' and
|
||||
;; an error in `ido-completing-read' when some links
|
||||
;; have no description.
|
||||
;; in the case of `completing-read-default' when
|
||||
;; some links have no description.
|
||||
(delq nil (mapcar 'cadr org-stored-links)))
|
||||
nil nil nil
|
||||
'org-link--history
|
||||
|
@ -1977,8 +1995,7 @@ non-interactively, don't allow to edit the default description."
|
|||
((eq org-link-file-path-type 'relative)
|
||||
(setq path (file-relative-name path)))
|
||||
((functionp org-link-file-path-type)
|
||||
(setq path (funcall org-link-file-path-type
|
||||
(expand-file-name path))))
|
||||
(setq path (funcall org-link-file-path-type path)))
|
||||
(t
|
||||
(save-match-data
|
||||
(if (string-match (concat "^" (regexp-quote
|
||||
|
|
|
@ -894,17 +894,13 @@ the entry is scheduled today or was scheduled previously is not
|
|||
shown.
|
||||
|
||||
When set to the symbol `not-today', skip scheduled previously,
|
||||
but not scheduled today.
|
||||
|
||||
When set to the symbol `repeated-after-deadline', skip scheduled
|
||||
items if they are repeated beyond the current deadline."
|
||||
but not scheduled today."
|
||||
:group 'org-agenda-skip
|
||||
:group 'org-agenda-daily/weekly
|
||||
:type '(choice
|
||||
(const :tag "Never" nil)
|
||||
(const :tag "Always" t)
|
||||
(const :tag "Not when scheduled today" not-today)
|
||||
(const :tag "When repeated past deadline" repeated-after-deadline)))
|
||||
(const :tag "Not when scheduled today" not-today)))
|
||||
|
||||
(defcustom org-agenda-skip-timestamp-if-deadline-is-shown nil
|
||||
"Non-nil means skip timestamp line if same entry shows because of deadline.
|
||||
|
@ -1341,10 +1337,16 @@ When set to the symbol `next' only the first future repeat is shown."
|
|||
(const :tag "Show all repeated entries" t)
|
||||
(const :tag "Show next repeated entry" next)
|
||||
(const :tag "Do not show repeated entries" nil))
|
||||
:version "26.1"
|
||||
:package-version '(Org . "9.1")
|
||||
:safe #'symbolp)
|
||||
|
||||
(defcustom org-agenda-skip-scheduled-repeats-after-deadline nil
|
||||
"Non-nil hides scheduled repeated entries past deadline."
|
||||
:group 'org-agenda-daily/weekly
|
||||
:type 'boolean
|
||||
:package-version '(Org . "9.7")
|
||||
:safe t)
|
||||
|
||||
(defcustom org-agenda-prefer-last-repeat nil
|
||||
"Non-nil sets date for repeated entries to their last repeat.
|
||||
|
||||
|
@ -5826,7 +5828,7 @@ displayed in agenda view."
|
|||
(if org-agenda-include-inactive-timestamps "[[<]" "<")
|
||||
(regexp-quote
|
||||
(format-time-string
|
||||
(org-time-stamp-format nil 'no-brackets)
|
||||
"%Y-%m-%d" ; We do not use `org-time-stamp-format' to not demand day name in timestamps.
|
||||
(org-encode-time ; DATE bound by calendar
|
||||
0 0 0 (nth 1 date) (car date) (nth 2 date))))
|
||||
"\\|\\(<[0-9]+-[0-9]+-[0-9]+[^>\n]+?\\+[0-9]+[hdwmy]>\\)"
|
||||
|
@ -6108,7 +6110,7 @@ then those holidays will be skipped."
|
|||
" *\\["
|
||||
(regexp-quote
|
||||
(format-time-string
|
||||
(org-time-stamp-format nil 'no-brackets)
|
||||
"%Y-%m-%d" ; We do not use `org-time-stamp-format' to not demand day name in timestamps.
|
||||
(org-encode-time ; DATE bound by calendar
|
||||
0 0 0 (nth 1 date) (car date) (nth 2 date))))))
|
||||
(org-agenda-search-headline-for-time nil)
|
||||
|
@ -6661,18 +6663,25 @@ scheduled items with an hour specification like [h]h:mm."
|
|||
;; Skip entry if it already appears as a deadline, per
|
||||
;; `org-agenda-skip-scheduled-if-deadline-is-shown'. This
|
||||
;; doesn't apply to habits.
|
||||
(when (or org-agenda-skip-scheduled-repeats-after-deadline
|
||||
;; FIXME: Backwards-compatibility.
|
||||
(eq org-agenda-skip-scheduled-if-deadline-is-shown
|
||||
'repeated-after-deadline))
|
||||
(let ((deadline
|
||||
(time-to-days
|
||||
(when (org-element-property :deadline el)
|
||||
(org-time-string-to-time
|
||||
(org-element-interpret-data
|
||||
(org-element-property :deadline el)))))))
|
||||
(when (and (or (<= (org-agenda--timestamp-to-absolute s) deadline)
|
||||
(not (= schedule current)))
|
||||
(> current deadline))
|
||||
(throw :skip nil))))
|
||||
(when (pcase org-agenda-skip-scheduled-if-deadline-is-shown
|
||||
((guard
|
||||
(or (not (memq (line-beginning-position 0) deadline-pos))
|
||||
habitp))
|
||||
nil)
|
||||
(`repeated-after-deadline
|
||||
(let ((deadline (time-to-days
|
||||
(when (org-element-property :deadline el)
|
||||
(org-time-string-to-time
|
||||
(org-element-interpret-data
|
||||
(org-element-property :deadline el)))))))
|
||||
(and (<= schedule deadline) (> current deadline))))
|
||||
(`not-today pastschedp)
|
||||
(`t t)
|
||||
(_ nil))
|
||||
|
|
|
@ -501,12 +501,6 @@ The capture buffer is current and still narrowed."
|
|||
:version "24.1"
|
||||
:type 'hook)
|
||||
|
||||
(defcustom org-capture-bookmark t
|
||||
"When non-nil, add bookmark pointing at the last stored position when capturing."
|
||||
:group 'org-capture
|
||||
:version "24.3"
|
||||
:type 'boolean)
|
||||
|
||||
;;; The property list for keeping information about the capture process
|
||||
|
||||
(defvar org-capture-plist nil
|
||||
|
@ -1001,12 +995,12 @@ Store them in the capture property list."
|
|||
((or `here
|
||||
`(here))
|
||||
(org-capture-put :exact-position (point) :insert-here t))
|
||||
(`(file ,path)
|
||||
(`(file ,(and path (pred stringp)))
|
||||
(set-buffer (org-capture-target-buffer path))
|
||||
(org-capture-put-target-region-and-position)
|
||||
(widen)
|
||||
(setq target-entry-p nil))
|
||||
(`(id ,id)
|
||||
(`(id ,(and id (or (pred stringp) (pred symbolp))))
|
||||
(pcase (org-id-find id)
|
||||
(`(,path . ,position)
|
||||
(set-buffer (org-capture-target-buffer path))
|
||||
|
@ -1014,7 +1008,7 @@ Store them in the capture property list."
|
|||
(org-capture-put-target-region-and-position)
|
||||
(goto-char position))
|
||||
(_ (error "Cannot find target ID \"%s\"" id))))
|
||||
(`(file+headline ,path ,headline)
|
||||
(`(file+headline ,(and path (pred stringp)) ,(and headline (pred stringp)))
|
||||
(set-buffer (org-capture-target-buffer path))
|
||||
;; Org expects the target file to be in Org mode, otherwise
|
||||
;; it throws an error. However, the default notes files
|
||||
|
@ -1036,7 +1030,7 @@ Store them in the capture property list."
|
|||
(unless (bolp) (insert "\n"))
|
||||
(insert "* " headline "\n")
|
||||
(forward-line -1)))
|
||||
(`(file+olp ,path . ,outline-path)
|
||||
(`(file+olp ,(and path (pred stringp)) . ,(and outline-path (guard outline-path)))
|
||||
(let ((m (org-find-olp (cons (org-capture-expand-file path)
|
||||
outline-path))))
|
||||
(set-buffer (marker-buffer m))
|
||||
|
@ -1044,7 +1038,7 @@ Store them in the capture property list."
|
|||
(widen)
|
||||
(goto-char m)
|
||||
(set-marker m nil)))
|
||||
(`(file+regexp ,path ,regexp)
|
||||
(`(file+regexp ,(and path (pred stringp)) ,(and regexp (pred stringp)))
|
||||
(set-buffer (org-capture-target-buffer path))
|
||||
(org-capture-put-target-region-and-position)
|
||||
(widen)
|
||||
|
@ -1057,7 +1051,7 @@ Store them in the capture property list."
|
|||
(org-capture-put :exact-position (point))
|
||||
(setq target-entry-p
|
||||
(and (derived-mode-p 'org-mode) (org-at-heading-p)))))
|
||||
(`(file+olp+datetree ,path . ,outline-path)
|
||||
(`(file+olp+datetree ,(and path (pred stringp)) . ,outline-path)
|
||||
(let ((m (if outline-path
|
||||
(org-find-olp (cons (org-capture-expand-file path)
|
||||
outline-path))
|
||||
|
@ -1112,7 +1106,7 @@ Store them in the capture property list."
|
|||
;; the following is the keep-restriction argument for
|
||||
;; org-datetree-find-date-create
|
||||
(when outline-path 'subtree-at-point))))
|
||||
(`(file+function ,path ,function)
|
||||
(`(file+function ,(and path (pred stringp)) ,(and function (pred functionp)))
|
||||
(set-buffer (org-capture-target-buffer path))
|
||||
(org-capture-put-target-region-and-position)
|
||||
(widen)
|
||||
|
@ -1120,7 +1114,7 @@ Store them in the capture property list."
|
|||
(org-capture-put :exact-position (point))
|
||||
(setq target-entry-p
|
||||
(and (derived-mode-p 'org-mode) (org-at-heading-p))))
|
||||
(`(function ,fun)
|
||||
(`(function ,(and fun (pred functionp)))
|
||||
(funcall fun)
|
||||
(org-capture-put :exact-position (point))
|
||||
(setq target-entry-p
|
||||
|
@ -1506,7 +1500,9 @@ Of course, if exact position has been required, just put it there."
|
|||
(point))))))
|
||||
(with-current-buffer (buffer-base-buffer (current-buffer))
|
||||
(org-with-point-at pos
|
||||
(when org-capture-bookmark
|
||||
;; FIXME: `org-capture-bookmark' is obsolete. To be removed
|
||||
;; in future Org releases.
|
||||
(when (with-no-warnings org-capture-bookmark)
|
||||
(let ((bookmark (plist-get org-bookmark-names-plist :last-capture)))
|
||||
(when bookmark
|
||||
(condition-case err
|
||||
|
|
|
@ -183,28 +183,10 @@ See `org-columns-summary-types' for details.")
|
|||
(org-defkey org-columns-map "\M-b" #'backward-char)
|
||||
(org-defkey org-columns-map "a" #'org-columns-edit-allowed)
|
||||
(org-defkey org-columns-map "s" #'org-columns-edit-attributes)
|
||||
(org-defkey org-columns-map "\M-f"
|
||||
(lambda () (interactive) (goto-char (1+ (point)))))
|
||||
(org-defkey org-columns-map [right]
|
||||
(lambda () (interactive) (goto-char (1+ (point)))))
|
||||
(org-defkey org-columns-map [down]
|
||||
(lambda () (interactive)
|
||||
(let ((col (current-column)))
|
||||
(forward-line 1)
|
||||
(while (and (org-invisible-p2) (not (eobp)))
|
||||
(forward-line 1))
|
||||
(move-to-column col)
|
||||
(if (derived-mode-p 'org-agenda-mode)
|
||||
(org-agenda-do-context-action)))))
|
||||
(org-defkey org-columns-map [up]
|
||||
(lambda () (interactive)
|
||||
(let ((col (current-column)))
|
||||
(forward-line -1)
|
||||
(while (and (org-invisible-p2) (not (bobp)))
|
||||
(forward-line -1))
|
||||
(move-to-column col)
|
||||
(if (eq major-mode 'org-agenda-mode)
|
||||
(org-agenda-do-context-action)))))
|
||||
(org-defkey org-columns-map "\M-f" #'forward-char)
|
||||
(org-defkey org-columns-map [right] #'forward-char)
|
||||
(org-defkey org-columns-map [up] #'org-columns-move-up)
|
||||
(org-defkey org-columns-map [down] #'org-columns-move-down)
|
||||
(org-defkey org-columns-map [(shift right)] #'org-columns-next-allowed-value)
|
||||
(org-defkey org-columns-map "n" #'org-columns-next-allowed-value)
|
||||
(org-defkey org-columns-map [(shift left)] #'org-columns-previous-allowed-value)
|
||||
|
@ -383,13 +365,15 @@ ORIGINAL is the real string, i.e., before it is modified by
|
|||
"Store the relative remapping of column header-line.
|
||||
This is needed to later remove this relative remapping.")
|
||||
|
||||
(defvar org-columns--read-only-string nil)
|
||||
(defun org-columns--display-here (columns &optional dateline)
|
||||
"Overlay the current line with column display.
|
||||
COLUMNS is an alist (SPEC VALUE DISPLAYED). Optional argument
|
||||
DATELINE is non-nil when the face used should be
|
||||
`org-agenda-column-dateline'."
|
||||
(when (and (ignore-errors (require 'face-remap))
|
||||
org-columns-header-line-remap)
|
||||
(when (and (not org-columns-header-line-remap)
|
||||
(or (fboundp 'face-remap-add-relative)
|
||||
(ignore-errors (require 'face-remap))))
|
||||
(setq org-columns-header-line-remap
|
||||
(face-remap-add-relative 'header-line '(:inherit default))))
|
||||
(save-excursion
|
||||
|
@ -456,9 +440,11 @@ DATELINE is non-nil when the face used should be
|
|||
(line-end-position 0)
|
||||
(line-beginning-position 2)
|
||||
'read-only
|
||||
(substitute-command-keys
|
||||
"Type \\<org-columns-map>`\\[org-columns-edit-value]' \
|
||||
to edit property")))))))
|
||||
(or org-columns--read-only-string
|
||||
(setq org-columns--read-only-string
|
||||
(substitute-command-keys
|
||||
"Type \\<org-columns-map>`\\[org-columns-edit-value]' \
|
||||
to edit property")))))))))
|
||||
|
||||
(defun org-columns--truncate-below-width (string width)
|
||||
"Return a substring of STRING no wider than WIDTH.
|
||||
|
@ -911,7 +897,6 @@ When COLUMNS-FMT-STRING is non-nil, use it as the column format."
|
|||
(setq truncate-lines t))
|
||||
(dolist (entry cache)
|
||||
(goto-char (car entry))
|
||||
(move-marker (car entry) nil)
|
||||
(org-columns--display-here (cdr entry)))))))))
|
||||
|
||||
(defun org-columns-new (&optional spec &rest attributes)
|
||||
|
@ -996,6 +981,30 @@ details."
|
|||
(interactive "p")
|
||||
(org-columns-widen (- arg)))
|
||||
|
||||
(defun org-columns-move-up ()
|
||||
"In column view, move cursor up one row.
|
||||
When in agenda column view, also call `org-agenda-do-context-action'."
|
||||
(interactive)
|
||||
(let ((col (current-column)))
|
||||
(forward-line -1)
|
||||
(while (and (org-invisible-p2) (not (bobp)))
|
||||
(forward-line -1))
|
||||
(move-to-column col)
|
||||
(if (eq major-mode 'org-agenda-mode)
|
||||
(org-agenda-do-context-action))))
|
||||
|
||||
(defun org-columns-move-down ()
|
||||
"In column view, move cursor down one row.
|
||||
When in agenda column view, also call `org-agenda-do-context-action'."
|
||||
(interactive)
|
||||
(let ((col (current-column)))
|
||||
(forward-line 1)
|
||||
(while (and (org-invisible-p2) (not (eobp)))
|
||||
(forward-line 1))
|
||||
(move-to-column col)
|
||||
(if (derived-mode-p 'org-agenda-mode)
|
||||
(org-agenda-do-context-action))))
|
||||
|
||||
(defun org-columns-move-right ()
|
||||
"Swap this column with the one to the right."
|
||||
(interactive)
|
||||
|
@ -1207,8 +1216,8 @@ Return the result as a duration."
|
|||
SPEC is a column format specification. When optional argument
|
||||
UPDATE is non-nil, summarized values can replace existing ones in
|
||||
properties drawers."
|
||||
(let* ((lmax (if (bound-and-true-p org-inlinetask-min-level)
|
||||
org-inlinetask-min-level
|
||||
(let* ((lmax (if (bound-and-true-p org-inlinetask-max-level)
|
||||
org-inlinetask-max-level
|
||||
29)) ;Hard-code deepest level.
|
||||
(lvals (make-vector (1+ lmax) nil))
|
||||
(level 0)
|
||||
|
|
|
@ -232,6 +232,18 @@ removed."
|
|||
default)))
|
||||
": ")))
|
||||
|
||||
(if (fboundp 'ensure-list)
|
||||
(defalias 'org-ensure-list #'ensure-list)
|
||||
(defun org-ensure-list (object)
|
||||
"Return OBJECT as a list.
|
||||
If OBJECT is already a list, return OBJECT itself. If it's
|
||||
not a list, return a one-element list containing OBJECT.
|
||||
|
||||
Compatability substitute for `ensure-list' in Emacs 28."
|
||||
(if (listp object)
|
||||
object
|
||||
(list object))))
|
||||
|
||||
|
||||
;;; Emacs < 27.1 compatibility
|
||||
|
||||
|
@ -629,6 +641,24 @@ Counting starts at 1."
|
|||
(define-obsolete-function-alias 'org-file-url-p 'org-url-p "9.6")
|
||||
(define-obsolete-variable-alias 'org-plantuml-executable-args 'org-plantuml-args
|
||||
"Org 9.6")
|
||||
|
||||
(defconst org-latex-line-break-safe "\\\\[0pt]"
|
||||
"Linebreak protecting the following [...].
|
||||
|
||||
Without \"[0pt]\" it would be interpreted as an optional argument to
|
||||
the \\\\.
|
||||
|
||||
This constant, for example, makes the below code not err:
|
||||
|
||||
\\begin{tabular}{c|c}
|
||||
[t] & s\\\\[0pt]
|
||||
[I] & A\\\\[0pt]
|
||||
[m] & kg
|
||||
\\end{tabular}")
|
||||
(make-obsolete 'org-latex-line-break-safe
|
||||
"should not be used - it is not safe in all the scenarios."
|
||||
"9.7")
|
||||
|
||||
(defun org-in-fixed-width-region-p ()
|
||||
"Non-nil if point in a fixed-width region."
|
||||
(save-match-data
|
||||
|
@ -637,6 +667,393 @@ Counting starts at 1."
|
|||
"use `org-element' library"
|
||||
"9.0")
|
||||
|
||||
(define-obsolete-variable-alias
|
||||
'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-process-default "9.7")
|
||||
(define-obsolete-variable-alias
|
||||
'org-preview-latex-process-alist 'org-latex-preview-process-alist "9.7")
|
||||
(define-obsolete-function-alias
|
||||
'org-clear-latex-preview 'org-latex-preview-clear-overlays "9.7")
|
||||
(make-obsolete
|
||||
'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-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)
|
||||
"Return a RGB color specification for dvipng."
|
||||
(org-dvipng-color-format (face-attribute 'default attr nil)))
|
||||
|
||||
;; FIXME: Unused; obsoleted; to be removed.
|
||||
(defun org-dvipng-color-format (color-name)
|
||||
"Convert COLOR-NAME to a RGB color value for dvipng."
|
||||
(apply #'format "rgb %s %s %s"
|
||||
(mapcar 'org-latex-preview--normalize-color
|
||||
(color-values color-name))))
|
||||
(make-obsolete
|
||||
'org-dvipng-color "to be removed" "9.7")
|
||||
(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"))
|
||||
|
@ -663,8 +1080,9 @@ Counting starts at 1."
|
|||
"Switch to buffer in a second window on the current frame.
|
||||
In particular, do not allow pop-up frames.
|
||||
Returns the newly created buffer."
|
||||
(with-no-warnings (org-no-popups (apply #'switch-to-buffer-other-window args))))
|
||||
(make-obsolete 'org-switch-to-buffer-other-window "no longer used" "9.7")
|
||||
(let (pop-up-frames pop-up-windows)
|
||||
(apply #'switch-to-buffer-other-window args)))
|
||||
(make-obsolete 'org-switch-to-buffer-other-window "no longer used" "9.7")
|
||||
|
||||
(make-obsolete 'org-refresh-category-properties "no longer used" "9.7")
|
||||
(make-obsolete 'org-refresh-effort-properties "no longer used" "9.7")
|
||||
|
@ -757,13 +1175,23 @@ See `org-link-parameters' for documentation on the other parameters."
|
|||
(org-unbracket-string "<" ">" s))
|
||||
(make-obsolete 'org-remove-angle-brackets 'org-unbracket-string "9.0")
|
||||
|
||||
(defcustom org-capture-bookmark t
|
||||
"When non-nil, add bookmark pointing at the last stored position when capturing."
|
||||
:group 'org-capture
|
||||
:version "24.3"
|
||||
:type 'boolean)
|
||||
(make-obsolete-variable
|
||||
'org-capture-bookmark
|
||||
"use `org-bookmark-names-plist' instead."
|
||||
"9.7")
|
||||
|
||||
(defcustom org-publish-sitemap-file-entry-format "%t"
|
||||
"Format string for site-map file entry.
|
||||
You could use brackets to delimit on what part the link will be.
|
||||
|
||||
%t is the title.
|
||||
%a is the author.
|
||||
%d is the date formatted using `org-publish-sitemap-date-format'."
|
||||
%d is the date."
|
||||
:group 'org-export-publish
|
||||
:type 'string)
|
||||
(make-obsolete-variable
|
||||
|
|
|
@ -71,6 +71,7 @@
|
|||
(defvar epg-context)
|
||||
|
||||
(declare-function org-back-over-empty-lines "org" ())
|
||||
(declare-function org-current-level "org" ())
|
||||
(declare-function org-back-to-heading "org" (&optional invisible-ok))
|
||||
(declare-function org-before-first-heading-p "org" ())
|
||||
(declare-function org-end-of-meta-data "org" (&optional full))
|
||||
|
@ -251,6 +252,7 @@ Assume `epg-context' is set."
|
|||
(org-fold-subtree t))
|
||||
nil)))))
|
||||
|
||||
(defvar org-outline-regexp-bol)
|
||||
;;;###autoload
|
||||
(defun org-decrypt-entry ()
|
||||
"Decrypt the content of the current headline."
|
||||
|
@ -266,6 +268,7 @@ Assume `epg-context' is set."
|
|||
(save-excursion
|
||||
(org-previous-visible-heading 1)
|
||||
(point))))
|
||||
(level (org-current-level))
|
||||
(encrypted-text (org-crypt--encrypted-text beg end))
|
||||
(decrypted-text
|
||||
(decode-coding-string
|
||||
|
@ -276,15 +279,27 @@ Assume `epg-context' is set."
|
|||
;; outline property starts at the \n of the heading.
|
||||
(delete-region (1- (point)) end)
|
||||
(setq origin-marker (point-marker))
|
||||
;; Store a checksum of the decrypted and the encrypted text
|
||||
;; value. This allows reusing the same encrypted text if the
|
||||
;; text does not change, and therefore avoid a re-encryption
|
||||
;; process.
|
||||
(insert "\n"
|
||||
(propertize decrypted-text
|
||||
'org-crypt-checksum (sha1 decrypted-text)
|
||||
'org-crypt-key (org-crypt-key-for-heading)
|
||||
'org-crypt-text encrypted-text))
|
||||
(if (string-match (org-headline-re level) decrypted-text)
|
||||
;; If decrypted text contains other headings with levels
|
||||
;; below LEVEL, adjust the subtree.
|
||||
(let ((start 0) (min-level level))
|
||||
(while (string-match (org-headline-re level) decrypted-text start)
|
||||
(setq min-level (min min-level (1- (length (match-string 0 decrypted-text))))
|
||||
start (match-end 0)))
|
||||
(insert "\n"
|
||||
(replace-regexp-in-string
|
||||
org-outline-regexp-bol
|
||||
(concat (make-string (1+ (- level min-level)) ?*) "\\&")
|
||||
decrypted-text)))
|
||||
;; Store a checksum of the decrypted and the encrypted text
|
||||
;; value. This allows reusing the same encrypted text if the
|
||||
;; text does not change, and therefore avoid a re-encryption
|
||||
;; process.
|
||||
(insert "\n"
|
||||
(propertize decrypted-text
|
||||
'org-crypt-checksum (sha1 decrypted-text)
|
||||
'org-crypt-key (org-crypt-key-for-heading)
|
||||
'org-crypt-text encrypted-text)))
|
||||
;; Apply initial visibility.
|
||||
(save-restriction
|
||||
(narrow-to-region origin-marker (point))
|
||||
|
|
|
@ -149,7 +149,7 @@
|
|||
(defvar org-ctags-enabled-p t
|
||||
"Activate ctags support in org mode?")
|
||||
|
||||
(defvar org-ctags-tag-regexp "/<<([^>]+)>>/\\1/d,definition/"
|
||||
(defvar org-ctags-tag-regexp "/<<([^<>]+)>>/\\1/d,definition/"
|
||||
"Regexp expression used by ctags external program.
|
||||
The regexp matches tag destinations in Org files.
|
||||
Format is: /REGEXP/TAGNAME/FLAGS,TAGTYPE/
|
||||
|
@ -484,11 +484,11 @@ its subdirectories contain large numbers of taggable files."
|
|||
(setq exitcode
|
||||
(shell-command
|
||||
(format (concat "%s --langdef=orgmode --langmap=orgmode:.org "
|
||||
"--regex-orgmode=\"%s\" -f \"%s\" -e -R \"%s\"")
|
||||
"--regex-orgmode=\"%s\" -f \"%s\" -e -R %s")
|
||||
org-ctags-path-to-ctags
|
||||
org-ctags-tag-regexp
|
||||
(expand-file-name (concat dir-name "/TAGS"))
|
||||
(expand-file-name (concat dir-name "/*")))))
|
||||
(expand-file-name (concat (shell-quote-argument dir-name) "/*")))))
|
||||
(cond
|
||||
((eql 0 exitcode)
|
||||
(setq-local org-ctags-tag-list
|
||||
|
@ -506,12 +506,11 @@ its subdirectories contain large numbers of taggable files."
|
|||
|
||||
(defun org-ctags-find-tag-interactive ()
|
||||
"Prompt for the name of a tag, with autocompletion, then visit the named tag.
|
||||
Uses `ido-mode' if available.
|
||||
If the user enters a string that does not match an existing tag, create
|
||||
a new topic."
|
||||
(interactive)
|
||||
(let* ((tag (ido-completing-read "Topic: " org-ctags-tag-list
|
||||
nil 'confirm nil 'org-ctags-find-tag-history)))
|
||||
(let* ((tag (completing-read "Topic: " org-ctags-tag-list
|
||||
nil 'confirm nil 'org-ctags-find-tag-history)))
|
||||
(when tag
|
||||
(cond
|
||||
((member tag org-ctags-tag-list)
|
||||
|
|
|
@ -615,7 +615,7 @@ With a numeric prefix, show all headlines up to that level."
|
|||
(cond
|
||||
;; `fold' is technically not allowed value, but it is often
|
||||
;; intuitively tried by users by analogy with #+STARTUP: fold.
|
||||
((memq org-startup-folded '(t fold))
|
||||
((memq org-startup-folded '(t fold overview))
|
||||
(org-cycle-overview))
|
||||
((eq org-startup-folded 'content)
|
||||
(org-cycle-content))
|
||||
|
@ -667,8 +667,7 @@ With a numeric prefix, show all headlines up to that level."
|
|||
(org-cycle-content))))
|
||||
((or "all" "showall")
|
||||
(org-fold-show-subtree))
|
||||
(_ nil)))
|
||||
(org-end-of-subtree t)))))))
|
||||
(_ nil)))))))))
|
||||
|
||||
(defun org-cycle-overview ()
|
||||
"Switch to overview mode, showing only top-level headlines."
|
||||
|
|
|
@ -205,6 +205,7 @@
|
|||
|
||||
(require 'org-macs)
|
||||
(require 'inline) ; load indentation rules
|
||||
(require 'subr-x) ;; FIXME: Required for Emacs 27
|
||||
|
||||
;;;; Syntax node type
|
||||
|
||||
|
@ -230,16 +231,11 @@ when NODE is an anonymous node."
|
|||
|
||||
(define-inline org-element-type-p (node types)
|
||||
"Return non-nil when NODE type is one of TYPES.
|
||||
TYPES can be a type symbol or a list of symbols."
|
||||
(if (inline-const-p types)
|
||||
(if (listp (inline-const-val types))
|
||||
(inline-quote (memq (org-element-type ,node t) ,types))
|
||||
(inline-quote (eq (org-element-type ,node t) ,types)))
|
||||
(inline-letevals (node types)
|
||||
(inline-quote
|
||||
(if (listp ,types)
|
||||
(memq (org-element-type ,node t) ,types)
|
||||
(eq (org-element-type ,node t) ,types))))))
|
||||
TYPES can be a type symbol or a list of symbols."
|
||||
(inline-letevals (node types)
|
||||
(if (listp (inline-const-val types))
|
||||
(inline-quote (memq (org-element-type ,node t) ,types))
|
||||
(inline-quote (eq (org-element-type ,node t) ,types)))))
|
||||
|
||||
(defun org-element-secondary-p (node)
|
||||
"Non-nil when NODE directly belongs to a secondary node.
|
||||
|
@ -353,18 +349,15 @@ node types.")
|
|||
(setq plist (plist-put plist property idx)))
|
||||
org-element--standard-properties)
|
||||
plist)
|
||||
"Property list holding standard indexes for `org-element--standard-properties'."))
|
||||
"Property list holding standard indexes for `org-element--standard-properties'.")
|
||||
|
||||
(define-inline org-element--property-idx (property)
|
||||
"Return standard property index or nil."
|
||||
(declare (pure t))
|
||||
(if (inline-const-p property)
|
||||
(define-inline org-element--property-idx (property)
|
||||
"Return standard property index or nil."
|
||||
(declare (pure t))
|
||||
(inline-letevals (property)
|
||||
(plist-get
|
||||
org-element--standard-properties-idxs
|
||||
(inline-const-val property))
|
||||
(inline-quote (plist-get
|
||||
org-element--standard-properties-idxs
|
||||
,property))))
|
||||
(inline-const-val property)))))
|
||||
|
||||
(define-inline org-element--parray (node)
|
||||
"Return standard property array for NODE."
|
||||
|
@ -413,26 +406,16 @@ Ignore standard property array."
|
|||
Do not resolve deferred values.
|
||||
If PROPERTY is not present, return DFLT."
|
||||
(declare (pure t))
|
||||
(let ((idx (and (inline-const-p property)
|
||||
(org-element--property-idx property))))
|
||||
(if idx
|
||||
(inline-letevals (node)
|
||||
(inline-quote
|
||||
(if-let ((parray (org-element--parray ,node)))
|
||||
(pcase (aref parray ,idx)
|
||||
(`org-element-ast--nil ,dflt)
|
||||
(val val))
|
||||
;; No property array exists. Fall back to `plist-get'.
|
||||
(org-element--plist-property ,property ,node ,dflt))))
|
||||
(inline-letevals (node property)
|
||||
(inline-quote
|
||||
(let ((idx (org-element--property-idx ,property)))
|
||||
(if-let ((parray (and idx (org-element--parray ,node))))
|
||||
(pcase (aref parray idx)
|
||||
(`org-element-ast--nil ,dflt)
|
||||
(val val))
|
||||
;; No property array exists. Fall back to `plist-get'.
|
||||
(org-element--plist-property ,property ,node ,dflt))))))))
|
||||
(inline-letevals (node property)
|
||||
(let ((idx (org-element--property-idx (inline-const-val property))))
|
||||
(inline-quote
|
||||
(let ((idx (or ,idx (org-element--property-idx ,property))))
|
||||
(if-let ((parray (and idx (org-element--parray ,node))))
|
||||
(pcase (aref parray idx)
|
||||
(`org-element-ast--nil ,dflt)
|
||||
(val val))
|
||||
;; No property array exists. Fall back to `plist-get'.
|
||||
(org-element--plist-property ,property ,node ,dflt)))))))
|
||||
|
||||
(define-inline org-element--put-parray (node &optional parray)
|
||||
"Initialize standard property array in NODE.
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
;; Copyright (C) 2012-2024 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Nicolas Goaziou <n.goaziou at gmail dot com>
|
||||
;; Maintainer: Ihor Radchenko <yantar92 at posteo dot net>
|
||||
;; Keywords: outlines, hypermedia, calendar, wp
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
@ -2870,6 +2871,7 @@ Assume point is at the beginning of the paragraph."
|
|||
(progn (forward-line 0) t))))
|
||||
((looking-at-p org-element-drawer-re)
|
||||
(save-excursion
|
||||
(forward-line 1)
|
||||
(re-search-forward "^[ \t]*:END:[ \t]*$" limit t)))
|
||||
((looking-at "[ \t]*#\\+BEGIN_\\(\\S-+\\)")
|
||||
(save-excursion
|
||||
|
@ -7989,10 +7991,10 @@ the cache."
|
|||
(if org-element--cache-map-statistics
|
||||
(progn
|
||||
(setq before-time (float-time))
|
||||
(re-search-forward (or (car-safe ,re) ,re) nil 'move)
|
||||
(cl-incf re-search-time
|
||||
(- (float-time)
|
||||
before-time)))
|
||||
(prog1 (re-search-forward (or (car-safe ,re) ,re) nil 'move)
|
||||
(cl-incf re-search-time
|
||||
(- (float-time)
|
||||
before-time))))
|
||||
(re-search-forward (or (car-safe ,re) ,re) nil 'move)))
|
||||
(unless (or (< (point) (or start -1))
|
||||
(and data
|
||||
|
@ -8176,22 +8178,21 @@ the cache."
|
|||
(move-start-to-next-match
|
||||
(if last-match next-re fail-re)))
|
||||
(when (and (or (not start) (eq (org-element-begin data) start))
|
||||
(< (org-element-begin data) to-pos))
|
||||
(< (org-element-begin data) to-pos)
|
||||
(not continue-flag))
|
||||
;; Calculate where next possible element
|
||||
;; starts and update START if needed.
|
||||
(setq start (next-element-start))
|
||||
(goto-char start)
|
||||
;; Move START further if possible.
|
||||
(when (and next-element-re
|
||||
;; Do not move if we know for
|
||||
;; sure that cache does not
|
||||
;; contain gaps. Regexp
|
||||
;; searches are not cheap.
|
||||
(not (cache-gapless-p)))
|
||||
(move-start-to-next-match next-element-re)
|
||||
;; Make sure that point is at START
|
||||
;; before running FUNC.
|
||||
(goto-char start))
|
||||
(save-excursion
|
||||
(when (and next-element-re
|
||||
;; Do not move if we know for
|
||||
;; sure that cache does not
|
||||
;; contain gaps. Regexp
|
||||
;; searches are not cheap.
|
||||
(not (cache-gapless-p)))
|
||||
(move-start-to-next-match next-element-re)))
|
||||
;; Try FUNC if DATA matches all the
|
||||
;; restrictions. Calculate new START.
|
||||
(when (or (not restrict-elements)
|
||||
|
|
|
@ -389,6 +389,10 @@ changes."
|
|||
"Face used for tables."
|
||||
:group 'org-faces)
|
||||
|
||||
(defface org-table-row '((t :inherit org-table))
|
||||
"Face used to fontify whole table rows (including newlines and indentation)."
|
||||
:group 'org-faces)
|
||||
|
||||
(defface org-table-header '((t :inherit org-table
|
||||
:background "LightGray"
|
||||
:foreground "Black"))
|
||||
|
|
|
@ -280,12 +280,13 @@
|
|||
|
||||
;;; Customization
|
||||
|
||||
(defcustom org-fold-core-style 'text-properties
|
||||
(defcustom org-fold-core-style (if (version< emacs-version "29")
|
||||
'text-properties
|
||||
'overlays)
|
||||
"Internal implementation detail used to hide folded text.
|
||||
Can be either `text-properties' or `overlays'.
|
||||
The former is faster on large files, while the latter is generally
|
||||
less error-prone with regard to third-party packages that haven't yet
|
||||
adapted to the new folding implementation.
|
||||
The former is faster on large files in Emacs <29, while the latter is
|
||||
generally less error-prone with regard to third-party packages.
|
||||
|
||||
Important: This variable must be set before loading Org."
|
||||
:group 'org
|
||||
|
@ -1356,7 +1357,9 @@ Pass the same FROM, TO, FLAG, and SPEC-OR-ALIAS."
|
|||
"Perform folding for `org-fold-core--region-delayed-list'."
|
||||
(when org-fold-core--region-delayed-list
|
||||
(mapc (lambda (args)
|
||||
(when (< (nth 0 args) (nth 1 args))
|
||||
(when (and (buffer-live-p (marker-buffer (nth 0 args)))
|
||||
(buffer-live-p (marker-buffer (nth 1 args)))
|
||||
(< (nth 0 args) (nth 1 args)))
|
||||
(org-with-point-at (car args)
|
||||
(apply #'org-fold-core-region args))))
|
||||
;; Restore the initial folding order.
|
||||
|
|
|
@ -595,7 +595,8 @@ Return a non-nil value when toggling is successful."
|
|||
|
||||
(defun org-fold-hide-drawer-all (&optional begin end)
|
||||
"Fold all drawers in the current buffer or active region BEGIN..END."
|
||||
(interactive "r")
|
||||
(interactive (list (and (use-region-p) (region-beginning))
|
||||
(and (use-region-p) (region-end))))
|
||||
(let ((begin (or begin (point-min)))
|
||||
(end (or end (point-max))))
|
||||
(org-fold--hide-drawers begin end)))
|
||||
|
|
|
@ -137,6 +137,7 @@ Possible values are:
|
|||
|
||||
nil Prompt the user for each label.
|
||||
t Create unique labels of the form [fn:1], [fn:2], etc.
|
||||
anonymous Create anonymous footnotes
|
||||
confirm Like t, but let the user edit the created value.
|
||||
The label can be removed from the minibuffer to create
|
||||
an anonymous footnote.
|
||||
|
@ -146,6 +147,7 @@ random Automatically generate a unique, random label."
|
|||
(const :tag "Prompt for label" nil)
|
||||
(const :tag "Create automatic [fn:N]" t)
|
||||
(const :tag "Offer automatic [fn:N] for editing" confirm)
|
||||
(const :tag "Create anoymous [fn::]" anonymous)
|
||||
(const :tag "Create a random label" random))
|
||||
:safe #'symbolp)
|
||||
|
||||
|
@ -666,15 +668,16 @@ or new, let the user edit the definition of the footnote."
|
|||
(user-error "Cannot insert a footnote here"))
|
||||
(let* ((all (org-footnote-all-labels))
|
||||
(label
|
||||
(if (eq org-footnote-auto-label 'random)
|
||||
(format "%x" (abs (random)))
|
||||
(org-footnote-normalize-label
|
||||
(let ((propose (org-footnote-unique-label all)))
|
||||
(if (eq org-footnote-auto-label t) propose
|
||||
(completing-read
|
||||
"Label (leave empty for anonymous): "
|
||||
(mapcar #'list all) nil nil
|
||||
(and (eq org-footnote-auto-label 'confirm) propose))))))))
|
||||
(unless (eq org-footnote-auto-label 'anonymous)
|
||||
(if (eq org-footnote-auto-label 'random)
|
||||
(format "%x" (abs (random)))
|
||||
(org-footnote-normalize-label
|
||||
(let ((propose (org-footnote-unique-label all)))
|
||||
(if (eq org-footnote-auto-label t) propose
|
||||
(completing-read
|
||||
"Label (leave empty for anonymous): "
|
||||
(mapcar #'list all) nil nil
|
||||
(and (eq org-footnote-auto-label 'confirm) propose)))))))))
|
||||
(cond ((not label)
|
||||
(insert "[fn::]")
|
||||
(backward-char 1))
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1152,7 +1152,7 @@ This function modifies STRUCT."
|
|||
(org-fold-core-regions (cdr folds) :relative beg-A)
|
||||
(org-fold-core-regions
|
||||
(car folds)
|
||||
:relative (+ beg-B (- size-B size-A (length between-A-no-blank-and-B))))
|
||||
:relative (+ beg-A size-B (length between-A-no-blank-and-B)))
|
||||
;; 2. Now modify struct. No need to re-read the list, the
|
||||
;; transformation is just a shift of positions. Some special
|
||||
;; attention is required for items ending at END-A and END-B
|
||||
|
|
276
lisp/org-macs.el
276
lisp/org-macs.el
|
@ -344,6 +344,278 @@ If EXCLUDE-TMP is non-nil, ignore temporary buffers."
|
|||
nil))
|
||||
(buffer-list)))))
|
||||
|
||||
|
||||
;;; Async stack
|
||||
|
||||
(defvar org-async--stack nil
|
||||
"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 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.")
|
||||
|
||||
(defvar org-async-timeout 120
|
||||
"Default timeout for a process started via `org-async-queue'.")
|
||||
|
||||
(defvar org-async-check-timeout-interval 1
|
||||
"Check for processes which have exceeded their timeout every this many seconds.")
|
||||
|
||||
(defvar org-async--counter 0)
|
||||
|
||||
(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
|
||||
a shell command, with `start-process-shell-command' and a list
|
||||
run using `start-process' with the car as the command and the cdr
|
||||
as the arguments. The process will be executed in DIR (if set)
|
||||
or `default-directory'.
|
||||
|
||||
There is also a \"special form\" of PROC, namely a list where the
|
||||
first item is the symbol org-async-task, and the rest constitutes
|
||||
an argument list for `org-async-call'. This form allows for easy
|
||||
specification of callbacks that are themselves async tasks, e.g.
|
||||
(org-async-call \\='(\"sleep 1\")
|
||||
:success \\='(org-async-task (\"notify-send\" \"done\")))
|
||||
When using this form, all other arguments are ignored.
|
||||
|
||||
When BUFFER is provided, the output of PROC will be directed to it.
|
||||
Shoud BUFFER be t, then a temp buffer will be created and removed
|
||||
during `org-async--cleanup-process'.
|
||||
|
||||
SUCCESS and FAILURE can be any form accepted by `org-async--execute-callback',
|
||||
namely:
|
||||
- A string, which is used a `message' string with the exit-code,
|
||||
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' 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.
|
||||
i.e. the call signature is (content new-content-string INFO)
|
||||
When BUFFER is non-nil, there are two other major differences:
|
||||
- The new content is silently inserted before FILTER is called
|
||||
- Note that `point' is left alone and is not moved by this.
|
||||
- The process buffer is the current buffer when FILTER is called.
|
||||
|
||||
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'.
|
||||
|
||||
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.
|
||||
((and (consp proc)
|
||||
(eq (car proc) 'org-async-task))
|
||||
(apply #'org-async-call (cdr proc)))
|
||||
;; Start the async process now.
|
||||
((or now (< (length org-async--stack) org-async-process-limit))
|
||||
(let ((proc
|
||||
(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
|
||||
(format "org-async-%d" (cl-incf org-async--counter))
|
||||
buffer proc))
|
||||
((consp proc)
|
||||
(apply #'start-process
|
||||
(format "org-async-%s-%d"
|
||||
(car proc) (cl-incf org-async--counter))
|
||||
buffer proc))
|
||||
(t (error "Async process input %S not a recognised format"
|
||||
proc)))))
|
||||
(timeout (or timeout org-async-timeout)))
|
||||
(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
|
||||
: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)
|
||||
(car org-async--stack)))
|
||||
;; Queue the task to be run later.
|
||||
(t
|
||||
(setq org-async--wait-queue
|
||||
(append org-async--wait-queue
|
||||
(list (list proc
|
||||
:success success
|
||||
:failure failure
|
||||
:filter filter
|
||||
:buffer buffer
|
||||
:info info
|
||||
:dir dir
|
||||
:timeout timeout
|
||||
: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
|
||||
`org-async-call'."
|
||||
(when-let ((proc-info (alist-get process org-async--stack)))
|
||||
(let ((filter (plist-get proc-info :filter))
|
||||
(buffer (plist-get proc-info :buffer)))
|
||||
(if buffer
|
||||
(with-current-buffer buffer
|
||||
(save-excursion
|
||||
(goto-char (point-max))
|
||||
(insert string))
|
||||
(funcall filter process string (plist-get proc-info :info)))
|
||||
(funcall filter process string (plist-get proc-info :info))))))
|
||||
|
||||
(defun org-async--sentinel (process _signal)
|
||||
"Watch PROCESS for death, and cleanup accordingly.
|
||||
When a signal is recieved, the status of PROCESS is checked.
|
||||
Should the it have an exit status, with status code 0,
|
||||
`org-async--cleanup-process' is run with the \"failed\" argument
|
||||
unset. Should the process have finished in any other manner,
|
||||
`org-async--cleanup-process' is run with the \"failed\" argument."
|
||||
(pcase (process-status process)
|
||||
((and 'exit (guard (= 0 (process-exit-status process))))
|
||||
(org-async--cleanup-process process))
|
||||
((or 'exit 'signal 'failed)
|
||||
(org-async--cleanup-process process 'failed))))
|
||||
|
||||
(defun org-async--cleanup-process (process &optional failed)
|
||||
"Remove PROCESS from the async stack, and run its callback.
|
||||
If the exit code of PROCESS is zero and FAILED is non-nil, then
|
||||
the success callback is run (via `org-async--execute-callback').
|
||||
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))
|
||||
(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
|
||||
(if (and (not failed)
|
||||
(= 0 (process-exit-status process)))
|
||||
:success :failure))
|
||||
(process-exit-status process)
|
||||
proc-buf
|
||||
(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 &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,
|
||||
PROCESS-BUFFER, and INFO as arguments.
|
||||
- A function, which is called with EXIT-CODE, PROCESS-BUFFER,
|
||||
and INFO as arguments.
|
||||
- A list, which is either:
|
||||
- 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.
|
||||
|
||||
When BLOCKING is set, all callback tasks are made blocking."
|
||||
(cond
|
||||
((stringp callback)
|
||||
(message callback exit-code process-buffer info))
|
||||
((functionp callback)
|
||||
(funcall callback exit-code process-buffer info))
|
||||
((consp callback)
|
||||
(if (eq (car callback) 'org-async-task)
|
||||
(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 blocking))))
|
||||
((null callback)) ; Do nothing.
|
||||
(t (message "Ignoring invalid `org-async-call' callback: %S" callback))))
|
||||
|
||||
(defvar org-async--monitor-scheduled nil)
|
||||
(defun org-async--monitor (&optional force)
|
||||
"Check each process against their timeouts, and kill any overdue.
|
||||
The only runs when `org-async--monitor-scheduled' is nil, unless FORCE is set.
|
||||
Should any processes still be alive after checking the stack, this will run
|
||||
itself using a timer in `org-async-check-timeout-interval' seconds."
|
||||
(when (or force (null org-async--monitor-scheduled))
|
||||
(dolist (stack-proc org-async--stack)
|
||||
(if (process-live-p (car stack-proc))
|
||||
(let ((timeout (plist-get (cdr stack-proc) :timeout)))
|
||||
(when (and (numberp timeout)
|
||||
(< 0 timeout
|
||||
(- (float-time)
|
||||
(plist-get (cdr stack-proc) :start-time))))
|
||||
(kill-process (car stack-proc))))
|
||||
(org-async--cleanup-process (car stack-proc))))
|
||||
(if org-async--stack
|
||||
(setq org-async--monitor-scheduled
|
||||
(run-at-time org-async-check-timeout-interval
|
||||
nil #'org-async--monitor t))
|
||||
(setq org-async--monitor-scheduled nil))))
|
||||
|
||||
|
||||
;;; File
|
||||
|
@ -1626,7 +1898,9 @@ it for output."
|
|||
(cond
|
||||
((functionp command)
|
||||
(funcall command (shell-quote-argument relname)))
|
||||
((stringp command) (shell-command command log-buf)))))
|
||||
((stringp command)
|
||||
(let ((shell-command-dont-erase-buffer t))
|
||||
(shell-command command log-buf))))))
|
||||
;; Check for process failure. Output file is expected to be
|
||||
;; located in the same directory as SOURCE.
|
||||
(unless (org-file-newer-than-p output time)
|
||||
|
|
|
@ -83,6 +83,7 @@
|
|||
|
||||
;;; Customization
|
||||
|
||||
;;;###autoload
|
||||
(defcustom org-num-face nil
|
||||
"Face to use for numbering.
|
||||
When nil, use the same face as the headline. This value is
|
||||
|
@ -104,6 +105,7 @@ Any `face' text property on the returned string overrides
|
|||
:package-version '(Org . "9.3")
|
||||
:type 'function)
|
||||
|
||||
;;;###autoload
|
||||
(defcustom org-num-max-level nil
|
||||
"Level below which headlines are not numbered.
|
||||
When set to nil, all headlines are numbered."
|
||||
|
@ -113,6 +115,7 @@ When set to nil, all headlines are numbered."
|
|||
(integer :tag "Stop numbering at level"))
|
||||
:safe (lambda (val) (or (null val) (wholenump val))))
|
||||
|
||||
;;;###autoload
|
||||
(defcustom org-num-skip-commented nil
|
||||
"Non-nil means commented sub-trees are not numbered."
|
||||
:group 'org-appearance
|
||||
|
@ -120,6 +123,7 @@ When set to nil, all headlines are numbered."
|
|||
:type 'boolean
|
||||
:safe #'booleanp)
|
||||
|
||||
;;;###autoload
|
||||
(defcustom org-num-skip-footnotes nil
|
||||
"Non-nil means footnotes sections are not numbered."
|
||||
:group 'org-appearance
|
||||
|
@ -127,6 +131,7 @@ When set to nil, all headlines are numbered."
|
|||
:type 'boolean
|
||||
:safe #'booleanp)
|
||||
|
||||
;;;###autoload
|
||||
(defcustom org-num-skip-tags nil
|
||||
"List of tags preventing the numbering of sub-trees.
|
||||
|
||||
|
@ -141,6 +146,7 @@ control tag inheritance."
|
|||
:type '(repeat (string :tag "Tag"))
|
||||
:safe (lambda (val) (and (listp val) (cl-every #'stringp val))))
|
||||
|
||||
;;;###autoload
|
||||
(defcustom org-num-skip-unnumbered nil
|
||||
"Non-nil means numbering obeys to UNNUMBERED property."
|
||||
:group 'org-appearance
|
||||
|
|
|
@ -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.
|
||||
|
@ -1313,11 +1327,11 @@ such scenario."
|
|||
(defvar org-persist--refresh-gc-lock-timer nil
|
||||
"Timer used to refresh session timestamp in `org-persist-gc-lock-file'.")
|
||||
|
||||
(when (and org-persist--disable-when-emacs-Q
|
||||
;; FIXME: This is relying on undocumented fact that
|
||||
;; Emacs sets `user-init-file' to nil when loaded with
|
||||
;; "-Q" argument.
|
||||
(not user-init-file))
|
||||
(unless (and org-persist--disable-when-emacs-Q
|
||||
;; FIXME: This is relying on undocumented fact that
|
||||
;; Emacs sets `user-init-file' to nil when loaded with
|
||||
;; "-Q" argument.
|
||||
(not user-init-file))
|
||||
(unless org-persist--refresh-gc-lock-timer
|
||||
(setq org-persist--refresh-gc-lock-timer
|
||||
(run-at-time nil org-persist-gc-lock-interval #'org-persist--refresh-gc-lock))))
|
||||
|
|
|
@ -809,9 +809,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
|
||||
|
||||
|
|
|
@ -467,16 +467,17 @@ prevents it from hanging Emacs."
|
|||
This may be useful when columns have been shrunk."
|
||||
(save-excursion
|
||||
(when pos (goto-char pos))
|
||||
(goto-char (line-beginning-position))
|
||||
(let ((end (line-end-position)) str)
|
||||
(goto-char (1- pos))
|
||||
(while (progn (forward-char 1) (< (point) end))
|
||||
(let ((ov (car (overlays-at (point)))))
|
||||
(if (not ov)
|
||||
(push (char-to-string (char-after)) str)
|
||||
(push (overlay-get ov 'display) str)
|
||||
(goto-char (1- (overlay-end ov))))))
|
||||
(format "|%s" (mapconcat #'identity (reverse str) "")))))
|
||||
(let* ((beg (line-beginning-position))
|
||||
(end (line-end-position))
|
||||
(str (buffer-substring beg end)))
|
||||
;; FIXME: This does not handle intersecting overlays.
|
||||
(dolist (ov (overlays-in beg end))
|
||||
(when (overlay-get ov 'display)
|
||||
(put-text-property
|
||||
(- (overlay-start ov) beg) (- (overlay-end ov) beg)
|
||||
'display (overlay-get ov 'display)
|
||||
str)))
|
||||
str)))
|
||||
|
||||
(defvar-local org-table-header-overlay nil)
|
||||
(put 'org-table-header-overlay 'permanent-local t)
|
||||
|
@ -487,19 +488,24 @@ This may be useful when columns have been shrunk."
|
|||
(progn
|
||||
(when (overlayp org-table-header-overlay)
|
||||
(delete-overlay org-table-header-overlay))
|
||||
;; We might be called after scrolling but before display is
|
||||
;; updated. Make sure that any queued redisplay is executed
|
||||
;; before we look into `window-start'.
|
||||
(redisplay)
|
||||
(let* ((ws (window-start))
|
||||
(beg (save-excursion
|
||||
(goto-char (org-table-begin))
|
||||
(while (or (org-at-table-hline-p)
|
||||
(looking-at-p ".*|\\s-+<[rcl]?\\([0-9]+\\)?>"))
|
||||
(move-beginning-of-line 2))
|
||||
(line-beginning-position)))
|
||||
(end (save-excursion (goto-char beg) (line-end-position))))
|
||||
(line-beginning-position))))
|
||||
(if (pos-visible-in-window-p beg)
|
||||
(when (overlayp org-table-header-overlay)
|
||||
(delete-overlay org-table-header-overlay))
|
||||
(setq org-table-header-overlay
|
||||
(make-overlay ws (+ ws (- end beg))))
|
||||
(make-overlay
|
||||
(save-excursion (goto-char ws) (line-beginning-position))
|
||||
(save-excursion (goto-char ws) (line-end-position))))
|
||||
(org-overlay-display
|
||||
org-table-header-overlay
|
||||
(org-table-row-get-visible-string beg)
|
||||
|
@ -4468,46 +4474,48 @@ Optional argument NEW may specify text to replace the current field content."
|
|||
(cond
|
||||
((and (not new) org-table-may-need-update)) ; Realignment will happen anyway
|
||||
((org-at-table-hline-p))
|
||||
((and (not new)
|
||||
(or (not (eq (marker-buffer org-table-aligned-begin-marker)
|
||||
(current-buffer)))
|
||||
(< (point) org-table-aligned-begin-marker)
|
||||
(>= (point) org-table-aligned-end-marker)))
|
||||
;; This is not the same table, force a full re-align.
|
||||
(setq org-table-may-need-update t))
|
||||
(t
|
||||
;; Realign the current field, based on previous full realign.
|
||||
(let ((pos (point))
|
||||
(col (org-table-current-column)))
|
||||
(when (> col 0)
|
||||
(skip-chars-backward "^|")
|
||||
(if (not (looking-at " *\\(?:\\([^|\n]*?\\) *\\(|\\)\\|\\([^|\n]+?\\) *\\($\\)\\)"))
|
||||
(setq org-table-may-need-update t)
|
||||
(let* ((align (nth (1- col) org-table-last-alignment))
|
||||
(width (nth (1- col) org-table-last-column-widths))
|
||||
(cell (match-string 0))
|
||||
(field (match-string 1))
|
||||
(properly-closed? (/= (match-beginning 2) (match-end 2)))
|
||||
(new-cell
|
||||
(save-match-data
|
||||
(cond (org-table-may-need-update
|
||||
(format " %s |" (or new field)))
|
||||
((not properly-closed?)
|
||||
(setq org-table-may-need-update t)
|
||||
(format " %s |" (or new field)))
|
||||
((not new)
|
||||
(concat (org-table--align-field field width align)
|
||||
"|"))
|
||||
((and width (<= (org-string-width new nil 'org-table) width))
|
||||
(concat (org-table--align-field new width align)
|
||||
"|"))
|
||||
(t
|
||||
(setq org-table-may-need-update t)
|
||||
(format " %s |" new))))))
|
||||
(unless (equal new-cell cell)
|
||||
(let (org-table-may-need-update)
|
||||
(replace-match new-cell t t)))
|
||||
(goto-char pos))))))))
|
||||
(when (or (not (eq (marker-buffer org-table-aligned-begin-marker)
|
||||
(current-buffer)))
|
||||
(< (point) org-table-aligned-begin-marker)
|
||||
(>= (point) org-table-aligned-end-marker))
|
||||
;; This is not the same table, force a full re-align.
|
||||
(setq org-table-may-need-update t
|
||||
org-table-last-alignment nil
|
||||
org-table-last-column-widths nil))
|
||||
(when new
|
||||
;; Realign the current field, based on previous full realign.
|
||||
(let ((pos (point))
|
||||
(col (org-table-current-column)))
|
||||
(when (> col 0)
|
||||
(skip-chars-backward "^|")
|
||||
(if (not (looking-at " *\\(?:\\([^|\n]*?\\) *\\(|\\)\\|\\([^|\n]+?\\) *\\($\\)\\)"))
|
||||
(setq org-table-may-need-update t)
|
||||
(let* ((align (nth (1- col) org-table-last-alignment))
|
||||
(width (nth (1- col) org-table-last-column-widths))
|
||||
(cell (match-string 0))
|
||||
(field (match-string 1))
|
||||
(properly-closed? (/= (match-beginning 2) (match-end 2)))
|
||||
(new-cell
|
||||
(save-match-data
|
||||
(cond (org-table-may-need-update
|
||||
(format " %s |" (or new field)))
|
||||
((not properly-closed?)
|
||||
(setq org-table-may-need-update t)
|
||||
(format " %s |" (or new field)))
|
||||
((not new)
|
||||
(concat (org-table--align-field field width align)
|
||||
"|"))
|
||||
((and width (<= (org-string-width new nil 'org-table) width))
|
||||
(concat (org-table--align-field new width align)
|
||||
"|"))
|
||||
(t
|
||||
(setq org-table-may-need-update t)
|
||||
(format " %s |" new))))))
|
||||
(unless (equal new-cell cell)
|
||||
(let (org-table-may-need-update)
|
||||
(replace-match new-cell t t)))
|
||||
(goto-char pos)))))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun org-table-sort-lines
|
||||
|
|
900
lisp/org.el
900
lisp/org.el
File diff suppressed because it is too large
Load Diff
|
@ -3,7 +3,6 @@
|
|||
;; Copyright (C) 2012-2024 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Nicolas Goaziou <n.goaziou at gmail dot com>
|
||||
;; Maintainer: Nicolas Goaziou <mail@nicolasgoaziou.fr>
|
||||
;; Keywords: outlines, hypermedia, calendar, wp
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
;; Author: Carsten Dominik <carsten.dominik AT gmail DOT com>
|
||||
;; Nicolas Goaziou <n.goaziou AT gmail DOT com>
|
||||
;; Maintainer: Nicolas Goaziou <mail@nicolasgoaziou.fr>
|
||||
;; Keywords: org, wp, tex
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
@ -513,6 +512,18 @@ used as a communication channel."
|
|||
(options (if raw-options
|
||||
(org-beamer--normalize-argument raw-options 'option)
|
||||
""))
|
||||
;; also process actions
|
||||
(raw-action (org-element-property :BEAMER_ACT headline))
|
||||
(action (if raw-action
|
||||
;; If BEAMER_act property has its value enclosed in square
|
||||
;; brackets, it is a default overlay specification and
|
||||
;; overlay specification is empty. Otherwise, it is an
|
||||
;; overlay specification and the default one is nil.
|
||||
(org-beamer--normalize-argument
|
||||
raw-action
|
||||
(if (string-match "\\`\\[.*\\]\\'" raw-action) 'defaction
|
||||
'action))
|
||||
""))
|
||||
;; Start a "columns" environment when explicitly requested or
|
||||
;; when there is no previous headline or the previous
|
||||
;; headline do not have a BEAMER_column property.
|
||||
|
@ -522,12 +533,12 @@ used as a communication channel."
|
|||
(or (equal environment "columns")
|
||||
(and column-width
|
||||
(not (and parent-env
|
||||
(equal (downcase parent-env) "columns")))
|
||||
(equal (downcase parent-env) "columns")))
|
||||
(or (org-export-first-sibling-p headline info)
|
||||
(not (org-element-property
|
||||
:BEAMER_COL
|
||||
(org-export-get-previous-element
|
||||
headline info)))))))
|
||||
:BEAMER_COL
|
||||
(org-export-get-previous-element
|
||||
headline info)))))))
|
||||
;; End the "columns" environment when explicitly requested or
|
||||
;; when there is no next headline or the next headline do not
|
||||
;; have a BEAMER_column property.
|
||||
|
@ -535,11 +546,11 @@ used as a communication channel."
|
|||
(or (equal environment "columns")
|
||||
(and column-width
|
||||
(not (and parent-env
|
||||
(equal (downcase parent-env) "columns")))
|
||||
(equal (downcase parent-env) "columns")))
|
||||
(or (org-export-last-sibling-p headline info)
|
||||
(not (org-element-property
|
||||
:BEAMER_COL
|
||||
(org-export-get-next-element headline info))))))))
|
||||
:BEAMER_COL
|
||||
(org-export-get-next-element headline info))))))))
|
||||
(concat
|
||||
(when start-columns-p
|
||||
;; Column can accept options only when the environment is
|
||||
|
@ -547,10 +558,13 @@ used as a communication channel."
|
|||
(if (not (equal environment "columns")) "\\begin{columns}\n"
|
||||
(format "\\begin{columns}%s\n" options)))
|
||||
(when column-width
|
||||
(format "\\begin{column}%s{%s}\n"
|
||||
(format "\\begin{column}%s%s{%s}\n"
|
||||
;; One can specify placement for column only when
|
||||
;; HEADLINE stands for a column on its own.
|
||||
(if (equal environment "column") options "")
|
||||
options
|
||||
(if env-format
|
||||
"" ; Inner environment is specified - pass actions later.
|
||||
action)
|
||||
(format "%s\\columnwidth" column-width)))
|
||||
;; Block's opening string.
|
||||
(when (nth 2 env-format)
|
||||
|
@ -558,23 +572,18 @@ used as a communication channel."
|
|||
(org-fill-template
|
||||
(nth 2 env-format)
|
||||
(nconc
|
||||
;; If BEAMER_act property has its value enclosed in square
|
||||
;; brackets, it is a default overlay specification and
|
||||
;; overlay specification is empty. Otherwise, it is an
|
||||
;; overlay specification and the default one is nil.
|
||||
(let ((action (org-element-property :BEAMER_ACT headline)))
|
||||
(cond
|
||||
((not action) (list (cons "a" "") (cons "A" "") (cons "R" "")))
|
||||
((and (string-prefix-p "[" action)
|
||||
(string-suffix-p "]" action))
|
||||
(list
|
||||
(cons "A" (org-beamer--normalize-argument action 'defaction))
|
||||
(cons "a" "")
|
||||
(cons "R" action)))
|
||||
(t
|
||||
(list (cons "a" (org-beamer--normalize-argument action 'action))
|
||||
(cons "A" "")
|
||||
(cons "R" action)))))
|
||||
(cond
|
||||
((not action) (list (cons "a" "") (cons "A" "") (cons "R" "")))
|
||||
((and (string-prefix-p "[" action)
|
||||
(string-suffix-p "]" action))
|
||||
(list
|
||||
(cons "A" (org-beamer--normalize-argument action 'defaction))
|
||||
(cons "a" "")
|
||||
(cons "R" raw-action)))
|
||||
(t
|
||||
(list (cons "a" action)
|
||||
(cons "A" "")
|
||||
(cons "R" raw-action))))
|
||||
(list (cons "o" options)
|
||||
(cons "O" (or raw-options ""))
|
||||
(cons "h" title)
|
||||
|
@ -821,9 +830,7 @@ holding export options."
|
|||
;; Timestamp.
|
||||
(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)
|
||||
;; Document class and packages.
|
||||
;; Document class, packages, and some configuration.
|
||||
(org-latex-make-preamble info)
|
||||
;; Insert themes.
|
||||
(let ((format-theme
|
||||
|
@ -872,12 +879,6 @@ holding export options."
|
|||
(let ((template (plist-get info :latex-hyperref-template)))
|
||||
(and (stringp template)
|
||||
(format-spec template (org-latex--format-spec info))))
|
||||
;; engrave-faces-latex preamble
|
||||
(when (and (eq (plist-get info :latex-src-block-backend) 'engraved)
|
||||
(org-element-map (plist-get info :parse-tree)
|
||||
'(src-block inline-src-block) #'identity
|
||||
info t))
|
||||
(org-latex-generate-engraved-preamble info))
|
||||
;; Document start.
|
||||
"\\begin{document}\n\n"
|
||||
;; Title command.
|
||||
|
|
376
lisp/ox-html.el
376
lisp/ox-html.el
|
@ -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'; }
|
||||
|
@ -822,7 +826,7 @@ e.g. \"tex:mathjax\". Allowed values are:
|
|||
be loaded.
|
||||
`html' Use `org-latex-to-html-convert-command' to convert
|
||||
LaTeX fragments to HTML.
|
||||
SYMBOL Any symbol defined in `org-preview-latex-process-alist',
|
||||
SYMBOL Any symbol defined in `org-latex-preview-process-alist',
|
||||
e.g., `dvipng'."
|
||||
:group 'org-export-html
|
||||
:version "24.4"
|
||||
|
@ -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,36 @@ 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
|
||||
"Shell 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\".
|
||||
|
||||
The LaTeX fragment is replaced as is, without escaping special shell
|
||||
syntax. It may be necessary to use single-quotes around \\='%i\\=', not
|
||||
double-quotes. Else a math fragment such as \"$y = 200$\" may be
|
||||
expanded to \" = 200\"."
|
||||
: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 +1830,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)))
|
||||
|
@ -2682,7 +2731,10 @@ information."
|
|||
(let ((attributes (org-export-read-attribute :attr_html example-block)))
|
||||
(if (plist-get attributes :textarea)
|
||||
(org-html--textarea-block example-block)
|
||||
(format "<pre class=\"example\"%s>\n%s</pre>"
|
||||
(if-let ((class-val (plist-get attributes :class)))
|
||||
(setq attributes (plist-put attributes :class (concat "example " class-val)))
|
||||
(setq attributes (plist-put attributes :class "example")))
|
||||
(format "<pre%s>\n%s</pre>"
|
||||
(let* ((reference (org-html--reference example-block info))
|
||||
(a (org-html--make-attribute-string
|
||||
(if (or (not reference) (plist-member attributes :id))
|
||||
|
@ -2991,58 +3043,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-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))))
|
||||
(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 +3170,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-preview-latex-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-preview-latex-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
|
||||
|
||||
|
|
813
lisp/ox-latex.el
813
lisp/ox-latex.el
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -3,7 +3,6 @@
|
|||
;; Copyright (C) 2012-2024 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Nicolas Goaziou <n.goaziou@gmail.com>
|
||||
;; Maintainer: Nicolas Goaziou <mail@nicolasgoaziou.fr>
|
||||
;; Keywords: org, wp, markdown
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
@ -152,8 +151,8 @@ headings for its own use."
|
|||
TREE is the parse tree being exported. BACKEND is the export
|
||||
backend used. INFO is a plist used as a communication channel.
|
||||
|
||||
Enforce a blank line between elements. There are two exceptions
|
||||
to this rule:
|
||||
Enforce a blank line between elements. There are exceptions to this
|
||||
rule:
|
||||
|
||||
1. Preserve blank lines between sibling items in a plain list,
|
||||
|
||||
|
@ -161,8 +160,12 @@ to this rule:
|
|||
paragraph and the next sub-list when the latter ends the
|
||||
current item.
|
||||
|
||||
3. Do not add blank lines after table rows. (This is irrelevant for
|
||||
md exporter, but may surprise derived backends).
|
||||
|
||||
Assume BACKEND is `md'."
|
||||
(org-element-map tree (remq 'item org-element-all-elements)
|
||||
(org-element-map tree
|
||||
(remq 'table-row (remq 'item org-element-all-elements))
|
||||
(lambda (e)
|
||||
(org-element-put-property
|
||||
e :post-blank
|
||||
|
|
258
lisp/ox-odt.el
258
lisp/ox-odt.el
|
@ -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))
|
||||
|
@ -3712,114 +3713,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-format-latex cache-subdir nil nil cache-dir
|
||||
nil display-msg nil
|
||||
processing-type)
|
||||
(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)
|
||||
|
||||
|
||||
|
@ -4146,7 +4180,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.
|
||||
|
@ -4322,15 +4356,15 @@ The list of the form (OUTPUT-FMT-1 OUTPUT-FMT-2 ...)."
|
|||
(defun org-odt-convert-read-params ()
|
||||
"Return IN-FILE and OUT-FMT params for `org-odt-do-convert'.
|
||||
This is a helper routine for interactive use."
|
||||
(let* ((input (if (featurep 'ido) 'ido-completing-read 'completing-read))
|
||||
(in-file (read-file-name "File to be converted: "
|
||||
(let* ((in-file (read-file-name "File to be converted: "
|
||||
nil buffer-file-name t))
|
||||
(in-fmt (file-name-extension in-file))
|
||||
(out-fmt-choices (org-odt-reachable-formats in-fmt))
|
||||
(out-fmt
|
||||
(or (and out-fmt-choices
|
||||
(funcall input "Output format: "
|
||||
out-fmt-choices nil nil nil))
|
||||
(completing-read
|
||||
"Output format: "
|
||||
out-fmt-choices nil nil nil))
|
||||
(error
|
||||
"No known converter or no known output formats for %s files"
|
||||
in-fmt))))
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
;; Copyright (C) 2013-2024 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Nicolas Goaziou <n.goaziou@gmail.com>
|
||||
;; Maintainer: Nicolas Goaziou <mail@nicolasgoaziou.fr>
|
||||
;; Keywords: org, wp
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
@ -54,6 +53,20 @@ setting of `org-html-htmlize-output-type' is `css'."
|
|||
(const :tag "Don't include external stylesheet link" nil)
|
||||
(string :tag "URL or local href")))
|
||||
|
||||
(defcustom org-org-with-special-rows t
|
||||
"Non-nil means export special table rows.
|
||||
Special rows are the rows containing special marking characters, as
|
||||
described in the Info node `(org)Advanced features'."
|
||||
:group 'org-export-org
|
||||
:type 'boolean
|
||||
:package-version '(Org . "9.7"))
|
||||
|
||||
(defcustom org-org-with-cite-processors nil
|
||||
"Non-nil means use citation processors when exporting citations."
|
||||
:group 'org-export-org
|
||||
:type 'boolean
|
||||
:package-version '(Org . "9.7"))
|
||||
|
||||
(org-export-define-backend 'org
|
||||
'((babel-call . org-org-identity)
|
||||
(bold . org-org-identity)
|
||||
|
@ -75,6 +88,8 @@ setting of `org-html-htmlize-output-type' is `css'."
|
|||
(inline-src-block . org-org-identity)
|
||||
(inlinetask . org-org-identity)
|
||||
(italic . org-org-identity)
|
||||
(citation . org-org-identity)
|
||||
(citation-reference . org-org-identity)
|
||||
(item . org-org-identity)
|
||||
(keyword . org-org-keyword)
|
||||
(latex-environment . org-org-identity)
|
||||
|
@ -112,7 +127,11 @@ setting of `org-html-htmlize-output-type' is `css'."
|
|||
(lambda (a s v b)
|
||||
(if a (org-org-export-to-org t s v b)
|
||||
(org-open-file (org-org-export-to-org nil s v b)))))))
|
||||
:filters-alist '((:filter-parse-tree . org-org--add-missing-sections)))
|
||||
:filters-alist '((:filter-parse-tree . org-org--add-missing-sections))
|
||||
:options-alist
|
||||
;; Export special table rows.
|
||||
'((:with-special-rows nil nil org-org-with-special-rows)
|
||||
(:with-cite-processors nil nil org-org-with-cite-processors)))
|
||||
|
||||
(defun org-org--add-missing-sections (tree _backend _info)
|
||||
"Ensure each headline has an associated section.
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
;; Copyright (C) 2006-2024 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: David O'Toole <dto@gnu.org>
|
||||
;; Maintainer: Nicolas Goaziou <mail@nicolasgoaziou.fr>
|
||||
;; Keywords: hypermedia, outlines, wp
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
;; Copyright (C) 2012-2024 Free Software Foundation, Inc.
|
||||
;; Author: Jonathan Leech-Pepin <jonathan.leechpepin at gmail dot com>
|
||||
;; Maintainer: Nicolas Goaziou <mail@nicolasgoaziou.fr>
|
||||
;; Keywords: outlines, hypermedia, calendar, wp
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
|
652
lisp/ox.el
652
lisp/ox.el
|
@ -3,7 +3,7 @@
|
|||
;; Copyright (C) 2012-2024 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Nicolas Goaziou <mail@nicolasgoaziou.fr>
|
||||
;; Maintainer: Nicolas Goaziou <mail@nicolasgoaziou.fr>
|
||||
;; Maintainer: Ihor Radchenko <yantar92 at posteo dot net>
|
||||
;; Keywords: outlines, hypermedia, calendar, wp
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
@ -140,6 +140,7 @@
|
|||
(:with-properties nil "prop" org-export-with-properties)
|
||||
(:with-smart-quotes nil "'" org-export-with-smart-quotes)
|
||||
(:with-special-strings nil "-" org-export-with-special-strings)
|
||||
(:with-special-rows nil nil nil)
|
||||
(:with-statistics-cookies nil "stat" org-export-with-statistics-cookies)
|
||||
(:with-sub-superscript nil "^" org-export-with-sub-superscripts)
|
||||
(:with-toc nil "toc" org-export-with-toc)
|
||||
|
@ -150,6 +151,7 @@
|
|||
(:with-title nil "title" org-export-with-title)
|
||||
(:with-todo-keywords nil "todo" org-export-with-todo-keywords)
|
||||
;; Citations processing.
|
||||
(:with-cite-processors nil nil org-export-process-citations)
|
||||
(:cite-export "CITE_EXPORT" nil org-cite-export-processors))
|
||||
"Alist between export properties and ways to set them.
|
||||
|
||||
|
@ -385,6 +387,14 @@ e.g. \"date:nil\"."
|
|||
:type 'boolean
|
||||
:safe #'booleanp)
|
||||
|
||||
(defcustom org-export-process-citations t
|
||||
"Non-nil means process citations using citation processors.
|
||||
nil will leave citation processing to export backend."
|
||||
:group 'org-export-general
|
||||
:type 'boolean
|
||||
:package-version '(Org . "9.7")
|
||||
:safe #'booleanp)
|
||||
|
||||
(defcustom org-export-date-timestamp-format nil
|
||||
"Timestamp format string to use for DATE keyword.
|
||||
|
||||
|
@ -1050,7 +1060,7 @@ mode."
|
|||
|
||||
(cl-defstruct (org-export-backend (:constructor org-export-create-backend)
|
||||
(:copier nil))
|
||||
name parent transcoders options filters blocks menu)
|
||||
name parent transcoders options filters blocks menu feature-conditions feature-implementations)
|
||||
|
||||
;;;###autoload
|
||||
(defun org-export-get-backend (name)
|
||||
|
@ -1156,6 +1166,62 @@ returns filters inherited from parent backends, if any."
|
|||
(setq filters (append filters (org-export-backend-filters backend))))
|
||||
filters)))
|
||||
|
||||
(defvar org-export-conditional-features)
|
||||
|
||||
(defun org-export-get-all-feature-conditions (backend)
|
||||
"Return full feature condition alist for BACKEND.
|
||||
|
||||
BACKEND is an export back-end, as return by, e.g,,
|
||||
`org-export-create-backend'. Return value is an alist where keys
|
||||
are feature conditions, and values are feature symbols.
|
||||
|
||||
Unlike `org-export-backend-feature-conditions', this function
|
||||
also returns conditions inherited from parent back-ends, if any."
|
||||
(when (symbolp backend) (setq backend (org-export-get-backend backend)))
|
||||
(and backend
|
||||
(let ((conditions (org-export-backend-feature-conditions backend))
|
||||
parent)
|
||||
(while (setq parent (org-export-backend-parent backend))
|
||||
(setq backend (org-export-get-backend parent))
|
||||
(dolist (condition (org-export-backend-feature-conditions backend))
|
||||
(push condition conditions)))
|
||||
(dolist (condition org-export-conditional-features)
|
||||
(unless (assq (car condition) conditions)
|
||||
(push condition conditions)))
|
||||
conditions)))
|
||||
|
||||
(defun org-export-get-all-feature-implementations (backend)
|
||||
"Return full feature implementation alist for BACKEND.
|
||||
|
||||
BACKEND is an export back-end, as return by, e.g,,
|
||||
`org-export-create-backend'. Return value is an alist where keys
|
||||
are feature symbols, and values are an implementation
|
||||
specification plist.
|
||||
|
||||
Unlike `org-export-backend-feature-implementations', this function
|
||||
also returns implementations inherited from parent back-ends, if any."
|
||||
(when (symbolp backend) (setq backend (org-export-get-backend backend)))
|
||||
(and backend
|
||||
(let ((implementations (org-export-backend-feature-implementations backend))
|
||||
parent)
|
||||
(while (setq parent (org-export-backend-parent backend))
|
||||
(setq backend (org-export-get-backend parent))
|
||||
(dolist (implementation (org-export-backend-feature-implementations backend))
|
||||
(unless (assq (car implementation) implementations)
|
||||
(push implementation implementations))))
|
||||
implementations)))
|
||||
|
||||
(defun org-export-install-features (info)
|
||||
"Install feature conditions and implementations in the communication channel.
|
||||
INFO is a plist containing the current communication channel.
|
||||
Return the updated communication channel."
|
||||
(plist-put info :feature-conditions
|
||||
(org-export-get-all-feature-conditions
|
||||
(plist-get info :back-end)))
|
||||
(plist-put info :feature-implementations
|
||||
(org-export-get-all-feature-implementations
|
||||
(plist-get info :back-end))))
|
||||
|
||||
(defun org-export-define-backend (backend transcoders &rest body)
|
||||
"Define a new backend BACKEND.
|
||||
|
||||
|
@ -1267,20 +1333,24 @@ keywords are understood:
|
|||
`org-export-options-alist' for more information about
|
||||
structure of the values."
|
||||
(declare (indent 1))
|
||||
(let (filters menu-entry options)
|
||||
(let (filters menu-entry options feature-conditions feature-implementations)
|
||||
(while (keywordp (car body))
|
||||
(let ((keyword (pop body)))
|
||||
(pcase keyword
|
||||
(:filters-alist (setq filters (pop body)))
|
||||
(:menu-entry (setq menu-entry (pop body)))
|
||||
(:options-alist (setq options (pop body)))
|
||||
(:feature-conditions-alist (setq feature-conditions (pop body)))
|
||||
(:feature-implementations-alist (setq feature-implementations (pop body)))
|
||||
(_ (error "Unknown keyword: %s" keyword)))))
|
||||
(org-export-register-backend
|
||||
(org-export-create-backend :name backend
|
||||
:transcoders transcoders
|
||||
:options options
|
||||
:filters filters
|
||||
:menu menu-entry))))
|
||||
:menu menu-entry
|
||||
:feature-conditions feature-conditions
|
||||
:feature-implementations feature-implementations))))
|
||||
|
||||
(defun org-export-define-derived-backend (child parent &rest body)
|
||||
"Create a new backend as a variant of an existing one.
|
||||
|
@ -1327,7 +1397,7 @@ The backend could then be called with, for example:
|
|||
|
||||
(org-export-to-buffer \\='my-latex \"*Test my-latex*\")"
|
||||
(declare (indent 2))
|
||||
(let (filters menu-entry options transcoders)
|
||||
(let (filters menu-entry options transcoders feature-conditions feature-implementations)
|
||||
(while (keywordp (car body))
|
||||
(let ((keyword (pop body)))
|
||||
(pcase keyword
|
||||
|
@ -1335,6 +1405,8 @@ The backend could then be called with, for example:
|
|||
(:menu-entry (setq menu-entry (pop body)))
|
||||
(:options-alist (setq options (pop body)))
|
||||
(:translate-alist (setq transcoders (pop body)))
|
||||
(:feature-conditions-alist (setq feature-conditions (pop body)))
|
||||
(:feature-implementations-alist (setq feature-implementations (pop body)))
|
||||
(_ (error "Unknown keyword: %s" keyword)))))
|
||||
(org-export-register-backend
|
||||
(org-export-create-backend :name child
|
||||
|
@ -1342,7 +1414,9 @@ The backend could then be called with, for example:
|
|||
:transcoders transcoders
|
||||
:options options
|
||||
:filters filters
|
||||
:menu menu-entry))))
|
||||
:menu menu-entry
|
||||
:feature-conditions feature-conditions
|
||||
:feature-implementations feature-implementations))))
|
||||
|
||||
|
||||
|
||||
|
@ -1838,7 +1912,9 @@ not exported."
|
|||
(and (org-export-table-has-special-column-p
|
||||
(org-element-lineage datum 'table))
|
||||
(org-export-first-sibling-p datum options)))
|
||||
(table-row (org-export-table-row-is-special-p datum options))
|
||||
(table-row
|
||||
(unless (plist-get options :with-special-rows)
|
||||
(org-export-table-row-is-special-p datum options)))
|
||||
(timestamp
|
||||
;; `:with-timestamps' only applies to isolated timestamps
|
||||
;; objects, i.e. timestamp objects in a paragraph containing only
|
||||
|
@ -2043,6 +2119,550 @@ keywords before output."
|
|||
(funcall (intern (format "org-element-%s-interpreter" type))
|
||||
blob contents))))
|
||||
|
||||
|
||||
;;; Conditional/Generated Features
|
||||
;;
|
||||
;; Many formats have some version of a preamble, whether it be HTML's
|
||||
;; <head>...</head> or the content before LaTeX's \begin{document}.
|
||||
;; Depending on the particular features in the Org document being
|
||||
;; exported, different setup snippets will be needed. There's the
|
||||
;; "everything and the kitchen sink" approach of adding absolutely
|
||||
;; everything that might be needed, and the post-translation editing
|
||||
;; with filters approach, but neither really solve this problem nicely.
|
||||
;;
|
||||
;; The conditional/generated preamble defines mechanisms of detecting
|
||||
;; which "export features" are used in a document, handles
|
||||
;; interactions between features, and provides/generates content to
|
||||
;; support the features.
|
||||
;;
|
||||
;; Each export feature condition takes the form of a
|
||||
;; (CONDITION . FEATURES) cons cell (see `org-export-detect-features'),
|
||||
;; and each implementation takes the form of a (FEATURE . (:KEY VALUE ...))
|
||||
;; associated plist (see `org-export-resolve-feature-implementations'
|
||||
;; and `org-export-expand-feature-snippets').
|
||||
;;
|
||||
;; This functionality is applied during export as follows:
|
||||
;; 1. The export feature conditions and implementations are installed
|
||||
;; into the INFO plist with `org-export-install-features'.
|
||||
;; This simply applies `org-export-get-all-feature-conditions' and
|
||||
;; `org-export-get-all-feature-implementations', which merges the
|
||||
;; backend's conditions/implementations with all of it's parents and
|
||||
;; finally the global condition list
|
||||
;; `org-export-conditional-features'.
|
||||
;; 2. The "export features" used in a document are detected with
|
||||
;; `org-export-detect-features'.
|
||||
;; 3. The interaction between different feature implementations is
|
||||
;; resolved with `org-export-resolve-feature-implementations',
|
||||
;; producing an ordered list of implementations to be actually used
|
||||
;; in an export.
|
||||
;; 4. The feature implementation's snippets are transformed into strings
|
||||
;; to be inserted with `org-export-expand-feature-snippets'.
|
||||
|
||||
(defcustom org-export-conditional-features
|
||||
`(("^[ \t]*#\\+print_bibliography:" bibliography)
|
||||
(,(lambda (info)
|
||||
(org-element-map (plist-get info :parse-tree)
|
||||
'link
|
||||
(lambda (link)
|
||||
(and (member (org-element-property :type link)
|
||||
'("http" "https" "ftp" "file"))
|
||||
(file-name-extension (org-element-property :path link))
|
||||
(member (downcase (file-name-extension
|
||||
(org-element-property :path link)))
|
||||
image-file-name-extensions)))
|
||||
info t))
|
||||
image)
|
||||
(,(lambda (info)
|
||||
(org-element-map (plist-get info :parse-tree)
|
||||
'table #'identity info t))
|
||||
table)
|
||||
(,(lambda (info)
|
||||
(org-element-map (plist-get info :parse-tree)
|
||||
'(src-block inline-src-block) #'identity info t))
|
||||
code))
|
||||
"Org feature tests and associated feature flags.
|
||||
|
||||
Alist where the car is a test for the presense of the feature,
|
||||
and the CDR is either a single feature symbol or a list of
|
||||
feature symbols.
|
||||
|
||||
See `org-export-detect-features' for how this is processed."
|
||||
:group 'org-export-general
|
||||
:type '(alist :key-type
|
||||
(choice (regexp :tag "Feature test regexp")
|
||||
(variable :tag "Feature variable")
|
||||
(function :tag "Feature test function"))
|
||||
:value-type
|
||||
(repeat symbol :tag "Feature symbols")))
|
||||
|
||||
(defun org-export-detect-features (info)
|
||||
"Detect features from `org-export-conditional-features' in INFO.
|
||||
|
||||
More specifically, for each (CONDITION . FEATURES) cons cell of
|
||||
the :feature-conditions list in INFO, the CONDITION is evaluated
|
||||
in two phases.
|
||||
|
||||
In phase one, CONDITION is transformed like so:
|
||||
- If a variable symbol, the value is fetched
|
||||
- If a function symbol, the function is called with INFO as the
|
||||
sole argument
|
||||
- If a string, passed on unmodified
|
||||
|
||||
In phase two, if the CONDITION result is a string, it is used as
|
||||
a case-sensitive regexp search in the buffer. The regexp
|
||||
matching is taken as confirmation of the existance of FEATURES.
|
||||
Any other non-nil value indicates the existance of FEATURES.
|
||||
|
||||
A list of all detected feature symbols is returned.
|
||||
|
||||
This function should be run in the processed export Org buffer,
|
||||
after includes have been expanded and commented trees removed."
|
||||
(delete-dups
|
||||
(cl-loop
|
||||
for (condition . features) in (plist-get info :feature-conditions)
|
||||
for matcher =
|
||||
(cond
|
||||
((stringp condition) condition)
|
||||
((functionp condition) (funcall condition info))
|
||||
((symbolp condition) (symbol-value condition))
|
||||
(t (error "org-export: Feature condition %s (for %s) unable to be used"
|
||||
condition features)))
|
||||
for active-features =
|
||||
(and (if (stringp matcher)
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(re-search-forward matcher nil t))
|
||||
matcher)
|
||||
(copy-sequence features))
|
||||
when active-features
|
||||
nconc active-features)))
|
||||
|
||||
(define-error 'org-missing-feature-dependency
|
||||
"A feature was asked for, but is not availible")
|
||||
|
||||
(define-error 'org-circular-feature-dependency
|
||||
"There was a circular dependency between some features")
|
||||
|
||||
(defun org-export-resolve-feature-implementations (info &optional features implementations)
|
||||
"Resolve the IMPLEMENTATIONS of FEATURES, of INFO.
|
||||
|
||||
FEATURES should be a list of all feature symbols to be resolved,
|
||||
and defaults to (plist-get info :features). IMPLEMENTATIONS
|
||||
should be an alist of feature symbols and specification plists,
|
||||
and defaults to (plist-get info :feature-implementations).
|
||||
|
||||
The following keys of the each implementation plist are recognised:
|
||||
- :snippet, which is either,
|
||||
- A string, which should be included in the preamble verbatim.
|
||||
- A variable, the value of which should be included in the preamble.
|
||||
- A function, which is called with two arguments — the export info,
|
||||
and the list of feature flags. The returned value is included in
|
||||
the preamble.
|
||||
- :requires, a feature or list of features this feature will enable.
|
||||
- :when, a feature or list of features which are required for this
|
||||
feature to be active.
|
||||
- :prevents, a feature or list of features that should be masked.
|
||||
- :order, for when inclusion order matters. Feature implementations
|
||||
with a lower order appear first. The default is 0.
|
||||
- :after, a feature or list of features that must be preceding.
|
||||
- :before, a feature or list of features that must be succeeding.
|
||||
|
||||
This function processes :requires, :when, and :prevents in turn,
|
||||
sorting according by :order both before processing :requires and
|
||||
after processing :prevents. The final implementation list is
|
||||
returned."
|
||||
(let* ((explicit-features (or features (plist-get info :features)))
|
||||
(implementations (or implementations
|
||||
(plist-get info :feature-implementations)))
|
||||
(current-implementations
|
||||
(sort (cl-loop for feat in explicit-features
|
||||
collect (assq feat implementations))
|
||||
(lambda (a b)
|
||||
(< (or (plist-get (cdr a) :order) 0)
|
||||
(or (plist-get (cdr b) :order) 0)))))
|
||||
;; require-records serves to record /why/ a particular implementation
|
||||
;; is used. It takes the form of an alist with feature symbols as the
|
||||
;; keys, and a list of features that ask for that feature as values.
|
||||
;; A t value is used to indicate the feature has been explicitly
|
||||
;; required.
|
||||
(require-records
|
||||
(cl-loop for feat in explicit-features
|
||||
collect (list feat t))))
|
||||
;; * Process ~:requires~
|
||||
;; Here we temporarily treat current-implementations as a queue of
|
||||
;; unproceesed implementations, and for each implemention move
|
||||
;; it to processed-implementations if not already present.
|
||||
;; :requires are processed by being added to the current-implementations
|
||||
;; stack as they are seen. Along the way require-records is built for
|
||||
;; the sake of the subsequent :prevents processing.
|
||||
(let ((impl-queue-last (last current-implementations))
|
||||
processed-implementations impl)
|
||||
(while current-implementations
|
||||
(setq impl (pop current-implementations))
|
||||
(unless (memq impl processed-implementations)
|
||||
(push impl processed-implementations)
|
||||
(dolist (req (org-ensure-list
|
||||
(plist-get (cdar processed-implementations) :requires)))
|
||||
(unless (assq req processed-implementations)
|
||||
(let ((required-impl (assq req implementations)))
|
||||
(unless required-impl
|
||||
(signal 'org-missing-feature-dependency
|
||||
(format "The feature `%s' was asked for but could not be found"
|
||||
req)))
|
||||
(setq impl-queue-last
|
||||
(if current-implementations
|
||||
(setcdr impl-queue-last (list required-impl))
|
||||
(setq current-implementations (list required-impl))))
|
||||
(push (car impl) (alist-get req require-records)))))))
|
||||
(setq current-implementations
|
||||
(nreverse (delq nil processed-implementations))))
|
||||
;; * Process ~:when~
|
||||
;; More specifically, remove features with unfulfilled :when conditions.
|
||||
;; To correctly resolve all the various :when conditions,
|
||||
;; do not make any assumptions about which features are active.
|
||||
;; Initially only consider non-:when implementations to be
|
||||
;; active, then run through the list of unconfirmed :when
|
||||
;; implementations and check their conditions against the list
|
||||
;; of confirmed features. Continue doing this until no more
|
||||
;; features are confirmed.
|
||||
(let ((processing t)
|
||||
(confirmed-features
|
||||
(cl-remove-if ; Count unimplemented features as present.
|
||||
(lambda (feat) (assq feat current-implementations))
|
||||
explicit-features))
|
||||
conditional-implementations when)
|
||||
;; Sort all features by the presense of :when.
|
||||
(dolist (impl current-implementations)
|
||||
(if (plist-get (cdr impl) :when)
|
||||
(push impl conditional-implementations)
|
||||
(push (car impl) confirmed-features)))
|
||||
(while processing
|
||||
(setq processing nil)
|
||||
;; Check for implementations which have satisfied :when
|
||||
;; contions.
|
||||
(dolist (impl conditional-implementations)
|
||||
(setq when (plist-get (cdr impl) :when))
|
||||
(when (cond
|
||||
((symbolp when)
|
||||
(memq when confirmed-features))
|
||||
((consp when)
|
||||
(not (cl-set-difference when confirmed-features))))
|
||||
(push (car impl) confirmed-features)
|
||||
(setq conditional-implementations
|
||||
(delq impl conditional-implementations)
|
||||
processing t))))
|
||||
;; Now all that remains is implementations with unsatisfiable
|
||||
;; :when conditions.
|
||||
(dolist (impl conditional-implementations)
|
||||
(setq current-implementations
|
||||
(delq impl current-implementations))))
|
||||
;; * Process ~:prevents~
|
||||
;; Go through every implementation and for prevented features
|
||||
;; 1. Remove them from current-implementations
|
||||
;; 2. Go through require-records and remove them from the cdrs.
|
||||
;; By modifying require-records in this way, features that are
|
||||
;; only present due to a now-prevented feature will have a
|
||||
;; nil cdr. We can then (recursively) check for these features
|
||||
;; with `rassq' and remove them.
|
||||
;; Since we used a queue rather than a stack when processing
|
||||
;; :requires, we know that second order requires (i.e. :requires
|
||||
;; of :requires) will come after after first order requires.
|
||||
;; This means that should a n-th order require be prevented by
|
||||
;; (n-1)-th order require, it will be removed before being
|
||||
;; processed, and hence handled correctly.
|
||||
(let (feats-to-remove removed null-require)
|
||||
(dolist (impl current-implementations)
|
||||
(setq feats-to-remove (org-ensure-list (plist-get (cdr impl) :prevents)))
|
||||
(while feats-to-remove
|
||||
;; Remove each of feats-to-remove.
|
||||
(dolist (feat feats-to-remove)
|
||||
(unless (memq feat removed)
|
||||
(push feat removed)
|
||||
(setq current-implementations
|
||||
(delq (assq feat current-implementations)
|
||||
current-implementations))
|
||||
(when (assq feat require-records)
|
||||
(setq require-records
|
||||
(delq (assq feat require-records) require-records)))))
|
||||
(dolist (rec require-records)
|
||||
(setcdr rec (cl-set-difference (cdr rec) feats-to-remove)))
|
||||
;; The features have now been removed.
|
||||
(setq feats-to-remove nil)
|
||||
;; Look for orphan requires.
|
||||
(when (setq null-require (rassq nil require-records))
|
||||
(push (car null-require) feats-to-remove)))))
|
||||
;; Re-sort by ~:order~, to position reqirued features correctly.
|
||||
(setq current-implementations
|
||||
(sort current-implementations
|
||||
(lambda (a b)
|
||||
(< (or (plist-get (cdr a) :order) 0)
|
||||
(or (plist-get (cdr b) :order) 0)))))
|
||||
;; * Processing ~:before~ and ~:after~
|
||||
;; To resolve dependency order, we will now perform a stable topological
|
||||
;; sort on any DAGs that exist within current-implementations.
|
||||
(org-export--feature-implementation-toposort
|
||||
current-implementations)))
|
||||
|
||||
(defun org-export--feature-implementation-toposort (implementations)
|
||||
"Perform a stable topological sort of IMPLEMENTATIONS.
|
||||
The sort is performed based on the :before and :after properties.
|
||||
|
||||
See <https://en.wikipedia.org/wiki/Topological_sorting> for more information
|
||||
on what this entails."
|
||||
(let ((feature-indicies
|
||||
(cl-loop
|
||||
for elt in implementations
|
||||
and index from 0
|
||||
collect (cons (car elt) index)))
|
||||
resolved-implementations
|
||||
adj-list node-stack)
|
||||
;; Build an adjacency list from :before and :after.
|
||||
(dolist (impl implementations)
|
||||
(push (list (car impl)) adj-list))
|
||||
(dolist (impl implementations)
|
||||
(let ((before (org-ensure-list (plist-get (cdr impl) :before)))
|
||||
(after (org-ensure-list (plist-get (cdr impl) :after))))
|
||||
(dolist (child before)
|
||||
(push (car impl) (cdr (assq child adj-list))))
|
||||
(when after
|
||||
(setcdr (assq (car impl) adj-list)
|
||||
(nconc (cdr (assq (car impl) adj-list))
|
||||
after)))))
|
||||
;; Initialise the node stack with the first implementation.
|
||||
(setq node-stack (list (car implementations))
|
||||
;; Make the order of adj-list match implementations.
|
||||
adj-list
|
||||
(mapcar
|
||||
(lambda (entry)
|
||||
(cons (car entry)
|
||||
;; Sort edges according to feature order, to do
|
||||
;; the DFS in order and make the result stable.
|
||||
(sort (cdr entry)
|
||||
(lambda (a b)
|
||||
(< (or (alist-get a feature-indicies)
|
||||
most-positive-fixnum)
|
||||
(or (alist-get b feature-indicies)
|
||||
most-positive-fixnum))))))
|
||||
(nreverse adj-list)))
|
||||
(while adj-list
|
||||
(let ((deps (alist-get (caar node-stack) adj-list))
|
||||
new-dep-found)
|
||||
;; Look for any unresolved dependencies.
|
||||
(while (and deps (not new-dep-found))
|
||||
(if (not (assq (car deps) adj-list))
|
||||
(setq deps (cdr deps))
|
||||
;; Check the unresolved dependency is not part of a cycle.
|
||||
(when (assq (car deps) node-stack)
|
||||
(signal 'org-circular-feature-dependency
|
||||
(format "Found a cycle in the feature dependency graph: %S"
|
||||
(cons (car deps)
|
||||
(nreverse (memq (car deps)
|
||||
(nreverse
|
||||
(mapcar #'car node-stack))))))))
|
||||
;; Push the unresolved dependency to the top of the stack.
|
||||
(push (assq (car deps) implementations)
|
||||
node-stack)
|
||||
(setq new-dep-found t)))
|
||||
(unless new-dep-found
|
||||
;; The top item of the stack has no unresolved dependencies.
|
||||
;; Move it to the resolved list, and remove its entry from
|
||||
;; adj-list to both mark it as such and ensure that
|
||||
;; node-stack will not be incremented to it when/if the
|
||||
;; stack is emptied.
|
||||
(push (car node-stack) resolved-implementations)
|
||||
(setq adj-list
|
||||
(delq (assq (caar node-stack) adj-list) adj-list)
|
||||
node-stack
|
||||
(or (cdr node-stack)
|
||||
(list (assq (caar adj-list) implementations)))))))
|
||||
(nreverse resolved-implementations)))
|
||||
|
||||
(defun org-export-expand-feature-snippets (info &rest feature-implementations)
|
||||
"Expand each of the feature :snippet keys in FEATURE-IMPLEMENTATIONS.
|
||||
FEATURE-IMPLEMENTATIONS is expected to be a list of implementation
|
||||
plists, if not provided explicitly it is extracted from the
|
||||
:feature-implementations key of INFO. Note that an explicitly
|
||||
provided nil FEATURE-IMPLEMENTATIONS is interpreted as no features.
|
||||
|
||||
Each implementation plist's :snippet value is expanded in order, in
|
||||
the following manner:
|
||||
- nil values are ignored
|
||||
- functions are called with INFO, and must produce a string or nil
|
||||
- variable symbols use the value, which must be a string or nil
|
||||
- strings are included verbatim
|
||||
- all other values throw an `error'.
|
||||
|
||||
\(fn INFO &optional FEATURE-IMPLEMENTATIONS)"
|
||||
(let ((feat-impls
|
||||
(cond
|
||||
((not feature-implementations)
|
||||
(plist-get info :feature-implementations))
|
||||
((= (length feature-implementations) 1)
|
||||
(car feature-implementations))
|
||||
(t (signal 'wrong-number-of-arguments
|
||||
`(org-export-expand-feature-snippets
|
||||
,(1+ (length feature-implementations)))))))
|
||||
expanded-snippets snippet value)
|
||||
(dolist (impl feat-impls)
|
||||
(setq snippet (plist-get (cdr impl) :snippet)
|
||||
value (cond
|
||||
((null snippet) nil)
|
||||
((functionp snippet) (funcall snippet info))
|
||||
((symbolp snippet) (symbol-value snippet))
|
||||
((stringp snippet) snippet)
|
||||
(t (error "org-export: The %s feature snippet %S is invalid (must be either nil, a function/variable symbol, or a string)"
|
||||
(car impl) snippet))))
|
||||
(cond
|
||||
((stringp value)
|
||||
(push value expanded-snippets))
|
||||
(value ; Non-string value, could come from function or variable.
|
||||
(error "org-export: The %s feature snippet %s must give nil or a string, but instead gave %S"
|
||||
(car impl)
|
||||
(cond
|
||||
((and (functionp snippet) (symbolp snippet))
|
||||
(format "function (`%s')" snippet))
|
||||
((functionp snippet) "anonymous function")
|
||||
(t (format "variable (`%s')" snippet)))
|
||||
value))))
|
||||
(nreverse expanded-snippets)))
|
||||
|
||||
(defun org-export-process-features (info)
|
||||
"Install feature conditions/implementations in INFO, and resolve them.
|
||||
See `org-export-detect-features' and `org-export-resolve-feature-implementations' for
|
||||
more information on what this entails."
|
||||
(org-export-install-features info)
|
||||
(let* ((exp-features (org-export-detect-features info))
|
||||
(resolved-implementations
|
||||
(org-export-resolve-feature-implementations info exp-features)))
|
||||
(plist-put info :feature-implementations resolved-implementations)
|
||||
(plist-put info :features (mapcar #'car resolved-implementations))))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro org-export-update-features (backend &rest feature-property-value-lists)
|
||||
"For BACKEND's export spec, set each FEATURE's :PROPERTY to VALUE.
|
||||
|
||||
The behaviour of this macro is best behaved with an example.
|
||||
For instance, to add some preamble content from the variable
|
||||
\"my-org-beamer-metropolis-tweaks\" when using the metropolis theme
|
||||
with beamer export:
|
||||
|
||||
(org-export-update-features \\='beamer
|
||||
(beamer-metropolis
|
||||
:condition (string-match-p \"metropolis$\" (plist-get info :beamer-theme))
|
||||
:snippet my-org-beamer-metropolis-tweaks
|
||||
:order 3))
|
||||
|
||||
The modifies the beamer backend, either creating or updating the
|
||||
\"beamer-metropolis\" feature. The :condition property adds a
|
||||
condition which detects the feature, and all other properties are
|
||||
applied to the feature's implementation plist. Setting
|
||||
:condition to t means the feature will always be enabled, and
|
||||
conversely setting :condition to nil means the feature will never
|
||||
be enabled.
|
||||
|
||||
When setting the :condition and :snippet properties, any sexp is
|
||||
is implicitly converted to,
|
||||
(lambda (info) SEXPR)
|
||||
|
||||
Each (FEATURE . (:PROPERTY VALUE)) form that is processed is
|
||||
taken from the single &rest argument
|
||||
FEATURE-PROPERTY-VALUE-LISTS.
|
||||
|
||||
\(fn BACKEND &rest (FEATURE . (:PROPERTY VALUE)...)...)"
|
||||
(declare (indent 1))
|
||||
(org-with-gensyms (backend-struct the-entry the-condition the-feat-impl cond-feat)
|
||||
(let ((backend-expr
|
||||
(if (and (eq (car-safe backend) 'quote)
|
||||
(symbolp (cadr backend))
|
||||
(not (cddr backend)))
|
||||
`(org-export-get-backend ',(cadr backend))
|
||||
`(if (symbolp ,backend)
|
||||
(org-export-get-backend ,backend)
|
||||
backend)))
|
||||
(backend-impls
|
||||
(list 'aref backend-struct
|
||||
(cl-struct-slot-offset 'org-export-backend 'feature-implementations)))
|
||||
(backend-conds
|
||||
(list 'aref backend-struct
|
||||
(cl-struct-slot-offset 'org-export-backend 'feature-conditions)))
|
||||
body condition-set-p implementation-set-p)
|
||||
(dolist (feature-property-value-set feature-property-value-lists)
|
||||
(when (eq (car feature-property-value-set) 'quote)
|
||||
(pop feature-property-value-set))
|
||||
(let ((features (car feature-property-value-set))
|
||||
(property-value-pairs (cdr feature-property-value-set))
|
||||
let-body property value)
|
||||
(while property-value-pairs
|
||||
(setq property (pop property-value-pairs)
|
||||
value (pop property-value-pairs))
|
||||
(cond
|
||||
((consp value)
|
||||
(unless (memq (car value) '(function quote))
|
||||
(if (and (memq property '(:condition :snippet))
|
||||
(not (functionp value)))
|
||||
(setq value `(lambda (info) ,value))
|
||||
(setq value (list 'quote value)))))
|
||||
((memq value '(nil t))) ; Leave unmodified.
|
||||
((symbolp value)
|
||||
(setq value (list 'quote value))))
|
||||
(if (eq property :condition)
|
||||
(progn
|
||||
(unless condition-set-p
|
||||
(setq condition-set-p t))
|
||||
(push
|
||||
(if value
|
||||
(let ((the-features (org-ensure-list features)))
|
||||
`(let* ((,the-condition ,value)
|
||||
(,the-entry (assoc ,the-condition ,backend-conds)))
|
||||
(if ,the-entry
|
||||
(setcdr ,the-entry
|
||||
(append ',the-features (cdr ,the-entry)))
|
||||
(push (cons ,the-condition ',the-features)
|
||||
,backend-conds))))
|
||||
(let ((single-feature
|
||||
(if (consp features)
|
||||
(intern (string-join (mapcar #'symbol-name features)
|
||||
"-and-"))
|
||||
features)))
|
||||
`(dolist (,cond-feat ,backend-conds)
|
||||
(cond
|
||||
((equal (cdr ,cond-feat) (list ',single-feature))
|
||||
(setf ,backend-conds (delq ,cond-feat ,backend-conds)))
|
||||
((memq ',single-feature (cdr ,cond-feat))
|
||||
(setcdr ,cond-feat
|
||||
(delq ',single-feature (cdr ,cond-feat))))))))
|
||||
body))
|
||||
(unless implementation-set-p
|
||||
(setq implementation-set-p t))
|
||||
(push
|
||||
(if let-body
|
||||
`(plist-put (cdr ,the-feat-impl) ,property ,value)
|
||||
`(setcdr ,the-feat-impl
|
||||
(plist-put (cdr ,the-feat-impl) ,property ,value)))
|
||||
let-body)))
|
||||
(when let-body
|
||||
(let ((the-feature
|
||||
(if (consp features)
|
||||
(intern (string-join (mapcar #'symbol-name features)
|
||||
"-and-"))
|
||||
features)))
|
||||
(when (consp features)
|
||||
(push
|
||||
`(plist-put (cdr ,the-feat-impl) :when ',features)
|
||||
let-body))
|
||||
(push
|
||||
`(let ((,the-feat-impl
|
||||
(or (assoc ',the-feature ,backend-impls)
|
||||
(car (push (list ',the-feature ,property nil)
|
||||
,backend-impls)))))
|
||||
,@(nreverse let-body))
|
||||
body)))))
|
||||
`(let ((,backend-struct ,backend-expr))
|
||||
,@(and (not (org-export-backend-p backend-expr))
|
||||
`((unless (org-export-backend-p ,backend-struct)
|
||||
(error "`%s' is not a loaded export backend" ,backend))))
|
||||
,@(nreverse body)
|
||||
nil))))
|
||||
|
||||
|
||||
;;; The Filter System
|
||||
|
@ -2922,6 +3542,9 @@ returned by the function."
|
|||
(backend &optional subtreep visible-only body-only ext-plist)
|
||||
"Transcode current Org buffer into BACKEND code.
|
||||
|
||||
See info node `(org)Advanced Export Configuration' for the details of
|
||||
the transcoding process.
|
||||
|
||||
BACKEND is either an export backend, as returned by, e.g.,
|
||||
`org-export-create-backend', or a symbol referring to
|
||||
a registered backend.
|
||||
|
@ -2998,7 +3621,8 @@ Return code as a string."
|
|||
(if (or (not (functionp template)) body-only) full-body
|
||||
(funcall template full-body info))))
|
||||
;; Call citation export finalizer.
|
||||
(setq output (org-cite-finalize-export output info))
|
||||
(when (plist-get info :with-cite-processors)
|
||||
(setq output (org-cite-finalize-export output info)))
|
||||
;; Remove all text properties since they cannot be
|
||||
;; retrieved from an external process. Finally call
|
||||
;; final-output filter and return result.
|
||||
|
@ -3068,8 +3692,9 @@ still inferior to file-local settings."
|
|||
info (org-export-get-environment backend subtreep ext-plist)))
|
||||
;; Pre-process citations environment, i.e. install
|
||||
;; bibliography list, and citation processor in INFO.
|
||||
(org-cite-store-bibliography info)
|
||||
(org-cite-store-export-processor info)
|
||||
(when (plist-get info :with-cite-processors)
|
||||
(org-cite-store-bibliography info)
|
||||
(org-cite-store-export-processor info))
|
||||
;; De-activate uninterpreted data from parsed keywords.
|
||||
(dolist (entry (append (org-export-get-all-options backend)
|
||||
org-export-options-alist))
|
||||
|
@ -3109,8 +3734,11 @@ still inferior to file-local settings."
|
|||
;; Process citations and bibliography. Replace each citation
|
||||
;; and "print_bibliography" keyword in the parse tree with
|
||||
;; the output of the selected citation export processor.
|
||||
(org-cite-process-citations info)
|
||||
(org-cite-process-bibliography info)
|
||||
(when (plist-get info :with-cite-processors)
|
||||
(org-cite-process-citations info)
|
||||
(org-cite-process-bibliography info))
|
||||
;; Install all the feature conditions and implementations.
|
||||
(org-export-process-features info)
|
||||
info))
|
||||
|
||||
;;;###autoload
|
||||
|
|
|
@ -69,13 +69,13 @@ REPRO_ARGS ?=
|
|||
##----------------------------------------------------------------------
|
||||
|
||||
# How to run tests
|
||||
req-ob-lang = --eval '(require '"'"'ob-$(ob-lang))'
|
||||
req-ob-lang = --eval '(require `ob-$(ob-lang))'
|
||||
lst-ob-lang = ($(ob-lang) . t)
|
||||
req-extra = --eval '(require '"'"'$(req))'
|
||||
req-extra = --eval '(require `$(req))'
|
||||
BTEST_RE ?= \\(org\\|ob\\|ox\\)
|
||||
BTEST_LOAD = \
|
||||
--eval '(add-to-list '"'"'load-path (concat default-directory "lisp"))' \
|
||||
--eval '(add-to-list '"'"'load-path (concat default-directory "testing"))'
|
||||
--eval '(add-to-list `load-path (concat default-directory "lisp"))' \
|
||||
--eval '(add-to-list `load-path (concat default-directory "testing"))'
|
||||
BTEST_INIT = $(BTEST_PRE) $(BTEST_LOAD) $(BTEST_POST)
|
||||
|
||||
BTEST = $(BATCH) $(BTEST_INIT) \
|
||||
|
@ -124,7 +124,7 @@ BATCH = $(EMACSQ) -batch \
|
|||
|
||||
# Emacs must be started in toplevel directory
|
||||
BATCHO = $(BATCH) \
|
||||
--eval '(add-to-list '"'"'load-path "./lisp")'
|
||||
--eval '(add-to-list `load-path "./lisp")'
|
||||
|
||||
# How to generate local.mk
|
||||
MAKE_LOCAL_MK = $(BATCHO) \
|
||||
|
@ -134,7 +134,7 @@ MAKE_LOCAL_MK = $(BATCHO) \
|
|||
|
||||
# Emacs must be started in lisp directory
|
||||
BATCHL = $(BATCH) \
|
||||
--eval '(add-to-list '"'"'load-path ".")'
|
||||
--eval '(add-to-list `load-path ".")'
|
||||
|
||||
# How to generate org-loaddefs.el
|
||||
MAKE_ORG_INSTALL = $(BATCHL) \
|
||||
|
@ -156,6 +156,10 @@ ELCDIR = $(BATCHL) \
|
|||
ELC = $(BATCHL) \
|
||||
--eval '(batch-byte-compile)'
|
||||
|
||||
# How to native-compile a single file
|
||||
ELN = $(BATCHL) \
|
||||
--eval '(batch-native-compile)'
|
||||
|
||||
# How to make a pdf file from a texinfo file
|
||||
TEXI2PDF = texi2pdf --batch --clean --expand
|
||||
|
||||
|
@ -199,9 +203,10 @@ SUDO = sudo
|
|||
INSTALL_INFO = install-info
|
||||
|
||||
# target method for 'compile'
|
||||
ORGCM = dirall
|
||||
ORGCM = single
|
||||
# ORGCM = dirall # 1x slowdown compared to default compilation method
|
||||
# ORGCM = single # 4x one Emacs process per compilation
|
||||
# ORGCM = native # 4x one Emacs process per native compilation
|
||||
# ORGCM = source # 5x ditto, but remove compiled file immediately
|
||||
# ORGCM = slint1 # 3x possibly elicit more warnings
|
||||
# ORGCM = slint2 # 7x possibly elicit even more warnings
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
.EXPORT_ALL_VARIABLES:
|
||||
.NOTPARALLEL: .PHONY
|
||||
# Additional distribution files
|
||||
DISTFILES_extra= Makefile etc
|
||||
|
||||
|
@ -27,7 +26,7 @@ ifneq ($(GITSTATUS),)
|
|||
GITVERSION := $(GITVERSION:.dirty=).dirty
|
||||
endif
|
||||
|
||||
.PHONY: all oldorg update update2 up0 up1 up2 single $(SUBDIRS) \
|
||||
.PHONY: all oldorg update update2 up0 up1 up2 single native $(SUBDIRS) \
|
||||
check test install $(INSTSUB) \
|
||||
info html pdf card refcard doc docs \
|
||||
autoloads cleanall clean $(CLEANDIRS:%=clean%) \
|
||||
|
@ -41,7 +40,7 @@ CONF_BASE = EMACS DESTDIR ORGCM ORG_MAKE_DOC
|
|||
CONF_DEST = lispdir infodir datadir testdir
|
||||
CONF_TEST = BTEST_PRE BTEST_POST BTEST_OB_LANGUAGES BTEST_EXTRA BTEST_RE
|
||||
CONF_EXEC = CP MKDIR RM RMR FIND CHMOD SUDO PDFTEX TEXI2PDF TEXI2HTML MAKEINFO INSTALL_INFO
|
||||
CONF_CALL = BATCH BATCHL ELC ELCDIR NOBATCH BTEST MAKE_LOCAL_MK MAKE_ORG_INSTALL MAKE_ORG_VERSION
|
||||
CONF_CALL = BATCH BATCHL ELC ELN ELCDIR NOBATCH BTEST MAKE_LOCAL_MK MAKE_ORG_INSTALL MAKE_ORG_VERSION
|
||||
config-eol:: EOL = \#
|
||||
config-eol:: config-all
|
||||
config config-all::
|
||||
|
@ -67,13 +66,16 @@ config config-test config-exe config-all config-version::
|
|||
@echo ""
|
||||
|
||||
oldorg: compile info # what the old makefile did when no target was specified
|
||||
uncompiled: cleanlisp autoloads # for developing
|
||||
uncompiled: | cleanlisp autoloads # for developing
|
||||
refcard: card
|
||||
update update2:: up0 all
|
||||
update update2:: | up0 all
|
||||
|
||||
single: ORGCM=single
|
||||
single: compile
|
||||
|
||||
native: ORGCM=native
|
||||
native: compile
|
||||
|
||||
.PRECIOUS: local.mk
|
||||
local.mk:
|
||||
$(info ======================================================)
|
||||
|
@ -126,7 +128,7 @@ $(INSTSUB):
|
|||
autoloads: lisp
|
||||
$(MAKE) -C $< $@
|
||||
|
||||
repro: cleanall autoloads
|
||||
repro: | cleanall autoloads
|
||||
-@$(REPRO) &
|
||||
|
||||
cleandirs:
|
||||
|
|
|
@ -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] \).
|
|
@ -0,0 +1,321 @@
|
|||
;;; test-duplicates-detector.el --- Tests for finding duplicates in Org tests -*- lexical-binding: t; -*-
|
||||
|
||||
;; Copyright (C) 2023 Ilya Chernyshov
|
||||
;; Authors: Ilya Chernyshov <ichernyshovvv@gmail.com>
|
||||
|
||||
;; 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/>.
|
||||
;;
|
||||
;;; Commentary:
|
||||
|
||||
;; Unit tests that check for duplicate forms and tests in all Org test files.
|
||||
|
||||
;; Forms are considered duplicate if they:
|
||||
|
||||
;; 1. are `equal-including-properties',
|
||||
;; 2. have the same nesting path,
|
||||
;; 3. either are `should-' macros or have `should-' macros inside.
|
||||
|
||||
;; To ignore a form or a group of forms, wrap them in
|
||||
;; `org-test-ignore-duplicate'.
|
||||
|
||||
;; `ert-deftest' are considered duplicate if their body are
|
||||
;; `equal-including-properties.' When comparing, the docstrings are not taken
|
||||
;; into account.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'org-test "../testing/org-test")
|
||||
|
||||
;;;; Variables
|
||||
|
||||
(defvar test-duplicates-progn-forms
|
||||
'( progn prog1 let dolist dotimes
|
||||
org-test-with-temp-text
|
||||
org-test-with-temp-text-in-file
|
||||
org-test-at-id
|
||||
org-test-ignore-duplicate)
|
||||
"List of forms equivalent to `progn'.
|
||||
Immediate children inside these are not checked for duplicates.")
|
||||
|
||||
(defvar test-duplicates-detector-file-path
|
||||
(expand-file-name "test-duplicates-detector.el"
|
||||
(expand-file-name "lisp" org-test-dir)))
|
||||
|
||||
(defvar test-duplicates-detector-files
|
||||
(remove
|
||||
test-duplicates-detector-file-path
|
||||
(directory-files
|
||||
(expand-file-name "lisp" org-test-dir) t "\\.el$")))
|
||||
|
||||
(defvar test-duplicates-detector-duplicate-forms nil
|
||||
"A list where each element is either:
|
||||
|
||||
((file test-name [(form-1 . numerical-order)
|
||||
(form-2 . numerical-order) ...])
|
||||
(dup-form-1 . (numerical-order [numerical-order ...]))
|
||||
[ (dup-form-2 . (numerical-order [numerical-order ...]))
|
||||
(dup-form-3 . (numerical-order [numerical-order ...]))
|
||||
...])
|
||||
|
||||
or
|
||||
|
||||
(test-1-symbol . duplicate-of-test-1-symbol)
|
||||
|
||||
|
||||
Where
|
||||
|
||||
(file test-name [(form-1 . numerical-order)
|
||||
(form-2 . numerical-order) ...])
|
||||
|
||||
is a path to duplicates. For example, the path for the
|
||||
duplicates in the following test:
|
||||
|
||||
test-file.el
|
||||
|
||||
(ertdeftest test-name ()
|
||||
\"Docstring.\"
|
||||
(let ((var-1 \"value\"))
|
||||
(when var-1
|
||||
(should-not
|
||||
(equal 2 (some-func \"string\" \"x\" nil)))
|
||||
(some-func \"string\" \"x=2\")
|
||||
(should-not
|
||||
(equal 2 (some-func \"string\" \"x\" nil)))
|
||||
(some-func \"string\" \"x=2\"))))
|
||||
|
||||
would look like this:
|
||||
|
||||
(\"/absolute/path/to/test-file.el\"
|
||||
test-name
|
||||
(let . 4) (when . 2))
|
||||
|
||||
And the records about the duplicates would look like this:
|
||||
|
||||
((should-not
|
||||
(equal 2 (some-func \"string\" \"x\" nil))) 4 2)")
|
||||
|
||||
(defvar test-duplicates-detector-forms nil
|
||||
"Nested alist of found forms and paths to them (not filtered).")
|
||||
|
||||
;;;; Macros
|
||||
|
||||
(defmacro org-test-ignore-duplicate (&rest body)
|
||||
"Eval BODY forms sequentially and return value of last one.
|
||||
|
||||
The macro's body will be ignored by `test-duplicates-detector.el'
|
||||
tests to skip duplicate forms inside the body."
|
||||
(declare (indent 0))
|
||||
`(progn ,@body))
|
||||
|
||||
;;;; ERT tests
|
||||
|
||||
(ert-deftest test-org-tests/find-duplicates ()
|
||||
"Try to find duplicate forms and ert-deftests in FILES."
|
||||
(should-not
|
||||
(test-duplicates-detector--find-duplicates
|
||||
test-duplicates-detector-files)))
|
||||
|
||||
;;;; Auxiliary functions
|
||||
|
||||
(defun test-duplicates-detector--find-duplicates (files)
|
||||
"Try to find duplicate forms and ert-deftests in FILES.
|
||||
|
||||
Duplicate forms will be written to
|
||||
`test-duplicates-detector-duplicate-forms'.
|
||||
|
||||
`message' paths to them in a human-readable format."
|
||||
(setq test-duplicates-detector-forms nil)
|
||||
(let (found-deftests duplicate-tests)
|
||||
(dolist (file files)
|
||||
(with-current-buffer (find-file-noselect file)
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(while (search-forward "(ert-deftest" nil t)
|
||||
(goto-char (match-beginning 0))
|
||||
(let (deftest test-name)
|
||||
(ignore-errors
|
||||
(while (setq deftest (read (current-buffer)))
|
||||
(setq test-name (cadr deftest))
|
||||
(when (eq (car deftest) 'ert-deftest)
|
||||
(if-let ((f (seq-find
|
||||
(lambda (x)
|
||||
(equal-including-properties
|
||||
;; if cadddr is a docstring
|
||||
(if (stringp (cadddr deftest))
|
||||
(cddddr deftest)
|
||||
(cdddr deftest))
|
||||
(if (stringp (cadddr x))
|
||||
(cddddr x)
|
||||
(cdddr x))))
|
||||
found-deftests)))
|
||||
(push (cons test-name (cadr f)) duplicate-tests)
|
||||
(push deftest found-deftests)
|
||||
(test-duplicates-detector--search-forms-recursively
|
||||
deftest (list file test-name)))))))))))
|
||||
(setq test-duplicates-detector-duplicate-forms
|
||||
(seq-filter
|
||||
#'cdr
|
||||
(mapcar
|
||||
(lambda (file)
|
||||
(cons
|
||||
(car file)
|
||||
(seq-filter
|
||||
(lambda (x)
|
||||
(and (caddr x)
|
||||
(seq-intersection
|
||||
'(should-not should should-error)
|
||||
(flatten-list (car x)))))
|
||||
(cdr file))))
|
||||
test-duplicates-detector-forms)))
|
||||
(when test-duplicates-detector-duplicate-forms
|
||||
(message
|
||||
"Found duplicates (To ignore the duplicate forms,
|
||||
wrap them in `org-test-ignore-duplicate'):
|
||||
%s"
|
||||
(mapconcat
|
||||
(lambda (path)
|
||||
(let* ((file (file-relative-name (caar path)))
|
||||
(test-name (symbol-name (cadar path)))
|
||||
(string-path (append (list file test-name)
|
||||
(mapcar (lambda (x)
|
||||
(symbol-name (car x)))
|
||||
(cddar path))))
|
||||
(indent -1)
|
||||
(print-level 3))
|
||||
(concat
|
||||
(mapconcat
|
||||
(lambda (x)
|
||||
(concat (make-string (* (setq indent (1+ indent)) 2) ? )
|
||||
x "\n"))
|
||||
string-path
|
||||
"")
|
||||
(mapconcat
|
||||
(lambda (x)
|
||||
(format "%s%S: %d times\n"
|
||||
(make-string (* indent 2) ? )
|
||||
(car x)
|
||||
(length (cdr x))))
|
||||
(cdr path)
|
||||
""))))
|
||||
test-duplicates-detector-duplicate-forms
|
||||
"")))
|
||||
(when duplicate-tests
|
||||
(message "Duplicate ERT tests found:\n%s\n"
|
||||
(mapconcat (lambda (x) (format "%S" x))
|
||||
duplicate-tests "\n")))
|
||||
(append test-duplicates-detector-duplicate-forms
|
||||
duplicate-tests)))
|
||||
|
||||
(defun test-duplicates-detector--search-forms-recursively (form form-path)
|
||||
"Search for forms recursively in FORM.
|
||||
|
||||
FORM-PATH is list of the form:
|
||||
(\"file-path\" ert-test-symbol
|
||||
(symbol-1 . sexp-order-1) (symbol-2 . sexp-order-2))
|
||||
|
||||
Write each form to `test-duplicates-detector-forms'"
|
||||
(let ((idx 0))
|
||||
(dolist (sub-form form)
|
||||
(when (consp sub-form)
|
||||
(unless (memq (car-safe form) test-duplicates-progn-forms)
|
||||
(push idx (alist-get
|
||||
sub-form
|
||||
(alist-get form-path test-duplicates-detector-forms
|
||||
nil nil #'equal)
|
||||
nil nil #'equal-including-properties)))
|
||||
(unless (memq (car sub-form)
|
||||
'(should-not should should-error))
|
||||
(test-duplicates-detector--search-forms-recursively
|
||||
sub-form
|
||||
(append form-path (list (cons (car sub-form) idx))))))
|
||||
(cl-incf idx))))
|
||||
|
||||
;;;; Testing the detector itself
|
||||
|
||||
(ert-deftest test-org-tests/test-duplicates-detector-testing-find-duplicates ()
|
||||
"Test `test-duplicates-detector--find-duplicates'."
|
||||
(should
|
||||
(equal
|
||||
(test-duplicates-detector--find-duplicates
|
||||
(list test-duplicates-detector-file-path))
|
||||
`(((,test-duplicates-detector-file-path
|
||||
test-org-tests/test-with-nested-duplicates)
|
||||
((let ((var "string")) (should (message "123 %s" var))) 6 4))
|
||||
((,test-duplicates-detector-file-path
|
||||
test-org-tests/test-with-duplicates-at-root)
|
||||
((should (message "123")) 6 4))
|
||||
(test-org-tests/duplicate-test-2 . test-org-tests/duplicate-test-1)))))
|
||||
|
||||
;;;;; Tests with duplicate forms
|
||||
|
||||
(ert-deftest test-org-tests/test-with-duplicates-at-root ()
|
||||
"Test with duplicates at the root."
|
||||
(should (message "123"))
|
||||
(format "%s" "string")
|
||||
(should
|
||||
(message "123")))
|
||||
|
||||
(ert-deftest test-org-tests/test-with-nested-duplicates ()
|
||||
"Test with nested duplicates."
|
||||
(let ((var "string"))
|
||||
(should
|
||||
(message "123 %s" var)))
|
||||
(format "%s" "string")
|
||||
(let ((var "string"))
|
||||
(should (message "123 %s" var)))
|
||||
(format "%s" "string"))
|
||||
|
||||
;;;;; Tests without duplicates
|
||||
|
||||
(ert-deftest test-org-tests/test-without-duplicates-1 ()
|
||||
"Test without duplicates."
|
||||
(let ((var-1 "asd"))
|
||||
(concat "string" var-1))
|
||||
(should
|
||||
(let ((var-1 "asd"))
|
||||
(concat "string" var-1))))
|
||||
|
||||
(ert-deftest test-org-tests/test-without-duplicates-2 ()
|
||||
"Test without duplicates.
|
||||
Equal `should' macros, but different nesting paths."
|
||||
(let ((var "string"))
|
||||
(should (format "123 %s" "asd")))
|
||||
(+ 5 6 9)
|
||||
(should (format "123 %s" "asd")))
|
||||
|
||||
;;;;; Duplicate deftests (maybe different names, but same body)
|
||||
|
||||
(ert-deftest test-org-tests/duplicate-test-1 ()
|
||||
"Docstring of duplicate-test-1."
|
||||
(let ((var 99))
|
||||
(+ 5 6 9 var)
|
||||
(should (format "123 %s" "asd")))
|
||||
(should (format "123 %s" "asd")))
|
||||
|
||||
(ert-deftest test-org-tests/duplicate-test-2 ()
|
||||
"Docstring of duplicate-test-2."
|
||||
(let ((var 99))
|
||||
(+ 5 6 9 var)
|
||||
(should (format "123 %s" "asd")))
|
||||
(should (format "123 %s" "asd")))
|
||||
|
||||
(provide 'test-duplicates-detector)
|
||||
|
||||
;; Local Variables:
|
||||
;; outline-regexp: "\\(;\\{3,\\} \\)"
|
||||
;; End:
|
||||
|
||||
;;; test-duplicates-detector.el ends here
|
|
@ -117,8 +117,6 @@ main
|
|||
(ert-deftest ob-haskell/session-named-none-means-one-shot-sessions ()
|
||||
"When no session, use a new session.
|
||||
\"none\" is a special name that means `no session'."
|
||||
(test-ob-haskell-ghci ":session none" "x=2" nil)
|
||||
(should-not (equal 2 (test-ob-haskell-ghci ":session \"none\"" "x" nil)))
|
||||
(test-ob-haskell-ghci ":session none" "x=2" nil)
|
||||
(should-not (equal 2 (test-ob-haskell-ghci ":session \"none\"" "x" nil))))
|
||||
|
||||
|
|
|
@ -590,6 +590,63 @@ DEADLINE: " (cdr timestamp))))
|
|||
(org-agenda nil "f")
|
||||
(buffer-string))))))))))))
|
||||
|
||||
(ert-deftest test-org-agenda/skip-scheduled-repeats-after-deadline ()
|
||||
"Test `org-agenda-skip-scheduled-repeats-after-deadline'."
|
||||
(cl-assert (not org-agenda-sticky) nil "precondition violation")
|
||||
(cl-assert (not (org-test-agenda--agenda-buffers))
|
||||
nil "precondition violation")
|
||||
(dolist (org-agenda-skip-scheduled-repeats-after-deadline '(nil t))
|
||||
(org-test-at-time "2024-01-01 8:00"
|
||||
(org-test-with-temp-text-in-file "
|
||||
* TODO Do me every day before Jan, 12th (included)
|
||||
SCHEDULED: <2024-01-03 Wed +1d> DEADLINE: <2024-01-05 Fri>
|
||||
"
|
||||
(let ((org-agenda-span 'week)
|
||||
(org-agenda-files `(,(buffer-file-name))))
|
||||
;; NOTE: Be aware that `org-agenda-list' may or may not display
|
||||
;; past scheduled items depending whether the date is today
|
||||
;; `org-today' or not.
|
||||
(org-agenda-list nil "<2024-01-01 Mon>")
|
||||
(set-buffer org-agenda-buffer-name)
|
||||
(if org-agenda-skip-scheduled-repeats-after-deadline
|
||||
(should
|
||||
;; Not displayed after deadline.
|
||||
(string-match-p
|
||||
"Week-agenda (W01):
|
||||
Monday 1 January 2024 W01
|
||||
[^:]+:In 4 d.: TODO Do me every day before Jan, 12th (included)
|
||||
Tuesday 2 January 2024
|
||||
Wednesday 3 January 2024
|
||||
[^:]+:Scheduled: TODO Do me every day before Jan, 12th (included)
|
||||
Thursday 4 January 2024
|
||||
[^:]+:Scheduled: TODO Do me every day before Jan, 12th (included)
|
||||
Friday 5 January 2024
|
||||
[^:]+:Scheduled: TODO Do me every day before Jan, 12th (included)
|
||||
[^:]+:Deadline: TODO Do me every day before Jan, 12th (included)
|
||||
Saturday 6 January 2024
|
||||
Sunday 7 January 2024"
|
||||
(buffer-string)))
|
||||
(should
|
||||
;; Displayed after deadline.
|
||||
(string-match-p
|
||||
"Week-agenda (W01):
|
||||
Monday 1 January 2024 W01
|
||||
[^:]+:In 4 d.: TODO Do me every day before Jan, 12th (included)
|
||||
Tuesday 2 January 2024
|
||||
Wednesday 3 January 2024
|
||||
[^:]+:Scheduled: TODO Do me every day before Jan, 12th (included)
|
||||
Thursday 4 January 2024
|
||||
[^:]+:Scheduled: TODO Do me every day before Jan, 12th (included)
|
||||
Friday 5 January 2024
|
||||
[^:]+:Scheduled: TODO Do me every day before Jan, 12th (included)
|
||||
[^:]+:Deadline: TODO Do me every day before Jan, 12th (included)
|
||||
Saturday 6 January 2024
|
||||
[^:]+:Scheduled: TODO Do me every day before Jan, 12th (included)
|
||||
Sunday 7 January 2024
|
||||
[^:]+:Scheduled: TODO Do me every day before Jan, 12th (included)"
|
||||
(buffer-string))))))
|
||||
(org-test-agenda--kill-all-agendas))))
|
||||
|
||||
(ert-deftest test-org-agenda/goto-date ()
|
||||
"Test `org-agenda-goto-date'."
|
||||
(unwind-protect
|
||||
|
|
|
@ -2629,30 +2629,34 @@ e^{i\\pi}+1=0
|
|||
(org-element-map (org-element-parse-buffer) 'paragraph 'identity)))
|
||||
;; Include incomplete-drawers.
|
||||
(should
|
||||
(org-test-with-temp-text ":TEST:\nParagraph"
|
||||
(org-test-with-temp-text "<point>:TEST:\nParagraph"
|
||||
(let ((elem (org-element-at-point)))
|
||||
(and (eq (org-element-type elem) 'paragraph)
|
||||
(= (point-max) (org-element-property :end elem))))))
|
||||
(should
|
||||
(org-test-with-temp-text "<point>foo\n:end:\nbar"
|
||||
(let ((elem (org-element-at-point)))
|
||||
(and (eq (org-element-type elem) 'paragraph)
|
||||
(= (point-max) (org-element-property :end elem))))))
|
||||
;; Include incomplete blocks.
|
||||
(should
|
||||
(org-test-with-temp-text "#+BEGIN_CENTER\nParagraph"
|
||||
(org-test-with-temp-text "<point>#+BEGIN_CENTER\nParagraph"
|
||||
(let ((elem (org-element-at-point)))
|
||||
(and (eq (org-element-type elem) 'paragraph)
|
||||
(= (point-max) (org-element-property :end elem))))))
|
||||
;; Include incomplete dynamic blocks.
|
||||
(should
|
||||
(org-test-with-temp-text "#+BEGIN: \n<point>Paragraph"
|
||||
(org-test-with-temp-text "<point>foo\n#+END_CENTER\nbar"
|
||||
(let ((elem (org-element-at-point)))
|
||||
(and (eq (org-element-type elem) 'paragraph)
|
||||
(= (point-max) (org-element-property :end elem))))))
|
||||
;; Include incomplete latex environments.
|
||||
(should
|
||||
(org-test-with-temp-text "\begin{equation}\nParagraph"
|
||||
(org-test-with-temp-text "<point>\begin{equation}\nParagraph"
|
||||
(let ((elem (org-element-at-point)))
|
||||
(and (eq (org-element-type elem) 'paragraph)
|
||||
(= (point-max) (org-element-property :end elem))))))
|
||||
(should
|
||||
(org-test-with-temp-text "Paragraph\n\begin{equation}"
|
||||
(org-test-with-temp-text "<point>Paragraph\n\begin{equation}"
|
||||
(let ((elem (org-element-at-point)))
|
||||
(and (eq (org-element-type elem) 'paragraph)
|
||||
(= (point-max) (org-element-property :end elem))))))
|
||||
|
|
|
@ -418,7 +418,8 @@ Contents
|
|||
*** <point>c"
|
||||
(org-set-visibility-according-to-property)
|
||||
(not (invisible-p (point)))))
|
||||
;; When VISIBILITY properties are nested, ignore inner ones.
|
||||
;; When VISIBILITY properties are nested, do not alter parent
|
||||
;; visibility unless necessary.
|
||||
(should
|
||||
(org-test-with-temp-text
|
||||
"
|
||||
|
@ -431,7 +432,20 @@ Contents
|
|||
:VISIBILITY: folded
|
||||
:END:"
|
||||
(org-set-visibility-according-to-property)
|
||||
(invisible-p (point)))))
|
||||
(invisible-p (point))))
|
||||
(should
|
||||
(org-test-with-temp-text
|
||||
"
|
||||
* A
|
||||
:PROPERTIES:
|
||||
:VISIBILITY: folded
|
||||
:END:
|
||||
** <point>B
|
||||
:PROPERTIES:
|
||||
:VISIBILITY: content
|
||||
:END:"
|
||||
(org-set-visibility-according-to-property)
|
||||
(not (invisible-p (point))))))
|
||||
|
||||
(ert-deftest test-org-fold/visibility-show-branches ()
|
||||
"Test visibility of inline archived subtrees."
|
||||
|
@ -680,6 +694,7 @@ Unfolded Paragraph.
|
|||
|
||||
(ert-deftest test-org-fold/org-fold-display-inline-images ()
|
||||
"Test inline images displaying when cycling."
|
||||
(skip-unless (not noninteractive))
|
||||
(let* ((org-cycle-inline-images-display t)
|
||||
(images-dir (expand-file-name "examples/images/" org-test-dir))
|
||||
(org-logo-image (expand-file-name "Org mode logo mono-color.png" images-dir)))
|
||||
|
@ -701,11 +716,18 @@ Unfolded Paragraph.
|
|||
(org-show-subtree)
|
||||
(org-fold-subtree t)
|
||||
(run-hook-with-args 'org-cycle-hook 'folded)
|
||||
(should (null org-inline-image-overlays))
|
||||
(should (null (overlays-in (point-min) (point-max))))
|
||||
(org-show-subtree)
|
||||
(should-not org-inline-image-overlays)
|
||||
(should-not (overlays-in (point-min) (point-max))))))
|
||||
(should-not
|
||||
(cl-every
|
||||
(lambda (ov) (overlay-get ov 'org-image-overlay))
|
||||
(overlays-in (point-min) (point-max))))
|
||||
(org-show-subtree)
|
||||
(run-hook-with-args 'org-cycle-hook 'subtree)
|
||||
(should org-inline-image-overlays)
|
||||
(should
|
||||
(cl-every
|
||||
(lambda (ov) (overlay-get ov 'org-image-overlay))
|
||||
(overlays-in (point-min) (point-max)))))))
|
||||
|
||||
(provide 'test-org-fold)
|
||||
|
||||
|
|
|
@ -21,6 +21,18 @@
|
|||
|
||||
(require 'org-footnote)
|
||||
|
||||
(ert-deftest test-org-footnote/new-anon ()
|
||||
"Test `org-footnote-new' specifications."
|
||||
;; `org-footnote-auto-label' is `anonymous'.
|
||||
(should
|
||||
(string-match-p
|
||||
"Test\\[fn::\\]"
|
||||
(org-test-with-temp-text "Test<point>"
|
||||
(let ((org-footnote-auto-label 'anonymous)
|
||||
(org-footnote-section nil))
|
||||
(org-footnote-new))
|
||||
(buffer-string)))))
|
||||
|
||||
(ert-deftest test-org-footnote/new ()
|
||||
"Test `org-footnote-new' specifications."
|
||||
;; `org-footnote-auto-label' is t.
|
||||
|
|
|
@ -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
|
|
@ -1633,11 +1633,11 @@ See also `test-org-table/copy-field'."
|
|||
(ert-deftest test-org-table/to-latex ()
|
||||
"Test `orgtbl-to-latex' specifications."
|
||||
(should
|
||||
(equal "\\begin{tabular}{l}\na\\\\[0pt]\n\\end{tabular}"
|
||||
(equal "\\begin{tabular}{l}\na\\\\\n\\end{tabular}"
|
||||
(orgtbl-to-latex (org-table-to-lisp "| a |") nil)))
|
||||
;; Test :environment parameter.
|
||||
(should
|
||||
(equal "\\begin{tabularx}{l}\na\\\\[0pt]\n\\end{tabularx}"
|
||||
(equal "\\begin{tabularx}{l}\na\\\\\n\\end{tabularx}"
|
||||
(orgtbl-to-latex (org-table-to-lisp "| a |")
|
||||
'(:environment "tabularx"))))
|
||||
;; Test :booktabs parameter.
|
||||
|
@ -1646,7 +1646,7 @@ See also `test-org-table/copy-field'."
|
|||
"\\toprule" (orgtbl-to-latex (org-table-to-lisp "| a |") '(:booktabs t))))
|
||||
;; Handle LaTeX snippets.
|
||||
(should
|
||||
(equal "\\begin{tabular}{l}\n\\(x\\)\\\\[0pt]\n\\end{tabular}"
|
||||
(equal "\\begin{tabular}{l}\n\\(x\\)\\\\\n\\end{tabular}"
|
||||
(orgtbl-to-latex (org-table-to-lisp "| $x$ |") nil)))
|
||||
;; Test pseudo objects and :raw parameter.
|
||||
(should
|
||||
|
|
|
@ -2855,7 +2855,7 @@ test <point>
|
|||
(should (org-find-olp '("Headline" "headline8") t))))
|
||||
|
||||
(ert-deftest test-org/map-entries ()
|
||||
"Test `org-map-entries' specifications."
|
||||
"Test `org-map-entries' and `org-element-cache-map' specifications."
|
||||
(dolist (org-element-use-cache '(t nil))
|
||||
;; Full match.
|
||||
(should
|
||||
|
@ -3097,7 +3097,16 @@ Let’s stop here
|
|||
(lambda ()
|
||||
(delete-region (point) (line-beginning-position 2))
|
||||
(setq org-map-continue-from (point))))
|
||||
(buffer-string))))))
|
||||
(buffer-string))))
|
||||
;; :next-re in `org-element-cache-map'
|
||||
(org-test-with-temp-text
|
||||
"* one
|
||||
* TODO two
|
||||
* three
|
||||
* four
|
||||
"
|
||||
(should (equal '("two")
|
||||
(org-element-cache-map (lambda (el) (org-element-property :title el)) :next-re "TODO"))))))
|
||||
|
||||
(ert-deftest test-org/edit-headline ()
|
||||
"Test `org-edit-headline' specifications."
|
||||
|
@ -3309,7 +3318,7 @@ Let’s stop here
|
|||
(list org-priority-highest org-priority-lowest org-priority-default))))
|
||||
;; STARTUP keyword.
|
||||
(should
|
||||
(equal '(t t)
|
||||
(equal '(fold t)
|
||||
(org-test-with-temp-text "#+STARTUP: fold odd"
|
||||
(org-mode-restart)
|
||||
(list org-startup-folded org-odd-levels-only))))
|
||||
|
@ -3982,8 +3991,9 @@ SCHEDULED: <2017-05-06 Sat>
|
|||
(org-file-contents "http://some-valid-url"))
|
||||
(kill-buffer buffer))))))
|
||||
;; Throw error when trying to access an invalid URL.
|
||||
(should-error
|
||||
(let ((buffer (generate-new-buffer "url-retrieve-output")))
|
||||
(should-not
|
||||
(let ((buffer (generate-new-buffer "url-retrieve-output"))
|
||||
(org-resource-download-policy t))
|
||||
(unwind-protect
|
||||
;; Simulate unsuccessful retrieval of a URL.
|
||||
(cl-letf (((symbol-function 'url-retrieve-synchronously)
|
||||
|
@ -3991,11 +4001,12 @@ SCHEDULED: <2017-05-06 Sat>
|
|||
(with-current-buffer buffer
|
||||
(insert "HTTP/1.1 404 Not found\n\ndoes not matter"))
|
||||
buffer)))
|
||||
(org-file-contents "http://this-url-must-not-exist"))
|
||||
(org-file-contents "http://this-url-must-not-exist" 'noerror))
|
||||
(kill-buffer buffer))))
|
||||
;; Try to access an invalid URL, but do not throw an error.
|
||||
(should-error
|
||||
(let ((buffer (generate-new-buffer "url-retrieve-output")))
|
||||
(let ((buffer (generate-new-buffer "url-retrieve-output"))
|
||||
(org-resource-download-policy t))
|
||||
(unwind-protect
|
||||
;; Simulate unsuccessful retrieval of a URL.
|
||||
(cl-letf (((symbol-function 'url-retrieve-synchronously)
|
||||
|
@ -4006,7 +4017,8 @@ SCHEDULED: <2017-05-06 Sat>
|
|||
(org-file-contents "http://this-url-must-not-exist"))
|
||||
(kill-buffer buffer))))
|
||||
(should
|
||||
(let ((buffer (generate-new-buffer "url-retrieve-output")))
|
||||
(let ((buffer (generate-new-buffer "url-retrieve-output"))
|
||||
(org-resource-download-policy t))
|
||||
(unwind-protect
|
||||
;; Simulate unsuccessful retrieval of a URL.
|
||||
(cl-letf (((symbol-function 'url-retrieve-synchronously)
|
||||
|
|
|
@ -29,6 +29,29 @@
|
|||
|
||||
|
||||
|
||||
(ert-deftest text-ox-latex/protect-square-brackets ()
|
||||
"Test [foo] being interpreted as plain text even after LaTeX commands."
|
||||
(org-test-with-exported-text
|
||||
'latex
|
||||
"* This is test
|
||||
lorem @@latex:\\pagebreak@@ [ipsum]
|
||||
|
||||
#+begin_figure
|
||||
[lorem] figure
|
||||
#+end_figure
|
||||
|
||||
| [foo] | 2 |
|
||||
| [bar] | 3 |
|
||||
|
||||
- [bax]
|
||||
- [aur]
|
||||
"
|
||||
(goto-char (point-min))
|
||||
(should (search-forward "lorem \\pagebreak {[}ipsum]"))
|
||||
(should (search-forward "{[}lorem] figure"))
|
||||
(should (search-forward "{[}foo]"))
|
||||
(should (search-forward "\\item {[}bax]"))))
|
||||
|
||||
(ert-deftest test-ox-latex/verse ()
|
||||
"Test verse blocks."
|
||||
(org-test-with-exported-text
|
||||
|
@ -48,14 +71,14 @@ lorem ipsum dolor
|
|||
(should
|
||||
(search-forward
|
||||
"\\begin{verse}
|
||||
lorem ipsum dolor\\\\[0pt]
|
||||
lorem ipsum dolor\\\\
|
||||
lorem ipsum dolor
|
||||
|
||||
lorem ipsum dolor\\\\[0pt]
|
||||
lorem ipsum dolor\\\\
|
||||
lorem ipsum dolor
|
||||
|
||||
lorem ipsum dolor\\\\[0pt]
|
||||
lorem ipsum dolor\\\\[0pt]
|
||||
lorem ipsum dolor\\\\
|
||||
lorem ipsum dolor\\\\
|
||||
\\end{verse}"))))
|
||||
|
||||
(ert-deftest test-ox-latex/longtable ()
|
||||
|
@ -75,15 +98,15 @@ lorem ipsum dolor\\\\[0pt]
|
|||
(should
|
||||
(search-forward
|
||||
"\\begin{longtable}{lr}
|
||||
First & Second\\\\[0pt]
|
||||
Column & Column\\\\[0pt]
|
||||
First & Second\\\\
|
||||
Column & Column\\\\
|
||||
\\hline
|
||||
\\endfirsthead"))
|
||||
(goto-char (point-min))
|
||||
(should
|
||||
(search-forward
|
||||
"First & Second\\\\[0pt]
|
||||
Column & Column \\\\[0pt]
|
||||
"First & Second\\\\
|
||||
Column & Column \\\\
|
||||
|
||||
\\hline
|
||||
\\endhead"))
|
||||
|
|
|
@ -2140,6 +2140,120 @@ Footnotes[fn:2], foot[fn:test] and [fn:inline:inline footnote]
|
|||
(bold . (lambda (bold contents info) (concat contents "!")))))
|
||||
'(:with-emphasize t)))))
|
||||
|
||||
|
||||
;;; Export features
|
||||
|
||||
(ert-deftest test-org-export/feature-resolution ()
|
||||
"Test the behaviour of `org-export-resolve-feature-implementations'"
|
||||
;; Check implementations for listed features are given.
|
||||
(should
|
||||
(equal (org-export-resolve-feature-implementations
|
||||
nil '(a b c) '((a) (b) (c)))
|
||||
'((a) (b) (c))))
|
||||
(should
|
||||
(equal (org-export-resolve-feature-implementations
|
||||
nil '(a b c) '((a)))
|
||||
'((a))))
|
||||
(should
|
||||
(equal (org-export-resolve-feature-implementations
|
||||
nil '(a) '((a) (b) (c)))
|
||||
'((a))))
|
||||
;; Check depencency resolution.
|
||||
(should
|
||||
(equal (org-export-resolve-feature-implementations
|
||||
nil '(a) '((a :requires b) (b) (c)))
|
||||
'((a :requires b) (b))))
|
||||
(should
|
||||
(equal (org-export-resolve-feature-implementations
|
||||
nil '(a) '((a :requires (b c)) (b) (c)))
|
||||
'((a :requires (b c)) (b) (c))))
|
||||
(should
|
||||
(equal (org-export-resolve-feature-implementations
|
||||
nil '(a) '((a :requires b) (b :requires c) (c)))
|
||||
'((a :requires b) (b :requires c) (c))))
|
||||
(should
|
||||
(equal (org-export-resolve-feature-implementations
|
||||
nil '(a b c) '((a :prevents b) (b) (c)))
|
||||
'((a :prevents b) (c))))
|
||||
(should
|
||||
(equal (org-export-resolve-feature-implementations
|
||||
nil '(a b c) '((a :prevents (b c)) (b) (c)))
|
||||
'((a :prevents (b c)))))
|
||||
(should
|
||||
(equal (org-export-resolve-feature-implementations
|
||||
nil '(a b c d) '((a :requires (b c)) (b) (c) (d :prevents b)))
|
||||
'((a :requires (b c)) (c) (d :prevents b))))
|
||||
(should
|
||||
(equal (org-export-resolve-feature-implementations
|
||||
nil '(a b c d) '((a :requires (b c)) (b) (c :prevents b)))
|
||||
'((a :requires (b c)) (c :prevents b))))
|
||||
(should
|
||||
(equal (org-export-resolve-feature-implementations
|
||||
nil '(a d) '((a :requires b) (b :requires c) (c) (d :prevents a)))
|
||||
'((d :prevents a))))
|
||||
(should
|
||||
(equal (org-export-resolve-feature-implementations
|
||||
nil '(a b c d) '((a :requires b) (b :requires c) (c) (d :prevents a)))
|
||||
'((b :requires c) (c) (d :prevents a))))
|
||||
(should-error
|
||||
(org-export-resolve-feature-implementations
|
||||
nil '(a) '((a :requires b)))
|
||||
:type 'org-missing-feature-dependency)
|
||||
;; Check application of the :when condition.
|
||||
(should
|
||||
(equal (org-export-resolve-feature-implementations
|
||||
nil '(a b c) '((a :when b) (b)))
|
||||
'((a :when b) (b))))
|
||||
(should
|
||||
(equal (org-export-resolve-feature-implementations
|
||||
nil '(a b c) '((a :when (b c)) (b) (c)))
|
||||
'((a :when (b c)) (b) (c))))
|
||||
(should
|
||||
(equal (org-export-resolve-feature-implementations
|
||||
nil '(a b c) '((a) (b) (c :when (a b))))
|
||||
'((a) (b) (c :when (a b)))))
|
||||
(should
|
||||
(equal (org-export-resolve-feature-implementations
|
||||
nil '(a b c) '((a :when b) (b :when c) (c)))
|
||||
'((a :when b) (b :when c) (c))))
|
||||
;; Check simple ordering.
|
||||
(should
|
||||
(equal (org-export-resolve-feature-implementations
|
||||
nil '(a b c) '((a :order 3) (b :order 1) (c :order 2)))
|
||||
'((b :order 1) (c :order 2) (a :order 3))))
|
||||
(should
|
||||
(equal (org-export-resolve-feature-implementations
|
||||
nil '(a b c) '((a :order 1) (b) (c :order -1)))
|
||||
'((c :order -1) (b) (a :order 1))))
|
||||
(should
|
||||
(equal (org-export-resolve-feature-implementations
|
||||
nil '(a) '((a :order 1 :requires b) (b :requires c) (c :order -1)))
|
||||
'((c :order -1) (b :requires c) (a :order 1 :requires b))))
|
||||
;; Check before/after ordering.
|
||||
(should
|
||||
(equal (org-export-resolve-feature-implementations
|
||||
nil '(a b c) '((a :after (b c)) (b) (c)))
|
||||
'((b) (c) (a :after (b c)))))
|
||||
(should
|
||||
(equal (org-export-resolve-feature-implementations
|
||||
nil '(a b c) '((a :after b) (b :after c) (c)))
|
||||
'((c) (b :after c) (a :after b))))
|
||||
(should
|
||||
(equal (org-export-resolve-feature-implementations
|
||||
nil '(a b c) '((a) (b) (c :before (a b))))
|
||||
'((c :before (a b)) (a) (b))))
|
||||
(should
|
||||
(equal (org-export-resolve-feature-implementations
|
||||
nil '(a b c) '((a) (b :before a) (c :before b)))
|
||||
'((c :before b) (b :before a) (a))))
|
||||
(should
|
||||
(equal (org-export-resolve-feature-implementations
|
||||
nil '(a b c) '((a) (b :after c :before a) (c)))
|
||||
'((c) (b :after c :before a) (a))))
|
||||
(should-error ; Circular dependency
|
||||
(org-export-resolve-feature-implementations
|
||||
nil '(a b) '((a :after b) (b :after a)))
|
||||
:type 'org-circular-feature-dependency))
|
||||
|
||||
|
||||
;;; Comments
|
||||
|
|
Loading…
Reference in New Issue