commit | author | age
|
76bbd0
|
1 |
;;; ox.el --- Export Framework for Org Mode -*- lexical-binding: t; -*- |
C |
2 |
|
|
3 |
;; Copyright (C) 2012-2018 Free Software Foundation, Inc. |
|
4 |
|
|
5 |
;; Author: Nicolas Goaziou <n.goaziou at gmail dot com> |
|
6 |
;; Keywords: outlines, hypermedia, calendar, wp |
|
7 |
|
|
8 |
;; This file is part of GNU Emacs. |
|
9 |
|
|
10 |
;; GNU Emacs is free software: you can redistribute it and/or modify |
|
11 |
;; it under the terms of the GNU General Public License as published by |
|
12 |
;; the Free Software Foundation, either version 3 of the License, or |
|
13 |
;; (at your option) any later version. |
|
14 |
|
|
15 |
;; GNU Emacs is distributed in the hope that it will be useful, |
|
16 |
;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
17 |
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
18 |
;; GNU General Public License for more details. |
|
19 |
|
|
20 |
;; You should have received a copy of the GNU General Public License |
|
21 |
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. |
|
22 |
|
|
23 |
;;; Commentary: |
|
24 |
;; |
|
25 |
;; This library implements a generic export engine for Org, built on |
|
26 |
;; its syntactical parser: Org Elements. |
|
27 |
;; |
|
28 |
;; Besides that parser, the generic exporter is made of three distinct |
|
29 |
;; parts: |
|
30 |
;; |
|
31 |
;; - The communication channel consists of a property list, which is |
|
32 |
;; created and updated during the process. Its use is to offer |
|
33 |
;; every piece of information, would it be about initial environment |
|
34 |
;; or contextual data, all in a single place. |
|
35 |
;; |
|
36 |
;; - The transcoder walks the parse tree, ignores or treat as plain |
|
37 |
;; text elements and objects according to export options, and |
|
38 |
;; eventually calls back-end specific functions to do the real |
|
39 |
;; transcoding, concatenating their return value along the way. |
|
40 |
;; |
|
41 |
;; - The filter system is activated at the very beginning and the very |
|
42 |
;; end of the export process, and each time an element or an object |
|
43 |
;; has been converted. It is the entry point to fine-tune standard |
|
44 |
;; output from back-end transcoders. See "The Filter System" |
|
45 |
;; section for more information. |
|
46 |
;; |
|
47 |
;; The core functions is `org-export-as'. It returns the transcoded |
|
48 |
;; buffer as a string. Its derivatives are `org-export-to-buffer' and |
|
49 |
;; `org-export-to-file'. |
|
50 |
;; |
|
51 |
;; An export back-end is defined with `org-export-define-backend'. |
|
52 |
;; This function can also support specific buffer keywords, OPTION |
|
53 |
;; keyword's items and filters. Refer to function's documentation for |
|
54 |
;; more information. |
|
55 |
;; |
|
56 |
;; If the new back-end shares most properties with another one, |
|
57 |
;; `org-export-define-derived-backend' can be used to simplify the |
|
58 |
;; process. |
|
59 |
;; |
|
60 |
;; Any back-end can define its own variables. Among them, those |
|
61 |
;; customizable should belong to the `org-export-BACKEND' group. |
|
62 |
;; |
|
63 |
;; Tools for common tasks across back-ends are implemented in the |
|
64 |
;; following part of the file. |
|
65 |
;; |
|
66 |
;; Eventually, a dispatcher (`org-export-dispatch') is provided in the |
|
67 |
;; last one. |
|
68 |
;; |
|
69 |
;; See <https://orgmode.org/worg/dev/org-export-reference.html> for |
|
70 |
;; more information. |
|
71 |
|
|
72 |
;;; Code: |
|
73 |
|
|
74 |
(require 'cl-lib) |
|
75 |
(require 'ob-exp) |
|
76 |
(require 'org-element) |
|
77 |
(require 'org-macro) |
|
78 |
(require 'tabulated-list) |
|
79 |
|
|
80 |
(declare-function org-src-coderef-format "org-src" (&optional element)) |
|
81 |
(declare-function org-src-coderef-regexp "org-src" (fmt &optional label)) |
|
82 |
(declare-function org-publish "ox-publish" (project &optional force async)) |
|
83 |
(declare-function org-publish-all "ox-publish" (&optional force async)) |
|
84 |
(declare-function org-publish-current-file "ox-publish" (&optional force async)) |
|
85 |
(declare-function org-publish-current-project "ox-publish" (&optional force async)) |
|
86 |
|
|
87 |
(defvar org-publish-project-alist) |
|
88 |
(defvar org-table-number-fraction) |
|
89 |
(defvar org-table-number-regexp) |
|
90 |
|
|
91 |
|
|
92 |
;;; Internal Variables |
|
93 |
;; |
|
94 |
;; Among internal variables, the most important is |
|
95 |
;; `org-export-options-alist'. This variable define the global export |
|
96 |
;; options, shared between every exporter, and how they are acquired. |
|
97 |
|
|
98 |
(defconst org-export-max-depth 19 |
|
99 |
"Maximum nesting depth for headlines, counting from 0.") |
|
100 |
|
|
101 |
(defconst org-export-options-alist |
|
102 |
'((:title "TITLE" nil nil parse) |
|
103 |
(:date "DATE" nil nil parse) |
|
104 |
(:author "AUTHOR" nil user-full-name parse) |
|
105 |
(:email "EMAIL" nil user-mail-address t) |
|
106 |
(:language "LANGUAGE" nil org-export-default-language t) |
|
107 |
(:select-tags "SELECT_TAGS" nil org-export-select-tags split) |
|
108 |
(:exclude-tags "EXCLUDE_TAGS" nil org-export-exclude-tags split) |
|
109 |
(:creator "CREATOR" nil org-export-creator-string) |
|
110 |
(:headline-levels nil "H" org-export-headline-levels) |
|
111 |
(:preserve-breaks nil "\\n" org-export-preserve-breaks) |
|
112 |
(:section-numbers nil "num" org-export-with-section-numbers) |
|
113 |
(:time-stamp-file nil "timestamp" org-export-time-stamp-file) |
|
114 |
(:with-archived-trees nil "arch" org-export-with-archived-trees) |
|
115 |
(:with-author nil "author" org-export-with-author) |
|
116 |
(:with-broken-links nil "broken-links" org-export-with-broken-links) |
|
117 |
(:with-clocks nil "c" org-export-with-clocks) |
|
118 |
(:with-creator nil "creator" org-export-with-creator) |
|
119 |
(:with-date nil "date" org-export-with-date) |
|
120 |
(:with-drawers nil "d" org-export-with-drawers) |
|
121 |
(:with-email nil "email" org-export-with-email) |
|
122 |
(:with-emphasize nil "*" org-export-with-emphasize) |
|
123 |
(:with-entities nil "e" org-export-with-entities) |
|
124 |
(:with-fixed-width nil ":" org-export-with-fixed-width) |
|
125 |
(:with-footnotes nil "f" org-export-with-footnotes) |
|
126 |
(:with-inlinetasks nil "inline" org-export-with-inlinetasks) |
|
127 |
(:with-latex nil "tex" org-export-with-latex) |
|
128 |
(:with-planning nil "p" org-export-with-planning) |
|
129 |
(:with-priority nil "pri" org-export-with-priority) |
|
130 |
(:with-properties nil "prop" org-export-with-properties) |
|
131 |
(:with-smart-quotes nil "'" org-export-with-smart-quotes) |
|
132 |
(:with-special-strings nil "-" org-export-with-special-strings) |
|
133 |
(:with-statistics-cookies nil "stat" org-export-with-statistics-cookies) |
|
134 |
(:with-sub-superscript nil "^" org-export-with-sub-superscripts) |
|
135 |
(:with-toc nil "toc" org-export-with-toc) |
|
136 |
(:with-tables nil "|" org-export-with-tables) |
|
137 |
(:with-tags nil "tags" org-export-with-tags) |
|
138 |
(:with-tasks nil "tasks" org-export-with-tasks) |
|
139 |
(:with-timestamps nil "<" org-export-with-timestamps) |
|
140 |
(:with-title nil "title" org-export-with-title) |
|
141 |
(:with-todo-keywords nil "todo" org-export-with-todo-keywords)) |
|
142 |
"Alist between export properties and ways to set them. |
|
143 |
|
|
144 |
The key of the alist is the property name, and the value is a list |
|
145 |
like (KEYWORD OPTION DEFAULT BEHAVIOR) where: |
|
146 |
|
|
147 |
KEYWORD is a string representing a buffer keyword, or nil. Each |
|
148 |
property defined this way can also be set, during subtree |
|
149 |
export, through a headline property named after the keyword |
|
150 |
with the \"EXPORT_\" prefix (i.e. DATE keyword and EXPORT_DATE |
|
151 |
property). |
|
152 |
OPTION is a string that could be found in an #+OPTIONS: line. |
|
153 |
DEFAULT is the default value for the property. |
|
154 |
BEHAVIOR determines how Org should handle multiple keywords for |
|
155 |
the same property. It is a symbol among: |
|
156 |
nil Keep old value and discard the new one. |
|
157 |
t Replace old value with the new one. |
|
158 |
`space' Concatenate the values, separating them with a space. |
|
159 |
`newline' Concatenate the values, separating them with |
|
160 |
a newline. |
|
161 |
`split' Split values at white spaces, and cons them to the |
|
162 |
previous list. |
|
163 |
`parse' Parse value as a list of strings and Org objects, |
|
164 |
which can then be transcoded with, e.g., |
|
165 |
`org-export-data'. It implies `space' behavior. |
|
166 |
|
|
167 |
Values set through KEYWORD and OPTION have precedence over |
|
168 |
DEFAULT. |
|
169 |
|
|
170 |
All these properties should be back-end agnostic. Back-end |
|
171 |
specific properties are set through `org-export-define-backend'. |
|
172 |
Properties redefined there have precedence over these.") |
|
173 |
|
|
174 |
(defconst org-export-special-keywords '("FILETAGS" "SETUPFILE" "OPTIONS") |
|
175 |
"List of in-buffer keywords that require special treatment. |
|
176 |
These keywords are not directly associated to a property. The |
|
177 |
way they are handled must be hard-coded into |
|
178 |
`org-export--get-inbuffer-options' function.") |
|
179 |
|
|
180 |
(defconst org-export-filters-alist |
|
181 |
'((:filter-body . org-export-filter-body-functions) |
|
182 |
(:filter-bold . org-export-filter-bold-functions) |
|
183 |
(:filter-babel-call . org-export-filter-babel-call-functions) |
|
184 |
(:filter-center-block . org-export-filter-center-block-functions) |
|
185 |
(:filter-clock . org-export-filter-clock-functions) |
|
186 |
(:filter-code . org-export-filter-code-functions) |
|
187 |
(:filter-diary-sexp . org-export-filter-diary-sexp-functions) |
|
188 |
(:filter-drawer . org-export-filter-drawer-functions) |
|
189 |
(:filter-dynamic-block . org-export-filter-dynamic-block-functions) |
|
190 |
(:filter-entity . org-export-filter-entity-functions) |
|
191 |
(:filter-example-block . org-export-filter-example-block-functions) |
|
192 |
(:filter-export-block . org-export-filter-export-block-functions) |
|
193 |
(:filter-export-snippet . org-export-filter-export-snippet-functions) |
|
194 |
(:filter-final-output . org-export-filter-final-output-functions) |
|
195 |
(:filter-fixed-width . org-export-filter-fixed-width-functions) |
|
196 |
(:filter-footnote-definition . org-export-filter-footnote-definition-functions) |
|
197 |
(:filter-footnote-reference . org-export-filter-footnote-reference-functions) |
|
198 |
(:filter-headline . org-export-filter-headline-functions) |
|
199 |
(:filter-horizontal-rule . org-export-filter-horizontal-rule-functions) |
|
200 |
(:filter-inline-babel-call . org-export-filter-inline-babel-call-functions) |
|
201 |
(:filter-inline-src-block . org-export-filter-inline-src-block-functions) |
|
202 |
(:filter-inlinetask . org-export-filter-inlinetask-functions) |
|
203 |
(:filter-italic . org-export-filter-italic-functions) |
|
204 |
(:filter-item . org-export-filter-item-functions) |
|
205 |
(:filter-keyword . org-export-filter-keyword-functions) |
|
206 |
(:filter-latex-environment . org-export-filter-latex-environment-functions) |
|
207 |
(:filter-latex-fragment . org-export-filter-latex-fragment-functions) |
|
208 |
(:filter-line-break . org-export-filter-line-break-functions) |
|
209 |
(:filter-link . org-export-filter-link-functions) |
|
210 |
(:filter-node-property . org-export-filter-node-property-functions) |
|
211 |
(:filter-options . org-export-filter-options-functions) |
|
212 |
(:filter-paragraph . org-export-filter-paragraph-functions) |
|
213 |
(:filter-parse-tree . org-export-filter-parse-tree-functions) |
|
214 |
(:filter-plain-list . org-export-filter-plain-list-functions) |
|
215 |
(:filter-plain-text . org-export-filter-plain-text-functions) |
|
216 |
(:filter-planning . org-export-filter-planning-functions) |
|
217 |
(:filter-property-drawer . org-export-filter-property-drawer-functions) |
|
218 |
(:filter-quote-block . org-export-filter-quote-block-functions) |
|
219 |
(:filter-radio-target . org-export-filter-radio-target-functions) |
|
220 |
(:filter-section . org-export-filter-section-functions) |
|
221 |
(:filter-special-block . org-export-filter-special-block-functions) |
|
222 |
(:filter-src-block . org-export-filter-src-block-functions) |
|
223 |
(:filter-statistics-cookie . org-export-filter-statistics-cookie-functions) |
|
224 |
(:filter-strike-through . org-export-filter-strike-through-functions) |
|
225 |
(:filter-subscript . org-export-filter-subscript-functions) |
|
226 |
(:filter-superscript . org-export-filter-superscript-functions) |
|
227 |
(:filter-table . org-export-filter-table-functions) |
|
228 |
(:filter-table-cell . org-export-filter-table-cell-functions) |
|
229 |
(:filter-table-row . org-export-filter-table-row-functions) |
|
230 |
(:filter-target . org-export-filter-target-functions) |
|
231 |
(:filter-timestamp . org-export-filter-timestamp-functions) |
|
232 |
(:filter-underline . org-export-filter-underline-functions) |
|
233 |
(:filter-verbatim . org-export-filter-verbatim-functions) |
|
234 |
(:filter-verse-block . org-export-filter-verse-block-functions)) |
|
235 |
"Alist between filters properties and initial values. |
|
236 |
|
|
237 |
The key of each association is a property name accessible through |
|
238 |
the communication channel. Its value is a configurable global |
|
239 |
variable defining initial filters. |
|
240 |
|
|
241 |
This list is meant to install user specified filters. Back-end |
|
242 |
developers may install their own filters using |
|
243 |
`org-export-define-backend'. Filters defined there will always |
|
244 |
be prepended to the current list, so they always get applied |
|
245 |
first.") |
|
246 |
|
|
247 |
(defconst org-export-default-inline-image-rule |
|
248 |
`(("file" . |
|
249 |
,(format "\\.%s\\'" |
|
250 |
(regexp-opt |
|
251 |
'("png" "jpeg" "jpg" "gif" "tiff" "tif" "xbm" |
|
252 |
"xpm" "pbm" "pgm" "ppm") t)))) |
|
253 |
"Default rule for link matching an inline image. |
|
254 |
This rule applies to links with no description. By default, it |
|
255 |
will be considered as an inline image if it targets a local file |
|
256 |
whose extension is either \"png\", \"jpeg\", \"jpg\", \"gif\", |
|
257 |
\"tiff\", \"tif\", \"xbm\", \"xpm\", \"pbm\", \"pgm\" or \"ppm\". |
|
258 |
See `org-export-inline-image-p' for more information about |
|
259 |
rules.") |
|
260 |
|
|
261 |
(defconst org-export-ignored-local-variables |
|
262 |
'(org-font-lock-keywords |
|
263 |
org-element--cache org-element--cache-objects org-element--cache-sync-keys |
|
264 |
org-element--cache-sync-requests org-element--cache-sync-timer) |
|
265 |
"List of variables not copied through upon buffer duplication. |
|
266 |
Export process takes place on a copy of the original buffer. |
|
267 |
When this copy is created, all Org related local variables not in |
|
268 |
this list are copied to the new buffer. Variables with an |
|
269 |
unreadable value are also ignored.") |
|
270 |
|
|
271 |
(defvar org-export-async-debug nil |
|
272 |
"Non-nil means asynchronous export process should leave data behind. |
|
273 |
|
|
274 |
This data is found in the appropriate \"*Org Export Process*\" |
|
275 |
buffer, and in files prefixed with \"org-export-process\" and |
|
276 |
located in `temporary-file-directory'. |
|
277 |
|
|
278 |
When non-nil, it will also set `debug-on-error' to a non-nil |
|
279 |
value in the external process.") |
|
280 |
|
|
281 |
(defvar org-export-stack-contents nil |
|
282 |
"Record asynchronously generated export results and processes. |
|
283 |
This is an alist: its CAR is the source of the |
|
284 |
result (destination file or buffer for a finished process, |
|
285 |
original buffer for a running one) and its CDR is a list |
|
286 |
containing the back-end used, as a symbol, and either a process |
|
287 |
or the time at which it finished. It is used to build the menu |
|
288 |
from `org-export-stack'.") |
|
289 |
|
|
290 |
(defvar org-export-registered-backends nil |
|
291 |
"List of backends currently available in the exporter. |
|
292 |
This variable is set with `org-export-define-backend' and |
|
293 |
`org-export-define-derived-backend' functions.") |
|
294 |
|
|
295 |
(defvar org-export-dispatch-last-action nil |
|
296 |
"Last command called from the dispatcher. |
|
297 |
The value should be a list. Its CAR is the action, as a symbol, |
|
298 |
and its CDR is a list of export options.") |
|
299 |
|
|
300 |
(defvar org-export-dispatch-last-position (make-marker) |
|
301 |
"The position where the last export command was created using the dispatcher. |
|
302 |
This marker will be used with `C-u C-c C-e' to make sure export repetition |
|
303 |
uses the same subtree if the previous command was restricted to a subtree.") |
|
304 |
|
|
305 |
;; For compatibility with Org < 8 |
|
306 |
(defvar org-export-current-backend nil |
|
307 |
"Name, if any, of the back-end used during an export process. |
|
308 |
|
|
309 |
Its value is a symbol such as `html', `latex', `ascii', or nil if |
|
310 |
the back-end is anonymous (see `org-export-create-backend') or if |
|
311 |
there is no export process in progress. |
|
312 |
|
|
313 |
It can be used to teach Babel blocks how to act differently |
|
314 |
according to the back-end used.") |
|
315 |
|
|
316 |
|
|
317 |
|
|
318 |
;;; User-configurable Variables |
|
319 |
;; |
|
320 |
;; Configuration for the masses. |
|
321 |
;; |
|
322 |
;; They should never be accessed directly, as their value is to be |
|
323 |
;; stored in a property list (cf. `org-export-options-alist'). |
|
324 |
;; Back-ends will read their value from there instead. |
|
325 |
|
|
326 |
(defgroup org-export nil |
|
327 |
"Options for exporting Org mode files." |
|
328 |
:tag "Org Export" |
|
329 |
:group 'org) |
|
330 |
|
|
331 |
(defgroup org-export-general nil |
|
332 |
"General options for export engine." |
|
333 |
:tag "Org Export General" |
|
334 |
:group 'org-export) |
|
335 |
|
|
336 |
(defcustom org-export-with-archived-trees 'headline |
|
337 |
"Whether sub-trees with the ARCHIVE tag should be exported. |
|
338 |
|
|
339 |
This can have three different values: |
|
340 |
nil Do not export, pretend this tree is not present. |
|
341 |
t Do export the entire tree. |
|
342 |
`headline' Only export the headline, but skip the tree below it. |
|
343 |
|
|
344 |
This option can also be set with the OPTIONS keyword, |
|
345 |
e.g. \"arch:nil\"." |
|
346 |
:group 'org-export-general |
|
347 |
:type '(choice |
|
348 |
(const :tag "Not at all" nil) |
|
349 |
(const :tag "Headline only" headline) |
|
350 |
(const :tag "Entirely" t)) |
|
351 |
:safe (lambda (x) (memq x '(t nil headline)))) |
|
352 |
|
|
353 |
(defcustom org-export-with-author t |
|
354 |
"Non-nil means insert author name into the exported file. |
|
355 |
This option can also be set with the OPTIONS keyword, |
|
356 |
e.g. \"author:nil\"." |
|
357 |
:group 'org-export-general |
|
358 |
:type 'boolean |
|
359 |
:safe #'booleanp) |
|
360 |
|
|
361 |
(defcustom org-export-with-clocks nil |
|
362 |
"Non-nil means export CLOCK keywords. |
|
363 |
This option can also be set with the OPTIONS keyword, |
|
364 |
e.g. \"c:t\"." |
|
365 |
:group 'org-export-general |
|
366 |
:type 'boolean |
|
367 |
:safe #'booleanp) |
|
368 |
|
|
369 |
(defcustom org-export-with-creator nil |
|
370 |
"Non-nil means the postamble should contain a creator sentence. |
|
371 |
|
|
372 |
The sentence can be set in `org-export-creator-string', which |
|
373 |
see. |
|
374 |
|
|
375 |
This option can also be set with the OPTIONS keyword, e.g., |
|
376 |
\"creator:t\"." |
|
377 |
:group 'org-export-general |
|
378 |
:version "26.1" |
|
379 |
:package-version '(Org . "8.3") |
|
380 |
:type 'boolean |
|
381 |
:safe #'booleanp) |
|
382 |
|
|
383 |
(defcustom org-export-with-date t |
|
384 |
"Non-nil means insert date in the exported document. |
|
385 |
This option can also be set with the OPTIONS keyword, |
|
386 |
e.g. \"date:nil\"." |
|
387 |
:group 'org-export-general |
|
388 |
:type 'boolean |
|
389 |
:safe #'booleanp) |
|
390 |
|
|
391 |
(defcustom org-export-date-timestamp-format nil |
|
392 |
"Time-stamp format string to use for DATE keyword. |
|
393 |
|
|
394 |
The format string, when specified, only applies if date consists |
|
395 |
in a single time-stamp. Otherwise its value will be ignored. |
|
396 |
|
|
397 |
See `format-time-string' for details on how to build this |
|
398 |
string." |
|
399 |
:group 'org-export-general |
|
400 |
:type '(choice |
|
401 |
(string :tag "Time-stamp format string") |
|
402 |
(const :tag "No format string" nil)) |
|
403 |
:safe (lambda (x) (or (null x) (stringp x)))) |
|
404 |
|
|
405 |
(defcustom org-export-creator-string |
|
406 |
(format "Emacs %s (Org mode %s)" |
|
407 |
emacs-version |
|
408 |
(if (fboundp 'org-version) (org-version) "unknown version")) |
|
409 |
"Information about the creator of the document. |
|
410 |
This option can also be set on with the CREATOR keyword." |
|
411 |
:group 'org-export-general |
|
412 |
:type '(string :tag "Creator string") |
|
413 |
:safe #'stringp) |
|
414 |
|
|
415 |
(defcustom org-export-with-drawers '(not "LOGBOOK") |
|
416 |
"Non-nil means export contents of standard drawers. |
|
417 |
|
|
418 |
When t, all drawers are exported. This may also be a list of |
|
419 |
drawer names to export, as strings. If that list starts with |
|
420 |
`not', only drawers with such names will be ignored. |
|
421 |
|
|
422 |
This variable doesn't apply to properties drawers. See |
|
423 |
`org-export-with-properties' instead. |
|
424 |
|
|
425 |
This option can also be set with the OPTIONS keyword, |
|
426 |
e.g. \"d:nil\"." |
|
427 |
:group 'org-export-general |
|
428 |
:version "24.4" |
|
429 |
:package-version '(Org . "8.0") |
|
430 |
:type '(choice |
|
431 |
(const :tag "All drawers" t) |
|
432 |
(const :tag "None" nil) |
|
433 |
(repeat :tag "Selected drawers" |
|
434 |
(string :tag "Drawer name")) |
|
435 |
(list :tag "Ignored drawers" |
|
436 |
(const :format "" not) |
|
437 |
(repeat :tag "Specify names of drawers to ignore during export" |
|
438 |
:inline t |
|
439 |
(string :tag "Drawer name")))) |
|
440 |
:safe (lambda (x) (or (booleanp x) (consp x)))) |
|
441 |
|
|
442 |
(defcustom org-export-with-email nil |
|
443 |
"Non-nil means insert author email into the exported file. |
|
444 |
This option can also be set with the OPTIONS keyword, |
|
445 |
e.g. \"email:t\"." |
|
446 |
:group 'org-export-general |
|
447 |
:type 'boolean |
|
448 |
:safe #'booleanp) |
|
449 |
|
|
450 |
(defcustom org-export-with-emphasize t |
|
451 |
"Non-nil means interpret *word*, /word/, _word_ and +word+. |
|
452 |
|
|
453 |
If the export target supports emphasizing text, the word will be |
|
454 |
typeset in bold, italic, with an underline or strike-through, |
|
455 |
respectively. |
|
456 |
|
|
457 |
This option can also be set with the OPTIONS keyword, |
|
458 |
e.g. \"*:nil\"." |
|
459 |
:group 'org-export-general |
|
460 |
:type 'boolean |
|
461 |
:safe #'booleanp) |
|
462 |
|
|
463 |
(defcustom org-export-exclude-tags '("noexport") |
|
464 |
"Tags that exclude a tree from export. |
|
465 |
|
|
466 |
All trees carrying any of these tags will be excluded from |
|
467 |
export. This is without condition, so even subtrees inside that |
|
468 |
carry one of the `org-export-select-tags' will be removed. |
|
469 |
|
|
470 |
This option can also be set with the EXCLUDE_TAGS keyword." |
|
471 |
:group 'org-export-general |
|
472 |
:type '(repeat (string :tag "Tag")) |
|
473 |
:safe (lambda (x) (and (listp x) (cl-every #'stringp x)))) |
|
474 |
|
|
475 |
(defcustom org-export-with-fixed-width t |
|
476 |
"Non-nil means export lines starting with \":\". |
|
477 |
This option can also be set with the OPTIONS keyword, |
|
478 |
e.g. \"::nil\"." |
|
479 |
:group 'org-export-general |
|
480 |
:version "24.4" |
|
481 |
:package-version '(Org . "8.0") |
|
482 |
:type 'boolean |
|
483 |
:safe #'booleanp) |
|
484 |
|
|
485 |
(defcustom org-export-with-footnotes t |
|
486 |
"Non-nil means Org footnotes should be exported. |
|
487 |
This option can also be set with the OPTIONS keyword, |
|
488 |
e.g. \"f:nil\"." |
|
489 |
:group 'org-export-general |
|
490 |
:type 'boolean |
|
491 |
:safe #'booleanp) |
|
492 |
|
|
493 |
(defcustom org-export-with-latex t |
|
494 |
"Non-nil means process LaTeX environments and fragments. |
|
495 |
|
|
496 |
This option can also be set with the OPTIONS line, |
|
497 |
e.g. \"tex:verbatim\". Allowed values are: |
|
498 |
|
|
499 |
nil Ignore math snippets. |
|
500 |
`verbatim' Keep everything in verbatim. |
|
501 |
t Allow export of math snippets." |
|
502 |
:group 'org-export-general |
|
503 |
:version "24.4" |
|
504 |
:package-version '(Org . "8.0") |
|
505 |
:type '(choice |
|
506 |
(const :tag "Do not process math in any way" nil) |
|
507 |
(const :tag "Interpret math snippets" t) |
|
508 |
(const :tag "Leave math verbatim" verbatim)) |
|
509 |
:safe (lambda (x) (memq x '(t nil verbatim)))) |
|
510 |
|
|
511 |
(defcustom org-export-headline-levels 3 |
|
512 |
"The last level which is still exported as a headline. |
|
513 |
|
|
514 |
Inferior levels will usually produce itemize or enumerate lists |
|
515 |
when exported, but back-end behavior may differ. |
|
516 |
|
|
517 |
This option can also be set with the OPTIONS keyword, |
|
518 |
e.g. \"H:2\"." |
|
519 |
:group 'org-export-general |
|
520 |
:type 'integer |
|
521 |
:safe #'integerp) |
|
522 |
|
|
523 |
(defcustom org-export-default-language "en" |
|
524 |
"The default language for export and clocktable translations, as a string. |
|
525 |
This may have an association in |
|
526 |
`org-clock-clocktable-language-setup', |
|
527 |
`org-export-smart-quotes-alist' and `org-export-dictionary'. |
|
528 |
This option can also be set with the LANGUAGE keyword." |
|
529 |
:group 'org-export-general |
|
530 |
:type '(string :tag "Language") |
|
531 |
:safe #'stringp) |
|
532 |
|
|
533 |
(defcustom org-export-preserve-breaks nil |
|
534 |
"Non-nil means preserve all line breaks when exporting. |
|
535 |
This option can also be set with the OPTIONS keyword, |
|
536 |
e.g. \"\\n:t\"." |
|
537 |
:group 'org-export-general |
|
538 |
:type 'boolean |
|
539 |
:safe #'booleanp) |
|
540 |
|
|
541 |
(defcustom org-export-with-entities t |
|
542 |
"Non-nil means interpret entities when exporting. |
|
543 |
|
|
544 |
For example, HTML export converts \\alpha to α and \\AA to |
|
545 |
Å. |
|
546 |
|
|
547 |
For a list of supported names, see the constant `org-entities' |
|
548 |
and the user option `org-entities-user'. |
|
549 |
|
|
550 |
This option can also be set with the OPTIONS keyword, |
|
551 |
e.g. \"e:nil\"." |
|
552 |
:group 'org-export-general |
|
553 |
:type 'boolean |
|
554 |
:safe #'booleanp) |
|
555 |
|
|
556 |
(defcustom org-export-with-inlinetasks t |
|
557 |
"Non-nil means inlinetasks should be exported. |
|
558 |
This option can also be set with the OPTIONS keyword, |
|
559 |
e.g. \"inline:nil\"." |
|
560 |
:group 'org-export-general |
|
561 |
:version "24.4" |
|
562 |
:package-version '(Org . "8.0") |
|
563 |
:type 'boolean |
|
564 |
:safe #'booleanp) |
|
565 |
|
|
566 |
(defcustom org-export-with-planning nil |
|
567 |
"Non-nil means include planning info in export. |
|
568 |
|
|
569 |
Planning info is the line containing either SCHEDULED:, |
|
570 |
DEADLINE:, CLOSED: time-stamps, or a combination of them. |
|
571 |
|
|
572 |
This option can also be set with the OPTIONS keyword, |
|
573 |
e.g. \"p:t\"." |
|
574 |
:group 'org-export-general |
|
575 |
:version "24.4" |
|
576 |
:package-version '(Org . "8.0") |
|
577 |
:type 'boolean |
|
578 |
:safe #'booleanp) |
|
579 |
|
|
580 |
(defcustom org-export-with-priority nil |
|
581 |
"Non-nil means include priority cookies in export. |
|
582 |
This option can also be set with the OPTIONS keyword, |
|
583 |
e.g. \"pri:t\"." |
|
584 |
:group 'org-export-general |
|
585 |
:type 'boolean |
|
586 |
:safe #'booleanp) |
|
587 |
|
|
588 |
(defcustom org-export-with-properties nil |
|
589 |
"Non-nil means export contents of properties drawers. |
|
590 |
|
|
591 |
When t, all properties are exported. This may also be a list of |
|
592 |
properties to export, as strings. |
|
593 |
|
|
594 |
This option can also be set with the OPTIONS keyword, |
|
595 |
e.g. \"prop:t\"." |
|
596 |
:group 'org-export-general |
|
597 |
:version "26.1" |
|
598 |
:package-version '(Org . "8.3") |
|
599 |
:type '(choice |
|
600 |
(const :tag "All properties" t) |
|
601 |
(const :tag "None" nil) |
|
602 |
(repeat :tag "Selected properties" |
|
603 |
(string :tag "Property name"))) |
|
604 |
:safe (lambda (x) (or (booleanp x) |
|
605 |
(and (listp x) (cl-every #'stringp x))))) |
|
606 |
|
|
607 |
(defcustom org-export-with-section-numbers t |
|
608 |
"Non-nil means add section numbers to headlines when exporting. |
|
609 |
|
|
610 |
When set to an integer n, numbering will only happen for |
|
611 |
headlines whose relative level is higher or equal to n. |
|
612 |
|
|
613 |
This option can also be set with the OPTIONS keyword, |
|
614 |
e.g. \"num:t\"." |
|
615 |
:group 'org-export-general |
|
616 |
:type 'boolean |
|
617 |
:safe #'booleanp) |
|
618 |
|
|
619 |
(defcustom org-export-select-tags '("export") |
|
620 |
"Tags that select a tree for export. |
|
621 |
|
|
622 |
If any such tag is found in a buffer, all trees that do not carry |
|
623 |
one of these tags will be ignored during export. Inside trees |
|
624 |
that are selected like this, you can still deselect a subtree by |
|
625 |
tagging it with one of the `org-export-exclude-tags'. |
|
626 |
|
|
627 |
This option can also be set with the SELECT_TAGS keyword." |
|
628 |
:group 'org-export-general |
|
629 |
:type '(repeat (string :tag "Tag")) |
|
630 |
:safe (lambda (x) (and (listp x) (cl-every #'stringp x)))) |
|
631 |
|
|
632 |
(defcustom org-export-with-smart-quotes nil |
|
633 |
"Non-nil means activate smart quotes during export. |
|
634 |
This option can also be set with the OPTIONS keyword, |
|
635 |
e.g., \"':t\". |
|
636 |
|
|
637 |
When setting this to non-nil, you need to take care of |
|
638 |
using the correct Babel package when exporting to LaTeX. |
|
639 |
E.g., you can load Babel for french like this: |
|
640 |
|
|
641 |
#+LATEX_HEADER: \\usepackage[french]{babel}" |
|
642 |
:group 'org-export-general |
|
643 |
:version "24.4" |
|
644 |
:package-version '(Org . "8.0") |
|
645 |
:type 'boolean |
|
646 |
:safe #'booleanp) |
|
647 |
|
|
648 |
(defcustom org-export-with-special-strings t |
|
649 |
"Non-nil means interpret \"\\-\", \"--\" and \"---\" for export. |
|
650 |
|
|
651 |
When this option is turned on, these strings will be exported as: |
|
652 |
|
|
653 |
Org HTML LaTeX UTF-8 |
|
654 |
-----+----------+--------+------- |
|
655 |
\\- ­ \\- |
|
656 |
-- – -- – |
|
657 |
--- — --- — |
|
658 |
... … \\ldots … |
|
659 |
|
|
660 |
This option can also be set with the OPTIONS keyword, |
|
661 |
e.g. \"-:nil\"." |
|
662 |
:group 'org-export-general |
|
663 |
:type 'boolean |
|
664 |
:safe #'booleanp) |
|
665 |
|
|
666 |
(defcustom org-export-with-statistics-cookies t |
|
667 |
"Non-nil means include statistics cookies in export. |
|
668 |
This option can also be set with the OPTIONS keyword, |
|
669 |
e.g. \"stat:nil\"" |
|
670 |
:group 'org-export-general |
|
671 |
:version "24.4" |
|
672 |
:package-version '(Org . "8.0") |
|
673 |
:type 'boolean |
|
674 |
:safe #'booleanp) |
|
675 |
|
|
676 |
(defcustom org-export-with-sub-superscripts t |
|
677 |
"Non-nil means interpret \"_\" and \"^\" for export. |
|
678 |
|
|
679 |
If you want to control how Org displays those characters, see |
|
680 |
`org-use-sub-superscripts'. `org-export-with-sub-superscripts' |
|
681 |
used to be an alias for `org-use-sub-superscripts' in Org <8.0, |
|
682 |
it is not anymore. |
|
683 |
|
|
684 |
When this option is turned on, you can use TeX-like syntax for |
|
685 |
sub- and superscripts and see them exported correctly. |
|
686 |
|
|
687 |
You can also set the option with #+OPTIONS: ^:t |
|
688 |
|
|
689 |
Several characters after \"_\" or \"^\" will be considered as a |
|
690 |
single item - so grouping with {} is normally not needed. For |
|
691 |
example, the following things will be parsed as single sub- or |
|
692 |
superscripts: |
|
693 |
|
|
694 |
10^24 or 10^tau several digits will be considered 1 item. |
|
695 |
10^-12 or 10^-tau a leading sign with digits or a word |
|
696 |
x^2-y^3 will be read as x^2 - y^3, because items are |
|
697 |
terminated by almost any nonword/nondigit char. |
|
698 |
x_{i^2} or x^(2-i) braces or parenthesis do grouping. |
|
699 |
|
|
700 |
Still, ambiguity is possible. So when in doubt, use {} to enclose |
|
701 |
the sub/superscript. If you set this variable to the symbol `{}', |
|
702 |
the braces are *required* in order to trigger interpretations as |
|
703 |
sub/superscript. This can be helpful in documents that need \"_\" |
|
704 |
frequently in plain text." |
|
705 |
:group 'org-export-general |
|
706 |
:version "24.4" |
|
707 |
:package-version '(Org . "8.0") |
|
708 |
:type '(choice |
|
709 |
(const :tag "Interpret them" t) |
|
710 |
(const :tag "Curly brackets only" {}) |
|
711 |
(const :tag "Do not interpret them" nil)) |
|
712 |
:safe (lambda (x) (memq x '(t nil {})))) |
|
713 |
|
|
714 |
(defcustom org-export-with-toc t |
|
715 |
"Non-nil means create a table of contents in exported files. |
|
716 |
|
|
717 |
The table of contents contains headlines with levels up to |
|
718 |
`org-export-headline-levels'. |
|
719 |
|
|
720 |
When this variable is set to an integer N, include levels up to |
|
721 |
N in the table of contents. Although it may then be different |
|
722 |
from `org-export-headline-levels', it is cannot be larger than |
|
723 |
the number of headline levels. |
|
724 |
|
|
725 |
When nil, no table of contents is created. |
|
726 |
|
|
727 |
This option can also be set with the OPTIONS keyword, |
|
728 |
e.g. \"toc:nil\" or \"toc:3\"." |
|
729 |
:group 'org-export-general |
|
730 |
:type '(choice |
|
731 |
(const :tag "No Table of Contents" nil) |
|
732 |
(const :tag "Full Table of Contents" t) |
|
733 |
(integer :tag "TOC to level")) |
|
734 |
:safe (lambda (x) |
|
735 |
(or (booleanp x) |
|
736 |
(integerp x)))) |
|
737 |
|
|
738 |
(defcustom org-export-with-tables t |
|
739 |
"Non-nil means export tables. |
|
740 |
This option can also be set with the OPTIONS keyword, |
|
741 |
e.g. \"|:nil\"." |
|
742 |
:group 'org-export-general |
|
743 |
:version "24.4" |
|
744 |
:package-version '(Org . "8.0") |
|
745 |
:type 'boolean |
|
746 |
:safe #'booleanp) |
|
747 |
|
|
748 |
(defcustom org-export-with-tags t |
|
749 |
"If nil, do not export tags, just remove them from headlines. |
|
750 |
|
|
751 |
If this is the symbol `not-in-toc', tags will be removed from |
|
752 |
table of contents entries, but still be shown in the headlines of |
|
753 |
the document. |
|
754 |
|
|
755 |
This option can also be set with the OPTIONS keyword, |
|
756 |
e.g. \"tags:nil\"." |
|
757 |
:group 'org-export-general |
|
758 |
:type '(choice |
|
759 |
(const :tag "Off" nil) |
|
760 |
(const :tag "Not in TOC" not-in-toc) |
|
761 |
(const :tag "On" t)) |
|
762 |
:safe (lambda (x) (memq x '(t nil not-in-toc)))) |
|
763 |
|
|
764 |
(defcustom org-export-with-tasks t |
|
765 |
"Non-nil means include TODO items for export. |
|
766 |
|
|
767 |
This may have the following values: |
|
768 |
t include tasks independent of state. |
|
769 |
`todo' include only tasks that are not yet done. |
|
770 |
`done' include only tasks that are already done. |
|
771 |
nil ignore all tasks. |
|
772 |
list of keywords include tasks with these keywords. |
|
773 |
|
|
774 |
This option can also be set with the OPTIONS keyword, |
|
775 |
e.g. \"tasks:nil\"." |
|
776 |
:group 'org-export-general |
|
777 |
:type '(choice |
|
778 |
(const :tag "All tasks" t) |
|
779 |
(const :tag "No tasks" nil) |
|
780 |
(const :tag "Not-done tasks" todo) |
|
781 |
(const :tag "Only done tasks" done) |
|
782 |
(repeat :tag "Specific TODO keywords" |
|
783 |
(string :tag "Keyword"))) |
|
784 |
:safe (lambda (x) (or (memq x '(nil t todo done)) |
|
785 |
(and (listp x) |
|
786 |
(cl-every #'stringp x))))) |
|
787 |
|
|
788 |
(defcustom org-export-with-title t |
|
789 |
"Non-nil means print title into the exported file. |
|
790 |
This option can also be set with the OPTIONS keyword, |
|
791 |
e.g. \"title:nil\"." |
|
792 |
:group 'org-export-general |
|
793 |
:version "26.1" |
|
794 |
:package-version '(Org . "8.3") |
|
795 |
:type 'boolean |
|
796 |
:safe #'booleanp) |
|
797 |
|
|
798 |
(defcustom org-export-time-stamp-file t |
|
799 |
"Non-nil means insert a time stamp into the exported file. |
|
800 |
The time stamp shows when the file was created. This option can |
|
801 |
also be set with the OPTIONS keyword, e.g. \"timestamp:nil\"." |
|
802 |
:group 'org-export-general |
|
803 |
:type 'boolean |
|
804 |
:safe #'booleanp) |
|
805 |
|
|
806 |
(defcustom org-export-with-timestamps t |
|
807 |
"Non nil means allow timestamps in export. |
|
808 |
|
|
809 |
It can be set to any of the following values: |
|
810 |
t export all timestamps. |
|
811 |
`active' export active timestamps only. |
|
812 |
`inactive' export inactive timestamps only. |
|
813 |
nil do not export timestamps |
|
814 |
|
|
815 |
This only applies to timestamps isolated in a paragraph |
|
816 |
containing only timestamps. Other timestamps are always |
|
817 |
exported. |
|
818 |
|
|
819 |
This option can also be set with the OPTIONS keyword, e.g. |
|
820 |
\"<:nil\"." |
|
821 |
:group 'org-export-general |
|
822 |
:type '(choice |
|
823 |
(const :tag "All timestamps" t) |
|
824 |
(const :tag "Only active timestamps" active) |
|
825 |
(const :tag "Only inactive timestamps" inactive) |
|
826 |
(const :tag "No timestamp" nil)) |
|
827 |
:safe (lambda (x) (memq x '(t nil active inactive)))) |
|
828 |
|
|
829 |
(defcustom org-export-with-todo-keywords t |
|
830 |
"Non-nil means include TODO keywords in export. |
|
831 |
When nil, remove all these keywords from the export. This option |
|
832 |
can also be set with the OPTIONS keyword, e.g. \"todo:nil\"." |
|
833 |
:group 'org-export-general |
|
834 |
:type 'boolean) |
|
835 |
|
|
836 |
(defcustom org-export-allow-bind-keywords nil |
|
837 |
"Non-nil means BIND keywords can define local variable values. |
|
838 |
This is a potential security risk, which is why the default value |
|
839 |
is nil. You can also allow them through local buffer variables." |
|
840 |
:group 'org-export-general |
|
841 |
:version "24.4" |
|
842 |
:package-version '(Org . "8.0") |
|
843 |
:type 'boolean) |
|
844 |
|
|
845 |
(defcustom org-export-with-broken-links nil |
|
846 |
"Non-nil means do not raise an error on broken links. |
|
847 |
|
|
848 |
When this variable is non-nil, broken links are ignored, without |
|
849 |
stopping the export process. If it is set to `mark', broken |
|
850 |
links are marked as such in the output, with a string like |
|
851 |
|
|
852 |
[BROKEN LINK: path] |
|
853 |
|
|
854 |
where PATH is the un-resolvable reference. |
|
855 |
|
|
856 |
This option can also be set with the OPTIONS keyword, e.g., |
|
857 |
\"broken-links:mark\"." |
|
858 |
:group 'org-export-general |
|
859 |
:version "26.1" |
|
860 |
:package-version '(Org . "9.0") |
|
861 |
:type '(choice |
|
862 |
(const :tag "Ignore broken links" t) |
|
863 |
(const :tag "Mark broken links in output" mark) |
|
864 |
(const :tag "Raise an error" nil))) |
|
865 |
|
|
866 |
(defcustom org-export-snippet-translation-alist nil |
|
867 |
"Alist between export snippets back-ends and exporter back-ends. |
|
868 |
|
|
869 |
This variable allows providing shortcuts for export snippets. |
|
870 |
|
|
871 |
For example, with a value of \\='((\"h\" . \"html\")), the |
|
872 |
HTML back-end will recognize the contents of \"@@h:<b>@@\" as |
|
873 |
HTML code while every other back-end will ignore it." |
|
874 |
:group 'org-export-general |
|
875 |
:version "24.4" |
|
876 |
:package-version '(Org . "8.0") |
|
877 |
:type '(repeat |
|
878 |
(cons (string :tag "Shortcut") |
|
879 |
(string :tag "Back-end"))) |
|
880 |
:safe (lambda (x) |
|
881 |
(and (listp x) |
|
882 |
(cl-every #'consp x) |
|
883 |
(cl-every #'stringp (mapcar #'car x)) |
|
884 |
(cl-every #'stringp (mapcar #'cdr x))))) |
|
885 |
|
|
886 |
(defcustom org-export-global-macros nil |
|
887 |
"Alist between macro names and expansion templates. |
|
888 |
|
|
889 |
This variable defines macro expansion templates available |
|
890 |
globally. Associations follow the pattern |
|
891 |
|
|
892 |
(NAME . TEMPLATE) |
|
893 |
|
|
894 |
where NAME is a string beginning with a letter and consisting of |
|
895 |
alphanumeric characters only. |
|
896 |
|
|
897 |
TEMPLATE is the string to which the macro is going to be |
|
898 |
expanded. Inside, \"$1\", \"$2\"... are place-holders for |
|
899 |
macro's arguments. Moreover, if the template starts with |
|
900 |
\"(eval\", it will be parsed as an Elisp expression and evaluated |
|
901 |
accordingly." |
|
902 |
:group 'org-export-general |
|
903 |
:version "26.1" |
|
904 |
:package-version '(Org . "9.1") |
|
905 |
:type '(repeat |
|
906 |
(cons (string :tag "Name") |
|
907 |
(string :tag "Template")))) |
|
908 |
|
|
909 |
(defcustom org-export-coding-system nil |
|
910 |
"Coding system for the exported file." |
|
911 |
:group 'org-export-general |
|
912 |
:version "24.4" |
|
913 |
:package-version '(Org . "8.0") |
|
914 |
:type 'coding-system) |
|
915 |
|
|
916 |
(defcustom org-export-copy-to-kill-ring nil |
|
917 |
"Non-nil means pushing export output to the kill ring. |
|
918 |
This variable is ignored during asynchronous export." |
|
919 |
:group 'org-export-general |
|
920 |
:version "26.1" |
|
921 |
:package-version '(Org . "8.3") |
|
922 |
:type '(choice |
|
923 |
(const :tag "Always" t) |
|
924 |
(const :tag "When export is done interactively" if-interactive) |
|
925 |
(const :tag "Never" nil))) |
|
926 |
|
|
927 |
(defcustom org-export-initial-scope 'buffer |
|
928 |
"The initial scope when exporting with `org-export-dispatch'. |
|
929 |
This variable can be either set to `buffer' or `subtree'." |
|
930 |
:group 'org-export-general |
|
931 |
:type '(choice |
|
932 |
(const :tag "Export current buffer" buffer) |
|
933 |
(const :tag "Export current subtree" subtree))) |
|
934 |
|
|
935 |
(defcustom org-export-show-temporary-export-buffer t |
|
936 |
"Non-nil means show buffer after exporting to temp buffer. |
|
937 |
When Org exports to a file, the buffer visiting that file is never |
|
938 |
shown, but remains buried. However, when exporting to |
|
939 |
a temporary buffer, that buffer is popped up in a second window. |
|
940 |
When this variable is nil, the buffer remains buried also in |
|
941 |
these cases." |
|
942 |
:group 'org-export-general |
|
943 |
:type 'boolean) |
|
944 |
|
|
945 |
(defcustom org-export-in-background nil |
|
946 |
"Non-nil means export and publishing commands will run in background. |
|
947 |
Results from an asynchronous export are never displayed |
|
948 |
automatically. But you can retrieve them with `\\[org-export-stack]'." |
|
949 |
:group 'org-export-general |
|
950 |
:version "24.4" |
|
951 |
:package-version '(Org . "8.0") |
|
952 |
:type 'boolean) |
|
953 |
|
|
954 |
(defcustom org-export-async-init-file nil |
|
955 |
"File used to initialize external export process. |
|
956 |
|
|
957 |
Value must be either nil or an absolute file name. When nil, the |
|
958 |
external process is launched like a regular Emacs session, |
|
959 |
loading user's initialization file and any site specific |
|
960 |
configuration. If a file is provided, it, and only it, is loaded |
|
961 |
at start-up. |
|
962 |
|
|
963 |
Therefore, using a specific configuration makes the process to |
|
964 |
load faster and the export more portable." |
|
965 |
:group 'org-export-general |
|
966 |
:version "24.4" |
|
967 |
:package-version '(Org . "8.0") |
|
968 |
:type '(choice |
|
969 |
(const :tag "Regular startup" nil) |
|
970 |
(file :tag "Specific start-up file" :must-match t))) |
|
971 |
|
|
972 |
(defcustom org-export-dispatch-use-expert-ui nil |
|
973 |
"Non-nil means using a non-intrusive `org-export-dispatch'. |
|
974 |
In that case, no help buffer is displayed. Though, an indicator |
|
975 |
for current export scope is added to the prompt (\"b\" when |
|
976 |
output is restricted to body only, \"s\" when it is restricted to |
|
977 |
the current subtree, \"v\" when only visible elements are |
|
978 |
considered for export, \"f\" when publishing functions should be |
|
979 |
passed the FORCE argument and \"a\" when the export should be |
|
980 |
asynchronous). Also, [?] allows switching back to standard |
|
981 |
mode." |
|
982 |
:group 'org-export-general |
|
983 |
:version "24.4" |
|
984 |
:package-version '(Org . "8.0") |
|
985 |
:type 'boolean) |
|
986 |
|
|
987 |
|
|
988 |
|
|
989 |
;;; Defining Back-ends |
|
990 |
;; |
|
991 |
;; An export back-end is a structure with `org-export-backend' type |
|
992 |
;; and `name', `parent', `transcoders', `options', `filters', `blocks' |
|
993 |
;; and `menu' slots. |
|
994 |
;; |
|
995 |
;; At the lowest level, a back-end is created with |
|
996 |
;; `org-export-create-backend' function. |
|
997 |
;; |
|
998 |
;; A named back-end can be registered with |
|
999 |
;; `org-export-register-backend' function. A registered back-end can |
|
1000 |
;; later be referred to by its name, with `org-export-get-backend' |
|
1001 |
;; function. Also, such a back-end can become the parent of a derived |
|
1002 |
;; back-end from which slot values will be inherited by default. |
|
1003 |
;; `org-export-derived-backend-p' can check if a given back-end is |
|
1004 |
;; derived from a list of back-end names. |
|
1005 |
;; |
|
1006 |
;; `org-export-get-all-transcoders', `org-export-get-all-options' and |
|
1007 |
;; `org-export-get-all-filters' return the full alist of transcoders, |
|
1008 |
;; options and filters, including those inherited from ancestors. |
|
1009 |
;; |
|
1010 |
;; At a higher level, `org-export-define-backend' is the standard way |
|
1011 |
;; to define an export back-end. If the new back-end is similar to |
|
1012 |
;; a registered back-end, `org-export-define-derived-backend' may be |
|
1013 |
;; used instead. |
|
1014 |
;; |
|
1015 |
;; Eventually `org-export-barf-if-invalid-backend' returns an error |
|
1016 |
;; when a given back-end hasn't been registered yet. |
|
1017 |
|
|
1018 |
(cl-defstruct (org-export-backend (:constructor org-export-create-backend) |
|
1019 |
(:copier nil)) |
|
1020 |
name parent transcoders options filters blocks menu) |
|
1021 |
|
|
1022 |
;;;###autoload |
|
1023 |
(defun org-export-get-backend (name) |
|
1024 |
"Return export back-end named after NAME. |
|
1025 |
NAME is a symbol. Return nil if no such back-end is found." |
|
1026 |
(cl-find-if (lambda (b) (and (eq name (org-export-backend-name b)))) |
|
1027 |
org-export-registered-backends)) |
|
1028 |
|
|
1029 |
(defun org-export-register-backend (backend) |
|
1030 |
"Register BACKEND as a known export back-end. |
|
1031 |
BACKEND is a structure with `org-export-backend' type." |
|
1032 |
;; Refuse to register an unnamed back-end. |
|
1033 |
(unless (org-export-backend-name backend) |
|
1034 |
(error "Cannot register a unnamed export back-end")) |
|
1035 |
;; Refuse to register a back-end with an unknown parent. |
|
1036 |
(let ((parent (org-export-backend-parent backend))) |
|
1037 |
(when (and parent (not (org-export-get-backend parent))) |
|
1038 |
(error "Cannot use unknown \"%s\" back-end as a parent" parent))) |
|
1039 |
;; If a back-end with the same name as BACKEND is already |
|
1040 |
;; registered, replace it with BACKEND. Otherwise, simply add |
|
1041 |
;; BACKEND to the list of registered back-ends. |
|
1042 |
(let ((old (org-export-get-backend (org-export-backend-name backend)))) |
|
1043 |
(if old (setcar (memq old org-export-registered-backends) backend) |
|
1044 |
(push backend org-export-registered-backends)))) |
|
1045 |
|
|
1046 |
(defun org-export-barf-if-invalid-backend (backend) |
|
1047 |
"Signal an error if BACKEND isn't defined." |
|
1048 |
(unless (org-export-backend-p backend) |
|
1049 |
(error "Unknown \"%s\" back-end: Aborting export" backend))) |
|
1050 |
|
|
1051 |
(defun org-export-derived-backend-p (backend &rest backends) |
|
1052 |
"Non-nil if BACKEND is derived from one of BACKENDS. |
|
1053 |
BACKEND is an export back-end, as returned by, e.g., |
|
1054 |
`org-export-create-backend', or a symbol referring to |
|
1055 |
a registered back-end. BACKENDS is constituted of symbols." |
|
1056 |
(when (symbolp backend) (setq backend (org-export-get-backend backend))) |
|
1057 |
(when backend |
|
1058 |
(catch 'exit |
|
1059 |
(while (org-export-backend-parent backend) |
|
1060 |
(when (memq (org-export-backend-name backend) backends) |
|
1061 |
(throw 'exit t)) |
|
1062 |
(setq backend |
|
1063 |
(org-export-get-backend (org-export-backend-parent backend)))) |
|
1064 |
(memq (org-export-backend-name backend) backends)))) |
|
1065 |
|
|
1066 |
(defun org-export-get-all-transcoders (backend) |
|
1067 |
"Return full translation table for BACKEND. |
|
1068 |
|
|
1069 |
BACKEND is an export back-end, as return by, e.g,, |
|
1070 |
`org-export-create-backend'. Return value is an alist where |
|
1071 |
keys are element or object types, as symbols, and values are |
|
1072 |
transcoders. |
|
1073 |
|
|
1074 |
Unlike to `org-export-backend-transcoders', this function |
|
1075 |
also returns transcoders inherited from parent back-ends, |
|
1076 |
if any." |
|
1077 |
(when (symbolp backend) (setq backend (org-export-get-backend backend))) |
|
1078 |
(when backend |
|
1079 |
(let ((transcoders (org-export-backend-transcoders backend)) |
|
1080 |
parent) |
|
1081 |
(while (setq parent (org-export-backend-parent backend)) |
|
1082 |
(setq backend (org-export-get-backend parent)) |
|
1083 |
(setq transcoders |
|
1084 |
(append transcoders (org-export-backend-transcoders backend)))) |
|
1085 |
transcoders))) |
|
1086 |
|
|
1087 |
(defun org-export-get-all-options (backend) |
|
1088 |
"Return export options for BACKEND. |
|
1089 |
|
|
1090 |
BACKEND is an export back-end, as return by, e.g,, |
|
1091 |
`org-export-create-backend'. See `org-export-options-alist' |
|
1092 |
for the shape of the return value. |
|
1093 |
|
|
1094 |
Unlike to `org-export-backend-options', this function also |
|
1095 |
returns options inherited from parent back-ends, if any. |
|
1096 |
|
|
1097 |
Return nil if BACKEND is unknown." |
|
1098 |
(when (symbolp backend) (setq backend (org-export-get-backend backend))) |
|
1099 |
(when backend |
|
1100 |
(let ((options (org-export-backend-options backend)) |
|
1101 |
parent) |
|
1102 |
(while (setq parent (org-export-backend-parent backend)) |
|
1103 |
(setq backend (org-export-get-backend parent)) |
|
1104 |
(setq options (append options (org-export-backend-options backend)))) |
|
1105 |
options))) |
|
1106 |
|
|
1107 |
(defun org-export-get-all-filters (backend) |
|
1108 |
"Return complete list of filters for BACKEND. |
|
1109 |
|
|
1110 |
BACKEND is an export back-end, as return by, e.g,, |
|
1111 |
`org-export-create-backend'. Return value is an alist where |
|
1112 |
keys are symbols and values lists of functions. |
|
1113 |
|
|
1114 |
Unlike to `org-export-backend-filters', this function also |
|
1115 |
returns filters inherited from parent back-ends, if any." |
|
1116 |
(when (symbolp backend) (setq backend (org-export-get-backend backend))) |
|
1117 |
(when backend |
|
1118 |
(let ((filters (org-export-backend-filters backend)) |
|
1119 |
parent) |
|
1120 |
(while (setq parent (org-export-backend-parent backend)) |
|
1121 |
(setq backend (org-export-get-backend parent)) |
|
1122 |
(setq filters (append filters (org-export-backend-filters backend)))) |
|
1123 |
filters))) |
|
1124 |
|
|
1125 |
(defun org-export-define-backend (backend transcoders &rest body) |
|
1126 |
"Define a new back-end BACKEND. |
|
1127 |
|
|
1128 |
TRANSCODERS is an alist between object or element types and |
|
1129 |
functions handling them. |
|
1130 |
|
|
1131 |
These functions should return a string without any trailing |
|
1132 |
space, or nil. They must accept three arguments: the object or |
|
1133 |
element itself, its contents or nil when it isn't recursive and |
|
1134 |
the property list used as a communication channel. |
|
1135 |
|
|
1136 |
Contents, when not nil, are stripped from any global indentation |
|
1137 |
\(although the relative one is preserved). They also always end |
|
1138 |
with a single newline character. |
|
1139 |
|
|
1140 |
If, for a given type, no function is found, that element or |
|
1141 |
object type will simply be ignored, along with any blank line or |
|
1142 |
white space at its end. The same will happen if the function |
|
1143 |
returns the nil value. If that function returns the empty |
|
1144 |
string, the type will be ignored, but the blank lines or white |
|
1145 |
spaces will be kept. |
|
1146 |
|
|
1147 |
In addition to element and object types, one function can be |
|
1148 |
associated to the `template' (or `inner-template') symbol and |
|
1149 |
another one to the `plain-text' symbol. |
|
1150 |
|
|
1151 |
The former returns the final transcoded string, and can be used |
|
1152 |
to add a preamble and a postamble to document's body. It must |
|
1153 |
accept two arguments: the transcoded string and the property list |
|
1154 |
containing export options. A function associated to `template' |
|
1155 |
will not be applied if export has option \"body-only\". |
|
1156 |
A function associated to `inner-template' is always applied. |
|
1157 |
|
|
1158 |
The latter, when defined, is to be called on every text not |
|
1159 |
recognized as an element or an object. It must accept two |
|
1160 |
arguments: the text string and the information channel. It is an |
|
1161 |
appropriate place to protect special chars relative to the |
|
1162 |
back-end. |
|
1163 |
|
|
1164 |
BODY can start with pre-defined keyword arguments. The following |
|
1165 |
keywords are understood: |
|
1166 |
|
|
1167 |
:filters-alist |
|
1168 |
|
|
1169 |
Alist between filters and function, or list of functions, |
|
1170 |
specific to the back-end. See `org-export-filters-alist' for |
|
1171 |
a list of all allowed filters. Filters defined here |
|
1172 |
shouldn't make a back-end test, as it may prevent back-ends |
|
1173 |
derived from this one to behave properly. |
|
1174 |
|
|
1175 |
:menu-entry |
|
1176 |
|
|
1177 |
Menu entry for the export dispatcher. It should be a list |
|
1178 |
like: |
|
1179 |
|
|
1180 |
\\='(KEY DESCRIPTION-OR-ORDINAL ACTION-OR-MENU) |
|
1181 |
|
|
1182 |
where : |
|
1183 |
|
|
1184 |
KEY is a free character selecting the back-end. |
|
1185 |
|
|
1186 |
DESCRIPTION-OR-ORDINAL is either a string or a number. |
|
1187 |
|
|
1188 |
If it is a string, is will be used to name the back-end in |
|
1189 |
its menu entry. If it is a number, the following menu will |
|
1190 |
be displayed as a sub-menu of the back-end with the same |
|
1191 |
KEY. Also, the number will be used to determine in which |
|
1192 |
order such sub-menus will appear (lowest first). |
|
1193 |
|
|
1194 |
ACTION-OR-MENU is either a function or an alist. |
|
1195 |
|
|
1196 |
If it is an action, it will be called with four |
|
1197 |
arguments (booleans): ASYNC, SUBTREEP, VISIBLE-ONLY and |
|
1198 |
BODY-ONLY. See `org-export-as' for further explanations on |
|
1199 |
some of them. |
|
1200 |
|
|
1201 |
If it is an alist, associations should follow the |
|
1202 |
pattern: |
|
1203 |
|
|
1204 |
\\='(KEY DESCRIPTION ACTION) |
|
1205 |
|
|
1206 |
where KEY, DESCRIPTION and ACTION are described above. |
|
1207 |
|
|
1208 |
Valid values include: |
|
1209 |
|
|
1210 |
\\='(?m \"My Special Back-end\" my-special-export-function) |
|
1211 |
|
|
1212 |
or |
|
1213 |
|
|
1214 |
\\='(?l \"Export to LaTeX\" |
|
1215 |
(?p \"As PDF file\" org-latex-export-to-pdf) |
|
1216 |
(?o \"As PDF file and open\" |
|
1217 |
(lambda (a s v b) |
|
1218 |
(if a (org-latex-export-to-pdf t s v b) |
|
1219 |
(org-open-file |
|
1220 |
(org-latex-export-to-pdf nil s v b))))))) |
|
1221 |
|
|
1222 |
or the following, which will be added to the previous |
|
1223 |
sub-menu, |
|
1224 |
|
|
1225 |
\\='(?l 1 |
|
1226 |
((?B \"As TEX buffer (Beamer)\" org-beamer-export-as-latex) |
|
1227 |
(?P \"As PDF file (Beamer)\" org-beamer-export-to-pdf))) |
|
1228 |
|
|
1229 |
:options-alist |
|
1230 |
|
|
1231 |
Alist between back-end specific properties introduced in |
|
1232 |
communication channel and how their value are acquired. See |
|
1233 |
`org-export-options-alist' for more information about |
|
1234 |
structure of the values." |
|
1235 |
(declare (indent 1)) |
|
1236 |
(let (filters menu-entry options) |
|
1237 |
(while (keywordp (car body)) |
|
1238 |
(let ((keyword (pop body))) |
|
1239 |
(pcase keyword |
|
1240 |
(:filters-alist (setq filters (pop body))) |
|
1241 |
(:menu-entry (setq menu-entry (pop body))) |
|
1242 |
(:options-alist (setq options (pop body))) |
|
1243 |
(_ (error "Unknown keyword: %s" keyword))))) |
|
1244 |
(org-export-register-backend |
|
1245 |
(org-export-create-backend :name backend |
|
1246 |
:transcoders transcoders |
|
1247 |
:options options |
|
1248 |
:filters filters |
|
1249 |
:menu menu-entry)))) |
|
1250 |
|
|
1251 |
(defun org-export-define-derived-backend (child parent &rest body) |
|
1252 |
"Create a new back-end as a variant of an existing one. |
|
1253 |
|
|
1254 |
CHILD is the name of the derived back-end. PARENT is the name of |
|
1255 |
the parent back-end. |
|
1256 |
|
|
1257 |
BODY can start with pre-defined keyword arguments. The following |
|
1258 |
keywords are understood: |
|
1259 |
|
|
1260 |
:filters-alist |
|
1261 |
|
|
1262 |
Alist of filters that will overwrite or complete filters |
|
1263 |
defined in PARENT back-end. See `org-export-filters-alist' |
|
1264 |
for a list of allowed filters. |
|
1265 |
|
|
1266 |
:menu-entry |
|
1267 |
|
|
1268 |
Menu entry for the export dispatcher. See |
|
1269 |
`org-export-define-backend' for more information about the |
|
1270 |
expected value. |
|
1271 |
|
|
1272 |
:options-alist |
|
1273 |
|
|
1274 |
Alist of back-end specific properties that will overwrite or |
|
1275 |
complete those defined in PARENT back-end. Refer to |
|
1276 |
`org-export-options-alist' for more information about |
|
1277 |
structure of the values. |
|
1278 |
|
|
1279 |
:translate-alist |
|
1280 |
|
|
1281 |
Alist of element and object types and transcoders that will |
|
1282 |
overwrite or complete transcode table from PARENT back-end. |
|
1283 |
Refer to `org-export-define-backend' for detailed information |
|
1284 |
about transcoders. |
|
1285 |
|
|
1286 |
As an example, here is how one could define \"my-latex\" back-end |
|
1287 |
as a variant of `latex' back-end with a custom template function: |
|
1288 |
|
|
1289 |
(org-export-define-derived-backend \\='my-latex \\='latex |
|
1290 |
:translate-alist \\='((template . my-latex-template-fun))) |
|
1291 |
|
|
1292 |
The back-end could then be called with, for example: |
|
1293 |
|
|
1294 |
(org-export-to-buffer \\='my-latex \"*Test my-latex*\")" |
|
1295 |
(declare (indent 2)) |
|
1296 |
(let (filters menu-entry options transcoders) |
|
1297 |
(while (keywordp (car body)) |
|
1298 |
(let ((keyword (pop body))) |
|
1299 |
(pcase keyword |
|
1300 |
(:filters-alist (setq filters (pop body))) |
|
1301 |
(:menu-entry (setq menu-entry (pop body))) |
|
1302 |
(:options-alist (setq options (pop body))) |
|
1303 |
(:translate-alist (setq transcoders (pop body))) |
|
1304 |
(_ (error "Unknown keyword: %s" keyword))))) |
|
1305 |
(org-export-register-backend |
|
1306 |
(org-export-create-backend :name child |
|
1307 |
:parent parent |
|
1308 |
:transcoders transcoders |
|
1309 |
:options options |
|
1310 |
:filters filters |
|
1311 |
:menu menu-entry)))) |
|
1312 |
|
|
1313 |
|
|
1314 |
|
|
1315 |
;;; The Communication Channel |
|
1316 |
;; |
|
1317 |
;; During export process, every function has access to a number of |
|
1318 |
;; properties. They are of two types: |
|
1319 |
;; |
|
1320 |
;; 1. Environment options are collected once at the very beginning of |
|
1321 |
;; the process, out of the original buffer and configuration. |
|
1322 |
;; Collecting them is handled by `org-export-get-environment' |
|
1323 |
;; function. |
|
1324 |
;; |
|
1325 |
;; Most environment options are defined through the |
|
1326 |
;; `org-export-options-alist' variable. |
|
1327 |
;; |
|
1328 |
;; 2. Tree properties are extracted directly from the parsed tree, |
|
1329 |
;; just before export, by `org-export--collect-tree-properties'. |
|
1330 |
|
|
1331 |
;;;; Environment Options |
|
1332 |
;; |
|
1333 |
;; Environment options encompass all parameters defined outside the |
|
1334 |
;; scope of the parsed data. They come from five sources, in |
|
1335 |
;; increasing precedence order: |
|
1336 |
;; |
|
1337 |
;; - Global variables, |
|
1338 |
;; - Buffer's attributes, |
|
1339 |
;; - Options keyword symbols, |
|
1340 |
;; - Buffer keywords, |
|
1341 |
;; - Subtree properties. |
|
1342 |
;; |
|
1343 |
;; The central internal function with regards to environment options |
|
1344 |
;; is `org-export-get-environment'. It updates global variables with |
|
1345 |
;; "#+BIND:" keywords, then retrieve and prioritize properties from |
|
1346 |
;; the different sources. |
|
1347 |
;; |
|
1348 |
;; The internal functions doing the retrieval are: |
|
1349 |
;; `org-export--get-global-options', |
|
1350 |
;; `org-export--get-buffer-attributes', |
|
1351 |
;; `org-export--parse-option-keyword', |
|
1352 |
;; `org-export--get-subtree-options' and |
|
1353 |
;; `org-export--get-inbuffer-options' |
|
1354 |
;; |
|
1355 |
;; Also, `org-export--list-bound-variables' collects bound variables |
|
1356 |
;; along with their value in order to set them as buffer local |
|
1357 |
;; variables later in the process. |
|
1358 |
|
|
1359 |
;;;###autoload |
|
1360 |
(defun org-export-get-environment (&optional backend subtreep ext-plist) |
|
1361 |
"Collect export options from the current buffer. |
|
1362 |
|
|
1363 |
Optional argument BACKEND is an export back-end, as returned by |
|
1364 |
`org-export-create-backend'. |
|
1365 |
|
|
1366 |
When optional argument SUBTREEP is non-nil, assume the export is |
|
1367 |
done against the current sub-tree. |
|
1368 |
|
|
1369 |
Third optional argument EXT-PLIST is a property list with |
|
1370 |
external parameters overriding Org default settings, but still |
|
1371 |
inferior to file-local settings." |
|
1372 |
;; First install #+BIND variables since these must be set before |
|
1373 |
;; global options are read. |
|
1374 |
(dolist (pair (org-export--list-bound-variables)) |
|
1375 |
(set (make-local-variable (car pair)) (nth 1 pair))) |
|
1376 |
;; Get and prioritize export options... |
|
1377 |
(org-combine-plists |
|
1378 |
;; ... from global variables... |
|
1379 |
(org-export--get-global-options backend) |
|
1380 |
;; ... from an external property list... |
|
1381 |
ext-plist |
|
1382 |
;; ... from in-buffer settings... |
|
1383 |
(org-export--get-inbuffer-options backend) |
|
1384 |
;; ... and from subtree, when appropriate. |
|
1385 |
(and subtreep (org-export--get-subtree-options backend)))) |
|
1386 |
|
|
1387 |
(defun org-export--parse-option-keyword (options &optional backend) |
|
1388 |
"Parse an OPTIONS line and return values as a plist. |
|
1389 |
Optional argument BACKEND is an export back-end, as returned by, |
|
1390 |
e.g., `org-export-create-backend'. It specifies which back-end |
|
1391 |
specific items to read, if any." |
|
1392 |
(let ((line |
|
1393 |
(let ((s 0) alist) |
|
1394 |
(while (string-match "\\(.+?\\):\\((.*?)\\|\\S-*\\)[ \t]*" options s) |
|
1395 |
(setq s (match-end 0)) |
|
1396 |
(push (cons (match-string 1 options) |
|
1397 |
(read (match-string 2 options))) |
|
1398 |
alist)) |
|
1399 |
alist)) |
|
1400 |
;; Priority is given to back-end specific options. |
|
1401 |
(all (append (org-export-get-all-options backend) |
|
1402 |
org-export-options-alist)) |
|
1403 |
(plist)) |
|
1404 |
(when line |
|
1405 |
(dolist (entry all plist) |
|
1406 |
(let ((item (nth 2 entry))) |
|
1407 |
(when item |
|
1408 |
(let ((v (assoc-string item line t))) |
|
1409 |
(when v (setq plist (plist-put plist (car entry) (cdr v))))))))))) |
|
1410 |
|
|
1411 |
(defun org-export--get-subtree-options (&optional backend) |
|
1412 |
"Get export options in subtree at point. |
|
1413 |
Optional argument BACKEND is an export back-end, as returned by, |
|
1414 |
e.g., `org-export-create-backend'. It specifies back-end used |
|
1415 |
for export. Return options as a plist." |
|
1416 |
;; For each buffer keyword, create a headline property setting the |
|
1417 |
;; same property in communication channel. The name for the |
|
1418 |
;; property is the keyword with "EXPORT_" appended to it. |
|
1419 |
(org-with-wide-buffer |
|
1420 |
;; Make sure point is at a heading. |
|
1421 |
(if (org-at-heading-p) (org-up-heading-safe) (org-back-to-heading t)) |
|
1422 |
(let ((plist |
|
1423 |
;; EXPORT_OPTIONS are parsed in a non-standard way. Take |
|
1424 |
;; care of them right from the start. |
|
1425 |
(let ((o (org-entry-get (point) "EXPORT_OPTIONS" 'selective))) |
|
1426 |
(and o (org-export--parse-option-keyword o backend)))) |
|
1427 |
;; Take care of EXPORT_TITLE. If it isn't defined, use |
|
1428 |
;; headline's title (with no todo keyword, priority cookie or |
|
1429 |
;; tag) as its fallback value. |
|
1430 |
(cache (list |
|
1431 |
(cons "TITLE" |
|
1432 |
(or (org-entry-get (point) "EXPORT_TITLE" 'selective) |
|
1433 |
(let ((case-fold-search nil)) |
|
1434 |
(looking-at org-complex-heading-regexp) |
|
1435 |
(match-string-no-properties 4)))))) |
|
1436 |
;; Look for both general keywords and back-end specific |
|
1437 |
;; options, with priority given to the latter. |
|
1438 |
(options (append (org-export-get-all-options backend) |
|
1439 |
org-export-options-alist))) |
|
1440 |
;; Handle other keywords. Then return PLIST. |
|
1441 |
(dolist (option options plist) |
|
1442 |
(let ((property (car option)) |
|
1443 |
(keyword (nth 1 option))) |
|
1444 |
(when keyword |
|
1445 |
(let ((value |
|
1446 |
(or (cdr (assoc keyword cache)) |
|
1447 |
(let ((v (org-entry-get (point) |
|
1448 |
(concat "EXPORT_" keyword) |
|
1449 |
'selective))) |
|
1450 |
(push (cons keyword v) cache) v)))) |
|
1451 |
(when value |
|
1452 |
(setq plist |
|
1453 |
(plist-put plist |
|
1454 |
property |
|
1455 |
(cl-case (nth 4 option) |
|
1456 |
(parse |
|
1457 |
(org-element-parse-secondary-string |
|
1458 |
value (org-element-restriction 'keyword))) |
|
1459 |
(split (split-string value)) |
|
1460 |
(t value)))))))))))) |
|
1461 |
|
|
1462 |
(defun org-export--get-inbuffer-options (&optional backend) |
|
1463 |
"Return current buffer export options, as a plist. |
|
1464 |
|
|
1465 |
Optional argument BACKEND, when non-nil, is an export back-end, |
|
1466 |
as returned by, e.g., `org-export-create-backend'. It specifies |
|
1467 |
which back-end specific options should also be read in the |
|
1468 |
process. |
|
1469 |
|
|
1470 |
Assume buffer is in Org mode. Narrowing, if any, is ignored." |
|
1471 |
(let* ((case-fold-search t) |
|
1472 |
(options (append |
|
1473 |
;; Priority is given to back-end specific options. |
|
1474 |
(org-export-get-all-options backend) |
|
1475 |
org-export-options-alist)) |
|
1476 |
(regexp (format "^[ \t]*#\\+%s:" |
|
1477 |
(regexp-opt (nconc (delq nil (mapcar #'cadr options)) |
|
1478 |
org-export-special-keywords)))) |
|
1479 |
plist to-parse) |
|
1480 |
(letrec ((find-properties |
|
1481 |
(lambda (keyword) |
|
1482 |
;; Return all properties associated to KEYWORD. |
|
1483 |
(let (properties) |
|
1484 |
(dolist (option options properties) |
|
1485 |
(when (equal (nth 1 option) keyword) |
|
1486 |
(cl-pushnew (car option) properties)))))) |
|
1487 |
(get-options |
|
1488 |
(lambda (&optional files) |
|
1489 |
;; Recursively read keywords in buffer. FILES is |
|
1490 |
;; a list of files read so far. PLIST is the current |
|
1491 |
;; property list obtained. |
|
1492 |
(org-with-wide-buffer |
|
1493 |
(goto-char (point-min)) |
|
1494 |
(while (re-search-forward regexp nil t) |
|
1495 |
(let ((element (org-element-at-point))) |
|
1496 |
(when (eq (org-element-type element) 'keyword) |
|
1497 |
(let ((key (org-element-property :key element)) |
|
1498 |
(val (org-element-property :value element))) |
|
1499 |
(cond |
|
1500 |
;; Options in `org-export-special-keywords'. |
|
1501 |
((equal key "SETUPFILE") |
|
1502 |
(let* ((uri (org-unbracket-string "\"" "\"" (org-trim val))) |
|
1503 |
(uri-is-url (org-file-url-p uri)) |
|
1504 |
(uri (if uri-is-url |
|
1505 |
uri |
|
1506 |
(expand-file-name uri)))) |
|
1507 |
;; Avoid circular dependencies. |
|
1508 |
(unless (member uri files) |
|
1509 |
(with-temp-buffer |
|
1510 |
(unless uri-is-url |
|
1511 |
(setq default-directory |
|
1512 |
(file-name-directory uri))) |
|
1513 |
(insert (org-file-contents uri 'noerror)) |
|
1514 |
(let ((org-inhibit-startup t)) (org-mode)) |
|
1515 |
(funcall get-options (cons uri files)))))) |
|
1516 |
((equal key "OPTIONS") |
|
1517 |
(setq plist |
|
1518 |
(org-combine-plists |
|
1519 |
plist |
|
1520 |
(org-export--parse-option-keyword |
|
1521 |
val backend)))) |
|
1522 |
((equal key "FILETAGS") |
|
1523 |
(setq plist |
|
1524 |
(org-combine-plists |
|
1525 |
plist |
|
1526 |
(list :filetags |
|
1527 |
(org-uniquify |
|
1528 |
(append |
|
1529 |
(org-split-string val ":") |
|
1530 |
(plist-get plist :filetags))))))) |
|
1531 |
(t |
|
1532 |
;; Options in `org-export-options-alist'. |
|
1533 |
(dolist (property (funcall find-properties key)) |
|
1534 |
(setq |
|
1535 |
plist |
|
1536 |
(plist-put |
|
1537 |
plist property |
|
1538 |
;; Handle value depending on specified |
|
1539 |
;; BEHAVIOR. |
|
1540 |
(cl-case (nth 4 (assq property options)) |
|
1541 |
(parse |
|
1542 |
(unless (memq property to-parse) |
|
1543 |
(push property to-parse)) |
|
1544 |
;; Even if `parse' implies `space' |
|
1545 |
;; behavior, we separate line with |
|
1546 |
;; "\n" so as to preserve |
|
1547 |
;; line-breaks. However, empty |
|
1548 |
;; lines are forbidden since `parse' |
|
1549 |
;; doesn't allow more than one |
|
1550 |
;; paragraph. |
|
1551 |
(let ((old (plist-get plist property))) |
|
1552 |
(cond ((not (org-string-nw-p val)) old) |
|
1553 |
(old (concat old "\n" val)) |
|
1554 |
(t val)))) |
|
1555 |
(space |
|
1556 |
(if (not (plist-get plist property)) |
|
1557 |
(org-trim val) |
|
1558 |
(concat (plist-get plist property) |
|
1559 |
" " |
|
1560 |
(org-trim val)))) |
|
1561 |
(newline |
|
1562 |
(org-trim |
|
1563 |
(concat (plist-get plist property) |
|
1564 |
"\n" |
|
1565 |
(org-trim val)))) |
|
1566 |
(split `(,@(plist-get plist property) |
|
1567 |
,@(split-string val))) |
|
1568 |
((t) val) |
|
1569 |
(otherwise |
|
1570 |
(if (not (plist-member plist property)) val |
|
1571 |
(plist-get plist property))))))))))))))))) |
|
1572 |
;; Read options in the current buffer and return value. |
|
1573 |
(funcall get-options (and buffer-file-name (list buffer-file-name))) |
|
1574 |
;; Parse properties in TO-PARSE. Remove newline characters not |
|
1575 |
;; involved in line breaks to simulate `space' behavior. |
|
1576 |
;; Finally return options. |
|
1577 |
(dolist (p to-parse plist) |
|
1578 |
(let ((value (org-element-parse-secondary-string |
|
1579 |
(plist-get plist p) |
|
1580 |
(org-element-restriction 'keyword)))) |
|
1581 |
(org-element-map value 'plain-text |
|
1582 |
(lambda (s) |
|
1583 |
(org-element-set-element |
|
1584 |
s (replace-regexp-in-string "\n" " " s)))) |
|
1585 |
(setq plist (plist-put plist p value))))))) |
|
1586 |
|
|
1587 |
(defun org-export--get-export-attributes |
|
1588 |
(&optional backend subtreep visible-only body-only) |
|
1589 |
"Return properties related to export process, as a plist. |
|
1590 |
Optional arguments BACKEND, SUBTREEP, VISIBLE-ONLY and BODY-ONLY |
|
1591 |
are like the arguments with the same names of function |
|
1592 |
`org-export-as'." |
|
1593 |
(list :export-options (delq nil |
|
1594 |
(list (and subtreep 'subtree) |
|
1595 |
(and visible-only 'visible-only) |
|
1596 |
(and body-only 'body-only))) |
|
1597 |
:back-end backend |
|
1598 |
:translate-alist (org-export-get-all-transcoders backend) |
|
1599 |
:exported-data (make-hash-table :test #'eq :size 4001))) |
|
1600 |
|
|
1601 |
(defun org-export--get-buffer-attributes () |
|
1602 |
"Return properties related to buffer attributes, as a plist." |
|
1603 |
(list :input-buffer (buffer-name (buffer-base-buffer)) |
|
1604 |
:input-file (buffer-file-name (buffer-base-buffer)))) |
|
1605 |
|
|
1606 |
(defun org-export--get-global-options (&optional backend) |
|
1607 |
"Return global export options as a plist. |
|
1608 |
Optional argument BACKEND, if non-nil, is an export back-end, as |
|
1609 |
returned by, e.g., `org-export-create-backend'. It specifies |
|
1610 |
which back-end specific export options should also be read in the |
|
1611 |
process." |
|
1612 |
(let (plist |
|
1613 |
;; Priority is given to back-end specific options. |
|
1614 |
(all (append (org-export-get-all-options backend) |
|
1615 |
org-export-options-alist))) |
|
1616 |
(dolist (cell all plist) |
|
1617 |
(let ((prop (car cell))) |
|
1618 |
(unless (plist-member plist prop) |
|
1619 |
(setq plist |
|
1620 |
(plist-put |
|
1621 |
plist |
|
1622 |
prop |
|
1623 |
;; Evaluate default value provided. |
|
1624 |
(let ((value (eval (nth 3 cell)))) |
|
1625 |
(if (eq (nth 4 cell) 'parse) |
|
1626 |
(org-element-parse-secondary-string |
|
1627 |
value (org-element-restriction 'keyword)) |
|
1628 |
value))))))))) |
|
1629 |
|
|
1630 |
(defun org-export--list-bound-variables () |
|
1631 |
"Return variables bound from BIND keywords in current buffer. |
|
1632 |
Also look for BIND keywords in setup files. The return value is |
|
1633 |
an alist where associations are (VARIABLE-NAME VALUE)." |
|
1634 |
(when org-export-allow-bind-keywords |
|
1635 |
(letrec ((collect-bind |
|
1636 |
(lambda (files alist) |
|
1637 |
;; Return an alist between variable names and their |
|
1638 |
;; value. FILES is a list of setup files names read |
|
1639 |
;; so far, used to avoid circular dependencies. ALIST |
|
1640 |
;; is the alist collected so far. |
|
1641 |
(let ((case-fold-search t)) |
|
1642 |
(org-with-wide-buffer |
|
1643 |
(goto-char (point-min)) |
|
1644 |
(while (re-search-forward |
|
1645 |
"^[ \t]*#\\+\\(BIND\\|SETUPFILE\\):" nil t) |
|
1646 |
(let ((element (org-element-at-point))) |
|
1647 |
(when (eq (org-element-type element) 'keyword) |
|
1648 |
(let ((val (org-element-property :value element))) |
|
1649 |
(if (equal (org-element-property :key element) |
|
1650 |
"BIND") |
|
1651 |
(push (read (format "(%s)" val)) alist) |
|
1652 |
;; Enter setup file. |
|
1653 |
(let* ((uri (org-unbracket-string "\"" "\"" val)) |
|
1654 |
(uri-is-url (org-file-url-p uri)) |
|
1655 |
(uri (if uri-is-url |
|
1656 |
uri |
|
1657 |
(expand-file-name uri)))) |
|
1658 |
;; Avoid circular dependencies. |
|
1659 |
(unless (member uri files) |
|
1660 |
(with-temp-buffer |
|
1661 |
(unless uri-is-url |
|
1662 |
(setq default-directory |
|
1663 |
(file-name-directory uri))) |
|
1664 |
(let ((org-inhibit-startup t)) (org-mode)) |
|
1665 |
(insert (org-file-contents uri 'noerror)) |
|
1666 |
(setq alist |
|
1667 |
(funcall collect-bind |
|
1668 |
(cons uri files) |
|
1669 |
alist)))))))))) |
|
1670 |
alist))))) |
|
1671 |
;; Return value in appropriate order of appearance. |
|
1672 |
(nreverse (funcall collect-bind nil nil))))) |
|
1673 |
|
|
1674 |
;; defsubst org-export-get-parent must be defined before first use, |
|
1675 |
;; was originally defined in the topology section |
|
1676 |
|
|
1677 |
(defsubst org-export-get-parent (blob) |
|
1678 |
"Return BLOB parent or nil. |
|
1679 |
BLOB is the element or object considered." |
|
1680 |
(org-element-property :parent blob)) |
|
1681 |
|
|
1682 |
;;;; Tree Properties |
|
1683 |
;; |
|
1684 |
;; Tree properties are information extracted from parse tree. They |
|
1685 |
;; are initialized at the beginning of the transcoding process by |
|
1686 |
;; `org-export--collect-tree-properties'. |
|
1687 |
;; |
|
1688 |
;; Dedicated functions focus on computing the value of specific tree |
|
1689 |
;; properties during initialization. Thus, |
|
1690 |
;; `org-export--populate-ignore-list' lists elements and objects that |
|
1691 |
;; should be skipped during export, `org-export--get-min-level' gets |
|
1692 |
;; the minimal exportable level, used as a basis to compute relative |
|
1693 |
;; level for headlines. Eventually |
|
1694 |
;; `org-export--collect-headline-numbering' builds an alist between |
|
1695 |
;; headlines and their numbering. |
|
1696 |
|
|
1697 |
(defun org-export--collect-tree-properties (data info) |
|
1698 |
"Extract tree properties from parse tree. |
|
1699 |
|
|
1700 |
DATA is the parse tree from which information is retrieved. INFO |
|
1701 |
is a list holding export options. |
|
1702 |
|
|
1703 |
Following tree properties are set or updated: |
|
1704 |
|
|
1705 |
`:headline-offset' Offset between true level of headlines and |
|
1706 |
local level. An offset of -1 means a headline |
|
1707 |
of level 2 should be considered as a level |
|
1708 |
1 headline in the context. |
|
1709 |
|
|
1710 |
`:headline-numbering' Alist of all headlines as key and the |
|
1711 |
associated numbering as value. |
|
1712 |
|
|
1713 |
`:id-alist' Alist of all ID references as key and associated file |
|
1714 |
as value. |
|
1715 |
|
|
1716 |
Return updated plist." |
|
1717 |
;; Install the parse tree in the communication channel. |
|
1718 |
(setq info (plist-put info :parse-tree data)) |
|
1719 |
;; Compute `:headline-offset' in order to be able to use |
|
1720 |
;; `org-export-get-relative-level'. |
|
1721 |
(setq info |
|
1722 |
(plist-put info |
|
1723 |
:headline-offset |
|
1724 |
(- 1 (org-export--get-min-level data info)))) |
|
1725 |
;; From now on, properties order doesn't matter: get the rest of the |
|
1726 |
;; tree properties. |
|
1727 |
(org-combine-plists |
|
1728 |
info |
|
1729 |
(list :headline-numbering (org-export--collect-headline-numbering data info) |
|
1730 |
:id-alist |
|
1731 |
(org-element-map data 'link |
|
1732 |
(lambda (l) |
|
1733 |
(and (string= (org-element-property :type l) "id") |
|
1734 |
(let* ((id (org-element-property :path l)) |
|
1735 |
(file (car (org-id-find id)))) |
|
1736 |
(and file (cons id (file-relative-name file)))))))))) |
|
1737 |
|
|
1738 |
(defun org-export--get-min-level (data options) |
|
1739 |
"Return minimum exportable headline's level in DATA. |
|
1740 |
DATA is parsed tree as returned by `org-element-parse-buffer'. |
|
1741 |
OPTIONS is a plist holding export options." |
|
1742 |
(catch 'exit |
|
1743 |
(let ((min-level 10000)) |
|
1744 |
(dolist (datum (org-element-contents data)) |
|
1745 |
(when (and (eq (org-element-type datum) 'headline) |
|
1746 |
(not (org-element-property :footnote-section-p datum)) |
|
1747 |
(not (memq datum (plist-get options :ignore-list)))) |
|
1748 |
(setq min-level (min (org-element-property :level datum) min-level)) |
|
1749 |
(when (= min-level 1) (throw 'exit 1)))) |
|
1750 |
;; If no headline was found, for the sake of consistency, set |
|
1751 |
;; minimum level to 1 nonetheless. |
|
1752 |
(if (= min-level 10000) 1 min-level)))) |
|
1753 |
|
|
1754 |
(defun org-export--collect-headline-numbering (data options) |
|
1755 |
"Return numbering of all exportable, numbered headlines in a parse tree. |
|
1756 |
|
|
1757 |
DATA is the parse tree. OPTIONS is the plist holding export |
|
1758 |
options. |
|
1759 |
|
|
1760 |
Return an alist whose key is a headline and value is its |
|
1761 |
associated numbering \(in the shape of a list of numbers) or nil |
|
1762 |
for a footnotes section." |
|
1763 |
(let ((numbering (make-vector org-export-max-depth 0))) |
|
1764 |
(org-element-map data 'headline |
|
1765 |
(lambda (headline) |
|
1766 |
(when (and (org-export-numbered-headline-p headline options) |
|
1767 |
(not (org-element-property :footnote-section-p headline))) |
|
1768 |
(let ((relative-level |
|
1769 |
(1- (org-export-get-relative-level headline options)))) |
|
1770 |
(cons |
|
1771 |
headline |
|
1772 |
(cl-loop |
|
1773 |
for n across numbering |
|
1774 |
for idx from 0 to org-export-max-depth |
|
1775 |
when (< idx relative-level) collect n |
|
1776 |
when (= idx relative-level) collect (aset numbering idx (1+ n)) |
|
1777 |
when (> idx relative-level) do (aset numbering idx 0)))))) |
|
1778 |
options))) |
|
1779 |
|
|
1780 |
(defun org-export--selected-trees (data info) |
|
1781 |
"List headlines and inlinetasks with a select tag in their tree. |
|
1782 |
DATA is parsed data as returned by `org-element-parse-buffer'. |
|
1783 |
INFO is a plist holding export options." |
|
1784 |
(let ((select (cl-mapcan (lambda (tag) (org-tags-expand tag t)) |
|
1785 |
(plist-get info :select-tags)))) |
|
1786 |
(if (cl-some (lambda (tag) (member tag select)) (plist-get info :filetags)) |
|
1787 |
;; If FILETAGS contains a select tag, every headline or |
|
1788 |
;; inlinetask is returned. |
|
1789 |
(org-element-map data '(headline inlinetask) #'identity) |
|
1790 |
(letrec ((selected-trees nil) |
|
1791 |
(walk-data |
|
1792 |
(lambda (data genealogy) |
|
1793 |
(let ((type (org-element-type data))) |
|
1794 |
(cond |
|
1795 |
((memq type '(headline inlinetask)) |
|
1796 |
(let ((tags (org-element-property :tags data))) |
|
1797 |
(if (cl-some (lambda (tag) (member tag select)) tags) |
|
1798 |
;; When a select tag is found, mark full |
|
1799 |
;; genealogy and every headline within the |
|
1800 |
;; tree as acceptable. |
|
1801 |
(setq selected-trees |
|
1802 |
(append |
|
1803 |
genealogy |
|
1804 |
(org-element-map data '(headline inlinetask) |
|
1805 |
#'identity) |
|
1806 |
selected-trees)) |
|
1807 |
;; If at a headline, continue searching in |
|
1808 |
;; tree, recursively. |
|
1809 |
(when (eq type 'headline) |
|
1810 |
(dolist (el (org-element-contents data)) |
|
1811 |
(funcall walk-data el (cons data genealogy))))))) |
|
1812 |
((or (eq type 'org-data) |
|
1813 |
(memq type org-element-greater-elements)) |
|
1814 |
(dolist (el (org-element-contents data)) |
|
1815 |
(funcall walk-data el genealogy)))))))) |
|
1816 |
(funcall walk-data data nil) |
|
1817 |
selected-trees)))) |
|
1818 |
|
|
1819 |
(defun org-export--skip-p (datum options selected excluded) |
|
1820 |
"Non-nil when element or object DATUM should be skipped during export. |
|
1821 |
OPTIONS is the plist holding export options. SELECTED, when |
|
1822 |
non-nil, is a list of headlines or inlinetasks belonging to |
|
1823 |
a tree with a select tag. EXCLUDED is a list of tags, as |
|
1824 |
strings. Any headline or inlinetask marked with one of those is |
|
1825 |
not exported." |
|
1826 |
(cl-case (org-element-type datum) |
|
1827 |
((comment comment-block) |
|
1828 |
;; Skip all comments and comment blocks. Make to keep maximum |
|
1829 |
;; number of blank lines around the comment so as to preserve |
|
1830 |
;; local structure of the document upon interpreting it back into |
|
1831 |
;; Org syntax. |
|
1832 |
(let* ((previous (org-export-get-previous-element datum options)) |
|
1833 |
(before (or (org-element-property :post-blank previous) 0)) |
|
1834 |
(after (or (org-element-property :post-blank datum) 0))) |
|
1835 |
(when previous |
|
1836 |
(org-element-put-property previous :post-blank (max before after 1)))) |
|
1837 |
t) |
|
1838 |
(clock (not (plist-get options :with-clocks))) |
|
1839 |
(drawer |
|
1840 |
(let ((with-drawers-p (plist-get options :with-drawers))) |
|
1841 |
(or (not with-drawers-p) |
|
1842 |
(and (consp with-drawers-p) |
|
1843 |
;; If `:with-drawers' value starts with `not', ignore |
|
1844 |
;; every drawer whose name belong to that list. |
|
1845 |
;; Otherwise, ignore drawers whose name isn't in that |
|
1846 |
;; list. |
|
1847 |
(let ((name (org-element-property :drawer-name datum))) |
|
1848 |
(if (eq (car with-drawers-p) 'not) |
|
1849 |
(member-ignore-case name (cdr with-drawers-p)) |
|
1850 |
(not (member-ignore-case name with-drawers-p)))))))) |
|
1851 |
(fixed-width (not (plist-get options :with-fixed-width))) |
|
1852 |
((footnote-definition footnote-reference) |
|
1853 |
(not (plist-get options :with-footnotes))) |
|
1854 |
((headline inlinetask) |
|
1855 |
(let ((with-tasks (plist-get options :with-tasks)) |
|
1856 |
(todo (org-element-property :todo-keyword datum)) |
|
1857 |
(todo-type (org-element-property :todo-type datum)) |
|
1858 |
(archived (plist-get options :with-archived-trees)) |
|
1859 |
(tags (org-export-get-tags datum options nil t))) |
|
1860 |
(or |
|
1861 |
(and (eq (org-element-type datum) 'inlinetask) |
|
1862 |
(not (plist-get options :with-inlinetasks))) |
|
1863 |
;; Ignore subtrees with an exclude tag. |
|
1864 |
(cl-some (lambda (tag) (member tag excluded)) tags) |
|
1865 |
;; When a select tag is present in the buffer, ignore any tree |
|
1866 |
;; without it. |
|
1867 |
(and selected (not (memq datum selected))) |
|
1868 |
;; Ignore commented sub-trees. |
|
1869 |
(org-element-property :commentedp datum) |
|
1870 |
;; Ignore archived subtrees if `:with-archived-trees' is nil. |
|
1871 |
(and (not archived) (org-element-property :archivedp datum)) |
|
1872 |
;; Ignore tasks, if specified by `:with-tasks' property. |
|
1873 |
(and todo |
|
1874 |
(or (not with-tasks) |
|
1875 |
(and (memq with-tasks '(todo done)) |
|
1876 |
(not (eq todo-type with-tasks))) |
|
1877 |
(and (consp with-tasks) (not (member todo with-tasks)))))))) |
|
1878 |
((latex-environment latex-fragment) (not (plist-get options :with-latex))) |
|
1879 |
(node-property |
|
1880 |
(let ((properties-set (plist-get options :with-properties))) |
|
1881 |
(cond ((null properties-set) t) |
|
1882 |
((consp properties-set) |
|
1883 |
(not (member-ignore-case (org-element-property :key datum) |
|
1884 |
properties-set)))))) |
|
1885 |
(planning (not (plist-get options :with-planning))) |
|
1886 |
(property-drawer (not (plist-get options :with-properties))) |
|
1887 |
(statistics-cookie (not (plist-get options :with-statistics-cookies))) |
|
1888 |
(table (not (plist-get options :with-tables))) |
|
1889 |
(table-cell |
|
1890 |
(and (org-export-table-has-special-column-p |
|
1891 |
(org-export-get-parent-table datum)) |
|
1892 |
(org-export-first-sibling-p datum options))) |
|
1893 |
(table-row (org-export-table-row-is-special-p datum options)) |
|
1894 |
(timestamp |
|
1895 |
;; `:with-timestamps' only applies to isolated timestamps |
|
1896 |
;; objects, i.e. timestamp objects in a paragraph containing only |
|
1897 |
;; timestamps and whitespaces. |
|
1898 |
(when (let ((parent (org-export-get-parent-element datum))) |
|
1899 |
(and (memq (org-element-type parent) '(paragraph verse-block)) |
|
1900 |
(not (org-element-map parent |
|
1901 |
(cons 'plain-text |
|
1902 |
(remq 'timestamp org-element-all-objects)) |
|
1903 |
(lambda (obj) |
|
1904 |
(or (not (stringp obj)) (org-string-nw-p obj))) |
|
1905 |
options t)))) |
|
1906 |
(cl-case (plist-get options :with-timestamps) |
|
1907 |
((nil) t) |
|
1908 |
(active |
|
1909 |
(not (memq (org-element-property :type datum) '(active active-range)))) |
|
1910 |
(inactive |
|
1911 |
(not (memq (org-element-property :type datum) |
|
1912 |
'(inactive inactive-range))))))))) |
|
1913 |
|
|
1914 |
|
|
1915 |
;;; The Transcoder |
|
1916 |
;; |
|
1917 |
;; `org-export-data' reads a parse tree (obtained with, i.e. |
|
1918 |
;; `org-element-parse-buffer') and transcodes it into a specified |
|
1919 |
;; back-end output. It takes care of filtering out elements or |
|
1920 |
;; objects according to export options and organizing the output blank |
|
1921 |
;; lines and white space are preserved. The function memoizes its |
|
1922 |
;; results, so it is cheap to call it within transcoders. |
|
1923 |
;; |
|
1924 |
;; It is possible to modify locally the back-end used by |
|
1925 |
;; `org-export-data' or even use a temporary back-end by using |
|
1926 |
;; `org-export-data-with-backend'. |
|
1927 |
;; |
|
1928 |
;; `org-export-transcoder' is an accessor returning appropriate |
|
1929 |
;; translator function for a given element or object. |
|
1930 |
|
|
1931 |
(defun org-export-transcoder (blob info) |
|
1932 |
"Return appropriate transcoder for BLOB. |
|
1933 |
INFO is a plist containing export directives." |
|
1934 |
(let ((type (org-element-type blob))) |
|
1935 |
;; Return contents only for complete parse trees. |
|
1936 |
(if (eq type 'org-data) (lambda (_datum contents _info) contents) |
|
1937 |
(let ((transcoder (cdr (assq type (plist-get info :translate-alist))))) |
|
1938 |
(and (functionp transcoder) transcoder))))) |
|
1939 |
|
|
1940 |
(defun org-export-data (data info) |
|
1941 |
"Convert DATA into current back-end format. |
|
1942 |
|
|
1943 |
DATA is a parse tree, an element or an object or a secondary |
|
1944 |
string. INFO is a plist holding export options. |
|
1945 |
|
|
1946 |
Return a string." |
|
1947 |
(or (gethash data (plist-get info :exported-data)) |
|
1948 |
;; Handle broken links according to |
|
1949 |
;; `org-export-with-broken-links'. |
|
1950 |
(cl-macrolet |
|
1951 |
((broken-link-handler |
|
1952 |
(&rest body) |
|
1953 |
`(condition-case err |
|
1954 |
(progn ,@body) |
|
1955 |
(org-link-broken |
|
1956 |
(pcase (plist-get info :with-broken-links) |
|
1957 |
(`nil (user-error "Unable to resolve link: %S" (nth 1 err))) |
|
1958 |
(`mark (org-export-data |
|
1959 |
(format "[BROKEN LINK: %s]" (nth 1 err)) info)) |
|
1960 |
(_ nil)))))) |
|
1961 |
(let* ((type (org-element-type data)) |
|
1962 |
(parent (org-export-get-parent data)) |
|
1963 |
(results |
|
1964 |
(cond |
|
1965 |
;; Ignored element/object. |
|
1966 |
((memq data (plist-get info :ignore-list)) nil) |
|
1967 |
;; Plain text. |
|
1968 |
((eq type 'plain-text) |
|
1969 |
(org-export-filter-apply-functions |
|
1970 |
(plist-get info :filter-plain-text) |
|
1971 |
(let ((transcoder (org-export-transcoder data info))) |
|
1972 |
(if transcoder (funcall transcoder data info) data)) |
|
1973 |
info)) |
|
1974 |
;; Secondary string. |
|
1975 |
((not type) |
|
1976 |
(mapconcat (lambda (obj) (org-export-data obj info)) data "")) |
|
1977 |
;; Element/Object without contents or, as a special |
|
1978 |
;; case, headline with archive tag and archived trees |
|
1979 |
;; restricted to title only. |
|
1980 |
((or (not (org-element-contents data)) |
|
1981 |
(and (eq type 'headline) |
|
1982 |
(eq (plist-get info :with-archived-trees) 'headline) |
|
1983 |
(org-element-property :archivedp data))) |
|
1984 |
(let ((transcoder (org-export-transcoder data info))) |
|
1985 |
(or (and (functionp transcoder) |
|
1986 |
(broken-link-handler |
|
1987 |
(funcall transcoder data nil info))) |
|
1988 |
;; Export snippets never return a nil value so |
|
1989 |
;; that white spaces following them are never |
|
1990 |
;; ignored. |
|
1991 |
(and (eq type 'export-snippet) "")))) |
|
1992 |
;; Element/Object with contents. |
|
1993 |
(t |
|
1994 |
(let ((transcoder (org-export-transcoder data info))) |
|
1995 |
(when transcoder |
|
1996 |
(let* ((greaterp (memq type org-element-greater-elements)) |
|
1997 |
(objectp |
|
1998 |
(and (not greaterp) |
|
1999 |
(memq type org-element-recursive-objects))) |
|
2000 |
(contents |
|
2001 |
(mapconcat |
|
2002 |
(lambda (element) (org-export-data element info)) |
|
2003 |
(org-element-contents |
|
2004 |
(if (or greaterp objectp) data |
|
2005 |
;; Elements directly containing |
|
2006 |
;; objects must have their indentation |
|
2007 |
;; normalized first. |
|
2008 |
(org-element-normalize-contents |
|
2009 |
data |
|
2010 |
;; When normalizing contents of the |
|
2011 |
;; first paragraph in an item or |
|
2012 |
;; a footnote definition, ignore |
|
2013 |
;; first line's indentation: there is |
|
2014 |
;; none and it might be misleading. |
|
2015 |
(when (eq type 'paragraph) |
|
2016 |
(and |
|
2017 |
(eq (car (org-element-contents parent)) |
|
2018 |
data) |
|
2019 |
(memq (org-element-type parent) |
|
2020 |
'(footnote-definition item))))))) |
|
2021 |
""))) |
|
2022 |
(broken-link-handler |
|
2023 |
(funcall transcoder data |
|
2024 |
(if (not greaterp) contents |
|
2025 |
(org-element-normalize-string contents)) |
|
2026 |
info))))))))) |
|
2027 |
;; Final result will be memoized before being returned. |
|
2028 |
(puthash |
|
2029 |
data |
|
2030 |
(cond |
|
2031 |
((not results) "") |
|
2032 |
((memq type '(org-data plain-text nil)) results) |
|
2033 |
;; Append the same white space between elements or objects |
|
2034 |
;; as in the original buffer, and call appropriate filters. |
|
2035 |
(t |
|
2036 |
(org-export-filter-apply-functions |
|
2037 |
(plist-get info (intern (format ":filter-%s" type))) |
|
2038 |
(let ((blank (or (org-element-property :post-blank data) 0))) |
|
2039 |
(if (eq (org-element-class data parent) 'object) |
|
2040 |
(concat results (make-string blank ?\s)) |
|
2041 |
(concat (org-element-normalize-string results) |
|
2042 |
(make-string blank ?\n)))) |
|
2043 |
info))) |
|
2044 |
(plist-get info :exported-data)))))) |
|
2045 |
|
|
2046 |
(defun org-export-data-with-backend (data backend info) |
|
2047 |
"Convert DATA into BACKEND format. |
|
2048 |
|
|
2049 |
DATA is an element, an object, a secondary string or a string. |
|
2050 |
BACKEND is a symbol. INFO is a plist used as a communication |
|
2051 |
channel. |
|
2052 |
|
|
2053 |
Unlike to `org-export-with-backend', this function will |
|
2054 |
recursively convert DATA using BACKEND translation table." |
|
2055 |
(when (symbolp backend) (setq backend (org-export-get-backend backend))) |
|
2056 |
;; Set-up a new communication channel with translations defined in |
|
2057 |
;; BACKEND as the translate table and a new hash table for |
|
2058 |
;; memoization. |
|
2059 |
(let ((new-info |
|
2060 |
(org-combine-plists |
|
2061 |
info |
|
2062 |
(list :back-end backend |
|
2063 |
:translate-alist (org-export-get-all-transcoders backend) |
|
2064 |
;; Size of the hash table is reduced since this |
|
2065 |
;; function will probably be used on small trees. |
|
2066 |
:exported-data (make-hash-table :test 'eq :size 401))))) |
|
2067 |
(prog1 (org-export-data data new-info) |
|
2068 |
;; Preserve `:internal-references', as those do not depend on |
|
2069 |
;; the back-end used; we need to make sure that any new |
|
2070 |
;; reference when the temporary back-end was active gets through |
|
2071 |
;; the default one. |
|
2072 |
(plist-put info :internal-references |
|
2073 |
(plist-get new-info :internal-references))))) |
|
2074 |
|
|
2075 |
(defun org-export-expand (blob contents &optional with-affiliated) |
|
2076 |
"Expand a parsed element or object to its original state. |
|
2077 |
|
|
2078 |
BLOB is either an element or an object. CONTENTS is its |
|
2079 |
contents, as a string or nil. |
|
2080 |
|
|
2081 |
When optional argument WITH-AFFILIATED is non-nil, add affiliated |
|
2082 |
keywords before output." |
|
2083 |
(let ((type (org-element-type blob))) |
|
2084 |
(concat (and with-affiliated |
|
2085 |
(eq (org-element-class blob) 'element) |
|
2086 |
(org-element--interpret-affiliated-keywords blob)) |
|
2087 |
(funcall (intern (format "org-element-%s-interpreter" type)) |
|
2088 |
blob contents)))) |
|
2089 |
|
|
2090 |
|
|
2091 |
|
|
2092 |
;;; The Filter System |
|
2093 |
;; |
|
2094 |
;; Filters allow end-users to tweak easily the transcoded output. |
|
2095 |
;; They are the functional counterpart of hooks, as every filter in |
|
2096 |
;; a set is applied to the return value of the previous one. |
|
2097 |
;; |
|
2098 |
;; Every set is back-end agnostic. Although, a filter is always |
|
2099 |
;; called, in addition to the string it applies to, with the back-end |
|
2100 |
;; used as argument, so it's easy for the end-user to add back-end |
|
2101 |
;; specific filters in the set. The communication channel, as |
|
2102 |
;; a plist, is required as the third argument. |
|
2103 |
;; |
|
2104 |
;; From the developer side, filters sets can be installed in the |
|
2105 |
;; process with the help of `org-export-define-backend', which |
|
2106 |
;; internally stores filters as an alist. Each association has a key |
|
2107 |
;; among the following symbols and a function or a list of functions |
|
2108 |
;; as value. |
|
2109 |
;; |
|
2110 |
;; - `:filter-options' applies to the property list containing export |
|
2111 |
;; options. Unlike to other filters, functions in this list accept |
|
2112 |
;; two arguments instead of three: the property list containing |
|
2113 |
;; export options and the back-end. Users can set its value through |
|
2114 |
;; `org-export-filter-options-functions' variable. |
|
2115 |
;; |
|
2116 |
;; - `:filter-parse-tree' applies directly to the complete parsed |
|
2117 |
;; tree. Users can set it through |
|
2118 |
;; `org-export-filter-parse-tree-functions' variable. |
|
2119 |
;; |
|
2120 |
;; - `:filter-body' applies to the body of the output, before template |
|
2121 |
;; translator chimes in. Users can set it through |
|
2122 |
;; `org-export-filter-body-functions' variable. |
|
2123 |
;; |
|
2124 |
;; - `:filter-final-output' applies to the final transcoded string. |
|
2125 |
;; Users can set it with `org-export-filter-final-output-functions' |
|
2126 |
;; variable. |
|
2127 |
;; |
|
2128 |
;; - `:filter-plain-text' applies to any string not recognized as Org |
|
2129 |
;; syntax. `org-export-filter-plain-text-functions' allows users to |
|
2130 |
;; configure it. |
|
2131 |
;; |
|
2132 |
;; - `:filter-TYPE' applies on the string returned after an element or |
|
2133 |
;; object of type TYPE has been transcoded. A user can modify |
|
2134 |
;; `org-export-filter-TYPE-functions' to install these filters. |
|
2135 |
;; |
|
2136 |
;; All filters sets are applied with |
|
2137 |
;; `org-export-filter-apply-functions' function. Filters in a set are |
|
2138 |
;; applied in a LIFO fashion. It allows developers to be sure that |
|
2139 |
;; their filters will be applied first. |
|
2140 |
;; |
|
2141 |
;; Filters properties are installed in communication channel with |
|
2142 |
;; `org-export-install-filters' function. |
|
2143 |
;; |
|
2144 |
;; Eventually, two hooks (`org-export-before-processing-hook' and |
|
2145 |
;; `org-export-before-parsing-hook') are run at the beginning of the |
|
2146 |
;; export process and just before parsing to allow for heavy structure |
|
2147 |
;; modifications. |
|
2148 |
|
|
2149 |
|
|
2150 |
;;;; Hooks |
|
2151 |
|
|
2152 |
(defvar org-export-before-processing-hook nil |
|
2153 |
"Hook run at the beginning of the export process. |
|
2154 |
|
|
2155 |
This is run before include keywords and macros are expanded and |
|
2156 |
Babel code blocks executed, on a copy of the original buffer |
|
2157 |
being exported. Visibility and narrowing are preserved. Point |
|
2158 |
is at the beginning of the buffer. |
|
2159 |
|
|
2160 |
Every function in this hook will be called with one argument: the |
|
2161 |
back-end currently used, as a symbol.") |
|
2162 |
|
|
2163 |
(defvar org-export-before-parsing-hook nil |
|
2164 |
"Hook run before parsing an export buffer. |
|
2165 |
|
|
2166 |
This is run after include keywords and macros have been expanded |
|
2167 |
and Babel code blocks executed, on a copy of the original buffer |
|
2168 |
being exported. Visibility and narrowing are preserved. Point |
|
2169 |
is at the beginning of the buffer. |
|
2170 |
|
|
2171 |
Every function in this hook will be called with one argument: the |
|
2172 |
back-end currently used, as a symbol.") |
|
2173 |
|
|
2174 |
|
|
2175 |
;;;; Special Filters |
|
2176 |
|
|
2177 |
(defvar org-export-filter-options-functions nil |
|
2178 |
"List of functions applied to the export options. |
|
2179 |
Each filter is called with two arguments: the export options, as |
|
2180 |
a plist, and the back-end, as a symbol. It must return |
|
2181 |
a property list containing export options.") |
|
2182 |
|
|
2183 |
(defvar org-export-filter-parse-tree-functions nil |
|
2184 |
"List of functions applied to the parsed tree. |
|
2185 |
Each filter is called with three arguments: the parse tree, as |
|
2186 |
returned by `org-element-parse-buffer', the back-end, as |
|
2187 |
a symbol, and the communication channel, as a plist. It must |
|
2188 |
return the modified parse tree to transcode.") |
|
2189 |
|
|
2190 |
(defvar org-export-filter-plain-text-functions nil |
|
2191 |
"List of functions applied to plain text. |
|
2192 |
Each filter is called with three arguments: a string which |
|
2193 |
contains no Org syntax, the back-end, as a symbol, and the |
|
2194 |
communication channel, as a plist. It must return a string or |
|
2195 |
nil.") |
|
2196 |
|
|
2197 |
(defvar org-export-filter-body-functions nil |
|
2198 |
"List of functions applied to transcoded body. |
|
2199 |
Each filter is called with three arguments: a string which |
|
2200 |
contains no Org syntax, the back-end, as a symbol, and the |
|
2201 |
communication channel, as a plist. It must return a string or |
|
2202 |
nil.") |
|
2203 |
|
|
2204 |
(defvar org-export-filter-final-output-functions nil |
|
2205 |
"List of functions applied to the transcoded string. |
|
2206 |
Each filter is called with three arguments: the full transcoded |
|
2207 |
string, the back-end, as a symbol, and the communication channel, |
|
2208 |
as a plist. It must return a string that will be used as the |
|
2209 |
final export output.") |
|
2210 |
|
|
2211 |
|
|
2212 |
;;;; Elements Filters |
|
2213 |
|
|
2214 |
(defvar org-export-filter-babel-call-functions nil |
|
2215 |
"List of functions applied to a transcoded babel-call. |
|
2216 |
Each filter is called with three arguments: the transcoded data, |
|
2217 |
as a string, the back-end, as a symbol, and the communication |
|
2218 |
channel, as a plist. It must return a string or nil.") |
|
2219 |
|
|
2220 |
(defvar org-export-filter-center-block-functions nil |
|
2221 |
"List of functions applied to a transcoded center block. |
|
2222 |
Each filter is called with three arguments: the transcoded data, |
|
2223 |
as a string, the back-end, as a symbol, and the communication |
|
2224 |
channel, as a plist. It must return a string or nil.") |
|
2225 |
|
|
2226 |
(defvar org-export-filter-clock-functions nil |
|
2227 |
"List of functions applied to a transcoded clock. |
|
2228 |
Each filter is called with three arguments: the transcoded data, |
|
2229 |
as a string, the back-end, as a symbol, and the communication |
|
2230 |
channel, as a plist. It must return a string or nil.") |
|
2231 |
|
|
2232 |
(defvar org-export-filter-diary-sexp-functions nil |
|
2233 |
"List of functions applied to a transcoded diary-sexp. |
|
2234 |
Each filter is called with three arguments: the transcoded data, |
|
2235 |
as a string, the back-end, as a symbol, and the communication |
|
2236 |
channel, as a plist. It must return a string or nil.") |
|
2237 |
|
|
2238 |
(defvar org-export-filter-drawer-functions nil |
|
2239 |
"List of functions applied to a transcoded drawer. |
|
2240 |
Each filter is called with three arguments: the transcoded data, |
|
2241 |
as a string, the back-end, as a symbol, and the communication |
|
2242 |
channel, as a plist. It must return a string or nil.") |
|
2243 |
|
|
2244 |
(defvar org-export-filter-dynamic-block-functions nil |
|
2245 |
"List of functions applied to a transcoded dynamic-block. |
|
2246 |
Each filter is called with three arguments: the transcoded data, |
|
2247 |
as a string, the back-end, as a symbol, and the communication |
|
2248 |
channel, as a plist. It must return a string or nil.") |
|
2249 |
|
|
2250 |
(defvar org-export-filter-example-block-functions nil |
|
2251 |
"List of functions applied to a transcoded example-block. |
|
2252 |
Each filter is called with three arguments: the transcoded data, |
|
2253 |
as a string, the back-end, as a symbol, and the communication |
|
2254 |
channel, as a plist. It must return a string or nil.") |
|
2255 |
|
|
2256 |
(defvar org-export-filter-export-block-functions nil |
|
2257 |
"List of functions applied to a transcoded export-block. |
|
2258 |
Each filter is called with three arguments: the transcoded data, |
|
2259 |
as a string, the back-end, as a symbol, and the communication |
|
2260 |
channel, as a plist. It must return a string or nil.") |
|
2261 |
|
|
2262 |
(defvar org-export-filter-fixed-width-functions nil |
|
2263 |
"List of functions applied to a transcoded fixed-width. |
|
2264 |
Each filter is called with three arguments: the transcoded data, |
|
2265 |
as a string, the back-end, as a symbol, and the communication |
|
2266 |
channel, as a plist. It must return a string or nil.") |
|
2267 |
|
|
2268 |
(defvar org-export-filter-footnote-definition-functions nil |
|
2269 |
"List of functions applied to a transcoded footnote-definition. |
|
2270 |
Each filter is called with three arguments: the transcoded data, |
|
2271 |
as a string, the back-end, as a symbol, and the communication |
|
2272 |
channel, as a plist. It must return a string or nil.") |
|
2273 |
|
|
2274 |
(defvar org-export-filter-headline-functions nil |
|
2275 |
"List of functions applied to a transcoded headline. |
|
2276 |
Each filter is called with three arguments: the transcoded data, |
|
2277 |
as a string, the back-end, as a symbol, and the communication |
|
2278 |
channel, as a plist. It must return a string or nil.") |
|
2279 |
|
|
2280 |
(defvar org-export-filter-horizontal-rule-functions nil |
|
2281 |
"List of functions applied to a transcoded horizontal-rule. |
|
2282 |
Each filter is called with three arguments: the transcoded data, |
|
2283 |
as a string, the back-end, as a symbol, and the communication |
|
2284 |
channel, as a plist. It must return a string or nil.") |
|
2285 |
|
|
2286 |
(defvar org-export-filter-inlinetask-functions nil |
|
2287 |
"List of functions applied to a transcoded inlinetask. |
|
2288 |
Each filter is called with three arguments: the transcoded data, |
|
2289 |
as a string, the back-end, as a symbol, and the communication |
|
2290 |
channel, as a plist. It must return a string or nil.") |
|
2291 |
|
|
2292 |
(defvar org-export-filter-item-functions nil |
|
2293 |
"List of functions applied to a transcoded item. |
|
2294 |
Each filter is called with three arguments: the transcoded data, |
|
2295 |
as a string, the back-end, as a symbol, and the communication |
|
2296 |
channel, as a plist. It must return a string or nil.") |
|
2297 |
|
|
2298 |
(defvar org-export-filter-keyword-functions nil |
|
2299 |
"List of functions applied to a transcoded keyword. |
|
2300 |
Each filter is called with three arguments: the transcoded data, |
|
2301 |
as a string, the back-end, as a symbol, and the communication |
|
2302 |
channel, as a plist. It must return a string or nil.") |
|
2303 |
|
|
2304 |
(defvar org-export-filter-latex-environment-functions nil |
|
2305 |
"List of functions applied to a transcoded latex-environment. |
|
2306 |
Each filter is called with three arguments: the transcoded data, |
|
2307 |
as a string, the back-end, as a symbol, and the communication |
|
2308 |
channel, as a plist. It must return a string or nil.") |
|
2309 |
|
|
2310 |
(defvar org-export-filter-node-property-functions nil |
|
2311 |
"List of functions applied to a transcoded node-property. |
|
2312 |
Each filter is called with three arguments: the transcoded data, |
|
2313 |
as a string, the back-end, as a symbol, and the communication |
|
2314 |
channel, as a plist. It must return a string or nil.") |
|
2315 |
|
|
2316 |
(defvar org-export-filter-paragraph-functions nil |
|
2317 |
"List of functions applied to a transcoded paragraph. |
|
2318 |
Each filter is called with three arguments: the transcoded data, |
|
2319 |
as a string, the back-end, as a symbol, and the communication |
|
2320 |
channel, as a plist. It must return a string or nil.") |
|
2321 |
|
|
2322 |
(defvar org-export-filter-plain-list-functions nil |
|
2323 |
"List of functions applied to a transcoded plain-list. |
|
2324 |
Each filter is called with three arguments: the transcoded data, |
|
2325 |
as a string, the back-end, as a symbol, and the communication |
|
2326 |
channel, as a plist. It must return a string or nil.") |
|
2327 |
|
|
2328 |
(defvar org-export-filter-planning-functions nil |
|
2329 |
"List of functions applied to a transcoded planning. |
|
2330 |
Each filter is called with three arguments: the transcoded data, |
|
2331 |
as a string, the back-end, as a symbol, and the communication |
|
2332 |
channel, as a plist. It must return a string or nil.") |
|
2333 |
|
|
2334 |
(defvar org-export-filter-property-drawer-functions nil |
|
2335 |
"List of functions applied to a transcoded property-drawer. |
|
2336 |
Each filter is called with three arguments: the transcoded data, |
|
2337 |
as a string, the back-end, as a symbol, and the communication |
|
2338 |
channel, as a plist. It must return a string or nil.") |
|
2339 |
|
|
2340 |
(defvar org-export-filter-quote-block-functions nil |
|
2341 |
"List of functions applied to a transcoded quote block. |
|
2342 |
Each filter is called with three arguments: the transcoded quote |
|
2343 |
data, as a string, the back-end, as a symbol, and the |
|
2344 |
communication channel, as a plist. It must return a string or |
|
2345 |
nil.") |
|
2346 |
|
|
2347 |
(defvar org-export-filter-section-functions nil |
|
2348 |
"List of functions applied to a transcoded section. |
|
2349 |
Each filter is called with three arguments: the transcoded data, |
|
2350 |
as a string, the back-end, as a symbol, and the communication |
|
2351 |
channel, as a plist. It must return a string or nil.") |
|
2352 |
|
|
2353 |
(defvar org-export-filter-special-block-functions nil |
|
2354 |
"List of functions applied to a transcoded special block. |
|
2355 |
Each filter is called with three arguments: the transcoded data, |
|
2356 |
as a string, the back-end, as a symbol, and the communication |
|
2357 |
channel, as a plist. It must return a string or nil.") |
|
2358 |
|
|
2359 |
(defvar org-export-filter-src-block-functions nil |
|
2360 |
"List of functions applied to a transcoded src-block. |
|
2361 |
Each filter is called with three arguments: the transcoded data, |
|
2362 |
as a string, the back-end, as a symbol, and the communication |
|
2363 |
channel, as a plist. It must return a string or nil.") |
|
2364 |
|
|
2365 |
(defvar org-export-filter-table-functions nil |
|
2366 |
"List of functions applied to a transcoded table. |
|
2367 |
Each filter is called with three arguments: the transcoded data, |
|
2368 |
as a string, the back-end, as a symbol, and the communication |
|
2369 |
channel, as a plist. It must return a string or nil.") |
|
2370 |
|
|
2371 |
(defvar org-export-filter-table-cell-functions nil |
|
2372 |
"List of functions applied to a transcoded table-cell. |
|
2373 |
Each filter is called with three arguments: the transcoded data, |
|
2374 |
as a string, the back-end, as a symbol, and the communication |
|
2375 |
channel, as a plist. It must return a string or nil.") |
|
2376 |
|
|
2377 |
(defvar org-export-filter-table-row-functions nil |
|
2378 |
"List of functions applied to a transcoded table-row. |
|
2379 |
Each filter is called with three arguments: the transcoded data, |
|
2380 |
as a string, the back-end, as a symbol, and the communication |
|
2381 |
channel, as a plist. It must return a string or nil.") |
|
2382 |
|
|
2383 |
(defvar org-export-filter-verse-block-functions nil |
|
2384 |
"List of functions applied to a transcoded verse block. |
|
2385 |
Each filter is called with three arguments: the transcoded data, |
|
2386 |
as a string, the back-end, as a symbol, and the communication |
|
2387 |
channel, as a plist. It must return a string or nil.") |
|
2388 |
|
|
2389 |
|
|
2390 |
;;;; Objects Filters |
|
2391 |
|
|
2392 |
(defvar org-export-filter-bold-functions nil |
|
2393 |
"List of functions applied to transcoded bold text. |
|
2394 |
Each filter is called with three arguments: the transcoded data, |
|
2395 |
as a string, the back-end, as a symbol, and the communication |
|
2396 |
channel, as a plist. It must return a string or nil.") |
|
2397 |
|
|
2398 |
(defvar org-export-filter-code-functions nil |
|
2399 |
"List of functions applied to transcoded code text. |
|
2400 |
Each filter is called with three arguments: the transcoded data, |
|
2401 |
as a string, the back-end, as a symbol, and the communication |
|
2402 |
channel, as a plist. It must return a string or nil.") |
|
2403 |
|
|
2404 |
(defvar org-export-filter-entity-functions nil |
|
2405 |
"List of functions applied to a transcoded entity. |
|
2406 |
Each filter is called with three arguments: the transcoded data, |
|
2407 |
as a string, the back-end, as a symbol, and the communication |
|
2408 |
channel, as a plist. It must return a string or nil.") |
|
2409 |
|
|
2410 |
(defvar org-export-filter-export-snippet-functions nil |
|
2411 |
"List of functions applied to a transcoded export-snippet. |
|
2412 |
Each filter is called with three arguments: the transcoded data, |
|
2413 |
as a string, the back-end, as a symbol, and the communication |
|
2414 |
channel, as a plist. It must return a string or nil.") |
|
2415 |
|
|
2416 |
(defvar org-export-filter-footnote-reference-functions nil |
|
2417 |
"List of functions applied to a transcoded footnote-reference. |
|
2418 |
Each filter is called with three arguments: the transcoded data, |
|
2419 |
as a string, the back-end, as a symbol, and the communication |
|
2420 |
channel, as a plist. It must return a string or nil.") |
|
2421 |
|
|
2422 |
(defvar org-export-filter-inline-babel-call-functions nil |
|
2423 |
"List of functions applied to a transcoded inline-babel-call. |
|
2424 |
Each filter is called with three arguments: the transcoded data, |
|
2425 |
as a string, the back-end, as a symbol, and the communication |
|
2426 |
channel, as a plist. It must return a string or nil.") |
|
2427 |
|
|
2428 |
(defvar org-export-filter-inline-src-block-functions nil |
|
2429 |
"List of functions applied to a transcoded inline-src-block. |
|
2430 |
Each filter is called with three arguments: the transcoded data, |
|
2431 |
as a string, the back-end, as a symbol, and the communication |
|
2432 |
channel, as a plist. It must return a string or nil.") |
|
2433 |
|
|
2434 |
(defvar org-export-filter-italic-functions nil |
|
2435 |
"List of functions applied to transcoded italic text. |
|
2436 |
Each filter is called with three arguments: the transcoded data, |
|
2437 |
as a string, the back-end, as a symbol, and the communication |
|
2438 |
channel, as a plist. It must return a string or nil.") |
|
2439 |
|
|
2440 |
(defvar org-export-filter-latex-fragment-functions nil |
|
2441 |
"List of functions applied to a transcoded latex-fragment. |
|
2442 |
Each filter is called with three arguments: the transcoded data, |
|
2443 |
as a string, the back-end, as a symbol, and the communication |
|
2444 |
channel, as a plist. It must return a string or nil.") |
|
2445 |
|
|
2446 |
(defvar org-export-filter-line-break-functions nil |
|
2447 |
"List of functions applied to a transcoded line-break. |
|
2448 |
Each filter is called with three arguments: the transcoded data, |
|
2449 |
as a string, the back-end, as a symbol, and the communication |
|
2450 |
channel, as a plist. It must return a string or nil.") |
|
2451 |
|
|
2452 |
(defvar org-export-filter-link-functions nil |
|
2453 |
"List of functions applied to a transcoded link. |
|
2454 |
Each filter is called with three arguments: the transcoded data, |
|
2455 |
as a string, the back-end, as a symbol, and the communication |
|
2456 |
channel, as a plist. It must return a string or nil.") |
|
2457 |
|
|
2458 |
(defvar org-export-filter-radio-target-functions nil |
|
2459 |
"List of functions applied to a transcoded radio-target. |
|
2460 |
Each filter is called with three arguments: the transcoded data, |
|
2461 |
as a string, the back-end, as a symbol, and the communication |
|
2462 |
channel, as a plist. It must return a string or nil.") |
|
2463 |
|
|
2464 |
(defvar org-export-filter-statistics-cookie-functions nil |
|
2465 |
"List of functions applied to a transcoded statistics-cookie. |
|
2466 |
Each filter is called with three arguments: the transcoded data, |
|
2467 |
as a string, the back-end, as a symbol, and the communication |
|
2468 |
channel, as a plist. It must return a string or nil.") |
|
2469 |
|
|
2470 |
(defvar org-export-filter-strike-through-functions nil |
|
2471 |
"List of functions applied to transcoded strike-through text. |
|
2472 |
Each filter is called with three arguments: the transcoded data, |
|
2473 |
as a string, the back-end, as a symbol, and the communication |
|
2474 |
channel, as a plist. It must return a string or nil.") |
|
2475 |
|
|
2476 |
(defvar org-export-filter-subscript-functions nil |
|
2477 |
"List of functions applied to a transcoded subscript. |
|
2478 |
Each filter is called with three arguments: the transcoded data, |
|
2479 |
as a string, the back-end, as a symbol, and the communication |
|
2480 |
channel, as a plist. It must return a string or nil.") |
|
2481 |
|
|
2482 |
(defvar org-export-filter-superscript-functions nil |
|
2483 |
"List of functions applied to a transcoded superscript. |
|
2484 |
Each filter is called with three arguments: the transcoded data, |
|
2485 |
as a string, the back-end, as a symbol, and the communication |
|
2486 |
channel, as a plist. It must return a string or nil.") |
|
2487 |
|
|
2488 |
(defvar org-export-filter-target-functions nil |
|
2489 |
"List of functions applied to a transcoded target. |
|
2490 |
Each filter is called with three arguments: the transcoded data, |
|
2491 |
as a string, the back-end, as a symbol, and the communication |
|
2492 |
channel, as a plist. It must return a string or nil.") |
|
2493 |
|
|
2494 |
(defvar org-export-filter-timestamp-functions nil |
|
2495 |
"List of functions applied to a transcoded timestamp. |
|
2496 |
Each filter is called with three arguments: the transcoded data, |
|
2497 |
as a string, the back-end, as a symbol, and the communication |
|
2498 |
channel, as a plist. It must return a string or nil.") |
|
2499 |
|
|
2500 |
(defvar org-export-filter-underline-functions nil |
|
2501 |
"List of functions applied to transcoded underline text. |
|
2502 |
Each filter is called with three arguments: the transcoded data, |
|
2503 |
as a string, the back-end, as a symbol, and the communication |
|
2504 |
channel, as a plist. It must return a string or nil.") |
|
2505 |
|
|
2506 |
(defvar org-export-filter-verbatim-functions nil |
|
2507 |
"List of functions applied to transcoded verbatim text. |
|
2508 |
Each filter is called with three arguments: the transcoded data, |
|
2509 |
as a string, the back-end, as a symbol, and the communication |
|
2510 |
channel, as a plist. It must return a string or nil.") |
|
2511 |
|
|
2512 |
|
|
2513 |
;;;; Filters Tools |
|
2514 |
;; |
|
2515 |
;; Internal function `org-export-install-filters' installs filters |
|
2516 |
;; hard-coded in back-ends (developer filters) and filters from global |
|
2517 |
;; variables (user filters) in the communication channel. |
|
2518 |
;; |
|
2519 |
;; Internal function `org-export-filter-apply-functions' takes care |
|
2520 |
;; about applying each filter in order to a given data. It ignores |
|
2521 |
;; filters returning a nil value but stops whenever a filter returns |
|
2522 |
;; an empty string. |
|
2523 |
|
|
2524 |
(defun org-export-filter-apply-functions (filters value info) |
|
2525 |
"Call every function in FILTERS. |
|
2526 |
|
|
2527 |
Functions are called with three arguments: a value, the export |
|
2528 |
back-end name and the communication channel. First function in |
|
2529 |
FILTERS is called with VALUE as its first argument. Second |
|
2530 |
function in FILTERS is called with the previous result as its |
|
2531 |
value, etc. |
|
2532 |
|
|
2533 |
Functions returning nil are skipped. Any function returning the |
|
2534 |
empty string ends the process, which returns the empty string. |
|
2535 |
|
|
2536 |
Call is done in a LIFO fashion, to be sure that developer |
|
2537 |
specified filters, if any, are called first." |
|
2538 |
(catch :exit |
|
2539 |
(let* ((backend (plist-get info :back-end)) |
|
2540 |
(backend-name (and backend (org-export-backend-name backend)))) |
|
2541 |
(dolist (filter filters value) |
|
2542 |
(let ((result (funcall filter value backend-name info))) |
|
2543 |
(cond ((not result)) |
|
2544 |
((equal result "") (throw :exit "")) |
|
2545 |
(t (setq value result)))))))) |
|
2546 |
|
|
2547 |
(defun org-export-install-filters (info) |
|
2548 |
"Install filters properties in communication channel. |
|
2549 |
INFO is a plist containing the current communication channel. |
|
2550 |
Return the updated communication channel." |
|
2551 |
(let (plist) |
|
2552 |
;; Install user-defined filters with `org-export-filters-alist' |
|
2553 |
;; and filters already in INFO (through ext-plist mechanism). |
|
2554 |
(dolist (p org-export-filters-alist) |
|
2555 |
(let* ((prop (car p)) |
|
2556 |
(info-value (plist-get info prop)) |
|
2557 |
(default-value (symbol-value (cdr p)))) |
|
2558 |
(setq plist |
|
2559 |
(plist-put plist prop |
|
2560 |
;; Filters in INFO will be called |
|
2561 |
;; before those user provided. |
|
2562 |
(append (if (listp info-value) info-value |
|
2563 |
(list info-value)) |
|
2564 |
default-value))))) |
|
2565 |
;; Prepend back-end specific filters to that list. |
|
2566 |
(dolist (p (org-export-get-all-filters (plist-get info :back-end))) |
|
2567 |
;; Single values get consed, lists are appended. |
|
2568 |
(let ((key (car p)) (value (cdr p))) |
|
2569 |
(when value |
|
2570 |
(setq plist |
|
2571 |
(plist-put |
|
2572 |
plist key |
|
2573 |
(if (atom value) (cons value (plist-get plist key)) |
|
2574 |
(append value (plist-get plist key)))))))) |
|
2575 |
;; Return new communication channel. |
|
2576 |
(org-combine-plists info plist))) |
|
2577 |
|
|
2578 |
|
|
2579 |
|
|
2580 |
;;; Core functions |
|
2581 |
;; |
|
2582 |
;; This is the room for the main function, `org-export-as', along with |
|
2583 |
;; its derivative, `org-export-string-as'. |
|
2584 |
;; `org-export--copy-to-kill-ring-p' determines if output of these |
|
2585 |
;; function should be added to kill ring. |
|
2586 |
;; |
|
2587 |
;; Note that `org-export-as' doesn't really parse the current buffer, |
|
2588 |
;; but a copy of it (with the same buffer-local variables and |
|
2589 |
;; visibility), where macros and include keywords are expanded and |
|
2590 |
;; Babel blocks are executed, if appropriate. |
|
2591 |
;; `org-export-with-buffer-copy' macro prepares that copy. |
|
2592 |
;; |
|
2593 |
;; File inclusion is taken care of by |
|
2594 |
;; `org-export-expand-include-keyword' and |
|
2595 |
;; `org-export--prepare-file-contents'. Structure wise, including |
|
2596 |
;; a whole Org file in a buffer often makes little sense. For |
|
2597 |
;; example, if the file contains a headline and the include keyword |
|
2598 |
;; was within an item, the item should contain the headline. That's |
|
2599 |
;; why file inclusion should be done before any structure can be |
|
2600 |
;; associated to the file, that is before parsing. |
|
2601 |
;; |
|
2602 |
;; `org-export-insert-default-template' is a command to insert |
|
2603 |
;; a default template (or a back-end specific template) at point or in |
|
2604 |
;; current subtree. |
|
2605 |
|
|
2606 |
(defun org-export-copy-buffer () |
|
2607 |
"Return a copy of the current buffer. |
|
2608 |
The copy preserves Org buffer-local variables, visibility and |
|
2609 |
narrowing." |
|
2610 |
(let ((copy-buffer-fun (org-export--generate-copy-script (current-buffer))) |
|
2611 |
(new-buf (generate-new-buffer (buffer-name)))) |
|
2612 |
(with-current-buffer new-buf |
|
2613 |
(funcall copy-buffer-fun) |
|
2614 |
(set-buffer-modified-p nil)) |
|
2615 |
new-buf)) |
|
2616 |
|
|
2617 |
(defmacro org-export-with-buffer-copy (&rest body) |
|
2618 |
"Apply BODY in a copy of the current buffer. |
|
2619 |
The copy preserves local variables, visibility and contents of |
|
2620 |
the original buffer. Point is at the beginning of the buffer |
|
2621 |
when BODY is applied." |
|
2622 |
(declare (debug t)) |
|
2623 |
(org-with-gensyms (buf-copy) |
|
2624 |
`(let ((,buf-copy (org-export-copy-buffer))) |
|
2625 |
(unwind-protect |
|
2626 |
(with-current-buffer ,buf-copy |
|
2627 |
(goto-char (point-min)) |
|
2628 |
(progn ,@body)) |
|
2629 |
(and (buffer-live-p ,buf-copy) |
|
2630 |
;; Kill copy without confirmation. |
|
2631 |
(progn (with-current-buffer ,buf-copy |
|
2632 |
(restore-buffer-modified-p nil)) |
|
2633 |
(kill-buffer ,buf-copy))))))) |
|
2634 |
|
|
2635 |
(defun org-export--generate-copy-script (buffer) |
|
2636 |
"Generate a function duplicating BUFFER. |
|
2637 |
|
|
2638 |
The copy will preserve local variables, visibility, contents and |
|
2639 |
narrowing of the original buffer. If a region was active in |
|
2640 |
BUFFER, contents will be narrowed to that region instead. |
|
2641 |
|
|
2642 |
The resulting function can be evaluated at a later time, from |
|
2643 |
another buffer, effectively cloning the original buffer there. |
|
2644 |
|
|
2645 |
The function assumes BUFFER's major mode is `org-mode'." |
|
2646 |
(with-current-buffer buffer |
|
2647 |
`(lambda () |
|
2648 |
(let ((inhibit-modification-hooks t)) |
|
2649 |
;; Set major mode. Ignore `org-mode-hook' as it has been run |
|
2650 |
;; already in BUFFER. |
|
2651 |
(let ((org-mode-hook nil) (org-inhibit-startup t)) (org-mode)) |
|
2652 |
;; Copy specific buffer local variables and variables set |
|
2653 |
;; through BIND keywords. |
|
2654 |
,@(let ((bound-variables (org-export--list-bound-variables)) |
|
2655 |
vars) |
|
2656 |
(dolist (entry (buffer-local-variables (buffer-base-buffer)) vars) |
|
2657 |
(when (consp entry) |
|
2658 |
(let ((var (car entry)) |
|
2659 |
(val (cdr entry))) |
|
2660 |
(and (not (memq var org-export-ignored-local-variables)) |
|
2661 |
(or (memq var |
|
2662 |
'(default-directory |
|
2663 |
buffer-file-name |
|
2664 |
buffer-file-coding-system)) |
|
2665 |
(assq var bound-variables) |
|
2666 |
(string-match "^\\(org-\\|orgtbl-\\)" |
|
2667 |
(symbol-name var))) |
|
2668 |
;; Skip unreadable values, as they cannot be |
|
2669 |
;; sent to external process. |
|
2670 |
(or (not val) (ignore-errors (read (format "%S" val)))) |
|
2671 |
(push `(set (make-local-variable (quote ,var)) |
|
2672 |
(quote ,val)) |
|
2673 |
vars)))))) |
|
2674 |
;; Whole buffer contents. |
|
2675 |
(insert |
|
2676 |
,(org-with-wide-buffer |
|
2677 |
(buffer-substring-no-properties |
|
2678 |
(point-min) (point-max)))) |
|
2679 |
;; Narrowing. |
|
2680 |
,(if (org-region-active-p) |
|
2681 |
`(narrow-to-region ,(region-beginning) ,(region-end)) |
|
2682 |
`(narrow-to-region ,(point-min) ,(point-max))) |
|
2683 |
;; Current position of point. |
|
2684 |
(goto-char ,(point)) |
|
2685 |
;; Overlays with invisible property. |
|
2686 |
,@(let (ov-set) |
|
2687 |
(dolist (ov (overlays-in (point-min) (point-max)) ov-set) |
|
2688 |
(let ((invis-prop (overlay-get ov 'invisible))) |
|
2689 |
(when invis-prop |
|
2690 |
(push `(overlay-put |
|
2691 |
(make-overlay ,(overlay-start ov) |
|
2692 |
,(overlay-end ov)) |
|
2693 |
'invisible (quote ,invis-prop)) |
|
2694 |
ov-set))))))))) |
|
2695 |
|
|
2696 |
(defun org-export--delete-comment-trees () |
|
2697 |
"Delete commented trees and commented inlinetasks in the buffer. |
|
2698 |
Narrowing, if any, is ignored." |
|
2699 |
(org-with-wide-buffer |
|
2700 |
(goto-char (point-min)) |
|
2701 |
(let* ((case-fold-search t) |
|
2702 |
(regexp (concat org-outline-regexp-bol ".*" org-comment-string))) |
|
2703 |
(while (re-search-forward regexp nil t) |
|
2704 |
(let ((element (org-element-at-point))) |
|
2705 |
(when (org-element-property :commentedp element) |
|
2706 |
(delete-region (org-element-property :begin element) |
|
2707 |
(org-element-property :end element)))))))) |
|
2708 |
|
|
2709 |
(defun org-export--prune-tree (data info) |
|
2710 |
"Prune non exportable elements from DATA. |
|
2711 |
DATA is the parse tree to traverse. INFO is the plist holding |
|
2712 |
export info. Also set `:ignore-list' in INFO to a list of |
|
2713 |
objects which should be ignored during export, but not removed |
|
2714 |
from tree." |
|
2715 |
(letrec ((ignore nil) |
|
2716 |
;; First find trees containing a select tag, if any. |
|
2717 |
(selected (org-export--selected-trees data info)) |
|
2718 |
;; List tags that prevent export of headlines. |
|
2719 |
(excluded (cl-mapcan (lambda (tag) (org-tags-expand tag t)) |
|
2720 |
(plist-get info :exclude-tags))) |
|
2721 |
(walk-data |
|
2722 |
(lambda (data) |
|
2723 |
;; Prune non-exportable elements and objects from tree. |
|
2724 |
;; As a special case, special rows and cells from tables |
|
2725 |
;; are stored in IGNORE, as they still need to be |
|
2726 |
;; accessed during export. |
|
2727 |
(when data |
|
2728 |
(let ((type (org-element-type data))) |
|
2729 |
(if (org-export--skip-p data info selected excluded) |
|
2730 |
(if (memq type '(table-cell table-row)) (push data ignore) |
|
2731 |
(org-element-extract-element data)) |
|
2732 |
(if (and (eq type 'headline) |
|
2733 |
(eq (plist-get info :with-archived-trees) |
|
2734 |
'headline) |
|
2735 |
(org-element-property :archivedp data)) |
|
2736 |
;; If headline is archived but tree below has |
|
2737 |
;; to be skipped, remove contents. |
|
2738 |
(org-element-set-contents data) |
|
2739 |
;; Move into recursive objects/elements. |
|
2740 |
(mapc walk-data (org-element-contents data))) |
|
2741 |
;; Move into secondary string, if any. |
|
2742 |
(dolist (p (cdr (assq type |
|
2743 |
org-element-secondary-value-alist))) |
|
2744 |
(mapc walk-data (org-element-property p data)))))))) |
|
2745 |
(definitions |
|
2746 |
;; Collect definitions before possibly pruning them so as |
|
2747 |
;; to avoid parsing them again if they are required. |
|
2748 |
(org-element-map data '(footnote-definition footnote-reference) |
|
2749 |
(lambda (f) |
|
2750 |
(cond |
|
2751 |
((eq 'footnote-definition (org-element-type f)) f) |
|
2752 |
((and (eq 'inline (org-element-property :type f)) |
|
2753 |
(org-element-property :label f)) |
|
2754 |
f) |
|
2755 |
(t nil)))))) |
|
2756 |
;; If a select tag is active, also ignore the section before the |
|
2757 |
;; first headline, if any. |
|
2758 |
(when selected |
|
2759 |
(let ((first-element (car (org-element-contents data)))) |
|
2760 |
(when (eq (org-element-type first-element) 'section) |
|
2761 |
(org-element-extract-element first-element)))) |
|
2762 |
;; Prune tree and communication channel. |
|
2763 |
(funcall walk-data data) |
|
2764 |
(dolist (entry (append |
|
2765 |
;; Priority is given to back-end specific options. |
|
2766 |
(org-export-get-all-options (plist-get info :back-end)) |
|
2767 |
org-export-options-alist)) |
|
2768 |
(when (eq (nth 4 entry) 'parse) |
|
2769 |
(funcall walk-data (plist-get info (car entry))))) |
|
2770 |
(let ((missing (org-export--missing-definitions data definitions))) |
|
2771 |
(funcall walk-data missing) |
|
2772 |
(org-export--install-footnote-definitions missing data)) |
|
2773 |
;; Eventually set `:ignore-list'. |
|
2774 |
(plist-put info :ignore-list ignore))) |
|
2775 |
|
|
2776 |
(defun org-export--missing-definitions (tree definitions) |
|
2777 |
"List footnote definitions missing from TREE. |
|
2778 |
Missing definitions are searched within DEFINITIONS, which is |
|
2779 |
a list of footnote definitions or in the widened buffer." |
|
2780 |
(let* ((list-labels |
|
2781 |
(lambda (data) |
|
2782 |
;; List all footnote labels encountered in DATA. Inline |
|
2783 |
;; footnote references are ignored. |
|
2784 |
(org-element-map data 'footnote-reference |
|
2785 |
(lambda (reference) |
|
2786 |
(and (eq (org-element-property :type reference) 'standard) |
|
2787 |
(org-element-property :label reference)))))) |
|
2788 |
defined undefined missing-definitions) |
|
2789 |
;; Partition DIRECT-REFERENCES between DEFINED and UNDEFINED |
|
2790 |
;; references. |
|
2791 |
(let ((known-definitions |
|
2792 |
(org-element-map tree '(footnote-reference footnote-definition) |
|
2793 |
(lambda (f) |
|
2794 |
(and (or (eq (org-element-type f) 'footnote-definition) |
|
2795 |
(eq (org-element-property :type f) 'inline)) |
|
2796 |
(org-element-property :label f))))) |
|
2797 |
seen) |
|
2798 |
(dolist (l (funcall list-labels tree)) |
|
2799 |
(cond ((member l seen)) |
|
2800 |
((member l known-definitions) (push l defined)) |
|
2801 |
(t (push l undefined))))) |
|
2802 |
;; Complete MISSING-DEFINITIONS by finding the definition of every |
|
2803 |
;; undefined label, first by looking into DEFINITIONS, then by |
|
2804 |
;; searching the widened buffer. This is a recursive process |
|
2805 |
;; since definitions found can themselves contain an undefined |
|
2806 |
;; reference. |
|
2807 |
(while undefined |
|
2808 |
(let* ((label (pop undefined)) |
|
2809 |
(definition |
|
2810 |
(cond |
|
2811 |
((cl-some |
|
2812 |
(lambda (d) (and (equal (org-element-property :label d) label) |
|
2813 |
d)) |
|
2814 |
definitions)) |
|
2815 |
((pcase (org-footnote-get-definition label) |
|
2816 |
(`(,_ ,beg . ,_) |
|
2817 |
(org-with-wide-buffer |
|
2818 |
(goto-char beg) |
|
2819 |
(let ((datum (org-element-context))) |
|
2820 |
(if (eq (org-element-type datum) 'footnote-reference) |
|
2821 |
datum |
|
2822 |
;; Parse definition with contents. |
|
2823 |
(save-restriction |
|
2824 |
(narrow-to-region |
|
2825 |
(org-element-property :begin datum) |
|
2826 |
(org-element-property :end datum)) |
|
2827 |
(org-element-map (org-element-parse-buffer) |
|
2828 |
'footnote-definition #'identity nil t)))))) |
|
2829 |
(_ nil))) |
|
2830 |
(t (user-error "Definition not found for footnote %s" label))))) |
|
2831 |
(push label defined) |
|
2832 |
(push definition missing-definitions) |
|
2833 |
;; Look for footnote references within DEFINITION, since |
|
2834 |
;; we may need to also find their definition. |
|
2835 |
(dolist (l (funcall list-labels definition)) |
|
2836 |
(unless (or (member l defined) ;Known label |
|
2837 |
(member l undefined)) ;Processed later |
|
2838 |
(push l undefined))))) |
|
2839 |
;; MISSING-DEFINITIONS may contain footnote references with inline |
|
2840 |
;; definitions. Make sure those are changed into real footnote |
|
2841 |
;; definitions. |
|
2842 |
(mapcar (lambda (d) |
|
2843 |
(if (eq (org-element-type d) 'footnote-definition) d |
|
2844 |
(let ((label (org-element-property :label d))) |
|
2845 |
(apply #'org-element-create |
|
2846 |
'footnote-definition `(:label ,label :post-blank 1) |
|
2847 |
(org-element-contents d))))) |
|
2848 |
missing-definitions))) |
|
2849 |
|
|
2850 |
(defun org-export--install-footnote-definitions (definitions tree) |
|
2851 |
"Install footnote definitions in tree. |
|
2852 |
|
|
2853 |
DEFINITIONS is the list of footnote definitions to install. TREE |
|
2854 |
is the parse tree. |
|
2855 |
|
|
2856 |
If there is a footnote section in TREE, definitions found are |
|
2857 |
appended to it. If `org-footnote-section' is non-nil, a new |
|
2858 |
footnote section containing all definitions is inserted in TREE. |
|
2859 |
Otherwise, definitions are appended at the end of the section |
|
2860 |
containing their first reference." |
|
2861 |
(cond |
|
2862 |
((null definitions)) |
|
2863 |
;; If there is a footnote section, insert definitions there. |
|
2864 |
((let ((footnote-section |
|
2865 |
(org-element-map tree 'headline |
|
2866 |
(lambda (h) (and (org-element-property :footnote-section-p h) h)) |
|
2867 |
nil t))) |
|
2868 |
(and footnote-section |
|
2869 |
(apply #'org-element-adopt-elements |
|
2870 |
footnote-section |
|
2871 |
(nreverse definitions))))) |
|
2872 |
;; If there should be a footnote section, create one containing all |
|
2873 |
;; the definitions at the end of the tree. |
|
2874 |
(org-footnote-section |
|
2875 |
(org-element-adopt-elements |
|
2876 |
tree |
|
2877 |
(org-element-create 'headline |
|
2878 |
(list :footnote-section-p t |
|
2879 |
:level 1 |
|
2880 |
:title org-footnote-section |
|
2881 |
:raw-value org-footnote-section) |
|
2882 |
(apply #'org-element-create |
|
2883 |
'section |
|
2884 |
nil |
|
2885 |
(nreverse definitions))))) |
|
2886 |
;; Otherwise add each definition at the end of the section where it |
|
2887 |
;; is first referenced. |
|
2888 |
(t |
|
2889 |
(letrec ((seen nil) |
|
2890 |
(insert-definitions |
|
2891 |
(lambda (data) |
|
2892 |
;; Insert footnote definitions in the same section as |
|
2893 |
;; their first reference in DATA. |
|
2894 |
(org-element-map data 'footnote-reference |
|
2895 |
(lambda (reference) |
|
2896 |
(when (eq (org-element-property :type reference) 'standard) |
|
2897 |
(let ((label (org-element-property :label reference))) |
|
2898 |
(unless (member label seen) |
|
2899 |
(push label seen) |
|
2900 |
(let ((definition |
|
2901 |
(cl-some |
|
2902 |
(lambda (d) |
|
2903 |
(and (equal (org-element-property :label d) |
|
2904 |
label) |
|
2905 |
d)) |
|
2906 |
definitions))) |
|
2907 |
(org-element-adopt-elements |
|
2908 |
(org-element-lineage reference '(section)) |
|
2909 |
definition) |
|
2910 |
;; Also insert definitions for nested |
|
2911 |
;; references, if any. |
|
2912 |
(funcall insert-definitions definition)))))))))) |
|
2913 |
(funcall insert-definitions tree))))) |
|
2914 |
|
|
2915 |
(defun org-export--remove-uninterpreted-data (data info) |
|
2916 |
"Change uninterpreted elements back into Org syntax. |
|
2917 |
DATA is a parse tree or a secondary string. INFO is a plist |
|
2918 |
containing export options. It is modified by side effect and |
|
2919 |
returned by the function." |
|
2920 |
(org-element-map data |
|
2921 |
'(entity bold italic latex-environment latex-fragment strike-through |
|
2922 |
subscript superscript underline) |
|
2923 |
(lambda (datum) |
|
2924 |
(let ((new |
|
2925 |
(cl-case (org-element-type datum) |
|
2926 |
;; ... entities... |
|
2927 |
(entity |
|
2928 |
(and (not (plist-get info :with-entities)) |
|
2929 |
(list (concat |
|
2930 |
(org-export-expand datum nil) |
|
2931 |
(make-string |
|
2932 |
(or (org-element-property :post-blank datum) 0) |
|
2933 |
?\s))))) |
|
2934 |
;; ... emphasis... |
|
2935 |
((bold italic strike-through underline) |
|
2936 |
(and (not (plist-get info :with-emphasize)) |
|
2937 |
(let ((marker (cl-case (org-element-type datum) |
|
2938 |
(bold "*") |
|
2939 |
(italic "/") |
|
2940 |
(strike-through "+") |
|
2941 |
(underline "_")))) |
|
2942 |
(append |
|
2943 |
(list marker) |
|
2944 |
(org-element-contents datum) |
|
2945 |
(list (concat |
|
2946 |
marker |
|
2947 |
(make-string |
|
2948 |
(or (org-element-property :post-blank datum) |
|
2949 |
0) |
|
2950 |
?\s))))))) |
|
2951 |
;; ... LaTeX environments and fragments... |
|
2952 |
((latex-environment latex-fragment) |
|
2953 |
(and (eq (plist-get info :with-latex) 'verbatim) |
|
2954 |
(list (org-export-expand datum nil)))) |
|
2955 |
;; ... sub/superscripts... |
|
2956 |
((subscript superscript) |
|
2957 |
(let ((sub/super-p (plist-get info :with-sub-superscript)) |
|
2958 |
(bracketp (org-element-property :use-brackets-p datum))) |
|
2959 |
(and (or (not sub/super-p) |
|
2960 |
(and (eq sub/super-p '{}) (not bracketp))) |
|
2961 |
(append |
|
2962 |
(list (concat |
|
2963 |
(if (eq (org-element-type datum) 'subscript) |
|
2964 |
"_" |
|
2965 |
"^") |
|
2966 |
(and bracketp "{"))) |
|
2967 |
(org-element-contents datum) |
|
2968 |
(list (concat |
|
2969 |
(and bracketp "}") |
|
2970 |
(and (org-element-property :post-blank datum) |
|
2971 |
(make-string |
|
2972 |
(org-element-property :post-blank datum) |
|
2973 |
?\s))))))))))) |
|
2974 |
(when new |
|
2975 |
;; Splice NEW at DATUM location in parse tree. |
|
2976 |
(dolist (e new (org-element-extract-element datum)) |
|
2977 |
(unless (equal e "") (org-element-insert-before e datum)))))) |
|
2978 |
info nil nil t) |
|
2979 |
;; Return modified parse tree. |
|
2980 |
data) |
|
2981 |
|
|
2982 |
;;;###autoload |
|
2983 |
(defun org-export-as |
|
2984 |
(backend &optional subtreep visible-only body-only ext-plist) |
|
2985 |
"Transcode current Org buffer into BACKEND code. |
|
2986 |
|
|
2987 |
BACKEND is either an export back-end, as returned by, e.g., |
|
2988 |
`org-export-create-backend', or a symbol referring to |
|
2989 |
a registered back-end. |
|
2990 |
|
|
2991 |
If narrowing is active in the current buffer, only transcode its |
|
2992 |
narrowed part. |
|
2993 |
|
|
2994 |
If a region is active, transcode that region. |
|
2995 |
|
|
2996 |
When optional argument SUBTREEP is non-nil, transcode the |
|
2997 |
sub-tree at point, extracting information from the headline |
|
2998 |
properties first. |
|
2999 |
|
|
3000 |
When optional argument VISIBLE-ONLY is non-nil, don't export |
|
3001 |
contents of hidden elements. |
|
3002 |
|
|
3003 |
When optional argument BODY-ONLY is non-nil, only return body |
|
3004 |
code, without surrounding template. |
|
3005 |
|
|
3006 |
Optional argument EXT-PLIST, when provided, is a property list |
|
3007 |
with external parameters overriding Org default settings, but |
|
3008 |
still inferior to file-local settings. |
|
3009 |
|
|
3010 |
Return code as a string." |
|
3011 |
(when (symbolp backend) (setq backend (org-export-get-backend backend))) |
|
3012 |
(org-export-barf-if-invalid-backend backend) |
|
3013 |
(save-excursion |
|
3014 |
(save-restriction |
|
3015 |
;; Narrow buffer to an appropriate region or subtree for |
|
3016 |
;; parsing. If parsing subtree, be sure to remove main |
|
3017 |
;; headline, planning data and property drawer. |
|
3018 |
(cond ((org-region-active-p) |
|
3019 |
(narrow-to-region (region-beginning) (region-end))) |
|
3020 |
(subtreep |
|
3021 |
(org-narrow-to-subtree) |
|
3022 |
(goto-char (point-min)) |
|
3023 |
(org-end-of-meta-data) |
|
3024 |
(narrow-to-region (point) (point-max)))) |
|
3025 |
;; Initialize communication channel with original buffer |
|
3026 |
;; attributes, unavailable in its copy. |
|
3027 |
(let* ((org-export-current-backend (org-export-backend-name backend)) |
|
3028 |
(info (org-combine-plists |
|
3029 |
(org-export--get-export-attributes |
|
3030 |
backend subtreep visible-only body-only) |
|
3031 |
(org-export--get-buffer-attributes))) |
|
3032 |
(parsed-keywords |
|
3033 |
(delq nil |
|
3034 |
(mapcar (lambda (o) (and (eq (nth 4 o) 'parse) (nth 1 o))) |
|
3035 |
(append (org-export-get-all-options backend) |
|
3036 |
org-export-options-alist)))) |
|
3037 |
tree) |
|
3038 |
;; Update communication channel and get parse tree. Buffer |
|
3039 |
;; isn't parsed directly. Instead, all buffer modifications |
|
3040 |
;; and consequent parsing are undertaken in a temporary copy. |
|
3041 |
(org-export-with-buffer-copy |
|
3042 |
;; Run first hook with current back-end's name as argument. |
|
3043 |
(run-hook-with-args 'org-export-before-processing-hook |
|
3044 |
(org-export-backend-name backend)) |
|
3045 |
;; Include files, delete comments and expand macros. |
|
3046 |
(org-export-expand-include-keyword) |
|
3047 |
(org-export--delete-comment-trees) |
|
3048 |
(org-macro-initialize-templates) |
|
3049 |
(org-macro-replace-all |
|
3050 |
(append org-macro-templates org-export-global-macros) |
|
3051 |
nil parsed-keywords) |
|
3052 |
;; Refresh buffer properties and radio targets after |
|
3053 |
;; potentially invasive previous changes. Likewise, do it |
|
3054 |
;; again after executing Babel code. |
|
3055 |
(org-set-regexps-and-options) |
|
3056 |
(org-update-radio-target-regexp) |
|
3057 |
(when org-export-use-babel |
|
3058 |
(org-babel-exp-process-buffer) |
|
3059 |
(org-set-regexps-and-options) |
|
3060 |
(org-update-radio-target-regexp)) |
|
3061 |
;; Run last hook with current back-end's name as argument. |
|
3062 |
;; Update buffer properties and radio targets one last time |
|
3063 |
;; before parsing. |
|
3064 |
(goto-char (point-min)) |
|
3065 |
(save-excursion |
|
3066 |
(run-hook-with-args 'org-export-before-parsing-hook |
|
3067 |
(org-export-backend-name backend))) |
|
3068 |
(org-set-regexps-and-options) |
|
3069 |
(org-update-radio-target-regexp) |
|
3070 |
;; Update communication channel with environment. |
|
3071 |
(setq info |
|
3072 |
(org-combine-plists |
|
3073 |
info (org-export-get-environment backend subtreep ext-plist))) |
|
3074 |
;; De-activate uninterpreted data from parsed keywords. |
|
3075 |
(dolist (entry (append (org-export-get-all-options backend) |
|
3076 |
org-export-options-alist)) |
|
3077 |
(pcase entry |
|
3078 |
(`(,p ,_ ,_ ,_ parse) |
|
3079 |
(let ((value (plist-get info p))) |
|
3080 |
(plist-put info |
|
3081 |
p |
|
3082 |
(org-export--remove-uninterpreted-data value info)))) |
|
3083 |
(_ nil))) |
|
3084 |
;; Install user's and developer's filters. |
|
3085 |
(setq info (org-export-install-filters info)) |
|
3086 |
;; Call options filters and update export options. We do not |
|
3087 |
;; use `org-export-filter-apply-functions' here since the |
|
3088 |
;; arity of such filters is different. |
|
3089 |
(let ((backend-name (org-export-backend-name backend))) |
|
3090 |
(dolist (filter (plist-get info :filter-options)) |
|
3091 |
(let ((result (funcall filter info backend-name))) |
|
3092 |
(when result (setq info result))))) |
|
3093 |
;; Expand export-specific set of macros: {{{author}}}, |
|
3094 |
;; {{{date(FORMAT)}}}, {{{email}}} and {{{title}}}. It must |
|
3095 |
;; be done once regular macros have been expanded, since |
|
3096 |
;; parsed keywords may contain one of them. |
|
3097 |
(org-macro-replace-all |
|
3098 |
(list |
|
3099 |
(cons "author" (org-element-interpret-data (plist-get info :author))) |
|
3100 |
(cons "date" |
|
3101 |
(let* ((date (plist-get info :date)) |
|
3102 |
(value (or (org-element-interpret-data date) ""))) |
|
3103 |
(if (and (consp date) |
|
3104 |
(not (cdr date)) |
|
3105 |
(eq (org-element-type (car date)) 'timestamp)) |
|
3106 |
(format "(eval (if (org-string-nw-p \"$1\") %s %S))" |
|
3107 |
(format "(org-timestamp-format '%S \"$1\")" |
|
3108 |
(org-element-copy (car date))) |
|
3109 |
value) |
|
3110 |
value))) |
|
3111 |
(cons "email" (org-element-interpret-data (plist-get info :email))) |
|
3112 |
(cons "title" (org-element-interpret-data (plist-get info :title))) |
|
3113 |
(cons "results" "$1")) |
|
3114 |
'finalize |
|
3115 |
parsed-keywords) |
|
3116 |
;; Parse buffer. |
|
3117 |
(setq tree (org-element-parse-buffer nil visible-only)) |
|
3118 |
;; Prune tree from non-exported elements and transform |
|
3119 |
;; uninterpreted elements or objects in both parse tree and |
|
3120 |
;; communication channel. |
|
3121 |
(org-export--prune-tree tree info) |
|
3122 |
(org-export--remove-uninterpreted-data tree info) |
|
3123 |
;; Call parse tree filters. |
|
3124 |
(setq tree |
|
3125 |
(org-export-filter-apply-functions |
|
3126 |
(plist-get info :filter-parse-tree) tree info)) |
|
3127 |
;; Now tree is complete, compute its properties and add them |
|
3128 |
;; to communication channel. |
|
3129 |
(setq info (org-export--collect-tree-properties tree info)) |
|
3130 |
;; Eventually transcode TREE. Wrap the resulting string into |
|
3131 |
;; a template. |
|
3132 |
(let* ((body (org-element-normalize-string |
|
3133 |
(or (org-export-data tree info) ""))) |
|
3134 |
(inner-template (cdr (assq 'inner-template |
|
3135 |
(plist-get info :translate-alist)))) |
|
3136 |
(full-body (org-export-filter-apply-functions |
|
3137 |
(plist-get info :filter-body) |
|
3138 |
(if (not (functionp inner-template)) body |
|
3139 |
(funcall inner-template body info)) |
|
3140 |
info)) |
|
3141 |
(template (cdr (assq 'template |
|
3142 |
(plist-get info :translate-alist))))) |
|
3143 |
;; Remove all text properties since they cannot be |
|
3144 |
;; retrieved from an external process. Finally call |
|
3145 |
;; final-output filter and return result. |
|
3146 |
(org-no-properties |
|
3147 |
(org-export-filter-apply-functions |
|
3148 |
(plist-get info :filter-final-output) |
|
3149 |
(if (or (not (functionp template)) body-only) full-body |
|
3150 |
(funcall template full-body info)) |
|
3151 |
info)))))))) |
|
3152 |
|
|
3153 |
;;;###autoload |
|
3154 |
(defun org-export-string-as (string backend &optional body-only ext-plist) |
|
3155 |
"Transcode STRING into BACKEND code. |
|
3156 |
|
|
3157 |
BACKEND is either an export back-end, as returned by, e.g., |
|
3158 |
`org-export-create-backend', or a symbol referring to |
|
3159 |
a registered back-end. |
|
3160 |
|
|
3161 |
When optional argument BODY-ONLY is non-nil, only return body |
|
3162 |
code, without preamble nor postamble. |
|
3163 |
|
|
3164 |
Optional argument EXT-PLIST, when provided, is a property list |
|
3165 |
with external parameters overriding Org default settings, but |
|
3166 |
still inferior to file-local settings. |
|
3167 |
|
|
3168 |
Return code as a string." |
|
3169 |
(with-temp-buffer |
|
3170 |
(insert string) |
|
3171 |
(let ((org-inhibit-startup t)) (org-mode)) |
|
3172 |
(org-export-as backend nil nil body-only ext-plist))) |
|
3173 |
|
|
3174 |
;;;###autoload |
|
3175 |
(defun org-export-replace-region-by (backend) |
|
3176 |
"Replace the active region by its export to BACKEND. |
|
3177 |
BACKEND is either an export back-end, as returned by, e.g., |
|
3178 |
`org-export-create-backend', or a symbol referring to |
|
3179 |
a registered back-end." |
|
3180 |
(unless (org-region-active-p) (user-error "No active region to replace")) |
|
3181 |
(insert |
|
3182 |
(org-export-string-as |
|
3183 |
(delete-and-extract-region (region-beginning) (region-end)) backend t))) |
|
3184 |
|
|
3185 |
;;;###autoload |
|
3186 |
(defun org-export-insert-default-template (&optional backend subtreep) |
|
3187 |
"Insert all export keywords with default values at beginning of line. |
|
3188 |
|
|
3189 |
BACKEND is a symbol referring to the name of a registered export |
|
3190 |
back-end, for which specific export options should be added to |
|
3191 |
the template, or `default' for default template. When it is nil, |
|
3192 |
the user will be prompted for a category. |
|
3193 |
|
|
3194 |
If SUBTREEP is non-nil, export configuration will be set up |
|
3195 |
locally for the subtree through node properties." |
|
3196 |
(interactive) |
|
3197 |
(unless (derived-mode-p 'org-mode) (user-error "Not in an Org mode buffer")) |
|
3198 |
(when (and subtreep (org-before-first-heading-p)) |
|
3199 |
(user-error "No subtree to set export options for")) |
|
3200 |
(let ((node (and subtreep (save-excursion (org-back-to-heading t) (point)))) |
|
3201 |
(backend |
|
3202 |
(or backend |
|
3203 |
(intern |
|
3204 |
(org-completing-read |
|
3205 |
"Options category: " |
|
3206 |
(cons "default" |
|
3207 |
(mapcar (lambda (b) |
|
3208 |
(symbol-name (org-export-backend-name b))) |
|
3209 |
org-export-registered-backends)) |
|
3210 |
nil t)))) |
|
3211 |
options keywords) |
|
3212 |
;; Populate OPTIONS and KEYWORDS. |
|
3213 |
(dolist (entry (cond ((eq backend 'default) org-export-options-alist) |
|
3214 |
((org-export-backend-p backend) |
|
3215 |
(org-export-backend-options backend)) |
|
3216 |
(t (org-export-backend-options |
|
3217 |
(org-export-get-backend backend))))) |
|
3218 |
(let ((keyword (nth 1 entry)) |
|
3219 |
(option (nth 2 entry))) |
|
3220 |
(cond |
|
3221 |
(keyword (unless (assoc keyword keywords) |
|
3222 |
(let ((value |
|
3223 |
(if (eq (nth 4 entry) 'split) |
|
3224 |
(mapconcat #'identity (eval (nth 3 entry)) " ") |
|
3225 |
(eval (nth 3 entry))))) |
|
3226 |
(push (cons keyword value) keywords)))) |
|
3227 |
(option (unless (assoc option options) |
|
3228 |
(push (cons option (eval (nth 3 entry))) options)))))) |
|
3229 |
;; Move to an appropriate location in order to insert options. |
|
3230 |
(unless subtreep (beginning-of-line)) |
|
3231 |
;; First (multiple) OPTIONS lines. Never go past fill-column. |
|
3232 |
(when options |
|
3233 |
(let ((items |
|
3234 |
(mapcar |
|
3235 |
#'(lambda (opt) (format "%s:%S" (car opt) (cdr opt))) |
|
3236 |
(sort options (lambda (k1 k2) (string< (car k1) (car k2))))))) |
|
3237 |
(if subtreep |
|
3238 |
(org-entry-put |
|
3239 |
node "EXPORT_OPTIONS" (mapconcat 'identity items " ")) |
|
3240 |
(while items |
|
3241 |
(insert "#+OPTIONS:") |
|
3242 |
(let ((width 10)) |
|
3243 |
(while (and items |
|
3244 |
(< (+ width (length (car items)) 1) fill-column)) |
|
3245 |
(let ((item (pop items))) |
|
3246 |
(insert " " item) |
|
3247 |
(cl-incf width (1+ (length item)))))) |
|
3248 |
(insert "\n"))))) |
|
3249 |
;; Then the rest of keywords, in the order specified in either |
|
3250 |
;; `org-export-options-alist' or respective export back-ends. |
|
3251 |
(dolist (key (nreverse keywords)) |
|
3252 |
(let ((val (cond ((equal (car key) "DATE") |
|
3253 |
(or (cdr key) |
|
3254 |
(with-temp-buffer |
|
3255 |
(org-insert-time-stamp (current-time))))) |
|
3256 |
((equal (car key) "TITLE") |
|
3257 |
(or (let ((visited-file |
|
3258 |
(buffer-file-name (buffer-base-buffer)))) |
|
3259 |
(and visited-file |
|
3260 |
(file-name-sans-extension |
|
3261 |
(file-name-nondirectory visited-file)))) |
|
3262 |
(buffer-name (buffer-base-buffer)))) |
|
3263 |
(t (cdr key))))) |
|
3264 |
(if subtreep (org-entry-put node (concat "EXPORT_" (car key)) val) |
|
3265 |
(insert |
|
3266 |
(format "#+%s:%s\n" |
|
3267 |
(car key) |
|
3268 |
(if (org-string-nw-p val) (format " %s" val) "")))))))) |
|
3269 |
|
|
3270 |
(defun org-export-expand-include-keyword (&optional included dir footnotes) |
|
3271 |
"Expand every include keyword in buffer. |
|
3272 |
Optional argument INCLUDED is a list of included file names along |
|
3273 |
with their line restriction, when appropriate. It is used to |
|
3274 |
avoid infinite recursion. Optional argument DIR is the current |
|
3275 |
working directory. It is used to properly resolve relative |
|
3276 |
paths. Optional argument FOOTNOTES is a hash-table used for |
|
3277 |
storing and resolving footnotes. It is created automatically." |
|
3278 |
(let ((case-fold-search t) |
|
3279 |
(file-prefix (make-hash-table :test #'equal)) |
|
3280 |
(current-prefix 0) |
|
3281 |
(footnotes (or footnotes (make-hash-table :test #'equal))) |
|
3282 |
(include-re "^[ \t]*#\\+INCLUDE:")) |
|
3283 |
;; If :minlevel is not set the text-property |
|
3284 |
;; `:org-include-induced-level' will be used to determine the |
|
3285 |
;; relative level when expanding INCLUDE. |
|
3286 |
;; Only affects included Org documents. |
|
3287 |
(goto-char (point-min)) |
|
3288 |
(while (re-search-forward include-re nil t) |
|
3289 |
(put-text-property (line-beginning-position) (line-end-position) |
|
3290 |
:org-include-induced-level |
|
3291 |
(1+ (org-reduced-level (or (org-current-level) 0))))) |
|
3292 |
;; Expand INCLUDE keywords. |
|
3293 |
(goto-char (point-min)) |
|
3294 |
(while (re-search-forward include-re nil t) |
|
3295 |
(unless (org-in-commented-heading-p) |
|
3296 |
(let ((element (save-match-data (org-element-at-point)))) |
|
3297 |
(when (eq (org-element-type element) 'keyword) |
|
3298 |
(beginning-of-line) |
|
3299 |
;; Extract arguments from keyword's value. |
|
3300 |
(let* ((value (org-element-property :value element)) |
|
3301 |
(ind (org-get-indentation)) |
|
3302 |
location |
|
3303 |
(file |
|
3304 |
(and (string-match |
|
3305 |
"^\\(\".+?\"\\|\\S-+\\)\\(?:\\s-+\\|$\\)" value) |
|
3306 |
(prog1 |
|
3307 |
(save-match-data |
|
3308 |
(let ((matched (match-string 1 value))) |
|
3309 |
(when (string-match "\\(::\\(.*?\\)\\)\"?\\'" |
|
3310 |
matched) |
|
3311 |
(setq location (match-string 2 matched)) |
|
3312 |
(setq matched |
|
3313 |
(replace-match "" nil nil matched 1))) |
|
3314 |
(expand-file-name |
|
3315 |
(org-unbracket-string "\"" "\"" matched) |
|
3316 |
dir))) |
|
3317 |
(setq value (replace-match "" nil nil value))))) |
|
3318 |
(only-contents |
|
3319 |
(and (string-match ":only-contents *\\([^: \r\t\n]\\S-*\\)?" |
|
3320 |
value) |
|
3321 |
(prog1 (org-not-nil (match-string 1 value)) |
|
3322 |
(setq value (replace-match "" nil nil value))))) |
|
3323 |
(lines |
|
3324 |
(and (string-match |
|
3325 |
":lines +\"\\(\\(?:[0-9]+\\)?-\\(?:[0-9]+\\)?\\)\"" |
|
3326 |
value) |
|
3327 |
(prog1 (match-string 1 value) |
|
3328 |
(setq value (replace-match "" nil nil value))))) |
|
3329 |
(env (cond |
|
3330 |
((string-match "\\<example\\>" value) 'literal) |
|
3331 |
((string-match "\\<export\\(?: +\\(.*\\)\\)?" value) |
|
3332 |
'literal) |
|
3333 |
((string-match "\\<src\\(?: +\\(.*\\)\\)?" value) |
|
3334 |
'literal))) |
|
3335 |
;; Minimal level of included file defaults to the |
|
3336 |
;; child level of the current headline, if any, or |
|
3337 |
;; one. It only applies is the file is meant to be |
|
3338 |
;; included as an Org one. |
|
3339 |
(minlevel |
|
3340 |
(and (not env) |
|
3341 |
(if (string-match ":minlevel +\\([0-9]+\\)" value) |
|
3342 |
(prog1 (string-to-number (match-string 1 value)) |
|
3343 |
(setq value (replace-match "" nil nil value))) |
|
3344 |
(get-text-property (point) |
|
3345 |
:org-include-induced-level)))) |
|
3346 |
(args (and (eq env 'literal) (match-string 1 value))) |
|
3347 |
(block (and (string-match "\\<\\(\\S-+\\)\\>" value) |
|
3348 |
(match-string 1 value)))) |
|
3349 |
;; Remove keyword. |
|
3350 |
(delete-region (point) (line-beginning-position 2)) |
|
3351 |
(cond |
|
3352 |
((not file) nil) |
|
3353 |
((not (file-readable-p file)) |
|
3354 |
(error "Cannot include file %s" file)) |
|
3355 |
;; Check if files has already been parsed. Look after |
|
3356 |
;; inclusion lines too, as different parts of the same |
|
3357 |
;; file can be included too. |
|
3358 |
((member (list file lines) included) |
|
3359 |
(error "Recursive file inclusion: %s" file)) |
|
3360 |
(t |
|
3361 |
(cond |
|
3362 |
((eq env 'literal) |
|
3363 |
(insert |
|
3364 |
(let ((ind-str (make-string ind ?\s)) |
|
3365 |
(arg-str (if (stringp args) (format " %s" args) "")) |
|
3366 |
(contents |
|
3367 |
(org-escape-code-in-string |
|
3368 |
(org-export--prepare-file-contents file lines)))) |
|
3369 |
(format "%s#+BEGIN_%s%s\n%s%s#+END_%s\n" |
|
3370 |
ind-str block arg-str contents ind-str block)))) |
|
3371 |
((stringp block) |
|
3372 |
(insert |
|
3373 |
(let ((ind-str (make-string ind ?\s)) |
|
3374 |
(contents |
|
3375 |
(org-export--prepare-file-contents file lines))) |
|
3376 |
(format "%s#+BEGIN_%s\n%s%s#+END_%s\n" |
|
3377 |
ind-str block contents ind-str block)))) |
|
3378 |
(t |
|
3379 |
(insert |
|
3380 |
(with-temp-buffer |
|
3381 |
(let ((org-inhibit-startup t) |
|
3382 |
(lines |
|
3383 |
(if location |
|
3384 |
(org-export--inclusion-absolute-lines |
|
3385 |
file location only-contents lines) |
|
3386 |
lines))) |
|
3387 |
(org-mode) |
|
3388 |
(insert |
|
3389 |
(org-export--prepare-file-contents |
|
3390 |
file lines ind minlevel |
|
3391 |
(or |
|
3392 |
(gethash file file-prefix) |
|
3393 |
(puthash file (cl-incf current-prefix) file-prefix)) |
|
3394 |
footnotes))) |
|
3395 |
(org-export-expand-include-keyword |
|
3396 |
(cons (list file lines) included) |
|
3397 |
(file-name-directory file) |
|
3398 |
footnotes) |
|
3399 |
(buffer-string))))) |
|
3400 |
;; Expand footnotes after all files have been |
|
3401 |
;; included. Footnotes are stored at end of buffer. |
|
3402 |
(unless included |
|
3403 |
(org-with-wide-buffer |
|
3404 |
(goto-char (point-max)) |
|
3405 |
(maphash (lambda (k v) |
|
3406 |
(insert (format "\n[fn:%s] %s\n" k v))) |
|
3407 |
footnotes)))))))))))) |
|
3408 |
|
|
3409 |
(defun org-export--inclusion-absolute-lines (file location only-contents lines) |
|
3410 |
"Resolve absolute lines for an included file with file-link. |
|
3411 |
|
|
3412 |
FILE is string file-name of the file to include. LOCATION is a |
|
3413 |
string name within FILE to be included (located via |
|
3414 |
`org-link-search'). If ONLY-CONTENTS is non-nil only the |
|
3415 |
contents of the named element will be included, as determined |
|
3416 |
Org-Element. If LINES is non-nil only those lines are included. |
|
3417 |
|
|
3418 |
Return a string of lines to be included in the format expected by |
|
3419 |
`org-export--prepare-file-contents'." |
|
3420 |
(with-temp-buffer |
|
3421 |
(insert-file-contents file) |
|
3422 |
(unless (eq major-mode 'org-mode) |
|
3423 |
(let ((org-inhibit-startup t)) (org-mode))) |
|
3424 |
(condition-case err |
|
3425 |
;; Enforce consistent search. |
|
3426 |
(let ((org-link-search-must-match-exact-headline nil)) |
|
3427 |
(org-link-search location)) |
|
3428 |
(error |
|
3429 |
(error "%s for %s::%s" (error-message-string err) file location))) |
|
3430 |
(let* ((element (org-element-at-point)) |
|
3431 |
(contents-begin |
|
3432 |
(and only-contents (org-element-property :contents-begin element)))) |
|
3433 |
(narrow-to-region |
|
3434 |
(or contents-begin (org-element-property :begin element)) |
|
3435 |
(org-element-property (if contents-begin :contents-end :end) element)) |
|
3436 |
(when (and only-contents |
|
3437 |
(memq (org-element-type element) '(headline inlinetask))) |
|
3438 |
;; Skip planning line and property-drawer. |
|
3439 |
(goto-char (point-min)) |
|
3440 |
(when (looking-at-p org-planning-line-re) (forward-line)) |
|
3441 |
(when (looking-at org-property-drawer-re) (goto-char (match-end 0))) |
|
3442 |
(unless (bolp) (forward-line)) |
|
3443 |
(narrow-to-region (point) (point-max)))) |
|
3444 |
(when lines |
|
3445 |
(org-skip-whitespace) |
|
3446 |
(beginning-of-line) |
|
3447 |
(let* ((lines (split-string lines "-")) |
|
3448 |
(lbeg (string-to-number (car lines))) |
|
3449 |
(lend (string-to-number (cadr lines))) |
|
3450 |
(beg (if (zerop lbeg) (point-min) |
|
3451 |
(goto-char (point-min)) |
|
3452 |
(forward-line (1- lbeg)) |
|
3453 |
(point))) |
|
3454 |
(end (if (zerop lend) (point-max) |
|
3455 |
(goto-char beg) |
|
3456 |
(forward-line (1- lend)) |
|
3457 |
(point)))) |
|
3458 |
(narrow-to-region beg end))) |
|
3459 |
(let ((end (point-max))) |
|
3460 |
(goto-char (point-min)) |
|
3461 |
(widen) |
|
3462 |
(let ((start-line (line-number-at-pos))) |
|
3463 |
(format "%d-%d" |
|
3464 |
start-line |
|
3465 |
(save-excursion |
|
3466 |
(+ start-line |
|
3467 |
(let ((counter 0)) |
|
3468 |
(while (< (point) end) (cl-incf counter) (forward-line)) |
|
3469 |
counter)))))))) |
|
3470 |
|
|
3471 |
(defun org-export--prepare-file-contents |
|
3472 |
(file &optional lines ind minlevel id footnotes) |
|
3473 |
"Prepare contents of FILE for inclusion and return it as a string. |
|
3474 |
|
|
3475 |
When optional argument LINES is a string specifying a range of |
|
3476 |
lines, include only those lines. |
|
3477 |
|
|
3478 |
Optional argument IND, when non-nil, is an integer specifying the |
|
3479 |
global indentation of returned contents. Since its purpose is to |
|
3480 |
allow an included file to stay in the same environment it was |
|
3481 |
created (e.g., a list item), it doesn't apply past the first |
|
3482 |
headline encountered. |
|
3483 |
|
|
3484 |
Optional argument MINLEVEL, when non-nil, is an integer |
|
3485 |
specifying the level that any top-level headline in the included |
|
3486 |
file should have. |
|
3487 |
|
|
3488 |
Optional argument ID is an integer that will be inserted before |
|
3489 |
each footnote definition and reference if FILE is an Org file. |
|
3490 |
This is useful to avoid conflicts when more than one Org file |
|
3491 |
with footnotes is included in a document. |
|
3492 |
|
|
3493 |
Optional argument FOOTNOTES is a hash-table to store footnotes in |
|
3494 |
the included document." |
|
3495 |
(with-temp-buffer |
|
3496 |
(insert-file-contents file) |
|
3497 |
(when lines |
|
3498 |
(let* ((lines (split-string lines "-")) |
|
3499 |
(lbeg (string-to-number (car lines))) |
|
3500 |
(lend (string-to-number (cadr lines))) |
|
3501 |
(beg (if (zerop lbeg) (point-min) |
|
3502 |
(goto-char (point-min)) |
|
3503 |
(forward-line (1- lbeg)) |
|
3504 |
(point))) |
|
3505 |
(end (if (zerop lend) (point-max) |
|
3506 |
(goto-char (point-min)) |
|
3507 |
(forward-line (1- lend)) |
|
3508 |
(point)))) |
|
3509 |
(narrow-to-region beg end))) |
|
3510 |
;; Remove blank lines at beginning and end of contents. The logic |
|
3511 |
;; behind that removal is that blank lines around include keyword |
|
3512 |
;; override blank lines in included file. |
|
3513 |
(goto-char (point-min)) |
|
3514 |
(org-skip-whitespace) |
|
3515 |
(beginning-of-line) |
|
3516 |
(delete-region (point-min) (point)) |
|
3517 |
(goto-char (point-max)) |
|
3518 |
(skip-chars-backward " \r\t\n") |
|
3519 |
(forward-line) |
|
3520 |
(delete-region (point) (point-max)) |
|
3521 |
;; If IND is set, preserve indentation of include keyword until |
|
3522 |
;; the first headline encountered. |
|
3523 |
(when (and ind (> ind 0)) |
|
3524 |
(unless (eq major-mode 'org-mode) |
|
3525 |
(let ((org-inhibit-startup t)) (org-mode))) |
|
3526 |
(goto-char (point-min)) |
|
3527 |
(let ((ind-str (make-string ind ?\s))) |
|
3528 |
(while (not (or (eobp) (looking-at org-outline-regexp-bol))) |
|
3529 |
;; Do not move footnote definitions out of column 0. |
|
3530 |
(unless (and (looking-at org-footnote-definition-re) |
|
3531 |
(eq (org-element-type (org-element-at-point)) |
|
3532 |
'footnote-definition)) |
|
3533 |
(insert ind-str)) |
|
3534 |
(forward-line)))) |
|
3535 |
;; When MINLEVEL is specified, compute minimal level for headlines |
|
3536 |
;; in the file (CUR-MIN), and remove stars to each headline so |
|
3537 |
;; that headlines with minimal level have a level of MINLEVEL. |
|
3538 |
(when minlevel |
|
3539 |
(unless (eq major-mode 'org-mode) |
|
3540 |
(let ((org-inhibit-startup t)) (org-mode))) |
|
3541 |
(org-with-limited-levels |
|
3542 |
(let ((levels (org-map-entries |
|
3543 |
(lambda () (org-reduced-level (org-current-level)))))) |
|
3544 |
(when levels |
|
3545 |
(let ((offset (- minlevel (apply #'min levels)))) |
|
3546 |
(unless (zerop offset) |
|
3547 |
(when org-odd-levels-only (setq offset (* offset 2))) |
|
3548 |
;; Only change stars, don't bother moving whole |
|
3549 |
;; sections. |
|
3550 |
(org-map-entries |
|
3551 |
(lambda () |
|
3552 |
(if (< offset 0) (delete-char (abs offset)) |
|
3553 |
(insert (make-string offset ?*))))))))))) |
|
3554 |
;; Append ID to all footnote references and definitions, so they |
|
3555 |
;; become file specific and cannot collide with footnotes in other |
|
3556 |
;; included files. Further, collect relevant footnote definitions |
|
3557 |
;; outside of LINES, in order to reintroduce them later. |
|
3558 |
(when id |
|
3559 |
(let ((marker-min (point-min-marker)) |
|
3560 |
(marker-max (point-max-marker)) |
|
3561 |
(get-new-label |
|
3562 |
(lambda (label) |
|
3563 |
;; Generate new label from LABEL by prefixing it with |
|
3564 |
;; "-ID-". |
|
3565 |
(format "-%d-%s" id label))) |
|
3566 |
(set-new-label |
|
3567 |
(lambda (f old new) |
|
3568 |
;; Replace OLD label with NEW in footnote F. |
|
3569 |
(save-excursion |
|
3570 |
(goto-char (+ (org-element-property :begin f) 4)) |
|
3571 |
(looking-at (regexp-quote old)) |
|
3572 |
(replace-match new)))) |
|
3573 |
(seen-alist)) |
|
3574 |
(goto-char (point-min)) |
|
3575 |
(while (re-search-forward org-footnote-re nil t) |
|
3576 |
(let ((footnote (save-excursion |
|
3577 |
(backward-char) |
|
3578 |
(org-element-context)))) |
|
3579 |
(when (memq (org-element-type footnote) |
|
3580 |
'(footnote-definition footnote-reference)) |
|
3581 |
(let* ((label (org-element-property :label footnote))) |
|
3582 |
;; Update the footnote-reference at point and collect |
|
3583 |
;; the new label, which is only used for footnotes |
|
3584 |
;; outsides LINES. |
|
3585 |
(when label |
|
3586 |
(let ((seen (cdr (assoc label seen-alist)))) |
|
3587 |
(if seen (funcall set-new-label footnote label seen) |
|
3588 |
(let ((new (funcall get-new-label label))) |
|
3589 |
(push (cons label new) seen-alist) |
|
3590 |
(org-with-wide-buffer |
|
3591 |
(let* ((def (org-footnote-get-definition label)) |
|
3592 |
(beg (nth 1 def))) |
|
3593 |
(when (and def |
|
3594 |
(or (< beg marker-min) |
|
3595 |
(>= beg marker-max))) |
|
3596 |
;; Store since footnote-definition is |
|
3597 |
;; outside of LINES. |
|
3598 |
(puthash new |
|
3599 |
(org-element-normalize-string (nth 3 def)) |
|
3600 |
footnotes)))) |
|
3601 |
(funcall set-new-label footnote label new))))))))) |
|
3602 |
(set-marker marker-min nil) |
|
3603 |
(set-marker marker-max nil))) |
|
3604 |
(org-element-normalize-string (buffer-string)))) |
|
3605 |
|
|
3606 |
(defun org-export--copy-to-kill-ring-p () |
|
3607 |
"Return a non-nil value when output should be added to the kill ring. |
|
3608 |
See also `org-export-copy-to-kill-ring'." |
|
3609 |
(if (eq org-export-copy-to-kill-ring 'if-interactive) |
|
3610 |
(not (or executing-kbd-macro noninteractive)) |
|
3611 |
(eq org-export-copy-to-kill-ring t))) |
|
3612 |
|
|
3613 |
|
|
3614 |
|
|
3615 |
;;; Tools For Back-Ends |
|
3616 |
;; |
|
3617 |
;; A whole set of tools is available to help build new exporters. Any |
|
3618 |
;; function general enough to have its use across many back-ends |
|
3619 |
;; should be added here. |
|
3620 |
|
|
3621 |
;;;; For Affiliated Keywords |
|
3622 |
;; |
|
3623 |
;; `org-export-read-attribute' reads a property from a given element |
|
3624 |
;; as a plist. It can be used to normalize affiliated keywords' |
|
3625 |
;; syntax. |
|
3626 |
;; |
|
3627 |
;; Since captions can span over multiple lines and accept dual values, |
|
3628 |
;; their internal representation is a bit tricky. Therefore, |
|
3629 |
;; `org-export-get-caption' transparently returns a given element's |
|
3630 |
;; caption as a secondary string. |
|
3631 |
|
|
3632 |
(defun org-export-read-attribute (attribute element &optional property) |
|
3633 |
"Turn ATTRIBUTE property from ELEMENT into a plist. |
|
3634 |
|
|
3635 |
When optional argument PROPERTY is non-nil, return the value of |
|
3636 |
that property within attributes. |
|
3637 |
|
|
3638 |
This function assumes attributes are defined as \":keyword |
|
3639 |
value\" pairs. It is appropriate for `:attr_html' like |
|
3640 |
properties. |
|
3641 |
|
|
3642 |
All values will become strings except the empty string and |
|
3643 |
\"nil\", which will become nil. Also, values containing only |
|
3644 |
double quotes will be read as-is, which means that \"\" value |
|
3645 |
will become the empty string." |
|
3646 |
(let* ((prepare-value |
|
3647 |
(lambda (str) |
|
3648 |
(save-match-data |
|
3649 |
(cond ((member str '(nil "" "nil")) nil) |
|
3650 |
((string-match "^\"\\(\"+\\)?\"$" str) |
|
3651 |
(or (match-string 1 str) "")) |
|
3652 |
(t str))))) |
|
3653 |
(attributes |
|
3654 |
(let ((value (org-element-property attribute element))) |
|
3655 |
(when value |
|
3656 |
(let ((s (mapconcat 'identity value " ")) result) |
|
3657 |
(while (string-match |
|
3658 |
"\\(?:^\\|[ \t]+\\)\\(:[-a-zA-Z0-9_]+\\)\\([ \t]+\\|$\\)" |
|
3659 |
s) |
|
3660 |
(let ((value (substring s 0 (match-beginning 0)))) |
|
3661 |
(push (funcall prepare-value value) result)) |
|
3662 |
(push (intern (match-string 1 s)) result) |
|
3663 |
(setq s (substring s (match-end 0)))) |
|
3664 |
;; Ignore any string before first property with `cdr'. |
|
3665 |
(cdr (nreverse (cons (funcall prepare-value s) result)))))))) |
|
3666 |
(if property (plist-get attributes property) attributes))) |
|
3667 |
|
|
3668 |
(defun org-export-get-caption (element &optional shortp) |
|
3669 |
"Return caption from ELEMENT as a secondary string. |
|
3670 |
|
|
3671 |
When optional argument SHORTP is non-nil, return short caption, |
|
3672 |
as a secondary string, instead. |
|
3673 |
|
|
3674 |
Caption lines are separated by a white space." |
|
3675 |
(let ((full-caption (org-element-property :caption element)) caption) |
|
3676 |
(dolist (line full-caption (cdr caption)) |
|
3677 |
(let ((cap (funcall (if shortp 'cdr 'car) line))) |
|
3678 |
(when cap |
|
3679 |
(setq caption (nconc (list " ") (copy-sequence cap) caption))))))) |
|
3680 |
|
|
3681 |
|
|
3682 |
;;;; For Derived Back-ends |
|
3683 |
;; |
|
3684 |
;; `org-export-with-backend' is a function allowing to locally use |
|
3685 |
;; another back-end to transcode some object or element. In a derived |
|
3686 |
;; back-end, it may be used as a fall-back function once all specific |
|
3687 |
;; cases have been treated. |
|
3688 |
|
|
3689 |
(defun org-export-with-backend (backend data &optional contents info) |
|
3690 |
"Call a transcoder from BACKEND on DATA. |
|
3691 |
BACKEND is an export back-end, as returned by, e.g., |
|
3692 |
`org-export-create-backend', or a symbol referring to |
|
3693 |
a registered back-end. DATA is an Org element, object, secondary |
|
3694 |
string or string. CONTENTS, when non-nil, is the transcoded |
|
3695 |
contents of DATA element, as a string. INFO, when non-nil, is |
|
3696 |
the communication channel used for export, as a plist." |
|
3697 |
(when (symbolp backend) (setq backend (org-export-get-backend backend))) |
|
3698 |
(org-export-barf-if-invalid-backend backend) |
|
3699 |
(let ((type (org-element-type data))) |
|
3700 |
(when (memq type '(nil org-data)) (error "No foreign transcoder available")) |
|
3701 |
(let* ((all-transcoders (org-export-get-all-transcoders backend)) |
|
3702 |
(transcoder (cdr (assq type all-transcoders)))) |
|
3703 |
(unless (functionp transcoder) (error "No foreign transcoder available")) |
|
3704 |
(let ((new-info |
|
3705 |
(org-combine-plists |
|
3706 |
info (list |
|
3707 |
:back-end backend |
|
3708 |
:translate-alist all-transcoders |
|
3709 |
:exported-data (make-hash-table :test #'eq :size 401))))) |
|
3710 |
;; `:internal-references' are shared across back-ends. |
|
3711 |
(prog1 (if (eq type 'plain-text) |
|
3712 |
(funcall transcoder data new-info) |
|
3713 |
(funcall transcoder data contents new-info)) |
|
3714 |
(plist-put info :internal-references |
|
3715 |
(plist-get new-info :internal-references))))))) |
|
3716 |
|
|
3717 |
|
|
3718 |
;;;; For Export Snippets |
|
3719 |
;; |
|
3720 |
;; Every export snippet is transmitted to the back-end. Though, the |
|
3721 |
;; latter will only retain one type of export-snippet, ignoring |
|
3722 |
;; others, based on the former's target back-end. The function |
|
3723 |
;; `org-export-snippet-backend' returns that back-end for a given |
|
3724 |
;; export-snippet. |
|
3725 |
|
|
3726 |
(defun org-export-snippet-backend (export-snippet) |
|
3727 |
"Return EXPORT-SNIPPET targeted back-end as a symbol. |
|
3728 |
Translation, with `org-export-snippet-translation-alist', is |
|
3729 |
applied." |
|
3730 |
(let ((back-end (org-element-property :back-end export-snippet))) |
|
3731 |
(intern |
|
3732 |
(or (cdr (assoc back-end org-export-snippet-translation-alist)) |
|
3733 |
back-end)))) |
|
3734 |
|
|
3735 |
|
|
3736 |
;;;; For Footnotes |
|
3737 |
;; |
|
3738 |
;; `org-export-collect-footnote-definitions' is a tool to list |
|
3739 |
;; actually used footnotes definitions in the whole parse tree, or in |
|
3740 |
;; a headline, in order to add footnote listings throughout the |
|
3741 |
;; transcoded data. |
|
3742 |
;; |
|
3743 |
;; `org-export-footnote-first-reference-p' is a predicate used by some |
|
3744 |
;; back-ends, when they need to attach the footnote definition only to |
|
3745 |
;; the first occurrence of the corresponding label. |
|
3746 |
;; |
|
3747 |
;; `org-export-get-footnote-definition' and |
|
3748 |
;; `org-export-get-footnote-number' provide easier access to |
|
3749 |
;; additional information relative to a footnote reference. |
|
3750 |
|
|
3751 |
(defun org-export-get-footnote-definition (footnote-reference info) |
|
3752 |
"Return definition of FOOTNOTE-REFERENCE as parsed data. |
|
3753 |
INFO is the plist used as a communication channel. If no such |
|
3754 |
definition can be found, raise an error." |
|
3755 |
(let ((label (org-element-property :label footnote-reference))) |
|
3756 |
(if (not label) (org-element-contents footnote-reference) |
|
3757 |
(let ((cache (or (plist-get info :footnote-definition-cache) |
|
3758 |
(let ((hash (make-hash-table :test #'equal))) |
|
3759 |
(plist-put info :footnote-definition-cache hash) |
|
3760 |
hash)))) |
|
3761 |
(or |
|
3762 |
(gethash label cache) |
|
3763 |
(puthash label |
|
3764 |
(org-element-map (plist-get info :parse-tree) |
|
3765 |
'(footnote-definition footnote-reference) |
|
3766 |
(lambda (f) |
|
3767 |
(cond |
|
3768 |
;; Skip any footnote with a different label. |
|
3769 |
;; Also skip any standard footnote reference |
|
3770 |
;; with the same label since those cannot |
|
3771 |
;; contain a definition. |
|
3772 |
((not (equal (org-element-property :label f) label)) nil) |
|
3773 |
((eq (org-element-property :type f) 'standard) nil) |
|
3774 |
((org-element-contents f)) |
|
3775 |
;; Even if the contents are empty, we can not |
|
3776 |
;; return nil since that would eventually raise |
|
3777 |
;; the error. Instead, return the equivalent |
|
3778 |
;; empty string. |
|
3779 |
(t ""))) |
|
3780 |
info t) |
|
3781 |
cache) |
|
3782 |
(error "Definition not found for footnote %s" label)))))) |
|
3783 |
|
|
3784 |
(defun org-export--footnote-reference-map |
|
3785 |
(function data info &optional body-first) |
|
3786 |
"Apply FUNCTION on every footnote reference in DATA. |
|
3787 |
INFO is a plist containing export state. By default, as soon as |
|
3788 |
a new footnote reference is encountered, FUNCTION is called onto |
|
3789 |
its definition. However, if BODY-FIRST is non-nil, this step is |
|
3790 |
delayed until the end of the process." |
|
3791 |
(letrec ((definitions nil) |
|
3792 |
(seen-refs nil) |
|
3793 |
(search-ref |
|
3794 |
(lambda (data delayp) |
|
3795 |
;; Search footnote references through DATA, filling |
|
3796 |
;; SEEN-REFS along the way. When DELAYP is non-nil, |
|
3797 |
;; store footnote definitions so they can be entered |
|
3798 |
;; later. |
|
3799 |
(org-element-map data 'footnote-reference |
|
3800 |
(lambda (f) |
|
3801 |
(funcall function f) |
|
3802 |
(let ((--label (org-element-property :label f))) |
|
3803 |
(unless (and --label (member --label seen-refs)) |
|
3804 |
(when --label (push --label seen-refs)) |
|
3805 |
;; Search for subsequent references in footnote |
|
3806 |
;; definition so numbering follows reading |
|
3807 |
;; logic, unless DELAYP in non-nil. |
|
3808 |
(cond |
|
3809 |
(delayp |
|
3810 |
(push (org-export-get-footnote-definition f info) |
|
3811 |
definitions)) |
|
3812 |
;; Do not force entering inline definitions, |
|
3813 |
;; since `org-element-map' already traverses |
|
3814 |
;; them at the right time. |
|
3815 |
((eq (org-element-property :type f) 'inline)) |
|
3816 |
(t (funcall search-ref |
|
3817 |
(org-export-get-footnote-definition f info) |
|
3818 |
nil)))))) |
|
3819 |
info nil |
|
3820 |
;; Don't enter footnote definitions since it will |
|
3821 |
;; happen when their first reference is found. |
|
3822 |
;; Moreover, if DELAYP is non-nil, make sure we |
|
3823 |
;; postpone entering definitions of inline references. |
|
3824 |
(if delayp '(footnote-definition footnote-reference) |
|
3825 |
'footnote-definition))))) |
|
3826 |
(funcall search-ref data body-first) |
|
3827 |
(funcall search-ref (nreverse definitions) nil))) |
|
3828 |
|
|
3829 |
(defun org-export-collect-footnote-definitions (info &optional data body-first) |
|
3830 |
"Return an alist between footnote numbers, labels and definitions. |
|
3831 |
|
|
3832 |
INFO is the current export state, as a plist. |
|
3833 |
|
|
3834 |
Definitions are collected throughout the whole parse tree, or |
|
3835 |
DATA when non-nil. |
|
3836 |
|
|
3837 |
Sorting is done by order of references. As soon as a new |
|
3838 |
reference is encountered, other references are searched within |
|
3839 |
its definition. However, if BODY-FIRST is non-nil, this step is |
|
3840 |
delayed after the whole tree is checked. This alters results |
|
3841 |
when references are found in footnote definitions. |
|
3842 |
|
|
3843 |
Definitions either appear as Org data or as a secondary string |
|
3844 |
for inlined footnotes. Unreferenced definitions are ignored." |
|
3845 |
(let ((n 0) labels alist) |
|
3846 |
(org-export--footnote-reference-map |
|
3847 |
(lambda (f) |
|
3848 |
;; Collect footnote number, label and definition. |
|
3849 |
(let ((l (org-element-property :label f))) |
|
3850 |
(unless (and l (member l labels)) |
|
3851 |
(cl-incf n) |
|
3852 |
(push (list n l (org-export-get-footnote-definition f info)) alist)) |
|
3853 |
(when l (push l labels)))) |
|
3854 |
(or data (plist-get info :parse-tree)) info body-first) |
|
3855 |
(nreverse alist))) |
|
3856 |
|
|
3857 |
(defun org-export-footnote-first-reference-p |
|
3858 |
(footnote-reference info &optional data body-first) |
|
3859 |
"Non-nil when a footnote reference is the first one for its label. |
|
3860 |
|
|
3861 |
FOOTNOTE-REFERENCE is the footnote reference being considered. |
|
3862 |
INFO is a plist containing current export state. |
|
3863 |
|
|
3864 |
Search is done throughout the whole parse tree, or DATA when |
|
3865 |
non-nil. |
|
3866 |
|
|
3867 |
By default, as soon as a new footnote reference is encountered, |
|
3868 |
other references are searched within its definition. However, if |
|
3869 |
BODY-FIRST is non-nil, this step is delayed after the whole tree |
|
3870 |
is checked. This alters results when references are found in |
|
3871 |
footnote definitions." |
|
3872 |
(let ((label (org-element-property :label footnote-reference))) |
|
3873 |
;; Anonymous footnotes are always a first reference. |
|
3874 |
(or (not label) |
|
3875 |
(catch 'exit |
|
3876 |
(org-export--footnote-reference-map |
|
3877 |
(lambda (f) |
|
3878 |
(let ((l (org-element-property :label f))) |
|
3879 |
(when (and l label (string= label l)) |
|
3880 |
(throw 'exit (eq footnote-reference f))))) |
|
3881 |
(or data (plist-get info :parse-tree)) info body-first))))) |
|
3882 |
|
|
3883 |
(defun org-export-get-footnote-number (footnote info &optional data body-first) |
|
3884 |
"Return number associated to a footnote. |
|
3885 |
|
|
3886 |
FOOTNOTE is either a footnote reference or a footnote definition. |
|
3887 |
INFO is the plist containing export state. |
|
3888 |
|
|
3889 |
Number is unique throughout the whole parse tree, or DATA, when |
|
3890 |
non-nil. |
|
3891 |
|
|
3892 |
By default, as soon as a new footnote reference is encountered, |
|
3893 |
counting process moves into its definition. However, if |
|
3894 |
BODY-FIRST is non-nil, this step is delayed until the end of the |
|
3895 |
process, leading to a different order when footnotes are nested." |
|
3896 |
(let ((count 0) |
|
3897 |
(seen) |
|
3898 |
(label (org-element-property :label footnote))) |
|
3899 |
(catch 'exit |
|
3900 |
(org-export--footnote-reference-map |
|
3901 |
(lambda (f) |
|
3902 |
(let ((l (org-element-property :label f))) |
|
3903 |
(cond |
|
3904 |
;; Anonymous footnote match: return number. |
|
3905 |
((and (not l) (not label) (eq footnote f)) (throw 'exit (1+ count))) |
|
3906 |
;; Labels match: return number. |
|
3907 |
((and label l (string= label l)) (throw 'exit (1+ count))) |
|
3908 |
;; Otherwise store label and increase counter if label |
|
3909 |
;; wasn't encountered yet. |
|
3910 |
((not l) (cl-incf count)) |
|
3911 |
((not (member l seen)) (push l seen) (cl-incf count))))) |
|
3912 |
(or data (plist-get info :parse-tree)) info body-first)))) |
|
3913 |
|
|
3914 |
|
|
3915 |
;;;; For Headlines |
|
3916 |
;; |
|
3917 |
;; `org-export-get-relative-level' is a shortcut to get headline |
|
3918 |
;; level, relatively to the lower headline level in the parsed tree. |
|
3919 |
;; |
|
3920 |
;; `org-export-get-headline-number' returns the section number of an |
|
3921 |
;; headline, while `org-export-number-to-roman' allows it to be |
|
3922 |
;; converted to roman numbers. With an optional argument, |
|
3923 |
;; `org-export-get-headline-number' returns a number to unnumbered |
|
3924 |
;; headlines (used for internal id). |
|
3925 |
;; |
|
3926 |
;; `org-export-low-level-p', `org-export-first-sibling-p' and |
|
3927 |
;; `org-export-last-sibling-p' are three useful predicates when it |
|
3928 |
;; comes to fulfill the `:headline-levels' property. |
|
3929 |
;; |
|
3930 |
;; `org-export-get-tags', `org-export-get-category' and |
|
3931 |
;; `org-export-get-node-property' extract useful information from an |
|
3932 |
;; headline or a parent headline. They all handle inheritance. |
|
3933 |
;; |
|
3934 |
;; `org-export-get-alt-title' tries to retrieve an alternative title, |
|
3935 |
;; as a secondary string, suitable for table of contents. It falls |
|
3936 |
;; back onto default title. |
|
3937 |
|
|
3938 |
(defun org-export-get-relative-level (headline info) |
|
3939 |
"Return HEADLINE relative level within current parsed tree. |
|
3940 |
INFO is a plist holding contextual information." |
|
3941 |
(+ (org-element-property :level headline) |
|
3942 |
(or (plist-get info :headline-offset) 0))) |
|
3943 |
|
|
3944 |
(defun org-export-low-level-p (headline info) |
|
3945 |
"Non-nil when HEADLINE is considered as low level. |
|
3946 |
|
|
3947 |
INFO is a plist used as a communication channel. |
|
3948 |
|
|
3949 |
A low level headlines has a relative level greater than |
|
3950 |
`:headline-levels' property value. |
|
3951 |
|
|
3952 |
Return value is the difference between HEADLINE relative level |
|
3953 |
and the last level being considered as high enough, or nil." |
|
3954 |
(let ((limit (plist-get info :headline-levels))) |
|
3955 |
(when (wholenump limit) |
|
3956 |
(let ((level (org-export-get-relative-level headline info))) |
|
3957 |
(and (> level limit) (- level limit)))))) |
|
3958 |
|
|
3959 |
(defun org-export-get-headline-number (headline info) |
|
3960 |
"Return numbered HEADLINE numbering as a list of numbers. |
|
3961 |
INFO is a plist holding contextual information." |
|
3962 |
(and (org-export-numbered-headline-p headline info) |
|
3963 |
(cdr (assq headline (plist-get info :headline-numbering))))) |
|
3964 |
|
|
3965 |
(defun org-export-numbered-headline-p (headline info) |
|
3966 |
"Return a non-nil value if HEADLINE element should be numbered. |
|
3967 |
INFO is a plist used as a communication channel." |
|
3968 |
(unless (org-not-nil (org-export-get-node-property :UNNUMBERED headline t)) |
|
3969 |
(let ((sec-num (plist-get info :section-numbers)) |
|
3970 |
(level (org-export-get-relative-level headline info))) |
|
3971 |
(if (wholenump sec-num) (<= level sec-num) sec-num)))) |
|
3972 |
|
|
3973 |
(defun org-export-number-to-roman (n) |
|
3974 |
"Convert integer N into a roman numeral." |
|
3975 |
(let ((roman '((1000 . "M") (900 . "CM") (500 . "D") (400 . "CD") |
|
3976 |
( 100 . "C") ( 90 . "XC") ( 50 . "L") ( 40 . "XL") |
|
3977 |
( 10 . "X") ( 9 . "IX") ( 5 . "V") ( 4 . "IV") |
|
3978 |
( 1 . "I"))) |
|
3979 |
(res "")) |
|
3980 |
(if (<= n 0) |
|
3981 |
(number-to-string n) |
|
3982 |
(while roman |
|
3983 |
(if (>= n (caar roman)) |
|
3984 |
(setq n (- n (caar roman)) |
|
3985 |
res (concat res (cdar roman))) |
|
3986 |
(pop roman))) |
|
3987 |
res))) |
|
3988 |
|
|
3989 |
(defun org-export-get-tags (element info &optional tags inherited) |
|
3990 |
"Return list of tags associated to ELEMENT. |
|
3991 |
|
|
3992 |
ELEMENT has either an `headline' or an `inlinetask' type. INFO |
|
3993 |
is a plist used as a communication channel. |
|
3994 |
|
|
3995 |
When non-nil, optional argument TAGS should be a list of strings. |
|
3996 |
Any tag belonging to this list will also be removed. |
|
3997 |
|
|
3998 |
When optional argument INHERITED is non-nil, tags can also be |
|
3999 |
inherited from parent headlines and FILETAGS keywords." |
|
4000 |
(cl-remove-if |
|
4001 |
(lambda (tag) (member tag tags)) |
|
4002 |
(if (not inherited) (org-element-property :tags element) |
|
4003 |
;; Build complete list of inherited tags. |
|
4004 |
(let ((current-tag-list (org-element-property :tags element))) |
|
4005 |
(dolist (parent (org-element-lineage element)) |
|
4006 |
(dolist (tag (org-element-property :tags parent)) |
|
4007 |
(when (and (memq (org-element-type parent) '(headline inlinetask)) |
|
4008 |
(not (member tag current-tag-list))) |
|
4009 |
(push tag current-tag-list)))) |
|
4010 |
;; Add FILETAGS keywords and return results. |
|
4011 |
(org-uniquify (append (plist-get info :filetags) current-tag-list)))))) |
|
4012 |
|
|
4013 |
(defun org-export-get-node-property (property blob &optional inherited) |
|
4014 |
"Return node PROPERTY value for BLOB. |
|
4015 |
|
|
4016 |
PROPERTY is an upcase symbol (i.e. `:COOKIE_DATA'). BLOB is an |
|
4017 |
element or object. |
|
4018 |
|
|
4019 |
If optional argument INHERITED is non-nil, the value can be |
|
4020 |
inherited from a parent headline. |
|
4021 |
|
|
4022 |
Return value is a string or nil." |
|
4023 |
(let ((headline (if (eq (org-element-type blob) 'headline) blob |
|
4024 |
(org-export-get-parent-headline blob)))) |
|
4025 |
(if (not inherited) (org-element-property property blob) |
|
4026 |
(let ((parent headline)) |
|
4027 |
(catch 'found |
|
4028 |
(while parent |
|
4029 |
(when (plist-member (nth 1 parent) property) |
|
4030 |
(throw 'found (org-element-property property parent))) |
|
4031 |
(setq parent (org-element-property :parent parent)))))))) |
|
4032 |
|
|
4033 |
(defun org-export-get-category (blob info) |
|
4034 |
"Return category for element or object BLOB. |
|
4035 |
|
|
4036 |
INFO is a plist used as a communication channel. |
|
4037 |
|
|
4038 |
CATEGORY is automatically inherited from a parent headline, from |
|
4039 |
#+CATEGORY: keyword or created out of original file name. If all |
|
4040 |
fail, the fall-back value is \"???\"." |
|
4041 |
(or (org-export-get-node-property :CATEGORY blob t) |
|
4042 |
(org-element-map (plist-get info :parse-tree) 'keyword |
|
4043 |
(lambda (kwd) |
|
4044 |
(when (equal (org-element-property :key kwd) "CATEGORY") |
|
4045 |
(org-element-property :value kwd))) |
|
4046 |
info 'first-match) |
|
4047 |
(let ((file (plist-get info :input-file))) |
|
4048 |
(and file (file-name-sans-extension (file-name-nondirectory file)))) |
|
4049 |
"???")) |
|
4050 |
|
|
4051 |
(defun org-export-get-alt-title (headline _) |
|
4052 |
"Return alternative title for HEADLINE, as a secondary string. |
|
4053 |
If no optional title is defined, fall-back to the regular title." |
|
4054 |
(let ((alt (org-element-property :ALT_TITLE headline))) |
|
4055 |
(if alt (org-element-parse-secondary-string |
|
4056 |
alt (org-element-restriction 'headline) headline) |
|
4057 |
(org-element-property :title headline)))) |
|
4058 |
|
|
4059 |
(defun org-export-first-sibling-p (blob info) |
|
4060 |
"Non-nil when BLOB is the first sibling in its parent. |
|
4061 |
BLOB is an element or an object. If BLOB is a headline, non-nil |
|
4062 |
means it is the first sibling in the sub-tree. INFO is a plist |
|
4063 |
used as a communication channel." |
|
4064 |
(memq (org-element-type (org-export-get-previous-element blob info)) |
|
4065 |
'(nil section))) |
|
4066 |
|
|
4067 |
(defun org-export-last-sibling-p (datum info) |
|
4068 |
"Non-nil when DATUM is the last sibling in its parent. |
|
4069 |
DATUM is an element or an object. INFO is a plist used as |
|
4070 |
a communication channel." |
|
4071 |
(let ((next (org-export-get-next-element datum info))) |
|
4072 |
(or (not next) |
|
4073 |
(and (eq 'headline (org-element-type datum)) |
|
4074 |
(> (org-element-property :level datum) |
|
4075 |
(org-element-property :level next)))))) |
|
4076 |
|
|
4077 |
|
|
4078 |
;;;; For Keywords |
|
4079 |
;; |
|
4080 |
;; `org-export-get-date' returns a date appropriate for the document |
|
4081 |
;; to about to be exported. In particular, it takes care of |
|
4082 |
;; `org-export-date-timestamp-format'. |
|
4083 |
|
|
4084 |
(defun org-export-get-date (info &optional fmt) |
|
4085 |
"Return date value for the current document. |
|
4086 |
|
|
4087 |
INFO is a plist used as a communication channel. FMT, when |
|
4088 |
non-nil, is a time format string that will be applied on the date |
|
4089 |
if it consists in a single timestamp object. It defaults to |
|
4090 |
`org-export-date-timestamp-format' when nil. |
|
4091 |
|
|
4092 |
A proper date can be a secondary string, a string or nil. It is |
|
4093 |
meant to be translated with `org-export-data' or alike." |
|
4094 |
(let ((date (plist-get info :date)) |
|
4095 |
(fmt (or fmt org-export-date-timestamp-format))) |
|
4096 |
(cond ((not date) nil) |
|
4097 |
((and fmt |
|
4098 |
(not (cdr date)) |
|
4099 |
(eq (org-element-type (car date)) 'timestamp)) |
|
4100 |
(org-timestamp-format (car date) fmt)) |
|
4101 |
(t date)))) |
|
4102 |
|
|
4103 |
|
|
4104 |
;;;; For Links |
|
4105 |
;; |
|
4106 |
;; `org-export-custom-protocol-maybe' handles custom protocol defined |
|
4107 |
;; in `org-link-parameters'. |
|
4108 |
;; |
|
4109 |
;; `org-export-get-coderef-format' returns an appropriate format |
|
4110 |
;; string for coderefs. |
|
4111 |
;; |
|
4112 |
;; `org-export-inline-image-p' returns a non-nil value when the link |
|
4113 |
;; provided should be considered as an inline image. |
|
4114 |
;; |
|
4115 |
;; `org-export-resolve-fuzzy-link' searches destination of fuzzy links |
|
4116 |
;; (i.e. links with "fuzzy" as type) within the parsed tree, and |
|
4117 |
;; returns an appropriate unique identifier. |
|
4118 |
;; |
|
4119 |
;; `org-export-resolve-id-link' returns the first headline with |
|
4120 |
;; specified id or custom-id in parse tree, the path to the external |
|
4121 |
;; file with the id. |
|
4122 |
;; |
|
4123 |
;; `org-export-resolve-coderef' associates a reference to a line |
|
4124 |
;; number in the element it belongs, or returns the reference itself |
|
4125 |
;; when the element isn't numbered. |
|
4126 |
;; |
|
4127 |
;; `org-export-file-uri' expands a filename as stored in :path value |
|
4128 |
;; of a "file" link into a file URI. |
|
4129 |
;; |
|
4130 |
;; Broken links raise a `org-link-broken' error, which is caught by |
|
4131 |
;; `org-export-data' for further processing, depending on |
|
4132 |
;; `org-export-with-broken-links' value. |
|
4133 |
|
|
4134 |
(org-define-error 'org-link-broken "Unable to resolve link; aborting") |
|
4135 |
|
|
4136 |
(defun org-export-custom-protocol-maybe (link desc backend) |
|
4137 |
"Try exporting LINK with a dedicated function. |
|
4138 |
|
|
4139 |
DESC is its description, as a string, or nil. BACKEND is the |
|
4140 |
back-end used for export, as a symbol. |
|
4141 |
|
|
4142 |
Return output as a string, or nil if no protocol handles LINK. |
|
4143 |
|
|
4144 |
A custom protocol has precedence over regular back-end export. |
|
4145 |
The function ignores links with an implicit type (e.g., |
|
4146 |
\"custom-id\")." |
|
4147 |
(let ((type (org-element-property :type link))) |
|
4148 |
(unless (or (member type '("coderef" "custom-id" "fuzzy" "radio")) |
|
4149 |
(not backend)) |
|
4150 |
(let ((protocol (org-link-get-parameter type :export))) |
|
4151 |
(and (functionp protocol) |
|
4152 |
(funcall protocol |
|
4153 |
(org-link-unescape (org-element-property :path link)) |
|
4154 |
desc |
|
4155 |
backend)))))) |
|
4156 |
|
|
4157 |
(defun org-export-get-coderef-format (path desc) |
|
4158 |
"Return format string for code reference link. |
|
4159 |
PATH is the link path. DESC is its description." |
|
4160 |
(save-match-data |
|
4161 |
(cond ((not desc) "%s") |
|
4162 |
((string-match (regexp-quote (concat "(" path ")")) desc) |
|
4163 |
(replace-match "%s" t t desc)) |
|
4164 |
(t desc)))) |
|
4165 |
|
|
4166 |
(defun org-export-inline-image-p (link &optional rules) |
|
4167 |
"Non-nil if LINK object points to an inline image. |
|
4168 |
|
|
4169 |
Optional argument is a set of RULES defining inline images. It |
|
4170 |
is an alist where associations have the following shape: |
|
4171 |
|
|
4172 |
(TYPE . REGEXP) |
|
4173 |
|
|
4174 |
Applying a rule means apply REGEXP against LINK's path when its |
|
4175 |
type is TYPE. The function will return a non-nil value if any of |
|
4176 |
the provided rules is non-nil. The default rule is |
|
4177 |
`org-export-default-inline-image-rule'. |
|
4178 |
|
|
4179 |
This only applies to links without a description." |
|
4180 |
(and (not (org-element-contents link)) |
|
4181 |
(let ((case-fold-search t)) |
|
4182 |
(cl-some (lambda (rule) |
|
4183 |
(and (string= (org-element-property :type link) (car rule)) |
|
4184 |
(string-match-p (cdr rule) |
|
4185 |
(org-element-property :path link)))) |
|
4186 |
(or rules org-export-default-inline-image-rule))))) |
|
4187 |
|
|
4188 |
(defun org-export-insert-image-links (data info &optional rules) |
|
4189 |
"Insert image links in DATA. |
|
4190 |
|
|
4191 |
Org syntax does not support nested links. Nevertheless, some |
|
4192 |
export back-ends support images as descriptions of links. Since |
|
4193 |
images are really links to image files, we need to make an |
|
4194 |
exception about links nesting. |
|
4195 |
|
|
4196 |
This function recognizes links whose contents are really images |
|
4197 |
and turn them into proper nested links. It is meant to be used |
|
4198 |
as a parse tree filter in back-ends supporting such constructs. |
|
4199 |
|
|
4200 |
DATA is a parse tree. INFO is the current state of the export |
|
4201 |
process, as a plist. |
|
4202 |
|
|
4203 |
A description is a valid images if it matches any rule in RULES, |
|
4204 |
if non-nil, or `org-export-default-inline-image-rule' otherwise. |
|
4205 |
See `org-export-inline-image-p' for more information about the |
|
4206 |
structure of RULES. |
|
4207 |
|
|
4208 |
Return modified DATA." |
|
4209 |
(let ((link-re (format "\\`\\(?:%s\\|%s\\)\\'" |
|
4210 |
org-plain-link-re |
|
4211 |
org-angle-link-re)) |
|
4212 |
(case-fold-search t)) |
|
4213 |
(org-element-map data 'link |
|
4214 |
(lambda (l) |
|
4215 |
(let ((contents (org-element-interpret-data (org-element-contents l)))) |
|
4216 |
(when (and (org-string-nw-p contents) |
|
4217 |
(string-match link-re contents)) |
|
4218 |
(let ((type (match-string 1 contents)) |
|
4219 |
(path (match-string 2 contents))) |
|
4220 |
(when (cl-some (lambda (rule) |
|
4221 |
(and (string= type (car rule)) |
|
4222 |
(string-match-p (cdr rule) path))) |
|
4223 |
(or rules org-export-default-inline-image-rule)) |
|
4224 |
;; Replace contents with image link. |
|
4225 |
(org-element-adopt-elements |
|
4226 |
(org-element-set-contents l nil) |
|
4227 |
(with-temp-buffer |
|
4228 |
(save-excursion (insert contents)) |
|
4229 |
(org-element-link-parser)))))))) |
|
4230 |
info nil nil t)) |
|
4231 |
data) |
|
4232 |
|
|
4233 |
(defun org-export-resolve-coderef (ref info) |
|
4234 |
"Resolve a code reference REF. |
|
4235 |
|
|
4236 |
INFO is a plist used as a communication channel. |
|
4237 |
|
|
4238 |
Return associated line number in source code, or REF itself, |
|
4239 |
depending on src-block or example element's switches. Throw an |
|
4240 |
error if no block contains REF." |
|
4241 |
(or (org-element-map (plist-get info :parse-tree) '(example-block src-block) |
|
4242 |
(lambda (el) |
|
4243 |
(with-temp-buffer |
|
4244 |
(insert (org-trim (org-element-property :value el))) |
|
4245 |
(let* ((label-fmt (or (org-element-property :label-fmt el) |
|
4246 |
org-coderef-label-format)) |
|
4247 |
(ref-re (org-src-coderef-regexp label-fmt ref))) |
|
4248 |
;; Element containing REF is found. Resolve it to |
|
4249 |
;; either a label or a line number, as needed. |
|
4250 |
(when (re-search-backward ref-re nil t) |
|
4251 |
(if (org-element-property :use-labels el) ref |
|
4252 |
(+ (or (org-export-get-loc el info) 0) |
|
4253 |
(line-number-at-pos))))))) |
|
4254 |
info 'first-match) |
|
4255 |
(signal 'org-link-broken (list ref)))) |
|
4256 |
|
|
4257 |
(defun org-export-search-cells (datum) |
|
4258 |
"List search cells for element or object DATUM. |
|
4259 |
|
|
4260 |
A search cell follows the pattern (TYPE . SEARCH) where |
|
4261 |
|
|
4262 |
TYPE is a symbol among `headline', `custom-id', `target' and |
|
4263 |
`other'. |
|
4264 |
|
|
4265 |
SEARCH is the string a link is expected to match. More |
|
4266 |
accurately, it is |
|
4267 |
|
|
4268 |
- headline's title, as a list of strings, if TYPE is |
|
4269 |
`headline'. |
|
4270 |
|
|
4271 |
- CUSTOM_ID value, as a string, if TYPE is `custom-id'. |
|
4272 |
|
|
4273 |
- target's or radio-target's name as a list of strings if |
|
4274 |
TYPE is `target'. |
|
4275 |
|
|
4276 |
- NAME affiliated keyword if TYPE is `other'. |
|
4277 |
|
|
4278 |
A search cell is the internal representation of a fuzzy link. It |
|
4279 |
ignores white spaces and statistics cookies, if applicable." |
|
4280 |
(pcase (org-element-type datum) |
|
4281 |
(`headline |
|
4282 |
(let ((title (split-string |
|
4283 |
(replace-regexp-in-string |
|
4284 |
"\\[[0-9]*\\(?:%\\|/[0-9]*\\)\\]" "" |
|
4285 |
(org-element-property :raw-value datum))))) |
|
4286 |
(delq nil |
|
4287 |
(list |
|
4288 |
(cons 'headline title) |
|
4289 |
(cons 'other title) |
|
4290 |
(let ((custom-id (org-element-property :custom-id datum))) |
|
4291 |
(and custom-id (cons 'custom-id custom-id))))))) |
|
4292 |
(`target |
|
4293 |
(list (cons 'target (split-string (org-element-property :value datum))))) |
|
4294 |
((and (let name (org-element-property :name datum)) |
|
4295 |
(guard name)) |
|
4296 |
(list (cons 'other (split-string name)))) |
|
4297 |
(_ nil))) |
|
4298 |
|
|
4299 |
(defun org-export-string-to-search-cell (s) |
|
4300 |
"Return search cells associated to string S. |
|
4301 |
S is either the path of a fuzzy link or a search option, i.e., it |
|
4302 |
tries to match either a headline (through custom ID or title), |
|
4303 |
a target or a named element." |
|
4304 |
(pcase (string-to-char s) |
|
4305 |
(?* (list (cons 'headline (split-string (substring s 1))))) |
|
4306 |
(?# (list (cons 'custom-id (substring s 1)))) |
|
4307 |
((let search (split-string s)) |
|
4308 |
(list (cons 'target search) (cons 'other search))))) |
|
4309 |
|
|
4310 |
(defun org-export-match-search-cell-p (datum cells) |
|
4311 |
"Non-nil when DATUM matches search cells CELLS. |
|
4312 |
DATUM is an element or object. CELLS is a list of search cells, |
|
4313 |
as returned by `org-export-search-cells'." |
|
4314 |
(let ((targets (org-export-search-cells datum))) |
|
4315 |
(and targets (cl-some (lambda (cell) (member cell targets)) cells)))) |
|
4316 |
|
|
4317 |
(defun org-export-resolve-fuzzy-link (link info) |
|
4318 |
"Return LINK destination. |
|
4319 |
|
|
4320 |
INFO is a plist holding contextual information. |
|
4321 |
|
|
4322 |
Return value can be an object or an element: |
|
4323 |
|
|
4324 |
- If LINK path matches a target object (i.e. <<path>>) return it. |
|
4325 |
|
|
4326 |
- If LINK path exactly matches the name affiliated keyword |
|
4327 |
(i.e. #+NAME: path) of an element, return that element. |
|
4328 |
|
|
4329 |
- If LINK path exactly matches any headline name, return that |
|
4330 |
element. |
|
4331 |
|
|
4332 |
- Otherwise, throw an error. |
|
4333 |
|
|
4334 |
Assume LINK type is \"fuzzy\". White spaces are not |
|
4335 |
significant." |
|
4336 |
(let* ((search-cells (org-export-string-to-search-cell |
|
4337 |
(org-link-unescape (org-element-property :path link)))) |
|
4338 |
(link-cache (or (plist-get info :resolve-fuzzy-link-cache) |
|
4339 |
(let ((table (make-hash-table :test #'eq))) |
|
4340 |
(plist-put info :resolve-fuzzy-link-cache table) |
|
4341 |
table))) |
|
4342 |
(cached (gethash search-cells link-cache 'not-found))) |
|
4343 |
(if (not (eq cached 'not-found)) cached |
|
4344 |
(let ((matches |
|
4345 |
(org-element-map (plist-get info :parse-tree) |
|
4346 |
(cons 'target org-element-all-elements) |
|
4347 |
(lambda (datum) |
|
4348 |
(and (org-export-match-search-cell-p datum search-cells) |
|
4349 |
datum))))) |
|
4350 |
(unless matches |
|
4351 |
(signal 'org-link-broken (list (org-element-property :path link)))) |
|
4352 |
(puthash |
|
4353 |
search-cells |
|
4354 |
;; There can be multiple matches for un-typed searches, i.e., |
|
4355 |
;; for searches not starting with # or *. In this case, |
|
4356 |
;; prioritize targets and names over headline titles. |
|
4357 |
;; Matching both a name and a target is not valid, and |
|
4358 |
;; therefore undefined. |
|
4359 |
(or (cl-some (lambda (datum) |
|
4360 |
(and (not (eq (org-element-type datum) 'headline)) |
|
4361 |
datum)) |
|
4362 |
matches) |
|
4363 |
(car matches)) |
|
4364 |
link-cache))))) |
|
4365 |
|
|
4366 |
(defun org-export-resolve-id-link (link info) |
|
4367 |
"Return headline referenced as LINK destination. |
|
4368 |
|
|
4369 |
INFO is a plist used as a communication channel. |
|
4370 |
|
|
4371 |
Return value can be the headline element matched in current parse |
|
4372 |
tree or a file name. Assume LINK type is either \"id\" or |
|
4373 |
\"custom-id\". Throw an error if no match is found." |
|
4374 |
(let ((id (org-element-property :path link))) |
|
4375 |
;; First check if id is within the current parse tree. |
|
4376 |
(or (org-element-map (plist-get info :parse-tree) 'headline |
|
4377 |
(lambda (headline) |
|
4378 |
(when (or (equal (org-element-property :ID headline) id) |
|
4379 |
(equal (org-element-property :CUSTOM_ID headline) id)) |
|
4380 |
headline)) |
|
4381 |
info 'first-match) |
|
4382 |
;; Otherwise, look for external files. |
|
4383 |
(cdr (assoc id (plist-get info :id-alist))) |
|
4384 |
(signal 'org-link-broken (list id))))) |
|
4385 |
|
|
4386 |
(defun org-export-resolve-radio-link (link info) |
|
4387 |
"Return radio-target object referenced as LINK destination. |
|
4388 |
|
|
4389 |
INFO is a plist used as a communication channel. |
|
4390 |
|
|
4391 |
Return value can be a radio-target object or nil. Assume LINK |
|
4392 |
has type \"radio\"." |
|
4393 |
(let ((path (replace-regexp-in-string |
|
4394 |
"[ \r\t\n]+" " " (org-element-property :path link)))) |
|
4395 |
(org-element-map (plist-get info :parse-tree) 'radio-target |
|
4396 |
(lambda (radio) |
|
4397 |
(and (eq (compare-strings |
|
4398 |
(replace-regexp-in-string |
|
4399 |
"[ \r\t\n]+" " " (org-element-property :value radio)) |
|
4400 |
nil nil path nil nil t) |
|
4401 |
t) |
|
4402 |
radio)) |
|
4403 |
info 'first-match))) |
|
4404 |
|
|
4405 |
(defun org-export-file-uri (filename) |
|
4406 |
"Return file URI associated to FILENAME." |
|
4407 |
(cond ((string-prefix-p "//" filename) (concat "file:" filename)) |
|
4408 |
((not (file-name-absolute-p filename)) filename) |
|
4409 |
((org-file-remote-p filename) (concat "file:/" filename)) |
|
4410 |
(t |
|
4411 |
(let ((fullname (expand-file-name filename))) |
|
4412 |
(concat (if (string-prefix-p "/" fullname) "file://" "file:///") |
|
4413 |
fullname))))) |
|
4414 |
|
|
4415 |
;;;; For References |
|
4416 |
;; |
|
4417 |
;; `org-export-get-reference' associate a unique reference for any |
|
4418 |
;; object or element. It uses `org-export-new-reference' and |
|
4419 |
;; `org-export-format-reference' to, respectively, generate new |
|
4420 |
;; internal references and turn them into a string suitable for |
|
4421 |
;; output. |
|
4422 |
;; |
|
4423 |
;; `org-export-get-ordinal' associates a sequence number to any object |
|
4424 |
;; or element. |
|
4425 |
|
|
4426 |
(defun org-export-new-reference (references) |
|
4427 |
"Return a unique reference, among REFERENCES. |
|
4428 |
REFERENCES is an alist whose values are in-use references, as |
|
4429 |
numbers. Returns a number, which is the internal representation |
|
4430 |
of a reference. See also `org-export-format-reference'." |
|
4431 |
;; Generate random 7 digits hexadecimal numbers. Collisions |
|
4432 |
;; increase exponentially with the numbers of references. However, |
|
4433 |
;; the odds for encountering at least one collision with 1000 active |
|
4434 |
;; references in the same document are roughly 0.2%, so this |
|
4435 |
;; shouldn't be the bottleneck. |
|
4436 |
(let ((new (random #x10000000))) |
|
4437 |
(while (rassq new references) (setq new (random #x10000000))) |
|
4438 |
new)) |
|
4439 |
|
|
4440 |
(defun org-export-format-reference (reference) |
|
4441 |
"Format REFERENCE into a string. |
|
4442 |
REFERENCE is a number representing a reference, as returned by |
|
4443 |
`org-export-new-reference', which see." |
|
4444 |
(format "org%07x" reference)) |
|
4445 |
|
|
4446 |
(defun org-export-get-reference (datum info) |
|
4447 |
"Return a unique reference for DATUM, as a string. |
|
4448 |
|
|
4449 |
DATUM is either an element or an object. INFO is the current |
|
4450 |
export state, as a plist. |
|
4451 |
|
|
4452 |
This function checks `:crossrefs' property in INFO for search |
|
4453 |
cells matching DATUM before creating a new reference. Returned |
|
4454 |
reference consists of alphanumeric characters only." |
|
4455 |
(let ((cache (plist-get info :internal-references))) |
|
4456 |
(or (car (rassq datum cache)) |
|
4457 |
(let* ((crossrefs (plist-get info :crossrefs)) |
|
4458 |
(cells (org-export-search-cells datum)) |
|
4459 |
;; Preserve any pre-existing association between |
|
4460 |
;; a search cell and a reference, i.e., when some |
|
4461 |
;; previously published document referenced a location |
|
4462 |
;; within current file (see |
|
4463 |
;; `org-publish-resolve-external-link'). |
|
4464 |
;; |
|
4465 |
;; However, there is no guarantee that search cells are |
|
4466 |
;; unique, e.g., there might be duplicate custom ID or |
|
4467 |
;; two headings with the same title in the file. |
|
4468 |
;; |
|
4469 |
;; As a consequence, before re-using any reference to |
|
4470 |
;; an element or object, we check that it doesn't refer |
|
4471 |
;; to a previous element or object. |
|
4472 |
(new (or (cl-some |
|
4473 |
(lambda (cell) |
|
4474 |
(let ((stored (cdr (assoc cell crossrefs)))) |
|
4475 |
(when stored |
|
4476 |
(let ((old (org-export-format-reference stored))) |
|
4477 |
(and (not (assoc old cache)) stored))))) |
|
4478 |
cells) |
|
4479 |
(org-export-new-reference cache))) |
|
4480 |
(reference-string (org-export-format-reference new))) |
|
4481 |
;; Cache contains both data already associated to |
|
4482 |
;; a reference and in-use internal references, so as to make |
|
4483 |
;; unique references. |
|
4484 |
(dolist (cell cells) (push (cons cell new) cache)) |
|
4485 |
;; Retain a direct association between reference string and |
|
4486 |
;; DATUM since (1) not every object or element can be given |
|
4487 |
;; a search cell (2) it permits quick lookup. |
|
4488 |
(push (cons reference-string datum) cache) |
|
4489 |
(plist-put info :internal-references cache) |
|
4490 |
reference-string)))) |
|
4491 |
|
|
4492 |
(defun org-export-get-ordinal (element info &optional types predicate) |
|
4493 |
"Return ordinal number of an element or object. |
|
4494 |
|
|
4495 |
ELEMENT is the element or object considered. INFO is the plist |
|
4496 |
used as a communication channel. |
|
4497 |
|
|
4498 |
Optional argument TYPES, when non-nil, is a list of element or |
|
4499 |
object types, as symbols, that should also be counted in. |
|
4500 |
Otherwise, only provided element's type is considered. |
|
4501 |
|
|
4502 |
Optional argument PREDICATE is a function returning a non-nil |
|
4503 |
value if the current element or object should be counted in. It |
|
4504 |
accepts two arguments: the element or object being considered and |
|
4505 |
the plist used as a communication channel. This allows counting |
|
4506 |
only a certain type of object (i.e. inline images). |
|
4507 |
|
|
4508 |
Return value is a list of numbers if ELEMENT is a headline or an |
|
4509 |
item. It is nil for keywords. It represents the footnote number |
|
4510 |
for footnote definitions and footnote references. If ELEMENT is |
|
4511 |
a target, return the same value as if ELEMENT was the closest |
|
4512 |
table, item or headline containing the target. In any other |
|
4513 |
case, return the sequence number of ELEMENT among elements or |
|
4514 |
objects of the same type." |
|
4515 |
;; Ordinal of a target object refer to the ordinal of the closest |
|
4516 |
;; table, item, or headline containing the object. |
|
4517 |
(when (eq (org-element-type element) 'target) |
|
4518 |
(setq element |
|
4519 |
(org-element-lineage |
|
4520 |
element |
|
4521 |
'(footnote-definition footnote-reference headline item table)))) |
|
4522 |
(cl-case (org-element-type element) |
|
4523 |
;; Special case 1: A headline returns its number as a list. |
|
4524 |
(headline (org-export-get-headline-number element info)) |
|
4525 |
;; Special case 2: An item returns its number as a list. |
|
4526 |
(item (let ((struct (org-element-property :structure element))) |
|
4527 |
(org-list-get-item-number |
|
4528 |
(org-element-property :begin element) |
|
4529 |
struct |
|
4530 |
(org-list-prevs-alist struct) |
|
4531 |
(org-list-parents-alist struct)))) |
|
4532 |
((footnote-definition footnote-reference) |
|
4533 |
(org-export-get-footnote-number element info)) |
|
4534 |
(otherwise |
|
4535 |
(let ((counter 0)) |
|
4536 |
;; Increment counter until ELEMENT is found again. |
|
4537 |
(org-element-map (plist-get info :parse-tree) |
|
4538 |
(or types (org-element-type element)) |
|
4539 |
(lambda (el) |
|
4540 |
(cond |
|
4541 |
((eq element el) (1+ counter)) |
|
4542 |
((not predicate) (cl-incf counter) nil) |
|
4543 |
((funcall predicate el info) (cl-incf counter) nil))) |
|
4544 |
info 'first-match))))) |
|
4545 |
|
|
4546 |
|
|
4547 |
;;;; For Src-Blocks |
|
4548 |
;; |
|
4549 |
;; `org-export-get-loc' counts number of code lines accumulated in |
|
4550 |
;; src-block or example-block elements with a "+n" switch until |
|
4551 |
;; a given element, excluded. Note: "-n" switches reset that count. |
|
4552 |
;; |
|
4553 |
;; `org-export-unravel-code' extracts source code (along with a code |
|
4554 |
;; references alist) from an `element-block' or `src-block' type |
|
4555 |
;; element. |
|
4556 |
;; |
|
4557 |
;; `org-export-format-code' applies a formatting function to each line |
|
4558 |
;; of code, providing relative line number and code reference when |
|
4559 |
;; appropriate. Since it doesn't access the original element from |
|
4560 |
;; which the source code is coming, it expects from the code calling |
|
4561 |
;; it to know if lines should be numbered and if code references |
|
4562 |
;; should appear. |
|
4563 |
;; |
|
4564 |
;; Eventually, `org-export-format-code-default' is a higher-level |
|
4565 |
;; function (it makes use of the two previous functions) which handles |
|
4566 |
;; line numbering and code references inclusion, and returns source |
|
4567 |
;; code in a format suitable for plain text or verbatim output. |
|
4568 |
|
|
4569 |
(defun org-export-get-loc (element info) |
|
4570 |
"Return count of lines of code before ELEMENT. |
|
4571 |
|
|
4572 |
ELEMENT is an example-block or src-block element. INFO is the |
|
4573 |
plist used as a communication channel. |
|
4574 |
|
|
4575 |
Count includes every line of code in example-block or src-block |
|
4576 |
with a \"+n\" or \"-n\" switch before block. Return nil if |
|
4577 |
ELEMENT doesn't allow line numbering." |
|
4578 |
(pcase (org-element-property :number-lines element) |
|
4579 |
(`(new . ,n) n) |
|
4580 |
(`(continued . ,n) |
|
4581 |
(let ((loc 0)) |
|
4582 |
(org-element-map (plist-get info :parse-tree) '(src-block example-block) |
|
4583 |
(lambda (el) |
|
4584 |
;; ELEMENT is reached: Quit loop and return locs. |
|
4585 |
(if (eq el element) (+ loc n) |
|
4586 |
;; Only count lines from src-block and example-block |
|
4587 |
;; elements with a "+n" or "-n" switch. |
|
4588 |
(let ((linum (org-element-property :number-lines el))) |
|
4589 |
(when linum |
|
4590 |
(let ((lines (org-count-lines |
|
4591 |
(org-element-property :value el)))) |
|
4592 |
;; Accumulate locs or reset them. |
|
4593 |
(pcase linum |
|
4594 |
(`(new . ,n) (setq loc (+ n lines))) |
|
4595 |
(`(continued . ,n) (cl-incf loc (+ n lines))))))) |
|
4596 |
nil)) ;Return nil to stay in the loop. |
|
4597 |
info 'first-match))))) |
|
4598 |
|
|
4599 |
(defun org-export-unravel-code (element) |
|
4600 |
"Clean source code and extract references out of it. |
|
4601 |
|
|
4602 |
ELEMENT has either a `src-block' an `example-block' type. |
|
4603 |
|
|
4604 |
Return a cons cell whose CAR is the source code, cleaned from any |
|
4605 |
reference, protective commas and spurious indentation, and CDR is |
|
4606 |
an alist between relative line number (integer) and name of code |
|
4607 |
reference on that line (string)." |
|
4608 |
(let* ((line 0) refs |
|
4609 |
(value (org-element-property :value element)) |
|
4610 |
;; Remove global indentation from code, if necessary. Also |
|
4611 |
;; remove final newline character, since it doesn't belongs |
|
4612 |
;; to the code proper. |
|
4613 |
(code (replace-regexp-in-string |
|
4614 |
"\n\\'" "" |
|
4615 |
(if (or org-src-preserve-indentation |
|
4616 |
(org-element-property :preserve-indent element)) |
|
4617 |
value |
|
4618 |
(org-remove-indentation value)))) |
|
4619 |
;; Build a regexp matching a loc with a reference. |
|
4620 |
(ref-re (org-src-coderef-regexp (org-src-coderef-format element)))) |
|
4621 |
;; Return value. |
|
4622 |
(cons |
|
4623 |
;; Code with references removed. |
|
4624 |
(mapconcat |
|
4625 |
(lambda (loc) |
|
4626 |
(cl-incf line) |
|
4627 |
(if (not (string-match ref-re loc)) loc |
|
4628 |
;; Ref line: remove ref, and add its position in REFS. |
|
4629 |
(push (cons line (match-string 3 loc)) refs) |
|
4630 |
(replace-match "" nil nil loc 1))) |
|
4631 |
(split-string code "\n") "\n") |
|
4632 |
;; Reference alist. |
|
4633 |
refs))) |
|
4634 |
|
|
4635 |
(defun org-export-format-code (code fun &optional num-lines ref-alist) |
|
4636 |
"Format CODE by applying FUN line-wise and return it. |
|
4637 |
|
|
4638 |
CODE is a string representing the code to format. FUN is |
|
4639 |
a function. It must accept three arguments: a line of |
|
4640 |
code (string), the current line number (integer) or nil and the |
|
4641 |
reference associated to the current line (string) or nil. |
|
4642 |
|
|
4643 |
Optional argument NUM-LINES can be an integer representing the |
|
4644 |
number of code lines accumulated until the current code. Line |
|
4645 |
numbers passed to FUN will take it into account. If it is nil, |
|
4646 |
FUN's second argument will always be nil. This number can be |
|
4647 |
obtained with `org-export-get-loc' function. |
|
4648 |
|
|
4649 |
Optional argument REF-ALIST can be an alist between relative line |
|
4650 |
number (i.e. ignoring NUM-LINES) and the name of the code |
|
4651 |
reference on it. If it is nil, FUN's third argument will always |
|
4652 |
be nil. It can be obtained through the use of |
|
4653 |
`org-export-unravel-code' function." |
|
4654 |
(let ((--locs (split-string code "\n")) |
|
4655 |
(--line 0)) |
|
4656 |
(concat |
|
4657 |
(mapconcat |
|
4658 |
(lambda (--loc) |
|
4659 |
(cl-incf --line) |
|
4660 |
(let ((--ref (cdr (assq --line ref-alist)))) |
|
4661 |
(funcall fun --loc (and num-lines (+ num-lines --line)) --ref))) |
|
4662 |
--locs "\n") |
|
4663 |
"\n"))) |
|
4664 |
|
|
4665 |
(defun org-export-format-code-default (element info) |
|
4666 |
"Return source code from ELEMENT, formatted in a standard way. |
|
4667 |
|
|
4668 |
ELEMENT is either a `src-block' or `example-block' element. INFO |
|
4669 |
is a plist used as a communication channel. |
|
4670 |
|
|
4671 |
This function takes care of line numbering and code references |
|
4672 |
inclusion. Line numbers, when applicable, appear at the |
|
4673 |
beginning of the line, separated from the code by two white |
|
4674 |
spaces. Code references, on the other hand, appear flushed to |
|
4675 |
the right, separated by six white spaces from the widest line of |
|
4676 |
code." |
|
4677 |
;; Extract code and references. |
|
4678 |
(let* ((code-info (org-export-unravel-code element)) |
|
4679 |
(code (car code-info)) |
|
4680 |
(code-lines (split-string code "\n"))) |
|
4681 |
(if (null code-lines) "" |
|
4682 |
(let* ((refs (and (org-element-property :retain-labels element) |
|
4683 |
(cdr code-info))) |
|
4684 |
;; Handle line numbering. |
|
4685 |
(num-start (org-export-get-loc element info)) |
|
4686 |
(num-fmt |
|
4687 |
(and num-start |
|
4688 |
(format "%%%ds " |
|
4689 |
(length (number-to-string |
|
4690 |
(+ (length code-lines) num-start)))))) |
|
4691 |
;; Prepare references display, if required. Any reference |
|
4692 |
;; should start six columns after the widest line of code, |
|
4693 |
;; wrapped with parenthesis. |
|
4694 |
(max-width |
|
4695 |
(+ (apply 'max (mapcar 'length code-lines)) |
|
4696 |
(if (not num-start) 0 (length (format num-fmt num-start)))))) |
|
4697 |
(org-export-format-code |
|
4698 |
code |
|
4699 |
(lambda (loc line-num ref) |
|
4700 |
(let ((number-str (and num-fmt (format num-fmt line-num)))) |
|
4701 |
(concat |
|
4702 |
number-str |
|
4703 |
loc |
|
4704 |
(and ref |
|
4705 |
(concat (make-string (- (+ 6 max-width) |
|
4706 |
(+ (length loc) (length number-str))) |
|
4707 |
?\s) |
|
4708 |
(format "(%s)" ref)))))) |
|
4709 |
num-start refs))))) |
|
4710 |
|
|
4711 |
|
|
4712 |
;;;; For Tables |
|
4713 |
;; |
|
4714 |
;; `org-export-table-has-special-column-p' and and |
|
4715 |
;; `org-export-table-row-is-special-p' are predicates used to look for |
|
4716 |
;; meta-information about the table structure. |
|
4717 |
;; |
|
4718 |
;; `org-table-has-header-p' tells when the rows before the first rule |
|
4719 |
;; should be considered as table's header. |
|
4720 |
;; |
|
4721 |
;; `org-export-table-cell-width', `org-export-table-cell-alignment' |
|
4722 |
;; and `org-export-table-cell-borders' extract information from |
|
4723 |
;; a table-cell element. |
|
4724 |
;; |
|
4725 |
;; `org-export-table-dimensions' gives the number on rows and columns |
|
4726 |
;; in the table, ignoring horizontal rules and special columns. |
|
4727 |
;; `org-export-table-cell-address', given a table-cell object, returns |
|
4728 |
;; the absolute address of a cell. On the other hand, |
|
4729 |
;; `org-export-get-table-cell-at' does the contrary. |
|
4730 |
;; |
|
4731 |
;; `org-export-table-cell-starts-colgroup-p', |
|
4732 |
;; `org-export-table-cell-ends-colgroup-p', |
|
4733 |
;; `org-export-table-row-starts-rowgroup-p', |
|
4734 |
;; `org-export-table-row-ends-rowgroup-p', |
|
4735 |
;; `org-export-table-row-starts-header-p', |
|
4736 |
;; `org-export-table-row-ends-header-p' and |
|
4737 |
;; `org-export-table-row-in-header-p' indicate position of current row |
|
4738 |
;; or cell within the table. |
|
4739 |
|
|
4740 |
(defun org-export-table-has-special-column-p (table) |
|
4741 |
"Non-nil when TABLE has a special column. |
|
4742 |
All special columns will be ignored during export." |
|
4743 |
;; The table has a special column when every first cell of every row |
|
4744 |
;; has an empty value or contains a symbol among "/", "#", "!", "$", |
|
4745 |
;; "*" "_" and "^". Though, do not consider a first column |
|
4746 |
;; containing only empty cells as special. |
|
4747 |
(let ((special-column? 'empty)) |
|
4748 |
(catch 'exit |
|
4749 |
(dolist (row (org-element-contents table)) |
|
4750 |
(when (eq (org-element-property :type row) 'standard) |
|
4751 |
(let ((value (org-element-contents |
|
4752 |
(car (org-element-contents row))))) |
|
4753 |
(cond ((member value |
|
4754 |
'(("/") ("#") ("!") ("$") ("*") ("_") ("^"))) |
|
4755 |
(setq special-column? 'special)) |
|
4756 |
((null value)) |
|
4757 |
(t (throw 'exit nil)))))) |
|
4758 |
(eq special-column? 'special)))) |
|
4759 |
|
|
4760 |
(defun org-export-table-has-header-p (table info) |
|
4761 |
"Non-nil when TABLE has a header. |
|
4762 |
|
|
4763 |
INFO is a plist used as a communication channel. |
|
4764 |
|
|
4765 |
A table has a header when it contains at least two row groups." |
|
4766 |
(let* ((cache (or (plist-get info :table-header-cache) |
|
4767 |
(let ((table (make-hash-table :test #'eq))) |
|
4768 |
(plist-put info :table-header-cache table) |
|
4769 |
table))) |
|
4770 |
(cached (gethash table cache 'no-cache))) |
|
4771 |
(if (not (eq cached 'no-cache)) cached |
|
4772 |
(let ((rowgroup 1) row-flag) |
|
4773 |
(puthash table |
|
4774 |
(org-element-map table 'table-row |
|
4775 |
(lambda (row) |
|
4776 |
(cond |
|
4777 |
((> rowgroup 1) t) |
|
4778 |
((and row-flag |
|
4779 |
(eq (org-element-property :type row) 'rule)) |
|
4780 |
(cl-incf rowgroup) |
|
4781 |
(setq row-flag nil)) |
|
4782 |
((and (not row-flag) |
|
4783 |
(eq (org-element-property :type row) 'standard)) |
|
4784 |
(setq row-flag t) |
|
4785 |
nil))) |
|
4786 |
info 'first-match) |
|
4787 |
cache))))) |
|
4788 |
|
|
4789 |
(defun org-export-table-row-is-special-p (table-row _) |
|
4790 |
"Non-nil if TABLE-ROW is considered special. |
|
4791 |
All special rows will be ignored during export." |
|
4792 |
(when (eq (org-element-property :type table-row) 'standard) |
|
4793 |
(let ((first-cell (org-element-contents |
|
4794 |
(car (org-element-contents table-row))))) |
|
4795 |
;; A row is special either when... |
|
4796 |
(or |
|
4797 |
;; ... it starts with a field only containing "/", |
|
4798 |
(equal first-cell '("/")) |
|
4799 |
;; ... the table contains a special column and the row start |
|
4800 |
;; with a marking character among, "^", "_", "$" or "!", |
|
4801 |
(and (org-export-table-has-special-column-p |
|
4802 |
(org-export-get-parent table-row)) |
|
4803 |
(member first-cell '(("^") ("_") ("$") ("!")))) |
|
4804 |
;; ... it contains only alignment cookies and empty cells. |
|
4805 |
(let ((special-row-p 'empty)) |
|
4806 |
(catch 'exit |
|
4807 |
(dolist (cell (org-element-contents table-row)) |
|
4808 |
(let ((value (org-element-contents cell))) |
|
4809 |
;; Since VALUE is a secondary string, the following |
|
4810 |
;; checks avoid expanding it with `org-export-data'. |
|
4811 |
(cond ((not value)) |
|
4812 |
((and (not (cdr value)) |
|
4813 |
(stringp (car value)) |
|
4814 |
(string-match "\\`<[lrc]?\\([0-9]+\\)?>\\'" |
|
4815 |
(car value))) |
|
4816 |
(setq special-row-p 'cookie)) |
|
4817 |
(t (throw 'exit nil))))) |
|
4818 |
(eq special-row-p 'cookie))))))) |
|
4819 |
|
|
4820 |
(defun org-export-table-row-group (table-row info) |
|
4821 |
"Return TABLE-ROW's group number, as an integer. |
|
4822 |
|
|
4823 |
INFO is a plist used as the communication channel. |
|
4824 |
|
|
4825 |
Return value is the group number, as an integer, or nil for |
|
4826 |
special rows and rows separators. First group is also table's |
|
4827 |
header." |
|
4828 |
(when (eq (org-element-property :type table-row) 'standard) |
|
4829 |
(let* ((cache (or (plist-get info :table-row-group-cache) |
|
4830 |
(let ((table (make-hash-table :test #'eq))) |
|
4831 |
(plist-put info :table-row-group-cache table) |
|
4832 |
table))) |
|
4833 |
(cached (gethash table-row cache 'no-cache))) |
|
4834 |
(if (not (eq cached 'no-cache)) cached |
|
4835 |
;; First time a row is queried, populate cache with all the |
|
4836 |
;; rows from the table. |
|
4837 |
(let ((group 0) row-flag) |
|
4838 |
(org-element-map (org-export-get-parent table-row) 'table-row |
|
4839 |
(lambda (row) |
|
4840 |
(if (eq (org-element-property :type row) 'rule) |
|
4841 |
(setq row-flag nil) |
|
4842 |
(unless row-flag (cl-incf group) (setq row-flag t)) |
|
4843 |
(puthash row group cache))) |
|
4844 |
info)) |
|
4845 |
(gethash table-row cache))))) |
|
4846 |
|
|
4847 |
(defun org-export-table-cell-width (table-cell info) |
|
4848 |
"Return TABLE-CELL contents width. |
|
4849 |
|
|
4850 |
INFO is a plist used as the communication channel. |
|
4851 |
|
|
4852 |
Return value is the width given by the last width cookie in the |
|
4853 |
same column as TABLE-CELL, or nil." |
|
4854 |
(let* ((row (org-export-get-parent table-cell)) |
|
4855 |
(table (org-export-get-parent row)) |
|
4856 |
(cells (org-element-contents row)) |
|
4857 |
(columns (length cells)) |
|
4858 |
(column (- columns (length (memq table-cell cells)))) |
|
4859 |
(cache (or (plist-get info :table-cell-width-cache) |
|
4860 |
(let ((table (make-hash-table :test #'eq))) |
|
4861 |
(plist-put info :table-cell-width-cache table) |
|
4862 |
table))) |
|
4863 |
(width-vector (or (gethash table cache) |
|
4864 |
(puthash table (make-vector columns 'empty) cache))) |
|
4865 |
(value (aref width-vector column))) |
|
4866 |
(if (not (eq value 'empty)) value |
|
4867 |
(let (cookie-width) |
|
4868 |
(dolist (row (org-element-contents table) |
|
4869 |
(aset width-vector column cookie-width)) |
|
4870 |
(when (org-export-table-row-is-special-p row info) |
|
4871 |
;; In a special row, try to find a width cookie at COLUMN. |
|
4872 |
(let* ((value (org-element-contents |
|
4873 |
(elt (org-element-contents row) column))) |
|
4874 |
(cookie (car value))) |
|
4875 |
;; The following checks avoid expanding unnecessarily |
|
4876 |
;; the cell with `org-export-data'. |
|
4877 |
(when (and value |
|
4878 |
(not (cdr value)) |
|
4879 |
(stringp cookie) |
|
4880 |
(string-match "\\`<[lrc]?\\([0-9]+\\)?>\\'" cookie) |
|
4881 |
(match-string 1 cookie)) |
|
4882 |
(setq cookie-width |
|
4883 |
(string-to-number (match-string 1 cookie))))))))))) |
|
4884 |
|
|
4885 |
(defun org-export-table-cell-alignment (table-cell info) |
|
4886 |
"Return TABLE-CELL contents alignment. |
|
4887 |
|
|
4888 |
INFO is a plist used as the communication channel. |
|
4889 |
|
|
4890 |
Return alignment as specified by the last alignment cookie in the |
|
4891 |
same column as TABLE-CELL. If no such cookie is found, a default |
|
4892 |
alignment value will be deduced from fraction of numbers in the |
|
4893 |
column (see `org-table-number-fraction' for more information). |
|
4894 |
Possible values are `left', `right' and `center'." |
|
4895 |
;; Load `org-table-number-fraction' and `org-table-number-regexp'. |
|
4896 |
(require 'org-table) |
|
4897 |
(let* ((row (org-export-get-parent table-cell)) |
|
4898 |
(table (org-export-get-parent row)) |
|
4899 |
(cells (org-element-contents row)) |
|
4900 |
(columns (length cells)) |
|
4901 |
(column (- columns (length (memq table-cell cells)))) |
|
4902 |
(cache (or (plist-get info :table-cell-alignment-cache) |
|
4903 |
(let ((table (make-hash-table :test #'eq))) |
|
4904 |
(plist-put info :table-cell-alignment-cache table) |
|
4905 |
table))) |
|
4906 |
(align-vector (or (gethash table cache) |
|
4907 |
(puthash table (make-vector columns nil) cache)))) |
|
4908 |
(or (aref align-vector column) |
|
4909 |
(let ((number-cells 0) |
|
4910 |
(total-cells 0) |
|
4911 |
cookie-align |
|
4912 |
previous-cell-number-p) |
|
4913 |
(dolist (row (org-element-contents (org-export-get-parent row))) |
|
4914 |
(cond |
|
4915 |
;; In a special row, try to find an alignment cookie at |
|
4916 |
;; COLUMN. |
|
4917 |
((org-export-table-row-is-special-p row info) |
|
4918 |
(let ((value (org-element-contents |
|
4919 |
(elt (org-element-contents row) column)))) |
|
4920 |
;; Since VALUE is a secondary string, the following |
|
4921 |
;; checks avoid useless expansion through |
|
4922 |
;; `org-export-data'. |
|
4923 |
(when (and value |
|
4924 |
(not (cdr value)) |
|
4925 |
(stringp (car value)) |
|
4926 |
(string-match "\\`<\\([lrc]\\)?\\([0-9]+\\)?>\\'" |
|
4927 |
(car value)) |
|
4928 |
(match-string 1 (car value))) |
|
4929 |
(setq cookie-align (match-string 1 (car value)))))) |
|
4930 |
;; Ignore table rules. |
|
4931 |
((eq (org-element-property :type row) 'rule)) |
|
4932 |
;; In a standard row, check if cell's contents are |
|
4933 |
;; expressing some kind of number. Increase NUMBER-CELLS |
|
4934 |
;; accordingly. Though, don't bother if an alignment |
|
4935 |
;; cookie has already defined cell's alignment. |
|
4936 |
((not cookie-align) |
|
4937 |
(let ((value (org-export-data |
|
4938 |
(org-element-contents |
|
4939 |
(elt (org-element-contents row) column)) |
|
4940 |
info))) |
|
4941 |
(cl-incf total-cells) |
|
4942 |
;; Treat an empty cell as a number if it follows |
|
4943 |
;; a number. |
|
4944 |
(if (not (or (string-match org-table-number-regexp value) |
|
4945 |
(and (string= value "") previous-cell-number-p))) |
|
4946 |
(setq previous-cell-number-p nil) |
|
4947 |
(setq previous-cell-number-p t) |
|
4948 |
(cl-incf number-cells)))))) |
|
4949 |
;; Return value. Alignment specified by cookies has |
|
4950 |
;; precedence over alignment deduced from cell's contents. |
|
4951 |
(aset align-vector |
|
4952 |
column |
|
4953 |
(cond ((equal cookie-align "l") 'left) |
|
4954 |
((equal cookie-align "r") 'right) |
|
4955 |
((equal cookie-align "c") 'center) |
|
4956 |
((>= (/ (float number-cells) total-cells) |
|
4957 |
org-table-number-fraction) |
|
4958 |
'right) |
|
4959 |
(t 'left))))))) |
|
4960 |
|
|
4961 |
(defun org-export-table-cell-borders (table-cell info) |
|
4962 |
"Return TABLE-CELL borders. |
|
4963 |
|
|
4964 |
INFO is a plist used as a communication channel. |
|
4965 |
|
|
4966 |
Return value is a list of symbols, or nil. Possible values are: |
|
4967 |
`top', `bottom', `above', `below', `left' and `right'. Note: |
|
4968 |
`top' (resp. `bottom') only happen for a cell in the first |
|
4969 |
row (resp. last row) of the table, ignoring table rules, if any. |
|
4970 |
|
|
4971 |
Returned borders ignore special rows." |
|
4972 |
(let* ((row (org-export-get-parent table-cell)) |
|
4973 |
(table (org-export-get-parent-table table-cell)) |
|
4974 |
borders) |
|
4975 |
;; Top/above border? TABLE-CELL has a border above when a rule |
|
4976 |
;; used to demarcate row groups can be found above. Hence, |
|
4977 |
;; finding a rule isn't sufficient to push `above' in BORDERS: |
|
4978 |
;; another regular row has to be found above that rule. |
|
4979 |
(let (rule-flag) |
|
4980 |
(catch 'exit |
|
4981 |
;; Look at every row before the current one. |
|
4982 |
(dolist (row (cdr (memq row (reverse (org-element-contents table))))) |
|
4983 |
(cond ((eq (org-element-property :type row) 'rule) |
|
4984 |
(setq rule-flag t)) |
|
4985 |
((not (org-export-table-row-is-special-p row info)) |
|
4986 |
(if rule-flag (throw 'exit (push 'above borders)) |
|
4987 |
(throw 'exit nil))))) |
|
4988 |
;; No rule above, or rule found starts the table (ignoring any |
|
4989 |
;; special row): TABLE-CELL is at the top of the table. |
|
4990 |
(when rule-flag (push 'above borders)) |
|
4991 |
(push 'top borders))) |
|
4992 |
;; Bottom/below border? TABLE-CELL has a border below when next |
|
4993 |
;; non-regular row below is a rule. |
|
4994 |
(let (rule-flag) |
|
4995 |
(catch 'exit |
|
4996 |
;; Look at every row after the current one. |
|
4997 |
(dolist (row (cdr (memq row (org-element-contents table)))) |
|
4998 |
(cond ((eq (org-element-property :type row) 'rule) |
|
4999 |
(setq rule-flag t)) |
|
5000 |
((not (org-export-table-row-is-special-p row info)) |
|
5001 |
(if rule-flag (throw 'exit (push 'below borders)) |
|
5002 |
(throw 'exit nil))))) |
|
5003 |
;; No rule below, or rule found ends the table (modulo some |
|
5004 |
;; special row): TABLE-CELL is at the bottom of the table. |
|
5005 |
(when rule-flag (push 'below borders)) |
|
5006 |
(push 'bottom borders))) |
|
5007 |
;; Right/left borders? They can only be specified by column |
|
5008 |
;; groups. Column groups are defined in a row starting with "/". |
|
5009 |
;; Also a column groups row only contains "<", "<>", ">" or blank |
|
5010 |
;; cells. |
|
5011 |
(catch 'exit |
|
5012 |
(let ((column (let ((cells (org-element-contents row))) |
|
5013 |
(- (length cells) (length (memq table-cell cells)))))) |
|
5014 |
;; Table rows are read in reverse order so last column groups |
|
5015 |
;; row has precedence over any previous one. |
|
5016 |
(dolist (row (reverse (org-element-contents table))) |
|
5017 |
(unless (eq (org-element-property :type row) 'rule) |
|
5018 |
(when (equal (org-element-contents |
|
5019 |
(car (org-element-contents row))) |
|
5020 |
'("/")) |
|
5021 |
(let ((column-groups |
|
5022 |
(mapcar |
|
5023 |
(lambda (cell) |
|
5024 |
(let ((value (org-element-contents cell))) |
|
5025 |
(when (member value '(("<") ("<>") (">") nil)) |
|
5026 |
(car value)))) |
|
5027 |
(org-element-contents row)))) |
|
5028 |
;; There's a left border when previous cell, if |
|
5029 |
;; any, ends a group, or current one starts one. |
|
5030 |
(when (or (and (not (zerop column)) |
|
5031 |
(member (elt column-groups (1- column)) |
|
5032 |
'(">" "<>"))) |
|
5033 |
(member (elt column-groups column) '("<" "<>"))) |
|
5034 |
(push 'left borders)) |
|
5035 |
;; There's a right border when next cell, if any, |
|
5036 |
;; starts a group, or current one ends one. |
|
5037 |
(when (or (and (/= (1+ column) (length column-groups)) |
|
5038 |
(member (elt column-groups (1+ column)) |
|
5039 |
'("<" "<>"))) |
|
5040 |
(member (elt column-groups column) '(">" "<>"))) |
|
5041 |
(push 'right borders)) |
|
5042 |
(throw 'exit nil))))))) |
|
5043 |
;; Return value. |
|
5044 |
borders)) |
|
5045 |
|
|
5046 |
(defun org-export-table-cell-starts-colgroup-p (table-cell info) |
|
5047 |
"Non-nil when TABLE-CELL is at the beginning of a column group. |
|
5048 |
INFO is a plist used as a communication channel." |
|
5049 |
;; A cell starts a column group either when it is at the beginning |
|
5050 |
;; of a row (or after the special column, if any) or when it has |
|
5051 |
;; a left border. |
|
5052 |
(or (eq (org-element-map (org-export-get-parent table-cell) 'table-cell |
|
5053 |
'identity info 'first-match) |
|
5054 |
table-cell) |
|
5055 |
(memq 'left (org-export-table-cell-borders table-cell info)))) |
|
5056 |
|
|
5057 |
(defun org-export-table-cell-ends-colgroup-p (table-cell info) |
|
5058 |
"Non-nil when TABLE-CELL is at the end of a column group. |
|
5059 |
INFO is a plist used as a communication channel." |
|
5060 |
;; A cell ends a column group either when it is at the end of a row |
|
5061 |
;; or when it has a right border. |
|
5062 |
(or (eq (car (last (org-element-contents |
|
5063 |
(org-export-get-parent table-cell)))) |
|
5064 |
table-cell) |
|
5065 |
(memq 'right (org-export-table-cell-borders table-cell info)))) |
|
5066 |
|
|
5067 |
(defun org-export-table-row-starts-rowgroup-p (table-row info) |
|
5068 |
"Non-nil when TABLE-ROW is at the beginning of a row group. |
|
5069 |
INFO is a plist used as a communication channel." |
|
5070 |
(unless (or (eq (org-element-property :type table-row) 'rule) |
|
5071 |
(org-export-table-row-is-special-p table-row info)) |
|
5072 |
(let ((borders (org-export-table-cell-borders |
|
5073 |
(car (org-element-contents table-row)) info))) |
|
5074 |
(or (memq 'top borders) (memq 'above borders))))) |
|
5075 |
|
|
5076 |
(defun org-export-table-row-ends-rowgroup-p (table-row info) |
|
5077 |
"Non-nil when TABLE-ROW is at the end of a row group. |
|
5078 |
INFO is a plist used as a communication channel." |
|
5079 |
(unless (or (eq (org-element-property :type table-row) 'rule) |
|
5080 |
(org-export-table-row-is-special-p table-row info)) |
|
5081 |
(let ((borders (org-export-table-cell-borders |
|
5082 |
(car (org-element-contents table-row)) info))) |
|
5083 |
(or (memq 'bottom borders) (memq 'below borders))))) |
|
5084 |
|
|
5085 |
(defun org-export-table-row-in-header-p (table-row info) |
|
5086 |
"Non-nil when TABLE-ROW is located within table's header. |
|
5087 |
INFO is a plist used as a communication channel. Always return |
|
5088 |
nil for special rows and rows separators." |
|
5089 |
(and (org-export-table-has-header-p |
|
5090 |
(org-export-get-parent-table table-row) info) |
|
5091 |
(eql (org-export-table-row-group table-row info) 1))) |
|
5092 |
|
|
5093 |
(defun org-export-table-row-starts-header-p (table-row info) |
|
5094 |
"Non-nil when TABLE-ROW is the first table header's row. |
|
5095 |
INFO is a plist used as a communication channel." |
|
5096 |
(and (org-export-table-row-in-header-p table-row info) |
|
5097 |
(org-export-table-row-starts-rowgroup-p table-row info))) |
|
5098 |
|
|
5099 |
(defun org-export-table-row-ends-header-p (table-row info) |
|
5100 |
"Non-nil when TABLE-ROW is the last table header's row. |
|
5101 |
INFO is a plist used as a communication channel." |
|
5102 |
(and (org-export-table-row-in-header-p table-row info) |
|
5103 |
(org-export-table-row-ends-rowgroup-p table-row info))) |
|
5104 |
|
|
5105 |
(defun org-export-table-row-number (table-row info) |
|
5106 |
"Return TABLE-ROW number. |
|
5107 |
INFO is a plist used as a communication channel. Return value is |
|
5108 |
zero-indexed and ignores separators. The function returns nil |
|
5109 |
for special rows and separators." |
|
5110 |
(when (eq (org-element-property :type table-row) 'standard) |
|
5111 |
(let* ((cache (or (plist-get info :table-row-number-cache) |
|
5112 |
(let ((table (make-hash-table :test #'eq))) |
|
5113 |
(plist-put info :table-row-number-cache table) |
|
5114 |
table))) |
|
5115 |
(cached (gethash table-row cache 'no-cache))) |
|
5116 |
(if (not (eq cached 'no-cache)) cached |
|
5117 |
;; First time a row is queried, populate cache with all the |
|
5118 |
;; rows from the table. |
|
5119 |
(let ((number -1)) |
|
5120 |
(org-element-map (org-export-get-parent-table table-row) 'table-row |
|
5121 |
(lambda (row) |
|
5122 |
(when (eq (org-element-property :type row) 'standard) |
|
5123 |
(puthash row (cl-incf number) cache))) |
|
5124 |
info)) |
|
5125 |
(gethash table-row cache))))) |
|
5126 |
|
|
5127 |
(defun org-export-table-dimensions (table info) |
|
5128 |
"Return TABLE dimensions. |
|
5129 |
|
|
5130 |
INFO is a plist used as a communication channel. |
|
5131 |
|
|
5132 |
Return value is a CONS like (ROWS . COLUMNS) where |
|
5133 |
ROWS (resp. COLUMNS) is the number of exportable |
|
5134 |
rows (resp. columns)." |
|
5135 |
(let (first-row (columns 0) (rows 0)) |
|
5136 |
;; Set number of rows, and extract first one. |
|
5137 |
(org-element-map table 'table-row |
|
5138 |
(lambda (row) |
|
5139 |
(when (eq (org-element-property :type row) 'standard) |
|
5140 |
(cl-incf rows) |
|
5141 |
(unless first-row (setq first-row row)))) info) |
|
5142 |
;; Set number of columns. |
|
5143 |
(org-element-map first-row 'table-cell (lambda (_) (cl-incf columns)) info) |
|
5144 |
;; Return value. |
|
5145 |
(cons rows columns))) |
|
5146 |
|
|
5147 |
(defun org-export-table-cell-address (table-cell info) |
|
5148 |
"Return address of a regular TABLE-CELL object. |
|
5149 |
|
|
5150 |
TABLE-CELL is the cell considered. INFO is a plist used as |
|
5151 |
a communication channel. |
|
5152 |
|
|
5153 |
Address is a CONS cell (ROW . COLUMN), where ROW and COLUMN are |
|
5154 |
zero-based index. Only exportable cells are considered. The |
|
5155 |
function returns nil for other cells." |
|
5156 |
(let* ((table-row (org-export-get-parent table-cell)) |
|
5157 |
(row-number (org-export-table-row-number table-row info))) |
|
5158 |
(when row-number |
|
5159 |
(cons row-number |
|
5160 |
(let ((col-count 0)) |
|
5161 |
(org-element-map table-row 'table-cell |
|
5162 |
(lambda (cell) |
|
5163 |
(if (eq cell table-cell) col-count (cl-incf col-count) nil)) |
|
5164 |
info 'first-match)))))) |
|
5165 |
|
|
5166 |
(defun org-export-get-table-cell-at (address table info) |
|
5167 |
"Return regular table-cell object at ADDRESS in TABLE. |
|
5168 |
|
|
5169 |
Address is a CONS cell (ROW . COLUMN), where ROW and COLUMN are |
|
5170 |
zero-based index. TABLE is a table type element. INFO is |
|
5171 |
a plist used as a communication channel. |
|
5172 |
|
|
5173 |
If no table-cell, among exportable cells, is found at ADDRESS, |
|
5174 |
return nil." |
|
5175 |
(let ((column-pos (cdr address)) (column-count 0)) |
|
5176 |
(org-element-map |
|
5177 |
;; Row at (car address) or nil. |
|
5178 |
(let ((row-pos (car address)) (row-count 0)) |
|
5179 |
(org-element-map table 'table-row |
|
5180 |
(lambda (row) |
|
5181 |
(cond ((eq (org-element-property :type row) 'rule) nil) |
|
5182 |
((= row-count row-pos) row) |
|
5183 |
(t (cl-incf row-count) nil))) |
|
5184 |
info 'first-match)) |
|
5185 |
'table-cell |
|
5186 |
(lambda (cell) |
|
5187 |
(if (= column-count column-pos) cell |
|
5188 |
(cl-incf column-count) nil)) |
|
5189 |
info 'first-match))) |
|
5190 |
|
|
5191 |
|
|
5192 |
;;;; For Tables of Contents |
|
5193 |
;; |
|
5194 |
;; `org-export-collect-headlines' builds a list of all exportable |
|
5195 |
;; headline elements, maybe limited to a certain depth. One can then |
|
5196 |
;; easily parse it and transcode it. |
|
5197 |
;; |
|
5198 |
;; Building lists of tables, figures or listings is quite similar. |
|
5199 |
;; Once the generic function `org-export-collect-elements' is defined, |
|
5200 |
;; `org-export-collect-tables', `org-export-collect-figures' and |
|
5201 |
;; `org-export-collect-listings' can be derived from it. |
|
5202 |
;; |
|
5203 |
;; `org-export-toc-entry-backend' builds a special anonymous back-end |
|
5204 |
;; useful to export table of contents' entries. |
|
5205 |
|
|
5206 |
(defun org-export-collect-headlines (info &optional n scope) |
|
5207 |
"Collect headlines in order to build a table of contents. |
|
5208 |
|
|
5209 |
INFO is a plist used as a communication channel. |
|
5210 |
|
|
5211 |
When optional argument N is an integer, it specifies the depth of |
|
5212 |
the table of contents. Otherwise, it is set to the value of the |
|
5213 |
last headline level. See `org-export-headline-levels' for more |
|
5214 |
information. |
|
5215 |
|
|
5216 |
Optional argument SCOPE, when non-nil, is an element. If it is |
|
5217 |
a headline, only children of SCOPE are collected. Otherwise, |
|
5218 |
collect children of the headline containing provided element. If |
|
5219 |
there is no such headline, collect all headlines. In any case, |
|
5220 |
argument N becomes relative to the level of that headline. |
|
5221 |
|
|
5222 |
Return a list of all exportable headlines as parsed elements. |
|
5223 |
Footnote sections are ignored." |
|
5224 |
(let* ((scope (cond ((not scope) (plist-get info :parse-tree)) |
|
5225 |
((eq (org-element-type scope) 'headline) scope) |
|
5226 |
((org-export-get-parent-headline scope)) |
|
5227 |
(t (plist-get info :parse-tree)))) |
|
5228 |
(limit (plist-get info :headline-levels)) |
|
5229 |
(n (if (not (wholenump n)) limit |
|
5230 |
(min (if (eq (org-element-type scope) 'org-data) n |
|
5231 |
(+ (org-export-get-relative-level scope info) n)) |
|
5232 |
limit)))) |
|
5233 |
(org-element-map (org-element-contents scope) 'headline |
|
5234 |
(lambda (headline) |
|
5235 |
(unless (org-element-property :footnote-section-p headline) |
|
5236 |
(let ((level (org-export-get-relative-level headline info))) |
|
5237 |
(and (<= level n) headline)))) |
|
5238 |
info))) |
|
5239 |
|
|
5240 |
(defun org-export-collect-elements (type info &optional predicate) |
|
5241 |
"Collect referenceable elements of a determined type. |
|
5242 |
|
|
5243 |
TYPE can be a symbol or a list of symbols specifying element |
|
5244 |
types to search. Only elements with a caption are collected. |
|
5245 |
|
|
5246 |
INFO is a plist used as a communication channel. |
|
5247 |
|
|
5248 |
When non-nil, optional argument PREDICATE is a function accepting |
|
5249 |
one argument, an element of type TYPE. It returns a non-nil |
|
5250 |
value when that element should be collected. |
|
5251 |
|
|
5252 |
Return a list of all elements found, in order of appearance." |
|
5253 |
(org-element-map (plist-get info :parse-tree) type |
|
5254 |
(lambda (element) |
|
5255 |
(and (org-element-property :caption element) |
|
5256 |
(or (not predicate) (funcall predicate element)) |
|
5257 |
element)) |
|
5258 |
info)) |
|
5259 |
|
|
5260 |
(defun org-export-collect-tables (info) |
|
5261 |
"Build a list of tables. |
|
5262 |
INFO is a plist used as a communication channel. |
|
5263 |
|
|
5264 |
Return a list of table elements with a caption." |
|
5265 |
(org-export-collect-elements 'table info)) |
|
5266 |
|
|
5267 |
(defun org-export-collect-figures (info predicate) |
|
5268 |
"Build a list of figures. |
|
5269 |
|
|
5270 |
INFO is a plist used as a communication channel. PREDICATE is |
|
5271 |
a function which accepts one argument: a paragraph element and |
|
5272 |
whose return value is non-nil when that element should be |
|
5273 |
collected. |
|
5274 |
|
|
5275 |
A figure is a paragraph type element, with a caption, verifying |
|
5276 |
PREDICATE. The latter has to be provided since a \"figure\" is |
|
5277 |
a vague concept that may depend on back-end. |
|
5278 |
|
|
5279 |
Return a list of elements recognized as figures." |
|
5280 |
(org-export-collect-elements 'paragraph info predicate)) |
|
5281 |
|
|
5282 |
(defun org-export-collect-listings (info) |
|
5283 |
"Build a list of src blocks. |
|
5284 |
|
|
5285 |
INFO is a plist used as a communication channel. |
|
5286 |
|
|
5287 |
Return a list of src-block elements with a caption." |
|
5288 |
(org-export-collect-elements 'src-block info)) |
|
5289 |
|
|
5290 |
(defun org-export-toc-entry-backend (parent &rest transcoders) |
|
5291 |
"Return an export back-end appropriate for table of contents entries. |
|
5292 |
|
|
5293 |
PARENT is an export back-end the returned back-end should inherit |
|
5294 |
from. |
|
5295 |
|
|
5296 |
By default, the back-end removes footnote references and targets. |
|
5297 |
It also changes links and radio targets into regular text. |
|
5298 |
TRANSCODERS optional argument, when non-nil, specifies additional |
|
5299 |
transcoders. A transcoder follows the pattern (TYPE . FUNCTION) |
|
5300 |
where type is an element or object type and FUNCTION the function |
|
5301 |
transcoding it." |
|
5302 |
(declare (indent 1)) |
|
5303 |
(org-export-create-backend |
|
5304 |
:parent parent |
|
5305 |
:transcoders |
|
5306 |
(append transcoders |
|
5307 |
`((footnote-reference . ,#'ignore) |
|
5308 |
(link . ,(lambda (l c i) |
|
5309 |
(or c |
|
5310 |
(org-export-data |
|
5311 |
(org-element-property :raw-link l) |
|
5312 |
i)))) |
|
5313 |
(radio-target . ,(lambda (_r c _) c)) |
|
5314 |
(target . ,#'ignore))))) |
|
5315 |
|
|
5316 |
|
|
5317 |
;;;; Smart Quotes |
|
5318 |
;; |
|
5319 |
;; The main function for the smart quotes sub-system is |
|
5320 |
;; `org-export-activate-smart-quotes', which replaces every quote in |
|
5321 |
;; a given string from the parse tree with its "smart" counterpart. |
|
5322 |
;; |
|
5323 |
;; Dictionary for smart quotes is stored in |
|
5324 |
;; `org-export-smart-quotes-alist'. |
|
5325 |
|
|
5326 |
(defconst org-export-smart-quotes-alist |
|
5327 |
'(("ar" |
|
5328 |
(primary-opening |
|
5329 |
:utf-8 "«" :html "«" :latex "\\guillemotleft{}" |
|
5330 |
:texinfo "@guillemetleft{}") |
|
5331 |
(primary-closing |
|
5332 |
:utf-8 "»" :html "»" :latex "\\guillemotright{}" |
|
5333 |
:texinfo "@guillemetright{}") |
|
5334 |
(secondary-opening :utf-8 "‹" :html "‹" :latex "\\guilsinglleft{}" |
|
5335 |
:texinfo "@guilsinglleft{}") |
|
5336 |
(secondary-closing :utf-8 "›" :html "›" :latex "\\guilsinglright{}" |
|
5337 |
:texinfo "@guilsinglright{}") |
|
5338 |
(apostrophe :utf-8 "’" :html "’")) |
|
5339 |
("da" |
|
5340 |
;; one may use: »...«, "...", ›...‹, or '...'. |
|
5341 |
;; http://sproget.dk/raad-og-regler/retskrivningsregler/retskrivningsregler/a7-40-60/a7-58-anforselstegn/ |
|
5342 |
;; LaTeX quotes require Babel! |
|
5343 |
(primary-opening |
|
5344 |
:utf-8 "»" :html "»" :latex ">>" :texinfo "@guillemetright{}") |
|
5345 |
(primary-closing |
|
5346 |
:utf-8 "«" :html "«" :latex "<<" :texinfo "@guillemetleft{}") |
|
5347 |
(secondary-opening |
|
5348 |
:utf-8 "›" :html "›" :latex "\\frq{}" :texinfo "@guilsinglright{}") |
|
5349 |
(secondary-closing |
|
5350 |
:utf-8 "‹" :html "‹" :latex "\\flq{}" :texinfo "@guilsingleft{}") |
|
5351 |
(apostrophe :utf-8 "’" :html "’")) |
|
5352 |
("de" |
|
5353 |
(primary-opening |
|
5354 |
:utf-8 "„" :html "„" :latex "\"`" :texinfo "@quotedblbase{}") |
|
5355 |
(primary-closing |
|
5356 |
:utf-8 "“" :html "“" :latex "\"'" :texinfo "@quotedblleft{}") |
|
5357 |
(secondary-opening |
|
5358 |
:utf-8 "‚" :html "‚" :latex "\\glq{}" :texinfo "@quotesinglbase{}") |
|
5359 |
(secondary-closing |
|
5360 |
:utf-8 "‘" :html "‘" :latex "\\grq{}" :texinfo "@quoteleft{}") |
|
5361 |
(apostrophe :utf-8 "’" :html "’")) |
|
5362 |
("en" |
|
5363 |
(primary-opening :utf-8 "“" :html "“" :latex "``" :texinfo "``") |
|
5364 |
(primary-closing :utf-8 "”" :html "”" :latex "''" :texinfo "''") |
|
5365 |
(secondary-opening :utf-8 "‘" :html "‘" :latex "`" :texinfo "`") |
|
5366 |
(secondary-closing :utf-8 "’" :html "’" :latex "'" :texinfo "'") |
|
5367 |
(apostrophe :utf-8 "’" :html "’")) |
|
5368 |
("es" |
|
5369 |
(primary-opening |
|
5370 |
:utf-8 "«" :html "«" :latex "\\guillemotleft{}" |
|
5371 |
:texinfo "@guillemetleft{}") |
|
5372 |
(primary-closing |
|
5373 |
:utf-8 "»" :html "»" :latex "\\guillemotright{}" |
|
5374 |
:texinfo "@guillemetright{}") |
|
5375 |
(secondary-opening :utf-8 "“" :html "“" :latex "``" :texinfo "``") |
|
5376 |
(secondary-closing :utf-8 "”" :html "”" :latex "''" :texinfo "''") |
|
5377 |
(apostrophe :utf-8 "’" :html "’")) |
|
5378 |
("fr" |
|
5379 |
(primary-opening |
|
5380 |
:utf-8 "« " :html "« " :latex "\\og " |
|
5381 |
:texinfo "@guillemetleft{}@tie{}") |
|
5382 |
(primary-closing |
|
5383 |
:utf-8 " »" :html " »" :latex "\\fg{}" |
|
5384 |
:texinfo "@tie{}@guillemetright{}") |
|
5385 |
(secondary-opening |
|
5386 |
:utf-8 "« " :html "« " :latex "\\og " |
|
5387 |
:texinfo "@guillemetleft{}@tie{}") |
|
5388 |
(secondary-closing :utf-8 " »" :html " »" :latex "\\fg{}" |
|
5389 |
:texinfo "@tie{}@guillemetright{}") |
|
5390 |
(apostrophe :utf-8 "’" :html "’")) |
|
5391 |
("is" |
|
5392 |
(primary-opening |
|
5393 |
:utf-8 "„" :html "„" :latex "\"`" :texinfo "@quotedblbase{}") |
|
5394 |
(primary-closing |
|
5395 |
:utf-8 "“" :html "“" :latex "\"'" :texinfo "@quotedblleft{}") |
|
5396 |
(secondary-opening |
|
5397 |
:utf-8 "‚" :html "‚" :latex "\\glq{}" :texinfo "@quotesinglbase{}") |
|
5398 |
(secondary-closing |
|
5399 |
:utf-8 "‘" :html "‘" :latex "\\grq{}" :texinfo "@quoteleft{}") |
|
5400 |
(apostrophe :utf-8 "’" :html "’")) |
|
5401 |
("no" |
|
5402 |
;; https://nn.wikipedia.org/wiki/Sitatteikn |
|
5403 |
(primary-opening |
|
5404 |
:utf-8 "«" :html "«" :latex "\\guillemotleft{}" |
|
5405 |
:texinfo "@guillemetleft{}") |
|
5406 |
(primary-closing |
|
5407 |
:utf-8 "»" :html "»" :latex "\\guillemotright{}" |
|
5408 |
:texinfo "@guillemetright{}") |
|
5409 |
(secondary-opening :utf-8 "‘" :html "‘" :latex "`" :texinfo "`") |
|
5410 |
(secondary-closing :utf-8 "’" :html "’" :latex "'" :texinfo "'") |
|
5411 |
(apostrophe :utf-8 "’" :html "’")) |
|
5412 |
("nb" |
|
5413 |
;; https://nn.wikipedia.org/wiki/Sitatteikn |
|
5414 |
(primary-opening |
|
5415 |
:utf-8 "«" :html "«" :latex "\\guillemotleft{}" |
|
5416 |
:texinfo "@guillemetleft{}") |
|
5417 |
(primary-closing |
|
5418 |
:utf-8 "»" :html "»" :latex "\\guillemotright{}" |
|
5419 |
:texinfo "@guillemetright{}") |
|
5420 |
(secondary-opening :utf-8 "‘" :html "‘" :latex "`" :texinfo "`") |
|
5421 |
(secondary-closing :utf-8 "’" :html "’" :latex "'" :texinfo "'") |
|
5422 |
(apostrophe :utf-8 "’" :html "’")) |
|
5423 |
("nn" |
|
5424 |
;; https://nn.wikipedia.org/wiki/Sitatteikn |
|
5425 |
(primary-opening |
|
5426 |
:utf-8 "«" :html "«" :latex "\\guillemotleft{}" |
|
5427 |
:texinfo "@guillemetleft{}") |
|
5428 |
(primary-closing |
|
5429 |
:utf-8 "»" :html "»" :latex "\\guillemotright{}" |
|
5430 |
:texinfo "@guillemetright{}") |
|
5431 |
(secondary-opening :utf-8 "‘" :html "‘" :latex "`" :texinfo "`") |
|
5432 |
(secondary-closing :utf-8 "’" :html "’" :latex "'" :texinfo "'") |
|
5433 |
(apostrophe :utf-8 "’" :html "’")) |
|
5434 |
("ru" |
|
5435 |
;; http://ru.wikipedia.org/wiki/%D0%9A%D0%B0%D0%B2%D1%8B%D1%87%D0%BA%D0%B8#.D0.9A.D0.B0.D0.B2.D1.8B.D1.87.D0.BA.D0.B8.2C_.D0.B8.D1.81.D0.BF.D0.BE.D0.BB.D1.8C.D0.B7.D1.83.D0.B5.D0.BC.D1.8B.D0.B5_.D0.B2_.D1.80.D1.83.D1.81.D1.81.D0.BA.D0.BE.D0.BC_.D1.8F.D0.B7.D1.8B.D0.BA.D0.B5 |
|
5436 |
;; http://www.artlebedev.ru/kovodstvo/sections/104/ |
|
5437 |
(primary-opening :utf-8 "«" :html "«" :latex "{}<<" |
|
5438 |
:texinfo "@guillemetleft{}") |
|
5439 |
(primary-closing :utf-8 "»" :html "»" :latex ">>{}" |
|
5440 |
:texinfo "@guillemetright{}") |
|
5441 |
(secondary-opening |
|
5442 |
:utf-8 "„" :html "„" :latex "\\glqq{}" :texinfo "@quotedblbase{}") |
|
5443 |
(secondary-closing |
|
5444 |
:utf-8 "“" :html "“" :latex "\\grqq{}" :texinfo "@quotedblleft{}") |
|
5445 |
(apostrophe :utf-8 "’" :html: "'")) |
|
5446 |
("sl" |
|
5447 |
;; Based on https://sl.wikipedia.org/wiki/Narekovaj |
|
5448 |
(primary-opening :utf-8 "«" :html "«" :latex "{}<<" |
|
5449 |
:texinfo "@guillemetleft{}") |
|
5450 |
(primary-closing :utf-8 "»" :html "»" :latex ">>{}" |
|
5451 |
:texinfo "@guillemetright{}") |
|
5452 |
(secondary-opening |
|
5453 |
:utf-8 "„" :html "„" :latex "\\glqq{}" :texinfo "@quotedblbase{}") |
|
5454 |
(secondary-closing |
|
5455 |
:utf-8 "“" :html "“" :latex "\\grqq{}" :texinfo "@quotedblleft{}") |
|
5456 |
(apostrophe :utf-8 "’" :html "’")) |
|
5457 |
("sv" |
|
5458 |
;; Based on https://sv.wikipedia.org/wiki/Citattecken |
|
5459 |
(primary-opening :utf-8 "”" :html "”" :latex "’’" :texinfo "’’") |
|
5460 |
(primary-closing :utf-8 "”" :html "”" :latex "’’" :texinfo "’’") |
|
5461 |
(secondary-opening :utf-8 "’" :html "’" :latex "’" :texinfo "`") |
|
5462 |
(secondary-closing :utf-8 "’" :html "’" :latex "’" :texinfo "'") |
|
5463 |
(apostrophe :utf-8 "’" :html "’"))) |
|
5464 |
"Smart quotes translations. |
|
5465 |
|
|
5466 |
Alist whose CAR is a language string and CDR is an alist with |
|
5467 |
quote type as key and a plist associating various encodings to |
|
5468 |
their translation as value. |
|
5469 |
|
|
5470 |
A quote type can be any symbol among `primary-opening', |
|
5471 |
`primary-closing', `secondary-opening', `secondary-closing' and |
|
5472 |
`apostrophe'. |
|
5473 |
|
|
5474 |
Valid encodings include `:utf-8', `:html', `:latex' and |
|
5475 |
`:texinfo'. |
|
5476 |
|
|
5477 |
If no translation is found, the quote character is left as-is.") |
|
5478 |
|
|
5479 |
(defun org-export--smart-quote-status (s info) |
|
5480 |
"Return smart quote status at the beginning of string S. |
|
5481 |
INFO is the current export state, as a plist." |
|
5482 |
(let* ((parent (org-element-property :parent s)) |
|
5483 |
(cache (or (plist-get info :smart-quote-cache) |
|
5484 |
(let ((table (make-hash-table :test #'eq))) |
|
5485 |
(plist-put info :smart-quote-cache table) |
|
5486 |
table))) |
|
5487 |
(value (gethash parent cache 'missing-data))) |
|
5488 |
(if (not (eq value 'missing-data)) (cdr (assq s value)) |
|
5489 |
(let (level1-open full-status) |
|
5490 |
(org-element-map |
|
5491 |
(let ((secondary (org-element-secondary-p s))) |
|
5492 |
(if secondary (org-element-property secondary parent) |
|
5493 |
(org-element-contents parent))) |
|
5494 |
'plain-text |
|
5495 |
(lambda (text) |
|
5496 |
(let ((start 0) current-status) |
|
5497 |
(while (setq start (string-match "['\"]" text start)) |
|
5498 |
(push |
|
5499 |
(cond |
|
5500 |
((equal (match-string 0 text) "\"") |
|
5501 |
(setf level1-open (not level1-open)) |
|
5502 |
(if level1-open 'primary-opening 'primary-closing)) |
|
5503 |
;; Not already in a level 1 quote: this is an |
|
5504 |
;; apostrophe. |
|
5505 |
((not level1-open) 'apostrophe) |
|
5506 |
;; Extract previous char and next char. As |
|
5507 |
;; a special case, they can also be set to `blank', |
|
5508 |
;; `no-blank' or nil. Then determine if current |
|
5509 |
;; match is allowed as an opening quote or a closing |
|
5510 |
;; quote. |
|
5511 |
(t |
|
5512 |
(let* ((previous |
|
5513 |
(if (> start 0) (substring text (1- start) start) |
|
5514 |
(let ((p (org-export-get-previous-element |
|
5515 |
text info))) |
|
5516 |
(cond ((not p) nil) |
|
5517 |
((stringp p) (substring p -1)) |
|
5518 |
((memq (org-element-property :post-blank p) |
|
5519 |
'(0 nil)) |
|
5520 |
'no-blank) |
|
5521 |
(t 'blank))))) |
|
5522 |
(next |
|
5523 |
(if (< (1+ start) (length text)) |
|
5524 |
(substring text (1+ start) (+ start 2)) |
|
5525 |
(let ((n (org-export-get-next-element text info))) |
|
5526 |
(cond ((not n) nil) |
|
5527 |
((stringp n) (substring n 0 1)) |
|
5528 |
(t 'no-blank))))) |
|
5529 |
(allow-open |
|
5530 |
(and (if (stringp previous) |
|
5531 |
(string-match "\\s\"\\|\\s-\\|\\s(" |
|
5532 |
previous) |
|
5533 |
(memq previous '(blank nil))) |
|
5534 |
(if (stringp next) |
|
5535 |
(string-match "\\w\\|\\s.\\|\\s_" next) |
|
5536 |
(eq next 'no-blank)))) |
|
5537 |
(allow-close |
|
5538 |
(and (if (stringp previous) |
|
5539 |
(string-match "\\w\\|\\s.\\|\\s_" previous) |
|
5540 |
(eq previous 'no-blank)) |
|
5541 |
(if (stringp next) |
|
5542 |
(string-match "\\s-\\|\\s)\\|\\s.\\|\\s\"" |
|
5543 |
next) |
|
5544 |
(memq next '(blank nil)))))) |
|
5545 |
(cond |
|
5546 |
((and allow-open allow-close) (error "Should not happen")) |
|
5547 |
(allow-open 'secondary-opening) |
|
5548 |
(allow-close 'secondary-closing) |
|
5549 |
(t 'apostrophe))))) |
|
5550 |
current-status) |
|
5551 |
(cl-incf start)) |
|
5552 |
(when current-status |
|
5553 |
(push (cons text (nreverse current-status)) full-status)))) |
|
5554 |
info nil org-element-recursive-objects) |
|
5555 |
(puthash parent full-status cache) |
|
5556 |
(cdr (assq s full-status)))))) |
|
5557 |
|
|
5558 |
(defun org-export-activate-smart-quotes (s encoding info &optional original) |
|
5559 |
"Replace regular quotes with \"smart\" quotes in string S. |
|
5560 |
|
|
5561 |
ENCODING is a symbol among `:html', `:latex', `:texinfo' and |
|
5562 |
`:utf-8'. INFO is a plist used as a communication channel. |
|
5563 |
|
|
5564 |
The function has to retrieve information about string |
|
5565 |
surroundings in parse tree. It can only happen with an |
|
5566 |
unmodified string. Thus, if S has already been through another |
|
5567 |
process, a non-nil ORIGINAL optional argument will provide that |
|
5568 |
original string. |
|
5569 |
|
|
5570 |
Return the new string." |
|
5571 |
(let ((quote-status |
|
5572 |
(copy-sequence (org-export--smart-quote-status (or original s) info)))) |
|
5573 |
(replace-regexp-in-string |
|
5574 |
"['\"]" |
|
5575 |
(lambda (match) |
|
5576 |
(or (plist-get |
|
5577 |
(cdr (assq (pop quote-status) |
|
5578 |
(cdr (assoc (plist-get info :language) |
|
5579 |
org-export-smart-quotes-alist)))) |
|
5580 |
encoding) |
|
5581 |
match)) |
|
5582 |
s nil t))) |
|
5583 |
|
|
5584 |
;;;; Topology |
|
5585 |
;; |
|
5586 |
;; Here are various functions to retrieve information about the |
|
5587 |
;; neighborhood of a given element or object. Neighbors of interest |
|
5588 |
;; are direct parent (`org-export-get-parent'), parent headline |
|
5589 |
;; (`org-export-get-parent-headline'), first element containing an |
|
5590 |
;; object, (`org-export-get-parent-element'), parent table |
|
5591 |
;; (`org-export-get-parent-table'), previous element or object |
|
5592 |
;; (`org-export-get-previous-element') and next element or object |
|
5593 |
;; (`org-export-get-next-element'). |
|
5594 |
|
|
5595 |
;; defsubst org-export-get-parent must be defined before first use |
|
5596 |
|
|
5597 |
(defun org-export-get-parent-headline (blob) |
|
5598 |
"Return BLOB parent headline or nil. |
|
5599 |
BLOB is the element or object being considered." |
|
5600 |
(org-element-lineage blob '(headline))) |
|
5601 |
|
|
5602 |
(defun org-export-get-parent-element (object) |
|
5603 |
"Return first element containing OBJECT or nil. |
|
5604 |
OBJECT is the object to consider." |
|
5605 |
(org-element-lineage object org-element-all-elements)) |
|
5606 |
|
|
5607 |
(defun org-export-get-parent-table (object) |
|
5608 |
"Return OBJECT parent table or nil. |
|
5609 |
OBJECT is either a `table-cell' or `table-element' type object." |
|
5610 |
(org-element-lineage object '(table))) |
|
5611 |
|
|
5612 |
(defun org-export-get-previous-element (blob info &optional n) |
|
5613 |
"Return previous element or object. |
|
5614 |
|
|
5615 |
BLOB is an element or object. INFO is a plist used as |
|
5616 |
a communication channel. Return previous exportable element or |
|
5617 |
object, a string, or nil. |
|
5618 |
|
|
5619 |
When optional argument N is a positive integer, return a list |
|
5620 |
containing up to N siblings before BLOB, from farthest to |
|
5621 |
closest. With any other non-nil value, return a list containing |
|
5622 |
all of them." |
|
5623 |
(let* ((secondary (org-element-secondary-p blob)) |
|
5624 |
(parent (org-export-get-parent blob)) |
|
5625 |
(siblings |
|
5626 |
(if secondary (org-element-property secondary parent) |
|
5627 |
(org-element-contents parent))) |
|
5628 |
prev) |
|
5629 |
(catch 'exit |
|
5630 |
(dolist (obj (cdr (memq blob (reverse siblings))) prev) |
|
5631 |
(cond ((memq obj (plist-get info :ignore-list))) |
|
5632 |
((null n) (throw 'exit obj)) |
|
5633 |
((not (wholenump n)) (push obj prev)) |
|
5634 |
((zerop n) (throw 'exit prev)) |
|
5635 |
(t (cl-decf n) (push obj prev))))))) |
|
5636 |
|
|
5637 |
(defun org-export-get-next-element (blob info &optional n) |
|
5638 |
"Return next element or object. |
|
5639 |
|
|
5640 |
BLOB is an element or object. INFO is a plist used as |
|
5641 |
a communication channel. Return next exportable element or |
|
5642 |
object, a string, or nil. |
|
5643 |
|
|
5644 |
When optional argument N is a positive integer, return a list |
|
5645 |
containing up to N siblings after BLOB, from closest to farthest. |
|
5646 |
With any other non-nil value, return a list containing all of |
|
5647 |
them." |
|
5648 |
(let* ((secondary (org-element-secondary-p blob)) |
|
5649 |
(parent (org-export-get-parent blob)) |
|
5650 |
(siblings |
|
5651 |
(cdr (memq blob |
|
5652 |
(if secondary (org-element-property secondary parent) |
|
5653 |
(org-element-contents parent))))) |
|
5654 |
next) |
|
5655 |
(catch 'exit |
|
5656 |
(dolist (obj siblings (nreverse next)) |
|
5657 |
(cond ((memq obj (plist-get info :ignore-list))) |
|
5658 |
((null n) (throw 'exit obj)) |
|
5659 |
((not (wholenump n)) (push obj next)) |
|
5660 |
((zerop n) (throw 'exit (nreverse next))) |
|
5661 |
(t (cl-decf n) (push obj next))))))) |
|
5662 |
|
|
5663 |
|
|
5664 |
;;;; Translation |
|
5665 |
;; |
|
5666 |
;; `org-export-translate' translates a string according to the language |
|
5667 |
;; specified by the LANGUAGE keyword. `org-export-dictionary' contains |
|
5668 |
;; the dictionary used for the translation. |
|
5669 |
|
|
5670 |
(defconst org-export-dictionary |
|
5671 |
'(("%e %n: %c" |
|
5672 |
("fr" :default "%e %n : %c" :html "%e %n : %c")) |
|
5673 |
("Author" |
|
5674 |
("ar" :default "تأليف") |
|
5675 |
("ca" :default "Autor") |
|
5676 |
("cs" :default "Autor") |
|
5677 |
("da" :default "Forfatter") |
|
5678 |
("de" :default "Autor") |
|
5679 |
("eo" :html "Aŭtoro") |
|
5680 |
("es" :default "Autor") |
|
5681 |
("et" :default "Autor") |
|
5682 |
("fi" :html "Tekijä") |
|
5683 |
("fr" :default "Auteur") |
|
5684 |
("hu" :default "Szerzõ") |
|
5685 |
("is" :html "Höfundur") |
|
5686 |
("it" :default "Autore") |
|
5687 |
("ja" :default "著者" :html "著者") |
|
5688 |
("nl" :default "Auteur") |
|
5689 |
("no" :default "Forfatter") |
|
5690 |
("nb" :default "Forfatter") |
|
5691 |
("nn" :default "Forfattar") |
|
5692 |
("pl" :default "Autor") |
|
5693 |
("pt_BR" :default "Autor") |
|
5694 |
("ru" :html "Автор" :utf-8 "Автор") |
|
5695 |
("sl" :default "Avtor") |
|
5696 |
("sv" :html "Författare") |
|
5697 |
("uk" :html "Автор" :utf-8 "Автор") |
|
5698 |
("zh-CN" :html "作者" :utf-8 "作者") |
|
5699 |
("zh-TW" :html "作者" :utf-8 "作者")) |
|
5700 |
("Continued from previous page" |
|
5701 |
("ar" :default "تتمة الصفحة السابقة") |
|
5702 |
("cs" :default "Pokračování z předchozí strany") |
|
5703 |
("de" :default "Fortsetzung von vorheriger Seite") |
|
5704 |
("es" :html "Continúa de la página anterior" :ascii "Continua de la pagina anterior" :default "Continúa de la página anterior") |
|
5705 |
("fr" :default "Suite de la page précédente") |
|
5706 |
("it" :default "Continua da pagina precedente") |
|
5707 |
("ja" :default "前ページからの続き") |
|
5708 |
("nl" :default "Vervolg van vorige pagina") |
|
5709 |
("pt" :default "Continuação da página anterior") |
|
5710 |
("ru" :html "(Продолжение)" |
|
5711 |
:utf-8 "(Продолжение)") |
|
5712 |
("sl" :default "Nadaljevanje s prejšnje strani")) |
|
5713 |
("Continued on next page" |
|
5714 |
("ar" :default "التتمة في الصفحة التالية") |
|
5715 |
("cs" :default "Pokračuje na další stránce") |
|
5716 |
("de" :default "Fortsetzung nächste Seite") |
|
5717 |
("es" :html "Continúa en la siguiente página" :ascii "Continua en la siguiente pagina" :default "Continúa en la siguiente página") |
|
5718 |
("fr" :default "Suite page suivante") |
|
5719 |
("it" :default "Continua alla pagina successiva") |
|
5720 |
("ja" :default "次ページに続く") |
|
5721 |
("nl" :default "Vervolg op volgende pagina") |
|
5722 |
("pt" :default "Continua na página seguinte") |
|
5723 |
("ru" :html "(Продолжение следует)" |
|
5724 |
:utf-8 "(Продолжение следует)") |
|
5725 |
("sl" :default "Nadaljevanje na naslednji strani")) |
|
5726 |
("Created" |
|
5727 |
("cs" :default "Vytvořeno") |
|
5728 |
("sl" :default "Ustvarjeno")) |
|
5729 |
("Date" |
|
5730 |
("ar" :default "بتاريخ") |
|
5731 |
("ca" :default "Data") |
|
5732 |
("cs" :default "Datum") |
|
5733 |
("da" :default "Dato") |
|
5734 |
("de" :default "Datum") |
|
5735 |
("eo" :default "Dato") |
|
5736 |
("es" :default "Fecha") |
|
5737 |
("et" :html "Kuupäev" :utf-8 "Kuupäev") |
|
5738 |
("fi" :html "Päivämäärä") |
|
5739 |
("hu" :html "Dátum") |
|
5740 |
("is" :default "Dagsetning") |
|
5741 |
("it" :default "Data") |
|
5742 |
("ja" :default "日付" :html "日付") |
|
5743 |
("nl" :default "Datum") |
|
5744 |
("no" :default "Dato") |
|
5745 |
("nb" :default "Dato") |
|
5746 |
("nn" :default "Dato") |
|
5747 |
("pl" :default "Data") |
|
5748 |
("pt_BR" :default "Data") |
|
5749 |
("ru" :html "Дата" :utf-8 "Дата") |
|
5750 |
("sl" :default "Datum") |
|
5751 |
("sv" :default "Datum") |
|
5752 |
("uk" :html "Дата" :utf-8 "Дата") |
|
5753 |
("zh-CN" :html "日期" :utf-8 "日期") |
|
5754 |
("zh-TW" :html "日期" :utf-8 "日期")) |
|
5755 |
("Equation" |
|
5756 |
("ar" :default "معادلة") |
|
5757 |
("cs" :default "Rovnice") |
|
5758 |
("da" :default "Ligning") |
|
5759 |
("de" :default "Gleichung") |
|
5760 |
("es" :ascii "Ecuacion" :html "Ecuación" :default "Ecuación") |
|
5761 |
("et" :html "Võrrand" :utf-8 "Võrrand") |
|
5762 |
("fr" :ascii "Equation" :default "Équation") |
|
5763 |
("is" :default "Jafna") |
|
5764 |
("ja" :default "方程式") |
|
5765 |
("no" :default "Ligning") |
|
5766 |
("nb" :default "Ligning") |
|
5767 |
("nn" :default "Likning") |
|
5768 |
("pt_BR" :html "Equação" :default "Equação" :ascii "Equacao") |
|
5769 |
("ru" :html "Уравнение" |
|
5770 |
:utf-8 "Уравнение") |
|
5771 |
("sl" :default "Enačba") |
|
5772 |
("sv" :default "Ekvation") |
|
5773 |
("zh-CN" :html "方程" :utf-8 "方程")) |
|
5774 |
("Figure" |
|
5775 |
("ar" :default "شكل") |
|
5776 |
("cs" :default "Obrázek") |
|
5777 |
("da" :default "Figur") |
|
5778 |
("de" :default "Abbildung") |
|
5779 |
("es" :default "Figura") |
|
5780 |
("et" :default "Joonis") |
|
5781 |
("is" :default "Mynd") |
|
5782 |
("ja" :default "図" :html "図") |
|
5783 |
("no" :default "Illustrasjon") |
|
5784 |
("nb" :default "Illustrasjon") |
|
5785 |
("nn" :default "Illustrasjon") |
|
5786 |
("pt_BR" :default "Figura") |
|
5787 |
("ru" :html "Рисунок" :utf-8 "Рисунок") |
|
5788 |
("sv" :default "Illustration") |
|
5789 |
("zh-CN" :html "图" :utf-8 "图")) |
|
5790 |
("Figure %d:" |
|
5791 |
("ar" :default "شكل %d:") |
|
5792 |
("cs" :default "Obrázek %d:") |
|
5793 |
("da" :default "Figur %d") |
|
5794 |
("de" :default "Abbildung %d:") |
|
5795 |
("es" :default "Figura %d:") |
|
5796 |
("et" :default "Joonis %d:") |
|
5797 |
("fr" :default "Figure %d :" :html "Figure %d :") |
|
5798 |
("is" :default "Mynd %d") |
|
5799 |
("ja" :default "図%d: " :html "図%d: ") |
|
5800 |
("no" :default "Illustrasjon %d") |
|
5801 |
("nb" :default "Illustrasjon %d") |
|
5802 |
("nn" :default "Illustrasjon %d") |
|
5803 |
("pt_BR" :default "Figura %d:") |
|
5804 |
("ru" :html "Рис. %d.:" :utf-8 "Рис. %d.:") |
|
5805 |
("sl" :default "Slika %d") |
|
5806 |
("sv" :default "Illustration %d") |
|
5807 |
("zh-CN" :html "图%d " :utf-8 "图%d ")) |
|
5808 |
("Footnotes" |
|
5809 |
("ar" :default "الهوامش") |
|
5810 |
("ca" :html "Peus de pàgina") |
|
5811 |
("cs" :default "Poznámky pod čarou") |
|
5812 |
("da" :default "Fodnoter") |
|
5813 |
("de" :html "Fußnoten" :default "Fußnoten") |
|
5814 |
("eo" :default "Piednotoj") |
|
5815 |
("es" :ascii "Nota al pie de pagina" :html "Nota al pie de página" :default "Nota al pie de página") |
|
5816 |
("et" :html "Allmärkused" :utf-8 "Allmärkused") |
|
5817 |
("fi" :default "Alaviitteet") |
|
5818 |
("fr" :default "Notes de bas de page") |
|
5819 |
("hu" :html "Lábjegyzet") |
|
5820 |
("is" :html "Aftanmálsgreinar") |
|
5821 |
("it" :html "Note a piè di pagina") |
|
5822 |
("ja" :default "脚注" :html "脚注") |
|
5823 |
("nl" :default "Voetnoten") |
|
5824 |
("no" :default "Fotnoter") |
|
5825 |
("nb" :default "Fotnoter") |
|
5826 |
("nn" :default "Fotnotar") |
|
5827 |
("pl" :default "Przypis") |
|
5828 |
("pt_BR" :html "Notas de Rodapé" :default "Notas de Rodapé" :ascii "Notas de Rodape") |
|
5829 |
("ru" :html "Сноски" :utf-8 "Сноски") |
|
5830 |
("sl" :default "Opombe") |
|
5831 |
("sv" :default "Fotnoter") |
|
5832 |
("uk" :html "Примітки" |
|
5833 |
:utf-8 "Примітки") |
|
5834 |
("zh-CN" :html "脚注" :utf-8 "脚注") |
|
5835 |
("zh-TW" :html "腳註" :utf-8 "腳註")) |
|
5836 |
("List of Listings" |
|
5837 |
("ar" :default "قائمة بالبرامج") |
|
5838 |
("cs" :default "Seznam programů") |
|
5839 |
("da" :default "Programmer") |
|
5840 |
("de" :default "Programmauflistungsverzeichnis") |
|
5841 |
("es" :ascii "Indice de Listados de programas" :html "Índice de Listados de programas" :default "Índice de Listados de programas") |
|
5842 |
("et" :default "Loendite nimekiri") |
|
5843 |
("fr" :default "Liste des programmes") |
|
5844 |
("ja" :default "ソースコード目次") |
|
5845 |
("no" :default "Dataprogrammer") |
|
5846 |
("nb" :default "Dataprogrammer") |
|
5847 |
("ru" :html "Список распечаток" |
|
5848 |
:utf-8 "Список распечаток") |
|
5849 |
("sl" :default "Seznam programskih izpisov") |
|
5850 |
("zh-CN" :html "代码目录" :utf-8 "代码目录")) |
|
5851 |
("List of Tables" |
|
5852 |
("ar" :default "قائمة بالجداول") |
|
5853 |
("cs" :default "Seznam tabulek") |
|
5854 |
("da" :default "Tabeller") |
|
5855 |
("de" :default "Tabellenverzeichnis") |
|
5856 |
("es" :ascii "Indice de tablas" :html "Índice de tablas" :default "Índice de tablas") |
|
5857 |
("et" :default "Tabelite nimekiri") |
|
5858 |
("fr" :default "Liste des tableaux") |
|
5859 |
("is" :default "Töfluskrá" :html "Töfluskrá") |
|
5860 |
("ja" :default "表目次") |
|
5861 |
("no" :default "Tabeller") |
|
5862 |
("nb" :default "Tabeller") |
|
5863 |
("nn" :default "Tabeller") |
|
5864 |
("pt_BR" :default "Índice de Tabelas" :ascii "Indice de Tabelas") |
|
5865 |
("ru" :html "Список таблиц" |
|
5866 |
:utf-8 "Список таблиц") |
|
5867 |
("sl" :default "Seznam tabel") |
|
5868 |
("sv" :default "Tabeller") |
|
5869 |
("zh-CN" :html "表格目录" :utf-8 "表格目录")) |
|
5870 |
("Listing" |
|
5871 |
("ar" :default "برنامج") |
|
5872 |
("cs" :default "Program") |
|
5873 |
("da" :default "Program") |
|
5874 |
("de" :default "Programmlisting") |
|
5875 |
("es" :default "Listado de programa") |
|
5876 |
("et" :default "Loend") |
|
5877 |
("fr" :default "Programme" :html "Programme") |
|
5878 |
("ja" :default "ソースコード") |
|
5879 |
("no" :default "Dataprogram") |
|
5880 |
("nb" :default "Dataprogram") |
|
5881 |
("pt_BR" :default "Listagem") |
|
5882 |
("ru" :html "Распечатка" |
|
5883 |
:utf-8 "Распечатка") |
|
5884 |
("sl" :default "Izpis programa") |
|
5885 |
("zh-CN" :html "代码" :utf-8 "代码")) |
|
5886 |
("Listing %d:" |
|
5887 |
("ar" :default "برنامج %d:") |
|
5888 |
("cs" :default "Program %d:") |
|
5889 |
("da" :default "Program %d") |
|
5890 |
("de" :default "Programmlisting %d") |
|
5891 |
("es" :default "Listado de programa %d") |
|
5892 |
("et" :default "Loend %d") |
|
5893 |
("fr" :default "Programme %d :" :html "Programme %d :") |
|
5894 |
("ja" :default "ソースコード%d:") |
|
5895 |
("no" :default "Dataprogram %d") |
|
5896 |
("nb" :default "Dataprogram %d") |
|
5897 |
("pt_BR" :default "Listagem %d") |
|
5898 |
("ru" :html "Распечатка %d.:" |
|
5899 |
:utf-8 "Распечатка %d.:") |
|
5900 |
("sl" :default "Izpis programa %d") |
|
5901 |
("zh-CN" :html "代码%d " :utf-8 "代码%d ")) |
|
5902 |
("References" |
|
5903 |
("ar" :default "المراجع") |
|
5904 |
("cs" :default "Reference") |
|
5905 |
("fr" :ascii "References" :default "Références") |
|
5906 |
("de" :default "Quellen") |
|
5907 |
("es" :default "Referencias") |
|
5908 |
("sl" :default "Reference")) |
|
5909 |
("See figure %s" |
|
5910 |
("cs" :default "Viz obrázek %s") |
|
5911 |
("fr" :default "cf. figure %s" |
|
5912 |
:html "cf. figure %s" :latex "cf.~figure~%s") |
|
5913 |
("sl" :default "Glej sliko %s")) |
|
5914 |
("See listing %s" |
|
5915 |
("cs" :default "Viz program %s") |
|
5916 |
("fr" :default "cf. programme %s" |
|
5917 |
:html "cf. programme %s" :latex "cf.~programme~%s") |
|
5918 |
("sl" :default "Glej izpis programa %s")) |
|
5919 |
("See section %s" |
|
5920 |
("ar" :default "انظر قسم %s") |
|
5921 |
("cs" :default "Viz sekce %s") |
|
5922 |
("da" :default "jævnfør afsnit %s") |
|
5923 |
("de" :default "siehe Abschnitt %s") |
|
5924 |
("es" :ascii "Vea seccion %s" :html "Vea sección %s" :default "Vea sección %s") |
|
5925 |
("et" :html "Vaata peatükki %s" :utf-8 "Vaata peatükki %s") |
|
5926 |
("fr" :default "cf. section %s") |
|
5927 |
("ja" :default "セクション %s を参照") |
|
5928 |
("pt_BR" :html "Veja a seção %s" :default "Veja a seção %s" |
|
5929 |
:ascii "Veja a secao %s") |
|
5930 |
("ru" :html "См. раздел %s" |
|
5931 |
:utf-8 "См. раздел %s") |
|
5932 |
("sl" :default "Glej poglavje %d") |
|
5933 |
("zh-CN" :html "参见第%s节" :utf-8 "参见第%s节")) |
|
5934 |
("See table %s" |
|
5935 |
("cs" :default "Viz tabulka %s") |
|
5936 |
("fr" :default "cf. tableau %s" |
|
5937 |
:html "cf. tableau %s" :latex "cf.~tableau~%s") |
|
5938 |
("sl" :default "Glej tabelo %s")) |
|
5939 |
("Table" |
|
5940 |
("ar" :default "جدول") |
|
5941 |
("cs" :default "Tabulka") |
|
5942 |
("de" :default "Tabelle") |
|
5943 |
("es" :default "Tabla") |
|
5944 |
("et" :default "Tabel") |
|
5945 |
("fr" :default "Tableau") |
|
5946 |
("is" :default "Tafla") |
|
5947 |
("ja" :default "表" :html "表") |
|
5948 |
("pt_BR" :default "Tabela") |
|
5949 |
("ru" :html "Таблица" |
|
5950 |
:utf-8 "Таблица") |
|
5951 |
("zh-CN" :html "表" :utf-8 "表")) |
|
5952 |
("Table %d:" |
|
5953 |
("ar" :default "جدول %d:") |
|
5954 |
("cs" :default "Tabulka %d:") |
|
5955 |
("da" :default "Tabel %d") |
|
5956 |
("de" :default "Tabelle %d") |
|
5957 |
("es" :default "Tabla %d") |
|
5958 |
("et" :default "Tabel %d") |
|
5959 |
("fr" :default "Tableau %d :") |
|
5960 |
("is" :default "Tafla %d") |
|
5961 |
("ja" :default "表%d:" :html "表%d:") |
|
5962 |
("no" :default "Tabell %d") |
|
5963 |
("nb" :default "Tabell %d") |
|
5964 |
("nn" :default "Tabell %d") |
|
5965 |
("pt_BR" :default "Tabela %d") |
|
5966 |
("ru" :html "Таблица %d.:" |
|
5967 |
:utf-8 "Таблица %d.:") |
|
5968 |
("sl" :default "Tabela %d") |
|
5969 |
("sv" :default "Tabell %d") |
|
5970 |
("zh-CN" :html "表%d " :utf-8 "表%d ")) |
|
5971 |
("Table of Contents" |
|
5972 |
("ar" :default "قائمة المحتويات") |
|
5973 |
("ca" :html "Índex") |
|
5974 |
("cs" :default "Obsah") |
|
5975 |
("da" :default "Indhold") |
|
5976 |
("de" :default "Inhaltsverzeichnis") |
|
5977 |
("eo" :default "Enhavo") |
|
5978 |
("es" :ascii "Indice" :html "Índice" :default "Índice") |
|
5979 |
("et" :default "Sisukord") |
|
5980 |
("fi" :html "Sisällysluettelo") |
|
5981 |
("fr" :ascii "Sommaire" :default "Table des matières") |
|
5982 |
("hu" :html "Tartalomjegyzék") |
|
5983 |
("is" :default "Efnisyfirlit") |
|
5984 |
("it" :default "Indice") |
|
5985 |
("ja" :default "目次" :html "目次") |
|
5986 |
("nl" :default "Inhoudsopgave") |
|
5987 |
("no" :default "Innhold") |
|
5988 |
("nb" :default "Innhold") |
|
5989 |
("nn" :default "Innhald") |
|
5990 |
("pl" :html "Spis treści") |
|
5991 |
("pt_BR" :html "Índice" :utf8 "Índice" :ascii "Indice") |
|
5992 |
("ru" :html "Содержание" |
|
5993 |
:utf-8 "Содержание") |
|
5994 |
("sl" :default "Kazalo") |
|
5995 |
("sv" :html "Innehåll") |
|
5996 |
("uk" :html "Зміст" :utf-8 "Зміст") |
|
5997 |
("zh-CN" :html "目录" :utf-8 "目录") |
|
5998 |
("zh-TW" :html "目錄" :utf-8 "目錄")) |
|
5999 |
("Unknown reference" |
|
6000 |
("ar" :default "مرجع غير معرّف") |
|
6001 |
("da" :default "ukendt reference") |
|
6002 |
("de" :default "Unbekannter Verweis") |
|
6003 |
("es" :default "Referencia desconocida") |
|
6004 |
("et" :default "Tundmatu viide") |
|
6005 |
("fr" :ascii "Destination inconnue" :default "Référence inconnue") |
|
6006 |
("ja" :default "不明な参照先") |
|
6007 |
("pt_BR" :default "Referência desconhecida" |
|
6008 |
:ascii "Referencia desconhecida") |
|
6009 |
("ru" :html "Неизвестная ссылка" |
|
6010 |
:utf-8 "Неизвестная ссылка") |
|
6011 |
("sl" :default "Neznana referenca") |
|
6012 |
("zh-CN" :html "未知引用" :utf-8 "未知引用"))) |
|
6013 |
"Dictionary for export engine. |
|
6014 |
|
|
6015 |
Alist whose car is the string to translate and cdr is an alist |
|
6016 |
whose car is the language string and cdr is a plist whose |
|
6017 |
properties are possible charsets and values translated terms. |
|
6018 |
|
|
6019 |
It is used as a database for `org-export-translate'. Since this |
|
6020 |
function returns the string as-is if no translation was found, |
|
6021 |
the variable only needs to record values different from the |
|
6022 |
entry.") |
|
6023 |
|
|
6024 |
(defun org-export-translate (s encoding info) |
|
6025 |
"Translate string S according to language specification. |
|
6026 |
|
|
6027 |
ENCODING is a symbol among `:ascii', `:html', `:latex', `:latin1' |
|
6028 |
and `:utf-8'. INFO is a plist used as a communication channel. |
|
6029 |
|
|
6030 |
Translation depends on `:language' property. Return the |
|
6031 |
translated string. If no translation is found, try to fall back |
|
6032 |
to `:default' encoding. If it fails, return S." |
|
6033 |
(let* ((lang (plist-get info :language)) |
|
6034 |
(translations (cdr (assoc lang |
|
6035 |
(cdr (assoc s org-export-dictionary)))))) |
|
6036 |
(or (plist-get translations encoding) |
|
6037 |
(plist-get translations :default) |
|
6038 |
s))) |
|
6039 |
|
|
6040 |
|
|
6041 |
|
|
6042 |
;;; Asynchronous Export |
|
6043 |
;; |
|
6044 |
;; `org-export-async-start' is the entry point for asynchronous |
|
6045 |
;; export. It recreates current buffer (including visibility, |
|
6046 |
;; narrowing and visited file) in an external Emacs process, and |
|
6047 |
;; evaluates a command there. It then applies a function on the |
|
6048 |
;; returned results in the current process. |
|
6049 |
;; |
|
6050 |
;; At a higher level, `org-export-to-buffer' and `org-export-to-file' |
|
6051 |
;; allow exporting to a buffer or a file, asynchronously or not. |
|
6052 |
;; |
|
6053 |
;; `org-export-output-file-name' is an auxiliary function meant to be |
|
6054 |
;; used with `org-export-to-file'. With a given extension, it tries |
|
6055 |
;; to provide a canonical file name to write export output to. |
|
6056 |
;; |
|
6057 |
;; Asynchronously generated results are never displayed directly. |
|
6058 |
;; Instead, they are stored in `org-export-stack-contents'. They can |
|
6059 |
;; then be retrieved by calling `org-export-stack'. |
|
6060 |
;; |
|
6061 |
;; Export Stack is viewed through a dedicated major mode |
|
6062 |
;;`org-export-stack-mode' and tools: `org-export-stack-refresh', |
|
6063 |
;;`org-export-stack-delete', `org-export-stack-view' and |
|
6064 |
;;`org-export-stack-clear'. |
|
6065 |
;; |
|
6066 |
;; For back-ends, `org-export-add-to-stack' add a new source to stack. |
|
6067 |
;; It should be used whenever `org-export-async-start' is called. |
|
6068 |
|
|
6069 |
(defmacro org-export-async-start (fun &rest body) |
|
6070 |
"Call function FUN on the results returned by BODY evaluation. |
|
6071 |
|
|
6072 |
FUN is an anonymous function of one argument. BODY evaluation |
|
6073 |
happens in an asynchronous process, from a buffer which is an |
|
6074 |
exact copy of the current one. |
|
6075 |
|
|
6076 |
Use `org-export-add-to-stack' in FUN in order to register results |
|
6077 |
in the stack. |
|
6078 |
|
|
6079 |
This is a low level function. See also `org-export-to-buffer' |
|
6080 |
and `org-export-to-file' for more specialized functions." |
|
6081 |
(declare (indent 1) (debug t)) |
|
6082 |
(org-with-gensyms (process temp-file copy-fun proc-buffer coding) |
|
6083 |
;; Write the full sexp evaluating BODY in a copy of the current |
|
6084 |
;; buffer to a temporary file, as it may be too long for program |
|
6085 |
;; args in `start-process'. |
|
6086 |
`(with-temp-message "Initializing asynchronous export process" |
|
6087 |
(let ((,copy-fun (org-export--generate-copy-script (current-buffer))) |
|
6088 |
(,temp-file (make-temp-file "org-export-process")) |
|
6089 |
(,coding buffer-file-coding-system)) |
|
6090 |
(with-temp-file ,temp-file |
|
6091 |
(insert |
|
6092 |
;; Null characters (from variable values) are inserted |
|
6093 |
;; within the file. As a consequence, coding system for |
|
6094 |
;; buffer contents will not be recognized properly. So, |
|
6095 |
;; we make sure it is the same as the one used to display |
|
6096 |
;; the original buffer. |
|
6097 |
(format ";; -*- coding: %s; -*-\n%S" |
|
6098 |
,coding |
|
6099 |
`(with-temp-buffer |
|
6100 |
(when org-export-async-debug '(setq debug-on-error t)) |
|
6101 |
;; Ignore `kill-emacs-hook' and code evaluation |
|
6102 |
;; queries from Babel as we need a truly |
|
6103 |
;; non-interactive process. |
|
6104 |
(setq kill-emacs-hook nil |
|
6105 |
org-babel-confirm-evaluate-answer-no t) |
|
6106 |
;; Initialize export framework. |
|
6107 |
(require 'ox) |
|
6108 |
;; Re-create current buffer there. |
|
6109 |
(funcall ,,copy-fun) |
|
6110 |
(restore-buffer-modified-p nil) |
|
6111 |
;; Sexp to evaluate in the buffer. |
|
6112 |
(print (progn ,,@body)))))) |
|
6113 |
;; Start external process. |
|
6114 |
(let* ((process-connection-type nil) |
|
6115 |
(,proc-buffer (generate-new-buffer-name "*Org Export Process*")) |
|
6116 |
(,process |
|
6117 |
(apply |
|
6118 |
#'start-process |
|
6119 |
(append |
|
6120 |
(list "org-export-process" |
|
6121 |
,proc-buffer |
|
6122 |
(expand-file-name invocation-name invocation-directory) |
|
6123 |
"--batch") |
|
6124 |
(if org-export-async-init-file |
|
6125 |
(list "-Q" "-l" org-export-async-init-file) |
|
6126 |
(list "-l" user-init-file)) |
|
6127 |
(list "-l" ,temp-file))))) |
|
6128 |
;; Register running process in stack. |
|
6129 |
(org-export-add-to-stack (get-buffer ,proc-buffer) nil ,process) |
|
6130 |
;; Set-up sentinel in order to catch results. |
|
6131 |
(let ((handler ,fun)) |
|
6132 |
(set-process-sentinel |
|
6133 |
,process |
|
6134 |
`(lambda (p status) |
|
6135 |
(let ((proc-buffer (process-buffer p))) |
|
6136 |
(when (eq (process-status p) 'exit) |
|
6137 |
(unwind-protect |
|
6138 |
(if (zerop (process-exit-status p)) |
|
6139 |
(unwind-protect |
|
6140 |
(let ((results |
|
6141 |
(with-current-buffer proc-buffer |
|
6142 |
(goto-char (point-max)) |
|
6143 |
(backward-sexp) |
|
6144 |
(read (current-buffer))))) |
|
6145 |
(funcall ,handler results)) |
|
6146 |
(unless org-export-async-debug |
|
6147 |
(and (get-buffer proc-buffer) |
|
6148 |
(kill-buffer proc-buffer)))) |
|
6149 |
(org-export-add-to-stack proc-buffer nil p) |
|
6150 |
(ding) |
|
6151 |
(message "Process `%s' exited abnormally" p)) |
|
6152 |
(unless org-export-async-debug |
|
6153 |
(delete-file ,,temp-file))))))))))))) |
|
6154 |
|
|
6155 |
;;;###autoload |
|
6156 |
(defun org-export-to-buffer |
|
6157 |
(backend buffer |
|
6158 |
&optional async subtreep visible-only body-only ext-plist |
|
6159 |
post-process) |
|
6160 |
"Call `org-export-as' with output to a specified buffer. |
|
6161 |
|
|
6162 |
BACKEND is either an export back-end, as returned by, e.g., |
|
6163 |
`org-export-create-backend', or a symbol referring to |
|
6164 |
a registered back-end. |
|
6165 |
|
|
6166 |
BUFFER is the name of the output buffer. If it already exists, |
|
6167 |
it will be erased first, otherwise, it will be created. |
|
6168 |
|
|
6169 |
A non-nil optional argument ASYNC means the process should happen |
|
6170 |
asynchronously. The resulting buffer should then be accessible |
|
6171 |
through the `org-export-stack' interface. When ASYNC is nil, the |
|
6172 |
buffer is displayed if `org-export-show-temporary-export-buffer' |
|
6173 |
is non-nil. |
|
6174 |
|
|
6175 |
Optional arguments SUBTREEP, VISIBLE-ONLY, BODY-ONLY and |
|
6176 |
EXT-PLIST are similar to those used in `org-export-as', which |
|
6177 |
see. |
|
6178 |
|
|
6179 |
Optional argument POST-PROCESS is a function which should accept |
|
6180 |
no argument. It is always called within the current process, |
|
6181 |
from BUFFER, with point at its beginning. Export back-ends can |
|
6182 |
use it to set a major mode there, e.g, |
|
6183 |
|
|
6184 |
(defun org-latex-export-as-latex |
|
6185 |
(&optional async subtreep visible-only body-only ext-plist) |
|
6186 |
(interactive) |
|
6187 |
(org-export-to-buffer \\='latex \"*Org LATEX Export*\" |
|
6188 |
async subtreep visible-only body-only ext-plist (lambda () (LaTeX-mode)))) |
|
6189 |
|
|
6190 |
This function returns BUFFER." |
|
6191 |
(declare (indent 2)) |
|
6192 |
(if async |
|
6193 |
(org-export-async-start |
|
6194 |
`(lambda (output) |
|
6195 |
(with-current-buffer (get-buffer-create ,buffer) |
|
6196 |
(erase-buffer) |
|
6197 |
(setq buffer-file-coding-system ',buffer-file-coding-system) |
|
6198 |
(insert output) |
|
6199 |
(goto-char (point-min)) |
|
6200 |
(org-export-add-to-stack (current-buffer) ',backend) |
|
6201 |
(ignore-errors (funcall ,post-process)))) |
|
6202 |
`(org-export-as |
|
6203 |
',backend ,subtreep ,visible-only ,body-only ',ext-plist)) |
|
6204 |
(let ((output |
|
6205 |
(org-export-as backend subtreep visible-only body-only ext-plist)) |
|
6206 |
(buffer (get-buffer-create buffer)) |
|
6207 |
(encoding buffer-file-coding-system)) |
|
6208 |
(when (and (org-string-nw-p output) (org-export--copy-to-kill-ring-p)) |
|
6209 |
(org-kill-new output)) |
|
6210 |
(with-current-buffer buffer |
|
6211 |
(erase-buffer) |
|
6212 |
(setq buffer-file-coding-system encoding) |
|
6213 |
(insert output) |
|
6214 |
(goto-char (point-min)) |
|
6215 |
(and (functionp post-process) (funcall post-process))) |
|
6216 |
(when org-export-show-temporary-export-buffer |
|
6217 |
(switch-to-buffer-other-window buffer)) |
|
6218 |
buffer))) |
|
6219 |
|
|
6220 |
;;;###autoload |
|
6221 |
(defun org-export-to-file |
|
6222 |
(backend file &optional async subtreep visible-only body-only ext-plist |
|
6223 |
post-process) |
|
6224 |
"Call `org-export-as' with output to a specified file. |
|
6225 |
|
|
6226 |
BACKEND is either an export back-end, as returned by, e.g., |
|
6227 |
`org-export-create-backend', or a symbol referring to |
|
6228 |
a registered back-end. FILE is the name of the output file, as |
|
6229 |
a string. |
|
6230 |
|
|
6231 |
A non-nil optional argument ASYNC means the process should happen |
|
6232 |
asynchronously. The resulting buffer will then be accessible |
|
6233 |
through the `org-export-stack' interface. |
|
6234 |
|
|
6235 |
Optional arguments SUBTREEP, VISIBLE-ONLY, BODY-ONLY and |
|
6236 |
EXT-PLIST are similar to those used in `org-export-as', which |
|
6237 |
see. |
|
6238 |
|
|
6239 |
Optional argument POST-PROCESS is called with FILE as its |
|
6240 |
argument and happens asynchronously when ASYNC is non-nil. It |
|
6241 |
has to return a file name, or nil. Export back-ends can use this |
|
6242 |
to send the output file through additional processing, e.g, |
|
6243 |
|
|
6244 |
(defun org-latex-export-to-latex |
|
6245 |
(&optional async subtreep visible-only body-only ext-plist) |
|
6246 |
(interactive) |
|
6247 |
(let ((outfile (org-export-output-file-name \".tex\" subtreep))) |
|
6248 |
(org-export-to-file \\='latex outfile |
|
6249 |
async subtreep visible-only body-only ext-plist |
|
6250 |
(lambda (file) (org-latex-compile file))) |
|
6251 |
|
|
6252 |
The function returns either a file name returned by POST-PROCESS, |
|
6253 |
or FILE." |
|
6254 |
(declare (indent 2)) |
|
6255 |
(if (not (file-writable-p file)) (error "Output file not writable") |
|
6256 |
(let ((ext-plist (org-combine-plists `(:output-file ,file) ext-plist)) |
|
6257 |
(encoding (or org-export-coding-system buffer-file-coding-system))) |
|
6258 |
(if async |
|
6259 |
(org-export-async-start |
|
6260 |
`(lambda (file) |
|
6261 |
(org-export-add-to-stack (expand-file-name file) ',backend)) |
|
6262 |
`(let ((output |
|
6263 |
(org-export-as |
|
6264 |
',backend ,subtreep ,visible-only ,body-only |
|
6265 |
',ext-plist))) |
|
6266 |
(with-temp-buffer |
|
6267 |
(insert output) |
|
6268 |
(let ((coding-system-for-write ',encoding)) |
|
6269 |
(write-file ,file))) |
|
6270 |
(or (ignore-errors (funcall ',post-process ,file)) ,file))) |
|
6271 |
(let ((output (org-export-as |
|
6272 |
backend subtreep visible-only body-only ext-plist))) |
|
6273 |
(with-temp-buffer |
|
6274 |
(insert output) |
|
6275 |
(let ((coding-system-for-write encoding)) |
|
6276 |
(write-file file))) |
|
6277 |
(when (and (org-export--copy-to-kill-ring-p) (org-string-nw-p output)) |
|
6278 |
(org-kill-new output)) |
|
6279 |
;; Get proper return value. |
|
6280 |
(or (and (functionp post-process) (funcall post-process file)) |
|
6281 |
file)))))) |
|
6282 |
|
|
6283 |
(defun org-export-output-file-name (extension &optional subtreep pub-dir) |
|
6284 |
"Return output file's name according to buffer specifications. |
|
6285 |
|
|
6286 |
EXTENSION is a string representing the output file extension, |
|
6287 |
with the leading dot. |
|
6288 |
|
|
6289 |
With a non-nil optional argument SUBTREEP, try to determine |
|
6290 |
output file's name by looking for \"EXPORT_FILE_NAME\" property |
|
6291 |
of subtree at point. |
|
6292 |
|
|
6293 |
When optional argument PUB-DIR is set, use it as the publishing |
|
6294 |
directory. |
|
6295 |
|
|
6296 |
Return file name as a string." |
|
6297 |
(let* ((visited-file (buffer-file-name (buffer-base-buffer))) |
|
6298 |
(base-name |
|
6299 |
(concat |
|
6300 |
(file-name-sans-extension |
|
6301 |
(or |
|
6302 |
;; Check EXPORT_FILE_NAME subtree property. |
|
6303 |
(and subtreep (org-entry-get nil "EXPORT_FILE_NAME" 'selective)) |
|
6304 |
;; Check #+EXPORT_FILE_NAME keyword. |
|
6305 |
(org-with-point-at (point-min) |
|
6306 |
(catch :found |
|
6307 |
(let ((case-fold-search t)) |
|
6308 |
(while (re-search-forward |
|
6309 |
"^[ \t]*#\\+EXPORT_FILE_NAME:[ \t]+\\S-" nil t) |
|
6310 |
(let ((element (org-element-at-point))) |
|
6311 |
(when (eq 'keyword (org-element-type element)) |
|
6312 |
(throw :found |
|
6313 |
(org-element-property :value element)))))))) |
|
6314 |
;; Extract from buffer's associated file, if any. |
|
6315 |
(and visited-file (file-name-nondirectory visited-file)) |
|
6316 |
;; Can't determine file name on our own: ask user. |
|
6317 |
(read-file-name |
|
6318 |
"Output file: " pub-dir nil nil nil |
|
6319 |
(lambda (n) (string= extension (file-name-extension n t)))))) |
|
6320 |
extension)) |
|
6321 |
(output-file |
|
6322 |
;; Build file name. Enforce EXTENSION over whatever user |
|
6323 |
;; may have come up with. PUB-DIR, if defined, always has |
|
6324 |
;; precedence over any provided path. |
|
6325 |
(cond |
|
6326 |
(pub-dir (concat (file-name-as-directory pub-dir) |
|
6327 |
(file-name-nondirectory base-name))) |
|
6328 |
((file-name-absolute-p base-name) base-name) |
|
6329 |
(t base-name)))) |
|
6330 |
;; If writing to OUTPUT-FILE would overwrite original file, append |
|
6331 |
;; EXTENSION another time to final name. |
|
6332 |
(if (and visited-file (file-equal-p visited-file output-file)) |
|
6333 |
(concat output-file extension) |
|
6334 |
output-file))) |
|
6335 |
|
|
6336 |
(defun org-export-add-to-stack (source backend &optional process) |
|
6337 |
"Add a new result to export stack if not present already. |
|
6338 |
|
|
6339 |
SOURCE is a buffer or a file name containing export results. |
|
6340 |
BACKEND is a symbol representing export back-end used to generate |
|
6341 |
it. |
|
6342 |
|
|
6343 |
Entries already pointing to SOURCE and unavailable entries are |
|
6344 |
removed beforehand. Return the new stack." |
|
6345 |
(setq org-export-stack-contents |
|
6346 |
(cons (list source backend (or process (current-time))) |
|
6347 |
(org-export-stack-remove source)))) |
|
6348 |
|
|
6349 |
(defun org-export-stack () |
|
6350 |
"Menu for asynchronous export results and running processes." |
|
6351 |
(interactive) |
|
6352 |
(let ((buffer (get-buffer-create "*Org Export Stack*"))) |
|
6353 |
(with-current-buffer buffer |
|
6354 |
(org-export-stack-mode) |
|
6355 |
(tabulated-list-print t)) |
|
6356 |
(pop-to-buffer buffer)) |
|
6357 |
(message "Type \"q\" to quit, \"?\" for help")) |
|
6358 |
|
|
6359 |
(defun org-export-stack-clear () |
|
6360 |
"Remove all entries from export stack." |
|
6361 |
(interactive) |
|
6362 |
(setq org-export-stack-contents nil)) |
|
6363 |
|
|
6364 |
(defun org-export-stack-refresh () |
|
6365 |
"Refresh the export stack." |
|
6366 |
(interactive) |
|
6367 |
(tabulated-list-print t)) |
|
6368 |
|
|
6369 |
(defun org-export-stack-remove (&optional source) |
|
6370 |
"Remove export results at point from stack. |
|
6371 |
If optional argument SOURCE is non-nil, remove it instead." |
|
6372 |
(interactive) |
|
6373 |
(let ((source (or source (org-export--stack-source-at-point)))) |
|
6374 |
(setq org-export-stack-contents |
|
6375 |
(cl-remove-if (lambda (el) (equal (car el) source)) |
|
6376 |
org-export-stack-contents)))) |
|
6377 |
|
|
6378 |
(defun org-export-stack-view (&optional in-emacs) |
|
6379 |
"View export results at point in stack. |
|
6380 |
With an optional prefix argument IN-EMACS, force viewing files |
|
6381 |
within Emacs." |
|
6382 |
(interactive "P") |
|
6383 |
(let ((source (org-export--stack-source-at-point))) |
|
6384 |
(cond ((processp source) |
|
6385 |
(org-switch-to-buffer-other-window (process-buffer source))) |
|
6386 |
((bufferp source) (org-switch-to-buffer-other-window source)) |
|
6387 |
(t (org-open-file source in-emacs))))) |
|
6388 |
|
|
6389 |
(defvar org-export-stack-mode-map |
|
6390 |
(let ((km (make-sparse-keymap))) |
|
6391 |
(set-keymap-parent km tabulated-list-mode-map) |
|
6392 |
(define-key km " " 'next-line) |
|
6393 |
(define-key km "\C-n" 'next-line) |
|
6394 |
(define-key km [down] 'next-line) |
|
6395 |
(define-key km "\C-p" 'previous-line) |
|
6396 |
(define-key km "\C-?" 'previous-line) |
|
6397 |
(define-key km [up] 'previous-line) |
|
6398 |
(define-key km "C" 'org-export-stack-clear) |
|
6399 |
(define-key km "v" 'org-export-stack-view) |
|
6400 |
(define-key km (kbd "RET") 'org-export-stack-view) |
|
6401 |
(define-key km "d" 'org-export-stack-remove) |
|
6402 |
km) |
|
6403 |
"Keymap for Org Export Stack.") |
|
6404 |
|
|
6405 |
(define-derived-mode org-export-stack-mode tabulated-list-mode "Org-Stack" |
|
6406 |
"Mode for displaying asynchronous export stack. |
|
6407 |
|
|
6408 |
Type `\\[org-export-stack]' to visualize the asynchronous export |
|
6409 |
stack. |
|
6410 |
|
|
6411 |
In an Org Export Stack buffer, use \ |
|
6412 |
\\<org-export-stack-mode-map>`\\[org-export-stack-view]' to view export output |
|
6413 |
on current line, `\\[org-export-stack-remove]' to remove it from the stack and \ |
|
6414 |
`\\[org-export-stack-clear]' to clear |
|
6415 |
stack completely. |
|
6416 |
|
|
6417 |
Removing entries in a stack buffer does not affect files |
|
6418 |
or buffers, only display. |
|
6419 |
|
|
6420 |
\\{org-export-stack-mode-map}" |
|
6421 |
(setq tabulated-list-format |
|
6422 |
(vector (list "#" 4 #'org-export--stack-num-predicate) |
|
6423 |
(list "Back-End" 12 t) |
|
6424 |
(list "Age" 6 nil) |
|
6425 |
(list "Source" 0 nil))) |
|
6426 |
(setq tabulated-list-sort-key (cons "#" nil)) |
|
6427 |
(setq tabulated-list-entries #'org-export--stack-generate) |
|
6428 |
(add-hook 'tabulated-list-revert-hook #'org-export--stack-generate nil t) |
|
6429 |
(add-hook 'post-command-hook #'org-export-stack-refresh nil t) |
|
6430 |
(tabulated-list-init-header)) |
|
6431 |
|
|
6432 |
(defun org-export--stack-generate () |
|
6433 |
"Generate the asynchronous export stack for display. |
|
6434 |
Unavailable sources are removed from the list. Return a list |
|
6435 |
appropriate for `tabulated-list-print'." |
|
6436 |
;; Clear stack from exited processes, dead buffers or non-existent |
|
6437 |
;; files. |
|
6438 |
(setq org-export-stack-contents |
|
6439 |
(cl-remove-if-not |
|
6440 |
(lambda (el) |
|
6441 |
(if (processp (nth 2 el)) |
|
6442 |
(buffer-live-p (process-buffer (nth 2 el))) |
|
6443 |
(let ((source (car el))) |
|
6444 |
(if (bufferp source) (buffer-live-p source) |
|
6445 |
(file-exists-p source))))) |
|
6446 |
org-export-stack-contents)) |
|
6447 |
;; Update `tabulated-list-entries'. |
|
6448 |
(let ((counter 0)) |
|
6449 |
(mapcar |
|
6450 |
(lambda (entry) |
|
6451 |
(let ((source (car entry))) |
|
6452 |
(list source |
|
6453 |
(vector |
|
6454 |
;; Counter. |
|
6455 |
(number-to-string (cl-incf counter)) |
|
6456 |
;; Back-End. |
|
6457 |
(if (nth 1 entry) (symbol-name (nth 1 entry)) "") |
|
6458 |
;; Age. |
|
6459 |
(let ((info (nth 2 entry))) |
|
6460 |
(if (processp info) (symbol-name (process-status info)) |
|
6461 |
(format-seconds "%h:%.2m" (float-time (time-since info))))) |
|
6462 |
;; Source. |
|
6463 |
(if (stringp source) source (buffer-name source)))))) |
|
6464 |
org-export-stack-contents))) |
|
6465 |
|
|
6466 |
(defun org-export--stack-num-predicate (a b) |
|
6467 |
(< (string-to-number (aref (nth 1 a) 0)) |
|
6468 |
(string-to-number (aref (nth 1 b) 0)))) |
|
6469 |
|
|
6470 |
(defun org-export--stack-source-at-point () |
|
6471 |
"Return source from export results at point in stack." |
|
6472 |
(let ((source (car (nth (1- (org-current-line)) org-export-stack-contents)))) |
|
6473 |
(if (not source) (error "Source unavailable, please refresh buffer") |
|
6474 |
(let ((source-name (if (stringp source) source (buffer-name source)))) |
|
6475 |
(if (save-excursion |
|
6476 |
(beginning-of-line) |
|
6477 |
(looking-at-p (concat ".* +" (regexp-quote source-name) "$"))) |
|
6478 |
source |
|
6479 |
;; SOURCE is not consistent with current line. The stack |
|
6480 |
;; view is outdated. |
|
6481 |
(error (substitute-command-keys |
|
6482 |
"Source unavailable; type `\\[org-export-stack-refresh]' \ |
|
6483 |
to refresh buffer"))))))) |
|
6484 |
|
|
6485 |
|
|
6486 |
|
|
6487 |
;;; The Dispatcher |
|
6488 |
;; |
|
6489 |
;; `org-export-dispatch' is the standard interactive way to start an |
|
6490 |
;; export process. It uses `org-export--dispatch-ui' as a subroutine |
|
6491 |
;; for its interface, which, in turn, delegates response to key |
|
6492 |
;; pressed to `org-export--dispatch-action'. |
|
6493 |
|
|
6494 |
;;;###autoload |
|
6495 |
(defun org-export-dispatch (&optional arg) |
|
6496 |
"Export dispatcher for Org mode. |
|
6497 |
|
|
6498 |
It provides an access to common export related tasks in a buffer. |
|
6499 |
Its interface comes in two flavors: standard and expert. |
|
6500 |
|
|
6501 |
While both share the same set of bindings, only the former |
|
6502 |
displays the valid keys associations in a dedicated buffer. |
|
6503 |
Scrolling (resp. line-wise motion) in this buffer is done with |
|
6504 |
SPC and DEL (resp. C-n and C-p) keys. |
|
6505 |
|
|
6506 |
Set variable `org-export-dispatch-use-expert-ui' to switch to one |
|
6507 |
flavor or the other. |
|
6508 |
|
|
6509 |
When ARG is `\\[universal-argument]', repeat the last export action, with the\ |
|
6510 |
same |
|
6511 |
set of options used back then, on the current buffer. |
|
6512 |
|
|
6513 |
When ARG is `\\[universal-argument] \\[universal-argument]', display the \ |
|
6514 |
asynchronous export stack." |
|
6515 |
(interactive "P") |
|
6516 |
(let* ((input |
|
6517 |
(cond ((equal arg '(16)) '(stack)) |
|
6518 |
((and arg org-export-dispatch-last-action)) |
|
6519 |
(t (save-window-excursion |
|
6520 |
(unwind-protect |
|
6521 |
(progn |
|
6522 |
;; Remember where we are |
|
6523 |
(move-marker org-export-dispatch-last-position |
|
6524 |
(point) |
|
6525 |
(org-base-buffer (current-buffer))) |
|
6526 |
;; Get and store an export command |
|
6527 |
(setq org-export-dispatch-last-action |
|
6528 |
(org-export--dispatch-ui |
|
6529 |
(list org-export-initial-scope |
|
6530 |
(and org-export-in-background 'async)) |
|
6531 |
nil |
|
6532 |
org-export-dispatch-use-expert-ui))) |
|
6533 |
(and (get-buffer "*Org Export Dispatcher*") |
|
6534 |
(kill-buffer "*Org Export Dispatcher*"))))))) |
|
6535 |
(action (car input)) |
|
6536 |
(optns (cdr input))) |
|
6537 |
(unless (memq 'subtree optns) |
|
6538 |
(move-marker org-export-dispatch-last-position nil)) |
|
6539 |
(cl-case action |
|
6540 |
;; First handle special hard-coded actions. |
|
6541 |
(template (org-export-insert-default-template nil optns)) |
|
6542 |
(stack (org-export-stack)) |
|
6543 |
(publish-current-file |
|
6544 |
(org-publish-current-file (memq 'force optns) (memq 'async optns))) |
|
6545 |
(publish-current-project |
|
6546 |
(org-publish-current-project (memq 'force optns) (memq 'async optns))) |
|
6547 |
(publish-choose-project |
|
6548 |
(org-publish (assoc (completing-read |
|
6549 |
"Publish project: " |
|
6550 |
org-publish-project-alist nil t) |
|
6551 |
org-publish-project-alist) |
|
6552 |
(memq 'force optns) |
|
6553 |
(memq 'async optns))) |
|
6554 |
(publish-all (org-publish-all (memq 'force optns) (memq 'async optns))) |
|
6555 |
(otherwise |
|
6556 |
(save-excursion |
|
6557 |
(when arg |
|
6558 |
;; Repeating command, maybe move cursor to restore subtree |
|
6559 |
;; context. |
|
6560 |
(if (eq (marker-buffer org-export-dispatch-last-position) |
|
6561 |
(org-base-buffer (current-buffer))) |
|
6562 |
(goto-char org-export-dispatch-last-position) |
|
6563 |
;; We are in a different buffer, forget position. |
|
6564 |
(move-marker org-export-dispatch-last-position nil))) |
|
6565 |
(funcall action |
|
6566 |
;; Return a symbol instead of a list to ease |
|
6567 |
;; asynchronous export macro use. |
|
6568 |
(and (memq 'async optns) t) |
|
6569 |
(and (memq 'subtree optns) t) |
|
6570 |
(and (memq 'visible optns) t) |
|
6571 |
(and (memq 'body optns) t))))))) |
|
6572 |
|
|
6573 |
(defun org-export--dispatch-ui (options first-key expertp) |
|
6574 |
"Handle interface for `org-export-dispatch'. |
|
6575 |
|
|
6576 |
OPTIONS is a list containing current interactive options set for |
|
6577 |
export. It can contain any of the following symbols: |
|
6578 |
`body' toggles a body-only export |
|
6579 |
`subtree' restricts export to current subtree |
|
6580 |
`visible' restricts export to visible part of buffer. |
|
6581 |
`force' force publishing files. |
|
6582 |
`async' use asynchronous export process |
|
6583 |
|
|
6584 |
FIRST-KEY is the key pressed to select the first level menu. It |
|
6585 |
is nil when this menu hasn't been selected yet. |
|
6586 |
|
|
6587 |
EXPERTP, when non-nil, triggers expert UI. In that case, no help |
|
6588 |
buffer is provided, but indications about currently active |
|
6589 |
options are given in the prompt. Moreover, [?] allows switching |
|
6590 |
back to standard interface." |
|
6591 |
(let* ((fontify-key |
|
6592 |
(lambda (key &optional access-key) |
|
6593 |
;; Fontify KEY string. Optional argument ACCESS-KEY, when |
|
6594 |
;; non-nil is the required first-level key to activate |
|
6595 |
;; KEY. When its value is t, activate KEY independently |
|
6596 |
;; on the first key, if any. A nil value means KEY will |
|
6597 |
;; only be activated at first level. |
|
6598 |
(if (or (eq access-key t) (eq access-key first-key)) |
|
6599 |
(propertize key 'face 'org-warning) |
|
6600 |
key))) |
|
6601 |
(fontify-value |
|
6602 |
(lambda (value) |
|
6603 |
;; Fontify VALUE string. |
|
6604 |
(propertize value 'face 'font-lock-variable-name-face))) |
|
6605 |
;; Prepare menu entries by extracting them from registered |
|
6606 |
;; back-ends and sorting them by access key and by ordinal, |
|
6607 |
;; if any. |
|
6608 |
(entries |
|
6609 |
(sort (sort (delq nil |
|
6610 |
(mapcar #'org-export-backend-menu |
|
6611 |
org-export-registered-backends)) |
|
6612 |
(lambda (a b) |
|
6613 |
(let ((key-a (nth 1 a)) |
|
6614 |
(key-b (nth 1 b))) |
|
6615 |
(cond ((and (numberp key-a) (numberp key-b)) |
|
6616 |
(< key-a key-b)) |
|
6617 |
((numberp key-b) t))))) |
|
6618 |
'car-less-than-car)) |
|
6619 |
;; Compute a list of allowed keys based on the first key |
|
6620 |
;; pressed, if any. Some keys |
|
6621 |
;; (?^B, ?^V, ?^S, ?^F, ?^A, ?&, ?# and ?q) are always |
|
6622 |
;; available. |
|
6623 |
(allowed-keys |
|
6624 |
(nconc (list 2 22 19 6 1) |
|
6625 |
(if (not first-key) (org-uniquify (mapcar 'car entries)) |
|
6626 |
(let (sub-menu) |
|
6627 |
(dolist (entry entries (sort (mapcar 'car sub-menu) '<)) |
|
6628 |
(when (eq (car entry) first-key) |
|
6629 |
(setq sub-menu (append (nth 2 entry) sub-menu)))))) |
|
6630 |
(cond ((eq first-key ?P) (list ?f ?p ?x ?a)) |
|
6631 |
((not first-key) (list ?P))) |
|
6632 |
(list ?& ?#) |
|
6633 |
(when expertp (list ??)) |
|
6634 |
(list ?q))) |
|
6635 |
;; Build the help menu for standard UI. |
|
6636 |
(help |
|
6637 |
(unless expertp |
|
6638 |
(concat |
|
6639 |
;; Options are hard-coded. |
|
6640 |
(format "[%s] Body only: %s [%s] Visible only: %s |
|
6641 |
\[%s] Export scope: %s [%s] Force publishing: %s |
|
6642 |
\[%s] Async export: %s\n\n" |
|
6643 |
(funcall fontify-key "C-b" t) |
|
6644 |
(funcall fontify-value |
|
6645 |
(if (memq 'body options) "On " "Off")) |
|
6646 |
(funcall fontify-key "C-v" t) |
|
6647 |
(funcall fontify-value |
|
6648 |
(if (memq 'visible options) "On " "Off")) |
|
6649 |
(funcall fontify-key "C-s" t) |
|
6650 |
(funcall fontify-value |
|
6651 |
(if (memq 'subtree options) "Subtree" "Buffer ")) |
|
6652 |
(funcall fontify-key "C-f" t) |
|
6653 |
(funcall fontify-value |
|
6654 |
(if (memq 'force options) "On " "Off")) |
|
6655 |
(funcall fontify-key "C-a" t) |
|
6656 |
(funcall fontify-value |
|
6657 |
(if (memq 'async options) "On " "Off"))) |
|
6658 |
;; Display registered back-end entries. When a key |
|
6659 |
;; appears for the second time, do not create another |
|
6660 |
;; entry, but append its sub-menu to existing menu. |
|
6661 |
(let (last-key) |
|
6662 |
(mapconcat |
|
6663 |
(lambda (entry) |
|
6664 |
(let ((top-key (car entry))) |
|
6665 |
(concat |
|
6666 |
(unless (eq top-key last-key) |
|
6667 |
(setq last-key top-key) |
|
6668 |
(format "\n[%s] %s\n" |
|
6669 |
(funcall fontify-key (char-to-string top-key)) |
|
6670 |
(nth 1 entry))) |
|
6671 |
(let ((sub-menu (nth 2 entry))) |
|
6672 |
(unless (functionp sub-menu) |
|
6673 |
;; Split sub-menu into two columns. |
|
6674 |
(let ((index -1)) |
|
6675 |
(concat |
|
6676 |
(mapconcat |
|
6677 |
(lambda (sub-entry) |
|
6678 |
(cl-incf index) |
|
6679 |
(format |
|
6680 |
(if (zerop (mod index 2)) " [%s] %-26s" |
|
6681 |
"[%s] %s\n") |
|
6682 |
(funcall fontify-key |
|
6683 |
(char-to-string (car sub-entry)) |
|
6684 |
top-key) |
|
6685 |
(nth 1 sub-entry))) |
|
6686 |
sub-menu "") |
|
6687 |
(when (zerop (mod index 2)) "\n")))))))) |
|
6688 |
entries "")) |
|
6689 |
;; Publishing menu is hard-coded. |
|
6690 |
(format "\n[%s] Publish |
|
6691 |
[%s] Current file [%s] Current project |
|
6692 |
[%s] Choose project [%s] All projects\n\n\n" |
|
6693 |
(funcall fontify-key "P") |
|
6694 |
(funcall fontify-key "f" ?P) |
|
6695 |
(funcall fontify-key "p" ?P) |
|
6696 |
(funcall fontify-key "x" ?P) |
|
6697 |
(funcall fontify-key "a" ?P)) |
|
6698 |
(format "[%s] Export stack [%s] Insert template\n" |
|
6699 |
(funcall fontify-key "&" t) |
|
6700 |
(funcall fontify-key "#" t)) |
|
6701 |
(format "[%s] %s" |
|
6702 |
(funcall fontify-key "q" t) |
|
6703 |
(if first-key "Main menu" "Exit"))))) |
|
6704 |
;; Build prompts for both standard and expert UI. |
|
6705 |
(standard-prompt (unless expertp "Export command: ")) |
|
6706 |
(expert-prompt |
|
6707 |
(when expertp |
|
6708 |
(format |
|
6709 |
"Export command (C-%s%s%s%s%s) [%s]: " |
|
6710 |
(if (memq 'body options) (funcall fontify-key "b" t) "b") |
|
6711 |
(if (memq 'visible options) (funcall fontify-key "v" t) "v") |
|
6712 |
(if (memq 'subtree options) (funcall fontify-key "s" t) "s") |
|
6713 |
(if (memq 'force options) (funcall fontify-key "f" t) "f") |
|
6714 |
(if (memq 'async options) (funcall fontify-key "a" t) "a") |
|
6715 |
(mapconcat (lambda (k) |
|
6716 |
;; Strip control characters. |
|
6717 |
(unless (< k 27) (char-to-string k))) |
|
6718 |
allowed-keys ""))))) |
|
6719 |
;; With expert UI, just read key with a fancy prompt. In standard |
|
6720 |
;; UI, display an intrusive help buffer. |
|
6721 |
(if expertp |
|
6722 |
(org-export--dispatch-action |
|
6723 |
expert-prompt allowed-keys entries options first-key expertp) |
|
6724 |
;; At first call, create frame layout in order to display menu. |
|
6725 |
(unless (get-buffer "*Org Export Dispatcher*") |
|
6726 |
(delete-other-windows) |
|
6727 |
(org-switch-to-buffer-other-window |
|
6728 |
(get-buffer-create "*Org Export Dispatcher*")) |
|
6729 |
(setq cursor-type nil |
|
6730 |
header-line-format "Use SPC, DEL, C-n or C-p to navigate.") |
|
6731 |
;; Make sure that invisible cursor will not highlight square |
|
6732 |
;; brackets. |
|
6733 |
(set-syntax-table (copy-syntax-table)) |
|
6734 |
(modify-syntax-entry ?\[ "w")) |
|
6735 |
;; At this point, the buffer containing the menu exists and is |
|
6736 |
;; visible in the current window. So, refresh it. |
|
6737 |
(with-current-buffer "*Org Export Dispatcher*" |
|
6738 |
;; Refresh help. Maintain display continuity by re-visiting |
|
6739 |
;; previous window position. |
|
6740 |
(let ((pos (window-start))) |
|
6741 |
(erase-buffer) |
|
6742 |
(insert help) |
|
6743 |
(set-window-start nil pos))) |
|
6744 |
(org-fit-window-to-buffer) |
|
6745 |
(org-export--dispatch-action |
|
6746 |
standard-prompt allowed-keys entries options first-key expertp)))) |
|
6747 |
|
|
6748 |
(defun org-export--dispatch-action |
|
6749 |
(prompt allowed-keys entries options first-key expertp) |
|
6750 |
"Read a character from command input and act accordingly. |
|
6751 |
|
|
6752 |
PROMPT is the displayed prompt, as a string. ALLOWED-KEYS is |
|
6753 |
a list of characters available at a given step in the process. |
|
6754 |
ENTRIES is a list of menu entries. OPTIONS, FIRST-KEY and |
|
6755 |
EXPERTP are the same as defined in `org-export--dispatch-ui', |
|
6756 |
which see. |
|
6757 |
|
|
6758 |
Toggle export options when required. Otherwise, return value is |
|
6759 |
a list with action as CAR and a list of interactive export |
|
6760 |
options as CDR." |
|
6761 |
(let (key) |
|
6762 |
;; Scrolling: when in non-expert mode, act on motion keys (C-n, |
|
6763 |
;; C-p, SPC, DEL). |
|
6764 |
(while (and (setq key (read-char-exclusive prompt)) |
|
6765 |
(not expertp) |
|
6766 |
(memq key '(14 16 ?\s ?\d))) |
|
6767 |
(cl-case key |
|
6768 |
(14 (if (not (pos-visible-in-window-p (point-max))) |
|
6769 |
(ignore-errors (scroll-up 1)) |
|
6770 |
(message "End of buffer") |
|
6771 |
(sit-for 1))) |
|
6772 |
(16 (if (not (pos-visible-in-window-p (point-min))) |
|
6773 |
(ignore-errors (scroll-down 1)) |
|
6774 |
(message "Beginning of buffer") |
|
6775 |
(sit-for 1))) |
|
6776 |
(?\s (if (not (pos-visible-in-window-p (point-max))) |
|
6777 |
(scroll-up nil) |
|
6778 |
(message "End of buffer") |
|
6779 |
(sit-for 1))) |
|
6780 |
(?\d (if (not (pos-visible-in-window-p (point-min))) |
|
6781 |
(scroll-down nil) |
|
6782 |
(message "Beginning of buffer") |
|
6783 |
(sit-for 1))))) |
|
6784 |
(cond |
|
6785 |
;; Ignore undefined associations. |
|
6786 |
((not (memq key allowed-keys)) |
|
6787 |
(ding) |
|
6788 |
(unless expertp (message "Invalid key") (sit-for 1)) |
|
6789 |
(org-export--dispatch-ui options first-key expertp)) |
|
6790 |
;; q key at first level aborts export. At second level, cancel |
|
6791 |
;; first key instead. |
|
6792 |
((eq key ?q) (if (not first-key) (error "Export aborted") |
|
6793 |
(org-export--dispatch-ui options nil expertp))) |
|
6794 |
;; Help key: Switch back to standard interface if expert UI was |
|
6795 |
;; active. |
|
6796 |
((eq key ??) (org-export--dispatch-ui options first-key nil)) |
|
6797 |
;; Send request for template insertion along with export scope. |
|
6798 |
((eq key ?#) (cons 'template (memq 'subtree options))) |
|
6799 |
;; Switch to asynchronous export stack. |
|
6800 |
((eq key ?&) '(stack)) |
|
6801 |
;; Toggle options: C-b (2) C-v (22) C-s (19) C-f (6) C-a (1). |
|
6802 |
((memq key '(2 22 19 6 1)) |
|
6803 |
(org-export--dispatch-ui |
|
6804 |
(let ((option (cl-case key (2 'body) (22 'visible) (19 'subtree) |
|
6805 |
(6 'force) (1 'async)))) |
|
6806 |
(if (memq option options) (remq option options) |
|
6807 |
(cons option options))) |
|
6808 |
first-key expertp)) |
|
6809 |
;; Action selected: Send key and options back to |
|
6810 |
;; `org-export-dispatch'. |
|
6811 |
((or first-key (functionp (nth 2 (assq key entries)))) |
|
6812 |
(cons (cond |
|
6813 |
((not first-key) (nth 2 (assq key entries))) |
|
6814 |
;; Publishing actions are hard-coded. Send a special |
|
6815 |
;; signal to `org-export-dispatch'. |
|
6816 |
((eq first-key ?P) |
|
6817 |
(cl-case key |
|
6818 |
(?f 'publish-current-file) |
|
6819 |
(?p 'publish-current-project) |
|
6820 |
(?x 'publish-choose-project) |
|
6821 |
(?a 'publish-all))) |
|
6822 |
;; Return first action associated to FIRST-KEY + KEY |
|
6823 |
;; path. Indeed, derived backends can share the same |
|
6824 |
;; FIRST-KEY. |
|
6825 |
(t (catch 'found |
|
6826 |
(dolist (entry (member (assq first-key entries) entries)) |
|
6827 |
(let ((match (assq key (nth 2 entry)))) |
|
6828 |
(when match (throw 'found (nth 2 match)))))))) |
|
6829 |
options)) |
|
6830 |
;; Otherwise, enter sub-menu. |
|
6831 |
(t (org-export--dispatch-ui options key expertp))))) |
|
6832 |
|
|
6833 |
|
|
6834 |
|
|
6835 |
(provide 'ox) |
|
6836 |
|
|
6837 |
;; Local variables: |
|
6838 |
;; generated-autoload-file: "org-loaddefs.el" |
|
6839 |
;; End: |
|
6840 |
|
|
6841 |
;;; ox.el ends here |