config

Personal configuration.
git clone git://code.dwrz.net/config
Log | Files | Refs

ox-org.el (13673B)


      1 ;;; ox-org.el --- Org Backend for Org Export Engine -*- lexical-binding: t; -*-
      2 
      3 ;; Copyright (C) 2013-2024 Free Software Foundation, Inc.
      4 
      5 ;; Author: Nicolas Goaziou <n.goaziou@gmail.com>
      6 ;; Keywords: org, text
      7 
      8 ;; This file is part of GNU Emacs.
      9 
     10 ;; GNU Emacs is free software: you can redistribute it and/or modify
     11 ;; it under the terms of the GNU General Public License as published by
     12 ;; the Free Software Foundation, either version 3 of the License, or
     13 ;; (at your option) any later version.
     14 
     15 ;; GNU Emacs is distributed in the hope that it will be useful,
     16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
     17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     18 ;; GNU General Public License for more details.
     19 
     20 ;; You should have received a copy of the GNU General Public License
     21 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
     22 
     23 ;;; Commentary:
     24 
     25 ;;; Code:
     26 
     27 (require 'org-macs)
     28 (org-assert-version)
     29 
     30 (require 'ox)
     31 (declare-function htmlize-buffer "ext:htmlize" (&optional buffer))
     32 (defvar htmlize-output-type)
     33 
     34 (defgroup org-export-org nil
     35   "Options for exporting Org mode files to Org."
     36   :tag "Org Export Org"
     37   :group 'org-export
     38   :version "24.4"
     39   :package-version '(Org . "8.0"))
     40 
     41 (defcustom org-org-htmlized-css-url nil
     42   "URL pointing to the CSS defining colors for htmlized Emacs buffers.
     43 Normally when creating an htmlized version of an Org buffer,
     44 htmlize will create the CSS to define the font colors.  However,
     45 this does not work when converting in batch mode, and it also can
     46 look bad if different people with different fontification setup
     47 work on the same website.  When this variable is non-nil,
     48 creating an htmlized version of an Org buffer using
     49 `org-org-export-as-org' will include a link to this URL if the
     50 setting of `org-html-htmlize-output-type' is `css'."
     51   :group 'org-export-org
     52   :type '(choice
     53 	  (const :tag "Don't include external stylesheet link" nil)
     54 	  (string :tag "URL or local href")))
     55 
     56 (defcustom org-org-with-special-rows t
     57   "Non-nil means export special table rows.
     58 Special rows are the rows containing special marking characters, as
     59 described in the Info node `(org)Advanced features'."
     60   :group 'org-export-org
     61   :type 'boolean
     62   :package-version '(Org . "9.7"))
     63 
     64 (defcustom org-org-with-cite-processors nil
     65   "Non-nil means use citation processors when exporting citations."
     66   :group 'org-export-org
     67   :type 'boolean
     68   :package-version '(Org . "9.7"))
     69 
     70 (org-export-define-backend 'org
     71   '((babel-call . org-org-identity)
     72     (bold . org-org-identity)
     73     (center-block . org-org-identity)
     74     (clock . org-org-identity)
     75     (code . org-org-identity)
     76     (diary-sexp . org-org-identity)
     77     (drawer . org-org-identity)
     78     (dynamic-block . org-org-identity)
     79     (entity . org-org-identity)
     80     (example-block . org-org-identity)
     81     (export-block . org-org-export-block)
     82     (fixed-width . org-org-identity)
     83     (footnote-definition . ignore)
     84     (footnote-reference . org-org-identity)
     85     (headline . org-org-headline)
     86     (horizontal-rule . org-org-identity)
     87     (inline-babel-call . org-org-identity)
     88     (inline-src-block . org-org-identity)
     89     (inlinetask . org-org-identity)
     90     (italic . org-org-identity)
     91     (citation . org-org-identity)
     92     (citation-reference . org-org-identity)
     93     (item . org-org-identity)
     94     (keyword . org-org-keyword)
     95     (latex-environment . org-org-identity)
     96     (latex-fragment . org-org-identity)
     97     (line-break . org-org-identity)
     98     (link . org-org-link)
     99     (node-property . org-org-identity)
    100     (template . org-org-template)
    101     (paragraph . org-org-identity)
    102     (plain-list . org-org-identity)
    103     (planning . org-org-identity)
    104     (property-drawer . org-org-identity)
    105     (quote-block . org-org-identity)
    106     (radio-target . org-org-identity)
    107     (section . org-org-section)
    108     (special-block . org-org-identity)
    109     (src-block . org-org-identity)
    110     (statistics-cookie . org-org-identity)
    111     (strike-through . org-org-identity)
    112     (subscript . org-org-identity)
    113     (superscript . org-org-identity)
    114     (table . org-org-identity)
    115     (table-cell . org-org-identity)
    116     (table-row . org-org-identity)
    117     (target . org-org-identity)
    118     (timestamp . org-org-timestamp)
    119     (underline . org-org-identity)
    120     (verbatim . org-org-identity)
    121     (verse-block . org-org-identity))
    122   :menu-entry
    123   '(?O "Export to Org"
    124        ((?O "As Org buffer" org-org-export-as-org)
    125 	(?o "As Org file" org-org-export-to-org)
    126 	(?v "As Org file and open"
    127 	    (lambda (a s v b)
    128 	      (if a (org-org-export-to-org t s v b)
    129 		(org-open-file (org-org-export-to-org nil s v b)))))))
    130   :filters-alist '((:filter-parse-tree . org-org--add-missing-sections))
    131   :options-alist
    132   ;; Export special table rows.
    133   '((:with-special-rows nil nil org-org-with-special-rows)
    134     (:with-cite-processors nil nil org-org-with-cite-processors)))
    135 
    136 (defun org-org--add-missing-sections (tree _backend _info)
    137   "Ensure each headline has an associated section.
    138 
    139 TREE is the parse tree being exported.
    140 
    141 Footnotes relative to the headline are inserted in the section,
    142 using `org-org-section'.  However, this function is not called if
    143 the headline doesn't contain any section in the first place, so
    144 we make sure it is always called."
    145   (org-element-map tree 'headline
    146     (lambda (h)
    147       (let ((first-child (car (org-element-contents h)))
    148 	    (new-section (org-element-create 'section)))
    149 	(pcase (org-element-type first-child)
    150 	  (`section nil)
    151 	  (`nil (org-element-adopt h new-section))
    152 	  (_ (org-element-insert-before new-section first-child))))))
    153   tree)
    154 
    155 (defun org-org-export-block (export-block _contents _info)
    156   "Transcode a EXPORT-BLOCK element from Org to LaTeX.
    157 CONTENTS and INFO are ignored."
    158   (and (equal (org-element-property :type export-block) "ORG")
    159        (org-element-property :value export-block)))
    160 
    161 (defun org-org-identity (blob contents _info)
    162   "Transcode BLOB element or object back into Org syntax.
    163 CONTENTS is its contents, as a string or nil.  INFO is ignored."
    164   (let ((case-fold-search t))
    165     (replace-regexp-in-string
    166      "^[ \t]*#\\+attr_[-_a-z0-9]+:\\(?: .*\\)?\n" ""
    167      (org-export-expand blob contents t))))
    168 
    169 (defun org-org-headline (headline contents info)
    170   "Transcode HEADLINE element back into Org syntax.
    171 CONTENTS is its contents, as a string or nil.  INFO is ignored."
    172   (unless (org-element-property :footnote-section-p headline)
    173     (unless (plist-get info :with-todo-keywords)
    174       (org-element-put-property headline :todo-keyword nil))
    175     (unless (plist-get info :with-tags)
    176       (org-element-put-property headline :tags nil))
    177     (unless (plist-get info :with-priority)
    178       (org-element-put-property headline :priority nil))
    179     (org-element-put-property headline :level
    180 			      (org-export-get-relative-level headline info))
    181     (org-element-headline-interpreter headline contents)))
    182 
    183 (defun org-org-keyword (keyword _contents _info)
    184   "Transcode KEYWORD element back into Org syntax.
    185 CONTENTS is nil.  INFO is ignored."
    186   (let ((key (org-element-property :key keyword)))
    187     (unless (member key
    188 		    '("AUTHOR" "CREATOR" "DATE" "EMAIL" "OPTIONS" "TITLE"))
    189       (org-element-keyword-interpreter keyword nil))))
    190 
    191 (defun org-org-link (link contents info)
    192   "Transcode LINK object back into Org syntax.
    193 CONTENTS is the description of the link, as a string, or nil.
    194 INFO is a plist containing current export state."
    195   (or (org-export-custom-protocol-maybe link contents 'org info)
    196       (org-element-link-interpreter link contents)))
    197 
    198 (defun org-org-template (contents info)
    199   "Return Org document template with document keywords.
    200 CONTENTS is the transcoded contents string.  INFO is a plist used
    201 as a communication channel."
    202   (concat
    203    (and (plist-get info :time-stamp-file)
    204 	(format-time-string "# Created %Y-%m-%d %a %H:%M\n"))
    205    (org-element-normalize-string
    206     (mapconcat #'identity
    207 	       (org-element-map (plist-get info :parse-tree) 'keyword
    208 		 (lambda (k)
    209 		   (and (string-equal (org-element-property :key k) "OPTIONS")
    210 			(concat "#+options: "
    211 				(org-element-property :value k)))))
    212 	       "\n"))
    213    (and (plist-get info :with-title)
    214 	(format "#+title: %s\n" (org-export-data (plist-get info :title) info)))
    215    (and (plist-get info :with-date)
    216 	(let ((date (org-export-data (org-export-get-date info) info)))
    217 	  (and (org-string-nw-p date)
    218 	       (format "#+date: %s\n" date))))
    219    (and (plist-get info :with-author)
    220 	(let ((author (org-export-data (plist-get info :author) info)))
    221 	  (and (org-string-nw-p author)
    222 	       (format "#+author: %s\n" author))))
    223    (and (plist-get info :with-email)
    224 	(let ((email (org-export-data (plist-get info :email) info)))
    225 	  (and (org-string-nw-p email)
    226 	       (format "#+email: %s\n" email))))
    227    (and (plist-get info :with-creator)
    228 	(org-string-nw-p (plist-get info :creator))
    229 	(format "#+creator: %s\n" (plist-get info :creator)))
    230    contents))
    231 
    232 (defun org-org-timestamp (timestamp _contents _info)
    233   "Transcode a TIMESTAMP object to custom format or back into Org syntax."
    234   (org-timestamp-translate timestamp))
    235 
    236 (defun org-org-section (section contents info)
    237   "Transcode SECTION element back into Org syntax.
    238 CONTENTS is the contents of the section.  INFO is a plist used as
    239 a communication channel."
    240   (concat
    241    (org-element-normalize-string contents)
    242    ;; Insert footnote definitions appearing for the first time in this
    243    ;; section, or in the relative headline title.  Indeed, some of
    244    ;; them may not be available to narrowing so we make sure all of
    245    ;; them are included in the result.
    246    (let ((footnotes
    247 	  (org-element-map
    248 	      (list (org-element-lineage section 'headline) section)
    249 	      'footnote-reference
    250 	    (lambda (fn)
    251 	      (and (eq (org-element-property :type fn) 'standard)
    252 		   (org-export-footnote-first-reference-p fn info)
    253 		   (org-element-normalize-string
    254 		    (format "[fn:%s] %s"
    255 			    (org-element-property :label fn)
    256 			    (org-export-data
    257 			     (org-export-get-footnote-definition fn info)
    258 			     info)))))
    259 	    info nil 'headline t)))
    260      (and footnotes (concat "\n" (mapconcat #'identity footnotes "\n"))))))
    261 
    262 ;;;###autoload
    263 (defun org-org-export-as-org
    264     (&optional async subtreep visible-only body-only ext-plist)
    265   "Export current buffer to an Org buffer.
    266 
    267 If narrowing is active in the current buffer, only export its
    268 narrowed part.
    269 
    270 If a region is active, export that region.
    271 
    272 A non-nil optional argument ASYNC means the process should happen
    273 asynchronously.  The resulting buffer should be accessible
    274 through the `org-export-stack' interface.
    275 
    276 When optional argument SUBTREEP is non-nil, export the sub-tree
    277 at point, extracting information from the headline properties
    278 first.
    279 
    280 When optional argument VISIBLE-ONLY is non-nil, don't export
    281 contents of hidden elements.
    282 
    283 When optional argument BODY-ONLY is non-nil, strip document
    284 keywords from output.
    285 
    286 EXT-PLIST, when provided, is a property list with external
    287 parameters overriding Org default settings, but still inferior to
    288 file-local settings.
    289 
    290 Export is done in a buffer named \"*Org ORG Export*\", which will
    291 be displayed when `org-export-show-temporary-export-buffer' is
    292 non-nil."
    293   (interactive)
    294   (org-export-to-buffer 'org "*Org ORG Export*"
    295     async subtreep visible-only body-only ext-plist (lambda () (org-mode))))
    296 
    297 ;;;###autoload
    298 (defun org-org-export-to-org
    299     (&optional async subtreep visible-only body-only ext-plist)
    300   "Export current buffer to an Org file.
    301 
    302 If narrowing is active in the current buffer, only export its
    303 narrowed part.
    304 
    305 If a region is active, export that region.
    306 
    307 A non-nil optional argument ASYNC means the process should happen
    308 asynchronously.  The resulting file should be accessible through
    309 the `org-export-stack' interface.
    310 
    311 When optional argument SUBTREEP is non-nil, export the sub-tree
    312 at point, extracting information from the headline properties
    313 first.
    314 
    315 When optional argument VISIBLE-ONLY is non-nil, don't export
    316 contents of hidden elements.
    317 
    318 When optional argument BODY-ONLY is non-nil, strip document
    319 keywords from output.
    320 
    321 EXT-PLIST, when provided, is a property list with external
    322 parameters overriding Org default settings, but still inferior to
    323 file-local settings.
    324 
    325 Return output file name."
    326   (interactive)
    327   (let ((outfile (org-export-output-file-name ".org" subtreep)))
    328     (org-export-to-file 'org outfile
    329       async subtreep visible-only body-only ext-plist)))
    330 
    331 ;;;###autoload
    332 (defun org-org-publish-to-org (plist filename pub-dir)
    333   "Publish an Org file to Org.
    334 
    335 FILENAME is the filename of the Org file to be published.  PLIST
    336 is the property list for the given project.  PUB-DIR is the
    337 publishing directory.
    338 
    339 Return output file name."
    340   (org-publish-org-to 'org filename ".org" plist pub-dir)
    341   (when (plist-get plist :htmlized-source)
    342     (org-require-package 'htmlize)
    343     (require 'ox-html)
    344     (let* ((org-inhibit-startup t)
    345 	   (htmlize-output-type 'css)
    346 	   (html-ext (concat "." (or (plist-get plist :html-extension)
    347 				     org-html-extension "html")))
    348 	   newbuf)
    349       (org-with-file-buffer filename
    350         (font-lock-ensure)
    351         (org-fold-show-all)
    352         (setq newbuf (htmlize-buffer)))
    353       (with-current-buffer newbuf
    354 	(when org-org-htmlized-css-url
    355 	  (goto-char (point-min))
    356 	  (and (re-search-forward
    357 		"<style type=\"text/css\">\\(?:.\\|\n\\)*?\n[ \t]*</style>.*" nil t)
    358 	       (replace-match
    359 		(format
    360 		 "<link rel=\"stylesheet\" type=\"text/css\" href=\"%s\">"
    361 		 org-org-htmlized-css-url)
    362                 t t)))
    363 	(write-file (concat pub-dir (file-name-nondirectory filename) html-ext)))
    364       (kill-buffer newbuf))))
    365 
    366 
    367 (provide 'ox-org)
    368 
    369 ;; Local variables:
    370 ;; generated-autoload-file: "org-loaddefs.el"
    371 ;; End:
    372 
    373 ;;; ox-org.el ends here