Commit | Line | Data |
---|---|---|
271672fa BG |
1 | ;;; ox.el --- Generic Export Engine for Org Mode |
2 | ||
ba318903 | 3 | ;; Copyright (C) 2012-2014 Free Software Foundation, Inc. |
271672fa BG |
4 | |
5 | ;; Author: Nicolas Goaziou <n.goaziou at gmail dot com> | |
6 | ;; Keywords: outlines, hypermedia, calendar, wp | |
7 | ||
439d6b1c GM |
8 | ;; This file is part of GNU Emacs. |
9 | ||
271672fa BG |
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 <http://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 in 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. The exhaustive list | |
35 | ;; of properties is given in "The Communication Channel" section of | |
36 | ;; this file. | |
37 | ;; | |
38 | ;; - The transcoder walks the parse tree, ignores or treat as plain | |
39 | ;; text elements and objects according to export options, and | |
40 | ;; eventually calls back-end specific functions to do the real | |
41 | ;; transcoding, concatenating their return value along the way. | |
42 | ;; | |
43 | ;; - The filter system is activated at the very beginning and the very | |
44 | ;; end of the export process, and each time an element or an object | |
45 | ;; has been converted. It is the entry point to fine-tune standard | |
46 | ;; output from back-end transcoders. See "The Filter System" | |
47 | ;; section for more information. | |
48 | ;; | |
49 | ;; The core function is `org-export-as'. It returns the transcoded | |
50 | ;; buffer as a string. | |
51 | ;; | |
52 | ;; An export back-end is defined with `org-export-define-backend'. | |
53 | ;; This function can also support specific buffer keywords, OPTION | |
54 | ;; keyword's items and filters. Refer to function's documentation for | |
55 | ;; more information. | |
56 | ;; | |
57 | ;; If the new back-end shares most properties with another one, | |
58 | ;; `org-export-define-derived-backend' can be used to simplify the | |
59 | ;; process. | |
60 | ;; | |
61 | ;; Any back-end can define its own variables. Among them, those | |
62 | ;; customizable should belong to the `org-export-BACKEND' group. | |
63 | ;; | |
64 | ;; Tools for common tasks across back-ends are implemented in the | |
65 | ;; following part of the file. | |
66 | ;; | |
67 | ;; Then, a wrapper macro for asynchronous export, | |
68 | ;; `org-export-async-start', along with tools to display results. are | |
69 | ;; given in the penultimate part. | |
70 | ;; | |
71 | ;; Eventually, a dispatcher (`org-export-dispatch') for standard | |
72 | ;; back-ends is provided in the last one. | |
73 | ||
74 | ;;; Code: | |
75 | ||
76 | (eval-when-compile (require 'cl)) | |
77 | (require 'org-element) | |
78 | (require 'org-macro) | |
79 | (require 'ob-exp) | |
80 | ||
81 | (declare-function org-publish "ox-publish" (project &optional force async)) | |
82 | (declare-function org-publish-all "ox-publish" (&optional force async)) | |
83 | (declare-function | |
84 | org-publish-current-file "ox-publish" (&optional force async)) | |
85 | (declare-function org-publish-current-project "ox-publish" | |
86 | (&optional force async)) | |
87 | ||
88 | (defvar org-publish-project-alist) | |
89 | (defvar org-table-number-fraction) | |
90 | (defvar org-table-number-regexp) | |
91 | ||
92 | ||
93 | \f | |
94 | ;;; Internal Variables | |
95 | ;; | |
96 | ;; Among internal variables, the most important is | |
97 | ;; `org-export-options-alist'. This variable define the global export | |
98 | ;; options, shared between every exporter, and how they are acquired. | |
99 | ||
100 | (defconst org-export-max-depth 19 | |
101 | "Maximum nesting depth for headlines, counting from 0.") | |
102 | ||
103 | (defconst org-export-options-alist | |
104 | '((:author "AUTHOR" nil user-full-name t) | |
105 | (:creator "CREATOR" nil org-export-creator-string) | |
106 | (:date "DATE" nil nil t) | |
107 | (:description "DESCRIPTION" nil nil newline) | |
108 | (:email "EMAIL" nil user-mail-address t) | |
109 | (:exclude-tags "EXCLUDE_TAGS" nil org-export-exclude-tags split) | |
110 | (:headline-levels nil "H" org-export-headline-levels) | |
111 | (:keywords "KEYWORDS" nil nil space) | |
112 | (:language "LANGUAGE" nil org-export-default-language t) | |
113 | (:preserve-breaks nil "\\n" org-export-preserve-breaks) | |
114 | (:section-numbers nil "num" org-export-with-section-numbers) | |
115 | (:select-tags "SELECT_TAGS" nil org-export-select-tags split) | |
116 | (:time-stamp-file nil "timestamp" org-export-time-stamp-file) | |
117 | (:title "TITLE" nil nil space) | |
118 | (:with-archived-trees nil "arch" org-export-with-archived-trees) | |
119 | (:with-author nil "author" org-export-with-author) | |
120 | (:with-clocks nil "c" org-export-with-clocks) | |
121 | (:with-creator nil "creator" org-export-with-creator) | |
122 | (:with-date nil "date" org-export-with-date) | |
123 | (:with-drawers nil "d" org-export-with-drawers) | |
124 | (:with-email nil "email" org-export-with-email) | |
125 | (:with-emphasize nil "*" org-export-with-emphasize) | |
126 | (:with-entities nil "e" org-export-with-entities) | |
127 | (:with-fixed-width nil ":" org-export-with-fixed-width) | |
128 | (:with-footnotes nil "f" org-export-with-footnotes) | |
129 | (:with-inlinetasks nil "inline" org-export-with-inlinetasks) | |
130 | (:with-latex nil "tex" org-export-with-latex) | |
131 | (:with-planning nil "p" org-export-with-planning) | |
132 | (:with-priority nil "pri" org-export-with-priority) | |
133 | (:with-smart-quotes nil "'" org-export-with-smart-quotes) | |
134 | (:with-special-strings nil "-" org-export-with-special-strings) | |
135 | (:with-statistics-cookies nil "stat" org-export-with-statistics-cookies) | |
136 | (:with-sub-superscript nil "^" org-export-with-sub-superscripts) | |
137 | (:with-toc nil "toc" org-export-with-toc) | |
138 | (:with-tables nil "|" org-export-with-tables) | |
139 | (:with-tags nil "tags" org-export-with-tags) | |
140 | (:with-tasks nil "tasks" org-export-with-tasks) | |
141 | (:with-timestamps nil "<" org-export-with-timestamps) | |
142 | (:with-todo-keywords nil "todo" org-export-with-todo-keywords)) | |
143 | "Alist between export properties and ways to set them. | |
144 | ||
145 | The CAR of the alist is the property name, and the CDR is a list | |
da5ecfa9 | 146 | like (KEYWORD OPTION DEFAULT BEHAVIOR) where: |
271672fa BG |
147 | |
148 | KEYWORD is a string representing a buffer keyword, or nil. Each | |
149 | property defined this way can also be set, during subtree | |
150 | export, through a headline property named after the keyword | |
151 | with the \"EXPORT_\" prefix (i.e. DATE keyword and EXPORT_DATE | |
152 | property). | |
153 | OPTION is a string that could be found in an #+OPTIONS: line. | |
154 | DEFAULT is the default value for the property. | |
da5ecfa9 | 155 | BEHAVIOR determines how Org should handle multiple keywords for |
271672fa BG |
156 | the same property. It is a symbol among: |
157 | nil Keep old value and discard the new one. | |
158 | t Replace old value with the new one. | |
159 | `space' Concatenate the values, separating them with a space. | |
160 | `newline' Concatenate the values, separating them with | |
161 | a newline. | |
162 | `split' Split values at white spaces, and cons them to the | |
163 | previous list. | |
164 | ||
165 | Values set through KEYWORD and OPTION have precedence over | |
166 | DEFAULT. | |
167 | ||
168 | All these properties should be back-end agnostic. Back-end | |
169 | specific properties are set through `org-export-define-backend'. | |
170 | Properties redefined there have precedence over these.") | |
171 | ||
172 | (defconst org-export-special-keywords '("FILETAGS" "SETUPFILE" "OPTIONS") | |
173 | "List of in-buffer keywords that require special treatment. | |
174 | These keywords are not directly associated to a property. The | |
175 | way they are handled must be hard-coded into | |
176 | `org-export--get-inbuffer-options' function.") | |
177 | ||
178 | (defconst org-export-filters-alist | |
179 | '((:filter-bold . org-export-filter-bold-functions) | |
180 | (:filter-babel-call . org-export-filter-babel-call-functions) | |
181 | (:filter-center-block . org-export-filter-center-block-functions) | |
182 | (:filter-clock . org-export-filter-clock-functions) | |
183 | (:filter-code . org-export-filter-code-functions) | |
184 | (:filter-comment . org-export-filter-comment-functions) | |
185 | (:filter-comment-block . org-export-filter-comment-block-functions) | |
186 | (:filter-diary-sexp . org-export-filter-diary-sexp-functions) | |
187 | (:filter-drawer . org-export-filter-drawer-functions) | |
188 | (:filter-dynamic-block . org-export-filter-dynamic-block-functions) | |
189 | (:filter-entity . org-export-filter-entity-functions) | |
190 | (:filter-example-block . org-export-filter-example-block-functions) | |
191 | (:filter-export-block . org-export-filter-export-block-functions) | |
192 | (:filter-export-snippet . org-export-filter-export-snippet-functions) | |
193 | (:filter-final-output . org-export-filter-final-output-functions) | |
194 | (:filter-fixed-width . org-export-filter-fixed-width-functions) | |
195 | (:filter-footnote-definition . org-export-filter-footnote-definition-functions) | |
196 | (:filter-footnote-reference . org-export-filter-footnote-reference-functions) | |
197 | (:filter-headline . org-export-filter-headline-functions) | |
198 | (:filter-horizontal-rule . org-export-filter-horizontal-rule-functions) | |
199 | (:filter-inline-babel-call . org-export-filter-inline-babel-call-functions) | |
200 | (:filter-inline-src-block . org-export-filter-inline-src-block-functions) | |
201 | (:filter-inlinetask . org-export-filter-inlinetask-functions) | |
202 | (:filter-italic . org-export-filter-italic-functions) | |
203 | (:filter-item . org-export-filter-item-functions) | |
204 | (:filter-keyword . org-export-filter-keyword-functions) | |
205 | (:filter-latex-environment . org-export-filter-latex-environment-functions) | |
206 | (:filter-latex-fragment . org-export-filter-latex-fragment-functions) | |
207 | (:filter-line-break . org-export-filter-line-break-functions) | |
208 | (:filter-link . org-export-filter-link-functions) | |
209 | (:filter-node-property . org-export-filter-node-property-functions) | |
210 | (:filter-options . org-export-filter-options-functions) | |
211 | (:filter-paragraph . org-export-filter-paragraph-functions) | |
212 | (:filter-parse-tree . org-export-filter-parse-tree-functions) | |
213 | (:filter-plain-list . org-export-filter-plain-list-functions) | |
214 | (:filter-plain-text . org-export-filter-plain-text-functions) | |
215 | (:filter-planning . org-export-filter-planning-functions) | |
216 | (:filter-property-drawer . org-export-filter-property-drawer-functions) | |
217 | (:filter-quote-block . org-export-filter-quote-block-functions) | |
218 | (:filter-quote-section . org-export-filter-quote-section-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 | (defvar org-export-async-debug nil | |
262 | "Non-nil means asynchronous export process should leave data behind. | |
263 | ||
264 | This data is found in the appropriate \"*Org Export Process*\" | |
265 | buffer, and in files prefixed with \"org-export-process\" and | |
266 | located in `temporary-file-directory'. | |
267 | ||
268 | When non-nil, it will also set `debug-on-error' to a non-nil | |
269 | value in the external process.") | |
270 | ||
271 | (defvar org-export-stack-contents nil | |
272 | "Record asynchronously generated export results and processes. | |
273 | This is an alist: its CAR is the source of the | |
274 | result (destination file or buffer for a finished process, | |
275 | original buffer for a running one) and its CDR is a list | |
276 | containing the back-end used, as a symbol, and either a process | |
277 | or the time at which it finished. It is used to build the menu | |
278 | from `org-export-stack'.") | |
279 | ||
280 | (defvar org-export--registered-backends nil | |
281 | "List of backends currently available in the exporter. | |
282 | This variable is set with `org-export-define-backend' and | |
283 | `org-export-define-derived-backend' functions.") | |
284 | ||
285 | (defvar org-export-dispatch-last-action nil | |
286 | "Last command called from the dispatcher. | |
287 | The value should be a list. Its CAR is the action, as a symbol, | |
288 | and its CDR is a list of export options.") | |
289 | ||
290 | (defvar org-export-dispatch-last-position (make-marker) | |
291 | "The position where the last export command was created using the dispatcher. | |
292 | This marker will be used with `C-u C-c C-e' to make sure export repetition | |
293 | uses the same subtree if the previous command was restricted to a subtree.") | |
294 | ||
295 | ;; For compatibility with Org < 8 | |
296 | (defvar org-export-current-backend nil | |
297 | "Name, if any, of the back-end used during an export process. | |
298 | ||
299 | Its value is a symbol such as `html', `latex', `ascii', or nil if | |
300 | the back-end is anonymous (see `org-export-create-backend') or if | |
301 | there is no export process in progress. | |
302 | ||
303 | It can be used to teach Babel blocks how to act differently | |
304 | according to the back-end used.") | |
305 | ||
306 | \f | |
307 | ;;; User-configurable Variables | |
308 | ;; | |
309 | ;; Configuration for the masses. | |
310 | ;; | |
311 | ;; They should never be accessed directly, as their value is to be | |
312 | ;; stored in a property list (cf. `org-export-options-alist'). | |
313 | ;; Back-ends will read their value from there instead. | |
314 | ||
315 | (defgroup org-export nil | |
316 | "Options for exporting Org mode files." | |
317 | :tag "Org Export" | |
318 | :group 'org) | |
319 | ||
320 | (defgroup org-export-general nil | |
321 | "General options for export engine." | |
322 | :tag "Org Export General" | |
323 | :group 'org-export) | |
324 | ||
325 | (defcustom org-export-with-archived-trees 'headline | |
326 | "Whether sub-trees with the ARCHIVE tag should be exported. | |
327 | ||
328 | This can have three different values: | |
329 | nil Do not export, pretend this tree is not present. | |
330 | t Do export the entire tree. | |
331 | `headline' Only export the headline, but skip the tree below it. | |
332 | ||
333 | This option can also be set with the OPTIONS keyword, | |
334 | e.g. \"arch:nil\"." | |
335 | :group 'org-export-general | |
336 | :type '(choice | |
337 | (const :tag "Not at all" nil) | |
338 | (const :tag "Headline only" headline) | |
339 | (const :tag "Entirely" t))) | |
340 | ||
341 | (defcustom org-export-with-author t | |
342 | "Non-nil means insert author name into the exported file. | |
343 | This option can also be set with the OPTIONS keyword, | |
344 | e.g. \"author:nil\"." | |
345 | :group 'org-export-general | |
346 | :type 'boolean) | |
347 | ||
348 | (defcustom org-export-with-clocks nil | |
349 | "Non-nil means export CLOCK keywords. | |
350 | This option can also be set with the OPTIONS keyword, | |
351 | e.g. \"c:t\"." | |
352 | :group 'org-export-general | |
353 | :type 'boolean) | |
354 | ||
355 | (defcustom org-export-with-creator 'comment | |
356 | "Non-nil means the postamble should contain a creator sentence. | |
357 | ||
358 | The sentence can be set in `org-export-creator-string' and | |
359 | defaults to \"Generated by Org mode XX in Emacs XXX.\". | |
360 | ||
361 | If the value is `comment' insert it as a comment." | |
362 | :group 'org-export-general | |
363 | :type '(choice | |
364 | (const :tag "No creator sentence" nil) | |
3c8b09ca | 365 | (const :tag "Sentence as a comment" comment) |
271672fa BG |
366 | (const :tag "Insert the sentence" t))) |
367 | ||
368 | (defcustom org-export-with-date t | |
369 | "Non-nil means insert date in the exported document. | |
370 | This option can also be set with the OPTIONS keyword, | |
371 | e.g. \"date:nil\"." | |
372 | :group 'org-export-general | |
373 | :type 'boolean) | |
374 | ||
375 | (defcustom org-export-date-timestamp-format nil | |
376 | "Time-stamp format string to use for DATE keyword. | |
377 | ||
378 | The format string, when specified, only applies if date consists | |
379 | in a single time-stamp. Otherwise its value will be ignored. | |
380 | ||
381 | See `format-time-string' for details on how to build this | |
382 | string." | |
383 | :group 'org-export-general | |
384 | :type '(choice | |
385 | (string :tag "Time-stamp format string") | |
386 | (const :tag "No format string" nil))) | |
387 | ||
388 | (defcustom org-export-creator-string | |
389 | (format "Emacs %s (Org mode %s)" | |
390 | emacs-version | |
391 | (if (fboundp 'org-version) (org-version) "unknown version")) | |
392 | "Information about the creator of the document. | |
393 | This option can also be set on with the CREATOR keyword." | |
394 | :group 'org-export-general | |
395 | :type '(string :tag "Creator string")) | |
396 | ||
397 | (defcustom org-export-with-drawers '(not "LOGBOOK") | |
398 | "Non-nil means export contents of standard drawers. | |
399 | ||
400 | When t, all drawers are exported. This may also be a list of | |
401 | drawer names to export. If that list starts with `not', only | |
402 | drawers with such names will be ignored. | |
403 | ||
404 | This variable doesn't apply to properties drawers. | |
405 | ||
406 | This option can also be set with the OPTIONS keyword, | |
407 | e.g. \"d:nil\"." | |
408 | :group 'org-export-general | |
409 | :version "24.4" | |
410 | :package-version '(Org . "8.0") | |
411 | :type '(choice | |
412 | (const :tag "All drawers" t) | |
413 | (const :tag "None" nil) | |
414 | (repeat :tag "Selected drawers" | |
415 | (string :tag "Drawer name")) | |
416 | (list :tag "Ignored drawers" | |
417 | (const :format "" not) | |
418 | (repeat :tag "Specify names of drawers to ignore during export" | |
419 | :inline t | |
420 | (string :tag "Drawer name"))))) | |
421 | ||
422 | (defcustom org-export-with-email nil | |
423 | "Non-nil means insert author email into the exported file. | |
424 | This option can also be set with the OPTIONS keyword, | |
425 | e.g. \"email:t\"." | |
426 | :group 'org-export-general | |
427 | :type 'boolean) | |
428 | ||
429 | (defcustom org-export-with-emphasize t | |
430 | "Non-nil means interpret *word*, /word/, _word_ and +word+. | |
431 | ||
432 | If the export target supports emphasizing text, the word will be | |
433 | typeset in bold, italic, with an underline or strike-through, | |
434 | respectively. | |
435 | ||
436 | This option can also be set with the OPTIONS keyword, | |
437 | e.g. \"*:nil\"." | |
438 | :group 'org-export-general | |
439 | :type 'boolean) | |
440 | ||
441 | (defcustom org-export-exclude-tags '("noexport") | |
442 | "Tags that exclude a tree from export. | |
443 | ||
444 | All trees carrying any of these tags will be excluded from | |
445 | export. This is without condition, so even subtrees inside that | |
446 | carry one of the `org-export-select-tags' will be removed. | |
447 | ||
448 | This option can also be set with the EXCLUDE_TAGS keyword." | |
449 | :group 'org-export-general | |
450 | :type '(repeat (string :tag "Tag"))) | |
451 | ||
452 | (defcustom org-export-with-fixed-width t | |
453 | "Non-nil means lines starting with \":\" will be in fixed width font. | |
454 | ||
455 | This can be used to have pre-formatted text, fragments of code | |
456 | etc. For example: | |
457 | : ;; Some Lisp examples | |
458 | : (while (defc cnt) | |
459 | : (ding)) | |
460 | will be looking just like this in also HTML. See also the QUOTE | |
461 | keyword. Not all export backends support this. | |
462 | ||
463 | This option can also be set with the OPTIONS keyword, | |
464 | e.g. \"::nil\"." | |
465 | :group 'org-export-general | |
466 | :type 'boolean) | |
467 | ||
468 | (defcustom org-export-with-footnotes t | |
469 | "Non-nil means Org footnotes should be exported. | |
470 | This option can also be set with the OPTIONS keyword, | |
471 | e.g. \"f:nil\"." | |
472 | :group 'org-export-general | |
473 | :type 'boolean) | |
474 | ||
475 | (defcustom org-export-with-latex t | |
476 | "Non-nil means process LaTeX environments and fragments. | |
477 | ||
478 | This option can also be set with the OPTIONS line, | |
479 | e.g. \"tex:verbatim\". Allowed values are: | |
480 | ||
481 | nil Ignore math snippets. | |
482 | `verbatim' Keep everything in verbatim. | |
483 | t Allow export of math snippets." | |
484 | :group 'org-export-general | |
485 | :version "24.4" | |
486 | :package-version '(Org . "8.0") | |
487 | :type '(choice | |
488 | (const :tag "Do not process math in any way" nil) | |
489 | (const :tag "Interpret math snippets" t) | |
490 | (const :tag "Leave math verbatim" verbatim))) | |
491 | ||
492 | (defcustom org-export-headline-levels 3 | |
493 | "The last level which is still exported as a headline. | |
494 | ||
495 | Inferior levels will usually produce itemize or enumerate lists | |
3c8b09ca | 496 | when exported, but back-end behaviour may differ. |
271672fa BG |
497 | |
498 | This option can also be set with the OPTIONS keyword, | |
499 | e.g. \"H:2\"." | |
500 | :group 'org-export-general | |
501 | :type 'integer) | |
502 | ||
503 | (defcustom org-export-default-language "en" | |
504 | "The default language for export and clocktable translations, as a string. | |
505 | This may have an association in | |
506 | `org-clock-clocktable-language-setup', | |
507 | `org-export-smart-quotes-alist' and `org-export-dictionary'. | |
508 | This option can also be set with the LANGUAGE keyword." | |
509 | :group 'org-export-general | |
510 | :type '(string :tag "Language")) | |
511 | ||
512 | (defcustom org-export-preserve-breaks nil | |
513 | "Non-nil means preserve all line breaks when exporting. | |
514 | This option can also be set with the OPTIONS keyword, | |
515 | e.g. \"\\n:t\"." | |
516 | :group 'org-export-general | |
517 | :type 'boolean) | |
518 | ||
519 | (defcustom org-export-with-entities t | |
520 | "Non-nil means interpret entities when exporting. | |
521 | ||
522 | For example, HTML export converts \\alpha to α and \\AA to | |
523 | Å. | |
524 | ||
525 | For a list of supported names, see the constant `org-entities' | |
526 | and the user option `org-entities-user'. | |
527 | ||
528 | This option can also be set with the OPTIONS keyword, | |
529 | e.g. \"e:nil\"." | |
530 | :group 'org-export-general | |
531 | :type 'boolean) | |
532 | ||
533 | (defcustom org-export-with-inlinetasks t | |
534 | "Non-nil means inlinetasks should be exported. | |
535 | This option can also be set with the OPTIONS keyword, | |
536 | e.g. \"inline:nil\"." | |
537 | :group 'org-export-general | |
538 | :version "24.4" | |
539 | :package-version '(Org . "8.0") | |
540 | :type 'boolean) | |
541 | ||
542 | (defcustom org-export-with-planning nil | |
543 | "Non-nil means include planning info in export. | |
544 | ||
545 | Planning info is the line containing either SCHEDULED:, | |
546 | DEADLINE:, CLOSED: time-stamps, or a combination of them. | |
547 | ||
548 | This option can also be set with the OPTIONS keyword, | |
549 | e.g. \"p:t\"." | |
550 | :group 'org-export-general | |
551 | :version "24.4" | |
552 | :package-version '(Org . "8.0") | |
553 | :type 'boolean) | |
554 | ||
555 | (defcustom org-export-with-priority nil | |
556 | "Non-nil means include priority cookies in export. | |
557 | This option can also be set with the OPTIONS keyword, | |
558 | e.g. \"pri:t\"." | |
559 | :group 'org-export-general | |
560 | :type 'boolean) | |
561 | ||
562 | (defcustom org-export-with-section-numbers t | |
563 | "Non-nil means add section numbers to headlines when exporting. | |
564 | ||
565 | When set to an integer n, numbering will only happen for | |
566 | headlines whose relative level is higher or equal to n. | |
567 | ||
568 | This option can also be set with the OPTIONS keyword, | |
569 | e.g. \"num:t\"." | |
570 | :group 'org-export-general | |
571 | :type 'boolean) | |
572 | ||
573 | (defcustom org-export-select-tags '("export") | |
574 | "Tags that select a tree for export. | |
575 | ||
576 | If any such tag is found in a buffer, all trees that do not carry | |
577 | one of these tags will be ignored during export. Inside trees | |
578 | that are selected like this, you can still deselect a subtree by | |
579 | tagging it with one of the `org-export-exclude-tags'. | |
580 | ||
581 | This option can also be set with the SELECT_TAGS keyword." | |
582 | :group 'org-export-general | |
583 | :type '(repeat (string :tag "Tag"))) | |
584 | ||
585 | (defcustom org-export-with-smart-quotes nil | |
586 | "Non-nil means activate smart quotes during export. | |
587 | This option can also be set with the OPTIONS keyword, | |
588 | e.g., \"':t\". | |
589 | ||
590 | When setting this to non-nil, you need to take care of | |
591 | using the correct Babel package when exporting to LaTeX. | |
592 | E.g., you can load Babel for french like this: | |
593 | ||
594 | #+LATEX_HEADER: \\usepackage[french]{babel}" | |
595 | :group 'org-export-general | |
596 | :version "24.4" | |
597 | :package-version '(Org . "8.0") | |
598 | :type 'boolean) | |
599 | ||
600 | (defcustom org-export-with-special-strings t | |
601 | "Non-nil means interpret \"\\-\", \"--\" and \"---\" for export. | |
602 | ||
603 | When this option is turned on, these strings will be exported as: | |
604 | ||
605 | Org HTML LaTeX UTF-8 | |
606 | -----+----------+--------+------- | |
607 | \\- ­ \\- | |
608 | -- – -- – | |
609 | --- — --- — | |
610 | ... … \\ldots … | |
611 | ||
612 | This option can also be set with the OPTIONS keyword, | |
613 | e.g. \"-:nil\"." | |
614 | :group 'org-export-general | |
615 | :type 'boolean) | |
616 | ||
617 | (defcustom org-export-with-statistics-cookies t | |
618 | "Non-nil means include statistics cookies in export. | |
619 | This option can also be set with the OPTIONS keyword, | |
620 | e.g. \"stat:nil\"" | |
621 | :group 'org-export-general | |
622 | :version "24.4" | |
623 | :package-version '(Org . "8.0") | |
624 | :type 'boolean) | |
625 | ||
626 | (defcustom org-export-with-sub-superscripts t | |
627 | "Non-nil means interpret \"_\" and \"^\" for export. | |
628 | ||
73d3db82 BG |
629 | If you want to control how Org displays those characters, see |
630 | `org-use-sub-superscripts'. `org-export-with-sub-superscripts' | |
631 | used to be an alias for `org-use-sub-superscripts' in Org <8.0, | |
632 | it is not anymore. | |
633 | ||
271672fa | 634 | When this option is turned on, you can use TeX-like syntax for |
73d3db82 BG |
635 | sub- and superscripts and see them exported correctly. |
636 | ||
637 | You can also set the option with #+OPTIONS: ^:t | |
638 | ||
639 | Several characters after \"_\" or \"^\" will be considered as a | |
640 | single item - so grouping with {} is normally not needed. For | |
641 | example, the following things will be parsed as single sub- or | |
642 | superscripts: | |
271672fa BG |
643 | |
644 | 10^24 or 10^tau several digits will be considered 1 item. | |
645 | 10^-12 or 10^-tau a leading sign with digits or a word | |
646 | x^2-y^3 will be read as x^2 - y^3, because items are | |
647 | terminated by almost any nonword/nondigit char. | |
648 | x_{i^2} or x^(2-i) braces or parenthesis do grouping. | |
649 | ||
73d3db82 BG |
650 | Still, ambiguity is possible. So when in doubt, use {} to enclose |
651 | the sub/superscript. If you set this variable to the symbol `{}', | |
652 | the braces are *required* in order to trigger interpretations as | |
653 | sub/superscript. This can be helpful in documents that need \"_\" | |
654 | frequently in plain text." | |
271672fa | 655 | :group 'org-export-general |
73d3db82 BG |
656 | :version "24.4" |
657 | :package-version '(Org . "8.0") | |
271672fa BG |
658 | :type '(choice |
659 | (const :tag "Interpret them" t) | |
660 | (const :tag "Curly brackets only" {}) | |
661 | (const :tag "Do not interpret them" nil))) | |
662 | ||
663 | (defcustom org-export-with-toc t | |
664 | "Non-nil means create a table of contents in exported files. | |
665 | ||
666 | The TOC contains headlines with levels up | |
667 | to`org-export-headline-levels'. When an integer, include levels | |
668 | up to N in the toc, this may then be different from | |
669 | `org-export-headline-levels', but it will not be allowed to be | |
670 | larger than the number of headline levels. When nil, no table of | |
671 | contents is made. | |
672 | ||
673 | This option can also be set with the OPTIONS keyword, | |
674 | e.g. \"toc:nil\" or \"toc:3\"." | |
675 | :group 'org-export-general | |
676 | :type '(choice | |
677 | (const :tag "No Table of Contents" nil) | |
678 | (const :tag "Full Table of Contents" t) | |
679 | (integer :tag "TOC to level"))) | |
680 | ||
681 | (defcustom org-export-with-tables t | |
682 | "If non-nil, lines starting with \"|\" define a table. | |
683 | For example: | |
684 | ||
685 | | Name | Address | Birthday | | |
686 | |-------------+----------+-----------| | |
687 | | Arthur Dent | England | 29.2.2100 | | |
688 | ||
689 | This option can also be set with the OPTIONS keyword, | |
690 | e.g. \"|:nil\"." | |
691 | :group 'org-export-general | |
692 | :type 'boolean) | |
693 | ||
694 | (defcustom org-export-with-tags t | |
695 | "If nil, do not export tags, just remove them from headlines. | |
696 | ||
697 | If this is the symbol `not-in-toc', tags will be removed from | |
698 | table of contents entries, but still be shown in the headlines of | |
699 | the document. | |
700 | ||
701 | This option can also be set with the OPTIONS keyword, | |
702 | e.g. \"tags:nil\"." | |
703 | :group 'org-export-general | |
704 | :type '(choice | |
705 | (const :tag "Off" nil) | |
706 | (const :tag "Not in TOC" not-in-toc) | |
707 | (const :tag "On" t))) | |
708 | ||
709 | (defcustom org-export-with-tasks t | |
710 | "Non-nil means include TODO items for export. | |
711 | ||
712 | This may have the following values: | |
713 | t include tasks independent of state. | |
714 | `todo' include only tasks that are not yet done. | |
715 | `done' include only tasks that are already done. | |
716 | nil ignore all tasks. | |
717 | list of keywords include tasks with these keywords. | |
718 | ||
719 | This option can also be set with the OPTIONS keyword, | |
720 | e.g. \"tasks:nil\"." | |
721 | :group 'org-export-general | |
722 | :type '(choice | |
723 | (const :tag "All tasks" t) | |
724 | (const :tag "No tasks" nil) | |
725 | (const :tag "Not-done tasks" todo) | |
726 | (const :tag "Only done tasks" done) | |
727 | (repeat :tag "Specific TODO keywords" | |
728 | (string :tag "Keyword")))) | |
729 | ||
730 | (defcustom org-export-time-stamp-file t | |
731 | "Non-nil means insert a time stamp into the exported file. | |
732 | The time stamp shows when the file was created. This option can | |
733 | also be set with the OPTIONS keyword, e.g. \"timestamp:nil\"." | |
734 | :group 'org-export-general | |
735 | :type 'boolean) | |
736 | ||
737 | (defcustom org-export-with-timestamps t | |
738 | "Non nil means allow timestamps in export. | |
739 | ||
740 | It can be set to any of the following values: | |
741 | t export all timestamps. | |
742 | `active' export active timestamps only. | |
743 | `inactive' export inactive timestamps only. | |
744 | nil do not export timestamps | |
745 | ||
746 | This only applies to timestamps isolated in a paragraph | |
747 | containing only timestamps. Other timestamps are always | |
748 | exported. | |
749 | ||
750 | This option can also be set with the OPTIONS keyword, e.g. | |
751 | \"<:nil\"." | |
752 | :group 'org-export-general | |
753 | :type '(choice | |
754 | (const :tag "All timestamps" t) | |
755 | (const :tag "Only active timestamps" active) | |
756 | (const :tag "Only inactive timestamps" inactive) | |
757 | (const :tag "No timestamp" nil))) | |
758 | ||
759 | (defcustom org-export-with-todo-keywords t | |
760 | "Non-nil means include TODO keywords in export. | |
761 | When nil, remove all these keywords from the export. This option | |
762 | can also be set with the OPTIONS keyword, e.g. \"todo:nil\"." | |
763 | :group 'org-export-general | |
764 | :type 'boolean) | |
765 | ||
766 | (defcustom org-export-allow-bind-keywords nil | |
767 | "Non-nil means BIND keywords can define local variable values. | |
768 | This is a potential security risk, which is why the default value | |
769 | is nil. You can also allow them through local buffer variables." | |
770 | :group 'org-export-general | |
771 | :version "24.4" | |
772 | :package-version '(Org . "8.0") | |
773 | :type 'boolean) | |
774 | ||
775 | (defcustom org-export-snippet-translation-alist nil | |
776 | "Alist between export snippets back-ends and exporter back-ends. | |
777 | ||
778 | This variable allows to provide shortcuts for export snippets. | |
779 | ||
780 | For example, with a value of '\(\(\"h\" . \"html\"\)\), the | |
781 | HTML back-end will recognize the contents of \"@@h:<b>@@\" as | |
782 | HTML code while every other back-end will ignore it." | |
783 | :group 'org-export-general | |
784 | :version "24.4" | |
785 | :package-version '(Org . "8.0") | |
786 | :type '(repeat | |
787 | (cons (string :tag "Shortcut") | |
788 | (string :tag "Back-end")))) | |
789 | ||
790 | (defcustom org-export-coding-system nil | |
791 | "Coding system for the exported file." | |
792 | :group 'org-export-general | |
793 | :version "24.4" | |
794 | :package-version '(Org . "8.0") | |
795 | :type 'coding-system) | |
796 | ||
797 | (defcustom org-export-copy-to-kill-ring 'if-interactive | |
30cb51f1 BG |
798 | "Non-nil means pushing export output to the kill ring. |
799 | This variable is ignored during asynchronous export." | |
271672fa BG |
800 | :group 'org-export-general |
801 | :version "24.3" | |
802 | :type '(choice | |
803 | (const :tag "Always" t) | |
804 | (const :tag "When export is done interactively" if-interactive) | |
805 | (const :tag "Never" nil))) | |
806 | ||
807 | (defcustom org-export-initial-scope 'buffer | |
808 | "The initial scope when exporting with `org-export-dispatch'. | |
809 | This variable can be either set to `buffer' or `subtree'." | |
810 | :group 'org-export-general | |
811 | :type '(choice | |
812 | (const :tag "Export current buffer" buffer) | |
813 | (const :tag "Export current subtree" subtree))) | |
814 | ||
815 | (defcustom org-export-show-temporary-export-buffer t | |
816 | "Non-nil means show buffer after exporting to temp buffer. | |
817 | When Org exports to a file, the buffer visiting that file is ever | |
818 | shown, but remains buried. However, when exporting to | |
819 | a temporary buffer, that buffer is popped up in a second window. | |
820 | When this variable is nil, the buffer remains buried also in | |
821 | these cases." | |
822 | :group 'org-export-general | |
823 | :type 'boolean) | |
824 | ||
825 | (defcustom org-export-in-background nil | |
826 | "Non-nil means export and publishing commands will run in background. | |
827 | Results from an asynchronous export are never displayed | |
828 | automatically. But you can retrieve them with \\[org-export-stack]." | |
829 | :group 'org-export-general | |
830 | :version "24.4" | |
831 | :package-version '(Org . "8.0") | |
832 | :type 'boolean) | |
833 | ||
834 | (defcustom org-export-async-init-file user-init-file | |
835 | "File used to initialize external export process. | |
836 | Value must be an absolute file name. It defaults to user's | |
837 | initialization file. Though, a specific configuration makes the | |
838 | process faster and the export more portable." | |
839 | :group 'org-export-general | |
840 | :version "24.4" | |
841 | :package-version '(Org . "8.0") | |
842 | :type '(file :must-match t)) | |
843 | ||
844 | (defcustom org-export-dispatch-use-expert-ui nil | |
845 | "Non-nil means using a non-intrusive `org-export-dispatch'. | |
846 | In that case, no help buffer is displayed. Though, an indicator | |
847 | for current export scope is added to the prompt (\"b\" when | |
848 | output is restricted to body only, \"s\" when it is restricted to | |
849 | the current subtree, \"v\" when only visible elements are | |
850 | considered for export, \"f\" when publishing functions should be | |
851 | passed the FORCE argument and \"a\" when the export should be | |
852 | asynchronous). Also, \[?] allows to switch back to standard | |
853 | mode." | |
854 | :group 'org-export-general | |
855 | :version "24.4" | |
856 | :package-version '(Org . "8.0") | |
857 | :type 'boolean) | |
858 | ||
859 | ||
860 | \f | |
861 | ;;; Defining Back-ends | |
862 | ;; | |
863 | ;; An export back-end is a structure with `org-export-backend' type | |
864 | ;; and `name', `parent', `transcoders', `options', `filters', `blocks' | |
865 | ;; and `menu' slots. | |
866 | ;; | |
867 | ;; At the lowest level, a back-end is created with | |
868 | ;; `org-export-create-backend' function. | |
869 | ;; | |
870 | ;; A named back-end can be registered with | |
871 | ;; `org-export-register-backend' function. A registered back-end can | |
872 | ;; later be referred to by its name, with `org-export-get-backend' | |
873 | ;; function. Also, such a back-end can become the parent of a derived | |
874 | ;; back-end from which slot values will be inherited by default. | |
875 | ;; `org-export-derived-backend-p' can check if a given back-end is | |
876 | ;; derived from a list of back-end names. | |
877 | ;; | |
878 | ;; `org-export-get-all-transcoders', `org-export-get-all-options' and | |
879 | ;; `org-export-get-all-filters' return the full alist of transcoders, | |
880 | ;; options and filters, including those inherited from ancestors. | |
881 | ;; | |
882 | ;; At a higher level, `org-export-define-backend' is the standard way | |
883 | ;; to define an export back-end. If the new back-end is similar to | |
884 | ;; a registered back-end, `org-export-define-derived-backend' may be | |
885 | ;; used instead. | |
886 | ;; | |
887 | ;; Eventually `org-export-barf-if-invalid-backend' returns an error | |
888 | ;; when a given back-end hasn't been registered yet. | |
889 | ||
890 | (defstruct (org-export-backend (:constructor org-export-create-backend) | |
891 | (:copier nil)) | |
892 | name parent transcoders options filters blocks menu) | |
893 | ||
894 | (defun org-export-get-backend (name) | |
895 | "Return export back-end named after NAME. | |
896 | NAME is a symbol. Return nil if no such back-end is found." | |
897 | (catch 'found | |
898 | (dolist (b org-export--registered-backends) | |
899 | (when (eq (org-export-backend-name b) name) | |
900 | (throw 'found b))))) | |
901 | ||
902 | (defun org-export-register-backend (backend) | |
903 | "Register BACKEND as a known export back-end. | |
904 | BACKEND is a structure with `org-export-backend' type." | |
905 | ;; Refuse to register an unnamed back-end. | |
906 | (unless (org-export-backend-name backend) | |
907 | (error "Cannot register a unnamed export back-end")) | |
908 | ;; Refuse to register a back-end with an unknown parent. | |
909 | (let ((parent (org-export-backend-parent backend))) | |
910 | (when (and parent (not (org-export-get-backend parent))) | |
911 | (error "Cannot use unknown \"%s\" back-end as a parent" parent))) | |
912 | ;; Register dedicated export blocks in the parser. | |
913 | (dolist (name (org-export-backend-blocks backend)) | |
914 | (add-to-list 'org-element-block-name-alist | |
915 | (cons name 'org-element-export-block-parser))) | |
916 | ;; If a back-end with the same name as BACKEND is already | |
917 | ;; registered, replace it with BACKEND. Otherwise, simply add | |
918 | ;; BACKEND to the list of registered back-ends. | |
919 | (let ((old (org-export-get-backend (org-export-backend-name backend)))) | |
920 | (if old (setcar (memq old org-export--registered-backends) backend) | |
921 | (push backend org-export--registered-backends)))) | |
922 | ||
923 | (defun org-export-barf-if-invalid-backend (backend) | |
924 | "Signal an error if BACKEND isn't defined." | |
925 | (unless (org-export-backend-p backend) | |
926 | (error "Unknown \"%s\" back-end: Aborting export" backend))) | |
927 | ||
928 | (defun org-export-derived-backend-p (backend &rest backends) | |
929 | "Non-nil if BACKEND is derived from one of BACKENDS. | |
930 | BACKEND is an export back-end, as returned by, e.g., | |
931 | `org-export-create-backend', or a symbol referring to | |
932 | a registered back-end. BACKENDS is constituted of symbols." | |
933 | (when (symbolp backend) (setq backend (org-export-get-backend backend))) | |
934 | (when backend | |
935 | (catch 'exit | |
936 | (while (org-export-backend-parent backend) | |
937 | (when (memq (org-export-backend-name backend) backends) | |
938 | (throw 'exit t)) | |
939 | (setq backend | |
940 | (org-export-get-backend (org-export-backend-parent backend)))) | |
941 | (memq (org-export-backend-name backend) backends)))) | |
942 | ||
943 | (defun org-export-get-all-transcoders (backend) | |
944 | "Return full translation table for BACKEND. | |
945 | ||
946 | BACKEND is an export back-end, as return by, e.g,, | |
947 | `org-export-create-backend'. Return value is an alist where | |
948 | keys are element or object types, as symbols, and values are | |
949 | transcoders. | |
950 | ||
951 | Unlike to `org-export-backend-transcoders', this function | |
952 | also returns transcoders inherited from parent back-ends, | |
953 | if any." | |
954 | (when (symbolp backend) (setq backend (org-export-get-backend backend))) | |
955 | (when backend | |
956 | (let ((transcoders (org-export-backend-transcoders backend)) | |
957 | parent) | |
958 | (while (setq parent (org-export-backend-parent backend)) | |
959 | (setq backend (org-export-get-backend parent)) | |
960 | (setq transcoders | |
961 | (append transcoders (org-export-backend-transcoders backend)))) | |
962 | transcoders))) | |
963 | ||
964 | (defun org-export-get-all-options (backend) | |
965 | "Return export options for BACKEND. | |
966 | ||
967 | BACKEND is an export back-end, as return by, e.g,, | |
968 | `org-export-create-backend'. See `org-export-options-alist' | |
969 | for the shape of the return value. | |
970 | ||
971 | Unlike to `org-export-backend-options', this function also | |
972 | returns options inherited from parent back-ends, if any." | |
973 | (when (symbolp backend) (setq backend (org-export-get-backend backend))) | |
974 | (when backend | |
975 | (let ((options (org-export-backend-options backend)) | |
976 | parent) | |
977 | (while (setq parent (org-export-backend-parent backend)) | |
978 | (setq backend (org-export-get-backend parent)) | |
979 | (setq options (append options (org-export-backend-options backend)))) | |
980 | options))) | |
981 | ||
982 | (defun org-export-get-all-filters (backend) | |
983 | "Return complete list of filters for BACKEND. | |
984 | ||
985 | BACKEND is an export back-end, as return by, e.g,, | |
986 | `org-export-create-backend'. Return value is an alist where | |
987 | keys are symbols and values lists of functions. | |
988 | ||
989 | Unlike to `org-export-backend-filters', this function also | |
990 | returns filters inherited from parent back-ends, if any." | |
991 | (when (symbolp backend) (setq backend (org-export-get-backend backend))) | |
992 | (when backend | |
993 | (let ((filters (org-export-backend-filters backend)) | |
994 | parent) | |
995 | (while (setq parent (org-export-backend-parent backend)) | |
996 | (setq backend (org-export-get-backend parent)) | |
997 | (setq filters (append filters (org-export-backend-filters backend)))) | |
998 | filters))) | |
999 | ||
1000 | (defun org-export-define-backend (backend transcoders &rest body) | |
1001 | "Define a new back-end BACKEND. | |
1002 | ||
1003 | TRANSCODERS is an alist between object or element types and | |
1004 | functions handling them. | |
1005 | ||
1006 | These functions should return a string without any trailing | |
1007 | space, or nil. They must accept three arguments: the object or | |
1008 | element itself, its contents or nil when it isn't recursive and | |
1009 | the property list used as a communication channel. | |
1010 | ||
1011 | Contents, when not nil, are stripped from any global indentation | |
1012 | \(although the relative one is preserved). They also always end | |
1013 | with a single newline character. | |
1014 | ||
1015 | If, for a given type, no function is found, that element or | |
1016 | object type will simply be ignored, along with any blank line or | |
1017 | white space at its end. The same will happen if the function | |
1018 | returns the nil value. If that function returns the empty | |
1019 | string, the type will be ignored, but the blank lines or white | |
1020 | spaces will be kept. | |
1021 | ||
1022 | In addition to element and object types, one function can be | |
1023 | associated to the `template' (or `inner-template') symbol and | |
1024 | another one to the `plain-text' symbol. | |
1025 | ||
1026 | The former returns the final transcoded string, and can be used | |
1027 | to add a preamble and a postamble to document's body. It must | |
1028 | accept two arguments: the transcoded string and the property list | |
1029 | containing export options. A function associated to `template' | |
1030 | will not be applied if export has option \"body-only\". | |
1031 | A function associated to `inner-template' is always applied. | |
1032 | ||
1033 | The latter, when defined, is to be called on every text not | |
1034 | recognized as an element or an object. It must accept two | |
1035 | arguments: the text string and the information channel. It is an | |
1036 | appropriate place to protect special chars relative to the | |
1037 | back-end. | |
1038 | ||
1039 | BODY can start with pre-defined keyword arguments. The following | |
1040 | keywords are understood: | |
1041 | ||
1042 | :export-block | |
1043 | ||
1044 | String, or list of strings, representing block names that | |
1045 | will not be parsed. This is used to specify blocks that will | |
1046 | contain raw code specific to the back-end. These blocks | |
1047 | still have to be handled by the relative `export-block' type | |
1048 | translator. | |
1049 | ||
1050 | :filters-alist | |
1051 | ||
1052 | Alist between filters and function, or list of functions, | |
1053 | specific to the back-end. See `org-export-filters-alist' for | |
1054 | a list of all allowed filters. Filters defined here | |
1055 | shouldn't make a back-end test, as it may prevent back-ends | |
1056 | derived from this one to behave properly. | |
1057 | ||
1058 | :menu-entry | |
1059 | ||
1060 | Menu entry for the export dispatcher. It should be a list | |
1061 | like: | |
1062 | ||
1063 | '(KEY DESCRIPTION-OR-ORDINAL ACTION-OR-MENU) | |
1064 | ||
1065 | where : | |
1066 | ||
1067 | KEY is a free character selecting the back-end. | |
1068 | ||
1069 | DESCRIPTION-OR-ORDINAL is either a string or a number. | |
1070 | ||
1071 | If it is a string, is will be used to name the back-end in | |
1072 | its menu entry. If it is a number, the following menu will | |
1073 | be displayed as a sub-menu of the back-end with the same | |
1074 | KEY. Also, the number will be used to determine in which | |
1075 | order such sub-menus will appear (lowest first). | |
1076 | ||
1077 | ACTION-OR-MENU is either a function or an alist. | |
1078 | ||
1079 | If it is an action, it will be called with four | |
1080 | arguments (booleans): ASYNC, SUBTREEP, VISIBLE-ONLY and | |
1081 | BODY-ONLY. See `org-export-as' for further explanations on | |
1082 | some of them. | |
1083 | ||
1084 | If it is an alist, associations should follow the | |
1085 | pattern: | |
1086 | ||
1087 | '(KEY DESCRIPTION ACTION) | |
1088 | ||
1089 | where KEY, DESCRIPTION and ACTION are described above. | |
1090 | ||
1091 | Valid values include: | |
1092 | ||
1093 | '(?m \"My Special Back-end\" my-special-export-function) | |
1094 | ||
1095 | or | |
1096 | ||
1097 | '(?l \"Export to LaTeX\" | |
1098 | \(?p \"As PDF file\" org-latex-export-to-pdf) | |
1099 | \(?o \"As PDF file and open\" | |
1100 | \(lambda (a s v b) | |
1101 | \(if a (org-latex-export-to-pdf t s v b) | |
1102 | \(org-open-file | |
1103 | \(org-latex-export-to-pdf nil s v b))))))) | |
1104 | ||
1105 | or the following, which will be added to the previous | |
1106 | sub-menu, | |
1107 | ||
1108 | '(?l 1 | |
1109 | \((?B \"As TEX buffer (Beamer)\" org-beamer-export-as-latex) | |
1110 | \(?P \"As PDF file (Beamer)\" org-beamer-export-to-pdf))) | |
1111 | ||
1112 | :options-alist | |
1113 | ||
1114 | Alist between back-end specific properties introduced in | |
1115 | communication channel and how their value are acquired. See | |
1116 | `org-export-options-alist' for more information about | |
1117 | structure of the values." | |
1118 | (declare (indent 1)) | |
1119 | (let (blocks filters menu-entry options contents) | |
1120 | (while (keywordp (car body)) | |
1121 | (case (pop body) | |
1122 | (:export-block (let ((names (pop body))) | |
1123 | (setq blocks (if (consp names) (mapcar 'upcase names) | |
1124 | (list (upcase names)))))) | |
1125 | (:filters-alist (setq filters (pop body))) | |
1126 | (:menu-entry (setq menu-entry (pop body))) | |
1127 | (:options-alist (setq options (pop body))) | |
1128 | (t (pop body)))) | |
1129 | (org-export-register-backend | |
1130 | (org-export-create-backend :name backend | |
1131 | :transcoders transcoders | |
1132 | :options options | |
1133 | :filters filters | |
1134 | :blocks blocks | |
1135 | :menu menu-entry)))) | |
1136 | ||
1137 | (defun org-export-define-derived-backend (child parent &rest body) | |
1138 | "Create a new back-end as a variant of an existing one. | |
1139 | ||
1140 | CHILD is the name of the derived back-end. PARENT is the name of | |
1141 | the parent back-end. | |
1142 | ||
1143 | BODY can start with pre-defined keyword arguments. The following | |
1144 | keywords are understood: | |
1145 | ||
1146 | :export-block | |
1147 | ||
1148 | String, or list of strings, representing block names that | |
1149 | will not be parsed. This is used to specify blocks that will | |
1150 | contain raw code specific to the back-end. These blocks | |
1151 | still have to be handled by the relative `export-block' type | |
1152 | translator. | |
1153 | ||
1154 | :filters-alist | |
1155 | ||
1156 | Alist of filters that will overwrite or complete filters | |
1157 | defined in PARENT back-end. See `org-export-filters-alist' | |
1158 | for a list of allowed filters. | |
1159 | ||
1160 | :menu-entry | |
1161 | ||
1162 | Menu entry for the export dispatcher. See | |
1163 | `org-export-define-backend' for more information about the | |
1164 | expected value. | |
1165 | ||
1166 | :options-alist | |
1167 | ||
1168 | Alist of back-end specific properties that will overwrite or | |
1169 | complete those defined in PARENT back-end. Refer to | |
1170 | `org-export-options-alist' for more information about | |
1171 | structure of the values. | |
1172 | ||
1173 | :translate-alist | |
1174 | ||
1175 | Alist of element and object types and transcoders that will | |
1176 | overwrite or complete transcode table from PARENT back-end. | |
1177 | Refer to `org-export-define-backend' for detailed information | |
1178 | about transcoders. | |
1179 | ||
1180 | As an example, here is how one could define \"my-latex\" back-end | |
1181 | as a variant of `latex' back-end with a custom template function: | |
1182 | ||
1183 | \(org-export-define-derived-backend 'my-latex 'latex | |
1184 | :translate-alist '((template . my-latex-template-fun))) | |
1185 | ||
1186 | The back-end could then be called with, for example: | |
1187 | ||
1188 | \(org-export-to-buffer 'my-latex \"*Test my-latex*\")" | |
1189 | (declare (indent 2)) | |
1190 | (let (blocks filters menu-entry options transcoders contents) | |
1191 | (while (keywordp (car body)) | |
1192 | (case (pop body) | |
1193 | (:export-block (let ((names (pop body))) | |
1194 | (setq blocks (if (consp names) (mapcar 'upcase names) | |
1195 | (list (upcase names)))))) | |
1196 | (:filters-alist (setq filters (pop body))) | |
1197 | (:menu-entry (setq menu-entry (pop body))) | |
1198 | (:options-alist (setq options (pop body))) | |
1199 | (:translate-alist (setq transcoders (pop body))) | |
1200 | (t (pop body)))) | |
1201 | (org-export-register-backend | |
1202 | (org-export-create-backend :name child | |
1203 | :parent parent | |
1204 | :transcoders transcoders | |
1205 | :options options | |
1206 | :filters filters | |
1207 | :blocks blocks | |
1208 | :menu menu-entry)))) | |
1209 | ||
1210 | ||
1211 | \f | |
1212 | ;;; The Communication Channel | |
1213 | ;; | |
1214 | ;; During export process, every function has access to a number of | |
1215 | ;; properties. They are of two types: | |
1216 | ;; | |
1217 | ;; 1. Environment options are collected once at the very beginning of | |
1218 | ;; the process, out of the original buffer and configuration. | |
1219 | ;; Collecting them is handled by `org-export-get-environment' | |
1220 | ;; function. | |
1221 | ;; | |
1222 | ;; Most environment options are defined through the | |
1223 | ;; `org-export-options-alist' variable. | |
1224 | ;; | |
1225 | ;; 2. Tree properties are extracted directly from the parsed tree, | |
1226 | ;; just before export, by `org-export-collect-tree-properties'. | |
1227 | ;; | |
1228 | ;; Here is the full list of properties available during transcode | |
1229 | ;; process, with their category and their value type. | |
1230 | ;; | |
1231 | ;; + `:author' :: Author's name. | |
1232 | ;; - category :: option | |
1233 | ;; - type :: string | |
1234 | ;; | |
1235 | ;; + `:back-end' :: Current back-end used for transcoding. | |
1236 | ;; - category :: tree | |
1237 | ;; - type :: symbol | |
1238 | ;; | |
1239 | ;; + `:creator' :: String to write as creation information. | |
1240 | ;; - category :: option | |
1241 | ;; - type :: string | |
1242 | ;; | |
1243 | ;; + `:date' :: String to use as date. | |
1244 | ;; - category :: option | |
1245 | ;; - type :: string | |
1246 | ;; | |
1247 | ;; + `:description' :: Description text for the current data. | |
1248 | ;; - category :: option | |
1249 | ;; - type :: string | |
1250 | ;; | |
1251 | ;; + `:email' :: Author's email. | |
1252 | ;; - category :: option | |
1253 | ;; - type :: string | |
1254 | ;; | |
1255 | ;; + `:exclude-tags' :: Tags for exclusion of subtrees from export | |
1256 | ;; process. | |
1257 | ;; - category :: option | |
1258 | ;; - type :: list of strings | |
1259 | ;; | |
1260 | ;; + `:export-options' :: List of export options available for current | |
1261 | ;; process. | |
1262 | ;; - category :: none | |
1263 | ;; - type :: list of symbols, among `subtree', `body-only' and | |
1264 | ;; `visible-only'. | |
1265 | ;; | |
1266 | ;; + `:exported-data' :: Hash table used for memoizing | |
1267 | ;; `org-export-data'. | |
1268 | ;; - category :: tree | |
1269 | ;; - type :: hash table | |
1270 | ;; | |
1271 | ;; + `:filetags' :: List of global tags for buffer. Used by | |
1272 | ;; `org-export-get-tags' to get tags with inheritance. | |
1273 | ;; - category :: option | |
1274 | ;; - type :: list of strings | |
1275 | ;; | |
1276 | ;; + `:footnote-definition-alist' :: Alist between footnote labels and | |
1277 | ;; their definition, as parsed data. Only non-inlined footnotes | |
1278 | ;; are represented in this alist. Also, every definition isn't | |
1279 | ;; guaranteed to be referenced in the parse tree. The purpose of | |
1280 | ;; this property is to preserve definitions from oblivion | |
1281 | ;; (i.e. when the parse tree comes from a part of the original | |
1282 | ;; buffer), it isn't meant for direct use in a back-end. To | |
1283 | ;; retrieve a definition relative to a reference, use | |
1284 | ;; `org-export-get-footnote-definition' instead. | |
1285 | ;; - category :: option | |
1286 | ;; - type :: alist (STRING . LIST) | |
1287 | ;; | |
1288 | ;; + `:headline-levels' :: Maximum level being exported as an | |
1289 | ;; headline. Comparison is done with the relative level of | |
1290 | ;; headlines in the parse tree, not necessarily with their | |
1291 | ;; actual level. | |
1292 | ;; - category :: option | |
1293 | ;; - type :: integer | |
1294 | ;; | |
1295 | ;; + `:headline-offset' :: Difference between relative and real level | |
1296 | ;; of headlines in the parse tree. For example, a value of -1 | |
1297 | ;; means a level 2 headline should be considered as level | |
1298 | ;; 1 (cf. `org-export-get-relative-level'). | |
1299 | ;; - category :: tree | |
1300 | ;; - type :: integer | |
1301 | ;; | |
1302 | ;; + `:headline-numbering' :: Alist between headlines and their | |
1303 | ;; numbering, as a list of numbers | |
1304 | ;; (cf. `org-export-get-headline-number'). | |
1305 | ;; - category :: tree | |
1306 | ;; - type :: alist (INTEGER . LIST) | |
1307 | ;; | |
1308 | ;; + `:id-alist' :: Alist between ID strings and destination file's | |
1309 | ;; path, relative to current directory. It is used by | |
1310 | ;; `org-export-resolve-id-link' to resolve ID links targeting an | |
1311 | ;; external file. | |
1312 | ;; - category :: option | |
1313 | ;; - type :: alist (STRING . STRING) | |
1314 | ;; | |
1315 | ;; + `:ignore-list' :: List of elements and objects that should be | |
1316 | ;; ignored during export. | |
1317 | ;; - category :: tree | |
1318 | ;; - type :: list of elements and objects | |
1319 | ;; | |
1320 | ;; + `:input-file' :: Full path to input file, if any. | |
1321 | ;; - category :: option | |
1322 | ;; - type :: string or nil | |
1323 | ;; | |
1324 | ;; + `:keywords' :: List of keywords attached to data. | |
1325 | ;; - category :: option | |
1326 | ;; - type :: string | |
1327 | ;; | |
1328 | ;; + `:language' :: Default language used for translations. | |
1329 | ;; - category :: option | |
1330 | ;; - type :: string | |
1331 | ;; | |
1332 | ;; + `:parse-tree' :: Whole parse tree, available at any time during | |
1333 | ;; transcoding. | |
1334 | ;; - category :: option | |
1335 | ;; - type :: list (as returned by `org-element-parse-buffer') | |
1336 | ;; | |
1337 | ;; + `:preserve-breaks' :: Non-nil means transcoding should preserve | |
1338 | ;; all line breaks. | |
1339 | ;; - category :: option | |
1340 | ;; - type :: symbol (nil, t) | |
1341 | ;; | |
1342 | ;; + `:section-numbers' :: Non-nil means transcoding should add | |
1343 | ;; section numbers to headlines. | |
1344 | ;; - category :: option | |
1345 | ;; - type :: symbol (nil, t) | |
1346 | ;; | |
1347 | ;; + `:select-tags' :: List of tags enforcing inclusion of sub-trees | |
1348 | ;; in transcoding. When such a tag is present, subtrees without | |
1349 | ;; it are de facto excluded from the process. See | |
1350 | ;; `use-select-tags'. | |
1351 | ;; - category :: option | |
1352 | ;; - type :: list of strings | |
1353 | ;; | |
1354 | ;; + `:time-stamp-file' :: Non-nil means transcoding should insert | |
1355 | ;; a time stamp in the output. | |
1356 | ;; - category :: option | |
1357 | ;; - type :: symbol (nil, t) | |
1358 | ;; | |
1359 | ;; + `:translate-alist' :: Alist between element and object types and | |
1360 | ;; transcoding functions relative to the current back-end. | |
1361 | ;; Special keys `inner-template', `template' and `plain-text' are | |
1362 | ;; also possible. | |
1363 | ;; - category :: option | |
1364 | ;; - type :: alist (SYMBOL . FUNCTION) | |
1365 | ;; | |
1366 | ;; + `:with-archived-trees' :: Non-nil when archived subtrees should | |
1367 | ;; also be transcoded. If it is set to the `headline' symbol, | |
1368 | ;; only the archived headline's name is retained. | |
1369 | ;; - category :: option | |
1370 | ;; - type :: symbol (nil, t, `headline') | |
1371 | ;; | |
1372 | ;; + `:with-author' :: Non-nil means author's name should be included | |
1373 | ;; in the output. | |
1374 | ;; - category :: option | |
1375 | ;; - type :: symbol (nil, t) | |
1376 | ;; | |
1377 | ;; + `:with-clocks' :: Non-nil means clock keywords should be exported. | |
1378 | ;; - category :: option | |
1379 | ;; - type :: symbol (nil, t) | |
1380 | ;; | |
1381 | ;; + `:with-creator' :: Non-nil means a creation sentence should be | |
1382 | ;; inserted at the end of the transcoded string. If the value | |
1383 | ;; is `comment', it should be commented. | |
1384 | ;; - category :: option | |
1385 | ;; - type :: symbol (`comment', nil, t) | |
1386 | ;; | |
1387 | ;; + `:with-date' :: Non-nil means output should contain a date. | |
1388 | ;; - category :: option | |
1389 | ;; - type :. symbol (nil, t) | |
1390 | ;; | |
1391 | ;; + `:with-drawers' :: Non-nil means drawers should be exported. If | |
1392 | ;; its value is a list of names, only drawers with such names | |
1393 | ;; will be transcoded. If that list starts with `not', drawer | |
1394 | ;; with these names will be skipped. | |
1395 | ;; - category :: option | |
1396 | ;; - type :: symbol (nil, t) or list of strings | |
1397 | ;; | |
1398 | ;; + `:with-email' :: Non-nil means output should contain author's | |
1399 | ;; email. | |
1400 | ;; - category :: option | |
1401 | ;; - type :: symbol (nil, t) | |
1402 | ;; | |
1403 | ;; + `:with-emphasize' :: Non-nil means emphasized text should be | |
1404 | ;; interpreted. | |
1405 | ;; - category :: option | |
1406 | ;; - type :: symbol (nil, t) | |
1407 | ;; | |
1408 | ;; + `:with-fixed-width' :: Non-nil if transcoder should interpret | |
1409 | ;; strings starting with a colon as a fixed-with (verbatim) area. | |
1410 | ;; - category :: option | |
1411 | ;; - type :: symbol (nil, t) | |
1412 | ;; | |
1413 | ;; + `:with-footnotes' :: Non-nil if transcoder should interpret | |
1414 | ;; footnotes. | |
1415 | ;; - category :: option | |
1416 | ;; - type :: symbol (nil, t) | |
1417 | ;; | |
1418 | ;; + `:with-latex' :: Non-nil means `latex-environment' elements and | |
1419 | ;; `latex-fragment' objects should appear in export output. When | |
1420 | ;; this property is set to `verbatim', they will be left as-is. | |
1421 | ;; - category :: option | |
1422 | ;; - type :: symbol (`verbatim', nil, t) | |
1423 | ;; | |
1424 | ;; + `:with-planning' :: Non-nil means transcoding should include | |
1425 | ;; planning info. | |
1426 | ;; - category :: option | |
1427 | ;; - type :: symbol (nil, t) | |
1428 | ;; | |
1429 | ;; + `:with-priority' :: Non-nil means transcoding should include | |
1430 | ;; priority cookies. | |
1431 | ;; - category :: option | |
1432 | ;; - type :: symbol (nil, t) | |
1433 | ;; | |
1434 | ;; + `:with-smart-quotes' :: Non-nil means activate smart quotes in | |
1435 | ;; plain text. | |
1436 | ;; - category :: option | |
1437 | ;; - type :: symbol (nil, t) | |
1438 | ;; | |
1439 | ;; + `:with-special-strings' :: Non-nil means transcoding should | |
1440 | ;; interpret special strings in plain text. | |
1441 | ;; - category :: option | |
1442 | ;; - type :: symbol (nil, t) | |
1443 | ;; | |
1444 | ;; + `:with-sub-superscript' :: Non-nil means transcoding should | |
1445 | ;; interpret subscript and superscript. With a value of "{}", | |
1446 | ;; only interpret those using curly brackets. | |
1447 | ;; - category :: option | |
1448 | ;; - type :: symbol (nil, {}, t) | |
1449 | ;; | |
1450 | ;; + `:with-tables' :: Non-nil means transcoding should interpret | |
1451 | ;; tables. | |
1452 | ;; - category :: option | |
1453 | ;; - type :: symbol (nil, t) | |
1454 | ;; | |
1455 | ;; + `:with-tags' :: Non-nil means transcoding should keep tags in | |
1456 | ;; headlines. A `not-in-toc' value will remove them from the | |
1457 | ;; table of contents, if any, nonetheless. | |
1458 | ;; - category :: option | |
1459 | ;; - type :: symbol (nil, t, `not-in-toc') | |
1460 | ;; | |
1461 | ;; + `:with-tasks' :: Non-nil means transcoding should include | |
1462 | ;; headlines with a TODO keyword. A `todo' value will only | |
1463 | ;; include headlines with a todo type keyword while a `done' | |
1464 | ;; value will do the contrary. If a list of strings is provided, | |
1465 | ;; only tasks with keywords belonging to that list will be kept. | |
1466 | ;; - category :: option | |
1467 | ;; - type :: symbol (t, todo, done, nil) or list of strings | |
1468 | ;; | |
1469 | ;; + `:with-timestamps' :: Non-nil means transcoding should include | |
1470 | ;; time stamps. Special value `active' (resp. `inactive') ask to | |
1471 | ;; export only active (resp. inactive) timestamps. Otherwise, | |
1472 | ;; completely remove them. | |
1473 | ;; - category :: option | |
1474 | ;; - type :: symbol: (`active', `inactive', t, nil) | |
1475 | ;; | |
1476 | ;; + `:with-toc' :: Non-nil means that a table of contents has to be | |
1477 | ;; added to the output. An integer value limits its depth. | |
1478 | ;; - category :: option | |
1479 | ;; - type :: symbol (nil, t or integer) | |
1480 | ;; | |
1481 | ;; + `:with-todo-keywords' :: Non-nil means transcoding should | |
1482 | ;; include TODO keywords. | |
1483 | ;; - category :: option | |
1484 | ;; - type :: symbol (nil, t) | |
1485 | ||
1486 | ||
1487 | ;;;; Environment Options | |
1488 | ;; | |
1489 | ;; Environment options encompass all parameters defined outside the | |
1490 | ;; scope of the parsed data. They come from five sources, in | |
1491 | ;; increasing precedence order: | |
1492 | ;; | |
1493 | ;; - Global variables, | |
1494 | ;; - Buffer's attributes, | |
1495 | ;; - Options keyword symbols, | |
1496 | ;; - Buffer keywords, | |
1497 | ;; - Subtree properties. | |
1498 | ;; | |
1499 | ;; The central internal function with regards to environment options | |
1500 | ;; is `org-export-get-environment'. It updates global variables with | |
1501 | ;; "#+BIND:" keywords, then retrieve and prioritize properties from | |
1502 | ;; the different sources. | |
1503 | ;; | |
1504 | ;; The internal functions doing the retrieval are: | |
1505 | ;; `org-export--get-global-options', | |
1506 | ;; `org-export--get-buffer-attributes', | |
1507 | ;; `org-export--parse-option-keyword', | |
1508 | ;; `org-export--get-subtree-options' and | |
1509 | ;; `org-export--get-inbuffer-options' | |
1510 | ;; | |
1511 | ;; Also, `org-export--list-bound-variables' collects bound variables | |
1512 | ;; along with their value in order to set them as buffer local | |
1513 | ;; variables later in the process. | |
1514 | ||
1515 | (defun org-export-get-environment (&optional backend subtreep ext-plist) | |
1516 | "Collect export options from the current buffer. | |
1517 | ||
1518 | Optional argument BACKEND is an export back-end, as returned by | |
1519 | `org-export-create-backend'. | |
1520 | ||
1521 | When optional argument SUBTREEP is non-nil, assume the export is | |
1522 | done against the current sub-tree. | |
1523 | ||
1524 | Third optional argument EXT-PLIST is a property list with | |
1525 | external parameters overriding Org default settings, but still | |
1526 | inferior to file-local settings." | |
1527 | ;; First install #+BIND variables since these must be set before | |
1528 | ;; global options are read. | |
1529 | (dolist (pair (org-export--list-bound-variables)) | |
1530 | (org-set-local (car pair) (nth 1 pair))) | |
1531 | ;; Get and prioritize export options... | |
1532 | (org-combine-plists | |
1533 | ;; ... from global variables... | |
1534 | (org-export--get-global-options backend) | |
1535 | ;; ... from an external property list... | |
1536 | ext-plist | |
1537 | ;; ... from in-buffer settings... | |
1538 | (org-export--get-inbuffer-options backend) | |
1539 | ;; ... and from subtree, when appropriate. | |
1540 | (and subtreep (org-export--get-subtree-options backend)) | |
1541 | ;; Eventually add misc. properties. | |
1542 | (list | |
1543 | :back-end | |
1544 | backend | |
1545 | :translate-alist (org-export-get-all-transcoders backend) | |
1546 | :footnote-definition-alist | |
1547 | ;; Footnotes definitions must be collected in the original | |
1548 | ;; buffer, as there's no insurance that they will still be in | |
1549 | ;; the parse tree, due to possible narrowing. | |
1550 | (let (alist) | |
1551 | (org-with-wide-buffer | |
1552 | (goto-char (point-min)) | |
1553 | (while (re-search-forward org-footnote-definition-re nil t) | |
1554 | (let ((def (save-match-data (org-element-at-point)))) | |
1555 | (when (eq (org-element-type def) 'footnote-definition) | |
1556 | (push | |
1557 | (cons (org-element-property :label def) | |
1558 | (let ((cbeg (org-element-property :contents-begin def))) | |
1559 | (when cbeg | |
1560 | (org-element--parse-elements | |
1561 | cbeg (org-element-property :contents-end def) | |
1562 | nil nil nil nil (list 'org-data nil))))) | |
1563 | alist)))) | |
1564 | alist)) | |
1565 | :id-alist | |
1566 | ;; Collect id references. | |
1567 | (let (alist) | |
1568 | (org-with-wide-buffer | |
1569 | (goto-char (point-min)) | |
1570 | (while (re-search-forward "\\[\\[id:\\S-+?\\]" nil t) | |
1571 | (let ((link (org-element-context))) | |
1572 | (when (eq (org-element-type link) 'link) | |
1573 | (let* ((id (org-element-property :path link)) | |
1574 | (file (org-id-find-id-file id))) | |
1575 | (when file | |
1576 | (push (cons id (file-relative-name file)) alist))))))) | |
1577 | alist)))) | |
1578 | ||
1579 | (defun org-export--parse-option-keyword (options &optional backend) | |
1580 | "Parse an OPTIONS line and return values as a plist. | |
1581 | Optional argument BACKEND is an export back-end, as returned by, | |
1582 | e.g., `org-export-create-backend'. It specifies which back-end | |
1583 | specific items to read, if any." | |
1584 | (let* ((all | |
1585 | ;; Priority is given to back-end specific options. | |
1586 | (append (and backend (org-export-get-all-options backend)) | |
1587 | org-export-options-alist)) | |
1588 | plist) | |
1589 | (dolist (option all) | |
1590 | (let ((property (car option)) | |
1591 | (item (nth 2 option))) | |
1592 | (when (and item | |
1593 | (not (plist-member plist property)) | |
1594 | (string-match (concat "\\(\\`\\|[ \t]\\)" | |
1595 | (regexp-quote item) | |
1596 | ":\\(([^)\n]+)\\|[^ \t\n\r;,.]*\\)") | |
1597 | options)) | |
1598 | (setq plist (plist-put plist | |
1599 | property | |
1600 | (car (read-from-string | |
1601 | (match-string 2 options)))))))) | |
1602 | plist)) | |
1603 | ||
1604 | (defun org-export--get-subtree-options (&optional backend) | |
1605 | "Get export options in subtree at point. | |
1606 | Optional argument BACKEND is an export back-end, as returned by, | |
1607 | e.g., `org-export-create-backend'. It specifies back-end used | |
1608 | for export. Return options as a plist." | |
1609 | ;; For each buffer keyword, create a headline property setting the | |
1610 | ;; same property in communication channel. The name for the property | |
1611 | ;; is the keyword with "EXPORT_" appended to it. | |
1612 | (org-with-wide-buffer | |
1613 | (let (prop plist) | |
1614 | ;; Make sure point is at a heading. | |
1615 | (if (org-at-heading-p) (org-up-heading-safe) (org-back-to-heading t)) | |
1616 | ;; Take care of EXPORT_TITLE. If it isn't defined, use headline's | |
30cb51f1 BG |
1617 | ;; title (with no todo keyword, priority cookie or tag) as its |
1618 | ;; fallback value. | |
271672fa | 1619 | (when (setq prop (or (org-entry-get (point) "EXPORT_TITLE") |
30cb51f1 BG |
1620 | (progn (looking-at org-complex-heading-regexp) |
1621 | (org-match-string-no-properties 4)))) | |
271672fa BG |
1622 | (setq plist |
1623 | (plist-put | |
1624 | plist :title | |
1625 | (org-element-parse-secondary-string | |
1626 | prop (org-element-restriction 'keyword))))) | |
1627 | ;; EXPORT_OPTIONS are parsed in a non-standard way. | |
1628 | (when (setq prop (org-entry-get (point) "EXPORT_OPTIONS")) | |
1629 | (setq plist | |
1630 | (nconc plist (org-export--parse-option-keyword prop backend)))) | |
1631 | ;; Handle other keywords. TITLE keyword is excluded as it has | |
1632 | ;; been handled already. | |
1633 | (let ((seen '("TITLE"))) | |
1634 | (mapc | |
1635 | (lambda (option) | |
1636 | (let ((property (car option)) | |
1637 | (keyword (nth 1 option))) | |
1638 | (when (and keyword (not (member keyword seen))) | |
1639 | (let* ((subtree-prop (concat "EXPORT_" keyword)) | |
1640 | ;; Export properties are not case-sensitive. | |
1641 | (value (let ((case-fold-search t)) | |
1642 | (org-entry-get (point) subtree-prop)))) | |
1643 | (push keyword seen) | |
1644 | (when (and value (not (plist-member plist property))) | |
1645 | (setq plist | |
1646 | (plist-put | |
1647 | plist | |
1648 | property | |
1649 | (cond | |
1650 | ;; Parse VALUE if required. | |
1651 | ((member keyword org-element-document-properties) | |
1652 | (org-element-parse-secondary-string | |
1653 | value (org-element-restriction 'keyword))) | |
da5ecfa9 | 1654 | ;; If BEHAVIOR is `split' expected value is |
271672fa BG |
1655 | ;; a list of strings, not a string. |
1656 | ((eq (nth 4 option) 'split) (org-split-string value)) | |
1657 | (t value))))))))) | |
1658 | ;; Look for both general keywords and back-end specific | |
1659 | ;; options, with priority given to the latter. | |
1660 | (append (and backend (org-export-get-all-options backend)) | |
1661 | org-export-options-alist))) | |
1662 | ;; Return value. | |
1663 | plist))) | |
1664 | ||
1665 | (defun org-export--get-inbuffer-options (&optional backend) | |
1666 | "Return current buffer export options, as a plist. | |
1667 | ||
1668 | Optional argument BACKEND, when non-nil, is an export back-end, | |
1669 | as returned by, e.g., `org-export-create-backend'. It specifies | |
1670 | which back-end specific options should also be read in the | |
1671 | process. | |
1672 | ||
1673 | Assume buffer is in Org mode. Narrowing, if any, is ignored." | |
1674 | (let* (plist | |
1675 | get-options ; For byte-compiler. | |
1676 | (case-fold-search t) | |
1677 | (options (append | |
1678 | ;; Priority is given to back-end specific options. | |
1679 | (and backend (org-export-get-all-options backend)) | |
1680 | org-export-options-alist)) | |
1681 | (regexp (format "^[ \t]*#\\+%s:" | |
1682 | (regexp-opt (nconc (delq nil (mapcar 'cadr options)) | |
1683 | org-export-special-keywords)))) | |
1684 | (find-properties | |
1685 | (lambda (keyword) | |
1686 | ;; Return all properties associated to KEYWORD. | |
1687 | (let (properties) | |
1688 | (dolist (option options properties) | |
1689 | (when (equal (nth 1 option) keyword) | |
1690 | (pushnew (car option) properties)))))) | |
1691 | (get-options | |
1692 | (lambda (&optional files plist) | |
1693 | ;; Recursively read keywords in buffer. FILES is a list | |
1694 | ;; of files read so far. PLIST is the current property | |
1695 | ;; list obtained. | |
1696 | (org-with-wide-buffer | |
1697 | (goto-char (point-min)) | |
1698 | (while (re-search-forward regexp nil t) | |
1699 | (let ((element (org-element-at-point))) | |
1700 | (when (eq (org-element-type element) 'keyword) | |
1701 | (let ((key (org-element-property :key element)) | |
1702 | (val (org-element-property :value element))) | |
1703 | (cond | |
1704 | ;; Options in `org-export-special-keywords'. | |
1705 | ((equal key "SETUPFILE") | |
1706 | (let ((file (expand-file-name | |
1707 | (org-remove-double-quotes (org-trim val))))) | |
1708 | ;; Avoid circular dependencies. | |
1709 | (unless (member file files) | |
1710 | (with-temp-buffer | |
1711 | (insert (org-file-contents file 'noerror)) | |
1712 | (let ((org-inhibit-startup t)) (org-mode)) | |
1713 | (setq plist (funcall get-options | |
1714 | (cons file files) plist)))))) | |
1715 | ((equal key "OPTIONS") | |
1716 | (setq plist | |
1717 | (org-combine-plists | |
1718 | plist | |
1719 | (org-export--parse-option-keyword val backend)))) | |
1720 | ((equal key "FILETAGS") | |
1721 | (setq plist | |
1722 | (org-combine-plists | |
1723 | plist | |
1724 | (list :filetags | |
1725 | (org-uniquify | |
1726 | (append (org-split-string val ":") | |
1727 | (plist-get plist :filetags))))))) | |
1728 | (t | |
1729 | ;; Options in `org-export-options-alist'. | |
1730 | (dolist (property (funcall find-properties key)) | |
3c8b09ca | 1731 | (let ((behaviour (nth 4 (assq property options)))) |
271672fa BG |
1732 | (setq plist |
1733 | (plist-put | |
1734 | plist property | |
1735 | ;; Handle value depending on specified | |
da5ecfa9 | 1736 | ;; BEHAVIOR. |
3c8b09ca | 1737 | (case behaviour |
271672fa BG |
1738 | (space |
1739 | (if (not (plist-get plist property)) | |
1740 | (org-trim val) | |
1741 | (concat (plist-get plist property) | |
1742 | " " | |
1743 | (org-trim val)))) | |
1744 | (newline | |
1745 | (org-trim | |
1746 | (concat (plist-get plist property) | |
1747 | "\n" | |
1748 | (org-trim val)))) | |
1749 | (split `(,@(plist-get plist property) | |
1750 | ,@(org-split-string val))) | |
1751 | ('t val) | |
1752 | (otherwise | |
1753 | (if (not (plist-member plist property)) val | |
1754 | (plist-get plist property)))))))))))))) | |
1755 | ;; Return final value. | |
1756 | plist)))) | |
1757 | ;; Read options in the current buffer. | |
1758 | (setq plist (funcall get-options | |
1759 | (and buffer-file-name (list buffer-file-name)) nil)) | |
1760 | ;; Parse keywords specified in `org-element-document-properties' | |
1761 | ;; and return PLIST. | |
1762 | (dolist (keyword org-element-document-properties plist) | |
1763 | (dolist (property (funcall find-properties keyword)) | |
1764 | (let ((value (plist-get plist property))) | |
1765 | (when (stringp value) | |
1766 | (setq plist | |
1767 | (plist-put plist property | |
1768 | (org-element-parse-secondary-string | |
1769 | value (org-element-restriction 'keyword)))))))))) | |
1770 | ||
1771 | (defun org-export--get-buffer-attributes () | |
1772 | "Return properties related to buffer attributes, as a plist." | |
1773 | ;; Store full path of input file name, or nil. For internal use. | |
1774 | (let ((visited-file (buffer-file-name (buffer-base-buffer)))) | |
1775 | (list :input-file visited-file | |
1776 | :title (if (not visited-file) (buffer-name (buffer-base-buffer)) | |
1777 | (file-name-sans-extension | |
1778 | (file-name-nondirectory visited-file)))))) | |
1779 | ||
1780 | (defun org-export--get-global-options (&optional backend) | |
1781 | "Return global export options as a plist. | |
1782 | Optional argument BACKEND, if non-nil, is an export back-end, as | |
1783 | returned by, e.g., `org-export-create-backend'. It specifies | |
1784 | which back-end specific export options should also be read in the | |
1785 | process." | |
1786 | (let (plist | |
1787 | ;; Priority is given to back-end specific options. | |
1788 | (all (append (and backend (org-export-get-all-options backend)) | |
1789 | org-export-options-alist))) | |
1790 | (dolist (cell all plist) | |
1791 | (let ((prop (car cell)) | |
1792 | (default-value (nth 3 cell))) | |
1793 | (unless (or (not default-value) (plist-member plist prop)) | |
1794 | (setq plist | |
1795 | (plist-put | |
1796 | plist | |
1797 | prop | |
1798 | ;; Eval default value provided. If keyword is | |
1799 | ;; a member of `org-element-document-properties', | |
1800 | ;; parse it as a secondary string before storing it. | |
1801 | (let ((value (eval (nth 3 cell)))) | |
1802 | (if (not (stringp value)) value | |
1803 | (let ((keyword (nth 1 cell))) | |
1804 | (if (member keyword org-element-document-properties) | |
1805 | (org-element-parse-secondary-string | |
1806 | value (org-element-restriction 'keyword)) | |
1807 | value))))))))))) | |
1808 | ||
1809 | (defun org-export--list-bound-variables () | |
1810 | "Return variables bound from BIND keywords in current buffer. | |
1811 | Also look for BIND keywords in setup files. The return value is | |
1812 | an alist where associations are (VARIABLE-NAME VALUE)." | |
1813 | (when org-export-allow-bind-keywords | |
1814 | (let* (collect-bind ; For byte-compiler. | |
1815 | (collect-bind | |
1816 | (lambda (files alist) | |
1817 | ;; Return an alist between variable names and their | |
1818 | ;; value. FILES is a list of setup files names read so | |
1819 | ;; far, used to avoid circular dependencies. ALIST is | |
1820 | ;; the alist collected so far. | |
1821 | (let ((case-fold-search t)) | |
1822 | (org-with-wide-buffer | |
1823 | (goto-char (point-min)) | |
1824 | (while (re-search-forward | |
1825 | "^[ \t]*#\\+\\(BIND\\|SETUPFILE\\):" nil t) | |
1826 | (let ((element (org-element-at-point))) | |
1827 | (when (eq (org-element-type element) 'keyword) | |
1828 | (let ((val (org-element-property :value element))) | |
1829 | (if (equal (org-element-property :key element) "BIND") | |
1830 | (push (read (format "(%s)" val)) alist) | |
1831 | ;; Enter setup file. | |
1832 | (let ((file (expand-file-name | |
1833 | (org-remove-double-quotes val)))) | |
1834 | (unless (member file files) | |
1835 | (with-temp-buffer | |
1836 | (let ((org-inhibit-startup t)) (org-mode)) | |
1837 | (insert (org-file-contents file 'noerror)) | |
1838 | (setq alist | |
1839 | (funcall collect-bind | |
1840 | (cons file files) | |
1841 | alist)))))))))) | |
1842 | alist))))) | |
1843 | ;; Return value in appropriate order of appearance. | |
1844 | (nreverse (funcall collect-bind nil nil))))) | |
1845 | ||
1846 | ||
1847 | ;;;; Tree Properties | |
1848 | ;; | |
1849 | ;; Tree properties are information extracted from parse tree. They | |
1850 | ;; are initialized at the beginning of the transcoding process by | |
1851 | ;; `org-export-collect-tree-properties'. | |
1852 | ;; | |
1853 | ;; Dedicated functions focus on computing the value of specific tree | |
1854 | ;; properties during initialization. Thus, | |
1855 | ;; `org-export--populate-ignore-list' lists elements and objects that | |
1856 | ;; should be skipped during export, `org-export--get-min-level' gets | |
1857 | ;; the minimal exportable level, used as a basis to compute relative | |
1858 | ;; level for headlines. Eventually | |
1859 | ;; `org-export--collect-headline-numbering' builds an alist between | |
1860 | ;; headlines and their numbering. | |
1861 | ||
1862 | (defun org-export-collect-tree-properties (data info) | |
1863 | "Extract tree properties from parse tree. | |
1864 | ||
1865 | DATA is the parse tree from which information is retrieved. INFO | |
1866 | is a list holding export options. | |
1867 | ||
1868 | Following tree properties are set or updated: | |
1869 | ||
1870 | `:exported-data' Hash table used to memoize results from | |
1871 | `org-export-data'. | |
1872 | ||
1873 | `:footnote-definition-alist' List of footnotes definitions in | |
1874 | original buffer and current parse tree. | |
1875 | ||
1876 | `:headline-offset' Offset between true level of headlines and | |
1877 | local level. An offset of -1 means a headline | |
1878 | of level 2 should be considered as a level | |
1879 | 1 headline in the context. | |
1880 | ||
1881 | `:headline-numbering' Alist of all headlines as key an the | |
1882 | associated numbering as value. | |
1883 | ||
1884 | `:ignore-list' List of elements that should be ignored during | |
1885 | export. | |
1886 | ||
1887 | Return updated plist." | |
1888 | ;; Install the parse tree in the communication channel, in order to | |
1889 | ;; use `org-export-get-genealogy' and al. | |
1890 | (setq info (plist-put info :parse-tree data)) | |
1891 | ;; Get the list of elements and objects to ignore, and put it into | |
1892 | ;; `:ignore-list'. Do not overwrite any user ignore that might have | |
1893 | ;; been done during parse tree filtering. | |
1894 | (setq info | |
1895 | (plist-put info | |
1896 | :ignore-list | |
1897 | (append (org-export--populate-ignore-list data info) | |
1898 | (plist-get info :ignore-list)))) | |
1899 | ;; Compute `:headline-offset' in order to be able to use | |
1900 | ;; `org-export-get-relative-level'. | |
1901 | (setq info | |
1902 | (plist-put info | |
1903 | :headline-offset | |
1904 | (- 1 (org-export--get-min-level data info)))) | |
1905 | ;; Update footnotes definitions list with definitions in parse tree. | |
1906 | ;; This is required since buffer expansion might have modified | |
1907 | ;; boundaries of footnote definitions contained in the parse tree. | |
1908 | ;; This way, definitions in `footnote-definition-alist' are bound to | |
1909 | ;; match those in the parse tree. | |
1910 | (let ((defs (plist-get info :footnote-definition-alist))) | |
1911 | (org-element-map data 'footnote-definition | |
1912 | (lambda (fn) | |
1913 | (push (cons (org-element-property :label fn) | |
1914 | `(org-data nil ,@(org-element-contents fn))) | |
1915 | defs))) | |
1916 | (setq info (plist-put info :footnote-definition-alist defs))) | |
1917 | ;; Properties order doesn't matter: get the rest of the tree | |
1918 | ;; properties. | |
1919 | (nconc | |
1920 | `(:headline-numbering ,(org-export--collect-headline-numbering data info) | |
1921 | :exported-data ,(make-hash-table :test 'eq :size 4001)) | |
1922 | info)) | |
1923 | ||
1924 | (defun org-export--get-min-level (data options) | |
1925 | "Return minimum exportable headline's level in DATA. | |
1926 | DATA is parsed tree as returned by `org-element-parse-buffer'. | |
1927 | OPTIONS is a plist holding export options." | |
1928 | (catch 'exit | |
1929 | (let ((min-level 10000)) | |
1930 | (mapc | |
1931 | (lambda (blob) | |
1932 | (when (and (eq (org-element-type blob) 'headline) | |
1933 | (not (org-element-property :footnote-section-p blob)) | |
1934 | (not (memq blob (plist-get options :ignore-list)))) | |
1935 | (setq min-level (min (org-element-property :level blob) min-level))) | |
1936 | (when (= min-level 1) (throw 'exit 1))) | |
1937 | (org-element-contents data)) | |
1938 | ;; If no headline was found, for the sake of consistency, set | |
1939 | ;; minimum level to 1 nonetheless. | |
1940 | (if (= min-level 10000) 1 min-level)))) | |
1941 | ||
1942 | (defun org-export--collect-headline-numbering (data options) | |
1943 | "Return numbering of all exportable headlines in a parse tree. | |
1944 | ||
1945 | DATA is the parse tree. OPTIONS is the plist holding export | |
1946 | options. | |
1947 | ||
1948 | Return an alist whose key is a headline and value is its | |
1949 | associated numbering \(in the shape of a list of numbers\) or nil | |
1950 | for a footnotes section." | |
1951 | (let ((numbering (make-vector org-export-max-depth 0))) | |
1952 | (org-element-map data 'headline | |
1953 | (lambda (headline) | |
1954 | (unless (org-element-property :footnote-section-p headline) | |
1955 | (let ((relative-level | |
1956 | (1- (org-export-get-relative-level headline options)))) | |
1957 | (cons | |
1958 | headline | |
1959 | (loop for n across numbering | |
1960 | for idx from 0 to org-export-max-depth | |
1961 | when (< idx relative-level) collect n | |
1962 | when (= idx relative-level) collect (aset numbering idx (1+ n)) | |
1963 | when (> idx relative-level) do (aset numbering idx 0)))))) | |
1964 | options))) | |
1965 | ||
1966 | (defun org-export--populate-ignore-list (data options) | |
1967 | "Return list of elements and objects to ignore during export. | |
1968 | DATA is the parse tree to traverse. OPTIONS is the plist holding | |
1969 | export options." | |
1970 | (let* (ignore | |
1971 | walk-data | |
1972 | ;; First find trees containing a select tag, if any. | |
1973 | (selected (org-export--selected-trees data options)) | |
1974 | (walk-data | |
1975 | (lambda (data) | |
1976 | ;; Collect ignored elements or objects into IGNORE-LIST. | |
1977 | (let ((type (org-element-type data))) | |
1978 | (if (org-export--skip-p data options selected) (push data ignore) | |
1979 | (if (and (eq type 'headline) | |
1980 | (eq (plist-get options :with-archived-trees) 'headline) | |
1981 | (org-element-property :archivedp data)) | |
1982 | ;; If headline is archived but tree below has | |
1983 | ;; to be skipped, add it to ignore list. | |
1984 | (mapc (lambda (e) (push e ignore)) | |
1985 | (org-element-contents data)) | |
1986 | ;; Move into secondary string, if any. | |
1987 | (let ((sec-prop | |
1988 | (cdr (assq type org-element-secondary-value-alist)))) | |
1989 | (when sec-prop | |
1990 | (mapc walk-data (org-element-property sec-prop data)))) | |
1991 | ;; Move into recursive objects/elements. | |
1992 | (mapc walk-data (org-element-contents data)))))))) | |
1993 | ;; Main call. | |
1994 | (funcall walk-data data) | |
1995 | ;; Return value. | |
1996 | ignore)) | |
1997 | ||
1998 | (defun org-export--selected-trees (data info) | |
1999 | "Return list of headlines and inlinetasks with a select tag in their tree. | |
2000 | DATA is parsed data as returned by `org-element-parse-buffer'. | |
2001 | INFO is a plist holding export options." | |
2002 | (let* (selected-trees | |
2003 | walk-data ; For byte-compiler. | |
2004 | (walk-data | |
2005 | (function | |
2006 | (lambda (data genealogy) | |
2007 | (let ((type (org-element-type data))) | |
2008 | (cond | |
2009 | ((memq type '(headline inlinetask)) | |
2010 | (let ((tags (org-element-property :tags data))) | |
2011 | (if (loop for tag in (plist-get info :select-tags) | |
2012 | thereis (member tag tags)) | |
2013 | ;; When a select tag is found, mark full | |
2014 | ;; genealogy and every headline within the tree | |
2015 | ;; as acceptable. | |
2016 | (setq selected-trees | |
2017 | (append | |
2018 | genealogy | |
2019 | (org-element-map data '(headline inlinetask) | |
2020 | 'identity) | |
2021 | selected-trees)) | |
2022 | ;; If at a headline, continue searching in tree, | |
2023 | ;; recursively. | |
2024 | (when (eq type 'headline) | |
2025 | (mapc (lambda (el) | |
2026 | (funcall walk-data el (cons data genealogy))) | |
2027 | (org-element-contents data)))))) | |
2028 | ((or (eq type 'org-data) | |
2029 | (memq type org-element-greater-elements)) | |
2030 | (mapc (lambda (el) (funcall walk-data el genealogy)) | |
2031 | (org-element-contents data))))))))) | |
2032 | (funcall walk-data data nil) | |
2033 | selected-trees)) | |
2034 | ||
2035 | (defun org-export--skip-p (blob options selected) | |
2036 | "Non-nil when element or object BLOB should be skipped during export. | |
2037 | OPTIONS is the plist holding export options. SELECTED, when | |
2038 | non-nil, is a list of headlines or inlinetasks belonging to | |
2039 | a tree with a select tag." | |
2040 | (case (org-element-type blob) | |
2041 | (clock (not (plist-get options :with-clocks))) | |
2042 | (drawer | |
2043 | (let ((with-drawers-p (plist-get options :with-drawers))) | |
2044 | (or (not with-drawers-p) | |
2045 | (and (consp with-drawers-p) | |
2046 | ;; If `:with-drawers' value starts with `not', ignore | |
2047 | ;; every drawer whose name belong to that list. | |
2048 | ;; Otherwise, ignore drawers whose name isn't in that | |
2049 | ;; list. | |
2050 | (let ((name (org-element-property :drawer-name blob))) | |
2051 | (if (eq (car with-drawers-p) 'not) | |
2052 | (member-ignore-case name (cdr with-drawers-p)) | |
2053 | (not (member-ignore-case name with-drawers-p)))))))) | |
2054 | ((footnote-definition footnote-reference) | |
2055 | (not (plist-get options :with-footnotes))) | |
2056 | ((headline inlinetask) | |
2057 | (let ((with-tasks (plist-get options :with-tasks)) | |
2058 | (todo (org-element-property :todo-keyword blob)) | |
2059 | (todo-type (org-element-property :todo-type blob)) | |
2060 | (archived (plist-get options :with-archived-trees)) | |
2061 | (tags (org-element-property :tags blob))) | |
2062 | (or | |
2063 | (and (eq (org-element-type blob) 'inlinetask) | |
2064 | (not (plist-get options :with-inlinetasks))) | |
2065 | ;; Ignore subtrees with an exclude tag. | |
2066 | (loop for k in (plist-get options :exclude-tags) | |
2067 | thereis (member k tags)) | |
2068 | ;; When a select tag is present in the buffer, ignore any tree | |
2069 | ;; without it. | |
2070 | (and selected (not (memq blob selected))) | |
2071 | ;; Ignore commented sub-trees. | |
2072 | (org-element-property :commentedp blob) | |
2073 | ;; Ignore archived subtrees if `:with-archived-trees' is nil. | |
2074 | (and (not archived) (org-element-property :archivedp blob)) | |
2075 | ;; Ignore tasks, if specified by `:with-tasks' property. | |
2076 | (and todo | |
2077 | (or (not with-tasks) | |
2078 | (and (memq with-tasks '(todo done)) | |
2079 | (not (eq todo-type with-tasks))) | |
2080 | (and (consp with-tasks) (not (member todo with-tasks)))))))) | |
2081 | ((latex-environment latex-fragment) (not (plist-get options :with-latex))) | |
2082 | (planning (not (plist-get options :with-planning))) | |
2083 | (statistics-cookie (not (plist-get options :with-statistics-cookies))) | |
2084 | (table-cell | |
2085 | (and (org-export-table-has-special-column-p | |
2086 | (org-export-get-parent-table blob)) | |
2087 | (not (org-export-get-previous-element blob options)))) | |
2088 | (table-row (org-export-table-row-is-special-p blob options)) | |
2089 | (timestamp | |
2090 | ;; `:with-timestamps' only applies to isolated timestamps | |
2091 | ;; objects, i.e. timestamp objects in a paragraph containing only | |
2092 | ;; timestamps and whitespaces. | |
2093 | (when (let ((parent (org-export-get-parent-element blob))) | |
2094 | (and (memq (org-element-type parent) '(paragraph verse-block)) | |
2095 | (not (org-element-map parent | |
2096 | (cons 'plain-text | |
2097 | (remq 'timestamp org-element-all-objects)) | |
2098 | (lambda (obj) | |
2099 | (or (not (stringp obj)) (org-string-nw-p obj))) | |
2100 | options t)))) | |
2101 | (case (plist-get options :with-timestamps) | |
2102 | ('nil t) | |
2103 | (active | |
2104 | (not (memq (org-element-property :type blob) '(active active-range)))) | |
2105 | (inactive | |
2106 | (not (memq (org-element-property :type blob) | |
2107 | '(inactive inactive-range))))))))) | |
2108 | ||
2109 | \f | |
2110 | ;;; The Transcoder | |
2111 | ;; | |
2112 | ;; `org-export-data' reads a parse tree (obtained with, i.e. | |
2113 | ;; `org-element-parse-buffer') and transcodes it into a specified | |
2114 | ;; back-end output. It takes care of filtering out elements or | |
2115 | ;; objects according to export options and organizing the output blank | |
2116 | ;; lines and white space are preserved. The function memoizes its | |
2117 | ;; results, so it is cheap to call it within transcoders. | |
2118 | ;; | |
2119 | ;; It is possible to modify locally the back-end used by | |
2120 | ;; `org-export-data' or even use a temporary back-end by using | |
2121 | ;; `org-export-data-with-backend'. | |
2122 | ;; | |
2123 | ;; Internally, three functions handle the filtering of objects and | |
2124 | ;; elements during the export. In particular, | |
2125 | ;; `org-export-ignore-element' marks an element or object so future | |
2126 | ;; parse tree traversals skip it, `org-export--interpret-p' tells which | |
2127 | ;; elements or objects should be seen as real Org syntax and | |
2128 | ;; `org-export-expand' transforms the others back into their original | |
2129 | ;; shape | |
2130 | ;; | |
2131 | ;; `org-export-transcoder' is an accessor returning appropriate | |
2132 | ;; translator function for a given element or object. | |
2133 | ||
2134 | (defun org-export-transcoder (blob info) | |
2135 | "Return appropriate transcoder for BLOB. | |
2136 | INFO is a plist containing export directives." | |
2137 | (let ((type (org-element-type blob))) | |
2138 | ;; Return contents only for complete parse trees. | |
2139 | (if (eq type 'org-data) (lambda (blob contents info) contents) | |
2140 | (let ((transcoder (cdr (assq type (plist-get info :translate-alist))))) | |
2141 | (and (functionp transcoder) transcoder))))) | |
2142 | ||
2143 | (defun org-export-data (data info) | |
2144 | "Convert DATA into current back-end format. | |
2145 | ||
2146 | DATA is a parse tree, an element or an object or a secondary | |
2147 | string. INFO is a plist holding export options. | |
2148 | ||
2149 | Return transcoded string." | |
2150 | (let ((memo (gethash data (plist-get info :exported-data) 'no-memo))) | |
2151 | (if (not (eq memo 'no-memo)) memo | |
2152 | (let* ((type (org-element-type data)) | |
2153 | (results | |
2154 | (cond | |
2155 | ;; Ignored element/object. | |
2156 | ((memq data (plist-get info :ignore-list)) nil) | |
2157 | ;; Plain text. | |
2158 | ((eq type 'plain-text) | |
2159 | (org-export-filter-apply-functions | |
2160 | (plist-get info :filter-plain-text) | |
2161 | (let ((transcoder (org-export-transcoder data info))) | |
2162 | (if transcoder (funcall transcoder data info) data)) | |
2163 | info)) | |
2164 | ;; Uninterpreted element/object: change it back to Org | |
2165 | ;; syntax and export again resulting raw string. | |
2166 | ((not (org-export--interpret-p data info)) | |
2167 | (org-export-data | |
2168 | (org-export-expand | |
2169 | data | |
2170 | (mapconcat (lambda (blob) (org-export-data blob info)) | |
2171 | (org-element-contents data) | |
2172 | "")) | |
2173 | info)) | |
2174 | ;; Secondary string. | |
2175 | ((not type) | |
2176 | (mapconcat (lambda (obj) (org-export-data obj info)) data "")) | |
2177 | ;; Element/Object without contents or, as a special case, | |
2178 | ;; headline with archive tag and archived trees restricted | |
2179 | ;; to title only. | |
2180 | ((or (not (org-element-contents data)) | |
2181 | (and (eq type 'headline) | |
2182 | (eq (plist-get info :with-archived-trees) 'headline) | |
2183 | (org-element-property :archivedp data))) | |
2184 | (let ((transcoder (org-export-transcoder data info))) | |
2185 | (or (and (functionp transcoder) | |
2186 | (funcall transcoder data nil info)) | |
2187 | ;; Export snippets never return a nil value so | |
2188 | ;; that white spaces following them are never | |
2189 | ;; ignored. | |
2190 | (and (eq type 'export-snippet) "")))) | |
2191 | ;; Element/Object with contents. | |
2192 | (t | |
2193 | (let ((transcoder (org-export-transcoder data info))) | |
2194 | (when transcoder | |
2195 | (let* ((greaterp (memq type org-element-greater-elements)) | |
2196 | (objectp | |
2197 | (and (not greaterp) | |
2198 | (memq type org-element-recursive-objects))) | |
2199 | (contents | |
2200 | (mapconcat | |
2201 | (lambda (element) (org-export-data element info)) | |
2202 | (org-element-contents | |
2203 | (if (or greaterp objectp) data | |
2204 | ;; Elements directly containing objects | |
2205 | ;; must have their indentation normalized | |
2206 | ;; first. | |
2207 | (org-element-normalize-contents | |
2208 | data | |
2209 | ;; When normalizing contents of the first | |
2210 | ;; paragraph in an item or a footnote | |
2211 | ;; definition, ignore first line's | |
2212 | ;; indentation: there is none and it | |
2213 | ;; might be misleading. | |
2214 | (when (eq type 'paragraph) | |
2215 | (let ((parent (org-export-get-parent data))) | |
2216 | (and | |
2217 | (eq (car (org-element-contents parent)) | |
2218 | data) | |
2219 | (memq (org-element-type parent) | |
2220 | '(footnote-definition item)))))))) | |
2221 | ""))) | |
2222 | (funcall transcoder data | |
2223 | (if (not greaterp) contents | |
2224 | (org-element-normalize-string contents)) | |
2225 | info)))))))) | |
2226 | ;; Final result will be memoized before being returned. | |
2227 | (puthash | |
2228 | data | |
2229 | (cond | |
2230 | ((not results) nil) | |
2231 | ((memq type '(org-data plain-text nil)) results) | |
2232 | ;; Append the same white space between elements or objects as in | |
2233 | ;; the original buffer, and call appropriate filters. | |
2234 | (t | |
2235 | (let ((results | |
2236 | (org-export-filter-apply-functions | |
2237 | (plist-get info (intern (format ":filter-%s" type))) | |
2238 | (let ((post-blank (or (org-element-property :post-blank data) | |
2239 | 0))) | |
2240 | (if (memq type org-element-all-elements) | |
2241 | (concat (org-element-normalize-string results) | |
2242 | (make-string post-blank ?\n)) | |
2243 | (concat results (make-string post-blank ? )))) | |
2244 | info))) | |
2245 | results))) | |
2246 | (plist-get info :exported-data)))))) | |
2247 | ||
2248 | (defun org-export-data-with-backend (data backend info) | |
2249 | "Convert DATA into BACKEND format. | |
2250 | ||
2251 | DATA is an element, an object, a secondary string or a string. | |
2252 | BACKEND is a symbol. INFO is a plist used as a communication | |
2253 | channel. | |
2254 | ||
2255 | Unlike to `org-export-with-backend', this function will | |
2256 | recursively convert DATA using BACKEND translation table." | |
2257 | (when (symbolp backend) (setq backend (org-export-get-backend backend))) | |
2258 | (org-export-data | |
2259 | data | |
2260 | ;; Set-up a new communication channel with translations defined in | |
2261 | ;; BACKEND as the translate table and a new hash table for | |
2262 | ;; memoization. | |
2263 | (org-combine-plists | |
2264 | info | |
2265 | (list :back-end backend | |
2266 | :translate-alist (org-export-get-all-transcoders backend) | |
2267 | ;; Size of the hash table is reduced since this function | |
2268 | ;; will probably be used on small trees. | |
2269 | :exported-data (make-hash-table :test 'eq :size 401))))) | |
2270 | ||
2271 | (defun org-export--interpret-p (blob info) | |
2272 | "Non-nil if element or object BLOB should be interpreted during export. | |
2273 | If nil, BLOB will appear as raw Org syntax. Check is done | |
2274 | according to export options INFO, stored as a plist." | |
2275 | (case (org-element-type blob) | |
2276 | ;; ... entities... | |
2277 | (entity (plist-get info :with-entities)) | |
2278 | ;; ... emphasis... | |
2279 | ((bold italic strike-through underline) | |
2280 | (plist-get info :with-emphasize)) | |
2281 | ;; ... fixed-width areas. | |
2282 | (fixed-width (plist-get info :with-fixed-width)) | |
2283 | ;; ... LaTeX environments and fragments... | |
2284 | ((latex-environment latex-fragment) | |
2285 | (let ((with-latex-p (plist-get info :with-latex))) | |
2286 | (and with-latex-p (not (eq with-latex-p 'verbatim))))) | |
2287 | ;; ... sub/superscripts... | |
2288 | ((subscript superscript) | |
2289 | (let ((sub/super-p (plist-get info :with-sub-superscript))) | |
2290 | (if (eq sub/super-p '{}) | |
2291 | (org-element-property :use-brackets-p blob) | |
2292 | sub/super-p))) | |
2293 | ;; ... tables... | |
2294 | (table (plist-get info :with-tables)) | |
2295 | (otherwise t))) | |
2296 | ||
2297 | (defun org-export-expand (blob contents &optional with-affiliated) | |
2298 | "Expand a parsed element or object to its original state. | |
2299 | ||
2300 | BLOB is either an element or an object. CONTENTS is its | |
2301 | contents, as a string or nil. | |
2302 | ||
2303 | When optional argument WITH-AFFILIATED is non-nil, add affiliated | |
2304 | keywords before output." | |
2305 | (let ((type (org-element-type blob))) | |
2306 | (concat (and with-affiliated (memq type org-element-all-elements) | |
2307 | (org-element--interpret-affiliated-keywords blob)) | |
2308 | (funcall (intern (format "org-element-%s-interpreter" type)) | |
2309 | blob contents)))) | |
2310 | ||
2311 | (defun org-export-ignore-element (element info) | |
2312 | "Add ELEMENT to `:ignore-list' in INFO. | |
2313 | ||
2314 | Any element in `:ignore-list' will be skipped when using | |
2315 | `org-element-map'. INFO is modified by side effects." | |
2316 | (plist-put info :ignore-list (cons element (plist-get info :ignore-list)))) | |
2317 | ||
2318 | ||
2319 | \f | |
2320 | ;;; The Filter System | |
2321 | ;; | |
2322 | ;; Filters allow end-users to tweak easily the transcoded output. | |
2323 | ;; They are the functional counterpart of hooks, as every filter in | |
2324 | ;; a set is applied to the return value of the previous one. | |
2325 | ;; | |
2326 | ;; Every set is back-end agnostic. Although, a filter is always | |
2327 | ;; called, in addition to the string it applies to, with the back-end | |
2328 | ;; used as argument, so it's easy for the end-user to add back-end | |
2329 | ;; specific filters in the set. The communication channel, as | |
2330 | ;; a plist, is required as the third argument. | |
2331 | ;; | |
2332 | ;; From the developer side, filters sets can be installed in the | |
2333 | ;; process with the help of `org-export-define-backend', which | |
2334 | ;; internally stores filters as an alist. Each association has a key | |
2335 | ;; among the following symbols and a function or a list of functions | |
2336 | ;; as value. | |
2337 | ;; | |
2338 | ;; - `:filter-options' applies to the property list containing export | |
2339 | ;; options. Unlike to other filters, functions in this list accept | |
2340 | ;; two arguments instead of three: the property list containing | |
2341 | ;; export options and the back-end. Users can set its value through | |
2342 | ;; `org-export-filter-options-functions' variable. | |
2343 | ;; | |
2344 | ;; - `:filter-parse-tree' applies directly to the complete parsed | |
2345 | ;; tree. Users can set it through | |
2346 | ;; `org-export-filter-parse-tree-functions' variable. | |
2347 | ;; | |
2348 | ;; - `:filter-final-output' applies to the final transcoded string. | |
2349 | ;; Users can set it with `org-export-filter-final-output-functions' | |
2350 | ;; variable | |
2351 | ;; | |
2352 | ;; - `:filter-plain-text' applies to any string not recognized as Org | |
2353 | ;; syntax. `org-export-filter-plain-text-functions' allows users to | |
2354 | ;; configure it. | |
2355 | ;; | |
2356 | ;; - `:filter-TYPE' applies on the string returned after an element or | |
2357 | ;; object of type TYPE has been transcoded. A user can modify | |
2358 | ;; `org-export-filter-TYPE-functions' | |
2359 | ;; | |
2360 | ;; All filters sets are applied with | |
2361 | ;; `org-export-filter-apply-functions' function. Filters in a set are | |
2362 | ;; applied in a LIFO fashion. It allows developers to be sure that | |
2363 | ;; their filters will be applied first. | |
2364 | ;; | |
2365 | ;; Filters properties are installed in communication channel with | |
2366 | ;; `org-export-install-filters' function. | |
2367 | ;; | |
2368 | ;; Eventually, two hooks (`org-export-before-processing-hook' and | |
2369 | ;; `org-export-before-parsing-hook') are run at the beginning of the | |
2370 | ;; export process and just before parsing to allow for heavy structure | |
2371 | ;; modifications. | |
2372 | ||
2373 | ||
2374 | ;;;; Hooks | |
2375 | ||
2376 | (defvar org-export-before-processing-hook nil | |
2377 | "Hook run at the beginning of the export process. | |
2378 | ||
2379 | This is run before include keywords and macros are expanded and | |
2380 | Babel code blocks executed, on a copy of the original buffer | |
2381 | being exported. Visibility and narrowing are preserved. Point | |
2382 | is at the beginning of the buffer. | |
2383 | ||
2384 | Every function in this hook will be called with one argument: the | |
2385 | back-end currently used, as a symbol.") | |
2386 | ||
2387 | (defvar org-export-before-parsing-hook nil | |
2388 | "Hook run before parsing an export buffer. | |
2389 | ||
2390 | This is run after include keywords and macros have been expanded | |
2391 | and Babel code blocks executed, on a copy of the original buffer | |
2392 | being exported. Visibility and narrowing are preserved. Point | |
2393 | is at the beginning of the buffer. | |
2394 | ||
2395 | Every function in this hook will be called with one argument: the | |
2396 | back-end currently used, as a symbol.") | |
2397 | ||
2398 | ||
2399 | ;;;; Special Filters | |
2400 | ||
2401 | (defvar org-export-filter-options-functions nil | |
2402 | "List of functions applied to the export options. | |
2403 | Each filter is called with two arguments: the export options, as | |
2404 | a plist, and the back-end, as a symbol. It must return | |
2405 | a property list containing export options.") | |
2406 | ||
2407 | (defvar org-export-filter-parse-tree-functions nil | |
2408 | "List of functions applied to the parsed tree. | |
2409 | Each filter is called with three arguments: the parse tree, as | |
2410 | returned by `org-element-parse-buffer', the back-end, as | |
2411 | a symbol, and the communication channel, as a plist. It must | |
2412 | return the modified parse tree to transcode.") | |
2413 | ||
2414 | (defvar org-export-filter-plain-text-functions nil | |
2415 | "List of functions applied to plain text. | |
2416 | Each filter is called with three arguments: a string which | |
2417 | contains no Org syntax, the back-end, as a symbol, and the | |
2418 | communication channel, as a plist. It must return a string or | |
2419 | nil.") | |
2420 | ||
2421 | (defvar org-export-filter-final-output-functions nil | |
2422 | "List of functions applied to the transcoded string. | |
2423 | Each filter is called with three arguments: the full transcoded | |
2424 | string, the back-end, as a symbol, and the communication channel, | |
2425 | as a plist. It must return a string that will be used as the | |
2426 | final export output.") | |
2427 | ||
2428 | ||
2429 | ;;;; Elements Filters | |
2430 | ||
2431 | (defvar org-export-filter-babel-call-functions nil | |
2432 | "List of functions applied to a transcoded babel-call. | |
2433 | Each filter is called with three arguments: the transcoded data, | |
2434 | as a string, the back-end, as a symbol, and the communication | |
2435 | channel, as a plist. It must return a string or nil.") | |
2436 | ||
2437 | (defvar org-export-filter-center-block-functions nil | |
2438 | "List of functions applied to a transcoded center block. | |
2439 | Each filter is called with three arguments: the transcoded data, | |
2440 | as a string, the back-end, as a symbol, and the communication | |
2441 | channel, as a plist. It must return a string or nil.") | |
2442 | ||
2443 | (defvar org-export-filter-clock-functions nil | |
2444 | "List of functions applied to a transcoded clock. | |
2445 | Each filter is called with three arguments: the transcoded data, | |
2446 | as a string, the back-end, as a symbol, and the communication | |
2447 | channel, as a plist. It must return a string or nil.") | |
2448 | ||
2449 | (defvar org-export-filter-comment-functions nil | |
2450 | "List of functions applied to a transcoded comment. | |
2451 | Each filter is called with three arguments: the transcoded data, | |
2452 | as a string, the back-end, as a symbol, and the communication | |
2453 | channel, as a plist. It must return a string or nil.") | |
2454 | ||
2455 | (defvar org-export-filter-comment-block-functions nil | |
2456 | "List of functions applied to a transcoded comment-block. | |
2457 | Each filter is called with three arguments: the transcoded data, | |
2458 | as a string, the back-end, as a symbol, and the communication | |
2459 | channel, as a plist. It must return a string or nil.") | |
2460 | ||
2461 | (defvar org-export-filter-diary-sexp-functions nil | |
2462 | "List of functions applied to a transcoded diary-sexp. | |
2463 | Each filter is called with three arguments: the transcoded data, | |
2464 | as a string, the back-end, as a symbol, and the communication | |
2465 | channel, as a plist. It must return a string or nil.") | |
2466 | ||
2467 | (defvar org-export-filter-drawer-functions nil | |
2468 | "List of functions applied to a transcoded drawer. | |
2469 | Each filter is called with three arguments: the transcoded data, | |
2470 | as a string, the back-end, as a symbol, and the communication | |
2471 | channel, as a plist. It must return a string or nil.") | |
2472 | ||
2473 | (defvar org-export-filter-dynamic-block-functions nil | |
2474 | "List of functions applied to a transcoded dynamic-block. | |
2475 | Each filter is called with three arguments: the transcoded data, | |
2476 | as a string, the back-end, as a symbol, and the communication | |
2477 | channel, as a plist. It must return a string or nil.") | |
2478 | ||
2479 | (defvar org-export-filter-example-block-functions nil | |
2480 | "List of functions applied to a transcoded example-block. | |
2481 | Each filter is called with three arguments: the transcoded data, | |
2482 | as a string, the back-end, as a symbol, and the communication | |
2483 | channel, as a plist. It must return a string or nil.") | |
2484 | ||
2485 | (defvar org-export-filter-export-block-functions nil | |
2486 | "List of functions applied to a transcoded export-block. | |
2487 | Each filter is called with three arguments: the transcoded data, | |
2488 | as a string, the back-end, as a symbol, and the communication | |
2489 | channel, as a plist. It must return a string or nil.") | |
2490 | ||
2491 | (defvar org-export-filter-fixed-width-functions nil | |
2492 | "List of functions applied to a transcoded fixed-width. | |
2493 | Each filter is called with three arguments: the transcoded data, | |
2494 | as a string, the back-end, as a symbol, and the communication | |
2495 | channel, as a plist. It must return a string or nil.") | |
2496 | ||
2497 | (defvar org-export-filter-footnote-definition-functions nil | |
2498 | "List of functions applied to a transcoded footnote-definition. | |
2499 | Each filter is called with three arguments: the transcoded data, | |
2500 | as a string, the back-end, as a symbol, and the communication | |
2501 | channel, as a plist. It must return a string or nil.") | |
2502 | ||
2503 | (defvar org-export-filter-headline-functions nil | |
2504 | "List of functions applied to a transcoded headline. | |
2505 | Each filter is called with three arguments: the transcoded data, | |
2506 | as a string, the back-end, as a symbol, and the communication | |
2507 | channel, as a plist. It must return a string or nil.") | |
2508 | ||
2509 | (defvar org-export-filter-horizontal-rule-functions nil | |
2510 | "List of functions applied to a transcoded horizontal-rule. | |
2511 | Each filter is called with three arguments: the transcoded data, | |
2512 | as a string, the back-end, as a symbol, and the communication | |
2513 | channel, as a plist. It must return a string or nil.") | |
2514 | ||
2515 | (defvar org-export-filter-inlinetask-functions nil | |
2516 | "List of functions applied to a transcoded inlinetask. | |
2517 | Each filter is called with three arguments: the transcoded data, | |
2518 | as a string, the back-end, as a symbol, and the communication | |
2519 | channel, as a plist. It must return a string or nil.") | |
2520 | ||
2521 | (defvar org-export-filter-item-functions nil | |
2522 | "List of functions applied to a transcoded item. | |
2523 | Each filter is called with three arguments: the transcoded data, | |
2524 | as a string, the back-end, as a symbol, and the communication | |
2525 | channel, as a plist. It must return a string or nil.") | |
2526 | ||
2527 | (defvar org-export-filter-keyword-functions nil | |
2528 | "List of functions applied to a transcoded keyword. | |
2529 | Each filter is called with three arguments: the transcoded data, | |
2530 | as a string, the back-end, as a symbol, and the communication | |
2531 | channel, as a plist. It must return a string or nil.") | |
2532 | ||
2533 | (defvar org-export-filter-latex-environment-functions nil | |
2534 | "List of functions applied to a transcoded latex-environment. | |
2535 | Each filter is called with three arguments: the transcoded data, | |
2536 | as a string, the back-end, as a symbol, and the communication | |
2537 | channel, as a plist. It must return a string or nil.") | |
2538 | ||
2539 | (defvar org-export-filter-node-property-functions nil | |
2540 | "List of functions applied to a transcoded node-property. | |
2541 | Each filter is called with three arguments: the transcoded data, | |
2542 | as a string, the back-end, as a symbol, and the communication | |
2543 | channel, as a plist. It must return a string or nil.") | |
2544 | ||
2545 | (defvar org-export-filter-paragraph-functions nil | |
2546 | "List of functions applied to a transcoded paragraph. | |
2547 | Each filter is called with three arguments: the transcoded data, | |
2548 | as a string, the back-end, as a symbol, and the communication | |
2549 | channel, as a plist. It must return a string or nil.") | |
2550 | ||
2551 | (defvar org-export-filter-plain-list-functions nil | |
2552 | "List of functions applied to a transcoded plain-list. | |
2553 | Each filter is called with three arguments: the transcoded data, | |
2554 | as a string, the back-end, as a symbol, and the communication | |
2555 | channel, as a plist. It must return a string or nil.") | |
2556 | ||
2557 | (defvar org-export-filter-planning-functions nil | |
2558 | "List of functions applied to a transcoded planning. | |
2559 | Each filter is called with three arguments: the transcoded data, | |
2560 | as a string, the back-end, as a symbol, and the communication | |
2561 | channel, as a plist. It must return a string or nil.") | |
2562 | ||
2563 | (defvar org-export-filter-property-drawer-functions nil | |
2564 | "List of functions applied to a transcoded property-drawer. | |
2565 | Each filter is called with three arguments: the transcoded data, | |
2566 | as a string, the back-end, as a symbol, and the communication | |
2567 | channel, as a plist. It must return a string or nil.") | |
2568 | ||
2569 | (defvar org-export-filter-quote-block-functions nil | |
2570 | "List of functions applied to a transcoded quote block. | |
2571 | Each filter is called with three arguments: the transcoded quote | |
2572 | data, as a string, the back-end, as a symbol, and the | |
2573 | communication channel, as a plist. It must return a string or | |
2574 | nil.") | |
2575 | ||
2576 | (defvar org-export-filter-quote-section-functions nil | |
2577 | "List of functions applied to a transcoded quote-section. | |
2578 | Each filter is called with three arguments: the transcoded data, | |
2579 | as a string, the back-end, as a symbol, and the communication | |
2580 | channel, as a plist. It must return a string or nil.") | |
2581 | ||
2582 | (defvar org-export-filter-section-functions nil | |
2583 | "List of functions applied to a transcoded section. | |
2584 | Each filter is called with three arguments: the transcoded data, | |
2585 | as a string, the back-end, as a symbol, and the communication | |
2586 | channel, as a plist. It must return a string or nil.") | |
2587 | ||
2588 | (defvar org-export-filter-special-block-functions nil | |
2589 | "List of functions applied to a transcoded special block. | |
2590 | Each filter is called with three arguments: the transcoded data, | |
2591 | as a string, the back-end, as a symbol, and the communication | |
2592 | channel, as a plist. It must return a string or nil.") | |
2593 | ||
2594 | (defvar org-export-filter-src-block-functions nil | |
2595 | "List of functions applied to a transcoded src-block. | |
2596 | Each filter is called with three arguments: the transcoded data, | |
2597 | as a string, the back-end, as a symbol, and the communication | |
2598 | channel, as a plist. It must return a string or nil.") | |
2599 | ||
2600 | (defvar org-export-filter-table-functions nil | |
2601 | "List of functions applied to a transcoded table. | |
2602 | Each filter is called with three arguments: the transcoded data, | |
2603 | as a string, the back-end, as a symbol, and the communication | |
2604 | channel, as a plist. It must return a string or nil.") | |
2605 | ||
2606 | (defvar org-export-filter-table-cell-functions nil | |
2607 | "List of functions applied to a transcoded table-cell. | |
2608 | Each filter is called with three arguments: the transcoded data, | |
2609 | as a string, the back-end, as a symbol, and the communication | |
2610 | channel, as a plist. It must return a string or nil.") | |
2611 | ||
2612 | (defvar org-export-filter-table-row-functions nil | |
2613 | "List of functions applied to a transcoded table-row. | |
2614 | Each filter is called with three arguments: the transcoded data, | |
2615 | as a string, the back-end, as a symbol, and the communication | |
2616 | channel, as a plist. It must return a string or nil.") | |
2617 | ||
2618 | (defvar org-export-filter-verse-block-functions nil | |
2619 | "List of functions applied to a transcoded verse block. | |
2620 | Each filter is called with three arguments: the transcoded data, | |
2621 | as a string, the back-end, as a symbol, and the communication | |
2622 | channel, as a plist. It must return a string or nil.") | |
2623 | ||
2624 | ||
2625 | ;;;; Objects Filters | |
2626 | ||
2627 | (defvar org-export-filter-bold-functions nil | |
2628 | "List of functions applied to transcoded bold text. | |
2629 | Each filter is called with three arguments: the transcoded data, | |
2630 | as a string, the back-end, as a symbol, and the communication | |
2631 | channel, as a plist. It must return a string or nil.") | |
2632 | ||
2633 | (defvar org-export-filter-code-functions nil | |
2634 | "List of functions applied to transcoded code text. | |
2635 | Each filter is called with three arguments: the transcoded data, | |
2636 | as a string, the back-end, as a symbol, and the communication | |
2637 | channel, as a plist. It must return a string or nil.") | |
2638 | ||
2639 | (defvar org-export-filter-entity-functions nil | |
2640 | "List of functions applied to a transcoded entity. | |
2641 | Each filter is called with three arguments: the transcoded data, | |
2642 | as a string, the back-end, as a symbol, and the communication | |
2643 | channel, as a plist. It must return a string or nil.") | |
2644 | ||
2645 | (defvar org-export-filter-export-snippet-functions nil | |
2646 | "List of functions applied to a transcoded export-snippet. | |
2647 | Each filter is called with three arguments: the transcoded data, | |
2648 | as a string, the back-end, as a symbol, and the communication | |
2649 | channel, as a plist. It must return a string or nil.") | |
2650 | ||
2651 | (defvar org-export-filter-footnote-reference-functions nil | |
2652 | "List of functions applied to a transcoded footnote-reference. | |
2653 | Each filter is called with three arguments: the transcoded data, | |
2654 | as a string, the back-end, as a symbol, and the communication | |
2655 | channel, as a plist. It must return a string or nil.") | |
2656 | ||
2657 | (defvar org-export-filter-inline-babel-call-functions nil | |
2658 | "List of functions applied to a transcoded inline-babel-call. | |
2659 | Each filter is called with three arguments: the transcoded data, | |
2660 | as a string, the back-end, as a symbol, and the communication | |
2661 | channel, as a plist. It must return a string or nil.") | |
2662 | ||
2663 | (defvar org-export-filter-inline-src-block-functions nil | |
2664 | "List of functions applied to a transcoded inline-src-block. | |
2665 | Each filter is called with three arguments: the transcoded data, | |
2666 | as a string, the back-end, as a symbol, and the communication | |
2667 | channel, as a plist. It must return a string or nil.") | |
2668 | ||
2669 | (defvar org-export-filter-italic-functions nil | |
2670 | "List of functions applied to transcoded italic text. | |
2671 | Each filter is called with three arguments: the transcoded data, | |
2672 | as a string, the back-end, as a symbol, and the communication | |
2673 | channel, as a plist. It must return a string or nil.") | |
2674 | ||
2675 | (defvar org-export-filter-latex-fragment-functions nil | |
2676 | "List of functions applied to a transcoded latex-fragment. | |
2677 | Each filter is called with three arguments: the transcoded data, | |
2678 | as a string, the back-end, as a symbol, and the communication | |
2679 | channel, as a plist. It must return a string or nil.") | |
2680 | ||
2681 | (defvar org-export-filter-line-break-functions nil | |
2682 | "List of functions applied to a transcoded line-break. | |
2683 | Each filter is called with three arguments: the transcoded data, | |
2684 | as a string, the back-end, as a symbol, and the communication | |
2685 | channel, as a plist. It must return a string or nil.") | |
2686 | ||
2687 | (defvar org-export-filter-link-functions nil | |
2688 | "List of functions applied to a transcoded link. | |
2689 | Each filter is called with three arguments: the transcoded data, | |
2690 | as a string, the back-end, as a symbol, and the communication | |
2691 | channel, as a plist. It must return a string or nil.") | |
2692 | ||
2693 | (defvar org-export-filter-radio-target-functions nil | |
2694 | "List of functions applied to a transcoded radio-target. | |
2695 | Each filter is called with three arguments: the transcoded data, | |
2696 | as a string, the back-end, as a symbol, and the communication | |
2697 | channel, as a plist. It must return a string or nil.") | |
2698 | ||
2699 | (defvar org-export-filter-statistics-cookie-functions nil | |
2700 | "List of functions applied to a transcoded statistics-cookie. | |
2701 | Each filter is called with three arguments: the transcoded data, | |
2702 | as a string, the back-end, as a symbol, and the communication | |
2703 | channel, as a plist. It must return a string or nil.") | |
2704 | ||
2705 | (defvar org-export-filter-strike-through-functions nil | |
2706 | "List of functions applied to transcoded strike-through text. | |
2707 | Each filter is called with three arguments: the transcoded data, | |
2708 | as a string, the back-end, as a symbol, and the communication | |
2709 | channel, as a plist. It must return a string or nil.") | |
2710 | ||
2711 | (defvar org-export-filter-subscript-functions nil | |
2712 | "List of functions applied to a transcoded subscript. | |
2713 | Each filter is called with three arguments: the transcoded data, | |
2714 | as a string, the back-end, as a symbol, and the communication | |
2715 | channel, as a plist. It must return a string or nil.") | |
2716 | ||
2717 | (defvar org-export-filter-superscript-functions nil | |
2718 | "List of functions applied to a transcoded superscript. | |
2719 | Each filter is called with three arguments: the transcoded data, | |
2720 | as a string, the back-end, as a symbol, and the communication | |
2721 | channel, as a plist. It must return a string or nil.") | |
2722 | ||
2723 | (defvar org-export-filter-target-functions nil | |
2724 | "List of functions applied to a transcoded target. | |
2725 | Each filter is called with three arguments: the transcoded data, | |
2726 | as a string, the back-end, as a symbol, and the communication | |
2727 | channel, as a plist. It must return a string or nil.") | |
2728 | ||
2729 | (defvar org-export-filter-timestamp-functions nil | |
2730 | "List of functions applied to a transcoded timestamp. | |
2731 | Each filter is called with three arguments: the transcoded data, | |
2732 | as a string, the back-end, as a symbol, and the communication | |
2733 | channel, as a plist. It must return a string or nil.") | |
2734 | ||
2735 | (defvar org-export-filter-underline-functions nil | |
2736 | "List of functions applied to transcoded underline text. | |
2737 | Each filter is called with three arguments: the transcoded data, | |
2738 | as a string, the back-end, as a symbol, and the communication | |
2739 | channel, as a plist. It must return a string or nil.") | |
2740 | ||
2741 | (defvar org-export-filter-verbatim-functions nil | |
2742 | "List of functions applied to transcoded verbatim text. | |
2743 | Each filter is called with three arguments: the transcoded data, | |
2744 | as a string, the back-end, as a symbol, and the communication | |
2745 | channel, as a plist. It must return a string or nil.") | |
2746 | ||
2747 | ||
2748 | ;;;; Filters Tools | |
2749 | ;; | |
2750 | ;; Internal function `org-export-install-filters' installs filters | |
2751 | ;; hard-coded in back-ends (developer filters) and filters from global | |
2752 | ;; variables (user filters) in the communication channel. | |
2753 | ;; | |
2754 | ;; Internal function `org-export-filter-apply-functions' takes care | |
2755 | ;; about applying each filter in order to a given data. It ignores | |
2756 | ;; filters returning a nil value but stops whenever a filter returns | |
2757 | ;; an empty string. | |
2758 | ||
2759 | (defun org-export-filter-apply-functions (filters value info) | |
2760 | "Call every function in FILTERS. | |
2761 | ||
2762 | Functions are called with arguments VALUE, current export | |
2763 | back-end's name and INFO. A function returning a nil value will | |
2764 | be skipped. If it returns the empty string, the process ends and | |
2765 | VALUE is ignored. | |
2766 | ||
2767 | Call is done in a LIFO fashion, to be sure that developer | |
2768 | specified filters, if any, are called first." | |
2769 | (catch 'exit | |
2770 | (let* ((backend (plist-get info :back-end)) | |
2771 | (backend-name (and backend (org-export-backend-name backend)))) | |
2772 | (dolist (filter filters value) | |
2773 | (let ((result (funcall filter value backend-name info))) | |
2774 | (cond ((not result) value) | |
2775 | ((equal value "") (throw 'exit nil)) | |
2776 | (t (setq value result)))))))) | |
2777 | ||
2778 | (defun org-export-install-filters (info) | |
2779 | "Install filters properties in communication channel. | |
2780 | INFO is a plist containing the current communication channel. | |
2781 | Return the updated communication channel." | |
2782 | (let (plist) | |
2783 | ;; Install user-defined filters with `org-export-filters-alist' | |
2784 | ;; and filters already in INFO (through ext-plist mechanism). | |
2785 | (mapc (lambda (p) | |
2786 | (let* ((prop (car p)) | |
2787 | (info-value (plist-get info prop)) | |
2788 | (default-value (symbol-value (cdr p)))) | |
2789 | (setq plist | |
2790 | (plist-put plist prop | |
2791 | ;; Filters in INFO will be called | |
2792 | ;; before those user provided. | |
2793 | (append (if (listp info-value) info-value | |
2794 | (list info-value)) | |
2795 | default-value))))) | |
2796 | org-export-filters-alist) | |
2797 | ;; Prepend back-end specific filters to that list. | |
2798 | (mapc (lambda (p) | |
2799 | ;; Single values get consed, lists are appended. | |
2800 | (let ((key (car p)) (value (cdr p))) | |
2801 | (when value | |
2802 | (setq plist | |
2803 | (plist-put | |
2804 | plist key | |
2805 | (if (atom value) (cons value (plist-get plist key)) | |
2806 | (append value (plist-get plist key)))))))) | |
2807 | (org-export-get-all-filters (plist-get info :back-end))) | |
2808 | ;; Return new communication channel. | |
2809 | (org-combine-plists info plist))) | |
2810 | ||
2811 | ||
2812 | \f | |
2813 | ;;; Core functions | |
2814 | ;; | |
2815 | ;; This is the room for the main function, `org-export-as', along with | |
2816 | ;; its derivative, `org-export-string-as'. | |
2817 | ;; `org-export--copy-to-kill-ring-p' determines if output of these | |
2818 | ;; function should be added to kill ring. | |
2819 | ;; | |
2820 | ;; Note that `org-export-as' doesn't really parse the current buffer, | |
2821 | ;; but a copy of it (with the same buffer-local variables and | |
2822 | ;; visibility), where macros and include keywords are expanded and | |
2823 | ;; Babel blocks are executed, if appropriate. | |
2824 | ;; `org-export-with-buffer-copy' macro prepares that copy. | |
2825 | ;; | |
2826 | ;; File inclusion is taken care of by | |
2827 | ;; `org-export-expand-include-keyword' and | |
2828 | ;; `org-export--prepare-file-contents'. Structure wise, including | |
2829 | ;; a whole Org file in a buffer often makes little sense. For | |
2830 | ;; example, if the file contains a headline and the include keyword | |
2831 | ;; was within an item, the item should contain the headline. That's | |
2832 | ;; why file inclusion should be done before any structure can be | |
2833 | ;; associated to the file, that is before parsing. | |
2834 | ;; | |
2835 | ;; `org-export-insert-default-template' is a command to insert | |
2836 | ;; a default template (or a back-end specific template) at point or in | |
2837 | ;; current subtree. | |
2838 | ||
2839 | (defun org-export-copy-buffer () | |
2840 | "Return a copy of the current buffer. | |
2841 | The copy preserves Org buffer-local variables, visibility and | |
2842 | narrowing." | |
2843 | (let ((copy-buffer-fun (org-export--generate-copy-script (current-buffer))) | |
2844 | (new-buf (generate-new-buffer (buffer-name)))) | |
2845 | (with-current-buffer new-buf | |
2846 | (funcall copy-buffer-fun) | |
2847 | (set-buffer-modified-p nil)) | |
2848 | new-buf)) | |
2849 | ||
2850 | (defmacro org-export-with-buffer-copy (&rest body) | |
2851 | "Apply BODY in a copy of the current buffer. | |
2852 | The copy preserves local variables, visibility and contents of | |
2853 | the original buffer. Point is at the beginning of the buffer | |
2854 | when BODY is applied." | |
2855 | (declare (debug t)) | |
2856 | (org-with-gensyms (buf-copy) | |
2857 | `(let ((,buf-copy (org-export-copy-buffer))) | |
2858 | (unwind-protect | |
2859 | (with-current-buffer ,buf-copy | |
2860 | (goto-char (point-min)) | |
2861 | (progn ,@body)) | |
2862 | (and (buffer-live-p ,buf-copy) | |
2863 | ;; Kill copy without confirmation. | |
2864 | (progn (with-current-buffer ,buf-copy | |
2865 | (restore-buffer-modified-p nil)) | |
2866 | (kill-buffer ,buf-copy))))))) | |
2867 | ||
2868 | (defun org-export--generate-copy-script (buffer) | |
2869 | "Generate a function duplicating BUFFER. | |
2870 | ||
2871 | The copy will preserve local variables, visibility, contents and | |
2872 | narrowing of the original buffer. If a region was active in | |
2873 | BUFFER, contents will be narrowed to that region instead. | |
2874 | ||
d1389828 | 2875 | The resulting function can be evaluated at a later time, from |
271672fa BG |
2876 | another buffer, effectively cloning the original buffer there. |
2877 | ||
2878 | The function assumes BUFFER's major mode is `org-mode'." | |
2879 | (with-current-buffer buffer | |
2880 | `(lambda () | |
2881 | (let ((inhibit-modification-hooks t)) | |
2882 | ;; Set major mode. Ignore `org-mode-hook' as it has been run | |
2883 | ;; already in BUFFER. | |
2884 | (let ((org-mode-hook nil) (org-inhibit-startup t)) (org-mode)) | |
2885 | ;; Copy specific buffer local variables and variables set | |
2886 | ;; through BIND keywords. | |
2887 | ,@(let ((bound-variables (org-export--list-bound-variables)) | |
2888 | vars) | |
2889 | (dolist (entry (buffer-local-variables (buffer-base-buffer)) vars) | |
2890 | (when (consp entry) | |
2891 | (let ((var (car entry)) | |
2892 | (val (cdr entry))) | |
2893 | (and (not (eq var 'org-font-lock-keywords)) | |
2894 | (or (memq var | |
2895 | '(default-directory | |
2896 | buffer-file-name | |
2897 | buffer-file-coding-system)) | |
2898 | (assq var bound-variables) | |
2899 | (string-match "^\\(org-\\|orgtbl-\\)" | |
2900 | (symbol-name var))) | |
2901 | ;; Skip unreadable values, as they cannot be | |
2902 | ;; sent to external process. | |
2903 | (or (not val) (ignore-errors (read (format "%S" val)))) | |
2904 | (push `(set (make-local-variable (quote ,var)) | |
2905 | (quote ,val)) | |
2906 | vars)))))) | |
2907 | ;; Whole buffer contents. | |
2908 | (insert | |
2909 | ,(org-with-wide-buffer | |
2910 | (buffer-substring-no-properties | |
2911 | (point-min) (point-max)))) | |
2912 | ;; Narrowing. | |
2913 | ,(if (org-region-active-p) | |
2914 | `(narrow-to-region ,(region-beginning) ,(region-end)) | |
2915 | `(narrow-to-region ,(point-min) ,(point-max))) | |
2916 | ;; Current position of point. | |
2917 | (goto-char ,(point)) | |
2918 | ;; Overlays with invisible property. | |
2919 | ,@(let (ov-set) | |
2920 | (mapc | |
2921 | (lambda (ov) | |
2922 | (let ((invis-prop (overlay-get ov 'invisible))) | |
2923 | (when invis-prop | |
2924 | (push `(overlay-put | |
2925 | (make-overlay ,(overlay-start ov) | |
2926 | ,(overlay-end ov)) | |
2927 | 'invisible (quote ,invis-prop)) | |
2928 | ov-set)))) | |
2929 | (overlays-in (point-min) (point-max))) | |
2930 | ov-set))))) | |
2931 | ||
2932 | ;;;###autoload | |
2933 | (defun org-export-as | |
2934 | (backend &optional subtreep visible-only body-only ext-plist) | |
2935 | "Transcode current Org buffer into BACKEND code. | |
2936 | ||
2937 | BACKEND is either an export back-end, as returned by, e.g., | |
2938 | `org-export-create-backend', or a symbol referring to | |
2939 | a registered back-end. | |
2940 | ||
2941 | If narrowing is active in the current buffer, only transcode its | |
2942 | narrowed part. | |
2943 | ||
2944 | If a region is active, transcode that region. | |
2945 | ||
2946 | When optional argument SUBTREEP is non-nil, transcode the | |
2947 | sub-tree at point, extracting information from the headline | |
2948 | properties first. | |
2949 | ||
2950 | When optional argument VISIBLE-ONLY is non-nil, don't export | |
2951 | contents of hidden elements. | |
2952 | ||
2953 | When optional argument BODY-ONLY is non-nil, only return body | |
2954 | code, without surrounding template. | |
2955 | ||
2956 | Optional argument EXT-PLIST, when provided, is a property list | |
2957 | with external parameters overriding Org default settings, but | |
2958 | still inferior to file-local settings. | |
2959 | ||
2960 | Return code as a string." | |
2961 | (when (symbolp backend) (setq backend (org-export-get-backend backend))) | |
2962 | (org-export-barf-if-invalid-backend backend) | |
2963 | (save-excursion | |
2964 | (save-restriction | |
2965 | ;; Narrow buffer to an appropriate region or subtree for | |
2966 | ;; parsing. If parsing subtree, be sure to remove main headline | |
2967 | ;; too. | |
2968 | (cond ((org-region-active-p) | |
2969 | (narrow-to-region (region-beginning) (region-end))) | |
2970 | (subtreep | |
2971 | (org-narrow-to-subtree) | |
2972 | (goto-char (point-min)) | |
2973 | (forward-line) | |
2974 | (narrow-to-region (point) (point-max)))) | |
2975 | ;; Initialize communication channel with original buffer | |
2976 | ;; attributes, unavailable in its copy. | |
2977 | (let* ((org-export-current-backend (org-export-backend-name backend)) | |
2978 | (info (org-combine-plists | |
2979 | (list :export-options | |
2980 | (delq nil | |
2981 | (list (and subtreep 'subtree) | |
2982 | (and visible-only 'visible-only) | |
2983 | (and body-only 'body-only)))) | |
2984 | (org-export--get-buffer-attributes))) | |
2985 | tree) | |
2986 | ;; Update communication channel and get parse tree. Buffer | |
2987 | ;; isn't parsed directly. Instead, a temporary copy is | |
2988 | ;; created, where include keywords, macros are expanded and | |
2989 | ;; code blocks are evaluated. | |
2990 | (org-export-with-buffer-copy | |
2991 | ;; Run first hook with current back-end's name as argument. | |
2992 | (run-hook-with-args 'org-export-before-processing-hook | |
2993 | (org-export-backend-name backend)) | |
2994 | (org-export-expand-include-keyword) | |
2995 | ;; Update macro templates since #+INCLUDE keywords might have | |
2996 | ;; added some new ones. | |
2997 | (org-macro-initialize-templates) | |
2998 | (org-macro-replace-all org-macro-templates) | |
2999 | (org-export-execute-babel-code) | |
3000 | ;; Update radio targets since keyword inclusion might have | |
3001 | ;; added some more. | |
3002 | (org-update-radio-target-regexp) | |
3003 | ;; Run last hook with current back-end's name as argument. | |
3004 | (goto-char (point-min)) | |
3005 | (save-excursion | |
3006 | (run-hook-with-args 'org-export-before-parsing-hook | |
3007 | (org-export-backend-name backend))) | |
3008 | ;; Update communication channel with environment. Also | |
3009 | ;; install user's and developer's filters. | |
3010 | (setq info | |
3011 | (org-export-install-filters | |
3012 | (org-combine-plists | |
3013 | info (org-export-get-environment backend subtreep ext-plist)))) | |
3014 | ;; Expand export-specific set of macros: {{{author}}}, | |
3015 | ;; {{{date}}}, {{{email}}} and {{{title}}}. It must be done | |
3016 | ;; once regular macros have been expanded, since document | |
3017 | ;; keywords may contain one of them. | |
3018 | (org-macro-replace-all | |
3019 | (list (cons "author" | |
3020 | (org-element-interpret-data (plist-get info :author))) | |
3021 | (cons "date" | |
3022 | (org-element-interpret-data (plist-get info :date))) | |
3023 | ;; EMAIL is not a parsed keyword: store it as-is. | |
3024 | (cons "email" (or (plist-get info :email) "")) | |
3025 | (cons "title" | |
3026 | (org-element-interpret-data (plist-get info :title))))) | |
3027 | ;; Call options filters and update export options. We do not | |
3028 | ;; use `org-export-filter-apply-functions' here since the | |
3029 | ;; arity of such filters is different. | |
3030 | (let ((backend-name (org-export-backend-name backend))) | |
3031 | (dolist (filter (plist-get info :filter-options)) | |
3032 | (let ((result (funcall filter info backend-name))) | |
3033 | (when result (setq info result))))) | |
3034 | ;; Parse buffer and call parse-tree filter on it. | |
3035 | (setq tree | |
3036 | (org-export-filter-apply-functions | |
3037 | (plist-get info :filter-parse-tree) | |
3038 | (org-element-parse-buffer nil visible-only) info)) | |
3039 | ;; Now tree is complete, compute its properties and add them | |
3040 | ;; to communication channel. | |
3041 | (setq info | |
3042 | (org-combine-plists | |
3043 | info (org-export-collect-tree-properties tree info))) | |
3044 | ;; Eventually transcode TREE. Wrap the resulting string into | |
3045 | ;; a template. | |
3046 | (let* ((body (org-element-normalize-string | |
3047 | (or (org-export-data tree info) ""))) | |
3048 | (inner-template (cdr (assq 'inner-template | |
3049 | (plist-get info :translate-alist)))) | |
3050 | (full-body (if (not (functionp inner-template)) body | |
3051 | (funcall inner-template body info))) | |
3052 | (template (cdr (assq 'template | |
3053 | (plist-get info :translate-alist))))) | |
3054 | ;; Remove all text properties since they cannot be | |
3055 | ;; retrieved from an external process. Finally call | |
3056 | ;; final-output filter and return result. | |
3057 | (org-no-properties | |
3058 | (org-export-filter-apply-functions | |
3059 | (plist-get info :filter-final-output) | |
3060 | (if (or (not (functionp template)) body-only) full-body | |
3061 | (funcall template full-body info)) | |
3062 | info)))))))) | |
3063 | ||
3064 | ;;;###autoload | |
3065 | (defun org-export-string-as (string backend &optional body-only ext-plist) | |
3066 | "Transcode STRING into BACKEND code. | |
3067 | ||
3068 | BACKEND is either an export back-end, as returned by, e.g., | |
3069 | `org-export-create-backend', or a symbol referring to | |
3070 | a registered back-end. | |
3071 | ||
3072 | When optional argument BODY-ONLY is non-nil, only return body | |
3073 | code, without preamble nor postamble. | |
3074 | ||
3075 | Optional argument EXT-PLIST, when provided, is a property list | |
3076 | with external parameters overriding Org default settings, but | |
3077 | still inferior to file-local settings. | |
3078 | ||
3079 | Return code as a string." | |
3080 | (with-temp-buffer | |
3081 | (insert string) | |
3082 | (let ((org-inhibit-startup t)) (org-mode)) | |
3083 | (org-export-as backend nil nil body-only ext-plist))) | |
3084 | ||
3085 | ;;;###autoload | |
3086 | (defun org-export-replace-region-by (backend) | |
3087 | "Replace the active region by its export to BACKEND. | |
3088 | BACKEND is either an export back-end, as returned by, e.g., | |
3089 | `org-export-create-backend', or a symbol referring to | |
3090 | a registered back-end." | |
3091 | (if (not (org-region-active-p)) | |
3092 | (user-error "No active region to replace") | |
3093 | (let* ((beg (region-beginning)) | |
3094 | (end (region-end)) | |
3095 | (str (buffer-substring beg end)) rpl) | |
3096 | (setq rpl (org-export-string-as str backend t)) | |
3097 | (delete-region beg end) | |
3098 | (insert rpl)))) | |
3099 | ||
3100 | ;;;###autoload | |
3101 | (defun org-export-insert-default-template (&optional backend subtreep) | |
3102 | "Insert all export keywords with default values at beginning of line. | |
3103 | ||
3104 | BACKEND is a symbol referring to the name of a registered export | |
3105 | back-end, for which specific export options should be added to | |
3106 | the template, or `default' for default template. When it is nil, | |
3107 | the user will be prompted for a category. | |
3108 | ||
3109 | If SUBTREEP is non-nil, export configuration will be set up | |
3110 | locally for the subtree through node properties." | |
3111 | (interactive) | |
3112 | (unless (derived-mode-p 'org-mode) (user-error "Not in an Org mode buffer")) | |
3113 | (when (and subtreep (org-before-first-heading-p)) | |
3114 | (user-error "No subtree to set export options for")) | |
3115 | (let ((node (and subtreep (save-excursion (org-back-to-heading t) (point)))) | |
3116 | (backend | |
3117 | (or backend | |
3118 | (intern | |
3119 | (org-completing-read | |
3120 | "Options category: " | |
3121 | (cons "default" | |
3122 | (mapcar (lambda (b) | |
3123 | (symbol-name (org-export-backend-name b))) | |
3124 | org-export--registered-backends)))))) | |
3125 | options keywords) | |
3126 | ;; Populate OPTIONS and KEYWORDS. | |
3127 | (dolist (entry (cond ((eq backend 'default) org-export-options-alist) | |
3128 | ((org-export-backend-p backend) | |
30cb51f1 BG |
3129 | (org-export-backend-options backend)) |
3130 | (t (org-export-backend-options | |
271672fa BG |
3131 | (org-export-get-backend backend))))) |
3132 | (let ((keyword (nth 1 entry)) | |
3133 | (option (nth 2 entry))) | |
3134 | (cond | |
3135 | (keyword (unless (assoc keyword keywords) | |
3136 | (let ((value | |
3137 | (if (eq (nth 4 entry) 'split) | |
3138 | (mapconcat 'identity (eval (nth 3 entry)) " ") | |
3139 | (eval (nth 3 entry))))) | |
3140 | (push (cons keyword value) keywords)))) | |
3141 | (option (unless (assoc option options) | |
3142 | (push (cons option (eval (nth 3 entry))) options)))))) | |
3143 | ;; Move to an appropriate location in order to insert options. | |
3144 | (unless subtreep (beginning-of-line)) | |
3145 | ;; First get TITLE, DATE, AUTHOR and EMAIL if they belong to the | |
3146 | ;; list of available keywords. | |
3147 | (when (assoc "TITLE" keywords) | |
3148 | (let ((title | |
3149 | (or (let ((visited-file (buffer-file-name (buffer-base-buffer)))) | |
3150 | (and visited-file | |
3151 | (file-name-sans-extension | |
3152 | (file-name-nondirectory visited-file)))) | |
3153 | (buffer-name (buffer-base-buffer))))) | |
3154 | (if (not subtreep) (insert (format "#+TITLE: %s\n" title)) | |
3155 | (org-entry-put node "EXPORT_TITLE" title)))) | |
3156 | (when (assoc "DATE" keywords) | |
3157 | (let ((date (with-temp-buffer (org-insert-time-stamp (current-time))))) | |
3158 | (if (not subtreep) (insert "#+DATE: " date "\n") | |
3159 | (org-entry-put node "EXPORT_DATE" date)))) | |
3160 | (when (assoc "AUTHOR" keywords) | |
3161 | (let ((author (cdr (assoc "AUTHOR" keywords)))) | |
3162 | (if subtreep (org-entry-put node "EXPORT_AUTHOR" author) | |
3163 | (insert | |
3164 | (format "#+AUTHOR:%s\n" | |
3165 | (if (not (org-string-nw-p author)) "" | |
3166 | (concat " " author))))))) | |
3167 | (when (assoc "EMAIL" keywords) | |
3168 | (let ((email (cdr (assoc "EMAIL" keywords)))) | |
3169 | (if subtreep (org-entry-put node "EXPORT_EMAIL" email) | |
3170 | (insert | |
3171 | (format "#+EMAIL:%s\n" | |
3172 | (if (not (org-string-nw-p email)) "" | |
3173 | (concat " " email))))))) | |
3174 | ;; Then (multiple) OPTIONS lines. Never go past fill-column. | |
3175 | (when options | |
3176 | (let ((items | |
3177 | (mapcar | |
3178 | #'(lambda (opt) (format "%s:%S" (car opt) (cdr opt))) | |
3179 | (sort options (lambda (k1 k2) (string< (car k1) (car k2))))))) | |
3180 | (if subtreep | |
3181 | (org-entry-put | |
3182 | node "EXPORT_OPTIONS" (mapconcat 'identity items " ")) | |
3183 | (while items | |
3184 | (insert "#+OPTIONS:") | |
3185 | (let ((width 10)) | |
3186 | (while (and items | |
3187 | (< (+ width (length (car items)) 1) fill-column)) | |
3188 | (let ((item (pop items))) | |
3189 | (insert " " item) | |
3190 | (incf width (1+ (length item)))))) | |
3191 | (insert "\n"))))) | |
3192 | ;; And the rest of keywords. | |
3193 | (dolist (key (sort keywords (lambda (k1 k2) (string< (car k1) (car k2))))) | |
3194 | (unless (member (car key) '("TITLE" "DATE" "AUTHOR" "EMAIL")) | |
3195 | (let ((val (cdr key))) | |
3196 | (if subtreep (org-entry-put node (concat "EXPORT_" (car key)) val) | |
3197 | (insert | |
3198 | (format "#+%s:%s\n" | |
3199 | (car key) | |
3200 | (if (org-string-nw-p val) (format " %s" val) ""))))))))) | |
3201 | ||
3202 | (defun org-export-expand-include-keyword (&optional included dir) | |
3203 | "Expand every include keyword in buffer. | |
3204 | Optional argument INCLUDED is a list of included file names along | |
3205 | with their line restriction, when appropriate. It is used to | |
3206 | avoid infinite recursion. Optional argument DIR is the current | |
3207 | working directory. It is used to properly resolve relative | |
3208 | paths." | |
3209 | (let ((case-fold-search t)) | |
3210 | (goto-char (point-min)) | |
3211 | (while (re-search-forward "^[ \t]*#\\+INCLUDE:" nil t) | |
3212 | (let ((element (save-match-data (org-element-at-point)))) | |
3213 | (when (eq (org-element-type element) 'keyword) | |
3214 | (beginning-of-line) | |
3215 | ;; Extract arguments from keyword's value. | |
3216 | (let* ((value (org-element-property :value element)) | |
3217 | (ind (org-get-indentation)) | |
3218 | (file (and (string-match | |
3219 | "^\\(\".+?\"\\|\\S-+\\)\\(?:\\s-+\\|$\\)" value) | |
3220 | (prog1 (expand-file-name | |
3221 | (org-remove-double-quotes | |
3222 | (match-string 1 value)) | |
3223 | dir) | |
3224 | (setq value (replace-match "" nil nil value))))) | |
3225 | (lines | |
3226 | (and (string-match | |
3227 | ":lines +\"\\(\\(?:[0-9]+\\)?-\\(?:[0-9]+\\)?\\)\"" | |
3228 | value) | |
3229 | (prog1 (match-string 1 value) | |
3230 | (setq value (replace-match "" nil nil value))))) | |
3231 | (env (cond ((string-match "\\<example\\>" value) 'example) | |
3232 | ((string-match "\\<src\\(?: +\\(.*\\)\\)?" value) | |
3233 | (match-string 1 value)))) | |
3234 | ;; Minimal level of included file defaults to the child | |
3235 | ;; level of the current headline, if any, or one. It | |
3236 | ;; only applies is the file is meant to be included as | |
3237 | ;; an Org one. | |
3238 | (minlevel | |
3239 | (and (not env) | |
3240 | (if (string-match ":minlevel +\\([0-9]+\\)" value) | |
3241 | (prog1 (string-to-number (match-string 1 value)) | |
3242 | (setq value (replace-match "" nil nil value))) | |
3243 | (let ((cur (org-current-level))) | |
3244 | (if cur (1+ (org-reduced-level cur)) 1)))))) | |
3245 | ;; Remove keyword. | |
3246 | (delete-region (point) (progn (forward-line) (point))) | |
3247 | (cond | |
3248 | ((not file) nil) | |
3249 | ((not (file-readable-p file)) | |
3250 | (error "Cannot include file %s" file)) | |
3251 | ;; Check if files has already been parsed. Look after | |
3252 | ;; inclusion lines too, as different parts of the same file | |
3253 | ;; can be included too. | |
3254 | ((member (list file lines) included) | |
3255 | (error "Recursive file inclusion: %s" file)) | |
3256 | (t | |
3257 | (cond | |
3258 | ((eq env 'example) | |
3259 | (insert | |
3260 | (let ((ind-str (make-string ind ? )) | |
3261 | (contents | |
3262 | (org-escape-code-in-string | |
3263 | (org-export--prepare-file-contents file lines)))) | |
3264 | (format "%s#+BEGIN_EXAMPLE\n%s%s#+END_EXAMPLE\n" | |
3265 | ind-str contents ind-str)))) | |
3266 | ((stringp env) | |
3267 | (insert | |
3268 | (let ((ind-str (make-string ind ? )) | |
3269 | (contents | |
3270 | (org-escape-code-in-string | |
3271 | (org-export--prepare-file-contents file lines)))) | |
3272 | (format "%s#+BEGIN_SRC %s\n%s%s#+END_SRC\n" | |
3273 | ind-str env contents ind-str)))) | |
3274 | (t | |
3275 | (insert | |
3276 | (with-temp-buffer | |
3277 | (let ((org-inhibit-startup t)) (org-mode)) | |
3278 | (insert | |
3279 | (org-export--prepare-file-contents file lines ind minlevel)) | |
3280 | (org-export-expand-include-keyword | |
3281 | (cons (list file lines) included) | |
3282 | (file-name-directory file)) | |
3283 | (buffer-string))))))))))))) | |
3284 | ||
3285 | (defun org-export--prepare-file-contents (file &optional lines ind minlevel) | |
3286 | "Prepare the contents of FILE for inclusion and return them as a string. | |
3287 | ||
3288 | When optional argument LINES is a string specifying a range of | |
3289 | lines, include only those lines. | |
3290 | ||
3291 | Optional argument IND, when non-nil, is an integer specifying the | |
3292 | global indentation of returned contents. Since its purpose is to | |
3293 | allow an included file to stay in the same environment it was | |
3294 | created \(i.e. a list item), it doesn't apply past the first | |
3295 | headline encountered. | |
3296 | ||
3297 | Optional argument MINLEVEL, when non-nil, is an integer | |
3298 | specifying the level that any top-level headline in the included | |
3299 | file should have." | |
3300 | (with-temp-buffer | |
3301 | (insert-file-contents file) | |
3302 | (when lines | |
3303 | (let* ((lines (split-string lines "-")) | |
3304 | (lbeg (string-to-number (car lines))) | |
3305 | (lend (string-to-number (cadr lines))) | |
3306 | (beg (if (zerop lbeg) (point-min) | |
3307 | (goto-char (point-min)) | |
3308 | (forward-line (1- lbeg)) | |
3309 | (point))) | |
3310 | (end (if (zerop lend) (point-max) | |
3311 | (goto-char (point-min)) | |
3312 | (forward-line (1- lend)) | |
3313 | (point)))) | |
3314 | (narrow-to-region beg end))) | |
3315 | ;; Remove blank lines at beginning and end of contents. The logic | |
3316 | ;; behind that removal is that blank lines around include keyword | |
3317 | ;; override blank lines in included file. | |
3318 | (goto-char (point-min)) | |
3319 | (org-skip-whitespace) | |
3320 | (beginning-of-line) | |
3321 | (delete-region (point-min) (point)) | |
3322 | (goto-char (point-max)) | |
3323 | (skip-chars-backward " \r\t\n") | |
3324 | (forward-line) | |
3325 | (delete-region (point) (point-max)) | |
3326 | ;; If IND is set, preserve indentation of include keyword until | |
3327 | ;; the first headline encountered. | |
3328 | (when ind | |
3329 | (unless (eq major-mode 'org-mode) | |
3330 | (let ((org-inhibit-startup t)) (org-mode))) | |
3331 | (goto-char (point-min)) | |
3332 | (let ((ind-str (make-string ind ? ))) | |
3333 | (while (not (or (eobp) (looking-at org-outline-regexp-bol))) | |
3334 | ;; Do not move footnote definitions out of column 0. | |
3335 | (unless (and (looking-at org-footnote-definition-re) | |
3336 | (eq (org-element-type (org-element-at-point)) | |
3337 | 'footnote-definition)) | |
3338 | (insert ind-str)) | |
3339 | (forward-line)))) | |
3340 | ;; When MINLEVEL is specified, compute minimal level for headlines | |
3341 | ;; in the file (CUR-MIN), and remove stars to each headline so | |
3342 | ;; that headlines with minimal level have a level of MINLEVEL. | |
3343 | (when minlevel | |
3344 | (unless (eq major-mode 'org-mode) | |
3345 | (let ((org-inhibit-startup t)) (org-mode))) | |
3346 | (org-with-limited-levels | |
3347 | (let ((levels (org-map-entries | |
3348 | (lambda () (org-reduced-level (org-current-level)))))) | |
3349 | (when levels | |
3350 | (let ((offset (- minlevel (apply 'min levels)))) | |
3351 | (unless (zerop offset) | |
3352 | (when org-odd-levels-only (setq offset (* offset 2))) | |
3353 | ;; Only change stars, don't bother moving whole | |
3354 | ;; sections. | |
3355 | (org-map-entries | |
3356 | (lambda () (if (< offset 0) (delete-char (abs offset)) | |
3357 | (insert (make-string offset ?*))))))))))) | |
3358 | (org-element-normalize-string (buffer-string)))) | |
3359 | ||
3360 | (defun org-export-execute-babel-code () | |
3361 | "Execute every Babel code in the visible part of current buffer." | |
3362 | ;; Get a pristine copy of current buffer so Babel references can be | |
3363 | ;; properly resolved. | |
3364 | (let ((reference (org-export-copy-buffer))) | |
3365 | (unwind-protect (let ((org-current-export-file reference)) | |
3366 | (org-babel-exp-process-buffer)) | |
3367 | (kill-buffer reference)))) | |
3368 | ||
3369 | (defun org-export--copy-to-kill-ring-p () | |
3370 | "Return a non-nil value when output should be added to the kill ring. | |
3371 | See also `org-export-copy-to-kill-ring'." | |
3372 | (if (eq org-export-copy-to-kill-ring 'if-interactive) | |
3373 | (not (or executing-kbd-macro noninteractive)) | |
3374 | (eq org-export-copy-to-kill-ring t))) | |
3375 | ||
3376 | ||
3377 | \f | |
3378 | ;;; Tools For Back-Ends | |
3379 | ;; | |
3380 | ;; A whole set of tools is available to help build new exporters. Any | |
3381 | ;; function general enough to have its use across many back-ends | |
3382 | ;; should be added here. | |
3383 | ||
3384 | ;;;; For Affiliated Keywords | |
3385 | ;; | |
3386 | ;; `org-export-read-attribute' reads a property from a given element | |
3387 | ;; as a plist. It can be used to normalize affiliated keywords' | |
3388 | ;; syntax. | |
3389 | ;; | |
3390 | ;; Since captions can span over multiple lines and accept dual values, | |
3391 | ;; their internal representation is a bit tricky. Therefore, | |
3392 | ;; `org-export-get-caption' transparently returns a given element's | |
3393 | ;; caption as a secondary string. | |
3394 | ||
3395 | (defun org-export-read-attribute (attribute element &optional property) | |
3396 | "Turn ATTRIBUTE property from ELEMENT into a plist. | |
3397 | ||
3398 | When optional argument PROPERTY is non-nil, return the value of | |
3399 | that property within attributes. | |
3400 | ||
3401 | This function assumes attributes are defined as \":keyword | |
3402 | value\" pairs. It is appropriate for `:attr_html' like | |
3403 | properties. | |
3404 | ||
3405 | All values will become strings except the empty string and | |
3406 | \"nil\", which will become nil. Also, values containing only | |
3407 | double quotes will be read as-is, which means that \"\" value | |
3408 | will become the empty string." | |
3409 | (let* ((prepare-value | |
3410 | (lambda (str) | |
3411 | (save-match-data | |
3412 | (cond ((member str '(nil "" "nil")) nil) | |
3413 | ((string-match "^\"\\(\"+\\)?\"$" str) | |
3414 | (or (match-string 1 str) "")) | |
3415 | (t str))))) | |
3416 | (attributes | |
3417 | (let ((value (org-element-property attribute element))) | |
3418 | (when value | |
3419 | (let ((s (mapconcat 'identity value " ")) result) | |
3420 | (while (string-match | |
3421 | "\\(?:^\\|[ \t]+\\)\\(:[-a-zA-Z0-9_]+\\)\\([ \t]+\\|$\\)" | |
3422 | s) | |
3423 | (let ((value (substring s 0 (match-beginning 0)))) | |
3424 | (push (funcall prepare-value value) result)) | |
3425 | (push (intern (match-string 1 s)) result) | |
3426 | (setq s (substring s (match-end 0)))) | |
3427 | ;; Ignore any string before first property with `cdr'. | |
3428 | (cdr (nreverse (cons (funcall prepare-value s) result)))))))) | |
3429 | (if property (plist-get attributes property) attributes))) | |
3430 | ||
3431 | (defun org-export-get-caption (element &optional shortp) | |
3432 | "Return caption from ELEMENT as a secondary string. | |
3433 | ||
3434 | When optional argument SHORTP is non-nil, return short caption, | |
3435 | as a secondary string, instead. | |
3436 | ||
3437 | Caption lines are separated by a white space." | |
3438 | (let ((full-caption (org-element-property :caption element)) caption) | |
3439 | (dolist (line full-caption (cdr caption)) | |
3440 | (let ((cap (funcall (if shortp 'cdr 'car) line))) | |
3441 | (when cap | |
3442 | (setq caption (nconc (list " ") (copy-sequence cap) caption))))))) | |
3443 | ||
3444 | ||
3445 | ;;;; For Derived Back-ends | |
3446 | ;; | |
3447 | ;; `org-export-with-backend' is a function allowing to locally use | |
3448 | ;; another back-end to transcode some object or element. In a derived | |
3449 | ;; back-end, it may be used as a fall-back function once all specific | |
3450 | ;; cases have been treated. | |
3451 | ||
3452 | (defun org-export-with-backend (backend data &optional contents info) | |
3453 | "Call a transcoder from BACKEND on DATA. | |
3454 | BACKEND is an export back-end, as returned by, e.g., | |
3455 | `org-export-create-backend', or a symbol referring to | |
3456 | a registered back-end. DATA is an Org element, object, secondary | |
3457 | string or string. CONTENTS, when non-nil, is the transcoded | |
3458 | contents of DATA element, as a string. INFO, when non-nil, is | |
3459 | the communication channel used for export, as a plist." | |
3460 | (when (symbolp backend) (setq backend (org-export-get-backend backend))) | |
3461 | (org-export-barf-if-invalid-backend backend) | |
3462 | (let ((type (org-element-type data))) | |
3463 | (if (memq type '(nil org-data)) (error "No foreign transcoder available") | |
3464 | (let* ((all-transcoders (org-export-get-all-transcoders backend)) | |
3465 | (transcoder (cdr (assq type all-transcoders)))) | |
3466 | (if (not (functionp transcoder)) | |
3467 | (error "No foreign transcoder available") | |
3468 | (funcall | |
3469 | transcoder data contents | |
3470 | (org-combine-plists | |
3471 | info (list :back-end backend | |
3472 | :translate-alist all-transcoders | |
3473 | :exported-data (make-hash-table :test 'eq :size 401))))))))) | |
3474 | ||
3475 | ||
3476 | ;;;; For Export Snippets | |
3477 | ;; | |
3478 | ;; Every export snippet is transmitted to the back-end. Though, the | |
3479 | ;; latter will only retain one type of export-snippet, ignoring | |
3480 | ;; others, based on the former's target back-end. The function | |
3481 | ;; `org-export-snippet-backend' returns that back-end for a given | |
3482 | ;; export-snippet. | |
3483 | ||
3484 | (defun org-export-snippet-backend (export-snippet) | |
3485 | "Return EXPORT-SNIPPET targeted back-end as a symbol. | |
3486 | Translation, with `org-export-snippet-translation-alist', is | |
3487 | applied." | |
3488 | (let ((back-end (org-element-property :back-end export-snippet))) | |
3489 | (intern | |
3490 | (or (cdr (assoc back-end org-export-snippet-translation-alist)) | |
3491 | back-end)))) | |
3492 | ||
3493 | ||
3494 | ;;;; For Footnotes | |
3495 | ;; | |
3496 | ;; `org-export-collect-footnote-definitions' is a tool to list | |
3497 | ;; actually used footnotes definitions in the whole parse tree, or in | |
3498 | ;; a headline, in order to add footnote listings throughout the | |
3499 | ;; transcoded data. | |
3500 | ;; | |
3501 | ;; `org-export-footnote-first-reference-p' is a predicate used by some | |
3502 | ;; back-ends, when they need to attach the footnote definition only to | |
3503 | ;; the first occurrence of the corresponding label. | |
3504 | ;; | |
3505 | ;; `org-export-get-footnote-definition' and | |
3506 | ;; `org-export-get-footnote-number' provide easier access to | |
3507 | ;; additional information relative to a footnote reference. | |
3508 | ||
3509 | (defun org-export-collect-footnote-definitions (data info) | |
3510 | "Return an alist between footnote numbers, labels and definitions. | |
3511 | ||
3512 | DATA is the parse tree from which definitions are collected. | |
3513 | INFO is the plist used as a communication channel. | |
3514 | ||
3515 | Definitions are sorted by order of references. They either | |
3516 | appear as Org data or as a secondary string for inlined | |
3517 | footnotes. Unreferenced definitions are ignored." | |
3518 | (let* (num-alist | |
3519 | collect-fn ; for byte-compiler. | |
3520 | (collect-fn | |
3521 | (function | |
3522 | (lambda (data) | |
3523 | ;; Collect footnote number, label and definition in DATA. | |
3524 | (org-element-map data 'footnote-reference | |
3525 | (lambda (fn) | |
3526 | (when (org-export-footnote-first-reference-p fn info) | |
3527 | (let ((def (org-export-get-footnote-definition fn info))) | |
3528 | (push | |
3529 | (list (org-export-get-footnote-number fn info) | |
3530 | (org-element-property :label fn) | |
3531 | def) | |
3532 | num-alist) | |
3533 | ;; Also search in definition for nested footnotes. | |
3534 | (when (eq (org-element-property :type fn) 'standard) | |
3535 | (funcall collect-fn def))))) | |
3536 | ;; Don't enter footnote definitions since it will happen | |
3537 | ;; when their first reference is found. | |
3538 | info nil 'footnote-definition))))) | |
3539 | (funcall collect-fn (plist-get info :parse-tree)) | |
3540 | (reverse num-alist))) | |
3541 | ||
3542 | (defun org-export-footnote-first-reference-p (footnote-reference info) | |
3543 | "Non-nil when a footnote reference is the first one for its label. | |
3544 | ||
3545 | FOOTNOTE-REFERENCE is the footnote reference being considered. | |
3546 | INFO is the plist used as a communication channel." | |
3547 | (let ((label (org-element-property :label footnote-reference))) | |
3548 | ;; Anonymous footnotes are always a first reference. | |
3549 | (if (not label) t | |
3550 | ;; Otherwise, return the first footnote with the same LABEL and | |
3551 | ;; test if it is equal to FOOTNOTE-REFERENCE. | |
3552 | (let* (search-refs ; for byte-compiler. | |
3553 | (search-refs | |
3554 | (function | |
3555 | (lambda (data) | |
3556 | (org-element-map data 'footnote-reference | |
3557 | (lambda (fn) | |
3558 | (cond | |
3559 | ((string= (org-element-property :label fn) label) | |
3560 | (throw 'exit fn)) | |
3561 | ;; If FN isn't inlined, be sure to traverse its | |
3562 | ;; definition before resuming search. See | |
3563 | ;; comments in `org-export-get-footnote-number' | |
3564 | ;; for more information. | |
3565 | ((eq (org-element-property :type fn) 'standard) | |
3566 | (funcall search-refs | |
3567 | (org-export-get-footnote-definition fn info))))) | |
3568 | ;; Don't enter footnote definitions since it will | |
3569 | ;; happen when their first reference is found. | |
3570 | info 'first-match 'footnote-definition))))) | |
3571 | (eq (catch 'exit (funcall search-refs (plist-get info :parse-tree))) | |
3572 | footnote-reference))))) | |
3573 | ||
3574 | (defun org-export-get-footnote-definition (footnote-reference info) | |
3575 | "Return definition of FOOTNOTE-REFERENCE as parsed data. | |
3576 | INFO is the plist used as a communication channel. If no such | |
3577 | definition can be found, return the \"DEFINITION NOT FOUND\" | |
3578 | string." | |
3579 | (let ((label (org-element-property :label footnote-reference))) | |
3580 | (or (org-element-property :inline-definition footnote-reference) | |
3581 | (cdr (assoc label (plist-get info :footnote-definition-alist))) | |
3582 | "DEFINITION NOT FOUND."))) | |
3583 | ||
3584 | (defun org-export-get-footnote-number (footnote info) | |
3585 | "Return number associated to a footnote. | |
3586 | ||
3587 | FOOTNOTE is either a footnote reference or a footnote definition. | |
3588 | INFO is the plist used as a communication channel." | |
3589 | (let* ((label (org-element-property :label footnote)) | |
3590 | seen-refs | |
3591 | search-ref ; For byte-compiler. | |
3592 | (search-ref | |
3593 | (function | |
3594 | (lambda (data) | |
3595 | ;; Search footnote references through DATA, filling | |
3596 | ;; SEEN-REFS along the way. | |
3597 | (org-element-map data 'footnote-reference | |
3598 | (lambda (fn) | |
3599 | (let ((fn-lbl (org-element-property :label fn))) | |
3600 | (cond | |
3601 | ;; Anonymous footnote match: return number. | |
3602 | ((and (not fn-lbl) (eq fn footnote)) | |
3603 | (throw 'exit (1+ (length seen-refs)))) | |
3604 | ;; Labels match: return number. | |
3605 | ((and label (string= label fn-lbl)) | |
3606 | (throw 'exit (1+ (length seen-refs)))) | |
3607 | ;; Anonymous footnote: it's always a new one. | |
3608 | ;; Also, be sure to return nil from the `cond' so | |
3609 | ;; `first-match' doesn't get us out of the loop. | |
3610 | ((not fn-lbl) (push 'inline seen-refs) nil) | |
3611 | ;; Label not seen so far: add it so SEEN-REFS. | |
3612 | ;; | |
3613 | ;; Also search for subsequent references in | |
3614 | ;; footnote definition so numbering follows | |
3615 | ;; reading logic. Note that we don't have to care | |
3616 | ;; about inline definitions, since | |
3617 | ;; `org-element-map' already traverses them at the | |
3618 | ;; right time. | |
3619 | ;; | |
3620 | ;; Once again, return nil to stay in the loop. | |
3621 | ((not (member fn-lbl seen-refs)) | |
3622 | (push fn-lbl seen-refs) | |
3623 | (funcall search-ref | |
3624 | (org-export-get-footnote-definition fn info)) | |
3625 | nil)))) | |
3626 | ;; Don't enter footnote definitions since it will | |
3627 | ;; happen when their first reference is found. | |
3628 | info 'first-match 'footnote-definition))))) | |
3629 | (catch 'exit (funcall search-ref (plist-get info :parse-tree))))) | |
3630 | ||
3631 | ||
3632 | ;;;; For Headlines | |
3633 | ;; | |
3634 | ;; `org-export-get-relative-level' is a shortcut to get headline | |
3635 | ;; level, relatively to the lower headline level in the parsed tree. | |
3636 | ;; | |
3637 | ;; `org-export-get-headline-number' returns the section number of an | |
3638 | ;; headline, while `org-export-number-to-roman' allows to convert it | |
3639 | ;; to roman numbers. | |
3640 | ;; | |
3641 | ;; `org-export-low-level-p', `org-export-first-sibling-p' and | |
3642 | ;; `org-export-last-sibling-p' are three useful predicates when it | |
3643 | ;; comes to fulfill the `:headline-levels' property. | |
3644 | ;; | |
3645 | ;; `org-export-get-tags', `org-export-get-category' and | |
3646 | ;; `org-export-get-node-property' extract useful information from an | |
3647 | ;; headline or a parent headline. They all handle inheritance. | |
3648 | ;; | |
3649 | ;; `org-export-get-alt-title' tries to retrieve an alternative title, | |
3650 | ;; as a secondary string, suitable for table of contents. It falls | |
3651 | ;; back onto default title. | |
3652 | ||
3653 | (defun org-export-get-relative-level (headline info) | |
3654 | "Return HEADLINE relative level within current parsed tree. | |
3655 | INFO is a plist holding contextual information." | |
3656 | (+ (org-element-property :level headline) | |
3657 | (or (plist-get info :headline-offset) 0))) | |
3658 | ||
3659 | (defun org-export-low-level-p (headline info) | |
3660 | "Non-nil when HEADLINE is considered as low level. | |
3661 | ||
3662 | INFO is a plist used as a communication channel. | |
3663 | ||
3664 | A low level headlines has a relative level greater than | |
3665 | `:headline-levels' property value. | |
3666 | ||
3667 | Return value is the difference between HEADLINE relative level | |
3668 | and the last level being considered as high enough, or nil." | |
3669 | (let ((limit (plist-get info :headline-levels))) | |
3670 | (when (wholenump limit) | |
3671 | (let ((level (org-export-get-relative-level headline info))) | |
3672 | (and (> level limit) (- level limit)))))) | |
3673 | ||
3674 | (defun org-export-get-headline-number (headline info) | |
3675 | "Return HEADLINE numbering as a list of numbers. | |
3676 | INFO is a plist holding contextual information." | |
3677 | (cdr (assoc headline (plist-get info :headline-numbering)))) | |
3678 | ||
3679 | (defun org-export-numbered-headline-p (headline info) | |
3680 | "Return a non-nil value if HEADLINE element should be numbered. | |
3681 | INFO is a plist used as a communication channel." | |
3682 | (let ((sec-num (plist-get info :section-numbers)) | |
3683 | (level (org-export-get-relative-level headline info))) | |
3684 | (if (wholenump sec-num) (<= level sec-num) sec-num))) | |
3685 | ||
3686 | (defun org-export-number-to-roman (n) | |
3687 | "Convert integer N into a roman numeral." | |
3688 | (let ((roman '((1000 . "M") (900 . "CM") (500 . "D") (400 . "CD") | |
3689 | ( 100 . "C") ( 90 . "XC") ( 50 . "L") ( 40 . "XL") | |
3690 | ( 10 . "X") ( 9 . "IX") ( 5 . "V") ( 4 . "IV") | |
3691 | ( 1 . "I"))) | |
3692 | (res "")) | |
3693 | (if (<= n 0) | |
3694 | (number-to-string n) | |
3695 | (while roman | |
3696 | (if (>= n (caar roman)) | |
3697 | (setq n (- n (caar roman)) | |
3698 | res (concat res (cdar roman))) | |
3699 | (pop roman))) | |
3700 | res))) | |
3701 | ||
3702 | (defun org-export-get-tags (element info &optional tags inherited) | |
3703 | "Return list of tags associated to ELEMENT. | |
3704 | ||
3705 | ELEMENT has either an `headline' or an `inlinetask' type. INFO | |
3706 | is a plist used as a communication channel. | |
3707 | ||
3708 | Select tags (see `org-export-select-tags') and exclude tags (see | |
3709 | `org-export-exclude-tags') are removed from the list. | |
3710 | ||
3711 | When non-nil, optional argument TAGS should be a list of strings. | |
3712 | Any tag belonging to this list will also be removed. | |
3713 | ||
3714 | When optional argument INHERITED is non-nil, tags can also be | |
3715 | inherited from parent headlines and FILETAGS keywords." | |
3716 | (org-remove-if | |
3717 | (lambda (tag) (or (member tag (plist-get info :select-tags)) | |
3718 | (member tag (plist-get info :exclude-tags)) | |
3719 | (member tag tags))) | |
3720 | (if (not inherited) (org-element-property :tags element) | |
3721 | ;; Build complete list of inherited tags. | |
3722 | (let ((current-tag-list (org-element-property :tags element))) | |
3723 | (mapc | |
3724 | (lambda (parent) | |
3725 | (mapc | |
3726 | (lambda (tag) | |
3727 | (when (and (memq (org-element-type parent) '(headline inlinetask)) | |
3728 | (not (member tag current-tag-list))) | |
3729 | (push tag current-tag-list))) | |
3730 | (org-element-property :tags parent))) | |
3731 | (org-export-get-genealogy element)) | |
3732 | ;; Add FILETAGS keywords and return results. | |
3733 | (org-uniquify (append (plist-get info :filetags) current-tag-list)))))) | |
3734 | ||
3735 | (defun org-export-get-node-property (property blob &optional inherited) | |
3736 | "Return node PROPERTY value for BLOB. | |
3737 | ||
3738 | PROPERTY is an upcase symbol (i.e. `:COOKIE_DATA'). BLOB is an | |
3739 | element or object. | |
3740 | ||
3741 | If optional argument INHERITED is non-nil, the value can be | |
3742 | inherited from a parent headline. | |
3743 | ||
3744 | Return value is a string or nil." | |
3745 | (let ((headline (if (eq (org-element-type blob) 'headline) blob | |
3746 | (org-export-get-parent-headline blob)))) | |
3747 | (if (not inherited) (org-element-property property blob) | |
3748 | (let ((parent headline) value) | |
3749 | (catch 'found | |
3750 | (while parent | |
3751 | (when (plist-member (nth 1 parent) property) | |
3752 | (throw 'found (org-element-property property parent))) | |
3753 | (setq parent (org-element-property :parent parent)))))))) | |
3754 | ||
3755 | (defun org-export-get-category (blob info) | |
3756 | "Return category for element or object BLOB. | |
3757 | ||
3758 | INFO is a plist used as a communication channel. | |
3759 | ||
3760 | CATEGORY is automatically inherited from a parent headline, from | |
3761 | #+CATEGORY: keyword or created out of original file name. If all | |
3762 | fail, the fall-back value is \"???\"." | |
3763 | (or (let ((headline (if (eq (org-element-type blob) 'headline) blob | |
3764 | (org-export-get-parent-headline blob)))) | |
3765 | ;; Almost like `org-export-node-property', but we cannot trust | |
3766 | ;; `plist-member' as every headline has a `:CATEGORY' | |
3767 | ;; property, would it be nil or equal to "???" (which has the | |
3768 | ;; same meaning). | |
3769 | (let ((parent headline) value) | |
3770 | (catch 'found | |
3771 | (while parent | |
3772 | (let ((category (org-element-property :CATEGORY parent))) | |
3773 | (and category (not (equal "???" category)) | |
3774 | (throw 'found category))) | |
3775 | (setq parent (org-element-property :parent parent)))))) | |
3776 | (org-element-map (plist-get info :parse-tree) 'keyword | |
3777 | (lambda (kwd) | |
3778 | (when (equal (org-element-property :key kwd) "CATEGORY") | |
3779 | (org-element-property :value kwd))) | |
3780 | info 'first-match) | |
3781 | (let ((file (plist-get info :input-file))) | |
3782 | (and file (file-name-sans-extension (file-name-nondirectory file)))) | |
3783 | "???")) | |
3784 | ||
3785 | (defun org-export-get-alt-title (headline info) | |
3786 | "Return alternative title for HEADLINE, as a secondary string. | |
3787 | INFO is a plist used as a communication channel. If no optional | |
3788 | title is defined, fall-back to the regular title." | |
3789 | (or (org-element-property :alt-title headline) | |
3790 | (org-element-property :title headline))) | |
3791 | ||
3792 | (defun org-export-first-sibling-p (headline info) | |
3793 | "Non-nil when HEADLINE is the first sibling in its sub-tree. | |
3794 | INFO is a plist used as a communication channel." | |
3795 | (not (eq (org-element-type (org-export-get-previous-element headline info)) | |
3796 | 'headline))) | |
3797 | ||
3798 | (defun org-export-last-sibling-p (headline info) | |
3799 | "Non-nil when HEADLINE is the last sibling in its sub-tree. | |
3800 | INFO is a plist used as a communication channel." | |
3801 | (not (org-export-get-next-element headline info))) | |
3802 | ||
3803 | ||
3804 | ;;;; For Keywords | |
3805 | ;; | |
3806 | ;; `org-export-get-date' returns a date appropriate for the document | |
3807 | ;; to about to be exported. In particular, it takes care of | |
3808 | ;; `org-export-date-timestamp-format'. | |
3809 | ||
3810 | (defun org-export-get-date (info &optional fmt) | |
3811 | "Return date value for the current document. | |
3812 | ||
3813 | INFO is a plist used as a communication channel. FMT, when | |
3814 | non-nil, is a time format string that will be applied on the date | |
3815 | if it consists in a single timestamp object. It defaults to | |
3816 | `org-export-date-timestamp-format' when nil. | |
3817 | ||
3818 | A proper date can be a secondary string, a string or nil. It is | |
3819 | meant to be translated with `org-export-data' or alike." | |
3820 | (let ((date (plist-get info :date)) | |
3821 | (fmt (or fmt org-export-date-timestamp-format))) | |
3822 | (cond ((not date) nil) | |
3823 | ((and fmt | |
3824 | (not (cdr date)) | |
3825 | (eq (org-element-type (car date)) 'timestamp)) | |
3826 | (org-timestamp-format (car date) fmt)) | |
3827 | (t date)))) | |
3828 | ||
3829 | ||
3830 | ;;;; For Links | |
3831 | ;; | |
3832 | ;; `org-export-solidify-link-text' turns a string into a safer version | |
3833 | ;; for links, replacing most non-standard characters with hyphens. | |
3834 | ;; | |
3835 | ;; `org-export-get-coderef-format' returns an appropriate format | |
3836 | ;; string for coderefs. | |
3837 | ;; | |
3838 | ;; `org-export-inline-image-p' returns a non-nil value when the link | |
3839 | ;; provided should be considered as an inline image. | |
3840 | ;; | |
3841 | ;; `org-export-resolve-fuzzy-link' searches destination of fuzzy links | |
3842 | ;; (i.e. links with "fuzzy" as type) within the parsed tree, and | |
3843 | ;; returns an appropriate unique identifier when found, or nil. | |
3844 | ;; | |
3845 | ;; `org-export-resolve-id-link' returns the first headline with | |
3846 | ;; specified id or custom-id in parse tree, the path to the external | |
3847 | ;; file with the id or nil when neither was found. | |
3848 | ;; | |
3849 | ;; `org-export-resolve-coderef' associates a reference to a line | |
3850 | ;; number in the element it belongs, or returns the reference itself | |
3851 | ;; when the element isn't numbered. | |
3852 | ||
3853 | (defun org-export-solidify-link-text (s) | |
3854 | "Take link text S and make a safe target out of it." | |
3855 | (save-match-data | |
3856 | (mapconcat 'identity (org-split-string s "[^a-zA-Z0-9_.-:]+") "-"))) | |
3857 | ||
3858 | (defun org-export-get-coderef-format (path desc) | |
3859 | "Return format string for code reference link. | |
3860 | PATH is the link path. DESC is its description." | |
3861 | (save-match-data | |
3862 | (cond ((not desc) "%s") | |
3863 | ((string-match (regexp-quote (concat "(" path ")")) desc) | |
3864 | (replace-match "%s" t t desc)) | |
3865 | (t desc)))) | |
3866 | ||
3867 | (defun org-export-inline-image-p (link &optional rules) | |
3868 | "Non-nil if LINK object points to an inline image. | |
3869 | ||
3870 | Optional argument is a set of RULES defining inline images. It | |
3871 | is an alist where associations have the following shape: | |
3872 | ||
3873 | \(TYPE . REGEXP) | |
3874 | ||
3875 | Applying a rule means apply REGEXP against LINK's path when its | |
3876 | type is TYPE. The function will return a non-nil value if any of | |
3877 | the provided rules is non-nil. The default rule is | |
3878 | `org-export-default-inline-image-rule'. | |
3879 | ||
3880 | This only applies to links without a description." | |
3881 | (and (not (org-element-contents link)) | |
3882 | (let ((case-fold-search t) | |
3883 | (rules (or rules org-export-default-inline-image-rule))) | |
3884 | (catch 'exit | |
3885 | (mapc | |
3886 | (lambda (rule) | |
3887 | (and (string= (org-element-property :type link) (car rule)) | |
3888 | (string-match (cdr rule) | |
3889 | (org-element-property :path link)) | |
3890 | (throw 'exit t))) | |
3891 | rules) | |
3892 | ;; Return nil if no rule matched. | |
3893 | nil)))) | |
3894 | ||
3895 | (defun org-export-resolve-coderef (ref info) | |
3896 | "Resolve a code reference REF. | |
3897 | ||
3898 | INFO is a plist used as a communication channel. | |
3899 | ||
3900 | Return associated line number in source code, or REF itself, | |
3901 | depending on src-block or example element's switches." | |
3902 | (org-element-map (plist-get info :parse-tree) '(example-block src-block) | |
3903 | (lambda (el) | |
3904 | (with-temp-buffer | |
3905 | (insert (org-trim (org-element-property :value el))) | |
3906 | (let* ((label-fmt (regexp-quote | |
3907 | (or (org-element-property :label-fmt el) | |
3908 | org-coderef-label-format))) | |
3909 | (ref-re | |
3910 | (format "^.*?\\S-.*?\\([ \t]*\\(%s\\)\\)[ \t]*$" | |
3911 | (replace-regexp-in-string "%s" ref label-fmt nil t)))) | |
3912 | ;; Element containing REF is found. Resolve it to either | |
3913 | ;; a label or a line number, as needed. | |
3914 | (when (re-search-backward ref-re nil t) | |
3915 | (cond | |
3916 | ((org-element-property :use-labels el) ref) | |
3917 | ((eq (org-element-property :number-lines el) 'continued) | |
3918 | (+ (org-export-get-loc el info) (line-number-at-pos))) | |
3919 | (t (line-number-at-pos))))))) | |
3920 | info 'first-match)) | |
3921 | ||
3922 | (defun org-export-resolve-fuzzy-link (link info) | |
3923 | "Return LINK destination. | |
3924 | ||
3925 | INFO is a plist holding contextual information. | |
3926 | ||
3927 | Return value can be an object, an element, or nil: | |
3928 | ||
3929 | - If LINK path matches a target object (i.e. <<path>>) return it. | |
3930 | ||
3931 | - If LINK path exactly matches the name affiliated keyword | |
3932 | \(i.e. #+NAME: path) of an element, return that element. | |
3933 | ||
3934 | - If LINK path exactly matches any headline name, return that | |
3935 | element. If more than one headline share that name, priority | |
3936 | will be given to the one with the closest common ancestor, if | |
3937 | any, or the first one in the parse tree otherwise. | |
3938 | ||
3939 | - Otherwise, return nil. | |
3940 | ||
3941 | Assume LINK type is \"fuzzy\". White spaces are not | |
3942 | significant." | |
3943 | (let* ((raw-path (org-element-property :path link)) | |
3944 | (match-title-p (eq (aref raw-path 0) ?*)) | |
3945 | ;; Split PATH at white spaces so matches are space | |
3946 | ;; insensitive. | |
3947 | (path (org-split-string | |
3948 | (if match-title-p (substring raw-path 1) raw-path))) | |
3949 | ;; Cache for destinations that are not position dependent. | |
3950 | (link-cache | |
3951 | (or (plist-get info :resolve-fuzzy-link-cache) | |
3952 | (plist-get (setq info (plist-put info :resolve-fuzzy-link-cache | |
3953 | (make-hash-table :test 'equal))) | |
3954 | :resolve-fuzzy-link-cache))) | |
3955 | (cached (gethash path link-cache 'not-found))) | |
3956 | (cond | |
3957 | ;; Destination is not position dependent: use cached value. | |
3958 | ((and (not match-title-p) (not (eq cached 'not-found))) cached) | |
3959 | ;; First try to find a matching "<<path>>" unless user specified | |
3960 | ;; he was looking for a headline (path starts with a "*" | |
3961 | ;; character). | |
3962 | ((and (not match-title-p) | |
3963 | (let ((match (org-element-map (plist-get info :parse-tree) 'target | |
3964 | (lambda (blob) | |
3965 | (and (equal (org-split-string | |
3966 | (org-element-property :value blob)) | |
3967 | path) | |
3968 | blob)) | |
3969 | info 'first-match))) | |
3970 | (and match (puthash path match link-cache))))) | |
3971 | ;; Then try to find an element with a matching "#+NAME: path" | |
3972 | ;; affiliated keyword. | |
3973 | ((and (not match-title-p) | |
3974 | (let ((match (org-element-map (plist-get info :parse-tree) | |
3975 | org-element-all-elements | |
3976 | (lambda (el) | |
3977 | (let ((name (org-element-property :name el))) | |
3978 | (when (and name | |
3979 | (equal (org-split-string name) path)) | |
3980 | el))) | |
3981 | info 'first-match))) | |
3982 | (and match (puthash path match link-cache))))) | |
3983 | ;; Last case: link either points to a headline or to nothingness. | |
3984 | ;; Try to find the source, with priority given to headlines with | |
3985 | ;; the closest common ancestor. If such candidate is found, | |
3986 | ;; return it, otherwise return nil. | |
3987 | (t | |
3988 | (let ((find-headline | |
3989 | (function | |
3990 | ;; Return first headline whose `:raw-value' property is | |
3991 | ;; NAME in parse tree DATA, or nil. Statistics cookies | |
3992 | ;; are ignored. | |
3993 | (lambda (name data) | |
3994 | (org-element-map data 'headline | |
3995 | (lambda (headline) | |
3996 | (when (equal (org-split-string | |
3997 | (replace-regexp-in-string | |
3998 | "\\[[0-9]+%\\]\\|\\[[0-9]+/[0-9]+\\]" "" | |
3999 | (org-element-property :raw-value headline))) | |
4000 | name) | |
4001 | headline)) | |
4002 | info 'first-match))))) | |
4003 | ;; Search among headlines sharing an ancestor with link, from | |
4004 | ;; closest to farthest. | |
4005 | (catch 'exit | |
4006 | (mapc | |
4007 | (lambda (parent) | |
4008 | (let ((foundp (funcall find-headline path parent))) | |
4009 | (when foundp (throw 'exit foundp)))) | |
4010 | (let ((parent-hl (org-export-get-parent-headline link))) | |
4011 | (if (not parent-hl) (list (plist-get info :parse-tree)) | |
4012 | (cons parent-hl (org-export-get-genealogy parent-hl))))) | |
4013 | ;; No destination found: return nil. | |
4014 | (and (not match-title-p) (puthash path nil link-cache)))))))) | |
4015 | ||
4016 | (defun org-export-resolve-id-link (link info) | |
4017 | "Return headline referenced as LINK destination. | |
4018 | ||
4019 | INFO is a plist used as a communication channel. | |
4020 | ||
4021 | Return value can be the headline element matched in current parse | |
4022 | tree, a file name or nil. Assume LINK type is either \"id\" or | |
4023 | \"custom-id\"." | |
4024 | (let ((id (org-element-property :path link))) | |
4025 | ;; First check if id is within the current parse tree. | |
4026 | (or (org-element-map (plist-get info :parse-tree) 'headline | |
4027 | (lambda (headline) | |
4028 | (when (or (string= (org-element-property :ID headline) id) | |
4029 | (string= (org-element-property :CUSTOM_ID headline) id)) | |
4030 | headline)) | |
4031 | info 'first-match) | |
4032 | ;; Otherwise, look for external files. | |
4033 | (cdr (assoc id (plist-get info :id-alist)))))) | |
4034 | ||
4035 | (defun org-export-resolve-radio-link (link info) | |
4036 | "Return radio-target object referenced as LINK destination. | |
4037 | ||
4038 | INFO is a plist used as a communication channel. | |
4039 | ||
4040 | Return value can be a radio-target object or nil. Assume LINK | |
4041 | has type \"radio\"." | |
4042 | (let ((path (replace-regexp-in-string | |
4043 | "[ \r\t\n]+" " " (org-element-property :path link)))) | |
4044 | (org-element-map (plist-get info :parse-tree) 'radio-target | |
4045 | (lambda (radio) | |
4046 | (and (eq (compare-strings | |
4047 | (replace-regexp-in-string | |
4048 | "[ \r\t\n]+" " " (org-element-property :value radio)) | |
4049 | nil nil path nil nil t) | |
4050 | t) | |
4051 | radio)) | |
4052 | info 'first-match))) | |
4053 | ||
4054 | ||
4055 | ;;;; For References | |
4056 | ;; | |
4057 | ;; `org-export-get-ordinal' associates a sequence number to any object | |
4058 | ;; or element. | |
4059 | ||
4060 | (defun org-export-get-ordinal (element info &optional types predicate) | |
4061 | "Return ordinal number of an element or object. | |
4062 | ||
4063 | ELEMENT is the element or object considered. INFO is the plist | |
4064 | used as a communication channel. | |
4065 | ||
4066 | Optional argument TYPES, when non-nil, is a list of element or | |
4067 | object types, as symbols, that should also be counted in. | |
4068 | Otherwise, only provided element's type is considered. | |
4069 | ||
4070 | Optional argument PREDICATE is a function returning a non-nil | |
4071 | value if the current element or object should be counted in. It | |
4072 | accepts two arguments: the element or object being considered and | |
4073 | the plist used as a communication channel. This allows to count | |
4074 | only a certain type of objects (i.e. inline images). | |
4075 | ||
4076 | Return value is a list of numbers if ELEMENT is a headline or an | |
4077 | item. It is nil for keywords. It represents the footnote number | |
4078 | for footnote definitions and footnote references. If ELEMENT is | |
4079 | a target, return the same value as if ELEMENT was the closest | |
4080 | table, item or headline containing the target. In any other | |
4081 | case, return the sequence number of ELEMENT among elements or | |
4082 | objects of the same type." | |
4083 | ;; Ordinal of a target object refer to the ordinal of the closest | |
4084 | ;; table, item, or headline containing the object. | |
4085 | (when (eq (org-element-type element) 'target) | |
4086 | (setq element | |
4087 | (loop for parent in (org-export-get-genealogy element) | |
4088 | when | |
4089 | (memq | |
4090 | (org-element-type parent) | |
4091 | '(footnote-definition footnote-reference headline item | |
4092 | table)) | |
4093 | return parent))) | |
4094 | (case (org-element-type element) | |
4095 | ;; Special case 1: A headline returns its number as a list. | |
4096 | (headline (org-export-get-headline-number element info)) | |
4097 | ;; Special case 2: An item returns its number as a list. | |
4098 | (item (let ((struct (org-element-property :structure element))) | |
4099 | (org-list-get-item-number | |
4100 | (org-element-property :begin element) | |
4101 | struct | |
4102 | (org-list-prevs-alist struct) | |
4103 | (org-list-parents-alist struct)))) | |
4104 | ((footnote-definition footnote-reference) | |
4105 | (org-export-get-footnote-number element info)) | |
4106 | (otherwise | |
4107 | (let ((counter 0)) | |
4108 | ;; Increment counter until ELEMENT is found again. | |
4109 | (org-element-map (plist-get info :parse-tree) | |
4110 | (or types (org-element-type element)) | |
4111 | (lambda (el) | |
4112 | (cond | |
4113 | ((eq element el) (1+ counter)) | |
4114 | ((not predicate) (incf counter) nil) | |
4115 | ((funcall predicate el info) (incf counter) nil))) | |
4116 | info 'first-match))))) | |
4117 | ||
4118 | ||
4119 | ;;;; For Src-Blocks | |
4120 | ;; | |
4121 | ;; `org-export-get-loc' counts number of code lines accumulated in | |
4122 | ;; src-block or example-block elements with a "+n" switch until | |
4123 | ;; a given element, excluded. Note: "-n" switches reset that count. | |
4124 | ;; | |
4125 | ;; `org-export-unravel-code' extracts source code (along with a code | |
4126 | ;; references alist) from an `element-block' or `src-block' type | |
4127 | ;; element. | |
4128 | ;; | |
4129 | ;; `org-export-format-code' applies a formatting function to each line | |
4130 | ;; of code, providing relative line number and code reference when | |
4131 | ;; appropriate. Since it doesn't access the original element from | |
4132 | ;; which the source code is coming, it expects from the code calling | |
4133 | ;; it to know if lines should be numbered and if code references | |
4134 | ;; should appear. | |
4135 | ;; | |
4136 | ;; Eventually, `org-export-format-code-default' is a higher-level | |
4137 | ;; function (it makes use of the two previous functions) which handles | |
4138 | ;; line numbering and code references inclusion, and returns source | |
4139 | ;; code in a format suitable for plain text or verbatim output. | |
4140 | ||
4141 | (defun org-export-get-loc (element info) | |
4142 | "Return accumulated lines of code up to ELEMENT. | |
4143 | ||
4144 | INFO is the plist used as a communication channel. | |
4145 | ||
4146 | ELEMENT is excluded from count." | |
4147 | (let ((loc 0)) | |
4148 | (org-element-map (plist-get info :parse-tree) | |
4149 | `(src-block example-block ,(org-element-type element)) | |
4150 | (lambda (el) | |
4151 | (cond | |
4152 | ;; ELEMENT is reached: Quit the loop. | |
4153 | ((eq el element)) | |
4154 | ;; Only count lines from src-block and example-block elements | |
4155 | ;; with a "+n" or "-n" switch. A "-n" switch resets counter. | |
4156 | ((not (memq (org-element-type el) '(src-block example-block))) nil) | |
4157 | ((let ((linums (org-element-property :number-lines el))) | |
4158 | (when linums | |
4159 | ;; Accumulate locs or reset them. | |
4160 | (let ((lines (org-count-lines | |
4161 | (org-trim (org-element-property :value el))))) | |
4162 | (setq loc (if (eq linums 'new) lines (+ loc lines)))))) | |
4163 | ;; Return nil to stay in the loop. | |
4164 | nil))) | |
4165 | info 'first-match) | |
4166 | ;; Return value. | |
4167 | loc)) | |
4168 | ||
4169 | (defun org-export-unravel-code (element) | |
4170 | "Clean source code and extract references out of it. | |
4171 | ||
4172 | ELEMENT has either a `src-block' an `example-block' type. | |
4173 | ||
4174 | Return a cons cell whose CAR is the source code, cleaned from any | |
4175 | reference and protective comma and CDR is an alist between | |
4176 | relative line number (integer) and name of code reference on that | |
4177 | line (string)." | |
4178 | (let* ((line 0) refs | |
4179 | ;; Get code and clean it. Remove blank lines at its | |
4180 | ;; beginning and end. | |
4181 | (code (replace-regexp-in-string | |
4182 | "\\`\\([ \t]*\n\\)+" "" | |
4183 | (replace-regexp-in-string | |
4184 | "\\([ \t]*\n\\)*[ \t]*\\'" "\n" | |
4185 | (org-element-property :value element)))) | |
4186 | ;; Get format used for references. | |
4187 | (label-fmt (regexp-quote | |
4188 | (or (org-element-property :label-fmt element) | |
4189 | org-coderef-label-format))) | |
4190 | ;; Build a regexp matching a loc with a reference. | |
4191 | (with-ref-re | |
4192 | (format "^.*?\\S-.*?\\([ \t]*\\(%s\\)[ \t]*\\)$" | |
4193 | (replace-regexp-in-string | |
4194 | "%s" "\\([-a-zA-Z0-9_ ]+\\)" label-fmt nil t)))) | |
4195 | ;; Return value. | |
4196 | (cons | |
4197 | ;; Code with references removed. | |
4198 | (org-element-normalize-string | |
4199 | (mapconcat | |
4200 | (lambda (loc) | |
4201 | (incf line) | |
4202 | (if (not (string-match with-ref-re loc)) loc | |
4203 | ;; Ref line: remove ref, and signal its position in REFS. | |
4204 | (push (cons line (match-string 3 loc)) refs) | |
4205 | (replace-match "" nil nil loc 1))) | |
4206 | (org-split-string code "\n") "\n")) | |
4207 | ;; Reference alist. | |
4208 | refs))) | |
4209 | ||
4210 | (defun org-export-format-code (code fun &optional num-lines ref-alist) | |
4211 | "Format CODE by applying FUN line-wise and return it. | |
4212 | ||
4213 | CODE is a string representing the code to format. FUN is | |
4214 | a function. It must accept three arguments: a line of | |
4215 | code (string), the current line number (integer) or nil and the | |
4216 | reference associated to the current line (string) or nil. | |
4217 | ||
4218 | Optional argument NUM-LINES can be an integer representing the | |
4219 | number of code lines accumulated until the current code. Line | |
4220 | numbers passed to FUN will take it into account. If it is nil, | |
4221 | FUN's second argument will always be nil. This number can be | |
4222 | obtained with `org-export-get-loc' function. | |
4223 | ||
4224 | Optional argument REF-ALIST can be an alist between relative line | |
4225 | number (i.e. ignoring NUM-LINES) and the name of the code | |
4226 | reference on it. If it is nil, FUN's third argument will always | |
4227 | be nil. It can be obtained through the use of | |
4228 | `org-export-unravel-code' function." | |
4229 | (let ((--locs (org-split-string code "\n")) | |
4230 | (--line 0)) | |
4231 | (org-element-normalize-string | |
4232 | (mapconcat | |
4233 | (lambda (--loc) | |
4234 | (incf --line) | |
4235 | (let ((--ref (cdr (assq --line ref-alist)))) | |
4236 | (funcall fun --loc (and num-lines (+ num-lines --line)) --ref))) | |
4237 | --locs "\n")))) | |
4238 | ||
4239 | (defun org-export-format-code-default (element info) | |
4240 | "Return source code from ELEMENT, formatted in a standard way. | |
4241 | ||
4242 | ELEMENT is either a `src-block' or `example-block' element. INFO | |
4243 | is a plist used as a communication channel. | |
4244 | ||
4245 | This function takes care of line numbering and code references | |
4246 | inclusion. Line numbers, when applicable, appear at the | |
4247 | beginning of the line, separated from the code by two white | |
4248 | spaces. Code references, on the other hand, appear flushed to | |
4249 | the right, separated by six white spaces from the widest line of | |
4250 | code." | |
4251 | ;; Extract code and references. | |
4252 | (let* ((code-info (org-export-unravel-code element)) | |
4253 | (code (car code-info)) | |
4254 | (code-lines (org-split-string code "\n"))) | |
4255 | (if (null code-lines) "" | |
4256 | (let* ((refs (and (org-element-property :retain-labels element) | |
4257 | (cdr code-info))) | |
4258 | ;; Handle line numbering. | |
4259 | (num-start (case (org-element-property :number-lines element) | |
4260 | (continued (org-export-get-loc element info)) | |
4261 | (new 0))) | |
4262 | (num-fmt | |
4263 | (and num-start | |
4264 | (format "%%%ds " | |
4265 | (length (number-to-string | |
4266 | (+ (length code-lines) num-start)))))) | |
4267 | ;; Prepare references display, if required. Any reference | |
4268 | ;; should start six columns after the widest line of code, | |
4269 | ;; wrapped with parenthesis. | |
4270 | (max-width | |
4271 | (+ (apply 'max (mapcar 'length code-lines)) | |
4272 | (if (not num-start) 0 (length (format num-fmt num-start)))))) | |
4273 | (org-export-format-code | |
4274 | code | |
4275 | (lambda (loc line-num ref) | |
4276 | (let ((number-str (and num-fmt (format num-fmt line-num)))) | |
4277 | (concat | |
4278 | number-str | |
4279 | loc | |
4280 | (and ref | |
4281 | (concat (make-string | |
4282 | (- (+ 6 max-width) | |
4283 | (+ (length loc) (length number-str))) ? ) | |
4284 | (format "(%s)" ref)))))) | |
4285 | num-start refs))))) | |
4286 | ||
4287 | ||
4288 | ;;;; For Tables | |
4289 | ;; | |
4290 | ;; `org-export-table-has-special-column-p' and and | |
4291 | ;; `org-export-table-row-is-special-p' are predicates used to look for | |
4292 | ;; meta-information about the table structure. | |
4293 | ;; | |
4294 | ;; `org-table-has-header-p' tells when the rows before the first rule | |
4295 | ;; should be considered as table's header. | |
4296 | ;; | |
4297 | ;; `org-export-table-cell-width', `org-export-table-cell-alignment' | |
4298 | ;; and `org-export-table-cell-borders' extract information from | |
4299 | ;; a table-cell element. | |
4300 | ;; | |
4301 | ;; `org-export-table-dimensions' gives the number on rows and columns | |
4302 | ;; in the table, ignoring horizontal rules and special columns. | |
4303 | ;; `org-export-table-cell-address', given a table-cell object, returns | |
4304 | ;; the absolute address of a cell. On the other hand, | |
4305 | ;; `org-export-get-table-cell-at' does the contrary. | |
4306 | ;; | |
4307 | ;; `org-export-table-cell-starts-colgroup-p', | |
4308 | ;; `org-export-table-cell-ends-colgroup-p', | |
4309 | ;; `org-export-table-row-starts-rowgroup-p', | |
4310 | ;; `org-export-table-row-ends-rowgroup-p', | |
4311 | ;; `org-export-table-row-starts-header-p' and | |
4312 | ;; `org-export-table-row-ends-header-p' indicate position of current | |
4313 | ;; row or cell within the table. | |
4314 | ||
4315 | (defun org-export-table-has-special-column-p (table) | |
4316 | "Non-nil when TABLE has a special column. | |
4317 | All special columns will be ignored during export." | |
4318 | ;; The table has a special column when every first cell of every row | |
4319 | ;; has an empty value or contains a symbol among "/", "#", "!", "$", | |
4320 | ;; "*" "_" and "^". Though, do not consider a first row containing | |
4321 | ;; only empty cells as special. | |
4322 | (let ((special-column-p 'empty)) | |
4323 | (catch 'exit | |
4324 | (mapc | |
4325 | (lambda (row) | |
4326 | (when (eq (org-element-property :type row) 'standard) | |
4327 | (let ((value (org-element-contents | |
4328 | (car (org-element-contents row))))) | |
4329 | (cond ((member value '(("/") ("#") ("!") ("$") ("*") ("_") ("^"))) | |
4330 | (setq special-column-p 'special)) | |
4331 | ((not value)) | |
4332 | (t (throw 'exit nil)))))) | |
4333 | (org-element-contents table)) | |
4334 | (eq special-column-p 'special)))) | |
4335 | ||
4336 | (defun org-export-table-has-header-p (table info) | |
4337 | "Non-nil when TABLE has a header. | |
4338 | ||
4339 | INFO is a plist used as a communication channel. | |
4340 | ||
4341 | A table has a header when it contains at least two row groups." | |
4342 | (let ((cache (or (plist-get info :table-header-cache) | |
4343 | (plist-get (setq info | |
4344 | (plist-put info :table-header-cache | |
4345 | (make-hash-table :test 'eq))) | |
4346 | :table-header-cache)))) | |
4347 | (or (gethash table cache) | |
4348 | (let ((rowgroup 1) row-flag) | |
4349 | (puthash | |
4350 | table | |
4351 | (org-element-map table 'table-row | |
4352 | (lambda (row) | |
4353 | (cond | |
4354 | ((> rowgroup 1) t) | |
4355 | ((and row-flag (eq (org-element-property :type row) 'rule)) | |
4356 | (incf rowgroup) (setq row-flag nil)) | |
4357 | ((and (not row-flag) (eq (org-element-property :type row) | |
4358 | 'standard)) | |
4359 | (setq row-flag t) nil))) | |
4360 | info 'first-match) | |
4361 | cache))))) | |
4362 | ||
4363 | (defun org-export-table-row-is-special-p (table-row info) | |
4364 | "Non-nil if TABLE-ROW is considered special. | |
4365 | ||
4366 | INFO is a plist used as the communication channel. | |
4367 | ||
4368 | All special rows will be ignored during export." | |
4369 | (when (eq (org-element-property :type table-row) 'standard) | |
4370 | (let ((first-cell (org-element-contents | |
4371 | (car (org-element-contents table-row))))) | |
4372 | ;; A row is special either when... | |
4373 | (or | |
4374 | ;; ... it starts with a field only containing "/", | |
4375 | (equal first-cell '("/")) | |
4376 | ;; ... the table contains a special column and the row start | |
4377 | ;; with a marking character among, "^", "_", "$" or "!", | |
4378 | (and (org-export-table-has-special-column-p | |
4379 | (org-export-get-parent table-row)) | |
4380 | (member first-cell '(("^") ("_") ("$") ("!")))) | |
4381 | ;; ... it contains only alignment cookies and empty cells. | |
4382 | (let ((special-row-p 'empty)) | |
4383 | (catch 'exit | |
4384 | (mapc | |
4385 | (lambda (cell) | |
4386 | (let ((value (org-element-contents cell))) | |
4387 | ;; Since VALUE is a secondary string, the following | |
4388 | ;; checks avoid expanding it with `org-export-data'. | |
4389 | (cond ((not value)) | |
4390 | ((and (not (cdr value)) | |
4391 | (stringp (car value)) | |
4392 | (string-match "\\`<[lrc]?\\([0-9]+\\)?>\\'" | |
4393 | (car value))) | |
4394 | (setq special-row-p 'cookie)) | |
4395 | (t (throw 'exit nil))))) | |
4396 | (org-element-contents table-row)) | |
4397 | (eq special-row-p 'cookie))))))) | |
4398 | ||
4399 | (defun org-export-table-row-group (table-row info) | |
4400 | "Return TABLE-ROW's group number, as an integer. | |
4401 | ||
4402 | INFO is a plist used as the communication channel. | |
4403 | ||
4404 | Return value is the group number, as an integer, or nil for | |
4405 | special rows and rows separators. First group is also table's | |
4406 | header." | |
4407 | (let ((cache (or (plist-get info :table-row-group-cache) | |
4408 | (plist-get (setq info | |
4409 | (plist-put info :table-row-group-cache | |
4410 | (make-hash-table :test 'eq))) | |
4411 | :table-row-group-cache)))) | |
4412 | (cond ((gethash table-row cache)) | |
4413 | ((eq (org-element-property :type table-row) 'rule) nil) | |
4414 | (t (let ((group 0) row-flag) | |
4415 | (org-element-map (org-export-get-parent table-row) 'table-row | |
4416 | (lambda (row) | |
4417 | (if (eq (org-element-property :type row) 'rule) | |
4418 | (setq row-flag nil) | |
4419 | (unless row-flag (incf group) (setq row-flag t))) | |
4420 | (when (eq table-row row) (puthash table-row group cache))) | |
4421 | info 'first-match)))))) | |
4422 | ||
4423 | (defun org-export-table-cell-width (table-cell info) | |
4424 | "Return TABLE-CELL contents width. | |
4425 | ||
4426 | INFO is a plist used as the communication channel. | |
4427 | ||
4428 | Return value is the width given by the last width cookie in the | |
4429 | same column as TABLE-CELL, or nil." | |
4430 | (let* ((row (org-export-get-parent table-cell)) | |
4431 | (table (org-export-get-parent row)) | |
4432 | (cells (org-element-contents row)) | |
4433 | (columns (length cells)) | |
4434 | (column (- columns (length (memq table-cell cells)))) | |
4435 | (cache (or (plist-get info :table-cell-width-cache) | |
4436 | (plist-get (setq info | |
4437 | (plist-put info :table-cell-width-cache | |
4438 | (make-hash-table :test 'eq))) | |
4439 | :table-cell-width-cache))) | |
4440 | (width-vector (or (gethash table cache) | |
4441 | (puthash table (make-vector columns 'empty) cache))) | |
4442 | (value (aref width-vector column))) | |
4443 | (if (not (eq value 'empty)) value | |
4444 | (let (cookie-width) | |
4445 | (dolist (row (org-element-contents table) | |
4446 | (aset width-vector column cookie-width)) | |
4447 | (when (org-export-table-row-is-special-p row info) | |
4448 | ;; In a special row, try to find a width cookie at COLUMN. | |
4449 | (let* ((value (org-element-contents | |
4450 | (elt (org-element-contents row) column))) | |
4451 | (cookie (car value))) | |
4452 | ;; The following checks avoid expanding unnecessarily | |
4453 | ;; the cell with `org-export-data'. | |
4454 | (when (and value | |
4455 | (not (cdr value)) | |
4456 | (stringp cookie) | |
4457 | (string-match "\\`<[lrc]?\\([0-9]+\\)?>\\'" cookie) | |
4458 | (match-string 1 cookie)) | |
4459 | (setq cookie-width | |
4460 | (string-to-number (match-string 1 cookie))))))))))) | |
4461 | ||
4462 | (defun org-export-table-cell-alignment (table-cell info) | |
4463 | "Return TABLE-CELL contents alignment. | |
4464 | ||
4465 | INFO is a plist used as the communication channel. | |
4466 | ||
4467 | Return alignment as specified by the last alignment cookie in the | |
4468 | same column as TABLE-CELL. If no such cookie is found, a default | |
4469 | alignment value will be deduced from fraction of numbers in the | |
4470 | column (see `org-table-number-fraction' for more information). | |
4471 | Possible values are `left', `right' and `center'." | |
4472 | ;; Load `org-table-number-fraction' and `org-table-number-regexp'. | |
4473 | (require 'org-table) | |
4474 | (let* ((row (org-export-get-parent table-cell)) | |
4475 | (table (org-export-get-parent row)) | |
4476 | (cells (org-element-contents row)) | |
4477 | (columns (length cells)) | |
4478 | (column (- columns (length (memq table-cell cells)))) | |
4479 | (cache (or (plist-get info :table-cell-alignment-cache) | |
4480 | (plist-get (setq info | |
4481 | (plist-put info :table-cell-alignment-cache | |
4482 | (make-hash-table :test 'eq))) | |
4483 | :table-cell-alignment-cache))) | |
4484 | (align-vector (or (gethash table cache) | |
4485 | (puthash table (make-vector columns nil) cache)))) | |
4486 | (or (aref align-vector column) | |
4487 | (let ((number-cells 0) | |
4488 | (total-cells 0) | |
4489 | cookie-align | |
4490 | previous-cell-number-p) | |
4491 | (dolist (row (org-element-contents (org-export-get-parent row))) | |
4492 | (cond | |
4493 | ;; In a special row, try to find an alignment cookie at | |
4494 | ;; COLUMN. | |
4495 | ((org-export-table-row-is-special-p row info) | |
4496 | (let ((value (org-element-contents | |
4497 | (elt (org-element-contents row) column)))) | |
4498 | ;; Since VALUE is a secondary string, the following | |
4499 | ;; checks avoid useless expansion through | |
4500 | ;; `org-export-data'. | |
4501 | (when (and value | |
4502 | (not (cdr value)) | |
4503 | (stringp (car value)) | |
4504 | (string-match "\\`<\\([lrc]\\)?\\([0-9]+\\)?>\\'" | |
4505 | (car value)) | |
4506 | (match-string 1 (car value))) | |
4507 | (setq cookie-align (match-string 1 (car value)))))) | |
4508 | ;; Ignore table rules. | |
4509 | ((eq (org-element-property :type row) 'rule)) | |
4510 | ;; In a standard row, check if cell's contents are | |
4511 | ;; expressing some kind of number. Increase NUMBER-CELLS | |
4512 | ;; accordingly. Though, don't bother if an alignment | |
4513 | ;; cookie has already defined cell's alignment. | |
4514 | ((not cookie-align) | |
4515 | (let ((value (org-export-data | |
4516 | (org-element-contents | |
4517 | (elt (org-element-contents row) column)) | |
4518 | info))) | |
4519 | (incf total-cells) | |
4520 | ;; Treat an empty cell as a number if it follows | |
4521 | ;; a number. | |
4522 | (if (not (or (string-match org-table-number-regexp value) | |
4523 | (and (string= value "") previous-cell-number-p))) | |
4524 | (setq previous-cell-number-p nil) | |
4525 | (setq previous-cell-number-p t) | |
4526 | (incf number-cells)))))) | |
4527 | ;; Return value. Alignment specified by cookies has | |
4528 | ;; precedence over alignment deduced from cell's contents. | |
4529 | (aset align-vector | |
4530 | column | |
4531 | (cond ((equal cookie-align "l") 'left) | |
4532 | ((equal cookie-align "r") 'right) | |
4533 | ((equal cookie-align "c") 'center) | |
4534 | ((>= (/ (float number-cells) total-cells) | |
4535 | org-table-number-fraction) | |
4536 | 'right) | |
4537 | (t 'left))))))) | |
4538 | ||
4539 | (defun org-export-table-cell-borders (table-cell info) | |
4540 | "Return TABLE-CELL borders. | |
4541 | ||
4542 | INFO is a plist used as a communication channel. | |
4543 | ||
4544 | Return value is a list of symbols, or nil. Possible values are: | |
4545 | `top', `bottom', `above', `below', `left' and `right'. Note: | |
4546 | `top' (resp. `bottom') only happen for a cell in the first | |
4547 | row (resp. last row) of the table, ignoring table rules, if any. | |
4548 | ||
4549 | Returned borders ignore special rows." | |
4550 | (let* ((row (org-export-get-parent table-cell)) | |
4551 | (table (org-export-get-parent-table table-cell)) | |
4552 | borders) | |
4553 | ;; Top/above border? TABLE-CELL has a border above when a rule | |
4554 | ;; used to demarcate row groups can be found above. Hence, | |
4555 | ;; finding a rule isn't sufficient to push `above' in BORDERS: | |
4556 | ;; another regular row has to be found above that rule. | |
4557 | (let (rule-flag) | |
4558 | (catch 'exit | |
4559 | (mapc (lambda (row) | |
4560 | (cond ((eq (org-element-property :type row) 'rule) | |
4561 | (setq rule-flag t)) | |
4562 | ((not (org-export-table-row-is-special-p row info)) | |
4563 | (if rule-flag (throw 'exit (push 'above borders)) | |
4564 | (throw 'exit nil))))) | |
4565 | ;; Look at every row before the current one. | |
4566 | (cdr (memq row (reverse (org-element-contents table))))) | |
4567 | ;; No rule above, or rule found starts the table (ignoring any | |
4568 | ;; special row): TABLE-CELL is at the top of the table. | |
4569 | (when rule-flag (push 'above borders)) | |
4570 | (push 'top borders))) | |
4571 | ;; Bottom/below border? TABLE-CELL has a border below when next | |
4572 | ;; non-regular row below is a rule. | |
4573 | (let (rule-flag) | |
4574 | (catch 'exit | |
4575 | (mapc (lambda (row) | |
4576 | (cond ((eq (org-element-property :type row) 'rule) | |
4577 | (setq rule-flag t)) | |
4578 | ((not (org-export-table-row-is-special-p row info)) | |
4579 | (if rule-flag (throw 'exit (push 'below borders)) | |
4580 | (throw 'exit nil))))) | |
4581 | ;; Look at every row after the current one. | |
4582 | (cdr (memq row (org-element-contents table)))) | |
4583 | ;; No rule below, or rule found ends the table (modulo some | |
4584 | ;; special row): TABLE-CELL is at the bottom of the table. | |
4585 | (when rule-flag (push 'below borders)) | |
4586 | (push 'bottom borders))) | |
4587 | ;; Right/left borders? They can only be specified by column | |
4588 | ;; groups. Column groups are defined in a row starting with "/". | |
4589 | ;; Also a column groups row only contains "<", "<>", ">" or blank | |
4590 | ;; cells. | |
4591 | (catch 'exit | |
4592 | (let ((column (let ((cells (org-element-contents row))) | |
4593 | (- (length cells) (length (memq table-cell cells)))))) | |
4594 | (mapc | |
4595 | (lambda (row) | |
4596 | (unless (eq (org-element-property :type row) 'rule) | |
4597 | (when (equal (org-element-contents | |
4598 | (car (org-element-contents row))) | |
4599 | '("/")) | |
4600 | (let ((column-groups | |
4601 | (mapcar | |
4602 | (lambda (cell) | |
4603 | (let ((value (org-element-contents cell))) | |
4604 | (when (member value '(("<") ("<>") (">") nil)) | |
4605 | (car value)))) | |
4606 | (org-element-contents row)))) | |
4607 | ;; There's a left border when previous cell, if | |
4608 | ;; any, ends a group, or current one starts one. | |
4609 | (when (or (and (not (zerop column)) | |
4610 | (member (elt column-groups (1- column)) | |
4611 | '(">" "<>"))) | |
4612 | (member (elt column-groups column) '("<" "<>"))) | |
4613 | (push 'left borders)) | |
4614 | ;; There's a right border when next cell, if any, | |
4615 | ;; starts a group, or current one ends one. | |
4616 | (when (or (and (/= (1+ column) (length column-groups)) | |
4617 | (member (elt column-groups (1+ column)) | |
4618 | '("<" "<>"))) | |
4619 | (member (elt column-groups column) '(">" "<>"))) | |
4620 | (push 'right borders)) | |
4621 | (throw 'exit nil))))) | |
4622 | ;; Table rows are read in reverse order so last column groups | |
4623 | ;; row has precedence over any previous one. | |
4624 | (reverse (org-element-contents table))))) | |
4625 | ;; Return value. | |
4626 | borders)) | |
4627 | ||
4628 | (defun org-export-table-cell-starts-colgroup-p (table-cell info) | |
4629 | "Non-nil when TABLE-CELL is at the beginning of a row group. | |
4630 | INFO is a plist used as a communication channel." | |
4631 | ;; A cell starts a column group either when it is at the beginning | |
4632 | ;; of a row (or after the special column, if any) or when it has | |
4633 | ;; a left border. | |
4634 | (or (eq (org-element-map (org-export-get-parent table-cell) 'table-cell | |
4635 | 'identity info 'first-match) | |
4636 | table-cell) | |
4637 | (memq 'left (org-export-table-cell-borders table-cell info)))) | |
4638 | ||
4639 | (defun org-export-table-cell-ends-colgroup-p (table-cell info) | |
4640 | "Non-nil when TABLE-CELL is at the end of a row group. | |
4641 | INFO is a plist used as a communication channel." | |
4642 | ;; A cell ends a column group either when it is at the end of a row | |
4643 | ;; or when it has a right border. | |
4644 | (or (eq (car (last (org-element-contents | |
4645 | (org-export-get-parent table-cell)))) | |
4646 | table-cell) | |
4647 | (memq 'right (org-export-table-cell-borders table-cell info)))) | |
4648 | ||
4649 | (defun org-export-table-row-starts-rowgroup-p (table-row info) | |
4650 | "Non-nil when TABLE-ROW is at the beginning of a column group. | |
4651 | INFO is a plist used as a communication channel." | |
4652 | (unless (or (eq (org-element-property :type table-row) 'rule) | |
4653 | (org-export-table-row-is-special-p table-row info)) | |
4654 | (let ((borders (org-export-table-cell-borders | |
4655 | (car (org-element-contents table-row)) info))) | |
4656 | (or (memq 'top borders) (memq 'above borders))))) | |
4657 | ||
4658 | (defun org-export-table-row-ends-rowgroup-p (table-row info) | |
4659 | "Non-nil when TABLE-ROW is at the end of a column group. | |
4660 | INFO is a plist used as a communication channel." | |
4661 | (unless (or (eq (org-element-property :type table-row) 'rule) | |
4662 | (org-export-table-row-is-special-p table-row info)) | |
4663 | (let ((borders (org-export-table-cell-borders | |
4664 | (car (org-element-contents table-row)) info))) | |
4665 | (or (memq 'bottom borders) (memq 'below borders))))) | |
4666 | ||
4667 | (defun org-export-table-row-starts-header-p (table-row info) | |
4668 | "Non-nil when TABLE-ROW is the first table header's row. | |
4669 | INFO is a plist used as a communication channel." | |
4670 | (and (org-export-table-has-header-p | |
4671 | (org-export-get-parent-table table-row) info) | |
4672 | (org-export-table-row-starts-rowgroup-p table-row info) | |
4673 | (= (org-export-table-row-group table-row info) 1))) | |
4674 | ||
4675 | (defun org-export-table-row-ends-header-p (table-row info) | |
4676 | "Non-nil when TABLE-ROW is the last table header's row. | |
4677 | INFO is a plist used as a communication channel." | |
4678 | (and (org-export-table-has-header-p | |
4679 | (org-export-get-parent-table table-row) info) | |
4680 | (org-export-table-row-ends-rowgroup-p table-row info) | |
4681 | (= (org-export-table-row-group table-row info) 1))) | |
4682 | ||
4683 | (defun org-export-table-row-number (table-row info) | |
4684 | "Return TABLE-ROW number. | |
4685 | INFO is a plist used as a communication channel. Return value is | |
4686 | zero-based and ignores separators. The function returns nil for | |
d1389828 | 4687 | special columns and separators." |
271672fa BG |
4688 | (when (and (eq (org-element-property :type table-row) 'standard) |
4689 | (not (org-export-table-row-is-special-p table-row info))) | |
4690 | (let ((number 0)) | |
4691 | (org-element-map (org-export-get-parent-table table-row) 'table-row | |
4692 | (lambda (row) | |
4693 | (cond ((eq row table-row) number) | |
4694 | ((eq (org-element-property :type row) 'standard) | |
4695 | (incf number) nil))) | |
4696 | info 'first-match)))) | |
4697 | ||
4698 | (defun org-export-table-dimensions (table info) | |
4699 | "Return TABLE dimensions. | |
4700 | ||
4701 | INFO is a plist used as a communication channel. | |
4702 | ||
4703 | Return value is a CONS like (ROWS . COLUMNS) where | |
4704 | ROWS (resp. COLUMNS) is the number of exportable | |
4705 | rows (resp. columns)." | |
4706 | (let (first-row (columns 0) (rows 0)) | |
4707 | ;; Set number of rows, and extract first one. | |
4708 | (org-element-map table 'table-row | |
4709 | (lambda (row) | |
4710 | (when (eq (org-element-property :type row) 'standard) | |
4711 | (incf rows) | |
4712 | (unless first-row (setq first-row row)))) info) | |
4713 | ;; Set number of columns. | |
4714 | (org-element-map first-row 'table-cell (lambda (cell) (incf columns)) info) | |
4715 | ;; Return value. | |
4716 | (cons rows columns))) | |
4717 | ||
4718 | (defun org-export-table-cell-address (table-cell info) | |
4719 | "Return address of a regular TABLE-CELL object. | |
4720 | ||
4721 | TABLE-CELL is the cell considered. INFO is a plist used as | |
4722 | a communication channel. | |
4723 | ||
4724 | Address is a CONS cell (ROW . COLUMN), where ROW and COLUMN are | |
4725 | zero-based index. Only exportable cells are considered. The | |
4726 | function returns nil for other cells." | |
4727 | (let* ((table-row (org-export-get-parent table-cell)) | |
4728 | (row-number (org-export-table-row-number table-row info))) | |
4729 | (when row-number | |
4730 | (cons row-number | |
4731 | (let ((col-count 0)) | |
4732 | (org-element-map table-row 'table-cell | |
4733 | (lambda (cell) | |
4734 | (if (eq cell table-cell) col-count (incf col-count) nil)) | |
4735 | info 'first-match)))))) | |
4736 | ||
4737 | (defun org-export-get-table-cell-at (address table info) | |
4738 | "Return regular table-cell object at ADDRESS in TABLE. | |
4739 | ||
4740 | Address is a CONS cell (ROW . COLUMN), where ROW and COLUMN are | |
4741 | zero-based index. TABLE is a table type element. INFO is | |
4742 | a plist used as a communication channel. | |
4743 | ||
4744 | If no table-cell, among exportable cells, is found at ADDRESS, | |
4745 | return nil." | |
4746 | (let ((column-pos (cdr address)) (column-count 0)) | |
4747 | (org-element-map | |
4748 | ;; Row at (car address) or nil. | |
4749 | (let ((row-pos (car address)) (row-count 0)) | |
4750 | (org-element-map table 'table-row | |
4751 | (lambda (row) | |
4752 | (cond ((eq (org-element-property :type row) 'rule) nil) | |
4753 | ((= row-count row-pos) row) | |
4754 | (t (incf row-count) nil))) | |
4755 | info 'first-match)) | |
4756 | 'table-cell | |
4757 | (lambda (cell) | |
4758 | (if (= column-count column-pos) cell | |
4759 | (incf column-count) nil)) | |
4760 | info 'first-match))) | |
4761 | ||
4762 | ||
4763 | ;;;; For Tables Of Contents | |
4764 | ;; | |
4765 | ;; `org-export-collect-headlines' builds a list of all exportable | |
4766 | ;; headline elements, maybe limited to a certain depth. One can then | |
4767 | ;; easily parse it and transcode it. | |
4768 | ;; | |
4769 | ;; Building lists of tables, figures or listings is quite similar. | |
4770 | ;; Once the generic function `org-export-collect-elements' is defined, | |
4771 | ;; `org-export-collect-tables', `org-export-collect-figures' and | |
4772 | ;; `org-export-collect-listings' can be derived from it. | |
4773 | ||
4774 | (defun org-export-collect-headlines (info &optional n) | |
4775 | "Collect headlines in order to build a table of contents. | |
4776 | ||
4777 | INFO is a plist used as a communication channel. | |
4778 | ||
4779 | When optional argument N is an integer, it specifies the depth of | |
4780 | the table of contents. Otherwise, it is set to the value of the | |
4781 | last headline level. See `org-export-headline-levels' for more | |
4782 | information. | |
4783 | ||
4784 | Return a list of all exportable headlines as parsed elements. | |
4785 | Footnote sections, if any, will be ignored." | |
4786 | (let ((limit (plist-get info :headline-levels))) | |
4787 | (setq n (if (wholenump n) (min n limit) limit)) | |
4788 | (org-element-map (plist-get info :parse-tree) 'headline | |
4789 | #'(lambda (headline) | |
4790 | (unless (org-element-property :footnote-section-p headline) | |
4791 | (let ((level (org-export-get-relative-level headline info))) | |
4792 | (and (<= level n) headline)))) | |
4793 | info))) | |
4794 | ||
4795 | (defun org-export-collect-elements (type info &optional predicate) | |
4796 | "Collect referenceable elements of a determined type. | |
4797 | ||
4798 | TYPE can be a symbol or a list of symbols specifying element | |
4799 | types to search. Only elements with a caption are collected. | |
4800 | ||
4801 | INFO is a plist used as a communication channel. | |
4802 | ||
4803 | When non-nil, optional argument PREDICATE is a function accepting | |
4804 | one argument, an element of type TYPE. It returns a non-nil | |
4805 | value when that element should be collected. | |
4806 | ||
4807 | Return a list of all elements found, in order of appearance." | |
4808 | (org-element-map (plist-get info :parse-tree) type | |
4809 | (lambda (element) | |
4810 | (and (org-element-property :caption element) | |
4811 | (or (not predicate) (funcall predicate element)) | |
4812 | element)) | |
4813 | info)) | |
4814 | ||
4815 | (defun org-export-collect-tables (info) | |
4816 | "Build a list of tables. | |
4817 | INFO is a plist used as a communication channel. | |
4818 | ||
4819 | Return a list of table elements with a caption." | |
4820 | (org-export-collect-elements 'table info)) | |
4821 | ||
4822 | (defun org-export-collect-figures (info predicate) | |
4823 | "Build a list of figures. | |
4824 | ||
4825 | INFO is a plist used as a communication channel. PREDICATE is | |
4826 | a function which accepts one argument: a paragraph element and | |
4827 | whose return value is non-nil when that element should be | |
4828 | collected. | |
4829 | ||
4830 | A figure is a paragraph type element, with a caption, verifying | |
4831 | PREDICATE. The latter has to be provided since a \"figure\" is | |
4832 | a vague concept that may depend on back-end. | |
4833 | ||
4834 | Return a list of elements recognized as figures." | |
4835 | (org-export-collect-elements 'paragraph info predicate)) | |
4836 | ||
4837 | (defun org-export-collect-listings (info) | |
4838 | "Build a list of src blocks. | |
4839 | ||
4840 | INFO is a plist used as a communication channel. | |
4841 | ||
4842 | Return a list of src-block elements with a caption." | |
4843 | (org-export-collect-elements 'src-block info)) | |
4844 | ||
4845 | ||
4846 | ;;;; Smart Quotes | |
4847 | ;; | |
4848 | ;; The main function for the smart quotes sub-system is | |
4849 | ;; `org-export-activate-smart-quotes', which replaces every quote in | |
4850 | ;; a given string from the parse tree with its "smart" counterpart. | |
4851 | ;; | |
4852 | ;; Dictionary for smart quotes is stored in | |
4853 | ;; `org-export-smart-quotes-alist'. | |
4854 | ;; | |
4855 | ;; Internally, regexps matching potential smart quotes (checks at | |
4856 | ;; string boundaries are also necessary) are defined in | |
4857 | ;; `org-export-smart-quotes-regexps'. | |
4858 | ||
4859 | (defconst org-export-smart-quotes-alist | |
4860 | '(("da" | |
4861 | ;; one may use: »...«, "...", ›...‹, or '...'. | |
4862 | ;; http://sproget.dk/raad-og-regler/retskrivningsregler/retskrivningsregler/a7-40-60/a7-58-anforselstegn/ | |
4863 | ;; LaTeX quotes require Babel! | |
4864 | (opening-double-quote :utf-8 "»" :html "»" :latex ">>" | |
4865 | :texinfo "@guillemetright{}") | |
4866 | (closing-double-quote :utf-8 "«" :html "«" :latex "<<" | |
4867 | :texinfo "@guillemetleft{}") | |
4868 | (opening-single-quote :utf-8 "›" :html "›" :latex "\\frq{}" | |
4869 | :texinfo "@guilsinglright{}") | |
4870 | (closing-single-quote :utf-8 "‹" :html "‹" :latex "\\flq{}" | |
4871 | :texinfo "@guilsingleft{}") | |
4872 | (apostrophe :utf-8 "’" :html "’")) | |
4873 | ("de" | |
4874 | (opening-double-quote :utf-8 "„" :html "„" :latex "\"`" | |
4875 | :texinfo "@quotedblbase{}") | |
4876 | (closing-double-quote :utf-8 "“" :html "“" :latex "\"'" | |
4877 | :texinfo "@quotedblleft{}") | |
4878 | (opening-single-quote :utf-8 "‚" :html "‚" :latex "\\glq{}" | |
4879 | :texinfo "@quotesinglbase{}") | |
4880 | (closing-single-quote :utf-8 "‘" :html "‘" :latex "\\grq{}" | |
4881 | :texinfo "@quoteleft{}") | |
4882 | (apostrophe :utf-8 "’" :html "’")) | |
4883 | ("en" | |
4884 | (opening-double-quote :utf-8 "“" :html "“" :latex "``" :texinfo "``") | |
4885 | (closing-double-quote :utf-8 "”" :html "”" :latex "''" :texinfo "''") | |
4886 | (opening-single-quote :utf-8 "‘" :html "‘" :latex "`" :texinfo "`") | |
4887 | (closing-single-quote :utf-8 "’" :html "’" :latex "'" :texinfo "'") | |
4888 | (apostrophe :utf-8 "’" :html "’")) | |
4889 | ("es" | |
4890 | (opening-double-quote :utf-8 "«" :html "«" :latex "\\guillemotleft{}" | |
4891 | :texinfo "@guillemetleft{}") | |
4892 | (closing-double-quote :utf-8 "»" :html "»" :latex "\\guillemotright{}" | |
4893 | :texinfo "@guillemetright{}") | |
4894 | (opening-single-quote :utf-8 "“" :html "“" :latex "``" :texinfo "``") | |
4895 | (closing-single-quote :utf-8 "”" :html "”" :latex "''" :texinfo "''") | |
4896 | (apostrophe :utf-8 "’" :html "’")) | |
4897 | ("fr" | |
4898 | (opening-double-quote :utf-8 "« " :html "« " :latex "\\og " | |
4899 | :texinfo "@guillemetleft{}@tie{}") | |
4900 | (closing-double-quote :utf-8 " »" :html " »" :latex "\\fg{}" | |
4901 | :texinfo "@tie{}@guillemetright{}") | |
4902 | (opening-single-quote :utf-8 "« " :html "« " :latex "\\og " | |
4903 | :texinfo "@guillemetleft{}@tie{}") | |
4904 | (closing-single-quote :utf-8 " »" :html " »" :latex "\\fg{}" | |
4905 | :texinfo "@tie{}@guillemetright{}") | |
4906 | (apostrophe :utf-8 "’" :html "’")) | |
4907 | ("no" | |
4908 | ;; https://nn.wikipedia.org/wiki/Sitatteikn | |
4909 | (opening-double-quote :utf-8 "«" :html "«" :latex "\\guillemotleft{}" | |
4910 | :texinfo "@guillemetleft{}") | |
4911 | (closing-double-quote :utf-8 "»" :html "»" :latex "\\guillemotright{}" | |
4912 | :texinfo "@guillemetright{}") | |
4913 | (opening-single-quote :utf-8 "‘" :html "‘" :latex "`" :texinfo "`") | |
4914 | (closing-single-quote :utf-8 "’" :html "’" :latex "'" :texinfo "'") | |
4915 | (apostrophe :utf-8 "’" :html "’")) | |
4916 | ("nb" | |
4917 | ;; https://nn.wikipedia.org/wiki/Sitatteikn | |
4918 | (opening-double-quote :utf-8 "«" :html "«" :latex "\\guillemotleft{}" | |
4919 | :texinfo "@guillemetleft{}") | |
4920 | (closing-double-quote :utf-8 "»" :html "»" :latex "\\guillemotright{}" | |
4921 | :texinfo "@guillemetright{}") | |
4922 | (opening-single-quote :utf-8 "‘" :html "‘" :latex "`" :texinfo "`") | |
4923 | (closing-single-quote :utf-8 "’" :html "’" :latex "'" :texinfo "'") | |
4924 | (apostrophe :utf-8 "’" :html "’")) | |
4925 | ("nn" | |
4926 | ;; https://nn.wikipedia.org/wiki/Sitatteikn | |
4927 | (opening-double-quote :utf-8 "«" :html "«" :latex "\\guillemotleft{}" | |
4928 | :texinfo "@guillemetleft{}") | |
4929 | (closing-double-quote :utf-8 "»" :html "»" :latex "\\guillemotright{}" | |
4930 | :texinfo "@guillemetright{}") | |
4931 | (opening-single-quote :utf-8 "‘" :html "‘" :latex "`" :texinfo "`") | |
4932 | (closing-single-quote :utf-8 "’" :html "’" :latex "'" :texinfo "'") | |
4933 | (apostrophe :utf-8 "’" :html "’")) | |
4934 | ("sv" | |
4935 | ;; based on https://sv.wikipedia.org/wiki/Citattecken | |
4936 | (opening-double-quote :utf-8 "”" :html "”" :latex "’’" :texinfo "’’") | |
4937 | (closing-double-quote :utf-8 "”" :html "”" :latex "’’" :texinfo "’’") | |
4938 | (opening-single-quote :utf-8 "’" :html "’" :latex "’" :texinfo "`") | |
4939 | (closing-single-quote :utf-8 "’" :html "’" :latex "’" :texinfo "'") | |
4940 | (apostrophe :utf-8 "’" :html "’")) | |
4941 | ) | |
4942 | "Smart quotes translations. | |
4943 | ||
4944 | Alist whose CAR is a language string and CDR is an alist with | |
4945 | quote type as key and a plist associating various encodings to | |
4946 | their translation as value. | |
4947 | ||
4948 | A quote type can be any symbol among `opening-double-quote', | |
4949 | `closing-double-quote', `opening-single-quote', | |
4950 | `closing-single-quote' and `apostrophe'. | |
4951 | ||
4952 | Valid encodings include `:utf-8', `:html', `:latex' and | |
4953 | `:texinfo'. | |
4954 | ||
4955 | If no translation is found, the quote character is left as-is.") | |
4956 | ||
4957 | (defconst org-export-smart-quotes-regexps | |
4958 | (list | |
4959 | ;; Possible opening quote at beginning of string. | |
3c8b09ca | 4960 | "\\`\\([\"']\\)\\(\\w\\|\\s.\\|\\s_\\|\\s(\\)" |
271672fa BG |
4961 | ;; Possible closing quote at beginning of string. |
4962 | "\\`\\([\"']\\)\\(\\s-\\|\\s)\\|\\s.\\)" | |
4963 | ;; Possible apostrophe at beginning of string. | |
4964 | "\\`\\('\\)\\S-" | |
4965 | ;; Opening single and double quotes. | |
4966 | "\\(?:\\s-\\|\\s(\\)\\([\"']\\)\\(?:\\w\\|\\s.\\|\\s_\\)" | |
4967 | ;; Closing single and double quotes. | |
4968 | "\\(?:\\w\\|\\s.\\|\\s_\\)\\([\"']\\)\\(?:\\s-\\|\\s)\\|\\s.\\)" | |
4969 | ;; Apostrophe. | |
4970 | "\\S-\\('\\)\\S-" | |
4971 | ;; Possible opening quote at end of string. | |
4972 | "\\(?:\\s-\\|\\s(\\)\\([\"']\\)\\'" | |
4973 | ;; Possible closing quote at end of string. | |
4974 | "\\(?:\\w\\|\\s.\\|\\s_\\)\\([\"']\\)\\'" | |
4975 | ;; Possible apostrophe at end of string. | |
4976 | "\\S-\\('\\)\\'") | |
4977 | "List of regexps matching a quote or an apostrophe. | |
4978 | In every regexp, quote or apostrophe matched is put in group 1.") | |
4979 | ||
4980 | (defun org-export-activate-smart-quotes (s encoding info &optional original) | |
4981 | "Replace regular quotes with \"smart\" quotes in string S. | |
4982 | ||
4983 | ENCODING is a symbol among `:html', `:latex', `:texinfo' and | |
4984 | `:utf-8'. INFO is a plist used as a communication channel. | |
4985 | ||
4986 | The function has to retrieve information about string | |
4987 | surroundings in parse tree. It can only happen with an | |
4988 | unmodified string. Thus, if S has already been through another | |
4989 | process, a non-nil ORIGINAL optional argument will provide that | |
4990 | original string. | |
4991 | ||
4992 | Return the new string." | |
4993 | (if (equal s "") "" | |
4994 | (let* ((prev (org-export-get-previous-element (or original s) info)) | |
4995 | ;; Try to be flexible when computing number of blanks | |
4996 | ;; before object. The previous object may be a string | |
4997 | ;; introduced by the back-end and not completely parsed. | |
4998 | (pre-blank (and prev | |
4999 | (or (org-element-property :post-blank prev) | |
5000 | ;; A string with missing `:post-blank' | |
5001 | ;; property. | |
5002 | (and (stringp prev) | |
5003 | (string-match " *\\'" prev) | |
5004 | (length (match-string 0 prev))) | |
5005 | ;; Fallback value. | |
5006 | 0))) | |
5007 | (next (org-export-get-next-element (or original s) info)) | |
5008 | (get-smart-quote | |
5009 | (lambda (q type) | |
5010 | ;; Return smart quote associated to a give quote Q, as | |
5011 | ;; a string. TYPE is a symbol among `open', `close' and | |
5012 | ;; `apostrophe'. | |
5013 | (let ((key (case type | |
5014 | (apostrophe 'apostrophe) | |
5015 | (open (if (equal "'" q) 'opening-single-quote | |
5016 | 'opening-double-quote)) | |
5017 | (otherwise (if (equal "'" q) 'closing-single-quote | |
5018 | 'closing-double-quote))))) | |
5019 | (or (plist-get | |
5020 | (cdr (assq key | |
5021 | (cdr (assoc (plist-get info :language) | |
5022 | org-export-smart-quotes-alist)))) | |
5023 | encoding) | |
5024 | q))))) | |
5025 | (if (or (equal "\"" s) (equal "'" s)) | |
5026 | ;; Only a quote: no regexp can match. We have to check both | |
5027 | ;; sides and decide what to do. | |
5028 | (cond ((and (not prev) (not next)) s) | |
5029 | ((not prev) (funcall get-smart-quote s 'open)) | |
5030 | ((and (not next) (zerop pre-blank)) | |
5031 | (funcall get-smart-quote s 'close)) | |
5032 | ((not next) s) | |
5033 | ((zerop pre-blank) (funcall get-smart-quote s 'apostrophe)) | |
5034 | (t (funcall get-smart-quote 'open))) | |
5035 | ;; 1. Replace quote character at the beginning of S. | |
5036 | (cond | |
5037 | ;; Apostrophe? | |
5038 | ((and prev (zerop pre-blank) | |
5039 | (string-match (nth 2 org-export-smart-quotes-regexps) s)) | |
5040 | (setq s (replace-match | |
5041 | (funcall get-smart-quote (match-string 1 s) 'apostrophe) | |
5042 | nil t s 1))) | |
5043 | ;; Closing quote? | |
5044 | ((and prev (zerop pre-blank) | |
5045 | (string-match (nth 1 org-export-smart-quotes-regexps) s)) | |
5046 | (setq s (replace-match | |
5047 | (funcall get-smart-quote (match-string 1 s) 'close) | |
5048 | nil t s 1))) | |
5049 | ;; Opening quote? | |
5050 | ((and (or (not prev) (> pre-blank 0)) | |
5051 | (string-match (nth 0 org-export-smart-quotes-regexps) s)) | |
5052 | (setq s (replace-match | |
5053 | (funcall get-smart-quote (match-string 1 s) 'open) | |
5054 | nil t s 1)))) | |
5055 | ;; 2. Replace quotes in the middle of the string. | |
5056 | (setq s (replace-regexp-in-string | |
5057 | ;; Opening quotes. | |
5058 | (nth 3 org-export-smart-quotes-regexps) | |
5059 | (lambda (text) | |
5060 | (funcall get-smart-quote (match-string 1 text) 'open)) | |
5061 | s nil t 1)) | |
5062 | (setq s (replace-regexp-in-string | |
5063 | ;; Closing quotes. | |
5064 | (nth 4 org-export-smart-quotes-regexps) | |
5065 | (lambda (text) | |
5066 | (funcall get-smart-quote (match-string 1 text) 'close)) | |
5067 | s nil t 1)) | |
5068 | (setq s (replace-regexp-in-string | |
5069 | ;; Apostrophes. | |
5070 | (nth 5 org-export-smart-quotes-regexps) | |
5071 | (lambda (text) | |
5072 | (funcall get-smart-quote (match-string 1 text) 'apostrophe)) | |
5073 | s nil t 1)) | |
5074 | ;; 3. Replace quote character at the end of S. | |
5075 | (cond | |
5076 | ;; Apostrophe? | |
5077 | ((and next (string-match (nth 8 org-export-smart-quotes-regexps) s)) | |
5078 | (setq s (replace-match | |
5079 | (funcall get-smart-quote (match-string 1 s) 'apostrophe) | |
5080 | nil t s 1))) | |
5081 | ;; Closing quote? | |
5082 | ((and (not next) | |
5083 | (string-match (nth 7 org-export-smart-quotes-regexps) s)) | |
5084 | (setq s (replace-match | |
5085 | (funcall get-smart-quote (match-string 1 s) 'close) | |
5086 | nil t s 1))) | |
5087 | ;; Opening quote? | |
5088 | ((and next (string-match (nth 6 org-export-smart-quotes-regexps) s)) | |
5089 | (setq s (replace-match | |
5090 | (funcall get-smart-quote (match-string 1 s) 'open) | |
5091 | nil t s 1)))) | |
5092 | ;; Return string with smart quotes. | |
5093 | s)))) | |
5094 | ||
5095 | ;;;; Topology | |
5096 | ;; | |
5097 | ;; Here are various functions to retrieve information about the | |
4fa51741 | 5098 | ;; neighborhood of a given element or object. Neighbors of interest |
271672fa BG |
5099 | ;; are direct parent (`org-export-get-parent'), parent headline |
5100 | ;; (`org-export-get-parent-headline'), first element containing an | |
5101 | ;; object, (`org-export-get-parent-element'), parent table | |
5102 | ;; (`org-export-get-parent-table'), previous element or object | |
5103 | ;; (`org-export-get-previous-element') and next element or object | |
5104 | ;; (`org-export-get-next-element'). | |
5105 | ;; | |
5106 | ;; `org-export-get-genealogy' returns the full genealogy of a given | |
5107 | ;; element or object, from closest parent to full parse tree. | |
5108 | ||
5109 | (defsubst org-export-get-parent (blob) | |
5110 | "Return BLOB parent or nil. | |
5111 | BLOB is the element or object considered." | |
5112 | (org-element-property :parent blob)) | |
5113 | ||
5114 | (defun org-export-get-genealogy (blob) | |
5115 | "Return full genealogy relative to a given element or object. | |
5116 | ||
5117 | BLOB is the element or object being considered. | |
5118 | ||
5119 | Ancestors are returned from closest to farthest, the last one | |
5120 | being the full parse tree." | |
5121 | (let (genealogy (parent blob)) | |
5122 | (while (setq parent (org-element-property :parent parent)) | |
5123 | (push parent genealogy)) | |
5124 | (nreverse genealogy))) | |
5125 | ||
5126 | (defun org-export-get-parent-headline (blob) | |
5127 | "Return BLOB parent headline or nil. | |
5128 | BLOB is the element or object being considered." | |
5129 | (let ((parent blob)) | |
5130 | (while (and (setq parent (org-element-property :parent parent)) | |
5131 | (not (eq (org-element-type parent) 'headline)))) | |
5132 | parent)) | |
5133 | ||
5134 | (defun org-export-get-parent-element (object) | |
5135 | "Return first element containing OBJECT or nil. | |
5136 | OBJECT is the object to consider." | |
5137 | (let ((parent object)) | |
5138 | (while (and (setq parent (org-element-property :parent parent)) | |
5139 | (memq (org-element-type parent) org-element-all-objects))) | |
5140 | parent)) | |
5141 | ||
5142 | (defun org-export-get-parent-table (object) | |
5143 | "Return OBJECT parent table or nil. | |
5144 | OBJECT is either a `table-cell' or `table-element' type object." | |
5145 | (let ((parent object)) | |
5146 | (while (and (setq parent (org-element-property :parent parent)) | |
5147 | (not (eq (org-element-type parent) 'table)))) | |
5148 | parent)) | |
5149 | ||
5150 | (defun org-export-get-previous-element (blob info &optional n) | |
5151 | "Return previous element or object. | |
5152 | ||
5153 | BLOB is an element or object. INFO is a plist used as | |
5154 | a communication channel. Return previous exportable element or | |
5155 | object, a string, or nil. | |
5156 | ||
5157 | When optional argument N is a positive integer, return a list | |
5158 | containing up to N siblings before BLOB, from farthest to | |
5159 | closest. With any other non-nil value, return a list containing | |
5160 | all of them." | |
5161 | (let ((siblings | |
5162 | ;; An object can belong to the contents of its parent or | |
5163 | ;; to a secondary string. We check the latter option | |
5164 | ;; first. | |
5165 | (let ((parent (org-export-get-parent blob))) | |
5166 | (or (let ((sec-value (org-element-property | |
5167 | (cdr (assq (org-element-type parent) | |
5168 | org-element-secondary-value-alist)) | |
5169 | parent))) | |
5170 | (and (memq blob sec-value) sec-value)) | |
5171 | (org-element-contents parent)))) | |
5172 | prev) | |
5173 | (catch 'exit | |
5174 | (mapc (lambda (obj) | |
5175 | (cond ((memq obj (plist-get info :ignore-list))) | |
5176 | ((null n) (throw 'exit obj)) | |
5177 | ((not (wholenump n)) (push obj prev)) | |
5178 | ((zerop n) (throw 'exit prev)) | |
5179 | (t (decf n) (push obj prev)))) | |
5180 | (cdr (memq blob (reverse siblings)))) | |
5181 | prev))) | |
5182 | ||
5183 | (defun org-export-get-next-element (blob info &optional n) | |
5184 | "Return next element or object. | |
5185 | ||
5186 | BLOB is an element or object. INFO is a plist used as | |
5187 | a communication channel. Return next exportable element or | |
5188 | object, a string, or nil. | |
5189 | ||
5190 | When optional argument N is a positive integer, return a list | |
5191 | containing up to N siblings after BLOB, from closest to farthest. | |
5192 | With any other non-nil value, return a list containing all of | |
5193 | them." | |
5194 | (let ((siblings | |
5195 | ;; An object can belong to the contents of its parent or to | |
5196 | ;; a secondary string. We check the latter option first. | |
5197 | (let ((parent (org-export-get-parent blob))) | |
5198 | (or (let ((sec-value (org-element-property | |
5199 | (cdr (assq (org-element-type parent) | |
5200 | org-element-secondary-value-alist)) | |
5201 | parent))) | |
5202 | (cdr (memq blob sec-value))) | |
5203 | (cdr (memq blob (org-element-contents parent)))))) | |
5204 | next) | |
5205 | (catch 'exit | |
5206 | (mapc (lambda (obj) | |
5207 | (cond ((memq obj (plist-get info :ignore-list))) | |
5208 | ((null n) (throw 'exit obj)) | |
5209 | ((not (wholenump n)) (push obj next)) | |
5210 | ((zerop n) (throw 'exit (nreverse next))) | |
5211 | (t (decf n) (push obj next)))) | |
5212 | siblings) | |
5213 | (nreverse next)))) | |
5214 | ||
5215 | ||
5216 | ;;;; Translation | |
5217 | ;; | |
5218 | ;; `org-export-translate' translates a string according to the language | |
5219 | ;; specified by the LANGUAGE keyword. `org-export-dictionary' contains | |
5220 | ;; the dictionary used for the translation. | |
5221 | ||
5222 | (defconst org-export-dictionary | |
5223 | '(("%e %n: %c" | |
5224 | ("fr" :default "%e %n : %c" :html "%e %n : %c")) | |
5225 | ("Author" | |
5226 | ("ca" :default "Autor") | |
5227 | ("cs" :default "Autor") | |
5228 | ("da" :default "Forfatter") | |
5229 | ("de" :default "Autor") | |
5230 | ("eo" :html "Aŭtoro") | |
5231 | ("es" :default "Autor") | |
5232 | ("fi" :html "Tekijä") | |
5233 | ("fr" :default "Auteur") | |
5234 | ("hu" :default "Szerzõ") | |
5235 | ("is" :html "Höfundur") | |
5236 | ("it" :default "Autore") | |
5237 | ("ja" :html "著者" :utf-8 "著者") | |
5238 | ("nl" :default "Auteur") | |
5239 | ("no" :default "Forfatter") | |
5240 | ("nb" :default "Forfatter") | |
5241 | ("nn" :default "Forfattar") | |
5242 | ("pl" :default "Autor") | |
5243 | ("ru" :html "Автор" :utf-8 "Автор") | |
5244 | ("sv" :html "Författare") | |
5245 | ("uk" :html "Автор" :utf-8 "Автор") | |
5246 | ("zh-CN" :html "作者" :utf-8 "作者") | |
5247 | ("zh-TW" :html "作者" :utf-8 "作者")) | |
5248 | ("Date" | |
5249 | ("ca" :default "Data") | |
5250 | ("cs" :default "Datum") | |
5251 | ("da" :default "Dato") | |
5252 | ("de" :default "Datum") | |
5253 | ("eo" :default "Dato") | |
5254 | ("es" :default "Fecha") | |
5255 | ("fi" :html "Päivämäärä") | |
5256 | ("hu" :html "Dátum") | |
5257 | ("is" :default "Dagsetning") | |
5258 | ("it" :default "Data") | |
5259 | ("ja" :html "日付" :utf-8 "日付") | |
5260 | ("nl" :default "Datum") | |
5261 | ("no" :default "Dato") | |
5262 | ("nb" :default "Dato") | |
5263 | ("nn" :default "Dato") | |
5264 | ("pl" :default "Data") | |
5265 | ("ru" :html "Дата" :utf-8 "Дата") | |
5266 | ("sv" :default "Datum") | |
5267 | ("uk" :html "Дата" :utf-8 "Дата") | |
5268 | ("zh-CN" :html "日期" :utf-8 "日期") | |
5269 | ("zh-TW" :html "日期" :utf-8 "日期")) | |
5270 | ("Equation" | |
5271 | ("da" :default "Ligning") | |
5272 | ("de" :default "Gleichung") | |
5273 | ("es" :html "Ecuación" :default "Ecuación") | |
5274 | ("fr" :ascii "Equation" :default "Équation") | |
5275 | ("no" :default "Ligning") | |
5276 | ("nb" :default "Ligning") | |
5277 | ("nn" :default "Likning") | |
5278 | ("sv" :default "Ekvation") | |
5279 | ("zh-CN" :html "方程" :utf-8 "方程")) | |
5280 | ("Figure" | |
5281 | ("da" :default "Figur") | |
5282 | ("de" :default "Abbildung") | |
5283 | ("es" :default "Figura") | |
5284 | ("ja" :html "図" :utf-8 "図") | |
5285 | ("no" :default "Illustrasjon") | |
5286 | ("nb" :default "Illustrasjon") | |
5287 | ("nn" :default "Illustrasjon") | |
5288 | ("sv" :default "Illustration") | |
5289 | ("zh-CN" :html "图" :utf-8 "图")) | |
5290 | ("Figure %d:" | |
5291 | ("da" :default "Figur %d") | |
5292 | ("de" :default "Abbildung %d:") | |
5293 | ("es" :default "Figura %d:") | |
5294 | ("fr" :default "Figure %d :" :html "Figure %d :") | |
5295 | ("ja" :html "図%d: " :utf-8 "図%d: ") | |
5296 | ("no" :default "Illustrasjon %d") | |
5297 | ("nb" :default "Illustrasjon %d") | |
5298 | ("nn" :default "Illustrasjon %d") | |
5299 | ("sv" :default "Illustration %d") | |
5300 | ("zh-CN" :html "图%d " :utf-8 "图%d ")) | |
5301 | ("Footnotes" | |
5302 | ("ca" :html "Peus de pàgina") | |
5303 | ("cs" :default "Pozn\xe1mky pod carou") | |
5304 | ("da" :default "Fodnoter") | |
5305 | ("de" :html "Fußnoten" :default "Fußnoten") | |
5306 | ("eo" :default "Piednotoj") | |
5307 | ("es" :html "Nota al pie de página" :default "Nota al pie de página") | |
5308 | ("fi" :default "Alaviitteet") | |
5309 | ("fr" :default "Notes de bas de page") | |
5310 | ("hu" :html "Lábjegyzet") | |
5311 | ("is" :html "Aftanmálsgreinar") | |
5312 | ("it" :html "Note a piè di pagina") | |
5313 | ("ja" :html "脚注" :utf-8 "脚注") | |
5314 | ("nl" :default "Voetnoten") | |
5315 | ("no" :default "Fotnoter") | |
5316 | ("nb" :default "Fotnoter") | |
5317 | ("nn" :default "Fotnotar") | |
5318 | ("pl" :default "Przypis") | |
5319 | ("ru" :html "Сноски" :utf-8 "Сноски") | |
5320 | ("sv" :default "Fotnoter") | |
5321 | ("uk" :html "Примітки" | |
5322 | :utf-8 "Примітки") | |
5323 | ("zh-CN" :html "脚注" :utf-8 "脚注") | |
5324 | ("zh-TW" :html "腳註" :utf-8 "腳註")) | |
5325 | ("List of Listings" | |
5326 | ("da" :default "Programmer") | |
5327 | ("de" :default "Programmauflistungsverzeichnis") | |
5328 | ("es" :default "Indice de Listados de programas") | |
5329 | ("fr" :default "Liste des programmes") | |
5330 | ("no" :default "Dataprogrammer") | |
5331 | ("nb" :default "Dataprogrammer") | |
5332 | ("zh-CN" :html "代码目录" :utf-8 "代码目录")) | |
5333 | ("List of Tables" | |
5334 | ("da" :default "Tabeller") | |
5335 | ("de" :default "Tabellenverzeichnis") | |
5336 | ("es" :default "Indice de tablas") | |
5337 | ("fr" :default "Liste des tableaux") | |
5338 | ("no" :default "Tabeller") | |
5339 | ("nb" :default "Tabeller") | |
5340 | ("nn" :default "Tabeller") | |
5341 | ("sv" :default "Tabeller") | |
5342 | ("zh-CN" :html "表格目录" :utf-8 "表格目录")) | |
5343 | ("Listing %d:" | |
5344 | ("da" :default "Program %d") | |
5345 | ("de" :default "Programmlisting %d") | |
5346 | ("es" :default "Listado de programa %d") | |
5347 | ("fr" :default "Programme %d :" :html "Programme %d :") | |
5348 | ("no" :default "Dataprogram") | |
5349 | ("nb" :default "Dataprogram") | |
5350 | ("zh-CN" :html "代码%d " :utf-8 "代码%d ")) | |
5351 | ("See section %s" | |
5352 | ("da" :default "jævnfør afsnit %s") | |
5353 | ("de" :default "siehe Abschnitt %s") | |
5354 | ("es" :default "vea seccion %s") | |
5355 | ("fr" :default "cf. section %s") | |
5356 | ("zh-CN" :html "参见第%d节" :utf-8 "参见第%s节")) | |
5357 | ("Table" | |
5358 | ("de" :default "Tabelle") | |
5359 | ("es" :default "Tabla") | |
5360 | ("fr" :default "Tableau") | |
5361 | ("ja" :html "表" :utf-8 "表") | |
5362 | ("zh-CN" :html "表" :utf-8 "表")) | |
5363 | ("Table %d:" | |
5364 | ("da" :default "Tabel %d") | |
5365 | ("de" :default "Tabelle %d") | |
5366 | ("es" :default "Tabla %d") | |
5367 | ("fr" :default "Tableau %d :") | |
5368 | ("ja" :html "表%d:" :utf-8 "表%d:") | |
5369 | ("no" :default "Tabell %d") | |
5370 | ("nb" :default "Tabell %d") | |
5371 | ("nn" :default "Tabell %d") | |
5372 | ("sv" :default "Tabell %d") | |
5373 | ("zh-CN" :html "表%d " :utf-8 "表%d ")) | |
5374 | ("Table of Contents" | |
5375 | ("ca" :html "Índex") | |
5376 | ("cs" :default "Obsah") | |
5377 | ("da" :default "Indhold") | |
5378 | ("de" :default "Inhaltsverzeichnis") | |
5379 | ("eo" :default "Enhavo") | |
5380 | ("es" :html "Índice") | |
5381 | ("fi" :html "Sisällysluettelo") | |
5382 | ("fr" :ascii "Sommaire" :default "Table des matières") | |
5383 | ("hu" :html "Tartalomjegyzék") | |
5384 | ("is" :default "Efnisyfirlit") | |
5385 | ("it" :default "Indice") | |
5386 | ("ja" :html "目次" :utf-8 "目次") | |
5387 | ("nl" :default "Inhoudsopgave") | |
5388 | ("no" :default "Innhold") | |
5389 | ("nb" :default "Innhold") | |
5390 | ("nn" :default "Innhald") | |
5391 | ("pl" :html "Spis treści") | |
5392 | ("ru" :html "Содержание" | |
5393 | :utf-8 "Содержание") | |
5394 | ("sv" :html "Innehåll") | |
5395 | ("uk" :html "Зміст" :utf-8 "Зміст") | |
5396 | ("zh-CN" :html "目录" :utf-8 "目录") | |
5397 | ("zh-TW" :html "目錄" :utf-8 "目錄")) | |
5398 | ("Unknown reference" | |
5399 | ("da" :default "ukendt reference") | |
5400 | ("de" :default "Unbekannter Verweis") | |
5401 | ("es" :default "referencia desconocida") | |
5402 | ("fr" :ascii "Destination inconnue" :default "Référence inconnue") | |
5403 | ("zh-CN" :html "未知引用" :utf-8 "未知引用"))) | |
5404 | "Dictionary for export engine. | |
5405 | ||
5406 | Alist whose CAR is the string to translate and CDR is an alist | |
5407 | whose CAR is the language string and CDR is a plist whose | |
5408 | properties are possible charsets and values translated terms. | |
5409 | ||
5410 | It is used as a database for `org-export-translate'. Since this | |
5411 | function returns the string as-is if no translation was found, | |
5412 | the variable only needs to record values different from the | |
5413 | entry.") | |
5414 | ||
5415 | (defun org-export-translate (s encoding info) | |
5416 | "Translate string S according to language specification. | |
5417 | ||
5418 | ENCODING is a symbol among `:ascii', `:html', `:latex', `:latin1' | |
5419 | and `:utf-8'. INFO is a plist used as a communication channel. | |
5420 | ||
5421 | Translation depends on `:language' property. Return the | |
5422 | translated string. If no translation is found, try to fall back | |
5423 | to `:default' encoding. If it fails, return S." | |
5424 | (let* ((lang (plist-get info :language)) | |
5425 | (translations (cdr (assoc lang | |
5426 | (cdr (assoc s org-export-dictionary)))))) | |
5427 | (or (plist-get translations encoding) | |
5428 | (plist-get translations :default) | |
5429 | s))) | |
5430 | ||
5431 | ||
5432 | \f | |
5433 | ;;; Asynchronous Export | |
5434 | ;; | |
5435 | ;; `org-export-async-start' is the entry point for asynchronous | |
5436 | ;; export. It recreates current buffer (including visibility, | |
5437 | ;; narrowing and visited file) in an external Emacs process, and | |
5438 | ;; evaluates a command there. It then applies a function on the | |
5439 | ;; returned results in the current process. | |
5440 | ;; | |
5441 | ;; At a higher level, `org-export-to-buffer' and `org-export-to-file' | |
5442 | ;; allow to export to a buffer or a file, asynchronously or not. | |
5443 | ;; | |
5444 | ;; `org-export-output-file-name' is an auxiliary function meant to be | |
5445 | ;; used with `org-export-to-file'. With a given extension, it tries | |
5446 | ;; to provide a canonical file name to write export output to. | |
5447 | ;; | |
5448 | ;; Asynchronously generated results are never displayed directly. | |
5449 | ;; Instead, they are stored in `org-export-stack-contents'. They can | |
5450 | ;; then be retrieved by calling `org-export-stack'. | |
5451 | ;; | |
5452 | ;; Export Stack is viewed through a dedicated major mode | |
5453 | ;;`org-export-stack-mode' and tools: `org-export-stack-refresh', | |
5454 | ;;`org-export-stack-delete', `org-export-stack-view' and | |
5455 | ;;`org-export-stack-clear'. | |
5456 | ;; | |
5457 | ;; For back-ends, `org-export-add-to-stack' add a new source to stack. | |
5458 | ;; It should be used whenever `org-export-async-start' is called. | |
5459 | ||
5460 | (defmacro org-export-async-start (fun &rest body) | |
5461 | "Call function FUN on the results returned by BODY evaluation. | |
5462 | ||
5463 | BODY evaluation happens in an asynchronous process, from a buffer | |
5464 | which is an exact copy of the current one. | |
5465 | ||
5466 | Use `org-export-add-to-stack' in FUN in order to register results | |
5467 | in the stack. | |
5468 | ||
5469 | This is a low level function. See also `org-export-to-buffer' | |
5470 | and `org-export-to-file' for more specialized functions." | |
5471 | (declare (indent 1) (debug t)) | |
5472 | (org-with-gensyms (process temp-file copy-fun proc-buffer coding) | |
5473 | ;; Write the full sexp evaluating BODY in a copy of the current | |
5474 | ;; buffer to a temporary file, as it may be too long for program | |
5475 | ;; args in `start-process'. | |
5476 | `(with-temp-message "Initializing asynchronous export process" | |
5477 | (let ((,copy-fun (org-export--generate-copy-script (current-buffer))) | |
5478 | (,temp-file (make-temp-file "org-export-process")) | |
5479 | (,coding buffer-file-coding-system)) | |
5480 | (with-temp-file ,temp-file | |
5481 | (insert | |
5482 | ;; Null characters (from variable values) are inserted | |
5483 | ;; within the file. As a consequence, coding system for | |
5484 | ;; buffer contents will not be recognized properly. So, | |
5485 | ;; we make sure it is the same as the one used to display | |
5486 | ;; the original buffer. | |
5487 | (format ";; -*- coding: %s; -*-\n%S" | |
5488 | ,coding | |
5489 | `(with-temp-buffer | |
5490 | (when org-export-async-debug '(setq debug-on-error t)) | |
5491 | ;; Ignore `kill-emacs-hook' and code evaluation | |
5492 | ;; queries from Babel as we need a truly | |
5493 | ;; non-interactive process. | |
5494 | (setq kill-emacs-hook nil | |
5495 | org-babel-confirm-evaluate-answer-no t) | |
5496 | ;; Initialize export framework. | |
5497 | (require 'ox) | |
5498 | ;; Re-create current buffer there. | |
5499 | (funcall ,,copy-fun) | |
5500 | (restore-buffer-modified-p nil) | |
5501 | ;; Sexp to evaluate in the buffer. | |
5502 | (print (progn ,,@body)))))) | |
5503 | ;; Start external process. | |
5504 | (let* ((process-connection-type nil) | |
5505 | (,proc-buffer (generate-new-buffer-name "*Org Export Process*")) | |
5506 | (,process | |
5507 | (start-process | |
5508 | "org-export-process" ,proc-buffer | |
5509 | (expand-file-name invocation-name invocation-directory) | |
5510 | "-Q" "--batch" | |
5511 | "-l" org-export-async-init-file | |
5512 | "-l" ,temp-file))) | |
5513 | ;; Register running process in stack. | |
5514 | (org-export-add-to-stack (get-buffer ,proc-buffer) nil ,process) | |
5515 | ;; Set-up sentinel in order to catch results. | |
5516 | (let ((handler ,fun)) | |
5517 | (set-process-sentinel | |
5518 | ,process | |
5519 | `(lambda (p status) | |
5520 | (let ((proc-buffer (process-buffer p))) | |
5521 | (when (eq (process-status p) 'exit) | |
5522 | (unwind-protect | |
5523 | (if (zerop (process-exit-status p)) | |
5524 | (unwind-protect | |
5525 | (let ((results | |
5526 | (with-current-buffer proc-buffer | |
5527 | (goto-char (point-max)) | |
5528 | (backward-sexp) | |
5529 | (read (current-buffer))))) | |
5530 | (funcall ,handler results)) | |
5531 | (unless org-export-async-debug | |
5532 | (and (get-buffer proc-buffer) | |
5533 | (kill-buffer proc-buffer)))) | |
5534 | (org-export-add-to-stack proc-buffer nil p) | |
5535 | (ding) | |
5536 | (message "Process '%s' exited abnormally" p)) | |
5537 | (unless org-export-async-debug | |
5538 | (delete-file ,,temp-file))))))))))))) | |
5539 | ||
5540 | ;;;###autoload | |
5541 | (defun org-export-to-buffer | |
5542 | (backend buffer | |
5543 | &optional async subtreep visible-only body-only ext-plist | |
5544 | post-process) | |
5545 | "Call `org-export-as' with output to a specified buffer. | |
5546 | ||
5547 | BACKEND is either an export back-end, as returned by, e.g., | |
5548 | `org-export-create-backend', or a symbol referring to | |
5549 | a registered back-end. | |
5550 | ||
5551 | BUFFER is the name of the output buffer. If it already exists, | |
5552 | it will be erased first, otherwise, it will be created. | |
5553 | ||
5554 | A non-nil optional argument ASYNC means the process should happen | |
5555 | asynchronously. The resulting buffer should then be accessible | |
5556 | through the `org-export-stack' interface. When ASYNC is nil, the | |
5557 | buffer is displayed if `org-export-show-temporary-export-buffer' | |
5558 | is non-nil. | |
5559 | ||
5560 | Optional arguments SUBTREEP, VISIBLE-ONLY, BODY-ONLY and | |
5561 | EXT-PLIST are similar to those used in `org-export-as', which | |
5562 | see. | |
5563 | ||
5564 | Optional argument POST-PROCESS is a function which should accept | |
5565 | no argument. It is always called within the current process, | |
5566 | from BUFFER, with point at its beginning. Export back-ends can | |
5567 | use it to set a major mode there, e.g, | |
5568 | ||
5569 | \(defun org-latex-export-as-latex | |
5570 | \(&optional async subtreep visible-only body-only ext-plist) | |
5571 | \(interactive) | |
5572 | \(org-export-to-buffer 'latex \"*Org LATEX Export*\" | |
5573 | async subtreep visible-only body-only ext-plist (lambda () (LaTeX-mode)))) | |
5574 | ||
5575 | This function returns BUFFER." | |
5576 | (declare (indent 2)) | |
5577 | (if async | |
5578 | (org-export-async-start | |
5579 | `(lambda (output) | |
5580 | (with-current-buffer (get-buffer-create ,buffer) | |
5581 | (erase-buffer) | |
5582 | (setq buffer-file-coding-system ',buffer-file-coding-system) | |
5583 | (insert output) | |
5584 | (goto-char (point-min)) | |
5585 | (org-export-add-to-stack (current-buffer) ',backend) | |
5586 | (ignore-errors (funcall ,post-process)))) | |
5587 | `(org-export-as | |
5588 | ',backend ,subtreep ,visible-only ,body-only ',ext-plist)) | |
5589 | (let ((output | |
5590 | (org-export-as backend subtreep visible-only body-only ext-plist)) | |
5591 | (buffer (get-buffer-create buffer)) | |
5592 | (encoding buffer-file-coding-system)) | |
5593 | (when (and (org-string-nw-p output) (org-export--copy-to-kill-ring-p)) | |
5594 | (org-kill-new output)) | |
5595 | (with-current-buffer buffer | |
5596 | (erase-buffer) | |
5597 | (setq buffer-file-coding-system encoding) | |
5598 | (insert output) | |
5599 | (goto-char (point-min)) | |
5600 | (and (functionp post-process) (funcall post-process))) | |
5601 | (when org-export-show-temporary-export-buffer | |
5602 | (switch-to-buffer-other-window buffer)) | |
5603 | buffer))) | |
5604 | ||
5605 | ;;;###autoload | |
5606 | (defun org-export-to-file | |
5607 | (backend file &optional async subtreep visible-only body-only ext-plist | |
5608 | post-process) | |
5609 | "Call `org-export-as' with output to a specified file. | |
5610 | ||
5611 | BACKEND is either an export back-end, as returned by, e.g., | |
5612 | `org-export-create-backend', or a symbol referring to | |
5613 | a registered back-end. FILE is the name of the output file, as | |
5614 | a string. | |
5615 | ||
5616 | A non-nil optional argument ASYNC means the process should happen | |
3c8b09ca | 5617 | asynchronously. The resulting buffer will then be accessible |
271672fa BG |
5618 | through the `org-export-stack' interface. |
5619 | ||
5620 | Optional arguments SUBTREEP, VISIBLE-ONLY, BODY-ONLY and | |
5621 | EXT-PLIST are similar to those used in `org-export-as', which | |
5622 | see. | |
5623 | ||
5624 | Optional argument POST-PROCESS is called with FILE as its | |
5625 | argument and happens asynchronously when ASYNC is non-nil. It | |
5626 | has to return a file name, or nil. Export back-ends can use this | |
5627 | to send the output file through additional processing, e.g, | |
5628 | ||
5629 | \(defun org-latex-export-to-latex | |
5630 | \(&optional async subtreep visible-only body-only ext-plist) | |
5631 | \(interactive) | |
5632 | \(let ((outfile (org-export-output-file-name \".tex\" subtreep))) | |
5633 | \(org-export-to-file 'latex outfile | |
5634 | async subtreep visible-only body-only ext-plist | |
5635 | \(lambda (file) (org-latex-compile file))) | |
5636 | ||
5637 | The function returns either a file name returned by POST-PROCESS, | |
5638 | or FILE." | |
5639 | (declare (indent 2)) | |
5640 | (if (not (file-writable-p file)) (error "Output file not writable") | |
5641 | (let ((encoding (or org-export-coding-system buffer-file-coding-system))) | |
5642 | (if async | |
5643 | (org-export-async-start | |
5644 | `(lambda (file) | |
5645 | (org-export-add-to-stack (expand-file-name file) ',backend)) | |
5646 | `(let ((output | |
5647 | (org-export-as | |
5648 | ',backend ,subtreep ,visible-only ,body-only | |
5649 | ',ext-plist))) | |
5650 | (with-temp-buffer | |
5651 | (insert output) | |
5652 | (let ((coding-system-for-write ',encoding)) | |
5653 | (write-file ,file))) | |
5654 | (or (ignore-errors (funcall ',post-process ,file)) ,file))) | |
5655 | (let ((output (org-export-as | |
5656 | backend subtreep visible-only body-only ext-plist))) | |
5657 | (with-temp-buffer | |
5658 | (insert output) | |
5659 | (let ((coding-system-for-write encoding)) | |
5660 | (write-file file))) | |
5661 | (when (and (org-export--copy-to-kill-ring-p) (org-string-nw-p output)) | |
5662 | (org-kill-new output)) | |
5663 | ;; Get proper return value. | |
5664 | (or (and (functionp post-process) (funcall post-process file)) | |
5665 | file)))))) | |
5666 | ||
5667 | (defun org-export-output-file-name (extension &optional subtreep pub-dir) | |
5668 | "Return output file's name according to buffer specifications. | |
5669 | ||
5670 | EXTENSION is a string representing the output file extension, | |
5671 | with the leading dot. | |
5672 | ||
5673 | With a non-nil optional argument SUBTREEP, try to determine | |
5674 | output file's name by looking for \"EXPORT_FILE_NAME\" property | |
5675 | of subtree at point. | |
5676 | ||
5677 | When optional argument PUB-DIR is set, use it as the publishing | |
5678 | directory. | |
5679 | ||
5680 | When optional argument VISIBLE-ONLY is non-nil, don't export | |
5681 | contents of hidden elements. | |
5682 | ||
5683 | Return file name as a string." | |
5684 | (let* ((visited-file (buffer-file-name (buffer-base-buffer))) | |
5685 | (base-name | |
5686 | ;; File name may come from EXPORT_FILE_NAME subtree | |
5687 | ;; property, assuming point is at beginning of said | |
5688 | ;; sub-tree. | |
5689 | (file-name-sans-extension | |
5690 | (or (and subtreep | |
5691 | (org-entry-get | |
5692 | (save-excursion | |
5693 | (ignore-errors (org-back-to-heading) (point))) | |
5694 | "EXPORT_FILE_NAME" t)) | |
5695 | ;; File name may be extracted from buffer's associated | |
5696 | ;; file, if any. | |
5697 | (and visited-file (file-name-nondirectory visited-file)) | |
5698 | ;; Can't determine file name on our own: Ask user. | |
5699 | (let ((read-file-name-function | |
5700 | (and org-completion-use-ido 'ido-read-file-name))) | |
5701 | (read-file-name | |
5702 | "Output file: " pub-dir nil nil nil | |
5703 | (lambda (name) | |
5704 | (string= (file-name-extension name t) extension))))))) | |
5705 | (output-file | |
5706 | ;; Build file name. Enforce EXTENSION over whatever user | |
5707 | ;; may have come up with. PUB-DIR, if defined, always has | |
5708 | ;; precedence over any provided path. | |
5709 | (cond | |
5710 | (pub-dir | |
5711 | (concat (file-name-as-directory pub-dir) | |
5712 | (file-name-nondirectory base-name) | |
5713 | extension)) | |
5714 | ((file-name-absolute-p base-name) (concat base-name extension)) | |
5715 | (t (concat (file-name-as-directory ".") base-name extension))))) | |
5716 | ;; If writing to OUTPUT-FILE would overwrite original file, append | |
5717 | ;; EXTENSION another time to final name. | |
5718 | (if (and visited-file (org-file-equal-p visited-file output-file)) | |
5719 | (concat output-file extension) | |
5720 | output-file))) | |
5721 | ||
5722 | (defun org-export-add-to-stack (source backend &optional process) | |
5723 | "Add a new result to export stack if not present already. | |
5724 | ||
5725 | SOURCE is a buffer or a file name containing export results. | |
5726 | BACKEND is a symbol representing export back-end used to generate | |
5727 | it. | |
5728 | ||
5729 | Entries already pointing to SOURCE and unavailable entries are | |
5730 | removed beforehand. Return the new stack." | |
5731 | (setq org-export-stack-contents | |
5732 | (cons (list source backend (or process (current-time))) | |
5733 | (org-export-stack-remove source)))) | |
5734 | ||
5735 | (defun org-export-stack () | |
5736 | "Menu for asynchronous export results and running processes." | |
5737 | (interactive) | |
5738 | (let ((buffer (get-buffer-create "*Org Export Stack*"))) | |
5739 | (set-buffer buffer) | |
5740 | (when (zerop (buffer-size)) (org-export-stack-mode)) | |
5741 | (org-export-stack-refresh) | |
5742 | (pop-to-buffer buffer)) | |
5743 | (message "Type \"q\" to quit, \"?\" for help")) | |
5744 | ||
5745 | (defun org-export--stack-source-at-point () | |
5746 | "Return source from export results at point in stack." | |
5747 | (let ((source (car (nth (1- (org-current-line)) org-export-stack-contents)))) | |
5748 | (if (not source) (error "Source unavailable, please refresh buffer") | |
5749 | (let ((source-name (if (stringp source) source (buffer-name source)))) | |
5750 | (if (save-excursion | |
5751 | (beginning-of-line) | |
5752 | (looking-at (concat ".* +" (regexp-quote source-name) "$"))) | |
5753 | source | |
5754 | ;; SOURCE is not consistent with current line. The stack | |
5755 | ;; view is outdated. | |
5756 | (error "Source unavailable; type `g' to update buffer")))))) | |
5757 | ||
5758 | (defun org-export-stack-clear () | |
5759 | "Remove all entries from export stack." | |
5760 | (interactive) | |
5761 | (setq org-export-stack-contents nil)) | |
5762 | ||
5763 | (defun org-export-stack-refresh (&rest dummy) | |
5764 | "Refresh the asynchronous export stack. | |
5765 | DUMMY is ignored. Unavailable sources are removed from the list. | |
5766 | Return the new stack." | |
5767 | (let ((inhibit-read-only t)) | |
5768 | (org-preserve-lc | |
5769 | (erase-buffer) | |
5770 | (insert (concat | |
5771 | (let ((counter 0)) | |
5772 | (mapconcat | |
5773 | (lambda (entry) | |
5774 | (let ((proc-p (processp (nth 2 entry)))) | |
5775 | (concat | |
5776 | ;; Back-end. | |
5777 | (format " %-12s " (or (nth 1 entry) "")) | |
5778 | ;; Age. | |
5779 | (let ((data (nth 2 entry))) | |
5780 | (if proc-p (format " %6s " (process-status data)) | |
5781 | ;; Compute age of the results. | |
5782 | (org-format-seconds | |
5783 | "%4h:%.2m " | |
5784 | (float-time (time-since data))))) | |
5785 | ;; Source. | |
5786 | (format " %s" | |
5787 | (let ((source (car entry))) | |
5788 | (if (stringp source) source | |
5789 | (buffer-name source))))))) | |
5790 | ;; Clear stack from exited processes, dead buffers or | |
5791 | ;; non-existent files. | |
5792 | (setq org-export-stack-contents | |
5793 | (org-remove-if-not | |
5794 | (lambda (el) | |
5795 | (if (processp (nth 2 el)) | |
5796 | (buffer-live-p (process-buffer (nth 2 el))) | |
5797 | (let ((source (car el))) | |
5798 | (if (bufferp source) (buffer-live-p source) | |
5799 | (file-exists-p source))))) | |
5800 | org-export-stack-contents)) "\n"))))))) | |
5801 | ||
5802 | (defun org-export-stack-remove (&optional source) | |
5803 | "Remove export results at point from stack. | |
5804 | If optional argument SOURCE is non-nil, remove it instead." | |
5805 | (interactive) | |
5806 | (let ((source (or source (org-export--stack-source-at-point)))) | |
5807 | (setq org-export-stack-contents | |
5808 | (org-remove-if (lambda (el) (equal (car el) source)) | |
5809 | org-export-stack-contents)))) | |
5810 | ||
5811 | (defun org-export-stack-view (&optional in-emacs) | |
5812 | "View export results at point in stack. | |
5813 | With an optional prefix argument IN-EMACS, force viewing files | |
5814 | within Emacs." | |
5815 | (interactive "P") | |
5816 | (let ((source (org-export--stack-source-at-point))) | |
5817 | (cond ((processp source) | |
5818 | (org-switch-to-buffer-other-window (process-buffer source))) | |
5819 | ((bufferp source) (org-switch-to-buffer-other-window source)) | |
5820 | (t (org-open-file source in-emacs))))) | |
5821 | ||
5822 | (defvar org-export-stack-mode-map | |
5823 | (let ((km (make-sparse-keymap))) | |
5824 | (define-key km " " 'next-line) | |
5825 | (define-key km "n" 'next-line) | |
5826 | (define-key km "\C-n" 'next-line) | |
5827 | (define-key km [down] 'next-line) | |
5828 | (define-key km "p" 'previous-line) | |
5829 | (define-key km "\C-p" 'previous-line) | |
5830 | (define-key km "\C-?" 'previous-line) | |
5831 | (define-key km [up] 'previous-line) | |
5832 | (define-key km "C" 'org-export-stack-clear) | |
5833 | (define-key km "v" 'org-export-stack-view) | |
5834 | (define-key km (kbd "RET") 'org-export-stack-view) | |
5835 | (define-key km "d" 'org-export-stack-remove) | |
5836 | km) | |
5837 | "Keymap for Org Export Stack.") | |
5838 | ||
5839 | (define-derived-mode org-export-stack-mode special-mode "Org-Stack" | |
5840 | "Mode for displaying asynchronous export stack. | |
5841 | ||
5842 | Type \\[org-export-stack] to visualize the asynchronous export | |
5843 | stack. | |
5844 | ||
5845 | In an Org Export Stack buffer, use \\<org-export-stack-mode-map>\\[org-export-stack-view] to view export output | |
5846 | on current line, \\[org-export-stack-remove] to remove it from the stack and \\[org-export-stack-clear] to clear | |
5847 | stack completely. | |
5848 | ||
5849 | Removing entries in an Org Export Stack buffer doesn't affect | |
5850 | files or buffers, only the display. | |
5851 | ||
5852 | \\{org-export-stack-mode-map}" | |
5853 | (abbrev-mode 0) | |
5854 | (auto-fill-mode 0) | |
5855 | (setq buffer-read-only t | |
5856 | buffer-undo-list t | |
5857 | truncate-lines t | |
5858 | header-line-format | |
5859 | '(:eval | |
5860 | (format " %-12s | %6s | %s" "Back-End" "Age" "Source"))) | |
5861 | (org-add-hook 'post-command-hook 'org-export-stack-refresh nil t) | |
5862 | (set (make-local-variable 'revert-buffer-function) | |
5863 | 'org-export-stack-refresh)) | |
5864 | ||
5865 | ||
5866 | \f | |
5867 | ;;; The Dispatcher | |
5868 | ;; | |
5869 | ;; `org-export-dispatch' is the standard interactive way to start an | |
5870 | ;; export process. It uses `org-export--dispatch-ui' as a subroutine | |
5871 | ;; for its interface, which, in turn, delegates response to key | |
5872 | ;; pressed to `org-export--dispatch-action'. | |
5873 | ||
5874 | ;;;###autoload | |
5875 | (defun org-export-dispatch (&optional arg) | |
5876 | "Export dispatcher for Org mode. | |
5877 | ||
5878 | It provides an access to common export related tasks in a buffer. | |
d1389828 | 5879 | Its interface comes in two flavors: standard and expert. |
271672fa BG |
5880 | |
5881 | While both share the same set of bindings, only the former | |
5882 | displays the valid keys associations in a dedicated buffer. | |
5883 | Scrolling (resp. line-wise motion) in this buffer is done with | |
5884 | SPC and DEL (resp. C-n and C-p) keys. | |
5885 | ||
5886 | Set variable `org-export-dispatch-use-expert-ui' to switch to one | |
d1389828 | 5887 | flavor or the other. |
271672fa BG |
5888 | |
5889 | When ARG is \\[universal-argument], repeat the last export action, with the same set | |
5890 | of options used back then, on the current buffer. | |
5891 | ||
5892 | When ARG is \\[universal-argument] \\[universal-argument], display the asynchronous export stack." | |
5893 | (interactive "P") | |
5894 | (let* ((input | |
5895 | (cond ((equal arg '(16)) '(stack)) | |
5896 | ((and arg org-export-dispatch-last-action)) | |
5897 | (t (save-window-excursion | |
5898 | (unwind-protect | |
5899 | (progn | |
5900 | ;; Remember where we are | |
5901 | (move-marker org-export-dispatch-last-position | |
5902 | (point) | |
5903 | (org-base-buffer (current-buffer))) | |
5904 | ;; Get and store an export command | |
5905 | (setq org-export-dispatch-last-action | |
5906 | (org-export--dispatch-ui | |
5907 | (list org-export-initial-scope | |
5908 | (and org-export-in-background 'async)) | |
5909 | nil | |
5910 | org-export-dispatch-use-expert-ui))) | |
5911 | (and (get-buffer "*Org Export Dispatcher*") | |
5912 | (kill-buffer "*Org Export Dispatcher*"))))))) | |
5913 | (action (car input)) | |
5914 | (optns (cdr input))) | |
5915 | (unless (memq 'subtree optns) | |
5916 | (move-marker org-export-dispatch-last-position nil)) | |
5917 | (case action | |
5918 | ;; First handle special hard-coded actions. | |
5919 | (template (org-export-insert-default-template nil optns)) | |
5920 | (stack (org-export-stack)) | |
5921 | (publish-current-file | |
5922 | (org-publish-current-file (memq 'force optns) (memq 'async optns))) | |
5923 | (publish-current-project | |
5924 | (org-publish-current-project (memq 'force optns) (memq 'async optns))) | |
5925 | (publish-choose-project | |
5926 | (org-publish (assoc (org-icompleting-read | |
5927 | "Publish project: " | |
5928 | org-publish-project-alist nil t) | |
5929 | org-publish-project-alist) | |
5930 | (memq 'force optns) | |
5931 | (memq 'async optns))) | |
5932 | (publish-all (org-publish-all (memq 'force optns) (memq 'async optns))) | |
5933 | (otherwise | |
5934 | (save-excursion | |
5935 | (when arg | |
5936 | ;; Repeating command, maybe move cursor to restore subtree | |
5937 | ;; context. | |
5938 | (if (eq (marker-buffer org-export-dispatch-last-position) | |
5939 | (org-base-buffer (current-buffer))) | |
5940 | (goto-char org-export-dispatch-last-position) | |
5941 | ;; We are in a different buffer, forget position. | |
5942 | (move-marker org-export-dispatch-last-position nil))) | |
5943 | (funcall action | |
5944 | ;; Return a symbol instead of a list to ease | |
5945 | ;; asynchronous export macro use. | |
5946 | (and (memq 'async optns) t) | |
5947 | (and (memq 'subtree optns) t) | |
5948 | (and (memq 'visible optns) t) | |
5949 | (and (memq 'body optns) t))))))) | |
5950 | ||
5951 | (defun org-export--dispatch-ui (options first-key expertp) | |
5952 | "Handle interface for `org-export-dispatch'. | |
5953 | ||
5954 | OPTIONS is a list containing current interactive options set for | |
5955 | export. It can contain any of the following symbols: | |
5956 | `body' toggles a body-only export | |
5957 | `subtree' restricts export to current subtree | |
5958 | `visible' restricts export to visible part of buffer. | |
5959 | `force' force publishing files. | |
5960 | `async' use asynchronous export process | |
5961 | ||
5962 | FIRST-KEY is the key pressed to select the first level menu. It | |
5963 | is nil when this menu hasn't been selected yet. | |
5964 | ||
5965 | EXPERTP, when non-nil, triggers expert UI. In that case, no help | |
5966 | buffer is provided, but indications about currently active | |
5967 | options are given in the prompt. Moreover, \[?] allows to switch | |
5968 | back to standard interface." | |
5969 | (let* ((fontify-key | |
5970 | (lambda (key &optional access-key) | |
5971 | ;; Fontify KEY string. Optional argument ACCESS-KEY, when | |
5972 | ;; non-nil is the required first-level key to activate | |
5973 | ;; KEY. When its value is t, activate KEY independently | |
5974 | ;; on the first key, if any. A nil value means KEY will | |
5975 | ;; only be activated at first level. | |
5976 | (if (or (eq access-key t) (eq access-key first-key)) | |
5977 | (org-propertize key 'face 'org-warning) | |
5978 | key))) | |
5979 | (fontify-value | |
5980 | (lambda (value) | |
5981 | ;; Fontify VALUE string. | |
5982 | (org-propertize value 'face 'font-lock-variable-name-face))) | |
5983 | ;; Prepare menu entries by extracting them from registered | |
5984 | ;; back-ends and sorting them by access key and by ordinal, | |
5985 | ;; if any. | |
5986 | (entries | |
5987 | (sort (sort (delq nil | |
5988 | (mapcar 'org-export-backend-menu | |
5989 | org-export--registered-backends)) | |
5990 | (lambda (a b) | |
5991 | (let ((key-a (nth 1 a)) | |
5992 | (key-b (nth 1 b))) | |
5993 | (cond ((and (numberp key-a) (numberp key-b)) | |
5994 | (< key-a key-b)) | |
5995 | ((numberp key-b) t))))) | |
5996 | 'car-less-than-car)) | |
5997 | ;; Compute a list of allowed keys based on the first key | |
5998 | ;; pressed, if any. Some keys | |
5999 | ;; (?^B, ?^V, ?^S, ?^F, ?^A, ?&, ?# and ?q) are always | |
6000 | ;; available. | |
6001 | (allowed-keys | |
6002 | (nconc (list 2 22 19 6 1) | |
6003 | (if (not first-key) (org-uniquify (mapcar 'car entries)) | |
6004 | (let (sub-menu) | |
6005 | (dolist (entry entries (sort (mapcar 'car sub-menu) '<)) | |
6006 | (when (eq (car entry) first-key) | |
6007 | (setq sub-menu (append (nth 2 entry) sub-menu)))))) | |
6008 | (cond ((eq first-key ?P) (list ?f ?p ?x ?a)) | |
6009 | ((not first-key) (list ?P))) | |
6010 | (list ?& ?#) | |
6011 | (when expertp (list ??)) | |
6012 | (list ?q))) | |
6013 | ;; Build the help menu for standard UI. | |
6014 | (help | |
6015 | (unless expertp | |
6016 | (concat | |
6017 | ;; Options are hard-coded. | |
6018 | (format "[%s] Body only: %s [%s] Visible only: %s | |
6019 | \[%s] Export scope: %s [%s] Force publishing: %s | |
6020 | \[%s] Async export: %s\n\n" | |
6021 | (funcall fontify-key "C-b" t) | |
6022 | (funcall fontify-value | |
6023 | (if (memq 'body options) "On " "Off")) | |
6024 | (funcall fontify-key "C-v" t) | |
6025 | (funcall fontify-value | |
6026 | (if (memq 'visible options) "On " "Off")) | |
6027 | (funcall fontify-key "C-s" t) | |
6028 | (funcall fontify-value | |
6029 | (if (memq 'subtree options) "Subtree" "Buffer ")) | |
6030 | (funcall fontify-key "C-f" t) | |
6031 | (funcall fontify-value | |
6032 | (if (memq 'force options) "On " "Off")) | |
6033 | (funcall fontify-key "C-a" t) | |
6034 | (funcall fontify-value | |
6035 | (if (memq 'async options) "On " "Off"))) | |
6036 | ;; Display registered back-end entries. When a key | |
6037 | ;; appears for the second time, do not create another | |
6038 | ;; entry, but append its sub-menu to existing menu. | |
6039 | (let (last-key) | |
6040 | (mapconcat | |
6041 | (lambda (entry) | |
6042 | (let ((top-key (car entry))) | |
6043 | (concat | |
6044 | (unless (eq top-key last-key) | |
6045 | (setq last-key top-key) | |
6046 | (format "\n[%s] %s\n" | |
6047 | (funcall fontify-key (char-to-string top-key)) | |
6048 | (nth 1 entry))) | |
6049 | (let ((sub-menu (nth 2 entry))) | |
6050 | (unless (functionp sub-menu) | |
6051 | ;; Split sub-menu into two columns. | |
6052 | (let ((index -1)) | |
6053 | (concat | |
6054 | (mapconcat | |
6055 | (lambda (sub-entry) | |
6056 | (incf index) | |
6057 | (format | |
6058 | (if (zerop (mod index 2)) " [%s] %-26s" | |
6059 | "[%s] %s\n") | |
6060 | (funcall fontify-key | |
6061 | (char-to-string (car sub-entry)) | |
6062 | top-key) | |
6063 | (nth 1 sub-entry))) | |
6064 | sub-menu "") | |
6065 | (when (zerop (mod index 2)) "\n")))))))) | |
6066 | entries "")) | |
6067 | ;; Publishing menu is hard-coded. | |
6068 | (format "\n[%s] Publish | |
6069 | [%s] Current file [%s] Current project | |
6070 | [%s] Choose project [%s] All projects\n\n\n" | |
6071 | (funcall fontify-key "P") | |
6072 | (funcall fontify-key "f" ?P) | |
6073 | (funcall fontify-key "p" ?P) | |
6074 | (funcall fontify-key "x" ?P) | |
6075 | (funcall fontify-key "a" ?P)) | |
6076 | (format "[%s] Export stack [%s] Insert template\n" | |
6077 | (funcall fontify-key "&" t) | |
6078 | (funcall fontify-key "#" t)) | |
6079 | (format "[%s] %s" | |
6080 | (funcall fontify-key "q" t) | |
6081 | (if first-key "Main menu" "Exit"))))) | |
6082 | ;; Build prompts for both standard and expert UI. | |
6083 | (standard-prompt (unless expertp "Export command: ")) | |
6084 | (expert-prompt | |
6085 | (when expertp | |
6086 | (format | |
6087 | "Export command (C-%s%s%s%s%s) [%s]: " | |
6088 | (if (memq 'body options) (funcall fontify-key "b" t) "b") | |
6089 | (if (memq 'visible options) (funcall fontify-key "v" t) "v") | |
6090 | (if (memq 'subtree options) (funcall fontify-key "s" t) "s") | |
6091 | (if (memq 'force options) (funcall fontify-key "f" t) "f") | |
6092 | (if (memq 'async options) (funcall fontify-key "a" t) "a") | |
6093 | (mapconcat (lambda (k) | |
6094 | ;; Strip control characters. | |
6095 | (unless (< k 27) (char-to-string k))) | |
6096 | allowed-keys ""))))) | |
6097 | ;; With expert UI, just read key with a fancy prompt. In standard | |
6098 | ;; UI, display an intrusive help buffer. | |
6099 | (if expertp | |
6100 | (org-export--dispatch-action | |
6101 | expert-prompt allowed-keys entries options first-key expertp) | |
6102 | ;; At first call, create frame layout in order to display menu. | |
6103 | (unless (get-buffer "*Org Export Dispatcher*") | |
6104 | (delete-other-windows) | |
6105 | (org-switch-to-buffer-other-window | |
6106 | (get-buffer-create "*Org Export Dispatcher*")) | |
6107 | (setq cursor-type nil | |
6108 | header-line-format "Use SPC, DEL, C-n or C-p to navigate.") | |
6109 | ;; Make sure that invisible cursor will not highlight square | |
6110 | ;; brackets. | |
6111 | (set-syntax-table (copy-syntax-table)) | |
6112 | (modify-syntax-entry ?\[ "w")) | |
6113 | ;; At this point, the buffer containing the menu exists and is | |
6114 | ;; visible in the current window. So, refresh it. | |
6115 | (with-current-buffer "*Org Export Dispatcher*" | |
6116 | ;; Refresh help. Maintain display continuity by re-visiting | |
6117 | ;; previous window position. | |
6118 | (let ((pos (window-start))) | |
6119 | (erase-buffer) | |
6120 | (insert help) | |
6121 | (set-window-start nil pos))) | |
6122 | (org-fit-window-to-buffer) | |
6123 | (org-export--dispatch-action | |
6124 | standard-prompt allowed-keys entries options first-key expertp)))) | |
6125 | ||
6126 | (defun org-export--dispatch-action | |
6127 | (prompt allowed-keys entries options first-key expertp) | |
6128 | "Read a character from command input and act accordingly. | |
6129 | ||
6130 | PROMPT is the displayed prompt, as a string. ALLOWED-KEYS is | |
6131 | a list of characters available at a given step in the process. | |
6132 | ENTRIES is a list of menu entries. OPTIONS, FIRST-KEY and | |
6133 | EXPERTP are the same as defined in `org-export--dispatch-ui', | |
6134 | which see. | |
6135 | ||
6136 | Toggle export options when required. Otherwise, return value is | |
6137 | a list with action as CAR and a list of interactive export | |
6138 | options as CDR." | |
6139 | (let (key) | |
6140 | ;; Scrolling: when in non-expert mode, act on motion keys (C-n, | |
6141 | ;; C-p, SPC, DEL). | |
6142 | (while (and (setq key (read-char-exclusive prompt)) | |
6143 | (not expertp) | |
6144 | (memq key '(14 16 ?\s ?\d))) | |
6145 | (case key | |
6146 | (14 (if (not (pos-visible-in-window-p (point-max))) | |
6147 | (ignore-errors (scroll-up 1)) | |
6148 | (message "End of buffer") | |
6149 | (sit-for 1))) | |
6150 | (16 (if (not (pos-visible-in-window-p (point-min))) | |
6151 | (ignore-errors (scroll-down 1)) | |
6152 | (message "Beginning of buffer") | |
6153 | (sit-for 1))) | |
6154 | (?\s (if (not (pos-visible-in-window-p (point-max))) | |
6155 | (scroll-up nil) | |
6156 | (message "End of buffer") | |
6157 | (sit-for 1))) | |
6158 | (?\d (if (not (pos-visible-in-window-p (point-min))) | |
6159 | (scroll-down nil) | |
6160 | (message "Beginning of buffer") | |
6161 | (sit-for 1))))) | |
6162 | (cond | |
6163 | ;; Ignore undefined associations. | |
6164 | ((not (memq key allowed-keys)) | |
6165 | (ding) | |
6166 | (unless expertp (message "Invalid key") (sit-for 1)) | |
6167 | (org-export--dispatch-ui options first-key expertp)) | |
6168 | ;; q key at first level aborts export. At second level, cancel | |
6169 | ;; first key instead. | |
6170 | ((eq key ?q) (if (not first-key) (error "Export aborted") | |
6171 | (org-export--dispatch-ui options nil expertp))) | |
6172 | ;; Help key: Switch back to standard interface if expert UI was | |
6173 | ;; active. | |
6174 | ((eq key ??) (org-export--dispatch-ui options first-key nil)) | |
6175 | ;; Send request for template insertion along with export scope. | |
6176 | ((eq key ?#) (cons 'template (memq 'subtree options))) | |
6177 | ;; Switch to asynchronous export stack. | |
6178 | ((eq key ?&) '(stack)) | |
6179 | ;; Toggle options: C-b (2) C-v (22) C-s (19) C-f (6) C-a (1). | |
6180 | ((memq key '(2 22 19 6 1)) | |
6181 | (org-export--dispatch-ui | |
6182 | (let ((option (case key (2 'body) (22 'visible) (19 'subtree) | |
6183 | (6 'force) (1 'async)))) | |
6184 | (if (memq option options) (remq option options) | |
6185 | (cons option options))) | |
6186 | first-key expertp)) | |
6187 | ;; Action selected: Send key and options back to | |
6188 | ;; `org-export-dispatch'. | |
6189 | ((or first-key (functionp (nth 2 (assq key entries)))) | |
6190 | (cons (cond | |
6191 | ((not first-key) (nth 2 (assq key entries))) | |
6192 | ;; Publishing actions are hard-coded. Send a special | |
6193 | ;; signal to `org-export-dispatch'. | |
6194 | ((eq first-key ?P) | |
6195 | (case key | |
6196 | (?f 'publish-current-file) | |
6197 | (?p 'publish-current-project) | |
6198 | (?x 'publish-choose-project) | |
6199 | (?a 'publish-all))) | |
6200 | ;; Return first action associated to FIRST-KEY + KEY | |
6201 | ;; path. Indeed, derived backends can share the same | |
6202 | ;; FIRST-KEY. | |
6203 | (t (catch 'found | |
6204 | (mapc (lambda (entry) | |
6205 | (let ((match (assq key (nth 2 entry)))) | |
6206 | (when match (throw 'found (nth 2 match))))) | |
6207 | (member (assq first-key entries) entries))))) | |
6208 | options)) | |
6209 | ;; Otherwise, enter sub-menu. | |
6210 | (t (org-export--dispatch-ui options key expertp))))) | |
6211 | ||
6212 | ||
6213 | ||
6214 | (provide 'ox) | |
6215 | ||
6216 | ;; Local variables: | |
6217 | ;; generated-autoload-file: "org-loaddefs.el" | |
6218 | ;; End: | |
6219 | ||
6220 | ;;; ox.el ends here |