From e32a45ed36d6000db4b39171149072d11b77af72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Delafond?= Date: Sun, 13 Jul 2014 13:35:27 +0200 Subject: Imported Upstream version 8.0.7 --- contrib/lisp/org-export.el | 4518 -------------------------------------------- 1 file changed, 4518 deletions(-) delete mode 100644 contrib/lisp/org-export.el (limited to 'contrib/lisp/org-export.el') diff --git a/contrib/lisp/org-export.el b/contrib/lisp/org-export.el deleted file mode 100644 index 4f01b7e..0000000 --- a/contrib/lisp/org-export.el +++ /dev/null @@ -1,4518 +0,0 @@ -;;; org-export.el --- Generic Export Engine For Org - -;; Copyright (C) 2012 Free Software Foundation, Inc. - -;; Author: Nicolas Goaziou -;; Keywords: outlines, hypermedia, calendar, wp - -;; This program is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with this program. If not, see . - -;;; Commentary: -;; -;; This library implements a generic export engine for Org, built on -;; its syntactical parser: Org Elements. -;; -;; Besides that parser, the generic exporter is made of three distinct -;; parts: -;; -;; - The communication channel consists in a property list, which is -;; created and updated during the process. Its use is to offer -;; every piece of information, would it be about initial environment -;; or contextual data, all in a single place. The exhaustive list -;; of properties is given in "The Communication Channel" section of -;; this file. -;; -;; - The transcoder walks the parse tree, ignores or treat as plain -;; text elements and objects according to export options, and -;; eventually calls back-end specific functions to do the real -;; transcoding, concatenating their return value along the way. -;; -;; - The filter system is activated at the very beginning and the very -;; end of the export process, and each time an element or an object -;; has been converted. It is the entry point to fine-tune standard -;; output from back-end transcoders. See "The Filter System" -;; section for more information. -;; -;; The core function is `org-export-as'. It returns the transcoded -;; buffer as a string. -;; -;; An export back-end is defined with `org-export-define-backend', -;; which sets one mandatory variable: his translation table. Its name -;; is always `org-BACKEND-translate-alist' where BACKEND stands for -;; the name chosen for the back-end. Its value is an alist whose keys -;; are elements and objects types and values translator functions. -;; See function's docstring for more information about translators. -;; -;; Optionally, `org-export-define-backend' can also support specific -;; buffer keywords, OPTION keyword's items and filters. Also refer to -;; function documentation for more information. -;; -;; If the new back-end shares most properties with another one, -;; `org-export-define-derived-backend' can be used to simplify the -;; process. -;; -;; Any back-end can define its own variables. Among them, those -;; customizable should belong to the `org-export-BACKEND' group. -;; -;; Tools for common tasks across back-ends are implemented in the -;; penultimate part of this file. A dispatcher for standard back-ends -;; is provided in the last one. - -;;; Code: - -(eval-when-compile (require 'cl)) -(require 'org-element) - - -(declare-function org-e-ascii-export-as-ascii "org-e-ascii" - (&optional subtreep visible-only body-only ext-plist)) -(declare-function org-e-ascii-export-to-ascii "org-e-ascii" - (&optional subtreep visible-only body-only ext-plist pub-dir)) -(declare-function org-e-html-export-as-html "org-e-html" - (&optional subtreep visible-only body-only ext-plist)) -(declare-function org-e-html-export-to-html "org-e-html" - (&optional subtreep visible-only body-only ext-plist pub-dir)) -(declare-function org-e-latex-export-as-latex "org-e-latex" - (&optional subtreep visible-only body-only ext-plist)) -(declare-function org-e-latex-export-to-latex "org-e-latex" - (&optional subtreep visible-only body-only ext-plist pub-dir)) -(declare-function org-e-latex-export-to-pdf "org-e-latex" - (&optional subtreep visible-only body-only ext-plist pub-dir)) -(declare-function org-e-odt-export-to-odt "org-e-odt" - (&optional subtreep visible-only body-only ext-plist pub-dir)) -(declare-function org-e-publish "org-e-publish" (project &optional force)) -(declare-function org-e-publish-all "org-e-publish" (&optional force)) -(declare-function org-e-publish-current-file "org-e-publish" (&optional force)) -(declare-function org-e-publish-current-project "org-e-publish" - (&optional force)) -(declare-function org-export-blocks-preprocess "org-exp-blocks") - -(defvar org-e-publish-project-alist) -(defvar org-table-number-fraction) -(defvar org-table-number-regexp) - - - -;;; Internal Variables -;; -;; Among internal variables, the most important is -;; `org-export-options-alist'. This variable define the global export -;; options, shared between every exporter, and how they are acquired. - -(defconst org-export-max-depth 19 - "Maximum nesting depth for headlines, counting from 0.") - -(defconst org-export-options-alist - '((:author "AUTHOR" nil user-full-name t) - (:creator "CREATOR" nil org-export-creator-string) - (:date "DATE" nil nil t) - (:description "DESCRIPTION" nil nil newline) - (:email "EMAIL" nil user-mail-address t) - (:exclude-tags "EXCLUDE_TAGS" nil org-export-exclude-tags split) - (:headline-levels nil "H" org-export-headline-levels) - (:keywords "KEYWORDS" nil nil space) - (:language "LANGUAGE" nil org-export-default-language t) - (:preserve-breaks nil "\\n" org-export-preserve-breaks) - (:section-numbers nil "num" org-export-with-section-numbers) - (:select-tags "SELECT_TAGS" nil org-export-select-tags split) - (:time-stamp-file nil "timestamp" org-export-time-stamp-file) - (:title "TITLE" nil nil space) - (:with-archived-trees nil "arch" org-export-with-archived-trees) - (:with-author nil "author" org-export-with-author) - (:with-clocks nil "c" org-export-with-clocks) - (:with-creator nil "creator" org-export-with-creator) - (:with-drawers nil "d" org-export-with-drawers) - (:with-email nil "email" org-export-with-email) - (:with-emphasize nil "*" org-export-with-emphasize) - (:with-entities nil "e" org-export-with-entities) - (:with-fixed-width nil ":" org-export-with-fixed-width) - (:with-footnotes nil "f" org-export-with-footnotes) - (:with-inlinetasks nil "inline" org-export-with-inlinetasks) - (:with-plannings nil "p" org-export-with-planning) - (:with-priority nil "pri" org-export-with-priority) - (:with-special-strings nil "-" org-export-with-special-strings) - (:with-sub-superscript nil "^" org-export-with-sub-superscripts) - (:with-toc nil "toc" org-export-with-toc) - (:with-tables nil "|" org-export-with-tables) - (:with-tags nil "tags" org-export-with-tags) - (:with-tasks nil "tasks" org-export-with-tasks) - (:with-timestamps nil "<" org-export-with-timestamps) - (:with-todo-keywords nil "todo" org-export-with-todo-keywords)) - "Alist between export properties and ways to set them. - -The CAR of the alist is the property name, and the CDR is a list -like (KEYWORD OPTION DEFAULT BEHAVIOUR) where: - -KEYWORD is a string representing a buffer keyword, or nil. Each - property defined this way can also be set, during subtree - export, through an headline property named after the keyword - with the \"EXPORT_\" prefix (i.e. DATE keyword and EXPORT_DATE - property). -OPTION is a string that could be found in an #+OPTIONS: line. -DEFAULT is the default value for the property. -BEHAVIOUR determine how Org should handle multiple keywords for - the same property. It is a symbol among: - nil Keep old value and discard the new one. - t Replace old value with the new one. - `space' Concatenate the values, separating them with a space. - `newline' Concatenate the values, separating them with - a newline. - `split' Split values at white spaces, and cons them to the - previous list. - -KEYWORD and OPTION have precedence over DEFAULT. - -All these properties should be back-end agnostic. Back-end -specific properties are set through `org-export-define-backend'. -Properties redefined there have precedence over these.") - -(defconst org-export-special-keywords - '("SETUP_FILE" "OPTIONS" "MACRO") - "List of in-buffer keywords that require special treatment. -These keywords are not directly associated to a property. The -way they are handled must be hard-coded into -`org-export--get-inbuffer-options' function.") - -(defconst org-export-filters-alist - '((:filter-bold . org-export-filter-bold-functions) - (:filter-babel-call . org-export-filter-babel-call-functions) - (:filter-center-block . org-export-filter-center-block-functions) - (:filter-clock . org-export-filter-clock-functions) - (:filter-code . org-export-filter-code-functions) - (:filter-comment . org-export-filter-comment-functions) - (:filter-comment-block . org-export-filter-comment-block-functions) - (:filter-drawer . org-export-filter-drawer-functions) - (:filter-dynamic-block . org-export-filter-dynamic-block-functions) - (:filter-entity . org-export-filter-entity-functions) - (:filter-example-block . org-export-filter-example-block-functions) - (:filter-export-block . org-export-filter-export-block-functions) - (:filter-export-snippet . org-export-filter-export-snippet-functions) - (:filter-final-output . org-export-filter-final-output-functions) - (:filter-fixed-width . org-export-filter-fixed-width-functions) - (:filter-footnote-definition . org-export-filter-footnote-definition-functions) - (:filter-footnote-reference . org-export-filter-footnote-reference-functions) - (:filter-headline . org-export-filter-headline-functions) - (:filter-horizontal-rule . org-export-filter-horizontal-rule-functions) - (:filter-inline-babel-call . org-export-filter-inline-babel-call-functions) - (:filter-inline-src-block . org-export-filter-inline-src-block-functions) - (:filter-inlinetask . org-export-filter-inlinetask-functions) - (:filter-italic . org-export-filter-italic-functions) - (:filter-item . org-export-filter-item-functions) - (:filter-keyword . org-export-filter-keyword-functions) - (:filter-latex-environment . org-export-filter-latex-environment-functions) - (:filter-latex-fragment . org-export-filter-latex-fragment-functions) - (:filter-line-break . org-export-filter-line-break-functions) - (:filter-link . org-export-filter-link-functions) - (:filter-macro . org-export-filter-macro-functions) - (:filter-paragraph . org-export-filter-paragraph-functions) - (:filter-parse-tree . org-export-filter-parse-tree-functions) - (:filter-plain-list . org-export-filter-plain-list-functions) - (:filter-plain-text . org-export-filter-plain-text-functions) - (:filter-planning . org-export-filter-planning-functions) - (:filter-property-drawer . org-export-filter-property-drawer-functions) - (:filter-quote-block . org-export-filter-quote-block-functions) - (:filter-quote-section . org-export-filter-quote-section-functions) - (:filter-radio-target . org-export-filter-radio-target-functions) - (:filter-section . org-export-filter-section-functions) - (:filter-special-block . org-export-filter-special-block-functions) - (:filter-src-block . org-export-filter-src-block-functions) - (:filter-statistics-cookie . org-export-filter-statistics-cookie-functions) - (:filter-strike-through . org-export-filter-strike-through-functions) - (:filter-subscript . org-export-filter-subscript-functions) - (:filter-superscript . org-export-filter-superscript-functions) - (:filter-table . org-export-filter-table-functions) - (:filter-table-cell . org-export-filter-table-cell-functions) - (:filter-table-row . org-export-filter-table-row-functions) - (:filter-target . org-export-filter-target-functions) - (:filter-timestamp . org-export-filter-timestamp-functions) - (:filter-underline . org-export-filter-underline-functions) - (:filter-verbatim . org-export-filter-verbatim-functions) - (:filter-verse-block . org-export-filter-verse-block-functions)) - "Alist between filters properties and initial values. - -The key of each association is a property name accessible through -the communication channel. Its value is a configurable global -variable defining initial filters. - -This list is meant to install user specified filters. Back-end -developers may install their own filters using -`org-export-define-backend'. Filters defined there will always -be prepended to the current list, so they always get applied -first.") - -(defconst org-export-default-inline-image-rule - `(("file" . - ,(format "\\.%s\\'" - (regexp-opt - '("png" "jpeg" "jpg" "gif" "tiff" "tif" "xbm" - "xpm" "pbm" "pgm" "ppm") t)))) - "Default rule for link matching an inline image. -This rule applies to links with no description. By default, it -will be considered as an inline image if it targets a local file -whose extension is either \"png\", \"jpeg\", \"jpg\", \"gif\", -\"tiff\", \"tif\", \"xbm\", \"xpm\", \"pbm\", \"pgm\" or \"ppm\". -See `org-export-inline-image-p' for more information about -rules.") - - - -;;; User-configurable Variables -;; -;; Configuration for the masses. -;; -;; They should never be accessed directly, as their value is to be -;; stored in a property list (cf. `org-export-options-alist'). -;; Back-ends will read their value from there instead. - -(defgroup org-export nil - "Options for exporting Org mode files." - :tag "Org Export" - :group 'org) - -(defgroup org-export-general nil - "General options for export engine." - :tag "Org Export General" - :group 'org-export) - -(defcustom org-export-with-archived-trees 'headline - "Whether sub-trees with the ARCHIVE tag should be exported. - -This can have three different values: -nil Do not export, pretend this tree is not present. -t Do export the entire tree. -`headline' Only export the headline, but skip the tree below it. - -This option can also be set with the #+OPTIONS line, -e.g. \"arch:nil\"." - :group 'org-export-general - :type '(choice - (const :tag "Not at all" nil) - (const :tag "Headline only" 'headline) - (const :tag "Entirely" t))) - -(defcustom org-export-with-author t - "Non-nil means insert author name into the exported file. -This option can also be set with the #+OPTIONS line, -e.g. \"author:nil\"." - :group 'org-export-general - :type 'boolean) - -(defcustom org-export-with-clocks nil - "Non-nil means export CLOCK keywords. -This option can also be set with the #+OPTIONS line, -e.g. \"c:t\"." - :group 'org-export-general - :type 'boolean) - -(defcustom org-export-with-creator 'comment - "Non-nil means the postamble should contain a creator sentence. - -The sentence can be set in `org-export-creator-string' and -defaults to \"Generated by Org mode XX in Emacs XXX.\". - -If the value is `comment' insert it as a comment." - :group 'org-export-general - :type '(choice - (const :tag "No creator sentence" nil) - (const :tag "Sentence as a comment" 'comment) - (const :tag "Insert the sentence" t))) - -(defcustom org-export-creator-string - (format "Generated by Org mode %s in Emacs %s." - (if (fboundp 'org-version) (org-version) "(Unknown)") - emacs-version) - "String to insert at the end of the generated document." - :group 'org-export-general - :type '(string :tag "Creator string")) - -(defcustom org-export-with-drawers t - "Non-nil means export contents of standard drawers. - -When t, all drawers are exported. This may also be a list of -drawer names to export. This variable doesn't apply to -properties drawers. - -This option can also be set with the #+OPTIONS line, -e.g. \"d:nil\"." - :group 'org-export-general - :type '(choice - (const :tag "All drawers" t) - (const :tag "None" nil) - (repeat :tag "Selected drawers" - (string :tag "Drawer name")))) - -(defcustom org-export-with-email nil - "Non-nil means insert author email into the exported file. -This option can also be set with the #+OPTIONS line, -e.g. \"email:t\"." - :group 'org-export-general - :type 'boolean) - -(defcustom org-export-with-emphasize t - "Non-nil means interpret *word*, /word/, and _word_ as emphasized text. - -If the export target supports emphasizing text, the word will be -typeset in bold, italic, or underlined, respectively. Not all -export backends support this. - -This option can also be set with the #+OPTIONS line, e.g. \"*:nil\"." - :group 'org-export-general - :type 'boolean) - -(defcustom org-export-exclude-tags '("noexport") - "Tags that exclude a tree from export. - -All trees carrying any of these tags will be excluded from -export. This is without condition, so even subtrees inside that -carry one of the `org-export-select-tags' will be removed. - -This option can also be set with the #+EXCLUDE_TAGS: keyword." - :group 'org-export-general - :type '(repeat (string :tag "Tag"))) - -(defcustom org-export-with-fixed-width t - "Non-nil means lines starting with \":\" will be in fixed width font. - -This can be used to have pre-formatted text, fragments of code -etc. For example: - : ;; Some Lisp examples - : (while (defc cnt) - : (ding)) -will be looking just like this in also HTML. See also the QUOTE -keyword. Not all export backends support this. - -This option can also be set with the #+OPTIONS line, e.g. \"::nil\"." - :group 'org-export-translation - :type 'boolean) - -(defcustom org-export-with-footnotes t - "Non-nil means Org footnotes should be exported. -This option can also be set with the #+OPTIONS line, -e.g. \"f:nil\"." - :group 'org-export-general - :type 'boolean) - -(defcustom org-export-headline-levels 3 - "The last level which is still exported as a headline. - -Inferior levels will produce itemize lists when exported. - -This option can also be set with the #+OPTIONS line, e.g. \"H:2\"." - :group 'org-export-general - :type 'integer) - -(defcustom org-export-default-language "en" - "The default language for export and clocktable translations, as a string. -This may have an association in -`org-clock-clocktable-language-setup'." - :group 'org-export-general - :type '(string :tag "Language")) - -(defcustom org-export-preserve-breaks nil - "Non-nil means preserve all line breaks when exporting. - -Normally, in HTML output paragraphs will be reformatted. - -This option can also be set with the #+OPTIONS line, -e.g. \"\\n:t\"." - :group 'org-export-general - :type 'boolean) - -(defcustom org-export-with-entities t - "Non-nil means interpret entities when exporting. - -For example, HTML export converts \\alpha to α and \\AA to -Å. - -For a list of supported names, see the constant `org-entities' -and the user option `org-entities-user'. - -This option can also be set with the #+OPTIONS line, -e.g. \"e:nil\"." - :group 'org-export-general - :type 'boolean) - -(defcustom org-export-with-inlinetasks t - "Non-nil means inlinetasks should be exported. -This option can also be set with the #+OPTIONS line, -e.g. \"inline:nil\"." - :group 'org-export-general - :type 'boolean) - -(defcustom org-export-with-planning nil - "Non-nil means include planning info in export. -This option can also be set with the #+OPTIONS: line, -e.g. \"p:t\"." - :group 'org-export-general - :type 'boolean) - -(defcustom org-export-with-priority nil - "Non-nil means include priority cookies in export. -This option can also be set with the #+OPTIONS line, -e.g. \"pri:t\"." - :group 'org-export-general - :type 'boolean) - -(defcustom org-export-with-section-numbers t - "Non-nil means add section numbers to headlines when exporting. - -When set to an integer n, numbering will only happen for -headlines whose relative level is higher or equal to n. - -This option can also be set with the #+OPTIONS line, -e.g. \"num:t\"." - :group 'org-export-general - :type 'boolean) - -(defcustom org-export-select-tags '("export") - "Tags that select a tree for export. - -If any such tag is found in a buffer, all trees that do not carry -one of these tags will be ignored during export. Inside trees -that are selected like this, you can still deselect a subtree by -tagging it with one of the `org-export-exclude-tags'. - -This option can also be set with the #+SELECT_TAGS: keyword." - :group 'org-export-general - :type '(repeat (string :tag "Tag"))) - -(defcustom org-export-with-special-strings t - "Non-nil means interpret \"\-\", \"--\" and \"---\" for export. - -When this option is turned on, these strings will be exported as: - - Org HTML LaTeX - -----+----------+-------- - \\- ­ \\- - -- – -- - --- — --- - ... … \ldots - -This option can also be set with the #+OPTIONS line, -e.g. \"-:nil\"." - :group 'org-export-general - :type 'boolean) - -(defcustom org-export-with-sub-superscripts t - "Non-nil means interpret \"_\" and \"^\" for export. - -When this option is turned on, you can use TeX-like syntax for -sub- and superscripts. Several characters after \"_\" or \"^\" -will be considered as a single item - so grouping with {} is -normally not needed. For example, the following things will be -parsed as single sub- or superscripts. - - 10^24 or 10^tau several digits will be considered 1 item. - 10^-12 or 10^-tau a leading sign with digits or a word - x^2-y^3 will be read as x^2 - y^3, because items are - terminated by almost any nonword/nondigit char. - x_{i^2} or x^(2-i) braces or parenthesis do grouping. - -Still, ambiguity is possible - so when in doubt use {} to enclose -the sub/superscript. If you set this variable to the symbol -`{}', the braces are *required* in order to trigger -interpretations as sub/superscript. This can be helpful in -documents that need \"_\" frequently in plain text. - -This option can also be set with the #+OPTIONS line, -e.g. \"^:nil\"." - :group 'org-export-general - :type '(choice - (const :tag "Interpret them" t) - (const :tag "Curly brackets only" {}) - (const :tag "Do not interpret them" nil))) - -(defcustom org-export-with-toc t - "Non-nil means create a table of contents in exported files. - -The TOC contains headlines with levels up -to`org-export-headline-levels'. When an integer, include levels -up to N in the toc, this may then be different from -`org-export-headline-levels', but it will not be allowed to be -larger than the number of headline levels. When nil, no table of -contents is made. - -This option can also be set with the #+OPTIONS line, -e.g. \"toc:nil\" or \"toc:3\"." - :group 'org-export-general - :type '(choice - (const :tag "No Table of Contents" nil) - (const :tag "Full Table of Contents" t) - (integer :tag "TOC to level"))) - -(defcustom org-export-with-tables t - "If non-nil, lines starting with \"|\" define a table. -For example: - - | Name | Address | Birthday | - |-------------+----------+-----------| - | Arthur Dent | England | 29.2.2100 | - -This option can also be set with the #+OPTIONS line, e.g. \"|:nil\"." - :group 'org-export-general - :type 'boolean) - -(defcustom org-export-with-tags t - "If nil, do not export tags, just remove them from headlines. - -If this is the symbol `not-in-toc', tags will be removed from -table of contents entries, but still be shown in the headlines of -the document. - -This option can also be set with the #+OPTIONS line, -e.g. \"tags:nil\"." - :group 'org-export-general - :type '(choice - (const :tag "Off" nil) - (const :tag "Not in TOC" not-in-toc) - (const :tag "On" t))) - -(defcustom org-export-with-tasks t - "Non-nil means include TODO items for export. -This may have the following values: -t include tasks independent of state. -todo include only tasks that are not yet done. -done include only tasks that are already done. -nil remove all tasks before export -list of keywords keep only tasks with these keywords" - :group 'org-export-general - :type '(choice - (const :tag "All tasks" t) - (const :tag "No tasks" nil) - (const :tag "Not-done tasks" todo) - (const :tag "Only done tasks" done) - (repeat :tag "Specific TODO keywords" - (string :tag "Keyword")))) - -(defcustom org-export-time-stamp-file t - "Non-nil means insert a time stamp into the exported file. -The time stamp shows when the file was created. - -This option can also be set with the #+OPTIONS line, -e.g. \"timestamp:nil\"." - :group 'org-export-general - :type 'boolean) - -(defcustom org-export-with-timestamps t - "Non nil means allow timestamps in export. - -It can be set to `active', `inactive', t or nil, in order to -export, respectively, only active timestamps, only inactive ones, -all of them or none. - -This option can also be set with the #+OPTIONS line, e.g. -\"<:nil\"." - :group 'org-export-general - :type '(choice - (const :tag "All timestamps" t) - (const :tag "Only active timestamps" active) - (const :tag "Only inactive timestamps" inactive) - (const :tag "No timestamp" nil))) - -(defcustom org-export-with-todo-keywords t - "Non-nil means include TODO keywords in export. -When nil, remove all these keywords from the export." - :group 'org-export-general - :type 'boolean) - -(defcustom org-export-allow-BIND 'confirm - "Non-nil means allow #+BIND to define local variable values for export. -This is a potential security risk, which is why the user must -confirm the use of these lines." - :group 'org-export-general - :type '(choice - (const :tag "Never" nil) - (const :tag "Always" t) - (const :tag "Ask a confirmation for each file" confirm))) - -(defcustom org-export-snippet-translation-alist nil - "Alist between export snippets back-ends and exporter back-ends. - -This variable allows to provide shortcuts for export snippets. - -For example, with a value of '\(\(\"h\" . \"e-html\"\)\), the -HTML back-end will recognize the contents of \"@@h:@@\" as -HTML code while every other back-end will ignore it." - :group 'org-export-general - :type '(repeat - (cons - (string :tag "Shortcut") - (string :tag "Back-end")))) - -(defcustom org-export-coding-system nil - "Coding system for the exported file." - :group 'org-export-general - :type 'coding-system) - -(defcustom org-export-copy-to-kill-ring t - "Non-nil means exported stuff will also be pushed onto the kill ring." - :group 'org-export-general - :type 'boolean) - -(defcustom org-export-initial-scope 'buffer - "The initial scope when exporting with `org-export-dispatch'. -This variable can be either set to `buffer' or `subtree'." - :group 'org-export-general - :type '(choice - (const :tag "Export current buffer" 'buffer) - (const :tag "Export current subtree" 'subtree))) - -(defcustom org-export-show-temporary-export-buffer t - "Non-nil means show buffer after exporting to temp buffer. -When Org exports to a file, the buffer visiting that file is ever -shown, but remains buried. However, when exporting to -a temporary buffer, that buffer is popped up in a second window. -When this variable is nil, the buffer remains buried also in -these cases." - :group 'org-export-general - :type 'boolean) - -(defcustom org-export-dispatch-use-expert-ui nil - "Non-nil means using a non-intrusive `org-export-dispatch'. -In that case, no help buffer is displayed. Though, an indicator -for current export scope is added to the prompt \(i.e. \"b\" when -output is restricted to body only, \"s\" when it is restricted to -the current subtree and \"v\" when only visible elements are -considered for export\). Also, \[?] allows to switch back to -standard mode." - :group 'org-export-general - :type 'boolean) - - - -;;; Defining New Back-ends - -(defmacro org-export-define-backend (backend translators &rest body) - "Define a new back-end BACKEND. - -TRANSLATORS is an alist between object or element types and -functions handling them. - -These functions should return a string without any trailing -space, or nil. They must accept three arguments: the object or -element itself, its contents or nil when it isn't recursive and -the property list used as a communication channel. - -Contents, when not nil, are stripped from any global indentation -\(although the relative one is preserved). They also always end -with a single newline character. - -If, for a given type, no function is found, that element or -object type will simply be ignored, along with any blank line or -white space at its end. The same will happen if the function -returns the nil value. If that function returns the empty -string, the type will be ignored, but the blank lines or white -spaces will be kept. - -In addition to element and object types, one function can be -associated to the `template' symbol and another one to the -`plain-text' symbol. - -The former returns the final transcoded string, and can be used -to add a preamble and a postamble to document's body. It must -accept two arguments: the transcoded string and the property list -containing export options. - -The latter, when defined, is to be called on every text not -recognized as an element or an object. It must accept two -arguments: the text string and the information channel. It is an -appropriate place to protect special chars relative to the -back-end. - -BODY can start with pre-defined keyword arguments. The following -keywords are understood: - - :export-block - - String, or list of strings, representing block names that - will not be parsed. This is used to specify blocks that will - contain raw code specific to the back-end. These blocks - still have to be handled by the relative `export-block' type - translator. - - :filters-alist - - Alist between filters and function, or list of functions, - specific to the back-end. See `org-export-filters-alist' for - a list of all allowed filters. Filters defined here - shouldn't make a back-end test, as it may prevent back-ends - derived from this one to behave properly. - - :options-alist - - Alist between back-end specific properties introduced in - communication channel and how their value are acquired. See - `org-export-options-alist' for more information about - structure of the values. - -As an example, here is how the `e-ascii' back-end is defined: - -\(org-export-define-backend e-ascii - \((bold . org-e-ascii-bold) - \(center-block . org-e-ascii-center-block) - \(clock . org-e-ascii-clock) - \(code . org-e-ascii-code) - \(drawer . org-e-ascii-drawer) - \(dynamic-block . org-e-ascii-dynamic-block) - \(entity . org-e-ascii-entity) - \(example-block . org-e-ascii-example-block) - \(export-block . org-e-ascii-export-block) - \(export-snippet . org-e-ascii-export-snippet) - \(fixed-width . org-e-ascii-fixed-width) - \(footnote-definition . org-e-ascii-footnote-definition) - \(footnote-reference . org-e-ascii-footnote-reference) - \(headline . org-e-ascii-headline) - \(horizontal-rule . org-e-ascii-horizontal-rule) - \(inline-src-block . org-e-ascii-inline-src-block) - \(inlinetask . org-e-ascii-inlinetask) - \(italic . org-e-ascii-italic) - \(item . org-e-ascii-item) - \(keyword . org-e-ascii-keyword) - \(latex-environment . org-e-ascii-latex-environment) - \(latex-fragment . org-e-ascii-latex-fragment) - \(line-break . org-e-ascii-line-break) - \(link . org-e-ascii-link) - \(macro . org-e-ascii-macro) - \(paragraph . org-e-ascii-paragraph) - \(plain-list . org-e-ascii-plain-list) - \(plain-text . org-e-ascii-plain-text) - \(planning . org-e-ascii-planning) - \(property-drawer . org-e-ascii-property-drawer) - \(quote-block . org-e-ascii-quote-block) - \(quote-section . org-e-ascii-quote-section) - \(radio-target . org-e-ascii-radio-target) - \(section . org-e-ascii-section) - \(special-block . org-e-ascii-special-block) - \(src-block . org-e-ascii-src-block) - \(statistics-cookie . org-e-ascii-statistics-cookie) - \(strike-through . org-e-ascii-strike-through) - \(subscript . org-e-ascii-subscript) - \(superscript . org-e-ascii-superscript) - \(table . org-e-ascii-table) - \(table-cell . org-e-ascii-table-cell) - \(table-row . org-e-ascii-table-row) - \(target . org-e-ascii-target) - \(template . org-e-ascii-template) - \(timestamp . org-e-ascii-timestamp) - \(underline . org-e-ascii-underline) - \(verbatim . org-e-ascii-verbatim) - \(verse-block . org-e-ascii-verse-block)) - :export-block \"ASCII\" - :filters-alist ((:filter-headline . org-e-ascii-filter-headline-blank-lines) - \(:filter-section . org-e-ascii-filter-headline-blank-lines)) - :options-alist ((:ascii-charset nil nil org-e-ascii-charset)))" - (declare (debug (&define name sexp [&rest [keywordp sexp]] defbody)) - (indent 1)) - (let (filters options export-block) - (while (keywordp (car body)) - (case (pop body) - (:export-block (let ((names (pop body))) - (setq export-block - (if (consp names) (mapcar 'upcase names) - (list (upcase names)))))) - (:filters-alist (setq filters (pop body))) - (:options-alist (setq options (pop body))) - (t (pop body)))) - `(progn - ;; Define translators. - (defvar ,(intern (format "org-%s-translate-alist" backend)) ',translators - "Alist between element or object types and translators.") - ;; Define options. - ,(when options - `(defconst ,(intern (format "org-%s-options-alist" backend)) ',options - ,(format "Alist between %s export properties and ways to set them. -See `org-export-options-alist' for more information on the -structure of the values." - backend))) - ;; Define filters. - ,(when filters - `(defconst ,(intern (format "org-%s-filters-alist" backend)) ',filters - "Alist between filters keywords and back-end specific filters. -See `org-export-filters-alist' for more information.")) - ;; Tell parser to not parse EXPORT-BLOCK blocks. - ,(when export-block - `(mapc - (lambda (name) - (add-to-list 'org-element-block-name-alist - `(,name . org-element-export-block-parser))) - ',export-block)) - ;; Splice in the body, if any. - ,@body))) - -(defmacro org-export-define-derived-backend (child parent &rest body) - "Create a new back-end as a variant of an existing one. - -CHILD is the name of the derived back-end. PARENT is the name of -the parent back-end. - -BODY can start with pre-defined keyword arguments. The following -keywords are understood: - - :export-block - - String, or list of strings, representing block names that - will not be parsed. This is used to specify blocks that will - contain raw code specific to the back-end. These blocks - still have to be handled by the relative `export-block' type - translator. - - :filters-alist - - Alist of filters that will overwrite or complete filters - defined in PARENT back-end. See `org-export-filters-alist' - for more a list of allowed filters. - - :options-alist - - Alist of back-end specific properties that will overwrite or - complete those defined in PARENT back-end. Refer to - `org-export-options-alist' for more information about - structure of the values. - - :translate-alist - - Alist of element and object types and transcoders that will - overwrite or complete transcode table from PARENT back-end. - Refer to `org-export-define-backend' for detailed information - about transcoders. - -As an example, here is how one could define \"my-latex\" back-end -as a variant of `e-latex' back-end with a custom template -function: - - \(org-export-define-derived-backend my-latex e-latex - :translate-alist ((template . my-latex-template-fun))) - -The back-end could then be called with, for example: - - \(org-export-to-buffer 'my-latex \"*Test my-latex*\")" - (declare (debug (&define name sexp [&rest [keywordp sexp]] def-body)) - (indent 2)) - (let (filters options translate export-block) - (while (keywordp (car body)) - (case (pop body) - (:export-block (let ((names (pop body))) - (setq export-block - (if (consp names) (mapcar 'upcase names) - (list (upcase names)))))) - (:filters-alist (setq filters (pop body))) - (:options-alist (setq options (pop body))) - (:translate-alist (setq translate (pop body))) - (t (pop body)))) - `(progn - ;; Tell parser to not parse EXPORT-BLOCK blocks. - ,(when export-block - `(mapc - (lambda (name) - (add-to-list 'org-element-block-name-alist - `(,name . org-element-export-block-parser))) - ',export-block)) - ;; Define filters. - ,(let ((parent-filters (intern (format "org-%s-filters-alist" parent)))) - (when (or (boundp parent-filters) filters) - `(defconst ,(intern (format "org-%s-filters-alist" child)) - ',(append filters - (and (boundp parent-filters) - (copy-sequence (symbol-value parent-filters)))) - "Alist between filters keywords and back-end specific filters. -See `org-export-filters-alist' for more information."))) - ;; Define options. - ,(let ((parent-options (intern (format "org-%s-options-alist" parent)))) - (when (or (boundp parent-options) options) - `(defconst ,(intern (format "org-%s-options-alist" child)) - ',(append options - (and (boundp parent-options) - (copy-sequence (symbol-value parent-options)))) - ,(format "Alist between %s export properties and ways to set them. -See `org-export-options-alist' for more information on the -structure of the values." - child)))) - ;; Define translators. - (defvar ,(intern (format "org-%s-translate-alist" child)) - ',(append translate - (copy-sequence - (symbol-value - (intern (format "org-%s-translate-alist" parent))))) - "Alist between element or object types and translators.") - ;; Splice in the body, if any. - ,@body))) - - - -;;; The Communication Channel -;; -;; During export process, every function has access to a number of -;; properties. They are of two types: -;; -;; 1. Environment options are collected once at the very beginning of -;; the process, out of the original buffer and configuration. -;; Collecting them is handled by `org-export-get-environment' -;; function. -;; -;; Most environment options are defined through the -;; `org-export-options-alist' variable. -;; -;; 2. Tree properties are extracted directly from the parsed tree, -;; just before export, by `org-export-collect-tree-properties'. -;; -;; Here is the full list of properties available during transcode -;; process, with their category (option, tree or local) and their -;; value type. -;; -;; + `:author' :: Author's name. -;; - category :: option -;; - type :: string -;; -;; + `:back-end' :: Current back-end used for transcoding. -;; - category :: tree -;; - type :: symbol -;; -;; + `:creator' :: String to write as creation information. -;; - category :: option -;; - type :: string -;; -;; + `:date' :: String to use as date. -;; - category :: option -;; - type :: string -;; -;; + `:description' :: Description text for the current data. -;; - category :: option -;; - type :: string -;; -;; + `:email' :: Author's email. -;; - category :: option -;; - type :: string -;; -;; + `:exclude-tags' :: Tags for exclusion of subtrees from export -;; process. -;; - category :: option -;; - type :: list of strings -;; -;; + `:exported-data' :: Hash table used for memoizing -;; `org-export-data'. -;; - category :: tree -;; - type :: hash table -;; -;; + `:footnote-definition-alist' :: Alist between footnote labels and -;; their definition, as parsed data. Only non-inlined footnotes -;; are represented in this alist. Also, every definition isn't -;; guaranteed to be referenced in the parse tree. The purpose of -;; this property is to preserve definitions from oblivion -;; (i.e. when the parse tree comes from a part of the original -;; buffer), it isn't meant for direct use in a back-end. To -;; retrieve a definition relative to a reference, use -;; `org-export-get-footnote-definition' instead. -;; - category :: option -;; - type :: alist (STRING . LIST) -;; -;; + `:headline-levels' :: Maximum level being exported as an -;; headline. Comparison is done with the relative level of -;; headlines in the parse tree, not necessarily with their -;; actual level. -;; - category :: option -;; - type :: integer -;; -;; + `:headline-offset' :: Difference between relative and real level -;; of headlines in the parse tree. For example, a value of -1 -;; means a level 2 headline should be considered as level -;; 1 (cf. `org-export-get-relative-level'). -;; - category :: tree -;; - type :: integer -;; -;; + `:headline-numbering' :: Alist between headlines and their -;; numbering, as a list of numbers -;; (cf. `org-export-get-headline-number'). -;; - category :: tree -;; - type :: alist (INTEGER . LIST) -;; -;; + `:id-alist' :: Alist between ID strings and destination file's -;; path, relative to current directory. It is used by -;; `org-export-resolve-id-link' to resolve ID links targeting an -;; external file. -;; - category :: option -;; - type :: alist (STRING . STRING) -;; -;; + `:ignore-list' :: List of elements and objects that should be -;; ignored during export. -;; - category :: tree -;; - type :: list of elements and objects -;; -;; + `:input-file' :: Full path to input file, if any. -;; - category :: option -;; - type :: string or nil -;; -;; + `:keywords' :: List of keywords attached to data. -;; - category :: option -;; - type :: string -;; -;; + `:language' :: Default language used for translations. -;; - category :: option -;; - type :: string -;; -;; + `:parse-tree' :: Whole parse tree, available at any time during -;; transcoding. -;; - category :: option -;; - type :: list (as returned by `org-element-parse-buffer') -;; -;; + `:preserve-breaks' :: Non-nil means transcoding should preserve -;; all line breaks. -;; - category :: option -;; - type :: symbol (nil, t) -;; -;; + `:section-numbers' :: Non-nil means transcoding should add -;; section numbers to headlines. -;; - category :: option -;; - type :: symbol (nil, t) -;; -;; + `:select-tags' :: List of tags enforcing inclusion of sub-trees -;; in transcoding. When such a tag is present, subtrees without -;; it are de facto excluded from the process. See -;; `use-select-tags'. -;; - category :: option -;; - type :: list of strings -;; -;; + `:target-list' :: List of targets encountered in the parse tree. -;; This is used to partly resolve "fuzzy" links -;; (cf. `org-export-resolve-fuzzy-link'). -;; - category :: tree -;; - type :: list of strings -;; -;; + `:time-stamp-file' :: Non-nil means transcoding should insert -;; a time stamp in the output. -;; - category :: option -;; - type :: symbol (nil, t) -;; -;; + `:translate-alist' :: Alist between element and object types and -;; transcoding functions relative to the current back-end. -;; Special keys `template' and `plain-text' are also possible. -;; - category :: option -;; - type :: alist (SYMBOL . FUNCTION) -;; -;; + `:with-archived-trees' :: Non-nil when archived subtrees should -;; also be transcoded. If it is set to the `headline' symbol, -;; only the archived headline's name is retained. -;; - category :: option -;; - type :: symbol (nil, t, `headline') -;; -;; + `:with-author' :: Non-nil means author's name should be included -;; in the output. -;; - category :: option -;; - type :: symbol (nil, t) -;; -;; + `:with-clocks' :: Non-nild means clock keywords should be exported. -;; - category :: option -;; - type :: symbol (nil, t) -;; -;; + `:with-creator' :: Non-nild means a creation sentence should be -;; inserted at the end of the transcoded string. If the value -;; is `comment', it should be commented. -;; - category :: option -;; - type :: symbol (`comment', nil, t) -;; -;; + `:with-drawers' :: Non-nil means drawers should be exported. If -;; its value is a list of names, only drawers with such names -;; will be transcoded. -;; - category :: option -;; - type :: symbol (nil, t) or list of strings -;; -;; + `:with-email' :: Non-nil means output should contain author's -;; email. -;; - category :: option -;; - type :: symbol (nil, t) -;; -;; + `:with-emphasize' :: Non-nil means emphasized text should be -;; interpreted. -;; - category :: option -;; - type :: symbol (nil, t) -;; -;; + `:with-fixed-width' :: Non-nil if transcoder should interpret -;; strings starting with a colon as a fixed-with (verbatim) area. -;; - category :: option -;; - type :: symbol (nil, t) -;; -;; + `:with-footnotes' :: Non-nil if transcoder should interpret -;; footnotes. -;; - category :: option -;; - type :: symbol (nil, t) -;; -;; + `:with-plannings' :: Non-nil means transcoding should include -;; planning info. -;; - category :: option -;; - type :: symbol (nil, t) -;; -;; + `:with-priority' :: Non-nil means transcoding should include -;; priority cookies. -;; - category :: option -;; - type :: symbol (nil, t) -;; -;; + `:with-special-strings' :: Non-nil means transcoding should -;; interpret special strings in plain text. -;; - category :: option -;; - type :: symbol (nil, t) -;; -;; + `:with-sub-superscript' :: Non-nil means transcoding should -;; interpret subscript and superscript. With a value of "{}", -;; only interpret those using curly brackets. -;; - category :: option -;; - type :: symbol (nil, {}, t) -;; -;; + `:with-tables' :: Non-nil means transcoding should interpret -;; tables. -;; - category :: option -;; - type :: symbol (nil, t) -;; -;; + `:with-tags' :: Non-nil means transcoding should keep tags in -;; headlines. A `not-in-toc' value will remove them from the -;; table of contents, if any, nonetheless. -;; - category :: option -;; - type :: symbol (nil, t, `not-in-toc') -;; -;; + `:with-tasks' :: Non-nil means transcoding should include -;; headlines with a TODO keyword. A `todo' value will only -;; include headlines with a todo type keyword while a `done' -;; value will do the contrary. If a list of strings is provided, -;; only tasks with keywords belonging to that list will be kept. -;; - category :: option -;; - type :: symbol (t, todo, done, nil) or list of strings -;; -;; + `:with-timestamps' :: Non-nil means transcoding should include -;; time stamps. Special value `active' (resp. `inactive') ask to -;; export only active (resp. inactive) timestamps. Otherwise, -;; completely remove them. -;; - category :: option -;; - type :: symbol: (`active', `inactive', t, nil) -;; -;; + `:with-toc' :: Non-nil means that a table of contents has to be -;; added to the output. An integer value limits its depth. -;; - category :: option -;; - type :: symbol (nil, t or integer) -;; -;; + `:with-todo-keywords' :: Non-nil means transcoding should -;; include TODO keywords. -;; - category :: option -;; - type :: symbol (nil, t) - - -;;;; Environment Options -;; -;; Environment options encompass all parameters defined outside the -;; scope of the parsed data. They come from five sources, in -;; increasing precedence order: -;; -;; - Global variables, -;; - Buffer's attributes, -;; - Options keyword symbols, -;; - Buffer keywords, -;; - Subtree properties. -;; -;; The central internal function with regards to environment options -;; is `org-export-get-environment'. It updates global variables with -;; "#+BIND:" keywords, then retrieve and prioritize properties from -;; the different sources. -;; -;; The internal functions doing the retrieval are: -;; `org-export--get-global-options', -;; `org-export--get-buffer-attributes', -;; `org-export--parse-option-keyword', -;; `org-export--get-subtree-options' and -;; `org-export--get-inbuffer-options' -;; -;; Also, `org-export--confirm-letbind' and `org-export--install-letbind' -;; take care of the part relative to "#+BIND:" keywords. - -(defun org-export-get-environment (&optional backend subtreep ext-plist) - "Collect export options from the current buffer. - -Optional argument BACKEND is a symbol specifying which back-end -specific options to read, if any. - -When optional argument SUBTREEP is non-nil, assume the export is -done against the current sub-tree. - -Third optional argument EXT-PLIST is a property list with -external parameters overriding Org default settings, but still -inferior to file-local settings." - ;; First install #+BIND variables. - (org-export--install-letbind-maybe) - ;; Get and prioritize export options... - (org-combine-plists - ;; ... from global variables... - (org-export--get-global-options backend) - ;; ... from buffer's attributes... - (org-export--get-buffer-attributes) - ;; ... from an external property list... - ext-plist - ;; ... from in-buffer settings... - (org-export--get-inbuffer-options - backend - (and buffer-file-name (org-remove-double-quotes buffer-file-name))) - ;; ... and from subtree, when appropriate. - (and subtreep (org-export--get-subtree-options backend)) - ;; Eventually install back-end symbol and its translation table. - `(:back-end - ,backend - :translate-alist - ,(let ((trans-alist (intern (format "org-%s-translate-alist" backend)))) - (when (boundp trans-alist) (symbol-value trans-alist)))))) - -(defun org-export--parse-option-keyword (options &optional backend) - "Parse an OPTIONS line and return values as a plist. -Optional argument BACKEND is a symbol specifying which back-end -specific items to read, if any." - (let* ((all - (append org-export-options-alist - (and backend - (let ((var (intern - (format "org-%s-options-alist" backend)))) - (and (boundp var) (eval var)))))) - ;; Build an alist between #+OPTION: item and property-name. - (alist (delq nil - (mapcar (lambda (e) - (when (nth 2 e) (cons (regexp-quote (nth 2 e)) - (car e)))) - all))) - plist) - (mapc (lambda (e) - (when (string-match (concat "\\(\\`\\|[ \t]\\)" - (car e) - ":\\(([^)\n]+)\\|[^ \t\n\r;,.]*\\)") - options) - (setq plist (plist-put plist - (cdr e) - (car (read-from-string - (match-string 2 options))))))) - alist) - plist)) - -(defun org-export--get-subtree-options (&optional backend) - "Get export options in subtree at point. -Optional argument BACKEND is a symbol specifying back-end used -for export. Return options as a plist." - ;; For each buffer keyword, create an headline property setting the - ;; same property in communication channel. The name for the property - ;; is the keyword with "EXPORT_" appended to it. - (org-with-wide-buffer - (let (prop plist) - ;; Make sure point is at an heading. - (unless (org-at-heading-p) (org-back-to-heading t)) - ;; Take care of EXPORT_TITLE. If it isn't defined, use headline's - ;; title as its fallback value. - (when (setq prop (progn (looking-at org-todo-line-regexp) - (or (save-match-data - (org-entry-get (point) "EXPORT_TITLE")) - (org-match-string-no-properties 3)))) - (setq plist - (plist-put - plist :title - (org-element-parse-secondary-string - prop (org-element-restriction 'keyword))))) - ;; EXPORT_OPTIONS are parsed in a non-standard way. - (when (setq prop (org-entry-get (point) "EXPORT_OPTIONS")) - (setq plist - (nconc plist (org-export--parse-option-keyword prop backend)))) - ;; Handle other keywords. - (let ((seen '("TITLE"))) - (mapc - (lambda (option) - (let ((property (nth 1 option))) - (when (and property (not (member property seen))) - (let* ((subtree-prop (concat "EXPORT_" property)) - ;; Export properties are not case-sensitive. - (value (let ((case-fold-search t)) - (org-entry-get (point) subtree-prop)))) - (push property seen) - (when value - (setq plist - (plist-put - plist - (car option) - ;; Parse VALUE if required. - (if (member property org-element-parsed-keywords) - (org-element-parse-secondary-string - value (org-element-restriction 'keyword)) - value)))))))) - ;; Also look for both general keywords and back-end specific - ;; options if BACKEND is provided. - (append (and backend - (let ((var (intern - (format "org-%s-options-alist" backend)))) - (and (boundp var) (symbol-value var)))) - org-export-options-alist))) - ;; Return value. - plist))) - -(defun org-export--get-inbuffer-options (&optional backend files) - "Return current buffer export options, as a plist. - -Optional argument BACKEND, when non-nil, is a symbol specifying -which back-end specific options should also be read in the -process. - -Optional argument FILES is a list of setup files names read so -far, used to avoid circular dependencies. - -Assume buffer is in Org mode. Narrowing, if any, is ignored." - (org-with-wide-buffer - (goto-char (point-min)) - (let ((case-fold-search t) plist) - ;; 1. Special keywords, as in `org-export-special-keywords'. - (let ((special-re (org-make-options-regexp org-export-special-keywords))) - (while (re-search-forward special-re nil t) - (let ((element (org-element-at-point))) - (when (eq (org-element-type element) 'keyword) - (let* ((key (org-element-property :key element)) - (val (org-element-property :value element)) - (prop - (cond - ((string= key "SETUP_FILE") - (let ((file - (expand-file-name - (org-remove-double-quotes (org-trim val))))) - ;; Avoid circular dependencies. - (unless (member file files) - (with-temp-buffer - (insert (org-file-contents file 'noerror)) - (org-mode) - (org-export--get-inbuffer-options - backend (cons file files)))))) - ((string= key "OPTIONS") - (org-export--parse-option-keyword val backend)) - ((string= key "MACRO") - (when (string-match - "^\\([-a-zA-Z0-9_]+\\)\\(?:[ \t]+\\(.*?\\)[ \t]*$\\)?" - val) - (let ((key - (intern - (concat ":macro-" - (downcase (match-string 1 val))))) - (value (org-match-string-no-properties 2 val))) - (cond - ((not value) nil) - ;; Value will be evaled: do not parse it. - ((string-match "\\`(eval\\>" value) - (list key (list value))) - ;; Value has to be parsed for nested - ;; macros. - (t - (list - key - (let ((restr (org-element-restriction 'macro))) - (org-element-parse-secondary-string - ;; If user explicitly asks for - ;; a newline, be sure to preserve it - ;; from further filling with - ;; `hard-newline'. Also replace - ;; "\\n" with "\n", "\\\n" with "\\n" - ;; and so on... - (replace-regexp-in-string - "\\(\\\\\\\\\\)n" "\\\\" - (replace-regexp-in-string - "\\(?:^\\|[^\\\\]\\)\\(\\\\n\\)" - hard-newline value nil nil 1) - nil nil 1) - restr))))))))))) - (setq plist (org-combine-plists plist prop))))))) - ;; 2. Standard options, as in `org-export-options-alist'. - (let* ((all (append org-export-options-alist - ;; Also look for back-end specific options - ;; if BACKEND is defined. - (and backend - (let ((var - (intern - (format "org-%s-options-alist" backend)))) - (and (boundp var) (eval var)))))) - ;; Build alist between keyword name and property name. - (alist - (delq nil (mapcar - (lambda (e) (when (nth 1 e) (cons (nth 1 e) (car e)))) - all))) - ;; Build regexp matching all keywords associated to export - ;; options. Note: the search is case insensitive. - (opt-re (org-make-options-regexp - (delq nil (mapcar (lambda (e) (nth 1 e)) all))))) - (goto-char (point-min)) - (while (re-search-forward opt-re nil t) - (let ((element (org-element-at-point))) - (when (eq (org-element-type element) 'keyword) - (let* ((key (org-element-property :key element)) - (val (org-element-property :value element)) - (prop (cdr (assoc key alist))) - (behaviour (nth 4 (assq prop all)))) - (setq plist - (plist-put - plist prop - ;; Handle value depending on specified BEHAVIOUR. - (case behaviour - (space - (if (not (plist-get plist prop)) (org-trim val) - (concat (plist-get plist prop) " " (org-trim val)))) - (newline - (org-trim - (concat (plist-get plist prop) "\n" (org-trim val)))) - (split - `(,@(plist-get plist prop) ,@(org-split-string val))) - ('t val) - (otherwise (if (not (plist-member plist prop)) val - (plist-get plist prop)))))))))) - ;; Parse keywords specified in `org-element-parsed-keywords'. - (mapc - (lambda (key) - (let* ((prop (cdr (assoc key alist))) - (value (and prop (plist-get plist prop)))) - (when (stringp value) - (setq plist - (plist-put - plist prop - (org-element-parse-secondary-string - value (org-element-restriction 'keyword))))))) - org-element-parsed-keywords)) - ;; 3. Return final value. - plist))) - -(defun org-export--get-buffer-attributes () - "Return properties related to buffer attributes, as a plist." - (let ((visited-file (buffer-file-name (buffer-base-buffer)))) - (list - ;; Store full path of input file name, or nil. For internal use. - :input-file visited-file - :title (or (and visited-file - (file-name-sans-extension - (file-name-nondirectory visited-file))) - (buffer-name (buffer-base-buffer))) - :footnote-definition-alist - ;; Footnotes definitions must be collected in the original - ;; buffer, as there's no insurance that they will still be in the - ;; parse tree, due to possible narrowing. - (let (alist) - (org-with-wide-buffer - (goto-char (point-min)) - (while (re-search-forward org-footnote-definition-re nil t) - (let ((def (org-footnote-at-definition-p))) - (when def - (org-skip-whitespace) - (push (cons (car def) - (save-restriction - (narrow-to-region (point) (nth 2 def)) - ;; Like `org-element-parse-buffer', but - ;; makes sure the definition doesn't start - ;; with a section element. - (org-element--parse-elements - (point-min) (point-max) nil nil nil nil - (list 'org-data nil)))) - alist)))) - alist)) - :id-alist - ;; Collect id references. - (let (alist) - (org-with-wide-buffer - (goto-char (point-min)) - (while (re-search-forward - "\\[\\[id:\\(\\S-+?\\)\\]\\(?:\\[.*?\\]\\)?\\]" nil t) - (let* ((id (org-match-string-no-properties 1)) - (file (org-id-find-id-file id))) - (when file (push (cons id (file-relative-name file)) alist))))) - alist) - :macro-modification-time - (and visited-file - (file-exists-p visited-file) - (concat "(eval (format-time-string \"$1\" '" - (prin1-to-string (nth 5 (file-attributes visited-file))) - "))")) - ;; Store input file name as a macro. - :macro-input-file (and visited-file (file-name-nondirectory visited-file)) - ;; `:macro-date', `:macro-time' and `:macro-property' could as - ;; well be initialized as tree properties, since they don't - ;; depend on buffer properties. Though, it may be more logical - ;; to keep them close to other ":macro-" properties. - :macro-date "(eval (format-time-string \"$1\"))" - :macro-time "(eval (format-time-string \"$1\"))" - :macro-property "(eval (org-entry-get nil \"$1\" 'selective))"))) - -(defun org-export--get-global-options (&optional backend) - "Return global export options as a plist. - -Optional argument BACKEND, if non-nil, is a symbol specifying -which back-end specific export options should also be read in the -process." - (let ((all (append org-export-options-alist - (and backend - (let ((var (intern - (format "org-%s-options-alist" backend)))) - (and (boundp var) (symbol-value var)))))) - ;; Output value. - plist) - (mapc - (lambda (cell) - (setq plist - (plist-put - plist - (car cell) - ;; Eval default value provided. If keyword is a member - ;; of `org-element-parsed-keywords', parse it as - ;; a secondary string before storing it. - (let ((value (eval (nth 3 cell)))) - (if (not (stringp value)) value - (let ((keyword (nth 1 cell))) - (if (not (member keyword org-element-parsed-keywords)) value - (org-element-parse-secondary-string - value (org-element-restriction 'keyword))))))))) - all) - ;; Return value. - plist)) - -(defvar org-export--allow-BIND-local nil) -(defun org-export--confirm-letbind () - "Can we use #+BIND values during export? -By default this will ask for confirmation by the user, to divert -possible security risks." - (cond - ((not org-export-allow-BIND) nil) - ((eq org-export-allow-BIND t) t) - ((local-variable-p 'org-export--allow-BIND-local) - org-export--allow-BIND-local) - (t (org-set-local 'org-export--allow-BIND-local - (yes-or-no-p "Allow BIND values in this buffer? "))))) - -(defun org-export--install-letbind-maybe () - "Install the values from #+BIND lines as local variables. -Variables must be installed before in-buffer options are -retrieved." - (let (letbind pair) - (org-with-wide-buffer - (goto-char (point-min)) - (while (re-search-forward (org-make-options-regexp '("BIND")) nil t) - (when (org-export-confirm-letbind) - (push (read (concat "(" (org-match-string-no-properties 2) ")")) - letbind)))) - (while (setq pair (pop letbind)) - (org-set-local (car pair) (nth 1 pair))))) - - -;;;; Tree Properties -;; -;; Tree properties are infromation extracted from parse tree. They -;; are initialized at the beginning of the transcoding process by -;; `org-export-collect-tree-properties'. -;; -;; Dedicated functions focus on computing the value of specific tree -;; properties during initialization. Thus, -;; `org-export--populate-ignore-list' lists elements and objects that -;; should be skipped during export, `org-export--get-min-level' gets -;; the minimal exportable level, used as a basis to compute relative -;; level for headlines. Eventually -;; `org-export--collect-headline-numbering' builds an alist between -;; headlines and their numbering. - -(defun org-export-collect-tree-properties (data info) - "Extract tree properties from parse tree. - -DATA is the parse tree from which information is retrieved. INFO -is a list holding export options. - -Following tree properties are set or updated: - -`:exported-data' Hash table used to memoize results from - `org-export-data'. - -`:footnote-definition-alist' List of footnotes definitions in - original buffer and current parse tree. - -`:headline-offset' Offset between true level of headlines and - local level. An offset of -1 means an headline - of level 2 should be considered as a level - 1 headline in the context. - -`:headline-numbering' Alist of all headlines as key an the - associated numbering as value. - -`:ignore-list' List of elements that should be ignored during - export. - -`:target-list' List of all targets in the parse tree. - -Return updated plist." - ;; Install the parse tree in the communication channel, in order to - ;; use `org-export-get-genealogy' and al. - (setq info (plist-put info :parse-tree data)) - ;; Get the list of elements and objects to ignore, and put it into - ;; `:ignore-list'. Do not overwrite any user ignore that might have - ;; been done during parse tree filtering. - (setq info - (plist-put info - :ignore-list - (append (org-export--populate-ignore-list data info) - (plist-get info :ignore-list)))) - ;; Compute `:headline-offset' in order to be able to use - ;; `org-export-get-relative-level'. - (setq info - (plist-put info - :headline-offset - (- 1 (org-export--get-min-level data info)))) - ;; Update footnotes definitions list with definitions in parse tree. - ;; This is required since buffer expansion might have modified - ;; boundaries of footnote definitions contained in the parse tree. - ;; This way, definitions in `footnote-definition-alist' are bound to - ;; match those in the parse tree. - (let ((defs (plist-get info :footnote-definition-alist))) - (org-element-map - data 'footnote-definition - (lambda (fn) - (push (cons (org-element-property :label fn) - `(org-data nil ,@(org-element-contents fn))) - defs))) - (setq info (plist-put info :footnote-definition-alist defs))) - ;; Properties order doesn't matter: get the rest of the tree - ;; properties. - (nconc - `(:target-list - ,(org-element-map - data '(keyword target) - (lambda (blob) - (when (or (eq (org-element-type blob) 'target) - (string= (org-element-property :key blob) "TARGET")) - blob)) info) - :headline-numbering ,(org-export--collect-headline-numbering data info) - :exported-data ,(make-hash-table :test 'eq :size 4001)) - info)) - -(defun org-export--get-min-level (data options) - "Return minimum exportable headline's level in DATA. -DATA is parsed tree as returned by `org-element-parse-buffer'. -OPTIONS is a plist holding export options." - (catch 'exit - (let ((min-level 10000)) - (mapc - (lambda (blob) - (when (and (eq (org-element-type blob) 'headline) - (not (memq blob (plist-get options :ignore-list)))) - (setq min-level - (min (org-element-property :level blob) min-level))) - (when (= min-level 1) (throw 'exit 1))) - (org-element-contents data)) - ;; If no headline was found, for the sake of consistency, set - ;; minimum level to 1 nonetheless. - (if (= min-level 10000) 1 min-level)))) - -(defun org-export--collect-headline-numbering (data options) - "Return numbering of all exportable headlines in a parse tree. - -DATA is the parse tree. OPTIONS is the plist holding export -options. - -Return an alist whose key is an headline and value is its -associated numbering \(in the shape of a list of numbers\)." - (let ((numbering (make-vector org-export-max-depth 0))) - (org-element-map - data - 'headline - (lambda (headline) - (let ((relative-level - (1- (org-export-get-relative-level headline options)))) - (cons - headline - (loop for n across numbering - for idx from 0 to org-export-max-depth - when (< idx relative-level) collect n - when (= idx relative-level) collect (aset numbering idx (1+ n)) - when (> idx relative-level) do (aset numbering idx 0))))) - options))) - -(defun org-export--populate-ignore-list (data options) - "Return list of elements and objects to ignore during export. -DATA is the parse tree to traverse. OPTIONS is the plist holding -export options." - (let* (ignore - walk-data ; for byte-compiler. - (walk-data - (function - (lambda (data options selected) - ;; Collect ignored elements or objects into IGNORE-LIST. - (mapc - (lambda (el) - (if (org-export--skip-p el options selected) (push el ignore) - (let ((type (org-element-type el))) - (if (and (eq (plist-get options :with-archived-trees) - 'headline) - (eq (org-element-type el) 'headline) - (org-element-property :archivedp el)) - ;; If headline is archived but tree below has - ;; to be skipped, add it to ignore list. - (mapc (lambda (e) (push e ignore)) - (org-element-contents el)) - ;; Move into recursive objects/elements. - (when (org-element-contents el) - (funcall walk-data el options selected)))))) - (org-element-contents data)))))) - ;; Main call. First find trees containing a select tag, if any. - (funcall walk-data data options (org-export--selected-trees data options)) - ;; Return value. - ignore)) - -(defun org-export--selected-trees (data info) - "Return list of headlines containing a select tag in their tree. -DATA is parsed data as returned by `org-element-parse-buffer'. -INFO is a plist holding export options." - (let* (selected-trees - walk-data ; for byte-compiler. - (walk-data - (function - (lambda (data genealogy) - (case (org-element-type data) - (org-data (mapc (lambda (el) (funcall walk-data el genealogy)) - (org-element-contents data))) - (headline - (let ((tags (org-element-property :tags data))) - (if (loop for tag in (plist-get info :select-tags) - thereis (member tag tags)) - ;; When a select tag is found, mark full - ;; genealogy and every headline within the tree - ;; as acceptable. - (setq selected-trees - (append - genealogy - (org-element-map data 'headline 'identity) - selected-trees)) - ;; Else, continue searching in tree, recursively. - (mapc - (lambda (el) (funcall walk-data el (cons data genealogy))) - (org-element-contents data)))))))))) - (funcall walk-data data nil) selected-trees)) - -(defun org-export--skip-p (blob options selected) - "Non-nil when element or object BLOB should be skipped during export. -OPTIONS is the plist holding export options. SELECTED, when -non-nil, is a list of headlines belonging to a tree with a select -tag." - (case (org-element-type blob) - ;; Check headline. - (headline - (let ((with-tasks (plist-get options :with-tasks)) - (todo (org-element-property :todo-keyword blob)) - (todo-type (org-element-property :todo-type blob)) - (archived (plist-get options :with-archived-trees)) - (tags (org-element-property :tags blob))) - (or - ;; Ignore subtrees with an exclude tag. - (loop for k in (plist-get options :exclude-tags) - thereis (member k tags)) - ;; When a select tag is present in the buffer, ignore any tree - ;; without it. - (and selected (not (memq blob selected))) - ;; Ignore commented sub-trees. - (org-element-property :commentedp blob) - ;; Ignore archived subtrees if `:with-archived-trees' is nil. - (and (not archived) (org-element-property :archivedp blob)) - ;; Ignore tasks, if specified by `:with-tasks' property. - (and todo - (or (not with-tasks) - (and (memq with-tasks '(todo done)) - (not (eq todo-type with-tasks))) - (and (consp with-tasks) (not (member todo with-tasks)))))))) - ;; Check inlinetask. - (inlinetask (not (plist-get options :with-inlinetasks))) - ;; Check timestamp. - (timestamp - (case (plist-get options :with-timestamps) - ;; No timestamp allowed. - ('nil t) - ;; Only active timestamps allowed and the current one isn't - ;; active. - (active - (not (memq (org-element-property :type blob) - '(active active-range)))) - ;; Only inactive timestamps allowed and the current one isn't - ;; inactive. - (inactive - (not (memq (org-element-property :type blob) - '(inactive inactive-range)))))) - ;; Check drawer. - (drawer - (or (not (plist-get options :with-drawers)) - (and (consp (plist-get options :with-drawers)) - (not (member (org-element-property :drawer-name blob) - (plist-get options :with-drawers)))))) - ;; Check table-row. - (table-row (org-export-table-row-is-special-p blob options)) - ;; Check table-cell. - (table-cell - (and (org-export-table-has-special-column-p - (org-export-get-parent-table blob)) - (not (org-export-get-previous-element blob options)))) - ;; Check clock. - (clock (not (plist-get options :with-clocks))) - ;; Check planning. - (planning (not (plist-get options :with-plannings))))) - - - -;;; The Transcoder -;; -;; `org-export-data' reads a parse tree (obtained with, i.e. -;; `org-element-parse-buffer') and transcodes it into a specified -;; back-end output. It takes care of filtering out elements or -;; objects according to export options and organizing the output blank -;; lines and white space are preserved. The function memoizes its -;; results, so it is cheap to call it within translators. -;; -;; Internally, three functions handle the filtering of objects and -;; elements during the export. In particular, -;; `org-export-ignore-element' marks an element or object so future -;; parse tree traversals skip it, `org-export--interpret-p' tells which -;; elements or objects should be seen as real Org syntax and -;; `org-export-expand' transforms the others back into their original -;; shape -;; -;; `org-export-transcoder' is an accessor returning appropriate -;; translator function for a given element or object. - -(defun org-export-transcoder (blob info) - "Return appropriate transcoder for BLOB. -INFO is a plist containing export directives." - (let ((type (org-element-type blob))) - ;; Return contents only for complete parse trees. - (if (eq type 'org-data) (lambda (blob contents info) contents) - (let ((transcoder (cdr (assq type (plist-get info :translate-alist))))) - (and (functionp transcoder) transcoder))))) - -(defun org-export-data (data info) - "Convert DATA into current back-end format. - -DATA is a parse tree, an element or an object or a secondary -string. INFO is a plist holding export options. - -Return transcoded string." - (let ((memo (gethash data (plist-get info :exported-data) 'no-memo))) - (if (not (eq memo 'no-memo)) memo - (let* ((type (org-element-type data)) - (results - (cond - ;; Ignored element/object. - ((memq data (plist-get info :ignore-list)) nil) - ;; Plain text. - ((eq type 'plain-text) - (org-export-filter-apply-functions - (plist-get info :filter-plain-text) - (let ((transcoder (org-export-transcoder data info))) - (if transcoder (funcall transcoder data info) data)) - info)) - ;; Uninterpreted element/object: change it back to Org - ;; syntax and export again resulting raw string. - ((not (org-export--interpret-p data info)) - (org-export-data - (org-export-expand - data - (mapconcat (lambda (blob) (org-export-data blob info)) - (org-element-contents data) - "")) - info)) - ;; Secondary string. - ((not type) - (mapconcat (lambda (obj) (org-export-data obj info)) data "")) - ;; Element/Object without contents or, as a special case, - ;; headline with archive tag and archived trees restricted - ;; to title only. - ((or (not (org-element-contents data)) - (and (eq type 'headline) - (eq (plist-get info :with-archived-trees) 'headline) - (org-element-property :archivedp data))) - (let ((transcoder (org-export-transcoder data info))) - (and (functionp transcoder) - (funcall transcoder data nil info)))) - ;; Element/Object with contents. - (t - (let ((transcoder (org-export-transcoder data info))) - (when transcoder - (let* ((greaterp (memq type org-element-greater-elements)) - (objectp - (and (not greaterp) - (memq type org-element-recursive-objects))) - (contents - (mapconcat - (lambda (element) (org-export-data element info)) - (org-element-contents - (if (or greaterp objectp) data - ;; Elements directly containing objects - ;; must have their indentation normalized - ;; first. - (org-element-normalize-contents - data - ;; When normalizing contents of the first - ;; paragraph in an item or a footnote - ;; definition, ignore first line's - ;; indentation: there is none and it - ;; might be misleading. - (when (eq type 'paragraph) - (let ((parent (org-export-get-parent data))) - (and - (eq (car (org-element-contents parent)) - data) - (memq (org-element-type parent) - '(footnote-definition item)))))))) - ""))) - (funcall transcoder data - (if (not greaterp) contents - (org-element-normalize-string contents)) - info)))))))) - ;; Final result will be memoized before being returned. - (puthash - data - (cond - ((not results) nil) - ((memq type '(org-data plain-text nil)) results) - ;; Append the same white space between elements or objects as in - ;; the original buffer, and call appropriate filters. - (t - (let ((results - (org-export-filter-apply-functions - (plist-get info (intern (format ":filter-%s" type))) - (let ((post-blank (or (org-element-property :post-blank data) - 0))) - (if (memq type org-element-all-elements) - (concat (org-element-normalize-string results) - (make-string post-blank ?\n)) - (concat results (make-string post-blank ? )))) - info))) - results))) - (plist-get info :exported-data)))))) - -(defun org-export--interpret-p (blob info) - "Non-nil if element or object BLOB should be interpreted as Org syntax. -Check is done according to export options INFO, stored as -a plist." - (case (org-element-type blob) - ;; ... entities... - (entity (plist-get info :with-entities)) - ;; ... emphasis... - (emphasis (plist-get info :with-emphasize)) - ;; ... fixed-width areas. - (fixed-width (plist-get info :with-fixed-width)) - ;; ... footnotes... - ((footnote-definition footnote-reference) - (plist-get info :with-footnotes)) - ;; ... sub/superscripts... - ((subscript superscript) - (let ((sub/super-p (plist-get info :with-sub-superscript))) - (if (eq sub/super-p '{}) - (org-element-property :use-brackets-p blob) - sub/super-p))) - ;; ... tables... - (table (plist-get info :with-tables)) - (otherwise t))) - -(defun org-export-expand (blob contents) - "Expand a parsed element or object to its original state. -BLOB is either an element or an object. CONTENTS is its -contents, as a string or nil." - (funcall - (intern (format "org-element-%s-interpreter" (org-element-type blob))) - blob contents)) - -(defun org-export-ignore-element (element info) - "Add ELEMENT to `:ignore-list' in INFO. - -Any element in `:ignore-list' will be skipped when using -`org-element-map'. INFO is modified by side effects." - (plist-put info :ignore-list (cons element (plist-get info :ignore-list)))) - - - -;;; The Filter System -;; -;; Filters allow end-users to tweak easily the transcoded output. -;; They are the functional counterpart of hooks, as every filter in -;; a set is applied to the return value of the previous one. -;; -;; Every set is back-end agnostic. Although, a filter is always -;; called, in addition to the string it applies to, with the back-end -;; used as argument, so it's easy for the end-user to add back-end -;; specific filters in the set. The communication channel, as -;; a plist, is required as the third argument. -;; -;; From the developer side, filters sets can be installed in the -;; process with the help of `org-export-define-backend', which -;; internally sets `org-BACKEND-filters-alist' variable. Each -;; association has a key among the following symbols and a function or -;; a list of functions as value. -;; -;; - `:filter-parse-tree' applies directly on the complete parsed -;; tree. It's the only filters set that doesn't apply to a string. -;; Users can set it through `org-export-filter-parse-tree-functions' -;; variable. -;; -;; - `:filter-final-output' applies to the final transcoded string. -;; Users can set it with `org-export-filter-final-output-functions' -;; variable -;; -;; - `:filter-plain-text' applies to any string not recognized as Org -;; syntax. `org-export-filter-plain-text-functions' allows users to -;; configure it. -;; -;; - `:filter-TYPE' applies on the string returned after an element or -;; object of type TYPE has been transcoded. An user can modify -;; `org-export-filter-TYPE-functions' -;; -;; All filters sets are applied with -;; `org-export-filter-apply-functions' function. Filters in a set are -;; applied in a LIFO fashion. It allows developers to be sure that -;; their filters will be applied first. -;; -;; Filters properties are installed in communication channel with -;; `org-export-install-filters' function. -;; -;; Eventually, a hook (`org-export-before-parsing-hook') is run just -;; before parsing to allow for heavy structure modifications. - - -;;;; Before Parsing Hook - -(defvar org-export-before-parsing-hook nil - "Hook run before parsing an export buffer. - -This is run after include keywords have been expanded and Babel -code executed, on a copy of original buffer's area being -exported. Visibility is the same as in the original one. Point -is left at the beginning of the new one. - -Every function in this hook will be called with one argument: the -back-end currently used, as a symbol.") - - -;;;; Special Filters - -(defvar org-export-filter-parse-tree-functions nil - "List of functions applied to the parsed tree. -Each filter is called with three arguments: the parse tree, as -returned by `org-element-parse-buffer', the back-end, as -a symbol, and the communication channel, as a plist. It must -return the modified parse tree to transcode.") - -(defvar org-export-filter-final-output-functions nil - "List of functions applied to the transcoded string. -Each filter is called with three arguments: the full transcoded -string, the back-end, as a symbol, and the communication channel, -as a plist. It must return a string that will be used as the -final export output.") - -(defvar org-export-filter-plain-text-functions nil - "List of functions applied to plain text. -Each filter is called with three arguments: a string which -contains no Org syntax, the back-end, as a symbol, and the -communication channel, as a plist. It must return a string or -nil.") - - -;;;; Elements Filters - -(defvar org-export-filter-center-block-functions nil - "List of functions applied to a transcoded center block. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-clock-functions nil - "List of functions applied to a transcoded clock. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-drawer-functions nil - "List of functions applied to a transcoded drawer. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-dynamic-block-functions nil - "List of functions applied to a transcoded dynamic-block. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-headline-functions nil - "List of functions applied to a transcoded headline. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-inlinetask-functions nil - "List of functions applied to a transcoded inlinetask. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-plain-list-functions nil - "List of functions applied to a transcoded plain-list. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-item-functions nil - "List of functions applied to a transcoded item. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-comment-functions nil - "List of functions applied to a transcoded comment. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-comment-block-functions nil - "List of functions applied to a transcoded comment-comment. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-example-block-functions nil - "List of functions applied to a transcoded example-block. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-export-block-functions nil - "List of functions applied to a transcoded export-block. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-fixed-width-functions nil - "List of functions applied to a transcoded fixed-width. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-footnote-definition-functions nil - "List of functions applied to a transcoded footnote-definition. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-horizontal-rule-functions nil - "List of functions applied to a transcoded horizontal-rule. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-keyword-functions nil - "List of functions applied to a transcoded keyword. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-latex-environment-functions nil - "List of functions applied to a transcoded latex-environment. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-babel-call-functions nil - "List of functions applied to a transcoded babel-call. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-paragraph-functions nil - "List of functions applied to a transcoded paragraph. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-planning-functions nil - "List of functions applied to a transcoded planning. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-property-drawer-functions nil - "List of functions applied to a transcoded property-drawer. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-quote-block-functions nil - "List of functions applied to a transcoded quote block. -Each filter is called with three arguments: the transcoded quote -data, as a string, the back-end, as a symbol, and the -communication channel, as a plist. It must return a string or -nil.") - -(defvar org-export-filter-quote-section-functions nil - "List of functions applied to a transcoded quote-section. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-section-functions nil - "List of functions applied to a transcoded section. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-special-block-functions nil - "List of functions applied to a transcoded special block. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-src-block-functions nil - "List of functions applied to a transcoded src-block. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-table-functions nil - "List of functions applied to a transcoded table. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-table-cell-functions nil - "List of functions applied to a transcoded table-cell. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-table-row-functions nil - "List of functions applied to a transcoded table-row. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-verse-block-functions nil - "List of functions applied to a transcoded verse block. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - - -;;;; Objects Filters - -(defvar org-export-filter-bold-functions nil - "List of functions applied to transcoded bold text. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-code-functions nil - "List of functions applied to transcoded code text. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-entity-functions nil - "List of functions applied to a transcoded entity. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-export-snippet-functions nil - "List of functions applied to a transcoded export-snippet. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-footnote-reference-functions nil - "List of functions applied to a transcoded footnote-reference. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-inline-babel-call-functions nil - "List of functions applied to a transcoded inline-babel-call. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-inline-src-block-functions nil - "List of functions applied to a transcoded inline-src-block. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-italic-functions nil - "List of functions applied to transcoded italic text. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-latex-fragment-functions nil - "List of functions applied to a transcoded latex-fragment. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-line-break-functions nil - "List of functions applied to a transcoded line-break. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-link-functions nil - "List of functions applied to a transcoded link. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-macro-functions nil - "List of functions applied to a transcoded macro. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-radio-target-functions nil - "List of functions applied to a transcoded radio-target. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-statistics-cookie-functions nil - "List of functions applied to a transcoded statistics-cookie. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-strike-through-functions nil - "List of functions applied to transcoded strike-through text. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-subscript-functions nil - "List of functions applied to a transcoded subscript. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-superscript-functions nil - "List of functions applied to a transcoded superscript. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-target-functions nil - "List of functions applied to a transcoded target. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-timestamp-functions nil - "List of functions applied to a transcoded timestamp. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-underline-functions nil - "List of functions applied to transcoded underline text. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - -(defvar org-export-filter-verbatim-functions nil - "List of functions applied to transcoded verbatim text. -Each filter is called with three arguments: the transcoded data, -as a string, the back-end, as a symbol, and the communication -channel, as a plist. It must return a string or nil.") - - -;;;; Filters Tools -;; -;; Internal function `org-export-install-filters' installs filters -;; hard-coded in back-ends (developer filters) and filters from global -;; variables (user filters) in the communication channel. -;; -;; Internal function `org-export-filter-apply-functions' takes care -;; about applying each filter in order to a given data. It ignores -;; filters returning a nil value but stops whenever a filter returns -;; an empty string. - -(defun org-export-filter-apply-functions (filters value info) - "Call every function in FILTERS. - -Functions are called with arguments VALUE, current export -back-end and INFO. A function returning a nil value will be -skipped. If it returns the empty string, the process ends and -VALUE is ignored. - -Call is done in a LIFO fashion, to be sure that developer -specified filters, if any, are called first." - (catch 'exit - (dolist (filter filters value) - (let ((result (funcall filter value (plist-get info :back-end) info))) - (cond ((not value)) - ((equal value "") (throw 'exit nil)) - (t (setq value result))))))) - -(defun org-export-install-filters (info) - "Install filters properties in communication channel. - -INFO is a plist containing the current communication channel. - -Return the updated communication channel." - (let (plist) - ;; Install user defined filters with `org-export-filters-alist'. - (mapc (lambda (p) - (setq plist (plist-put plist (car p) (eval (cdr p))))) - org-export-filters-alist) - ;; Prepend back-end specific filters to that list. - (let ((back-end-filters (intern (format "org-%s-filters-alist" - (plist-get info :back-end))))) - (when (boundp back-end-filters) - (mapc (lambda (p) - ;; Single values get consed, lists are prepended. - (let ((key (car p)) (value (cdr p))) - (when value - (setq plist - (plist-put - plist key - (if (atom value) (cons value (plist-get plist key)) - (append value (plist-get plist key)))))))) - (eval back-end-filters)))) - ;; Return new communication channel. - (org-combine-plists info plist))) - - - -;;; Core functions -;; -;; This is the room for the main function, `org-export-as', along with -;; its derivatives, `org-export-to-buffer' and `org-export-to-file'. -;; They differ only by the way they output the resulting code. -;; -;; `org-export-output-file-name' is an auxiliary function meant to be -;; used with `org-export-to-file'. With a given extension, it tries -;; to provide a canonical file name to write export output to. -;; -;; Note that `org-export-as' doesn't really parse the current buffer, -;; but a copy of it (with the same buffer-local variables and -;; visibility), where include keywords are expanded and Babel blocks -;; are executed, if appropriate. -;; `org-export-with-current-buffer-copy' macro prepares that copy. -;; -;; File inclusion is taken care of by -;; `org-export-expand-include-keyword' and -;; `org-export--prepare-file-contents'. Structure wise, including -;; a whole Org file in a buffer often makes little sense. For -;; example, if the file contains an headline and the include keyword -;; was within an item, the item should contain the headline. That's -;; why file inclusion should be done before any structure can be -;; associated to the file, that is before parsing. - -(defun org-export-as - (backend &optional subtreep visible-only body-only ext-plist noexpand) - "Transcode current Org buffer into BACKEND code. - -If narrowing is active in the current buffer, only transcode its -narrowed part. - -If a region is active, transcode that region. - -When optional argument SUBTREEP is non-nil, transcode the -sub-tree at point, extracting information from the headline -properties first. - -When optional argument VISIBLE-ONLY is non-nil, don't export -contents of hidden elements. - -When optional argument BODY-ONLY is non-nil, only return body -code, without preamble nor postamble. - -Optional argument EXT-PLIST, when provided, is a property list -with external parameters overriding Org default settings, but -still inferior to file-local settings. - -Optional argument NOEXPAND, when non-nil, prevents included files -to be expanded and Babel code to be executed. - -Return code as a string." - (save-excursion - (save-restriction - ;; Narrow buffer to an appropriate region or subtree for - ;; parsing. If parsing subtree, be sure to remove main headline - ;; too. - (cond ((org-region-active-p) - (narrow-to-region (region-beginning) (region-end))) - (subtreep - (org-narrow-to-subtree) - (goto-char (point-min)) - (forward-line) - (narrow-to-region (point) (point-max)))) - ;; 1. Get export environment from original buffer. Also install - ;; user's and developer's filters. - (let ((info (org-export-install-filters - (org-export-get-environment backend subtreep ext-plist))) - ;; 2. Get parse tree. Buffer isn't parsed directly. - ;; Instead, a temporary copy is created, where include - ;; keywords are expanded and code blocks are evaluated. - (tree (let ((buf (or (buffer-file-name (buffer-base-buffer)) - (current-buffer)))) - (org-export-with-current-buffer-copy - (unless noexpand - (org-export-expand-include-keyword) - ;; TODO: Setting `org-current-export-file' is - ;; required by Org Babel to properly resolve - ;; noweb references. Once "org-exp.el" is - ;; removed, modify - ;; `org-export-blocks-preprocess' so it accepts - ;; the value as an argument instead. - (let ((org-current-export-file buf)) - (org-export-blocks-preprocess))) - (goto-char (point-min)) - ;; Run hook - ;; `org-export-before-parsing-hook'. with current - ;; back-end as argument. - (run-hook-with-args - 'org-export-before-parsing-hook backend) - ;; Eventually parse buffer. - (org-element-parse-buffer nil visible-only))))) - ;; 3. Call parse-tree filters to get the final tree. - (setq tree - (org-export-filter-apply-functions - (plist-get info :filter-parse-tree) tree info)) - ;; 4. Now tree is complete, compute its properties and add - ;; them to communication channel. - (setq info - (org-combine-plists - info (org-export-collect-tree-properties tree info))) - ;; 5. Eventually transcode TREE. Wrap the resulting string - ;; into a template, if required. Eventually call - ;; final-output filter. - (let* ((body (org-element-normalize-string (org-export-data tree info))) - (template (cdr (assq 'template - (plist-get info :translate-alist)))) - (output (org-export-filter-apply-functions - (plist-get info :filter-final-output) - (if (or (not (functionp template)) body-only) body - (funcall template body info)) - info))) - ;; Maybe add final OUTPUT to kill ring, then return it. - (when org-export-copy-to-kill-ring (org-kill-new output)) - output))))) - -(defun org-export-to-buffer - (backend buffer &optional subtreep visible-only body-only ext-plist noexpand) - "Call `org-export-as' with output to a specified buffer. - -BACKEND is the back-end used for transcoding, as a symbol. - -BUFFER is the output buffer. If it already exists, it will be -erased first, otherwise, it will be created. - -Optional arguments SUBTREEP, VISIBLE-ONLY, BODY-ONLY, EXT-PLIST -and NOEXPAND are similar to those used in `org-export-as', which -see. - -Return buffer." - (let ((out (org-export-as - backend subtreep visible-only body-only ext-plist noexpand)) - (buffer (get-buffer-create buffer))) - (with-current-buffer buffer - (erase-buffer) - (insert out) - (goto-char (point-min))) - buffer)) - -(defun org-export-to-file - (backend file &optional subtreep visible-only body-only ext-plist noexpand) - "Call `org-export-as' with output to a specified file. - -BACKEND is the back-end used for transcoding, as a symbol. FILE -is the name of the output file, as a string. - -Optional arguments SUBTREEP, VISIBLE-ONLY, BODY-ONLY, EXT-PLIST -and NOEXPAND are similar to those used in `org-export-as', which -see. - -Return output file's name." - ;; Checks for FILE permissions. `write-file' would do the same, but - ;; we'd rather avoid needless transcoding of parse tree. - (unless (file-writable-p file) (error "Output file not writable")) - ;; Insert contents to a temporary buffer and write it to FILE. - (let ((out (org-export-as - backend subtreep visible-only body-only ext-plist noexpand))) - (with-temp-buffer - (insert out) - (let ((coding-system-for-write org-export-coding-system)) - (write-file file)))) - ;; Return full path. - file) - -(defun org-export-output-file-name (extension &optional subtreep pub-dir) - "Return output file's name according to buffer specifications. - -EXTENSION is a string representing the output file extension, -with the leading dot. - -With a non-nil optional argument SUBTREEP, try to determine -output file's name by looking for \"EXPORT_FILE_NAME\" property -of subtree at point. - -When optional argument PUB-DIR is set, use it as the publishing -directory. - -When optional argument VISIBLE-ONLY is non-nil, don't export -contents of hidden elements. - -Return file name as a string, or nil if it couldn't be -determined." - (let ((base-name - ;; File name may come from EXPORT_FILE_NAME subtree property, - ;; assuming point is at beginning of said sub-tree. - (file-name-sans-extension - (or (and subtreep - (org-entry-get - (save-excursion - (ignore-errors (org-back-to-heading) (point))) - "EXPORT_FILE_NAME" t)) - ;; File name may be extracted from buffer's associated - ;; file, if any. - (buffer-file-name (buffer-base-buffer)) - ;; Can't determine file name on our own: Ask user. - (let ((read-file-name-function - (and org-completion-use-ido 'ido-read-file-name))) - (read-file-name - "Output file: " pub-dir nil nil nil - (lambda (name) - (string= (file-name-extension name t) extension)))))))) - ;; Build file name. Enforce EXTENSION over whatever user may have - ;; come up with. PUB-DIR, if defined, always has precedence over - ;; any provided path. - (cond - (pub-dir - (concat (file-name-as-directory pub-dir) - (file-name-nondirectory base-name) - extension)) - ((string= (file-name-nondirectory base-name) base-name) - (concat (file-name-as-directory ".") base-name extension)) - (t (concat base-name extension))))) - -(defmacro org-export-with-current-buffer-copy (&rest body) - "Apply BODY in a copy of the current buffer. - -The copy preserves local variables and visibility of the original -buffer. - -Point is at buffer's beginning when BODY is applied." - (org-with-gensyms (original-buffer offset buffer-string overlays) - `(let ((,original-buffer (current-buffer)) - (,offset (1- (point-min))) - (,buffer-string (buffer-string)) - (,overlays (mapcar - 'copy-overlay (overlays-in (point-min) (point-max))))) - (with-temp-buffer - (let ((buffer-invisibility-spec nil)) - (org-clone-local-variables - ,original-buffer - "^\\(org-\\|orgtbl-\\|major-mode$\\|outline-\\(regexp\\|level\\)$\\)") - (insert ,buffer-string) - (mapc (lambda (ov) - (move-overlay - ov - (- (overlay-start ov) ,offset) - (- (overlay-end ov) ,offset) - (current-buffer))) - ,overlays) - (goto-char (point-min)) - (progn ,@body)))))) -(def-edebug-spec org-export-with-current-buffer-copy (body)) - -(defun org-export-expand-include-keyword (&optional included dir) - "Expand every include keyword in buffer. -Optional argument INCLUDED is a list of included file names along -with their line restriction, when appropriate. It is used to -avoid infinite recursion. Optional argument DIR is the current -working directory. It is used to properly resolve relative -paths." - (let ((case-fold-search t)) - (goto-char (point-min)) - (while (re-search-forward "^[ \t]*#\\+INCLUDE: \\(.*\\)" nil t) - (when (eq (org-element-type (save-match-data (org-element-at-point))) - 'keyword) - (beginning-of-line) - ;; Extract arguments from keyword's value. - (let* ((value (match-string 1)) - (ind (org-get-indentation)) - (file (and (string-match "^\"\\(\\S-+\\)\"" value) - (prog1 (expand-file-name (match-string 1 value) dir) - (setq value (replace-match "" nil nil value))))) - (lines - (and (string-match - ":lines +\"\\(\\(?:[0-9]+\\)?-\\(?:[0-9]+\\)?\\)\"" value) - (prog1 (match-string 1 value) - (setq value (replace-match "" nil nil value))))) - (env (cond ((string-match "\\" value) 'example) - ((string-match "\\ level limit) (- level limit)))))) - -(defun org-export-get-headline-number (headline info) - "Return HEADLINE numbering as a list of numbers. -INFO is a plist holding contextual information." - (cdr (assoc headline (plist-get info :headline-numbering)))) - -(defun org-export-numbered-headline-p (headline info) - "Return a non-nil value if HEADLINE element should be numbered. -INFO is a plist used as a communication channel." - (let ((sec-num (plist-get info :section-numbers)) - (level (org-export-get-relative-level headline info))) - (if (wholenump sec-num) (<= level sec-num) sec-num))) - -(defun org-export-number-to-roman (n) - "Convert integer N into a roman numeral." - (let ((roman '((1000 . "M") (900 . "CM") (500 . "D") (400 . "CD") - ( 100 . "C") ( 90 . "XC") ( 50 . "L") ( 40 . "XL") - ( 10 . "X") ( 9 . "IX") ( 5 . "V") ( 4 . "IV") - ( 1 . "I"))) - (res "")) - (if (<= n 0) - (number-to-string n) - (while roman - (if (>= n (caar roman)) - (setq n (- n (caar roman)) - res (concat res (cdar roman))) - (pop roman))) - res))) - -(defun org-export-get-tags (element info &optional tags) - "Return list of tags associated to ELEMENT. - -ELEMENT has either an `headline' or an `inlinetask' type. INFO -is a plist used as a communication channel. - -Select tags (see `org-export-select-tags') and exclude tags (see -`org-export-exclude-tags') are removed from the list. - -When non-nil, optional argument TAGS should be a list of strings. -Any tag belonging to this list will also be removed." - (org-remove-if (lambda (tag) (or (member tag (plist-get info :select-tags)) - (member tag (plist-get info :exclude-tags)) - (member tag tags))) - (org-element-property :tags element))) - -(defun org-export-first-sibling-p (headline info) - "Non-nil when HEADLINE is the first sibling in its sub-tree. -INFO is a plist used as a communication channel." - (not (eq (org-element-type (org-export-get-previous-element headline info)) - 'headline))) - -(defun org-export-last-sibling-p (headline info) - "Non-nil when HEADLINE is the last sibling in its sub-tree. -INFO is a plist used as a communication channel." - (not (org-export-get-next-element headline info))) - - -;;;; For Links -;; -;; `org-export-solidify-link-text' turns a string into a safer version -;; for links, replacing most non-standard characters with hyphens. -;; -;; `org-export-get-coderef-format' returns an appropriate format -;; string for coderefs. -;; -;; `org-export-inline-image-p' returns a non-nil value when the link -;; provided should be considered as an inline image. -;; -;; `org-export-resolve-fuzzy-link' searches destination of fuzzy links -;; (i.e. links with "fuzzy" as type) within the parsed tree, and -;; returns an appropriate unique identifier when found, or nil. -;; -;; `org-export-resolve-id-link' returns the first headline with -;; specified id or custom-id in parse tree, the path to the external -;; file with the id or nil when neither was found. -;; -;; `org-export-resolve-coderef' associates a reference to a line -;; number in the element it belongs, or returns the reference itself -;; when the element isn't numbered. - -(defun org-export-solidify-link-text (s) - "Take link text S and make a safe target out of it." - (save-match-data - (mapconcat 'identity (org-split-string s "[^a-zA-Z0-9_.-]+") "-"))) - -(defun org-export-get-coderef-format (path desc) - "Return format string for code reference link. -PATH is the link path. DESC is its description." - (save-match-data - (cond ((not desc) "%s") - ((string-match (regexp-quote (concat "(" path ")")) desc) - (replace-match "%s" t t desc)) - (t desc)))) - -(defun org-export-inline-image-p (link &optional rules) - "Non-nil if LINK object points to an inline image. - -Optional argument is a set of RULES defining inline images. It -is an alist where associations have the following shape: - - \(TYPE . REGEXP) - -Applying a rule means apply REGEXP against LINK's path when its -type is TYPE. The function will return a non-nil value if any of -the provided rules is non-nil. The default rule is -`org-export-default-inline-image-rule'. - -This only applies to links without a description." - (and (not (org-element-contents link)) - (let ((case-fold-search t) - (rules (or rules org-export-default-inline-image-rule))) - (catch 'exit - (mapc - (lambda (rule) - (and (string= (org-element-property :type link) (car rule)) - (string-match (cdr rule) - (org-element-property :path link)) - (throw 'exit t))) - rules) - ;; Return nil if no rule matched. - nil)))) - -(defun org-export-resolve-coderef (ref info) - "Resolve a code reference REF. - -INFO is a plist used as a communication channel. - -Return associated line number in source code, or REF itself, -depending on src-block or example element's switches." - (org-element-map - (plist-get info :parse-tree) '(example-block src-block) - (lambda (el) - (with-temp-buffer - (insert (org-trim (org-element-property :value el))) - (let* ((label-fmt (regexp-quote - (or (org-element-property :label-fmt el) - org-coderef-label-format))) - (ref-re - (format "^.*?\\S-.*?\\([ \t]*\\(%s\\)\\)[ \t]*$" - (replace-regexp-in-string "%s" ref label-fmt nil t)))) - ;; Element containing REF is found. Resolve it to either - ;; a label or a line number, as needed. - (when (re-search-backward ref-re nil t) - (cond - ((org-element-property :use-labels el) ref) - ((eq (org-element-property :number-lines el) 'continued) - (+ (org-export-get-loc el info) (line-number-at-pos))) - (t (line-number-at-pos))))))) - info 'first-match)) - -(defun org-export-resolve-fuzzy-link (link info) - "Return LINK destination. - -INFO is a plist holding contextual information. - -Return value can be an object, an element, or nil: - -- If LINK path matches a target object (i.e. <>) or - element (i.e. \"#+TARGET: path\"), return it. - -- If LINK path exactly matches the name affiliated keyword - \(i.e. #+NAME: path) of an element, return that element. - -- If LINK path exactly matches any headline name, return that - element. If more than one headline share that name, priority - will be given to the one with the closest common ancestor, if - any, or the first one in the parse tree otherwise. - -- Otherwise, return nil. - -Assume LINK type is \"fuzzy\"." - (let* ((path (org-element-property :path link)) - (match-title-p (eq (aref path 0) ?*))) - (cond - ;; First try to find a matching "<>" unless user specified - ;; he was looking for an headline (path starts with a * - ;; character). - ((and (not match-title-p) - (loop for target in (plist-get info :target-list) - when (string= (org-element-property :value target) path) - return target))) - ;; Then try to find an element with a matching "#+NAME: path" - ;; affiliated keyword. - ((and (not match-title-p) - (org-element-map - (plist-get info :parse-tree) org-element-all-elements - (lambda (el) - (when (string= (org-element-property :name el) path) el)) - info 'first-match))) - ;; Last case: link either points to an headline or to - ;; nothingness. Try to find the source, with priority given to - ;; headlines with the closest common ancestor. If such candidate - ;; is found, return it, otherwise return nil. - (t - (let ((find-headline - (function - ;; Return first headline whose `:raw-value' property - ;; is NAME in parse tree DATA, or nil. - (lambda (name data) - (org-element-map - data 'headline - (lambda (headline) - (when (string= - (org-element-property :raw-value headline) - name) - headline)) - info 'first-match))))) - ;; Search among headlines sharing an ancestor with link, - ;; from closest to farthest. - (or (catch 'exit - (mapc - (lambda (parent) - (when (eq (org-element-type parent) 'headline) - (let ((foundp (funcall find-headline path parent))) - (when foundp (throw 'exit foundp))))) - (org-export-get-genealogy link)) nil) - ;; No match with a common ancestor: try the full parse-tree. - (funcall find-headline - (if match-title-p (substring path 1) path) - (plist-get info :parse-tree)))))))) - -(defun org-export-resolve-id-link (link info) - "Return headline referenced as LINK destination. - -INFO is a plist used as a communication channel. - -Return value can be the headline element matched in current parse -tree, a file name or nil. Assume LINK type is either \"id\" or -\"custom-id\"." - (let ((id (org-element-property :path link))) - ;; First check if id is within the current parse tree. - (or (org-element-map - (plist-get info :parse-tree) 'headline - (lambda (headline) - (when (or (string= (org-element-property :id headline) id) - (string= (org-element-property :custom-id headline) id)) - headline)) - info 'first-match) - ;; Otherwise, look for external files. - (cdr (assoc id (plist-get info :id-alist)))))) - -(defun org-export-resolve-radio-link (link info) - "Return radio-target object referenced as LINK destination. - -INFO is a plist used as a communication channel. - -Return value can be a radio-target object or nil. Assume LINK -has type \"radio\"." - (let ((path (org-element-property :path link))) - (org-element-map - (plist-get info :parse-tree) 'radio-target - (lambda (radio) - (when (equal (org-element-property :value radio) path) radio)) - info 'first-match))) - - -;;;; For Macros -;; -;; `org-export-expand-macro' simply takes care of expanding macros. - -(defun org-export-expand-macro (macro info) - "Expand MACRO and return it as a string. -INFO is a plist holding export options." - (let* ((key (org-element-property :key macro)) - (args (org-element-property :args macro)) - ;; User's macros are stored in the communication channel with - ;; a ":macro-" prefix. Replace arguments in VALUE. Also - ;; expand recursively macros within. - (value (org-export-data - (mapcar - (lambda (obj) - (if (not (stringp obj)) (org-export-data obj info) - (replace-regexp-in-string - "\\$[0-9]+" - (lambda (arg) - (nth (1- (string-to-number (substring arg 1))) args)) - obj))) - (plist-get info (intern (format ":macro-%s" key)))) - info))) - ;; VALUE starts with "(eval": it is a s-exp, `eval' it. - (when (string-match "\\`(eval\\>" value) (setq value (eval (read value)))) - ;; Return string. - (format "%s" (or value "")))) - - -;;;; For References -;; -;; `org-export-get-ordinal' associates a sequence number to any object -;; or element. - -(defun org-export-get-ordinal (element info &optional types predicate) - "Return ordinal number of an element or object. - -ELEMENT is the element or object considered. INFO is the plist -used as a communication channel. - -Optional argument TYPES, when non-nil, is a list of element or -object types, as symbols, that should also be counted in. -Otherwise, only provided element's type is considered. - -Optional argument PREDICATE is a function returning a non-nil -value if the current element or object should be counted in. It -accepts two arguments: the element or object being considered and -the plist used as a communication channel. This allows to count -only a certain type of objects (i.e. inline images). - -Return value is a list of numbers if ELEMENT is an headline or an -item. It is nil for keywords. It represents the footnote number -for footnote definitions and footnote references. If ELEMENT is -a target, return the same value as if ELEMENT was the closest -table, item or headline containing the target. In any other -case, return the sequence number of ELEMENT among elements or -objects of the same type." - ;; A target keyword, representing an invisible target, never has - ;; a sequence number. - (unless (eq (org-element-type element) 'keyword) - ;; Ordinal of a target object refer to the ordinal of the closest - ;; table, item, or headline containing the object. - (when (eq (org-element-type element) 'target) - (setq element - (loop for parent in (org-export-get-genealogy element) - when - (memq - (org-element-type parent) - '(footnote-definition footnote-reference headline item - table)) - return parent))) - (case (org-element-type element) - ;; Special case 1: An headline returns its number as a list. - (headline (org-export-get-headline-number element info)) - ;; Special case 2: An item returns its number as a list. - (item (let ((struct (org-element-property :structure element))) - (org-list-get-item-number - (org-element-property :begin element) - struct - (org-list-prevs-alist struct) - (org-list-parents-alist struct)))) - ((footnote-definition footnote-reference) - (org-export-get-footnote-number element info)) - (otherwise - (let ((counter 0)) - ;; Increment counter until ELEMENT is found again. - (org-element-map - (plist-get info :parse-tree) (or types (org-element-type element)) - (lambda (el) - (cond - ((eq element el) (1+ counter)) - ((not predicate) (incf counter) nil) - ((funcall predicate el info) (incf counter) nil))) - info 'first-match)))))) - - -;;;; For Src-Blocks -;; -;; `org-export-get-loc' counts number of code lines accumulated in -;; src-block or example-block elements with a "+n" switch until -;; a given element, excluded. Note: "-n" switches reset that count. -;; -;; `org-export-unravel-code' extracts source code (along with a code -;; references alist) from an `element-block' or `src-block' type -;; element. -;; -;; `org-export-format-code' applies a formatting function to each line -;; of code, providing relative line number and code reference when -;; appropriate. Since it doesn't access the original element from -;; which the source code is coming, it expects from the code calling -;; it to know if lines should be numbered and if code references -;; should appear. -;; -;; Eventually, `org-export-format-code-default' is a higher-level -;; function (it makes use of the two previous functions) which handles -;; line numbering and code references inclusion, and returns source -;; code in a format suitable for plain text or verbatim output. - -(defun org-export-get-loc (element info) - "Return accumulated lines of code up to ELEMENT. - -INFO is the plist used as a communication channel. - -ELEMENT is excluded from count." - (let ((loc 0)) - (org-element-map - (plist-get info :parse-tree) - `(src-block example-block ,(org-element-type element)) - (lambda (el) - (cond - ;; ELEMENT is reached: Quit the loop. - ((eq el element)) - ;; Only count lines from src-block and example-block elements - ;; with a "+n" or "-n" switch. A "-n" switch resets counter. - ((not (memq (org-element-type el) '(src-block example-block))) nil) - ((let ((linums (org-element-property :number-lines el))) - (when linums - ;; Accumulate locs or reset them. - (let ((lines (org-count-lines - (org-trim (org-element-property :value el))))) - (setq loc (if (eq linums 'new) lines (+ loc lines)))))) - ;; Return nil to stay in the loop. - nil))) - info 'first-match) - ;; Return value. - loc)) - -(defun org-export-unravel-code (element) - "Clean source code and extract references out of it. - -ELEMENT has either a `src-block' an `example-block' type. - -Return a cons cell whose CAR is the source code, cleaned from any -reference and protective comma and CDR is an alist between -relative line number (integer) and name of code reference on that -line (string)." - (let* ((line 0) refs - ;; Get code and clean it. Remove blank lines at its - ;; beginning and end. Also remove protective commas. - (code (let ((c (replace-regexp-in-string - "\\`\\([ \t]*\n\\)+" "" - (replace-regexp-in-string - "\\(:?[ \t]*\n\\)*[ \t]*\\'" "\n" - (org-element-property :value element))))) - ;; If appropriate, remove global indentation. - (unless (or org-src-preserve-indentation - (org-element-property :preserve-indent element)) - (setq c (org-remove-indentation c))) - ;; Free up the protected lines. Note: Org blocks - ;; have commas at the beginning or every line. - (if (string= (org-element-property :language element) "org") - (replace-regexp-in-string "^," "" c) - (replace-regexp-in-string - "^\\(,\\)\\(:?\\*\\|[ \t]*#\\+\\)" "" c nil nil 1)))) - ;; Get format used for references. - (label-fmt (regexp-quote - (or (org-element-property :label-fmt element) - org-coderef-label-format))) - ;; Build a regexp matching a loc with a reference. - (with-ref-re - (format "^.*?\\S-.*?\\([ \t]*\\(%s\\)[ \t]*\\)$" - (replace-regexp-in-string - "%s" "\\([-a-zA-Z0-9_ ]+\\)" label-fmt nil t)))) - ;; Return value. - (cons - ;; Code with references removed. - (org-element-normalize-string - (mapconcat - (lambda (loc) - (incf line) - (if (not (string-match with-ref-re loc)) loc - ;; Ref line: remove ref, and signal its position in REFS. - (push (cons line (match-string 3 loc)) refs) - (replace-match "" nil nil loc 1))) - (org-split-string code "\n") "\n")) - ;; Reference alist. - refs))) - -(defun org-export-format-code (code fun &optional num-lines ref-alist) - "Format CODE by applying FUN line-wise and return it. - -CODE is a string representing the code to format. FUN is -a function. It must accept three arguments: a line of -code (string), the current line number (integer) or nil and the -reference associated to the current line (string) or nil. - -Optional argument NUM-LINES can be an integer representing the -number of code lines accumulated until the current code. Line -numbers passed to FUN will take it into account. If it is nil, -FUN's second argument will always be nil. This number can be -obtained with `org-export-get-loc' function. - -Optional argument REF-ALIST can be an alist between relative line -number (i.e. ignoring NUM-LINES) and the name of the code -reference on it. If it is nil, FUN's third argument will always -be nil. It can be obtained through the use of -`org-export-unravel-code' function." - (let ((--locs (org-split-string code "\n")) - (--line 0)) - (org-element-normalize-string - (mapconcat - (lambda (--loc) - (incf --line) - (let ((--ref (cdr (assq --line ref-alist)))) - (funcall fun --loc (and num-lines (+ num-lines --line)) --ref))) - --locs "\n")))) - -(defun org-export-format-code-default (element info) - "Return source code from ELEMENT, formatted in a standard way. - -ELEMENT is either a `src-block' or `example-block' element. INFO -is a plist used as a communication channel. - -This function takes care of line numbering and code references -inclusion. Line numbers, when applicable, appear at the -beginning of the line, separated from the code by two white -spaces. Code references, on the other hand, appear flushed to -the right, separated by six white spaces from the widest line of -code." - ;; Extract code and references. - (let* ((code-info (org-export-unravel-code element)) - (code (car code-info)) - (code-lines (org-split-string code "\n")) - (refs (and (org-element-property :retain-labels element) - (cdr code-info))) - ;; Handle line numbering. - (num-start (case (org-element-property :number-lines element) - (continued (org-export-get-loc element info)) - (new 0))) - (num-fmt - (and num-start - (format "%%%ds " - (length (number-to-string - (+ (length code-lines) num-start)))))) - ;; Prepare references display, if required. Any reference - ;; should start six columns after the widest line of code, - ;; wrapped with parenthesis. - (max-width - (+ (apply 'max (mapcar 'length code-lines)) - (if (not num-start) 0 (length (format num-fmt num-start)))))) - (org-export-format-code - code - (lambda (loc line-num ref) - (let ((number-str (and num-fmt (format num-fmt line-num)))) - (concat - number-str - loc - (and ref - (concat (make-string - (- (+ 6 max-width) - (+ (length loc) (length number-str))) ? ) - (format "(%s)" ref)))))) - num-start refs))) - - -;;;; For Tables -;; -;; `org-export-table-has-special-column-p' and and -;; `org-export-table-row-is-special-p' are predicates used to look for -;; meta-information about the table structure. -;; -;; `org-table-has-header-p' tells when the rows before the first rule -;; should be considered as table's header. -;; -;; `org-export-table-cell-width', `org-export-table-cell-alignment' -;; and `org-export-table-cell-borders' extract information from -;; a table-cell element. -;; -;; `org-export-table-dimensions' gives the number on rows and columns -;; in the table, ignoring horizontal rules and special columns. -;; `org-export-table-cell-address', given a table-cell object, returns -;; the absolute address of a cell. On the other hand, -;; `org-export-get-table-cell-at' does the contrary. -;; -;; `org-export-table-cell-starts-colgroup-p', -;; `org-export-table-cell-ends-colgroup-p', -;; `org-export-table-row-starts-rowgroup-p', -;; `org-export-table-row-ends-rowgroup-p', -;; `org-export-table-row-starts-header-p' and -;; `org-export-table-row-ends-header-p' indicate position of current -;; row or cell within the table. - -(defun org-export-table-has-special-column-p (table) - "Non-nil when TABLE has a special column. -All special columns will be ignored during export." - ;; The table has a special column when every first cell of every row - ;; has an empty value or contains a symbol among "/", "#", "!", "$", - ;; "*" "_" and "^". Though, do not consider a first row containing - ;; only empty cells as special. - (let ((special-column-p 'empty)) - (catch 'exit - (mapc - (lambda (row) - (when (eq (org-element-property :type row) 'standard) - (let ((value (org-element-contents - (car (org-element-contents row))))) - (cond ((member value '(("/") ("#") ("!") ("$") ("*") ("_") ("^"))) - (setq special-column-p 'special)) - ((not value)) - (t (throw 'exit nil)))))) - (org-element-contents table)) - (eq special-column-p 'special)))) - -(defun org-export-table-has-header-p (table info) - "Non-nil when TABLE has an header. - -INFO is a plist used as a communication channel. - -A table has an header when it contains at least two row groups." - (let ((rowgroup 1) row-flag) - (org-element-map - table 'table-row - (lambda (row) - (cond - ((> rowgroup 1) t) - ((and row-flag (eq (org-element-property :type row) 'rule)) - (incf rowgroup) (setq row-flag nil)) - ((and (not row-flag) (eq (org-element-property :type row) 'standard)) - (setq row-flag t) nil))) - info))) - -(defun org-export-table-row-is-special-p (table-row info) - "Non-nil if TABLE-ROW is considered special. - -INFO is a plist used as the communication channel. - -All special rows will be ignored during export." - (when (eq (org-element-property :type table-row) 'standard) - (let ((first-cell (org-element-contents - (car (org-element-contents table-row))))) - ;; A row is special either when... - (or - ;; ... it starts with a field only containing "/", - (equal first-cell '("/")) - ;; ... the table contains a special column and the row start - ;; with a marking character among, "^", "_", "$" or "!", - (and (org-export-table-has-special-column-p - (org-export-get-parent table-row)) - (member first-cell '(("^") ("_") ("$") ("!")))) - ;; ... it contains only alignment cookies and empty cells. - (let ((special-row-p 'empty)) - (catch 'exit - (mapc - (lambda (cell) - (let ((value (org-element-contents cell))) - ;; Since VALUE is a secondary string, the following - ;; checks avoid expanding it with `org-export-data'. - (cond ((not value)) - ((and (not (cdr value)) - (stringp (car value)) - (string-match "\\`<[lrc]?\\([0-9]+\\)?>\\'" - (car value))) - (setq special-row-p 'cookie)) - (t (throw 'exit nil))))) - (org-element-contents table-row)) - (eq special-row-p 'cookie))))))) - -(defun org-export-table-row-group (table-row info) - "Return TABLE-ROW's group. - -INFO is a plist used as the communication channel. - -Return value is the group number, as an integer, or nil special -rows and table rules. Group 1 is also table's header." - (unless (or (eq (org-element-property :type table-row) 'rule) - (org-export-table-row-is-special-p table-row info)) - (let ((group 0) row-flag) - (catch 'found - (mapc - (lambda (row) - (cond - ((and (eq (org-element-property :type row) 'standard) - (not (org-export-table-row-is-special-p row info))) - (unless row-flag (incf group) (setq row-flag t))) - ((eq (org-element-property :type row) 'rule) - (setq row-flag nil))) - (when (eq table-row row) (throw 'found group))) - (org-element-contents (org-export-get-parent table-row))))))) - -(defun org-export-table-cell-width (table-cell info) - "Return TABLE-CELL contents width. - -INFO is a plist used as the communication channel. - -Return value is the width given by the last width cookie in the -same column as TABLE-CELL, or nil." - (let* ((row (org-export-get-parent table-cell)) - (column (let ((cells (org-element-contents row))) - (- (length cells) (length (memq table-cell cells))))) - (table (org-export-get-parent-table table-cell)) - cookie-width) - (mapc - (lambda (row) - (cond - ;; In a special row, try to find a width cookie at COLUMN. - ((org-export-table-row-is-special-p row info) - (let ((value (org-element-contents - (elt (org-element-contents row) column)))) - ;; The following checks avoid expanding unnecessarily the - ;; cell with `org-export-data' - (when (and value - (not (cdr value)) - (stringp (car value)) - (string-match "\\`<[lrc]?\\([0-9]+\\)?>\\'" (car value)) - (match-string 1 (car value))) - (setq cookie-width - (string-to-number (match-string 1 (car value))))))) - ;; Ignore table rules. - ((eq (org-element-property :type row) 'rule)))) - (org-element-contents table)) - ;; Return value. - cookie-width)) - -(defun org-export-table-cell-alignment (table-cell info) - "Return TABLE-CELL contents alignment. - -INFO is a plist used as the communication channel. - -Return alignment as specified by the last alignment cookie in the -same column as TABLE-CELL. If no such cookie is found, a default -alignment value will be deduced from fraction of numbers in the -column (see `org-table-number-fraction' for more information). -Possible values are `left', `right' and `center'." - (let* ((row (org-export-get-parent table-cell)) - (column (let ((cells (org-element-contents row))) - (- (length cells) (length (memq table-cell cells))))) - (table (org-export-get-parent-table table-cell)) - (number-cells 0) - (total-cells 0) - cookie-align) - (mapc - (lambda (row) - (cond - ;; In a special row, try to find an alignment cookie at - ;; COLUMN. - ((org-export-table-row-is-special-p row info) - (let ((value (org-element-contents - (elt (org-element-contents row) column)))) - ;; Since VALUE is a secondary string, the following checks - ;; avoid useless expansion through `org-export-data'. - (when (and value - (not (cdr value)) - (stringp (car value)) - (string-match "\\`<\\([lrc]\\)?\\([0-9]+\\)?>\\'" - (car value)) - (match-string 1 (car value))) - (setq cookie-align (match-string 1 (car value)))))) - ;; Ignore table rules. - ((eq (org-element-property :type row) 'rule)) - ;; In a standard row, check if cell's contents are expressing - ;; some kind of number. Increase NUMBER-CELLS accordingly. - ;; Though, don't bother if an alignment cookie has already - ;; defined cell's alignment. - ((not cookie-align) - (let ((value (org-export-data - (org-element-contents - (elt (org-element-contents row) column)) - info))) - (incf total-cells) - (when (string-match org-table-number-regexp value) - (incf number-cells)))))) - (org-element-contents table)) - ;; Return value. Alignment specified by cookies has precedence - ;; over alignment deduced from cells contents. - (cond ((equal cookie-align "l") 'left) - ((equal cookie-align "r") 'right) - ((equal cookie-align "c") 'center) - ((>= (/ (float number-cells) total-cells) org-table-number-fraction) - 'right) - (t 'left)))) - -(defun org-export-table-cell-borders (table-cell info) - "Return TABLE-CELL borders. - -INFO is a plist used as a communication channel. - -Return value is a list of symbols, or nil. Possible values are: -`top', `bottom', `above', `below', `left' and `right'. Note: -`top' (resp. `bottom') only happen for a cell in the first -row (resp. last row) of the table, ignoring table rules, if any. - -Returned borders ignore special rows." - (let* ((row (org-export-get-parent table-cell)) - (table (org-export-get-parent-table table-cell)) - borders) - ;; Top/above border? TABLE-CELL has a border above when a rule - ;; used to demarcate row groups can be found above. Hence, - ;; finding a rule isn't sufficient to push `above' in BORDERS: - ;; another regular row has to be found above that rule. - (let (rule-flag) - (catch 'exit - (mapc (lambda (row) - (cond ((eq (org-element-property :type row) 'rule) - (setq rule-flag t)) - ((not (org-export-table-row-is-special-p row info)) - (if rule-flag (throw 'exit (push 'above borders)) - (throw 'exit nil))))) - ;; Look at every row before the current one. - (cdr (memq row (reverse (org-element-contents table))))) - ;; No rule above, or rule found starts the table (ignoring any - ;; special row): TABLE-CELL is at the top of the table. - (when rule-flag (push 'above borders)) - (push 'top borders))) - ;; Bottom/below border? TABLE-CELL has a border below when next - ;; non-regular row below is a rule. - (let (rule-flag) - (catch 'exit - (mapc (lambda (row) - (cond ((eq (org-element-property :type row) 'rule) - (setq rule-flag t)) - ((not (org-export-table-row-is-special-p row info)) - (if rule-flag (throw 'exit (push 'below borders)) - (throw 'exit nil))))) - ;; Look at every row after the current one. - (cdr (memq row (org-element-contents table)))) - ;; No rule below, or rule found ends the table (modulo some - ;; special row): TABLE-CELL is at the bottom of the table. - (when rule-flag (push 'below borders)) - (push 'bottom borders))) - ;; Right/left borders? They can only be specified by column - ;; groups. Column groups are defined in a row starting with "/". - ;; Also a column groups row only contains "<", "<>", ">" or blank - ;; cells. - (catch 'exit - (let ((column (let ((cells (org-element-contents row))) - (- (length cells) (length (memq table-cell cells)))))) - (mapc - (lambda (row) - (unless (eq (org-element-property :type row) 'rule) - (when (equal (org-element-contents - (car (org-element-contents row))) - '("/")) - (let ((column-groups - (mapcar - (lambda (cell) - (let ((value (org-element-contents cell))) - (when (member value '(("<") ("<>") (">") nil)) - (car value)))) - (org-element-contents row)))) - ;; There's a left border when previous cell, if - ;; any, ends a group, or current one starts one. - (when (or (and (not (zerop column)) - (member (elt column-groups (1- column)) - '(">" "<>"))) - (member (elt column-groups column) '("<" "<>"))) - (push 'left borders)) - ;; There's a right border when next cell, if any, - ;; starts a group, or current one ends one. - (when (or (and (/= (1+ column) (length column-groups)) - (member (elt column-groups (1+ column)) - '("<" "<>"))) - (member (elt column-groups column) '(">" "<>"))) - (push 'right borders)) - (throw 'exit nil))))) - ;; Table rows are read in reverse order so last column groups - ;; row has precedence over any previous one. - (reverse (org-element-contents table))))) - ;; Return value. - borders)) - -(defun org-export-table-cell-starts-colgroup-p (table-cell info) - "Non-nil when TABLE-CELL is at the beginning of a row group. -INFO is a plist used as a communication channel." - ;; A cell starts a column group either when it is at the beginning - ;; of a row (or after the special column, if any) or when it has - ;; a left border. - (or (eq (org-element-map - (org-export-get-parent table-cell) - 'table-cell 'identity info 'first-match) - table-cell) - (memq 'left (org-export-table-cell-borders table-cell info)))) - -(defun org-export-table-cell-ends-colgroup-p (table-cell info) - "Non-nil when TABLE-CELL is at the end of a row group. -INFO is a plist used as a communication channel." - ;; A cell ends a column group either when it is at the end of a row - ;; or when it has a right border. - (or (eq (car (last (org-element-contents - (org-export-get-parent table-cell)))) - table-cell) - (memq 'right (org-export-table-cell-borders table-cell info)))) - -(defun org-export-table-row-starts-rowgroup-p (table-row info) - "Non-nil when TABLE-ROW is at the beginning of a column group. -INFO is a plist used as a communication channel." - (unless (or (eq (org-element-property :type table-row) 'rule) - (org-export-table-row-is-special-p table-row info)) - (let ((borders (org-export-table-cell-borders - (car (org-element-contents table-row)) info))) - (or (memq 'top borders) (memq 'above borders))))) - -(defun org-export-table-row-ends-rowgroup-p (table-row info) - "Non-nil when TABLE-ROW is at the end of a column group. -INFO is a plist used as a communication channel." - (unless (or (eq (org-element-property :type table-row) 'rule) - (org-export-table-row-is-special-p table-row info)) - (let ((borders (org-export-table-cell-borders - (car (org-element-contents table-row)) info))) - (or (memq 'bottom borders) (memq 'below borders))))) - -(defun org-export-table-row-starts-header-p (table-row info) - "Non-nil when TABLE-ROW is the first table header's row. -INFO is a plist used as a communication channel." - (and (org-export-table-has-header-p - (org-export-get-parent-table table-row) info) - (org-export-table-row-starts-rowgroup-p table-row info) - (= (org-export-table-row-group table-row info) 1))) - -(defun org-export-table-row-ends-header-p (table-row info) - "Non-nil when TABLE-ROW is the last table header's row. -INFO is a plist used as a communication channel." - (and (org-export-table-has-header-p - (org-export-get-parent-table table-row) info) - (org-export-table-row-ends-rowgroup-p table-row info) - (= (org-export-table-row-group table-row info) 1))) - -(defun org-export-table-dimensions (table info) - "Return TABLE dimensions. - -INFO is a plist used as a communication channel. - -Return value is a CONS like (ROWS . COLUMNS) where -ROWS (resp. COLUMNS) is the number of exportable -rows (resp. columns)." - (let (first-row (columns 0) (rows 0)) - ;; Set number of rows, and extract first one. - (org-element-map - table 'table-row - (lambda (row) - (when (eq (org-element-property :type row) 'standard) - (incf rows) - (unless first-row (setq first-row row)))) info) - ;; Set number of columns. - (org-element-map first-row 'table-cell (lambda (cell) (incf columns)) info) - ;; Return value. - (cons rows columns))) - -(defun org-export-table-cell-address (table-cell info) - "Return address of a regular TABLE-CELL object. - -TABLE-CELL is the cell considered. INFO is a plist used as -a communication channel. - -Address is a CONS cell (ROW . COLUMN), where ROW and COLUMN are -zero-based index. Only exportable cells are considered. The -function returns nil for other cells." - (let* ((table-row (org-export-get-parent table-cell)) - (table (org-export-get-parent-table table-cell))) - ;; Ignore cells in special rows or in special column. - (unless (or (org-export-table-row-is-special-p table-row info) - (and (org-export-table-has-special-column-p table) - (eq (car (org-element-contents table-row)) table-cell))) - (cons - ;; Row number. - (let ((row-count 0)) - (org-element-map - table 'table-row - (lambda (row) - (cond ((eq (org-element-property :type row) 'rule) nil) - ((eq row table-row) row-count) - (t (incf row-count) nil))) - info 'first-match)) - ;; Column number. - (let ((col-count 0)) - (org-element-map - table-row 'table-cell - (lambda (cell) - (if (eq cell table-cell) col-count (incf col-count) nil)) - info 'first-match)))))) - -(defun org-export-get-table-cell-at (address table info) - "Return regular table-cell object at ADDRESS in TABLE. - -Address is a CONS cell (ROW . COLUMN), where ROW and COLUMN are -zero-based index. TABLE is a table type element. INFO is -a plist used as a communication channel. - -If no table-cell, among exportable cells, is found at ADDRESS, -return nil." - (let ((column-pos (cdr address)) (column-count 0)) - (org-element-map - ;; Row at (car address) or nil. - (let ((row-pos (car address)) (row-count 0)) - (org-element-map - table 'table-row - (lambda (row) - (cond ((eq (org-element-property :type row) 'rule) nil) - ((= row-count row-pos) row) - (t (incf row-count) nil))) - info 'first-match)) - 'table-cell - (lambda (cell) - (if (= column-count column-pos) cell - (incf column-count) nil)) - info 'first-match))) - - -;;;; For Tables Of Contents -;; -;; `org-export-collect-headlines' builds a list of all exportable -;; headline elements, maybe limited to a certain depth. One can then -;; easily parse it and transcode it. -;; -;; Building lists of tables, figures or listings is quite similar. -;; Once the generic function `org-export-collect-elements' is defined, -;; `org-export-collect-tables', `org-export-collect-figures' and -;; `org-export-collect-listings' can be derived from it. - -(defun org-export-collect-headlines (info &optional n) - "Collect headlines in order to build a table of contents. - -INFO is a plist used as a communication channel. - -When optional argument N is an integer, it specifies the depth of -the table of contents. Otherwise, it is set to the value of the -last headline level. See `org-export-headline-levels' for more -information. - -Return a list of all exportable headlines as parsed elements." - (unless (wholenump n) (setq n (plist-get info :headline-levels))) - (org-element-map - (plist-get info :parse-tree) - 'headline - (lambda (headline) - ;; Strip contents from HEADLINE. - (let ((relative-level (org-export-get-relative-level headline info))) - (unless (> relative-level n) headline))) - info)) - -(defun org-export-collect-elements (type info &optional predicate) - "Collect referenceable elements of a determined type. - -TYPE can be a symbol or a list of symbols specifying element -types to search. Only elements with a caption are collected. - -INFO is a plist used as a communication channel. - -When non-nil, optional argument PREDICATE is a function accepting -one argument, an element of type TYPE. It returns a non-nil -value when that element should be collected. - -Return a list of all elements found, in order of appearance." - (org-element-map - (plist-get info :parse-tree) type - (lambda (element) - (and (org-element-property :caption element) - (or (not predicate) (funcall predicate element)) - element)) - info)) - -(defun org-export-collect-tables (info) - "Build a list of tables. -INFO is a plist used as a communication channel. - -Return a list of table elements with a caption." - (org-export-collect-elements 'table info)) - -(defun org-export-collect-figures (info predicate) - "Build a list of figures. - -INFO is a plist used as a communication channel. PREDICATE is -a function which accepts one argument: a paragraph element and -whose return value is non-nil when that element should be -collected. - -A figure is a paragraph type element, with a caption, verifying -PREDICATE. The latter has to be provided since a \"figure\" is -a vague concept that may depend on back-end. - -Return a list of elements recognized as figures." - (org-export-collect-elements 'paragraph info predicate)) - -(defun org-export-collect-listings (info) - "Build a list of src blocks. - -INFO is a plist used as a communication channel. - -Return a list of src-block elements with a caption." - (org-export-collect-elements 'src-block info)) - - -;;;; Topology -;; -;; Here are various functions to retrieve information about the -;; neighbourhood of a given element or object. Neighbours of interest -;; are direct parent (`org-export-get-parent'), parent headline -;; (`org-export-get-parent-headline'), first element containing an -;; object, (`org-export-get-parent-element'), parent table -;; (`org-export-get-parent-table'), previous element or object -;; (`org-export-get-previous-element') and next element or object -;; (`org-export-get-next-element'). -;; -;; `org-export-get-genealogy' returns the full genealogy of a given -;; element or object, from closest parent to full parse tree. - -(defun org-export-get-parent (blob) - "Return BLOB parent or nil. -BLOB is the element or object considered." - (org-element-property :parent blob)) - -(defun org-export-get-genealogy (blob) - "Return full genealogy relative to a given element or object. - -BLOB is the element or object being considered. - -Ancestors are returned from closest to farthest, the last one -being the full parse tree." - (let (genealogy (parent blob)) - (while (setq parent (org-element-property :parent parent)) - (push parent genealogy)) - (nreverse genealogy))) - -(defun org-export-get-parent-headline (blob) - "Return BLOB parent headline or nil. -BLOB is the element or object being considered." - (let ((parent blob)) - (while (and (setq parent (org-element-property :parent parent)) - (not (eq (org-element-type parent) 'headline)))) - parent)) - -(defun org-export-get-parent-element (object) - "Return first element containing OBJECT or nil. -OBJECT is the object to consider." - (let ((parent object)) - (while (and (setq parent (org-element-property :parent parent)) - (memq (org-element-type parent) org-element-all-objects))) - parent)) - -(defun org-export-get-parent-table (object) - "Return OBJECT parent table or nil. -OBJECT is either a `table-cell' or `table-element' type object." - (let ((parent object)) - (while (and (setq parent (org-element-property :parent parent)) - (not (eq (org-element-type parent) 'table)))) - parent)) - -(defun org-export-get-previous-element (blob info) - "Return previous element or object. -BLOB is an element or object. INFO is a plist used as -a communication channel. Return previous exportable element or -object, a string, or nil." - (let (prev) - (catch 'exit - (mapc (lambda (obj) - (cond ((eq obj blob) (throw 'exit prev)) - ((memq obj (plist-get info :ignore-list))) - (t (setq prev obj)))) - (org-element-contents (org-export-get-parent blob)))))) - -(defun org-export-get-next-element (blob info) - "Return next element or object. -BLOB is an element or object. INFO is a plist used as -a communication channel. Return next exportable element or -object, a string, or nil." - (catch 'found - (mapc (lambda (obj) - (unless (memq obj (plist-get info :ignore-list)) - (throw 'found obj))) - (cdr (memq blob (org-element-contents (org-export-get-parent blob))))) - nil)) - - -;;;; Translation -;; -;; `org-export-translate' translates a string according to language -;; specified by LANGUAGE keyword or `org-export-language-setup' -;; variable and a specified charset. `org-export-dictionary' contains -;; the dictionary used for the translation. - -(defconst org-export-dictionary - '(("Author" - ("fr" - :ascii "Auteur" - :latin1 "Auteur" - :utf-8 "Auteur")) - ("Date" - ("fr" - :ascii "Date" - :latin1 "Date" - :utf-8 "Date")) - ("Equation") - ("Figure") - ("Footnotes" - ("fr" - :ascii "Notes de bas de page" - :latin1 "Notes de bas de page" - :utf-8 "Notes de bas de page")) - ("List of Listings" - ("fr" - :ascii "Liste des programmes" - :latin1 "Liste des programmes" - :utf-8 "Liste des programmes")) - ("List of Tables" - ("fr" - :ascii "Liste des tableaux" - :latin1 "Liste des tableaux" - :utf-8 "Liste des tableaux")) - ("Listing %d:" - ("fr" - :ascii "Programme %d :" - :latin1 "Programme %d :" - :utf-8 "Programme nº %d :")) - ("Listing %d: %s" - ("fr" - :ascii "Programme %d : %s" - :latin1 "Programme %d : %s" - :utf-8 "Programme nº %d : %s")) - ("See section %s" - ("fr" - :ascii "cf. section %s" - :latin1 "cf. section %s" - :utf-8 "cf. section %s")) - ("Table %d:" - ("fr" - :ascii "Tableau %d :" - :latin1 "Tableau %d :" - :utf-8 "Tableau nº %d :")) - ("Table %d: %s" - ("fr" - :ascii "Tableau %d : %s" - :latin1 "Tableau %d : %s" - :utf-8 "Tableau nº %d : %s")) - ("Table of Contents" - ("fr" - :ascii "Sommaire" - :latin1 "Table des matières" - :utf-8 "Table des matières")) - ("Unknown reference" - ("fr" - :ascii "Destination inconnue" - :latin1 "Référence inconnue" - :utf-8 "Référence inconnue"))) - "Dictionary for export engine. - -Alist whose CAR is the string to translate and CDR is an alist -whose CAR is the language string and CDR is a plist whose -properties are possible charsets and values translated terms. - -It is used as a database for `org-export-translate'. Since this -function returns the string as-is if no translation was found, -the variable only needs to record values different from the -entry.") - -(defun org-export-translate (s encoding info) - "Translate string S according to language specification. - -ENCODING is a symbol among `:ascii', `:html', `:latex', `:latin1' -and `:utf-8'. INFO is a plist used as a communication channel. - -Translation depends on `:language' property. Return the -translated string. If no translation is found return S." - (let ((lang (plist-get info :language)) - (translations (cdr (assoc s org-export-dictionary)))) - (or (plist-get (cdr (assoc lang translations)) encoding) s))) - - - -;;; The Dispatcher -;; -;; `org-export-dispatch' is the standard interactive way to start an -;; export process. It uses `org-export-dispatch-ui' as a subroutine -;; for its interface. Most commons back-ends should have an entry in -;; it. - -;;;###autoload -(defun org-export-dispatch () - "Export dispatcher for Org mode. - -It provides an access to common export related tasks in a buffer. -Its interface comes in two flavours: standard and expert. While -both share the same set of bindings, only the former displays the -valid keys associations. Set `org-export-dispatch-use-expert-ui' -to switch to one or the other. - -Return an error if key pressed has no associated command." - (interactive) - (let* ((input (org-export-dispatch-ui - (if (listp org-export-initial-scope) org-export-initial-scope - (list org-export-initial-scope)) - org-export-dispatch-use-expert-ui)) - (raw-key (car input)) - (optns (cdr input))) - ;; Translate "C-a", "C-b"... into "a", "b"... Then take action - ;; depending on user's key pressed. - (case (if (< raw-key 27) (+ raw-key 96) raw-key) - ;; Allow to quit with "q" key. - (?q nil) - ;; Export with `e-ascii' back-end. - ((?A ?N ?U) - (org-e-ascii-export-as-ascii - (memq 'subtree optns) (memq 'visible optns) (memq 'body optns) - `(:ascii-charset ,(case raw-key (?A 'ascii) (?N 'latin1) (t 'utf-8))))) - ((?a ?n ?u) - (org-e-ascii-export-to-ascii - (memq 'subtree optns) (memq 'visible optns) (memq 'body optns) - `(:ascii-charset ,(case raw-key (?a 'ascii) (?n 'latin1) (t 'utf-8))))) - ;; Export with `e-latex' back-end. - (?L (org-e-latex-export-as-latex - (memq 'subtree optns) (memq 'visible optns) (memq 'body optns))) - (?l - (org-e-latex-export-to-latex - (memq 'subtree optns) (memq 'visible optns) (memq 'body optns))) - (?p - (org-e-latex-export-to-pdf - (memq 'subtree optns) (memq 'visible optns) (memq 'body optns))) - (?d - (org-open-file - (org-e-latex-export-to-pdf - (memq 'subtree optns) (memq 'visible optns) (memq 'body optns)))) - ;; Export with `e-html' back-end. - (?H - (org-e-html-export-as-html - (memq 'subtree optns) (memq 'visible optns) (memq 'body optns))) - (?h - (org-e-html-export-to-html - (memq 'subtree optns) (memq 'visible optns) (memq 'body optns))) - (?b - (org-open-file - (org-e-html-export-to-html - (memq 'subtree optns) (memq 'visible optns) (memq 'body optns)))) - ;; Export with `e-odt' back-end. - (?o - (org-e-odt-export-to-odt - (memq 'subtree optns) (memq 'visible optns) (memq 'body optns))) - (?O - (org-open-file - (org-e-odt-export-to-odt - (memq 'subtree optns) (memq 'visible optns) (memq 'body optns)))) - ;; Publishing facilities - (?F - (org-e-publish-current-file (memq 'force optns))) - (?P - (org-e-publish-current-project (memq 'force optns))) - (?X - (let ((project - (assoc (org-icompleting-read - "Publish project: " org-e-publish-project-alist nil t) - org-e-publish-project-alist))) - (org-e-publish project (memq 'force optns)))) - (?E - (org-e-publish-all (memq 'force optns))) - ;; Undefined command. - (t (error "No command associated with key %s" - (char-to-string raw-key)))))) - -(defun org-export-dispatch-ui (options expertp) - "Handle interface for `org-export-dispatch'. - -OPTIONS is a list containing current interactive options set for -export. It can contain any of the following symbols: -`body' toggles a body-only export -`subtree' restricts export to current subtree -`visible' restricts export to visible part of buffer. -`force' force publishing files. - -EXPERTP, when non-nil, triggers expert UI. In that case, no help -buffer is provided, but indications about currently active -options are given in the prompt. Moreover, \[?] allows to switch -back to standard interface. - -Return value is a list with key pressed as CAR and a list of -final interactive export options as CDR." - (let ((help - (format "---- (Options) ------------------------------------------- - -\[1] Body only: %s [2] Export scope: %s -\[3] Visible only: %s [4] Force publishing: %s - - ---- (ASCII/Latin-1/UTF-8 Export) ------------------------- - -\[a/n/u] to TXT file [A/N/U] to temporary buffer - ---- (HTML Export) ---------------------------------------- - -\[h] to HTML file [b] ... and open it -\[H] to temporary buffer - ---- (LaTeX Export) --------------------------------------- - -\[l] to TEX file [L] to temporary buffer -\[p] to PDF file [d] ... and open it - ---- (ODF Export) ----------------------------------------- - -\[o] to ODT file [O] ... and open it - ---- (Publish) -------------------------------------------- - -\[F] current file [P] current project -\[X] a project [E] every project" - (if (memq 'body options) "On " "Off") - (if (memq 'subtree options) "Subtree" "Buffer ") - (if (memq 'visible options) "On " "Off") - (if (memq 'force options) "On " "Off"))) - (standard-prompt "Export command: ") - (expert-prompt (format "Export command (%s%s%s%s): " - (if (memq 'body options) "b" "-") - (if (memq 'subtree options) "s" "-") - (if (memq 'visible options) "v" "-") - (if (memq 'force options) "f" "-"))) - (handle-keypress - (function - ;; Read a character from command input, toggling interactive - ;; options when applicable. PROMPT is the displayed prompt, - ;; as a string. - (lambda (prompt) - (let ((key (read-char-exclusive prompt))) - (cond - ;; Ignore non-standard characters (i.e. "M-a"). - ((not (characterp key)) (org-export-dispatch-ui options expertp)) - ;; Help key: Switch back to standard interface if - ;; expert UI was active. - ((eq key ??) (org-export-dispatch-ui options nil)) - ;; Toggle export options. - ((memq key '(?1 ?2 ?3 ?4)) - (org-export-dispatch-ui - (let ((option (case key (?1 'body) (?2 'subtree) (?3 'visible) - (?4 'force)))) - (if (memq option options) (remq option options) - (cons option options))) - expertp)) - ;; Action selected: Send key and options back to - ;; `org-export-dispatch'. - (t (cons key options)))))))) - ;; With expert UI, just read key with a fancy prompt. In standard - ;; UI, display an intrusive help buffer. - (if expertp (funcall handle-keypress expert-prompt) - (save-window-excursion - (delete-other-windows) - (with-output-to-temp-buffer "*Org Export/Publishing Help*" (princ help)) - (org-fit-window-to-buffer - (get-buffer-window "*Org Export/Publishing Help*")) - (funcall handle-keypress standard-prompt))))) - - -(provide 'org-export) -;;; org-export.el ends here -- cgit v1.2.3